$(eval $(call KernelPackage,sound-soc-hifiberry-dacplusdsp))
+define KernelPackage/sound-soc-hifiberry-dacplushd
+ TITLE:=Support for HifiBerry DAC+HD
+ KCONFIG:= \
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD \
+ CONFIG_SND_SOC_PCM179X \
+ CONFIG_SND_SOC_PCM179X_I2C
+ FILES:= \
+ $(LINUX_DIR)/drivers/clk/clk-hifiberry-dachd.ko \
+ $(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-dacplushd.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm179x-codec.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm179x-i2c.ko
+ AUTOLOAD:=$(call AutoLoad,68,clk-hifiberry-dachd snd-soc-pcm179x-codec \
+ snd-soc-pcm179x-i2c snd-soc-hifiberry-dacplushd)
+ DEPENDS:= \
+ kmod-sound-soc-bcm2835-i2s \
+ +kmod-i2c-bcm2835 \
+ +kmod-regmap-i2c
+ $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-hifiberry-dacplushd/description
+ This package contains support for HifiBerry DAC+HD
+endef
+
+$(eval $(call KernelPackage,sound-soc-hifiberry-dacplushd))
+
+
define KernelPackage/sound-soc-hifiberry-dacplusadc-pro
TITLE:=Support for HifiBerry DAC+ADC PRO
KCONFIG:= \
$(eval $(call KernelPackage,sound-soc-i-sabe-q2m))
+define KernelPackage/sound-soc-justboom-both
+ TITLE:=Support for JustBoom DAC and Digi
+ KCONFIG:= \
+ CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH \
+ CONFIG_SND_SOC_PCM512x \
+ CONFIG_SND_SOC_WM8804
+ FILES:= \
+ $(LINUX_DIR)/sound/soc/bcm/snd-soc-justboom-both.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8804.ko
+ AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm512x snd-soc-wm8804 \
+ snd-soc-justboom-both)
+ DEPENDS:= \
+ kmod-sound-soc-bcm2835-i2s \
+ +kmod-sound-soc-rpi-wm8804-soundcard \
+ +kmod-i2c-bcm2835
+ $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-justboom-both/description
+ This package contains support for JustBoom DAC and Digi
+endef
+
+$(eval $(call KernelPackage,sound-soc-justboom-both))
+
+
define KernelPackage/sound-soc-justboom-dac
TITLE:=Support for JustBoom DAC
KCONFIG:= \
--- /dev/null
+From 3e8dfb23cfab3003ff83f4d32568ae4e38536572 Mon Sep 17 00:00:00 2001
+Date: Sat, 20 Oct 2018 19:31:00 +0200
+Subject: [PATCH] staging: bcm2835-camera: Move module info to the end
+
+In order to have this more consistent between the vc04 services move
+the module information to the end of the file.
+
+---
+ .../vc04_services/bcm2835-camera/bcm2835-camera.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -43,12 +43,6 @@
+
+ #define MAX_BCM2835_CAMERAS 2
+
+-MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture");
+-MODULE_AUTHOR("Vincent Sanders");
+-MODULE_LICENSE("GPL");
+-MODULE_VERSION(BM2835_MMAL_VERSION);
+-MODULE_ALIAS("platform:bcm2835-camera");
+-
+ int bcm2835_v4l2_debug;
+ module_param_named(debug, bcm2835_v4l2_debug, int, 0644);
+ MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2");
+@@ -1989,3 +1983,9 @@ static struct platform_driver bcm2835_ca
+ };
+
+ module_platform_driver(bcm2835_camera_driver)
++
++MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture");
++MODULE_AUTHOR("Vincent Sanders");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(BM2835_MMAL_VERSION);
++MODULE_ALIAS("platform:bcm2835-camera");
+++ /dev/null
-From 3e8dfb23cfab3003ff83f4d32568ae4e38536572 Mon Sep 17 00:00:00 2001
-Date: Sat, 20 Oct 2018 19:31:00 +0200
-Subject: [PATCH] staging: bcm2835-camera: Move module info to the end
-
-In order to have this more consistent between the vc04 services move
-the module information to the end of the file.
-
----
- .../vc04_services/bcm2835-camera/bcm2835-camera.c | 12 ++++++------
- 1 file changed, 6 insertions(+), 6 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -43,12 +43,6 @@
-
- #define MAX_BCM2835_CAMERAS 2
-
--MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture");
--MODULE_AUTHOR("Vincent Sanders");
--MODULE_LICENSE("GPL");
--MODULE_VERSION(BM2835_MMAL_VERSION);
--MODULE_ALIAS("platform:bcm2835-camera");
--
- int bcm2835_v4l2_debug;
- module_param_named(debug, bcm2835_v4l2_debug, int, 0644);
- MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2");
-@@ -1989,3 +1983,9 @@ static struct platform_driver bcm2835_ca
- };
-
- module_platform_driver(bcm2835_camera_driver)
-+
-+MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture");
-+MODULE_AUTHOR("Vincent Sanders");
-+MODULE_LICENSE("GPL");
-+MODULE_VERSION(BM2835_MMAL_VERSION);
-+MODULE_ALIAS("platform:bcm2835-camera");
--- /dev/null
+From 1ada615db1b97faec9c4625ccfd2cc35d54d850a Mon Sep 17 00:00:00 2001
+Date: Sat, 13 Oct 2018 20:51:23 +0200
+Subject: [PATCH] staging: vchiq_arm: Fix platform device
+ unregistration
+
+In error case platform_device_register_data would return an ERR_PTR
+instead of NULL. So we better check this before unregistration.
+
+Fixes: 37b7b3087a2f ("staging/vc04_services: Register a platform device for the camera driver.")
+---
+ drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -3656,7 +3656,8 @@ failed_platform_init:
+
+ static int vchiq_remove(struct platform_device *pdev)
+ {
+- platform_device_unregister(bcm2835_camera);
++ if (!IS_ERR(bcm2835_camera))
++ platform_device_unregister(bcm2835_camera);
+ vchiq_debugfs_deinit();
+ device_destroy(vchiq_class, vchiq_devid);
+ class_destroy(vchiq_class);
--- /dev/null
+From 58ed78a70c3c3ef1ae99aefdd2c28ac81f66df85 Mon Sep 17 00:00:00 2001
+Date: Mon, 22 Oct 2018 15:16:51 +0200
+Subject: [PATCH] staging: vchiq_arm: Fix camera device registration
+
+Since the camera driver isn't probed via DT, we need to properly setup DMA.
+
+Fixes: 37b7b3087a2f ("staging/vc04_services: Register a platform device for the camera driver.")
+---
+ .../interface/vchiq_arm/vchiq_arm.c | 20 ++++++++++++++++---
+ 1 file changed, 17 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -49,6 +49,7 @@
+ #include <linux/of.h>
+ #include <linux/platform_device.h>
+ #include <linux/compat.h>
++#include <linux/dma-mapping.h>
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
+ #include "vchiq_core.h"
+@@ -3578,6 +3579,21 @@ void vchiq_platform_conn_state_changed(V
+ }
+ }
+
++static struct platform_device *
++vchiq_register_child(struct platform_device *pdev, const char *name)
++{
++ struct platform_device_info pdevinfo;
++
++ memset(&pdevinfo, 0, sizeof(pdevinfo));
++
++ pdevinfo.parent = &pdev->dev;
++ pdevinfo.name = name;
++ pdevinfo.id = PLATFORM_DEVID_NONE;
++ pdevinfo.dma_mask = DMA_BIT_MASK(32);
++
++ return platform_device_register_full(&pdevinfo);
++}
++
+ static int vchiq_probe(struct platform_device *pdev)
+ {
+ struct device_node *fw_node;
+@@ -3637,9 +3653,7 @@ static int vchiq_probe(struct platform_d
+ VCHIQ_VERSION, VCHIQ_VERSION_MIN,
+ MAJOR(vchiq_devid), MINOR(vchiq_devid));
+
+- bcm2835_camera = platform_device_register_data(&pdev->dev,
+- "bcm2835-camera", -1,
+- NULL, 0);
++ bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
+
+ return 0;
+
+++ /dev/null
-From 1ada615db1b97faec9c4625ccfd2cc35d54d850a Mon Sep 17 00:00:00 2001
-Date: Sat, 13 Oct 2018 20:51:23 +0200
-Subject: [PATCH] staging: vchiq_arm: Fix platform device
- unregistration
-
-In error case platform_device_register_data would return an ERR_PTR
-instead of NULL. So we better check this before unregistration.
-
-Fixes: 37b7b3087a2f ("staging/vc04_services: Register a platform device for the camera driver.")
----
- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -3656,7 +3656,8 @@ failed_platform_init:
-
- static int vchiq_remove(struct platform_device *pdev)
- {
-- platform_device_unregister(bcm2835_camera);
-+ if (!IS_ERR(bcm2835_camera))
-+ platform_device_unregister(bcm2835_camera);
- vchiq_debugfs_deinit();
- device_destroy(vchiq_class, vchiq_devid);
- class_destroy(vchiq_class);
--- /dev/null
+From 94a174095f29c77574548eea17aacaed5c540757 Mon Sep 17 00:00:00 2001
+Date: Sun, 21 Oct 2018 18:40:07 +0200
+Subject: [PATCH] staging: bcm2835-camera: Provide more specific probe
+ error messages
+
+Currently there is only a catch-all info message which print the
+relevant error code without any context. So add more specific error
+messages in order to narrow down possible issues.
+
+---
+ .../bcm2835-camera/bcm2835-camera.c | 58 +++++++++++++------
+ 1 file changed, 39 insertions(+), 19 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -1552,8 +1552,11 @@ static int mmal_init(struct bm2835_mmal_
+ struct vchiq_mmal_component *camera;
+
+ ret = vchiq_mmal_init(&dev->instance);
+- if (ret < 0)
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev, "%s: vchiq mmal init failed %d\n",
++ __func__, ret);
+ return ret;
++ }
+
+ /* get the camera component ready */
+ ret = vchiq_mmal_component_init(dev->instance, "ril.camera",
+@@ -1562,7 +1565,9 @@ static int mmal_init(struct bm2835_mmal_
+ goto unreg_mmal;
+
+ camera = dev->component[MMAL_COMPONENT_CAMERA];
+- if (camera->outputs < MMAL_CAMERA_PORT_COUNT) {
++ if (camera->outputs < MMAL_CAMERA_PORT_COUNT) {
++ v4l2_err(&dev->v4l2_dev, "%s: too few camera outputs %d needed %d\n",
++ __func__, camera->outputs, MMAL_CAMERA_PORT_COUNT);
+ ret = -EINVAL;
+ goto unreg_camera;
+ }
+@@ -1570,8 +1575,11 @@ static int mmal_init(struct bm2835_mmal_
+ ret = set_camera_parameters(dev->instance,
+ camera,
+ dev);
+- if (ret < 0)
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev, "%s: unable to set camera parameters: %d\n",
++ __func__, ret);
+ goto unreg_camera;
++ }
+
+ /* There was an error in the firmware that meant the camera component
+ * produced BGR instead of RGB.
+@@ -1660,8 +1668,8 @@ static int mmal_init(struct bm2835_mmal_
+
+ if (dev->component[MMAL_COMPONENT_PREVIEW]->inputs < 1) {
+ ret = -EINVAL;
+- pr_debug("too few input ports %d needed %d\n",
+- dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
++ v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
++ __func__, dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
+ goto unreg_preview;
+ }
+
+@@ -1674,8 +1682,8 @@ static int mmal_init(struct bm2835_mmal_
+
+ if (dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs < 1) {
+ ret = -EINVAL;
+- v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
+- dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
++ v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
++ __func__, dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
+ 1);
+ goto unreg_image_encoder;
+ }
+@@ -1689,8 +1697,8 @@ static int mmal_init(struct bm2835_mmal_
+
+ if (dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs < 1) {
+ ret = -EINVAL;
+- v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
+- dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
++ v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
++ __func__, dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
+ 1);
+ goto unreg_vid_encoder;
+ }
+@@ -1719,8 +1727,11 @@ static int mmal_init(struct bm2835_mmal_
+ sizeof(enable));
+ }
+ ret = bm2835_mmal_set_all_camera_controls(dev);
+- if (ret < 0)
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev, "%s: failed to set all camera controls: %d\n",
++ __func__, ret);
+ goto unreg_vid_encoder;
++ }
+
+ return 0;
+
+@@ -1886,21 +1897,29 @@ static int bcm2835_mmal_probe(struct pla
+ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+ "%s", BM2835_MMAL_MODULE_NAME);
+ ret = v4l2_device_register(NULL, &dev->v4l2_dev);
+- if (ret)
++ if (ret) {
++ dev_err(&pdev->dev, "%s: could not register V4L2 device: %d\n",
++ __func__, ret);
+ goto free_dev;
++ }
+
+ /* setup v4l controls */
+ ret = bm2835_mmal_init_controls(dev, &dev->ctrl_handler);
+- if (ret < 0)
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev, "%s: could not init controls: %d\n",
++ __func__, ret);
+ goto unreg_dev;
++ }
+ dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
+
+ /* mmal init */
+ dev->instance = instance;
+ ret = mmal_init(dev);
+- if (ret < 0)
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev, "%s: mmal init failed: %d\n",
++ __func__, ret);
+ goto unreg_dev;
+-
++ }
+ /* initialize queue */
+ q = &dev->capture.vb_vidq;
+ memset(q, 0, sizeof(*q));
+@@ -1918,16 +1937,19 @@ static int bcm2835_mmal_probe(struct pla
+
+ /* initialise video devices */
+ ret = bm2835_mmal_init_device(dev, &dev->vdev);
+- if (ret < 0)
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev, "%s: could not init device: %d\n",
++ __func__, ret);
+ goto unreg_dev;
++ }
+
+ /* Really want to call vidioc_s_fmt_vid_cap with the default
+ * format, but currently the APIs don't join up.
+ */
+ ret = mmal_setup_components(dev, &default_v4l2_format);
+ if (ret < 0) {
+- v4l2_err(&dev->v4l2_dev,
+- "%s: could not setup components\n", __func__);
++ v4l2_err(&dev->v4l2_dev, "%s: could not setup components: %d\n",
++ __func__, ret);
+ goto unreg_dev;
+ }
+
+@@ -1951,8 +1973,6 @@ cleanup_gdev:
+ bcm2835_cleanup_instance(gdev[i]);
+ gdev[i] = NULL;
+ }
+- pr_info("%s: error %d while loading driver\n",
+- BM2835_MMAL_MODULE_NAME, ret);
+
+ cleanup_mmal:
+ vchiq_mmal_finalise(instance);
+++ /dev/null
-From 58ed78a70c3c3ef1ae99aefdd2c28ac81f66df85 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Oct 2018 15:16:51 +0200
-Subject: [PATCH] staging: vchiq_arm: Fix camera device registration
-
-Since the camera driver isn't probed via DT, we need to properly setup DMA.
-
-Fixes: 37b7b3087a2f ("staging/vc04_services: Register a platform device for the camera driver.")
----
- .../interface/vchiq_arm/vchiq_arm.c | 20 ++++++++++++++++---
- 1 file changed, 17 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -49,6 +49,7 @@
- #include <linux/of.h>
- #include <linux/platform_device.h>
- #include <linux/compat.h>
-+#include <linux/dma-mapping.h>
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
- #include "vchiq_core.h"
-@@ -3578,6 +3579,21 @@ void vchiq_platform_conn_state_changed(V
- }
- }
-
-+static struct platform_device *
-+vchiq_register_child(struct platform_device *pdev, const char *name)
-+{
-+ struct platform_device_info pdevinfo;
-+
-+ memset(&pdevinfo, 0, sizeof(pdevinfo));
-+
-+ pdevinfo.parent = &pdev->dev;
-+ pdevinfo.name = name;
-+ pdevinfo.id = PLATFORM_DEVID_NONE;
-+ pdevinfo.dma_mask = DMA_BIT_MASK(32);
-+
-+ return platform_device_register_full(&pdevinfo);
-+}
-+
- static int vchiq_probe(struct platform_device *pdev)
- {
- struct device_node *fw_node;
-@@ -3637,9 +3653,7 @@ static int vchiq_probe(struct platform_d
- VCHIQ_VERSION, VCHIQ_VERSION_MIN,
- MAJOR(vchiq_devid), MINOR(vchiq_devid));
-
-- bcm2835_camera = platform_device_register_data(&pdev->dev,
-- "bcm2835-camera", -1,
-- NULL, 0);
-+ bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
-
- return 0;
-
--- /dev/null
+From 17eaf7c6e8dfcd76b4ed28587b07892e2a5a4ff5 Mon Sep 17 00:00:00 2001
+Date: Sun, 21 Oct 2018 19:08:29 +0200
+Subject: [PATCH] staging: bcm2835-camera: Add hint about possible
+ faulty GPU mem config
+
+As per default the GPU memory config of the Raspberry Pi isn't sufficient
+for the camera usage. Even worse the bcm2835 camera doesn't provide a
+helpful error message in this case. So let's add a hint to point the user
+to the likely cause.
+
+---
+ drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
+@@ -1620,8 +1620,11 @@ int vchiq_mmal_component_init(struct vch
+ component = &instance->component[instance->component_idx];
+
+ ret = create_component(instance, component, name);
+- if (ret < 0)
++ if (ret < 0) {
++ pr_err("%s: failed to create component %d (Not enough GPU mem?)\n",
++ __func__, ret);
+ goto unlock;
++ }
+
+ /* ports info needs gathering */
+ component->control.type = MMAL_PORT_TYPE_CONTROL;
+++ /dev/null
-From 94a174095f29c77574548eea17aacaed5c540757 Mon Sep 17 00:00:00 2001
-Date: Sun, 21 Oct 2018 18:40:07 +0200
-Subject: [PATCH] staging: bcm2835-camera: Provide more specific probe
- error messages
-
-Currently there is only a catch-all info message which print the
-relevant error code without any context. So add more specific error
-messages in order to narrow down possible issues.
-
----
- .../bcm2835-camera/bcm2835-camera.c | 58 +++++++++++++------
- 1 file changed, 39 insertions(+), 19 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -1552,8 +1552,11 @@ static int mmal_init(struct bm2835_mmal_
- struct vchiq_mmal_component *camera;
-
- ret = vchiq_mmal_init(&dev->instance);
-- if (ret < 0)
-+ if (ret < 0) {
-+ v4l2_err(&dev->v4l2_dev, "%s: vchiq mmal init failed %d\n",
-+ __func__, ret);
- return ret;
-+ }
-
- /* get the camera component ready */
- ret = vchiq_mmal_component_init(dev->instance, "ril.camera",
-@@ -1562,7 +1565,9 @@ static int mmal_init(struct bm2835_mmal_
- goto unreg_mmal;
-
- camera = dev->component[MMAL_COMPONENT_CAMERA];
-- if (camera->outputs < MMAL_CAMERA_PORT_COUNT) {
-+ if (camera->outputs < MMAL_CAMERA_PORT_COUNT) {
-+ v4l2_err(&dev->v4l2_dev, "%s: too few camera outputs %d needed %d\n",
-+ __func__, camera->outputs, MMAL_CAMERA_PORT_COUNT);
- ret = -EINVAL;
- goto unreg_camera;
- }
-@@ -1570,8 +1575,11 @@ static int mmal_init(struct bm2835_mmal_
- ret = set_camera_parameters(dev->instance,
- camera,
- dev);
-- if (ret < 0)
-+ if (ret < 0) {
-+ v4l2_err(&dev->v4l2_dev, "%s: unable to set camera parameters: %d\n",
-+ __func__, ret);
- goto unreg_camera;
-+ }
-
- /* There was an error in the firmware that meant the camera component
- * produced BGR instead of RGB.
-@@ -1660,8 +1668,8 @@ static int mmal_init(struct bm2835_mmal_
-
- if (dev->component[MMAL_COMPONENT_PREVIEW]->inputs < 1) {
- ret = -EINVAL;
-- pr_debug("too few input ports %d needed %d\n",
-- dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
-+ v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
-+ __func__, dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
- goto unreg_preview;
- }
-
-@@ -1674,8 +1682,8 @@ static int mmal_init(struct bm2835_mmal_
-
- if (dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs < 1) {
- ret = -EINVAL;
-- v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
-- dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
-+ v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
-+ __func__, dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
- 1);
- goto unreg_image_encoder;
- }
-@@ -1689,8 +1697,8 @@ static int mmal_init(struct bm2835_mmal_
-
- if (dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs < 1) {
- ret = -EINVAL;
-- v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
-- dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
-+ v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
-+ __func__, dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
- 1);
- goto unreg_vid_encoder;
- }
-@@ -1719,8 +1727,11 @@ static int mmal_init(struct bm2835_mmal_
- sizeof(enable));
- }
- ret = bm2835_mmal_set_all_camera_controls(dev);
-- if (ret < 0)
-+ if (ret < 0) {
-+ v4l2_err(&dev->v4l2_dev, "%s: failed to set all camera controls: %d\n",
-+ __func__, ret);
- goto unreg_vid_encoder;
-+ }
-
- return 0;
-
-@@ -1886,21 +1897,29 @@ static int bcm2835_mmal_probe(struct pla
- snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
- "%s", BM2835_MMAL_MODULE_NAME);
- ret = v4l2_device_register(NULL, &dev->v4l2_dev);
-- if (ret)
-+ if (ret) {
-+ dev_err(&pdev->dev, "%s: could not register V4L2 device: %d\n",
-+ __func__, ret);
- goto free_dev;
-+ }
-
- /* setup v4l controls */
- ret = bm2835_mmal_init_controls(dev, &dev->ctrl_handler);
-- if (ret < 0)
-+ if (ret < 0) {
-+ v4l2_err(&dev->v4l2_dev, "%s: could not init controls: %d\n",
-+ __func__, ret);
- goto unreg_dev;
-+ }
- dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
-
- /* mmal init */
- dev->instance = instance;
- ret = mmal_init(dev);
-- if (ret < 0)
-+ if (ret < 0) {
-+ v4l2_err(&dev->v4l2_dev, "%s: mmal init failed: %d\n",
-+ __func__, ret);
- goto unreg_dev;
--
-+ }
- /* initialize queue */
- q = &dev->capture.vb_vidq;
- memset(q, 0, sizeof(*q));
-@@ -1918,16 +1937,19 @@ static int bcm2835_mmal_probe(struct pla
-
- /* initialise video devices */
- ret = bm2835_mmal_init_device(dev, &dev->vdev);
-- if (ret < 0)
-+ if (ret < 0) {
-+ v4l2_err(&dev->v4l2_dev, "%s: could not init device: %d\n",
-+ __func__, ret);
- goto unreg_dev;
-+ }
-
- /* Really want to call vidioc_s_fmt_vid_cap with the default
- * format, but currently the APIs don't join up.
- */
- ret = mmal_setup_components(dev, &default_v4l2_format);
- if (ret < 0) {
-- v4l2_err(&dev->v4l2_dev,
-- "%s: could not setup components\n", __func__);
-+ v4l2_err(&dev->v4l2_dev, "%s: could not setup components: %d\n",
-+ __func__, ret);
- goto unreg_dev;
- }
-
-@@ -1951,8 +1973,6 @@ cleanup_gdev:
- bcm2835_cleanup_instance(gdev[i]);
- gdev[i] = NULL;
- }
-- pr_info("%s: error %d while loading driver\n",
-- BM2835_MMAL_MODULE_NAME, ret);
-
- cleanup_mmal:
- vchiq_mmal_finalise(instance);
+++ /dev/null
-From 17eaf7c6e8dfcd76b4ed28587b07892e2a5a4ff5 Mon Sep 17 00:00:00 2001
-Date: Sun, 21 Oct 2018 19:08:29 +0200
-Subject: [PATCH] staging: bcm2835-camera: Add hint about possible
- faulty GPU mem config
-
-As per default the GPU memory config of the Raspberry Pi isn't sufficient
-for the camera usage. Even worse the bcm2835 camera doesn't provide a
-helpful error message in this case. So let's add a hint to point the user
-to the likely cause.
-
----
- drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
-@@ -1620,8 +1620,11 @@ int vchiq_mmal_component_init(struct vch
- component = &instance->component[instance->component_idx];
-
- ret = create_component(instance, component, name);
-- if (ret < 0)
-+ if (ret < 0) {
-+ pr_err("%s: failed to create component %d (Not enough GPU mem?)\n",
-+ __func__, ret);
- goto unlock;
-+ }
-
- /* ports info needs gathering */
- component->control.type = MMAL_PORT_TYPE_CONTROL;
--- /dev/null
+From 73979b06255c3b7b536a53d09ea095aec8ed37aa Mon Sep 17 00:00:00 2001
+Date: Mon, 3 Dec 2018 12:50:38 +0000
+Subject: [PATCH] staging: vchiq_arm: Improve error handling on loading
+ drivers
+
+The handling of loading platform drivers requires checking IS_ERR
+for the pointer on unload.
+If the driver fails to load, NULL the pointer during probe as
+platform_device_unregister already checks for NULL.
+
+---
+ .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -3654,6 +3654,8 @@ static int vchiq_probe(struct platform_d
+ MAJOR(vchiq_devid), MINOR(vchiq_devid));
+
+ bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
++ if (IS_ERR(bcm2835_camera))
++ bcm2835_camera = NULL;
+
+ return 0;
+
+@@ -3670,8 +3672,9 @@ failed_platform_init:
+
+ static int vchiq_remove(struct platform_device *pdev)
+ {
+- if (!IS_ERR(bcm2835_camera))
+- platform_device_unregister(bcm2835_camera);
++ platform_device_unregister(bcm2835_codec);
++ platform_device_unregister(bcm2835_camera);
++ platform_device_unregister(vcsm_cma);
+ vchiq_debugfs_deinit();
+ device_destroy(vchiq_class, vchiq_devid);
+ class_destroy(vchiq_class);
--- /dev/null
+From 522f1499310d389e663a4e8dd0ccbb916b768766 Mon Sep 17 00:00:00 2001
+Date: Wed, 14 Feb 2018 17:04:26 +0000
+Subject: [PATCH] staging: bcm2835-camera: Do not bulk receive from
+ service thread
+
+vchi_bulk_queue_receive will queue up to a default of 4
+bulk receives on a connection before blocking.
+If called from the VCHI service_callback thread, then
+that thread is unable to service the VCHI_CALLBACK_BULK_RECEIVED
+events that would enable the queue call to succeed.
+
+Add a workqueue to schedule the call vchi_bulk_queue_receive
+in an alternate context to avoid the lock up.
+
+---
+ .../vc04_services/bcm2835-camera/mmal-vchiq.c | 101 ++++++++++--------
+ 1 file changed, 59 insertions(+), 42 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
+@@ -118,8 +118,10 @@ struct mmal_msg_context {
+
+ union {
+ struct {
+- /* work struct for defered callback - must come first */
++ /* work struct for buffer_cb callback */
+ struct work_struct work;
++ /* work struct for deferred callback */
++ struct work_struct buffer_to_host_work;
+ /* mmal instance */
+ struct vchiq_mmal_instance *instance;
+ /* mmal port */
+@@ -168,6 +170,9 @@ struct vchiq_mmal_instance {
+ /* component to use next */
+ int component_idx;
+ struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
++
++ /* ordered workqueue to process all bulk operations */
++ struct workqueue_struct *bulk_wq;
+ };
+
+ static struct mmal_msg_context *
+@@ -251,7 +256,44 @@ static void buffer_work_cb(struct work_s
+ msg_context->u.bulk.mmal_flags,
+ msg_context->u.bulk.dts,
+ msg_context->u.bulk.pts);
++}
+
++/* workqueue scheduled callback to handle receiving buffers
++ *
++ * VCHI will allow up to 4 bulk receives to be scheduled before blocking.
++ * If we block in the service_callback context then we can't process the
++ * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked
++ * vchi_bulk_queue_receive() call to complete.
++ */
++static void buffer_to_host_work_cb(struct work_struct *work)
++{
++ struct mmal_msg_context *msg_context =
++ container_of(work, struct mmal_msg_context,
++ u.bulk.buffer_to_host_work);
++ struct vchiq_mmal_instance *instance = msg_context->instance;
++ unsigned long len = msg_context->u.bulk.buffer_used;
++ int ret;
++
++ if (!len)
++ /* Dummy receive to ensure the buffers remain in order */
++ len = 8;
++ /* queue the bulk submission */
++ vchi_service_use(instance->handle);
++ ret = vchi_bulk_queue_receive(instance->handle,
++ msg_context->u.bulk.buffer->buffer,
++ /* Actual receive needs to be a multiple
++ * of 4 bytes
++ */
++ (len + 3) & ~3,
++ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
++ msg_context);
++
++ vchi_service_release(instance->handle);
++
++ if (ret != 0)
++ pr_err("%s: ctx: %p, vchi_bulk_queue_receive failed %d\n",
++ __func__, msg_context, ret);
+ }
+
+ /* enqueue a bulk receive for a given message context */
+@@ -260,7 +302,6 @@ static int bulk_receive(struct vchiq_mma
+ struct mmal_msg_context *msg_context)
+ {
+ unsigned long rd_len;
+- int ret;
+
+ rd_len = msg->u.buffer_from_host.buffer_header.length;
+
+@@ -294,45 +335,10 @@ static int bulk_receive(struct vchiq_mma
+ msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
+ msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
+
+- /* queue the bulk submission */
+- vchi_service_use(instance->handle);
+- ret = vchi_bulk_queue_receive(instance->handle,
+- msg_context->u.bulk.buffer->buffer,
+- /* Actual receive needs to be a multiple
+- * of 4 bytes
+- */
+- (rd_len + 3) & ~3,
+- VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
+- VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
+- msg_context);
+-
+- vchi_service_release(instance->handle);
++ queue_work(msg_context->instance->bulk_wq,
++ &msg_context->u.bulk.buffer_to_host_work);
+
+- return ret;
+-}
+-
+-/* enque a dummy bulk receive for a given message context */
+-static int dummy_bulk_receive(struct vchiq_mmal_instance *instance,
+- struct mmal_msg_context *msg_context)
+-{
+- int ret;
+-
+- /* zero length indicates this was a dummy transfer */
+- msg_context->u.bulk.buffer_used = 0;
+-
+- /* queue the bulk submission */
+- vchi_service_use(instance->handle);
+-
+- ret = vchi_bulk_queue_receive(instance->handle,
+- instance->bulk_scratch,
+- 8,
+- VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
+- VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
+- msg_context);
+-
+- vchi_service_release(instance->handle);
+-
+- return ret;
++ return 0;
+ }
+
+ /* data in message, memcpy from packet into output buffer */
+@@ -380,6 +386,8 @@ buffer_from_host(struct vchiq_mmal_insta
+
+ /* initialise work structure ready to schedule callback */
+ INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
++ INIT_WORK(&msg_context->u.bulk.buffer_to_host_work,
++ buffer_to_host_work_cb);
+
+ atomic_inc(&port->buffers_with_vpu);
+
+@@ -465,7 +473,7 @@ static void buffer_to_host_cb(struct vch
+ if (msg->u.buffer_from_host.buffer_header.flags &
+ MMAL_BUFFER_HEADER_FLAG_EOS) {
+ msg_context->u.bulk.status =
+- dummy_bulk_receive(instance, msg_context);
++ bulk_receive(instance, msg, msg_context);
+ if (msg_context->u.bulk.status == 0)
+ return; /* successful bulk submission, bulk
+ * completion will trigger callback
+@@ -1789,6 +1797,9 @@ int vchiq_mmal_finalise(struct vchiq_mma
+
+ mutex_unlock(&instance->vchiq_mutex);
+
++ flush_workqueue(instance->bulk_wq);
++ destroy_workqueue(instance->bulk_wq);
++
+ vfree(instance->bulk_scratch);
+
+ idr_destroy(&instance->context_map);
+@@ -1858,6 +1869,11 @@ int vchiq_mmal_init(struct vchiq_mmal_in
+
+ params.callback_param = instance;
+
++ instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq",
++ WQ_MEM_RECLAIM);
++ if (!instance->bulk_wq)
++ goto err_free;
++
+ status = vchi_service_open(vchi_instance, ¶ms, &instance->handle);
+ if (status) {
+ pr_err("Failed to open VCHI service connection (status=%d)\n",
+@@ -1872,8 +1888,9 @@ int vchiq_mmal_init(struct vchiq_mmal_in
+ return 0;
+
+ err_close_services:
+-
+ vchi_service_close(instance->handle);
++ destroy_workqueue(instance->bulk_wq);
++err_free:
+ vfree(instance->bulk_scratch);
+ kfree(instance);
+ return -ENODEV;
--- /dev/null
+From bf5bbfec3cb99c469eb59f2b19411146c47feb73 Mon Sep 17 00:00:00 2001
+Date: Mon, 29 Oct 2018 14:21:04 +0000
+Subject: [PATCH] staging: bcm2835-camera: Ensure H264 header bytes get
+ a sensible timestamp
+
+H264 header come from VC with 0 timestamps, which means they get a
+strange timestamp when processed with VC/kernel start times,
+particularly if used with the inline header option.
+Remember the last frame timestamp and use that if set, or otherwise
+use the kernel start time.
+
+https://github.com/raspberrypi/linux/issues/1836
+
+---
+ .../bcm2835-camera/bcm2835-camera.c | 30 +++++++++++++++++--
+ .../bcm2835-camera/bcm2835-camera.h | 2 ++
+ 2 files changed, 29 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -363,8 +363,13 @@ static void buffer_cb(struct vchiq_mmal_
+ }
+ } else {
+ if (dev->capture.frame_count) {
+- if (dev->capture.vc_start_timestamp != -1 &&
+- pts != 0) {
++ if (dev->capture.vc_start_timestamp == -1) {
++ buf->vb.vb2_buf.timestamp = ktime_get_ns();
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Buffer time set as current time - %lld",
++ buf->vb.vb2_buf.timestamp);
++
++ } else if (pts != 0) {
+ ktime_t timestamp;
+ s64 runtime_us = pts -
+ dev->capture.vc_start_timestamp;
+@@ -377,10 +382,28 @@ static void buffer_cb(struct vchiq_mmal_
+ ktime_to_ns(timestamp));
+ buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
+ } else {
+- buf->vb.vb2_buf.timestamp = ktime_get_ns();
++ if (dev->capture.last_timestamp) {
++ buf->vb.vb2_buf.timestamp =
++ dev->capture.last_timestamp;
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ "Buffer time set as last timestamp - %lld",
++ buf->vb.vb2_buf.timestamp);
++ } else {
++ buf->vb.vb2_buf.timestamp =
++ ktime_to_ns(dev->capture.kernel_start_ts);
++ v4l2_dbg(1, bcm2835_v4l2_debug,
++ &dev->v4l2_dev,
++ "Buffer time set as start timestamp - %lld",
++ buf->vb.vb2_buf.timestamp);
++ }
+ }
++ dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
+
+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Buffer has ts %llu",
++ dev->capture.last_timestamp);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
+@@ -546,6 +569,7 @@ static int start_streaming(struct vb2_qu
+ dev->capture.vc_start_timestamp, parameter_size);
+
+ dev->capture.kernel_start_ts = ktime_get();
++ dev->capture.last_timestamp = 0;
+
+ /* enable the camera port */
+ dev->capture.port->cb_ctx = dev;
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
+@@ -90,6 +90,8 @@ struct bm2835_mmal_dev {
+ s64 vc_start_timestamp;
+ /* Kernel start timestamp for streaming */
+ ktime_t kernel_start_ts;
++ /* Timestamp of last frame */
++ u64 last_timestamp;
+
+ struct vchiq_mmal_port *port; /* port being used for capture */
+ /* camera port being used for capture */
+++ /dev/null
-From 73979b06255c3b7b536a53d09ea095aec8ed37aa Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Dec 2018 12:50:38 +0000
-Subject: [PATCH] staging: vchiq_arm: Improve error handling on loading
- drivers
-
-The handling of loading platform drivers requires checking IS_ERR
-for the pointer on unload.
-If the driver fails to load, NULL the pointer during probe as
-platform_device_unregister already checks for NULL.
-
----
- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 12 ++++++++----
- 1 file changed, 8 insertions(+), 4 deletions(-)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -3654,6 +3654,8 @@ static int vchiq_probe(struct platform_d
- MAJOR(vchiq_devid), MINOR(vchiq_devid));
-
- bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
-+ if (IS_ERR(bcm2835_camera))
-+ bcm2835_camera = NULL;
-
- return 0;
-
-@@ -3670,8 +3672,9 @@ failed_platform_init:
-
- static int vchiq_remove(struct platform_device *pdev)
- {
-- if (!IS_ERR(bcm2835_camera))
-- platform_device_unregister(bcm2835_camera);
-+ platform_device_unregister(bcm2835_codec);
-+ platform_device_unregister(bcm2835_camera);
-+ platform_device_unregister(vcsm_cma);
- vchiq_debugfs_deinit();
- device_destroy(vchiq_class, vchiq_devid);
- class_destroy(vchiq_class);
--- /dev/null
+From 6c70a89ac19b1ead96be68002affcd1821014d52 Mon Sep 17 00:00:00 2001
+Date: Mon, 13 Feb 2017 13:11:41 +0000
+Subject: [PATCH] staging: bcm2835-camera: Correctly denote key frames
+ in encoded data
+
+Forward MMAL key frame flags to the V4L2 buffers.
+
+---
+ drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -401,6 +401,9 @@ static void buffer_cb(struct vchiq_mmal_
+ dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
+
+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
++ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
++ buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
++
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Buffer has ts %llu",
+ dev->capture.last_timestamp);
+++ /dev/null
-From 522f1499310d389e663a4e8dd0ccbb916b768766 Mon Sep 17 00:00:00 2001
-Date: Wed, 14 Feb 2018 17:04:26 +0000
-Subject: [PATCH] staging: bcm2835-camera: Do not bulk receive from
- service thread
-
-vchi_bulk_queue_receive will queue up to a default of 4
-bulk receives on a connection before blocking.
-If called from the VCHI service_callback thread, then
-that thread is unable to service the VCHI_CALLBACK_BULK_RECEIVED
-events that would enable the queue call to succeed.
-
-Add a workqueue to schedule the call vchi_bulk_queue_receive
-in an alternate context to avoid the lock up.
-
----
- .../vc04_services/bcm2835-camera/mmal-vchiq.c | 101 ++++++++++--------
- 1 file changed, 59 insertions(+), 42 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
-@@ -118,8 +118,10 @@ struct mmal_msg_context {
-
- union {
- struct {
-- /* work struct for defered callback - must come first */
-+ /* work struct for buffer_cb callback */
- struct work_struct work;
-+ /* work struct for deferred callback */
-+ struct work_struct buffer_to_host_work;
- /* mmal instance */
- struct vchiq_mmal_instance *instance;
- /* mmal port */
-@@ -168,6 +170,9 @@ struct vchiq_mmal_instance {
- /* component to use next */
- int component_idx;
- struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
-+
-+ /* ordered workqueue to process all bulk operations */
-+ struct workqueue_struct *bulk_wq;
- };
-
- static struct mmal_msg_context *
-@@ -251,7 +256,44 @@ static void buffer_work_cb(struct work_s
- msg_context->u.bulk.mmal_flags,
- msg_context->u.bulk.dts,
- msg_context->u.bulk.pts);
-+}
-
-+/* workqueue scheduled callback to handle receiving buffers
-+ *
-+ * VCHI will allow up to 4 bulk receives to be scheduled before blocking.
-+ * If we block in the service_callback context then we can't process the
-+ * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked
-+ * vchi_bulk_queue_receive() call to complete.
-+ */
-+static void buffer_to_host_work_cb(struct work_struct *work)
-+{
-+ struct mmal_msg_context *msg_context =
-+ container_of(work, struct mmal_msg_context,
-+ u.bulk.buffer_to_host_work);
-+ struct vchiq_mmal_instance *instance = msg_context->instance;
-+ unsigned long len = msg_context->u.bulk.buffer_used;
-+ int ret;
-+
-+ if (!len)
-+ /* Dummy receive to ensure the buffers remain in order */
-+ len = 8;
-+ /* queue the bulk submission */
-+ vchi_service_use(instance->handle);
-+ ret = vchi_bulk_queue_receive(instance->handle,
-+ msg_context->u.bulk.buffer->buffer,
-+ /* Actual receive needs to be a multiple
-+ * of 4 bytes
-+ */
-+ (len + 3) & ~3,
-+ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
-+ msg_context);
-+
-+ vchi_service_release(instance->handle);
-+
-+ if (ret != 0)
-+ pr_err("%s: ctx: %p, vchi_bulk_queue_receive failed %d\n",
-+ __func__, msg_context, ret);
- }
-
- /* enqueue a bulk receive for a given message context */
-@@ -260,7 +302,6 @@ static int bulk_receive(struct vchiq_mma
- struct mmal_msg_context *msg_context)
- {
- unsigned long rd_len;
-- int ret;
-
- rd_len = msg->u.buffer_from_host.buffer_header.length;
-
-@@ -294,45 +335,10 @@ static int bulk_receive(struct vchiq_mma
- msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
- msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
-
-- /* queue the bulk submission */
-- vchi_service_use(instance->handle);
-- ret = vchi_bulk_queue_receive(instance->handle,
-- msg_context->u.bulk.buffer->buffer,
-- /* Actual receive needs to be a multiple
-- * of 4 bytes
-- */
-- (rd_len + 3) & ~3,
-- VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
-- VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
-- msg_context);
--
-- vchi_service_release(instance->handle);
-+ queue_work(msg_context->instance->bulk_wq,
-+ &msg_context->u.bulk.buffer_to_host_work);
-
-- return ret;
--}
--
--/* enque a dummy bulk receive for a given message context */
--static int dummy_bulk_receive(struct vchiq_mmal_instance *instance,
-- struct mmal_msg_context *msg_context)
--{
-- int ret;
--
-- /* zero length indicates this was a dummy transfer */
-- msg_context->u.bulk.buffer_used = 0;
--
-- /* queue the bulk submission */
-- vchi_service_use(instance->handle);
--
-- ret = vchi_bulk_queue_receive(instance->handle,
-- instance->bulk_scratch,
-- 8,
-- VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
-- VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
-- msg_context);
--
-- vchi_service_release(instance->handle);
--
-- return ret;
-+ return 0;
- }
-
- /* data in message, memcpy from packet into output buffer */
-@@ -380,6 +386,8 @@ buffer_from_host(struct vchiq_mmal_insta
-
- /* initialise work structure ready to schedule callback */
- INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
-+ INIT_WORK(&msg_context->u.bulk.buffer_to_host_work,
-+ buffer_to_host_work_cb);
-
- atomic_inc(&port->buffers_with_vpu);
-
-@@ -465,7 +473,7 @@ static void buffer_to_host_cb(struct vch
- if (msg->u.buffer_from_host.buffer_header.flags &
- MMAL_BUFFER_HEADER_FLAG_EOS) {
- msg_context->u.bulk.status =
-- dummy_bulk_receive(instance, msg_context);
-+ bulk_receive(instance, msg, msg_context);
- if (msg_context->u.bulk.status == 0)
- return; /* successful bulk submission, bulk
- * completion will trigger callback
-@@ -1789,6 +1797,9 @@ int vchiq_mmal_finalise(struct vchiq_mma
-
- mutex_unlock(&instance->vchiq_mutex);
-
-+ flush_workqueue(instance->bulk_wq);
-+ destroy_workqueue(instance->bulk_wq);
-+
- vfree(instance->bulk_scratch);
-
- idr_destroy(&instance->context_map);
-@@ -1858,6 +1869,11 @@ int vchiq_mmal_init(struct vchiq_mmal_in
-
- params.callback_param = instance;
-
-+ instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq",
-+ WQ_MEM_RECLAIM);
-+ if (!instance->bulk_wq)
-+ goto err_free;
-+
- status = vchi_service_open(vchi_instance, ¶ms, &instance->handle);
- if (status) {
- pr_err("Failed to open VCHI service connection (status=%d)\n",
-@@ -1872,8 +1888,9 @@ int vchiq_mmal_init(struct vchiq_mmal_in
- return 0;
-
- err_close_services:
--
- vchi_service_close(instance->handle);
-+ destroy_workqueue(instance->bulk_wq);
-+err_free:
- vfree(instance->bulk_scratch);
- kfree(instance);
- return -ENODEV;
+++ /dev/null
-From bf5bbfec3cb99c469eb59f2b19411146c47feb73 Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Oct 2018 14:21:04 +0000
-Subject: [PATCH] staging: bcm2835-camera: Ensure H264 header bytes get
- a sensible timestamp
-
-H264 header come from VC with 0 timestamps, which means they get a
-strange timestamp when processed with VC/kernel start times,
-particularly if used with the inline header option.
-Remember the last frame timestamp and use that if set, or otherwise
-use the kernel start time.
-
-https://github.com/raspberrypi/linux/issues/1836
-
----
- .../bcm2835-camera/bcm2835-camera.c | 30 +++++++++++++++++--
- .../bcm2835-camera/bcm2835-camera.h | 2 ++
- 2 files changed, 29 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -363,8 +363,13 @@ static void buffer_cb(struct vchiq_mmal_
- }
- } else {
- if (dev->capture.frame_count) {
-- if (dev->capture.vc_start_timestamp != -1 &&
-- pts != 0) {
-+ if (dev->capture.vc_start_timestamp == -1) {
-+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Buffer time set as current time - %lld",
-+ buf->vb.vb2_buf.timestamp);
-+
-+ } else if (pts != 0) {
- ktime_t timestamp;
- s64 runtime_us = pts -
- dev->capture.vc_start_timestamp;
-@@ -377,10 +382,28 @@ static void buffer_cb(struct vchiq_mmal_
- ktime_to_ns(timestamp));
- buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
- } else {
-- buf->vb.vb2_buf.timestamp = ktime_get_ns();
-+ if (dev->capture.last_timestamp) {
-+ buf->vb.vb2_buf.timestamp =
-+ dev->capture.last_timestamp;
-+ v4l2_dbg(1, bcm2835_v4l2_debug,
-+ &dev->v4l2_dev,
-+ "Buffer time set as last timestamp - %lld",
-+ buf->vb.vb2_buf.timestamp);
-+ } else {
-+ buf->vb.vb2_buf.timestamp =
-+ ktime_to_ns(dev->capture.kernel_start_ts);
-+ v4l2_dbg(1, bcm2835_v4l2_debug,
-+ &dev->v4l2_dev,
-+ "Buffer time set as start timestamp - %lld",
-+ buf->vb.vb2_buf.timestamp);
-+ }
- }
-+ dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
-
- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Buffer has ts %llu",
-+ dev->capture.last_timestamp);
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
-
- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
-@@ -546,6 +569,7 @@ static int start_streaming(struct vb2_qu
- dev->capture.vc_start_timestamp, parameter_size);
-
- dev->capture.kernel_start_ts = ktime_get();
-+ dev->capture.last_timestamp = 0;
-
- /* enable the camera port */
- dev->capture.port->cb_ctx = dev;
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
-@@ -90,6 +90,8 @@ struct bm2835_mmal_dev {
- s64 vc_start_timestamp;
- /* Kernel start timestamp for streaming */
- ktime_t kernel_start_ts;
-+ /* Timestamp of last frame */
-+ u64 last_timestamp;
-
- struct vchiq_mmal_port *port; /* port being used for capture */
- /* camera port being used for capture */
--- /dev/null
+From 3cb19cb6b4d6dc86582abef6200c0fc663ae3f2a Mon Sep 17 00:00:00 2001
+Date: Fri, 10 Mar 2017 17:27:56 +0000
+Subject: [PATCH] staging: bcm2835-camera: Return early on errors
+
+Fix several instances where it is easier to return
+early on error conditions than handle it as an else
+clause.
+As requested by Mauro.
+
+---
+ .../bcm2835-camera/bcm2835-camera.c | 137 +++++++++---------
+ 1 file changed, 71 insertions(+), 66 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -335,7 +335,9 @@ static void buffer_cb(struct vchiq_mmal_
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+ return;
+- } else if (length == 0) {
++ }
++
++ if (length == 0) {
+ /* stream ended */
+ if (dev->capture.frame_count) {
+ /* empty buffer whilst capturing - expected to be an
+@@ -361,71 +363,72 @@ static void buffer_cb(struct vchiq_mmal_
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ complete(&dev->capture.frame_cmplt);
+ }
+- } else {
+- if (dev->capture.frame_count) {
+- if (dev->capture.vc_start_timestamp == -1) {
+- buf->vb.vb2_buf.timestamp = ktime_get_ns();
+- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+- "Buffer time set as current time - %lld",
+- buf->vb.vb2_buf.timestamp);
+-
+- } else if (pts != 0) {
+- ktime_t timestamp;
+- s64 runtime_us = pts -
+- dev->capture.vc_start_timestamp;
+- timestamp = ktime_add_us(dev->capture.kernel_start_ts,
+- runtime_us);
+- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+- "Convert start time %llu and %llu with offset %llu to %llu\n",
+- ktime_to_ns(dev->capture.kernel_start_ts),
+- dev->capture.vc_start_timestamp, pts,
+- ktime_to_ns(timestamp));
+- buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
+- } else {
+- if (dev->capture.last_timestamp) {
+- buf->vb.vb2_buf.timestamp =
+- dev->capture.last_timestamp;
+- v4l2_dbg(1, bcm2835_v4l2_debug,
+- &dev->v4l2_dev,
+- "Buffer time set as last timestamp - %lld",
+- buf->vb.vb2_buf.timestamp);
+- } else {
+- buf->vb.vb2_buf.timestamp =
+- ktime_to_ns(dev->capture.kernel_start_ts);
+- v4l2_dbg(1, bcm2835_v4l2_debug,
+- &dev->v4l2_dev,
+- "Buffer time set as start timestamp - %lld",
+- buf->vb.vb2_buf.timestamp);
+- }
+- }
+- dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
++ return;
++ }
+
+- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
+- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+- buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
++ if (!dev->capture.frame_count) {
++ /* signal frame completion */
++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
++ complete(&dev->capture.frame_cmplt);
++ return;
++ }
+
++ if (dev->capture.vc_start_timestamp == -1) {
++ /*
++ * VPU doesn't support MMAL_PARAMETER_SYSTEM_TIME, rely on
++ * kernel time, and have no latency compensation.
++ */
++ buf->vb.vb2_buf.timestamp = ktime_get_ns();
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Buffer time set as current time - %lld",
++ buf->vb.vb2_buf.timestamp);
++ } else if (pts != 0) {
++ ktime_t timestamp;
++ s64 runtime_us = pts -
++ dev->capture.vc_start_timestamp;
++ timestamp = ktime_add_us(dev->capture.kernel_start_ts,
++ runtime_us);
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Convert start time %llu and %llu with offset %llu to %llu\n",
++ ktime_to_ns(dev->capture.kernel_start_ts),
++ dev->capture.vc_start_timestamp, pts,
++ ktime_to_ns(timestamp));
++ buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
++ } else {
++ if (dev->capture.last_timestamp) {
++ buf->vb.vb2_buf.timestamp = dev->capture.last_timestamp;
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+- "Buffer has ts %llu",
+- dev->capture.last_timestamp);
+- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+-
+- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
+- is_capturing(dev)) {
+- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+- "Grab another frame as buffer has EOS");
+- vchiq_mmal_port_parameter_set(
+- instance,
+- dev->capture.camera_port,
+- MMAL_PARAMETER_CAPTURE,
+- &dev->capture.frame_count,
+- sizeof(dev->capture.frame_count));
+- }
++ "Buffer time set as last timestamp - %lld",
++ buf->vb.vb2_buf.timestamp);
+ } else {
+- /* signal frame completion */
+- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+- complete(&dev->capture.frame_cmplt);
++ buf->vb.vb2_buf.timestamp =
++ ktime_to_ns(dev->capture.kernel_start_ts);
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Buffer time set as start timestamp - %lld",
++ buf->vb.vb2_buf.timestamp);
+ }
+ }
++ dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
++
++ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
++ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
++ buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
++
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Buffer has ts %llu",
++ dev->capture.last_timestamp);
++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
++
++ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
++ is_capturing(dev)) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Grab another frame as buffer has EOS");
++ vchiq_mmal_port_parameter_set(instance,
++ dev->capture.camera_port,
++ MMAL_PARAMETER_CAPTURE,
++ &dev->capture.frame_count,
++ sizeof(dev->capture.frame_count));
++ }
+ }
+
+ static int enable_camera(struct bm2835_mmal_dev *dev)
+@@ -815,27 +818,29 @@ static int vidioc_overlay(struct file *f
+
+ ret = vchiq_mmal_port_set_format(dev->instance, src);
+ if (ret < 0)
+- goto error;
++ return ret;
+
+ ret = set_overlay_params(dev, dst);
+ if (ret < 0)
+- goto error;
++ return ret;
+
+- if (enable_camera(dev) < 0)
+- goto error;
++ if (enable_camera(dev) < 0) {
++ ret = -EINVAL;
++ return ret;
++ }
+
+ ret = vchiq_mmal_component_enable(
+ dev->instance,
+ dev->component[MMAL_COMPONENT_PREVIEW]);
+ if (ret < 0)
+- goto error;
++ return ret;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "connecting %p to %p\n",
+ src, dst);
+ ret = vchiq_mmal_port_connect_tunnel(dev->instance, src, dst);
+ if (!ret)
+ ret = vchiq_mmal_port_enable(dev->instance, src, NULL);
+-error:
++
+ return ret;
+ }
+
+++ /dev/null
-From 6c70a89ac19b1ead96be68002affcd1821014d52 Mon Sep 17 00:00:00 2001
-Date: Mon, 13 Feb 2017 13:11:41 +0000
-Subject: [PATCH] staging: bcm2835-camera: Correctly denote key frames
- in encoded data
-
-Forward MMAL key frame flags to the V4L2 buffers.
-
----
- drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -401,6 +401,9 @@ static void buffer_cb(struct vchiq_mmal_
- dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
-
- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
-+ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
-+ buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
-+
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Buffer has ts %llu",
- dev->capture.last_timestamp);
--- /dev/null
+From b1d4e377b4a8c73396d50c45106f3d3a710b11f5 Mon Sep 17 00:00:00 2001
+Date: Fri, 10 Mar 2017 17:35:38 +0000
+Subject: [PATCH] staging: bcm2835-camera: Remove dead email addresses
+
+None of the listed author email addresses were valid.
+Keep list of authors and the companies they represented.
+Update my email address.
+
+---
+ .../vc04_services/bcm2835-camera/bcm2835-camera.c | 9 +++++----
+ .../vc04_services/bcm2835-camera/bcm2835-camera.h | 9 +++++----
+ drivers/staging/vc04_services/bcm2835-camera/controls.c | 9 +++++----
+ .../staging/vc04_services/bcm2835-camera/mmal-common.h | 9 +++++----
+ .../vc04_services/bcm2835-camera/mmal-encodings.h | 9 +++++----
+ .../vc04_services/bcm2835-camera/mmal-msg-common.h | 9 +++++----
+ .../vc04_services/bcm2835-camera/mmal-msg-format.h | 9 +++++----
+ .../staging/vc04_services/bcm2835-camera/mmal-msg-port.h | 9 +++++----
+ drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h | 9 +++++----
+ .../vc04_services/bcm2835-camera/mmal-parameters.h | 9 +++++----
+ .../staging/vc04_services/bcm2835-camera/mmal-vchiq.c | 9 +++++----
+ .../staging/vc04_services/bcm2835-camera/mmal-vchiq.h | 9 +++++----
+ 12 files changed, 60 insertions(+), 48 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -4,10 +4,11 @@
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
+ */
+
+ #include <linux/errno.h>
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
+@@ -4,10 +4,11 @@
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
+ *
+ * core driver device
+ */
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -4,10 +4,11 @@
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
+ */
+
+ #include <linux/errno.h>
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
+@@ -4,10 +4,11 @@
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
+ *
+ * MMAL structures
+ *
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h
+@@ -4,10 +4,11 @@
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
+ */
+ #ifndef MMAL_ENCODINGS_H
+ #define MMAL_ENCODINGS_H
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h
+@@ -4,10 +4,11 @@
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
+ */
+
+ #ifndef MMAL_MSG_COMMON_H
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
+@@ -4,10 +4,11 @@
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
+ */
+
+ #ifndef MMAL_MSG_FORMAT_H
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
+@@ -4,10 +4,11 @@
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
+ */
+
+ /* MMAL_PORT_TYPE_T */
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
+@@ -4,10 +4,11 @@
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
+ */
+
+ /* all the data structures which serialise the MMAL protocol. note
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
+@@ -4,10 +4,11 @@
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
+ */
+
+ /* common parameters */
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
+@@ -4,10 +4,11 @@
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
+ *
+ * V4L2 driver MMAL vchiq interface code
+ */
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
+@@ -4,10 +4,11 @@
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
+ *
+ * MMAL interface to VCHIQ message passing
+ */
--- /dev/null
+From 4fb0df1b29feafacc244ca512b152dd3b96c224c Mon Sep 17 00:00:00 2001
+Date: Wed, 21 Feb 2018 13:49:32 +0000
+Subject: [PATCH] staging: bcm2835-camera: Fix comment style
+ violations.
+
+Fix comment style violations in the header files.
+
+---
+ .../bcm2835-camera/mmal-msg-format.h | 95 ++++++------
+ .../bcm2835-camera/mmal-msg-port.h | 124 ++++++++--------
+ .../vc04_services/bcm2835-camera/mmal-msg.h | 135 +++++++++---------
+ 3 files changed, 185 insertions(+), 169 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
+@@ -19,22 +19,23 @@
+ /* MMAL_ES_FORMAT_T */
+
+ struct mmal_audio_format {
+- u32 channels; /**< Number of audio channels */
+- u32 sample_rate; /**< Sample rate */
++ u32 channels; /* Number of audio channels */
++ u32 sample_rate; /* Sample rate */
+
+- u32 bits_per_sample; /**< Bits per sample */
+- u32 block_align; /**< Size of a block of data */
++ u32 bits_per_sample; /* Bits per sample */
++ u32 block_align; /* Size of a block of data */
+ };
+
+ struct mmal_video_format {
+- u32 width; /**< Width of frame in pixels */
+- u32 height; /**< Height of frame in rows of pixels */
+- struct mmal_rect crop; /**< Visible region of the frame */
+- struct mmal_rational frame_rate; /**< Frame rate */
+- struct mmal_rational par; /**< Pixel aspect ratio */
+-
+- /* FourCC specifying the color space of the video stream. See the
+- * \ref MmalColorSpace "pre-defined color spaces" for some examples.
++ u32 width; /* Width of frame in pixels */
++ u32 height; /* Height of frame in rows of pixels */
++ struct mmal_rect crop; /* Visible region of the frame */
++ struct mmal_rational frame_rate; /* Frame rate */
++ struct mmal_rational par; /* Pixel aspect ratio */
++
++ /*
++ * FourCC specifying the color space of the video stream. See the
++ * MmalColorSpace "pre-defined color spaces" for some examples.
+ */
+ u32 color_space;
+ };
+@@ -50,48 +51,56 @@ union mmal_es_specific_format {
+ struct mmal_subpicture_format subpicture;
+ };
+
+-/** Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
++/* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
+ struct mmal_es_format_local {
+- u32 type; /* enum mmal_es_type */
+-
+- u32 encoding; /* FourCC specifying encoding of the elementary stream.*/
+- u32 encoding_variant; /* FourCC specifying the specific
+- * encoding variant of the elementary
+- * stream.
+- */
+-
+- union mmal_es_specific_format *es; /* Type specific
+- * information for the
+- * elementary stream
+- */
++ u32 type; /* enum mmal_es_type */
+
+- u32 bitrate; /**< Bitrate in bits per second */
+- u32 flags; /**< Flags describing properties of the elementary stream. */
++ u32 encoding; /* FourCC specifying encoding of the elementary
++ * stream.
++ */
++ u32 encoding_variant; /* FourCC specifying the specific
++ * encoding variant of the elementary
++ * stream.
++ */
++
++ union mmal_es_specific_format *es; /* Type specific
++ * information for the
++ * elementary stream
++ */
++
++ u32 bitrate; /* Bitrate in bits per second */
++ u32 flags; /* Flags describing properties of the elementary
++ * stream.
++ */
+
+- u32 extradata_size; /**< Size of the codec specific data */
+- u8 *extradata; /**< Codec specific data */
++ u32 extradata_size; /* Size of the codec specific data */
++ u8 *extradata; /* Codec specific data */
+ };
+
+-/** Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
++/* Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
+ struct mmal_es_format {
+- u32 type; /* enum mmal_es_type */
++ u32 type; /* enum mmal_es_type */
+
+- u32 encoding; /* FourCC specifying encoding of the elementary stream.*/
+- u32 encoding_variant; /* FourCC specifying the specific
+- * encoding variant of the elementary
+- * stream.
+- */
++ u32 encoding; /* FourCC specifying encoding of the elementary
++ * stream.
++ */
++ u32 encoding_variant; /* FourCC specifying the specific
++ * encoding variant of the elementary
++ * stream.
++ */
+
+- u32 es; /* Type specific
++ u32 es; /* Type specific
+ * information for the
+ * elementary stream
+ */
+
+- u32 bitrate; /**< Bitrate in bits per second */
+- u32 flags; /**< Flags describing properties of the elementary stream. */
++ u32 bitrate; /* Bitrate in bits per second */
++ u32 flags; /* Flags describing properties of the elementary
++ * stream.
++ */
+
+- u32 extradata_size; /**< Size of the codec specific data */
+- u32 extradata; /**< Codec specific data */
++ u32 extradata_size; /* Size of the codec specific data */
++ u32 extradata; /* Codec specific data */
+ };
+
+ #endif /* MMAL_MSG_FORMAT_H */
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
+@@ -13,28 +13,31 @@
+
+ /* MMAL_PORT_TYPE_T */
+ enum mmal_port_type {
+- MMAL_PORT_TYPE_UNKNOWN = 0, /**< Unknown port type */
+- MMAL_PORT_TYPE_CONTROL, /**< Control port */
+- MMAL_PORT_TYPE_INPUT, /**< Input port */
+- MMAL_PORT_TYPE_OUTPUT, /**< Output port */
+- MMAL_PORT_TYPE_CLOCK, /**< Clock port */
++ MMAL_PORT_TYPE_UNKNOWN = 0, /* Unknown port type */
++ MMAL_PORT_TYPE_CONTROL, /* Control port */
++ MMAL_PORT_TYPE_INPUT, /* Input port */
++ MMAL_PORT_TYPE_OUTPUT, /* Output port */
++ MMAL_PORT_TYPE_CLOCK, /* Clock port */
+ };
+
+-/** The port is pass-through and doesn't need buffer headers allocated */
++/* The port is pass-through and doesn't need buffer headers allocated */
+ #define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01
+-/** The port wants to allocate the buffer payloads.
++/*
++ *The port wants to allocate the buffer payloads.
+ * This signals a preference that payload allocation should be done
+ * on this port for efficiency reasons.
+ */
+ #define MMAL_PORT_CAPABILITY_ALLOCATION 0x02
+-/** The port supports format change events.
++/*
++ * The port supports format change events.
+ * This applies to input ports and is used to let the client know
+ * whether the port supports being reconfigured via a format
+ * change event (i.e. without having to disable the port).
+ */
+ #define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04
+
+-/* mmal port structure (MMAL_PORT_T)
++/*
++ * mmal port structure (MMAL_PORT_T)
+ *
+ * most elements are informational only, the pointer values for
+ * interogation messages are generally provided as additional
+@@ -42,50 +45,50 @@ enum mmal_port_type {
+ * buffer_num, buffer_size and userdata parameters are writable.
+ */
+ struct mmal_port {
+- u32 priv; /* Private member used by the framework */
+- u32 name; /* Port name. Used for debugging purposes (RO) */
++ u32 priv; /* Private member used by the framework */
++ u32 name; /* Port name. Used for debugging purposes (RO) */
+
+- u32 type; /* Type of the port (RO) enum mmal_port_type */
+- u16 index; /* Index of the port in its type list (RO) */
+- u16 index_all; /* Index of the port in the list of all ports (RO) */
+-
+- u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
+- u32 format; /* Format of the elementary stream */
+-
+- u32 buffer_num_min; /* Minimum number of buffers the port
+- * requires (RO). This is set by the
+- * component.
+- */
+-
+- u32 buffer_size_min; /* Minimum size of buffers the port
+- * requires (RO). This is set by the
+- * component.
+- */
+-
+- u32 buffer_alignment_min; /* Minimum alignment requirement for
+- * the buffers (RO). A value of
+- * zero means no special alignment
+- * requirements. This is set by the
+- * component.
+- */
+-
+- u32 buffer_num_recommended; /* Number of buffers the port
+- * recommends for optimal
+- * performance (RO). A value of
+- * zero means no special
+- * recommendation. This is set
+- * by the component.
+- */
+-
+- u32 buffer_size_recommended; /* Size of buffers the port
+- * recommends for optimal
+- * performance (RO). A value of
+- * zero means no special
+- * recommendation. This is set
+- * by the component.
+- */
++ u32 type; /* Type of the port (RO) enum mmal_port_type */
++ u16 index; /* Index of the port in its type list (RO) */
++ u16 index_all; /* Index of the port in the list of all ports (RO) */
++
++ u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
++ u32 format; /* Format of the elementary stream */
++
++ u32 buffer_num_min; /* Minimum number of buffers the port
++ * requires (RO). This is set by the
++ * component.
++ */
++
++ u32 buffer_size_min; /* Minimum size of buffers the port
++ * requires (RO). This is set by the
++ * component.
++ */
++
++ u32 buffer_alignment_min;/* Minimum alignment requirement for
++ * the buffers (RO). A value of
++ * zero means no special alignment
++ * requirements. This is set by the
++ * component.
++ */
++
++ u32 buffer_num_recommended; /* Number of buffers the port
++ * recommends for optimal
++ * performance (RO). A value of
++ * zero means no special
++ * recommendation. This is set
++ * by the component.
++ */
++
++ u32 buffer_size_recommended; /* Size of buffers the port
++ * recommends for optimal
++ * performance (RO). A value of
++ * zero means no special
++ * recommendation. This is set
++ * by the component.
++ */
+
+- u32 buffer_num; /* Actual number of buffers the port will use.
++ u32 buffer_num; /* Actual number of buffers the port will use.
+ * This is set by the client.
+ */
+
+@@ -94,14 +97,13 @@ struct mmal_port {
+ * the client.
+ */
+
+- u32 component; /* Component this port belongs to (Read Only) */
++ u32 component; /* Component this port belongs to (Read Only) */
+
+- u32 userdata; /* Field reserved for use by the client */
+-
+- u32 capabilities; /* Flags describing the capabilities of a
+- * port (RO). Bitwise combination of \ref
+- * portcapabilities "Port capabilities"
+- * values.
+- */
++ u32 userdata; /* Field reserved for use by the client */
+
++ u32 capabilities; /* Flags describing the capabilities of a
++ * port (RO). Bitwise combination of \ref
++ * portcapabilities "Port capabilities"
++ * values.
++ */
+ };
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
+@@ -11,7 +11,8 @@
+ * Luke Diamand @ Broadcom
+ */
+
+-/* all the data structures which serialise the MMAL protocol. note
++/*
++ * all the data structures which serialise the MMAL protocol. note
+ * these are directly mapped onto the recived message data.
+ *
+ * BEWARE: They seem to *assume* pointers are u32 and that there is no
+@@ -41,51 +42,51 @@ enum mmal_msg_type {
+ MMAL_MSG_TYPE_SERVICE_CLOSED,
+ MMAL_MSG_TYPE_GET_VERSION,
+ MMAL_MSG_TYPE_COMPONENT_CREATE,
+- MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
++ MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
+ MMAL_MSG_TYPE_COMPONENT_ENABLE,
+ MMAL_MSG_TYPE_COMPONENT_DISABLE,
+ MMAL_MSG_TYPE_PORT_INFO_GET,
+ MMAL_MSG_TYPE_PORT_INFO_SET,
+- MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
++ MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
+ MMAL_MSG_TYPE_BUFFER_FROM_HOST,
+ MMAL_MSG_TYPE_BUFFER_TO_HOST,
+ MMAL_MSG_TYPE_GET_STATS,
+ MMAL_MSG_TYPE_PORT_PARAMETER_SET,
+- MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
++ MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
+ MMAL_MSG_TYPE_EVENT_TO_HOST,
+ MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT,
+ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR,
+ MMAL_MSG_TYPE_CONSUME_MEM,
+- MMAL_MSG_TYPE_LMK, /* 20 */
++ MMAL_MSG_TYPE_LMK, /* 20 */
+ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC,
+ MMAL_MSG_TYPE_DRM_GET_LHS32,
+ MMAL_MSG_TYPE_DRM_GET_TIME,
+ MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN,
+- MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
++ MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
+ MMAL_MSG_TYPE_HOST_LOG,
+ MMAL_MSG_TYPE_MSG_LAST
+ };
+
+ /* port action request messages differ depending on the action type */
+ enum mmal_msg_port_action_type {
+- MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */
+- MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
+- MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
+- MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
+- MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
+- MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
++ MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */
++ MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
++ MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
++ MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
++ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
++ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
+ MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/
+ };
+
+ struct mmal_msg_header {
+ u32 magic;
+- u32 type; /** enum mmal_msg_type */
++ u32 type; /* enum mmal_msg_type */
+
+ /* Opaque handle to the control service */
+ u32 control_service;
+
+- u32 context; /** a u32 per message context */
+- u32 status; /** The status of the vchiq operation */
++ u32 context; /* a u32 per message context */
++ u32 status; /* The status of the vchiq operation */
+ u32 padding;
+ };
+
+@@ -99,9 +100,9 @@ struct mmal_msg_version {
+
+ /* request to VC to create component */
+ struct mmal_msg_component_create {
+- u32 client_component; /* component context */
++ u32 client_component; /* component context */
+ char name[128];
+- u32 pid; /* For debug */
++ u32 pid; /* For debug */
+ };
+
+ /* reply from VC to component creation request */
+@@ -121,7 +122,7 @@ struct mmal_msg_component_destroy {
+ };
+
+ struct mmal_msg_component_destroy_reply {
+- u32 status; /** The component destruction status */
++ u32 status; /* The component destruction status */
+ };
+
+ /* request and reply to VC to enable a component */
+@@ -130,7 +131,7 @@ struct mmal_msg_component_enable {
+ };
+
+ struct mmal_msg_component_enable_reply {
+- u32 status; /** The component enable status */
++ u32 status; /* The component enable status */
+ };
+
+ /* request and reply to VC to disable a component */
+@@ -139,7 +140,7 @@ struct mmal_msg_component_disable {
+ };
+
+ struct mmal_msg_component_disable_reply {
+- u32 status; /** The component disable status */
++ u32 status; /* The component disable status */
+ };
+
+ /* request to VC to get port information */
+@@ -151,12 +152,12 @@ struct mmal_msg_port_info_get {
+
+ /* reply from VC to get port info request */
+ struct mmal_msg_port_info_get_reply {
+- u32 status; /** enum mmal_msg_status */
+- u32 component_handle; /* component handle port is associated with */
+- u32 port_type; /* enum mmal_msg_port_type */
+- u32 port_index; /* port indexed in query */
+- s32 found; /* unused */
+- u32 port_handle; /**< Handle to use for this port */
++ u32 status; /* enum mmal_msg_status */
++ u32 component_handle; /* component handle port is associated with */
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 port_index; /* port indexed in query */
++ s32 found; /* unused */
++ u32 port_handle; /* Handle to use for this port */
+ struct mmal_port port;
+ struct mmal_es_format format; /* elementary stream format */
+ union mmal_es_specific_format es; /* es type specific data */
+@@ -166,8 +167,8 @@ struct mmal_msg_port_info_get_reply {
+ /* request to VC to set port information */
+ struct mmal_msg_port_info_set {
+ u32 component_handle;
+- u32 port_type; /* enum mmal_msg_port_type */
+- u32 port_index; /* port indexed in query */
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 port_index; /* port indexed in query */
+ struct mmal_port port;
+ struct mmal_es_format format;
+ union mmal_es_specific_format es;
+@@ -177,11 +178,11 @@ struct mmal_msg_port_info_set {
+ /* reply from VC to port info set request */
+ struct mmal_msg_port_info_set_reply {
+ u32 status;
+- u32 component_handle; /* component handle port is associated with */
+- u32 port_type; /* enum mmal_msg_port_type */
+- u32 index; /* port indexed in query */
+- s32 found; /* unused */
+- u32 port_handle; /**< Handle to use for this port */
++ u32 component_handle; /* component handle port is associated with */
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 index; /* port indexed in query */
++ s32 found; /* unused */
++ u32 port_handle; /* Handle to use for this port */
+ struct mmal_port port;
+ struct mmal_es_format format;
+ union mmal_es_specific_format es;
+@@ -192,7 +193,7 @@ struct mmal_msg_port_info_set_reply {
+ struct mmal_msg_port_action_port {
+ u32 component_handle;
+ u32 port_handle;
+- u32 action; /* enum mmal_msg_port_action_type */
++ u32 action; /* enum mmal_msg_port_action_type */
+ struct mmal_port port;
+ };
+
+@@ -200,50 +201,53 @@ struct mmal_msg_port_action_port {
+ struct mmal_msg_port_action_handle {
+ u32 component_handle;
+ u32 port_handle;
+- u32 action; /* enum mmal_msg_port_action_type */
++ u32 action; /* enum mmal_msg_port_action_type */
+ u32 connect_component_handle;
+ u32 connect_port_handle;
+ };
+
+ struct mmal_msg_port_action_reply {
+- u32 status; /** The port action operation status */
++ u32 status; /* The port action operation status */
+ };
+
+ /* MMAL buffer transfer */
+
+-/** Size of space reserved in a buffer message for short messages. */
++/* Size of space reserved in a buffer message for short messages. */
+ #define MMAL_VC_SHORT_DATA 128
+
+-/** Signals that the current payload is the end of the stream of data */
++/* Signals that the current payload is the end of the stream of data */
+ #define MMAL_BUFFER_HEADER_FLAG_EOS BIT(0)
+-/** Signals that the start of the current payload starts a frame */
++/* Signals that the start of the current payload starts a frame */
+ #define MMAL_BUFFER_HEADER_FLAG_FRAME_START BIT(1)
+-/** Signals that the end of the current payload ends a frame */
++/* Signals that the end of the current payload ends a frame */
+ #define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2)
+-/** Signals that the current payload contains only complete frames (>1) */
++/* Signals that the current payload contains only complete frames (>1) */
+ #define MMAL_BUFFER_HEADER_FLAG_FRAME \
+ (MMAL_BUFFER_HEADER_FLAG_FRAME_START|MMAL_BUFFER_HEADER_FLAG_FRAME_END)
+-/** Signals that the current payload is a keyframe (i.e. self decodable) */
++/* Signals that the current payload is a keyframe (i.e. self decodable) */
+ #define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3)
+-/** Signals a discontinuity in the stream of data (e.g. after a seek).
++/*
++ * Signals a discontinuity in the stream of data (e.g. after a seek).
+ * Can be used for instance by a decoder to reset its state
+ */
+ #define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY BIT(4)
+-/** Signals a buffer containing some kind of config data for the component
++/*
++ * Signals a buffer containing some kind of config data for the component
+ * (e.g. codec config data)
+ */
+ #define MMAL_BUFFER_HEADER_FLAG_CONFIG BIT(5)
+-/** Signals an encrypted payload */
++/* Signals an encrypted payload */
+ #define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED BIT(6)
+-/** Signals a buffer containing side information */
++/* Signals a buffer containing side information */
+ #define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO BIT(7)
+-/** Signals a buffer which is the snapshot/postview image from a stills
++/*
++ * Signals a buffer which is the snapshot/postview image from a stills
+ * capture
+ */
+ #define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT BIT(8)
+-/** Signals a buffer which contains data known to be corrupted */
++/* Signals a buffer which contains data known to be corrupted */
+ #define MMAL_BUFFER_HEADER_FLAG_CORRUPTED BIT(9)
+-/** Signals that a buffer failed to be transmitted */
++/* Signals that a buffer failed to be transmitted */
+ #define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED BIT(10)
+
+ struct mmal_driver_buffer {
+@@ -255,8 +259,8 @@ struct mmal_driver_buffer {
+
+ /* buffer header */
+ struct mmal_buffer_header {
+- u32 next; /* next header */
+- u32 priv; /* framework private data */
++ u32 next; /* next header */
++ u32 priv; /* framework private data */
+ u32 cmd;
+ u32 data;
+ u32 alloc_size;
+@@ -281,7 +285,8 @@ struct mmal_buffer_header_type_specific
+ };
+
+ struct mmal_msg_buffer_from_host {
+- /* The front 32 bytes of the buffer header are copied
++ /*
++ *The front 32 bytes of the buffer header are copied
+ * back to us in the reply to allow for context. This
+ * area is used to store two mmal_driver_buffer structures to
+ * allow for multiple concurrent service users.
+@@ -296,7 +301,7 @@ struct mmal_msg_buffer_from_host {
+ s32 is_zero_copy;
+ s32 has_reference;
+
+- /** allows short data to be xfered in control message */
++ /* allows short data to be xfered in control message */
+ u32 payload_in_message;
+ u8 short_data[MMAL_VC_SHORT_DATA];
+ };
+@@ -306,10 +311,10 @@ struct mmal_msg_buffer_from_host {
+ #define MMAL_WORKER_PORT_PARAMETER_SPACE 96
+
+ struct mmal_msg_port_parameter_set {
+- u32 component_handle; /* component */
+- u32 port_handle; /* port */
+- u32 id; /* Parameter ID */
+- u32 size; /* Parameter size */
++ u32 component_handle; /* component */
++ u32 port_handle; /* port */
++ u32 id; /* Parameter ID */
++ u32 size; /* Parameter size */
+ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
+ };
+
+@@ -322,16 +327,16 @@ struct mmal_msg_port_parameter_set_reply
+ /* port parameter getting */
+
+ struct mmal_msg_port_parameter_get {
+- u32 component_handle; /* component */
+- u32 port_handle; /* port */
+- u32 id; /* Parameter ID */
+- u32 size; /* Parameter size */
++ u32 component_handle; /* component */
++ u32 port_handle; /* port */
++ u32 id; /* Parameter ID */
++ u32 size; /* Parameter size */
+ };
+
+ struct mmal_msg_port_parameter_get_reply {
+- u32 status; /* Status of mmal_port_parameter_get call */
+- u32 id; /* Parameter ID */
+- u32 size; /* Parameter size */
++ u32 status; /* Status of mmal_port_parameter_get call */
++ u32 id; /* Parameter ID */
++ u32 size; /* Parameter size */
+ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
+ };
+
+@@ -339,7 +344,7 @@ struct mmal_msg_port_parameter_get_reply
+ #define MMAL_WORKER_EVENT_SPACE 256
+
+ struct mmal_msg_event_to_host {
+- u32 client_component; /* component context */
++ u32 client_component; /* component context */
+
+ u32 port_type;
+ u32 port_num;
+++ /dev/null
-From 3cb19cb6b4d6dc86582abef6200c0fc663ae3f2a Mon Sep 17 00:00:00 2001
-Date: Fri, 10 Mar 2017 17:27:56 +0000
-Subject: [PATCH] staging: bcm2835-camera: Return early on errors
-
-Fix several instances where it is easier to return
-early on error conditions than handle it as an else
-clause.
-As requested by Mauro.
-
----
- .../bcm2835-camera/bcm2835-camera.c | 137 +++++++++---------
- 1 file changed, 71 insertions(+), 66 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -335,7 +335,9 @@ static void buffer_cb(struct vchiq_mmal_
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- }
- return;
-- } else if (length == 0) {
-+ }
-+
-+ if (length == 0) {
- /* stream ended */
- if (dev->capture.frame_count) {
- /* empty buffer whilst capturing - expected to be an
-@@ -361,71 +363,72 @@ static void buffer_cb(struct vchiq_mmal_
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- complete(&dev->capture.frame_cmplt);
- }
-- } else {
-- if (dev->capture.frame_count) {
-- if (dev->capture.vc_start_timestamp == -1) {
-- buf->vb.vb2_buf.timestamp = ktime_get_ns();
-- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-- "Buffer time set as current time - %lld",
-- buf->vb.vb2_buf.timestamp);
--
-- } else if (pts != 0) {
-- ktime_t timestamp;
-- s64 runtime_us = pts -
-- dev->capture.vc_start_timestamp;
-- timestamp = ktime_add_us(dev->capture.kernel_start_ts,
-- runtime_us);
-- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-- "Convert start time %llu and %llu with offset %llu to %llu\n",
-- ktime_to_ns(dev->capture.kernel_start_ts),
-- dev->capture.vc_start_timestamp, pts,
-- ktime_to_ns(timestamp));
-- buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
-- } else {
-- if (dev->capture.last_timestamp) {
-- buf->vb.vb2_buf.timestamp =
-- dev->capture.last_timestamp;
-- v4l2_dbg(1, bcm2835_v4l2_debug,
-- &dev->v4l2_dev,
-- "Buffer time set as last timestamp - %lld",
-- buf->vb.vb2_buf.timestamp);
-- } else {
-- buf->vb.vb2_buf.timestamp =
-- ktime_to_ns(dev->capture.kernel_start_ts);
-- v4l2_dbg(1, bcm2835_v4l2_debug,
-- &dev->v4l2_dev,
-- "Buffer time set as start timestamp - %lld",
-- buf->vb.vb2_buf.timestamp);
-- }
-- }
-- dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
-+ return;
-+ }
-
-- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
-- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
-- buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
-+ if (!dev->capture.frame_count) {
-+ /* signal frame completion */
-+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-+ complete(&dev->capture.frame_cmplt);
-+ return;
-+ }
-
-+ if (dev->capture.vc_start_timestamp == -1) {
-+ /*
-+ * VPU doesn't support MMAL_PARAMETER_SYSTEM_TIME, rely on
-+ * kernel time, and have no latency compensation.
-+ */
-+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Buffer time set as current time - %lld",
-+ buf->vb.vb2_buf.timestamp);
-+ } else if (pts != 0) {
-+ ktime_t timestamp;
-+ s64 runtime_us = pts -
-+ dev->capture.vc_start_timestamp;
-+ timestamp = ktime_add_us(dev->capture.kernel_start_ts,
-+ runtime_us);
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Convert start time %llu and %llu with offset %llu to %llu\n",
-+ ktime_to_ns(dev->capture.kernel_start_ts),
-+ dev->capture.vc_start_timestamp, pts,
-+ ktime_to_ns(timestamp));
-+ buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
-+ } else {
-+ if (dev->capture.last_timestamp) {
-+ buf->vb.vb2_buf.timestamp = dev->capture.last_timestamp;
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-- "Buffer has ts %llu",
-- dev->capture.last_timestamp);
-- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
--
-- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
-- is_capturing(dev)) {
-- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-- "Grab another frame as buffer has EOS");
-- vchiq_mmal_port_parameter_set(
-- instance,
-- dev->capture.camera_port,
-- MMAL_PARAMETER_CAPTURE,
-- &dev->capture.frame_count,
-- sizeof(dev->capture.frame_count));
-- }
-+ "Buffer time set as last timestamp - %lld",
-+ buf->vb.vb2_buf.timestamp);
- } else {
-- /* signal frame completion */
-- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-- complete(&dev->capture.frame_cmplt);
-+ buf->vb.vb2_buf.timestamp =
-+ ktime_to_ns(dev->capture.kernel_start_ts);
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Buffer time set as start timestamp - %lld",
-+ buf->vb.vb2_buf.timestamp);
- }
- }
-+ dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
-+
-+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
-+ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
-+ buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
-+
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Buffer has ts %llu",
-+ dev->capture.last_timestamp);
-+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
-+
-+ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
-+ is_capturing(dev)) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Grab another frame as buffer has EOS");
-+ vchiq_mmal_port_parameter_set(instance,
-+ dev->capture.camera_port,
-+ MMAL_PARAMETER_CAPTURE,
-+ &dev->capture.frame_count,
-+ sizeof(dev->capture.frame_count));
-+ }
- }
-
- static int enable_camera(struct bm2835_mmal_dev *dev)
-@@ -815,27 +818,29 @@ static int vidioc_overlay(struct file *f
-
- ret = vchiq_mmal_port_set_format(dev->instance, src);
- if (ret < 0)
-- goto error;
-+ return ret;
-
- ret = set_overlay_params(dev, dst);
- if (ret < 0)
-- goto error;
-+ return ret;
-
-- if (enable_camera(dev) < 0)
-- goto error;
-+ if (enable_camera(dev) < 0) {
-+ ret = -EINVAL;
-+ return ret;
-+ }
-
- ret = vchiq_mmal_component_enable(
- dev->instance,
- dev->component[MMAL_COMPONENT_PREVIEW]);
- if (ret < 0)
-- goto error;
-+ return ret;
-
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "connecting %p to %p\n",
- src, dst);
- ret = vchiq_mmal_port_connect_tunnel(dev->instance, src, dst);
- if (!ret)
- ret = vchiq_mmal_port_enable(dev->instance, src, NULL);
--error:
-+
- return ret;
- }
-
--- /dev/null
+From 54fde7601287891754bef85efbbc9b5648d043f4 Mon Sep 17 00:00:00 2001
+Date: Wed, 21 Feb 2018 14:13:03 +0000
+Subject: [PATCH] staging: bcm2835-camera: Fix spacing around operators
+
+Fix checkpatch warnings over spaces around operators.
+Many were around operations that can be replaced with the
+BIT(x) macro, so replace with that where appropriate.
+
+---
+ .../vc04_services/bcm2835-camera/controls.c | 32 +++++++++----------
+ .../vc04_services/bcm2835-camera/mmal-msg.h | 3 +-
+ .../bcm2835-camera/mmal-parameters.h | 12 +++----
+ 3 files changed, 24 insertions(+), 23 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -1123,10 +1123,10 @@ static const struct bm2835_mmal_v4l2_ctr
+ {
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ MMAL_CONTROL_TYPE_STD_MENU,
+- ~((1<<V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+- (1<<V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
+- (1<<V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+- (1<<V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
++ ~(BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 1, NULL,
+ MMAL_PARAMETER_PROFILE,
+@@ -1135,18 +1135,18 @@ static const struct bm2835_mmal_v4l2_ctr
+ },
+ {
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL, MMAL_CONTROL_TYPE_STD_MENU,
+- ~((1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
+- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
+- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
+- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
+- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
+- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
+- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
+- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
+- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
+- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
+- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
+- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
++ ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
+ V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
+ V4L2_MPEG_VIDEO_H264_LEVEL_4_0, 1, NULL,
+ MMAL_PARAMETER_PROFILE,
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
+@@ -223,7 +223,8 @@ struct mmal_msg_port_action_reply {
+ #define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2)
+ /* Signals that the current payload contains only complete frames (>1) */
+ #define MMAL_BUFFER_HEADER_FLAG_FRAME \
+- (MMAL_BUFFER_HEADER_FLAG_FRAME_START|MMAL_BUFFER_HEADER_FLAG_FRAME_END)
++ (MMAL_BUFFER_HEADER_FLAG_FRAME_START | \
++ MMAL_BUFFER_HEADER_FLAG_FRAME_END)
+ /* Signals that the current payload is a keyframe (i.e. self decodable) */
+ #define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3)
+ /*
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
+@@ -23,17 +23,17 @@
+ #define __MMAL_PARAMETERS_H
+
+ /** Common parameter ID group, used with many types of component. */
+-#define MMAL_PARAMETER_GROUP_COMMON (0<<16)
++#define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
+ /** Camera-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_CAMERA (1<<16)
++#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16)
+ /** Video-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_VIDEO (2<<16)
++#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16)
+ /** Audio-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_AUDIO (3<<16)
++#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16)
+ /** Clock-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_CLOCK (4<<16)
++#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16)
+ /** Miracast-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_MIRACAST (5<<16)
++#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16)
+
+ /* Common parameters */
+ enum mmal_parameter_common_type {
+++ /dev/null
-From b1d4e377b4a8c73396d50c45106f3d3a710b11f5 Mon Sep 17 00:00:00 2001
-Date: Fri, 10 Mar 2017 17:35:38 +0000
-Subject: [PATCH] staging: bcm2835-camera: Remove dead email addresses
-
-None of the listed author email addresses were valid.
-Keep list of authors and the companies they represented.
-Update my email address.
-
----
- .../vc04_services/bcm2835-camera/bcm2835-camera.c | 9 +++++----
- .../vc04_services/bcm2835-camera/bcm2835-camera.h | 9 +++++----
- drivers/staging/vc04_services/bcm2835-camera/controls.c | 9 +++++----
- .../staging/vc04_services/bcm2835-camera/mmal-common.h | 9 +++++----
- .../vc04_services/bcm2835-camera/mmal-encodings.h | 9 +++++----
- .../vc04_services/bcm2835-camera/mmal-msg-common.h | 9 +++++----
- .../vc04_services/bcm2835-camera/mmal-msg-format.h | 9 +++++----
- .../staging/vc04_services/bcm2835-camera/mmal-msg-port.h | 9 +++++----
- drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h | 9 +++++----
- .../vc04_services/bcm2835-camera/mmal-parameters.h | 9 +++++----
- .../staging/vc04_services/bcm2835-camera/mmal-vchiq.c | 9 +++++----
- .../staging/vc04_services/bcm2835-camera/mmal-vchiq.h | 9 +++++----
- 12 files changed, 60 insertions(+), 48 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -4,10 +4,11 @@
- *
- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
- *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
- */
-
- #include <linux/errno.h>
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
-@@ -4,10 +4,11 @@
- *
- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
- *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
- *
- * core driver device
- */
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -4,10 +4,11 @@
- *
- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
- *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
- */
-
- #include <linux/errno.h>
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
-@@ -4,10 +4,11 @@
- *
- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
- *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
- *
- * MMAL structures
- *
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h
-@@ -4,10 +4,11 @@
- *
- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
- *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
- */
- #ifndef MMAL_ENCODINGS_H
- #define MMAL_ENCODINGS_H
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h
-@@ -4,10 +4,11 @@
- *
- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
- *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
- */
-
- #ifndef MMAL_MSG_COMMON_H
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
-@@ -4,10 +4,11 @@
- *
- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
- *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
- */
-
- #ifndef MMAL_MSG_FORMAT_H
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
-@@ -4,10 +4,11 @@
- *
- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
- *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
- */
-
- /* MMAL_PORT_TYPE_T */
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
-@@ -4,10 +4,11 @@
- *
- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
- *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
- */
-
- /* all the data structures which serialise the MMAL protocol. note
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
-@@ -4,10 +4,11 @@
- *
- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
- *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
- */
-
- /* common parameters */
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
-@@ -4,10 +4,11 @@
- *
- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
- *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
- *
- * V4L2 driver MMAL vchiq interface code
- */
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
-@@ -4,10 +4,11 @@
- *
- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
- *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
- *
- * MMAL interface to VCHIQ message passing
- */
+++ /dev/null
-From 4fb0df1b29feafacc244ca512b152dd3b96c224c Mon Sep 17 00:00:00 2001
-Date: Wed, 21 Feb 2018 13:49:32 +0000
-Subject: [PATCH] staging: bcm2835-camera: Fix comment style
- violations.
-
-Fix comment style violations in the header files.
-
----
- .../bcm2835-camera/mmal-msg-format.h | 95 ++++++------
- .../bcm2835-camera/mmal-msg-port.h | 124 ++++++++--------
- .../vc04_services/bcm2835-camera/mmal-msg.h | 135 +++++++++---------
- 3 files changed, 185 insertions(+), 169 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
-@@ -19,22 +19,23 @@
- /* MMAL_ES_FORMAT_T */
-
- struct mmal_audio_format {
-- u32 channels; /**< Number of audio channels */
-- u32 sample_rate; /**< Sample rate */
-+ u32 channels; /* Number of audio channels */
-+ u32 sample_rate; /* Sample rate */
-
-- u32 bits_per_sample; /**< Bits per sample */
-- u32 block_align; /**< Size of a block of data */
-+ u32 bits_per_sample; /* Bits per sample */
-+ u32 block_align; /* Size of a block of data */
- };
-
- struct mmal_video_format {
-- u32 width; /**< Width of frame in pixels */
-- u32 height; /**< Height of frame in rows of pixels */
-- struct mmal_rect crop; /**< Visible region of the frame */
-- struct mmal_rational frame_rate; /**< Frame rate */
-- struct mmal_rational par; /**< Pixel aspect ratio */
--
-- /* FourCC specifying the color space of the video stream. See the
-- * \ref MmalColorSpace "pre-defined color spaces" for some examples.
-+ u32 width; /* Width of frame in pixels */
-+ u32 height; /* Height of frame in rows of pixels */
-+ struct mmal_rect crop; /* Visible region of the frame */
-+ struct mmal_rational frame_rate; /* Frame rate */
-+ struct mmal_rational par; /* Pixel aspect ratio */
-+
-+ /*
-+ * FourCC specifying the color space of the video stream. See the
-+ * MmalColorSpace "pre-defined color spaces" for some examples.
- */
- u32 color_space;
- };
-@@ -50,48 +51,56 @@ union mmal_es_specific_format {
- struct mmal_subpicture_format subpicture;
- };
-
--/** Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
-+/* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
- struct mmal_es_format_local {
-- u32 type; /* enum mmal_es_type */
--
-- u32 encoding; /* FourCC specifying encoding of the elementary stream.*/
-- u32 encoding_variant; /* FourCC specifying the specific
-- * encoding variant of the elementary
-- * stream.
-- */
--
-- union mmal_es_specific_format *es; /* Type specific
-- * information for the
-- * elementary stream
-- */
-+ u32 type; /* enum mmal_es_type */
-
-- u32 bitrate; /**< Bitrate in bits per second */
-- u32 flags; /**< Flags describing properties of the elementary stream. */
-+ u32 encoding; /* FourCC specifying encoding of the elementary
-+ * stream.
-+ */
-+ u32 encoding_variant; /* FourCC specifying the specific
-+ * encoding variant of the elementary
-+ * stream.
-+ */
-+
-+ union mmal_es_specific_format *es; /* Type specific
-+ * information for the
-+ * elementary stream
-+ */
-+
-+ u32 bitrate; /* Bitrate in bits per second */
-+ u32 flags; /* Flags describing properties of the elementary
-+ * stream.
-+ */
-
-- u32 extradata_size; /**< Size of the codec specific data */
-- u8 *extradata; /**< Codec specific data */
-+ u32 extradata_size; /* Size of the codec specific data */
-+ u8 *extradata; /* Codec specific data */
- };
-
--/** Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
-+/* Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
- struct mmal_es_format {
-- u32 type; /* enum mmal_es_type */
-+ u32 type; /* enum mmal_es_type */
-
-- u32 encoding; /* FourCC specifying encoding of the elementary stream.*/
-- u32 encoding_variant; /* FourCC specifying the specific
-- * encoding variant of the elementary
-- * stream.
-- */
-+ u32 encoding; /* FourCC specifying encoding of the elementary
-+ * stream.
-+ */
-+ u32 encoding_variant; /* FourCC specifying the specific
-+ * encoding variant of the elementary
-+ * stream.
-+ */
-
-- u32 es; /* Type specific
-+ u32 es; /* Type specific
- * information for the
- * elementary stream
- */
-
-- u32 bitrate; /**< Bitrate in bits per second */
-- u32 flags; /**< Flags describing properties of the elementary stream. */
-+ u32 bitrate; /* Bitrate in bits per second */
-+ u32 flags; /* Flags describing properties of the elementary
-+ * stream.
-+ */
-
-- u32 extradata_size; /**< Size of the codec specific data */
-- u32 extradata; /**< Codec specific data */
-+ u32 extradata_size; /* Size of the codec specific data */
-+ u32 extradata; /* Codec specific data */
- };
-
- #endif /* MMAL_MSG_FORMAT_H */
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
-@@ -13,28 +13,31 @@
-
- /* MMAL_PORT_TYPE_T */
- enum mmal_port_type {
-- MMAL_PORT_TYPE_UNKNOWN = 0, /**< Unknown port type */
-- MMAL_PORT_TYPE_CONTROL, /**< Control port */
-- MMAL_PORT_TYPE_INPUT, /**< Input port */
-- MMAL_PORT_TYPE_OUTPUT, /**< Output port */
-- MMAL_PORT_TYPE_CLOCK, /**< Clock port */
-+ MMAL_PORT_TYPE_UNKNOWN = 0, /* Unknown port type */
-+ MMAL_PORT_TYPE_CONTROL, /* Control port */
-+ MMAL_PORT_TYPE_INPUT, /* Input port */
-+ MMAL_PORT_TYPE_OUTPUT, /* Output port */
-+ MMAL_PORT_TYPE_CLOCK, /* Clock port */
- };
-
--/** The port is pass-through and doesn't need buffer headers allocated */
-+/* The port is pass-through and doesn't need buffer headers allocated */
- #define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01
--/** The port wants to allocate the buffer payloads.
-+/*
-+ *The port wants to allocate the buffer payloads.
- * This signals a preference that payload allocation should be done
- * on this port for efficiency reasons.
- */
- #define MMAL_PORT_CAPABILITY_ALLOCATION 0x02
--/** The port supports format change events.
-+/*
-+ * The port supports format change events.
- * This applies to input ports and is used to let the client know
- * whether the port supports being reconfigured via a format
- * change event (i.e. without having to disable the port).
- */
- #define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04
-
--/* mmal port structure (MMAL_PORT_T)
-+/*
-+ * mmal port structure (MMAL_PORT_T)
- *
- * most elements are informational only, the pointer values for
- * interogation messages are generally provided as additional
-@@ -42,50 +45,50 @@ enum mmal_port_type {
- * buffer_num, buffer_size and userdata parameters are writable.
- */
- struct mmal_port {
-- u32 priv; /* Private member used by the framework */
-- u32 name; /* Port name. Used for debugging purposes (RO) */
-+ u32 priv; /* Private member used by the framework */
-+ u32 name; /* Port name. Used for debugging purposes (RO) */
-
-- u32 type; /* Type of the port (RO) enum mmal_port_type */
-- u16 index; /* Index of the port in its type list (RO) */
-- u16 index_all; /* Index of the port in the list of all ports (RO) */
--
-- u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
-- u32 format; /* Format of the elementary stream */
--
-- u32 buffer_num_min; /* Minimum number of buffers the port
-- * requires (RO). This is set by the
-- * component.
-- */
--
-- u32 buffer_size_min; /* Minimum size of buffers the port
-- * requires (RO). This is set by the
-- * component.
-- */
--
-- u32 buffer_alignment_min; /* Minimum alignment requirement for
-- * the buffers (RO). A value of
-- * zero means no special alignment
-- * requirements. This is set by the
-- * component.
-- */
--
-- u32 buffer_num_recommended; /* Number of buffers the port
-- * recommends for optimal
-- * performance (RO). A value of
-- * zero means no special
-- * recommendation. This is set
-- * by the component.
-- */
--
-- u32 buffer_size_recommended; /* Size of buffers the port
-- * recommends for optimal
-- * performance (RO). A value of
-- * zero means no special
-- * recommendation. This is set
-- * by the component.
-- */
-+ u32 type; /* Type of the port (RO) enum mmal_port_type */
-+ u16 index; /* Index of the port in its type list (RO) */
-+ u16 index_all; /* Index of the port in the list of all ports (RO) */
-+
-+ u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
-+ u32 format; /* Format of the elementary stream */
-+
-+ u32 buffer_num_min; /* Minimum number of buffers the port
-+ * requires (RO). This is set by the
-+ * component.
-+ */
-+
-+ u32 buffer_size_min; /* Minimum size of buffers the port
-+ * requires (RO). This is set by the
-+ * component.
-+ */
-+
-+ u32 buffer_alignment_min;/* Minimum alignment requirement for
-+ * the buffers (RO). A value of
-+ * zero means no special alignment
-+ * requirements. This is set by the
-+ * component.
-+ */
-+
-+ u32 buffer_num_recommended; /* Number of buffers the port
-+ * recommends for optimal
-+ * performance (RO). A value of
-+ * zero means no special
-+ * recommendation. This is set
-+ * by the component.
-+ */
-+
-+ u32 buffer_size_recommended; /* Size of buffers the port
-+ * recommends for optimal
-+ * performance (RO). A value of
-+ * zero means no special
-+ * recommendation. This is set
-+ * by the component.
-+ */
-
-- u32 buffer_num; /* Actual number of buffers the port will use.
-+ u32 buffer_num; /* Actual number of buffers the port will use.
- * This is set by the client.
- */
-
-@@ -94,14 +97,13 @@ struct mmal_port {
- * the client.
- */
-
-- u32 component; /* Component this port belongs to (Read Only) */
-+ u32 component; /* Component this port belongs to (Read Only) */
-
-- u32 userdata; /* Field reserved for use by the client */
--
-- u32 capabilities; /* Flags describing the capabilities of a
-- * port (RO). Bitwise combination of \ref
-- * portcapabilities "Port capabilities"
-- * values.
-- */
-+ u32 userdata; /* Field reserved for use by the client */
-
-+ u32 capabilities; /* Flags describing the capabilities of a
-+ * port (RO). Bitwise combination of \ref
-+ * portcapabilities "Port capabilities"
-+ * values.
-+ */
- };
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
-@@ -11,7 +11,8 @@
- * Luke Diamand @ Broadcom
- */
-
--/* all the data structures which serialise the MMAL protocol. note
-+/*
-+ * all the data structures which serialise the MMAL protocol. note
- * these are directly mapped onto the recived message data.
- *
- * BEWARE: They seem to *assume* pointers are u32 and that there is no
-@@ -41,51 +42,51 @@ enum mmal_msg_type {
- MMAL_MSG_TYPE_SERVICE_CLOSED,
- MMAL_MSG_TYPE_GET_VERSION,
- MMAL_MSG_TYPE_COMPONENT_CREATE,
-- MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
-+ MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
- MMAL_MSG_TYPE_COMPONENT_ENABLE,
- MMAL_MSG_TYPE_COMPONENT_DISABLE,
- MMAL_MSG_TYPE_PORT_INFO_GET,
- MMAL_MSG_TYPE_PORT_INFO_SET,
-- MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
-+ MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
- MMAL_MSG_TYPE_BUFFER_FROM_HOST,
- MMAL_MSG_TYPE_BUFFER_TO_HOST,
- MMAL_MSG_TYPE_GET_STATS,
- MMAL_MSG_TYPE_PORT_PARAMETER_SET,
-- MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
-+ MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
- MMAL_MSG_TYPE_EVENT_TO_HOST,
- MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT,
- MMAL_MSG_TYPE_OPAQUE_ALLOCATOR,
- MMAL_MSG_TYPE_CONSUME_MEM,
-- MMAL_MSG_TYPE_LMK, /* 20 */
-+ MMAL_MSG_TYPE_LMK, /* 20 */
- MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC,
- MMAL_MSG_TYPE_DRM_GET_LHS32,
- MMAL_MSG_TYPE_DRM_GET_TIME,
- MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN,
-- MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
-+ MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
- MMAL_MSG_TYPE_HOST_LOG,
- MMAL_MSG_TYPE_MSG_LAST
- };
-
- /* port action request messages differ depending on the action type */
- enum mmal_msg_port_action_type {
-- MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */
-- MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
-- MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
-- MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
-- MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
-- MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
-+ MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */
-+ MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
-+ MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
-+ MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
-+ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
-+ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
- MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/
- };
-
- struct mmal_msg_header {
- u32 magic;
-- u32 type; /** enum mmal_msg_type */
-+ u32 type; /* enum mmal_msg_type */
-
- /* Opaque handle to the control service */
- u32 control_service;
-
-- u32 context; /** a u32 per message context */
-- u32 status; /** The status of the vchiq operation */
-+ u32 context; /* a u32 per message context */
-+ u32 status; /* The status of the vchiq operation */
- u32 padding;
- };
-
-@@ -99,9 +100,9 @@ struct mmal_msg_version {
-
- /* request to VC to create component */
- struct mmal_msg_component_create {
-- u32 client_component; /* component context */
-+ u32 client_component; /* component context */
- char name[128];
-- u32 pid; /* For debug */
-+ u32 pid; /* For debug */
- };
-
- /* reply from VC to component creation request */
-@@ -121,7 +122,7 @@ struct mmal_msg_component_destroy {
- };
-
- struct mmal_msg_component_destroy_reply {
-- u32 status; /** The component destruction status */
-+ u32 status; /* The component destruction status */
- };
-
- /* request and reply to VC to enable a component */
-@@ -130,7 +131,7 @@ struct mmal_msg_component_enable {
- };
-
- struct mmal_msg_component_enable_reply {
-- u32 status; /** The component enable status */
-+ u32 status; /* The component enable status */
- };
-
- /* request and reply to VC to disable a component */
-@@ -139,7 +140,7 @@ struct mmal_msg_component_disable {
- };
-
- struct mmal_msg_component_disable_reply {
-- u32 status; /** The component disable status */
-+ u32 status; /* The component disable status */
- };
-
- /* request to VC to get port information */
-@@ -151,12 +152,12 @@ struct mmal_msg_port_info_get {
-
- /* reply from VC to get port info request */
- struct mmal_msg_port_info_get_reply {
-- u32 status; /** enum mmal_msg_status */
-- u32 component_handle; /* component handle port is associated with */
-- u32 port_type; /* enum mmal_msg_port_type */
-- u32 port_index; /* port indexed in query */
-- s32 found; /* unused */
-- u32 port_handle; /**< Handle to use for this port */
-+ u32 status; /* enum mmal_msg_status */
-+ u32 component_handle; /* component handle port is associated with */
-+ u32 port_type; /* enum mmal_msg_port_type */
-+ u32 port_index; /* port indexed in query */
-+ s32 found; /* unused */
-+ u32 port_handle; /* Handle to use for this port */
- struct mmal_port port;
- struct mmal_es_format format; /* elementary stream format */
- union mmal_es_specific_format es; /* es type specific data */
-@@ -166,8 +167,8 @@ struct mmal_msg_port_info_get_reply {
- /* request to VC to set port information */
- struct mmal_msg_port_info_set {
- u32 component_handle;
-- u32 port_type; /* enum mmal_msg_port_type */
-- u32 port_index; /* port indexed in query */
-+ u32 port_type; /* enum mmal_msg_port_type */
-+ u32 port_index; /* port indexed in query */
- struct mmal_port port;
- struct mmal_es_format format;
- union mmal_es_specific_format es;
-@@ -177,11 +178,11 @@ struct mmal_msg_port_info_set {
- /* reply from VC to port info set request */
- struct mmal_msg_port_info_set_reply {
- u32 status;
-- u32 component_handle; /* component handle port is associated with */
-- u32 port_type; /* enum mmal_msg_port_type */
-- u32 index; /* port indexed in query */
-- s32 found; /* unused */
-- u32 port_handle; /**< Handle to use for this port */
-+ u32 component_handle; /* component handle port is associated with */
-+ u32 port_type; /* enum mmal_msg_port_type */
-+ u32 index; /* port indexed in query */
-+ s32 found; /* unused */
-+ u32 port_handle; /* Handle to use for this port */
- struct mmal_port port;
- struct mmal_es_format format;
- union mmal_es_specific_format es;
-@@ -192,7 +193,7 @@ struct mmal_msg_port_info_set_reply {
- struct mmal_msg_port_action_port {
- u32 component_handle;
- u32 port_handle;
-- u32 action; /* enum mmal_msg_port_action_type */
-+ u32 action; /* enum mmal_msg_port_action_type */
- struct mmal_port port;
- };
-
-@@ -200,50 +201,53 @@ struct mmal_msg_port_action_port {
- struct mmal_msg_port_action_handle {
- u32 component_handle;
- u32 port_handle;
-- u32 action; /* enum mmal_msg_port_action_type */
-+ u32 action; /* enum mmal_msg_port_action_type */
- u32 connect_component_handle;
- u32 connect_port_handle;
- };
-
- struct mmal_msg_port_action_reply {
-- u32 status; /** The port action operation status */
-+ u32 status; /* The port action operation status */
- };
-
- /* MMAL buffer transfer */
-
--/** Size of space reserved in a buffer message for short messages. */
-+/* Size of space reserved in a buffer message for short messages. */
- #define MMAL_VC_SHORT_DATA 128
-
--/** Signals that the current payload is the end of the stream of data */
-+/* Signals that the current payload is the end of the stream of data */
- #define MMAL_BUFFER_HEADER_FLAG_EOS BIT(0)
--/** Signals that the start of the current payload starts a frame */
-+/* Signals that the start of the current payload starts a frame */
- #define MMAL_BUFFER_HEADER_FLAG_FRAME_START BIT(1)
--/** Signals that the end of the current payload ends a frame */
-+/* Signals that the end of the current payload ends a frame */
- #define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2)
--/** Signals that the current payload contains only complete frames (>1) */
-+/* Signals that the current payload contains only complete frames (>1) */
- #define MMAL_BUFFER_HEADER_FLAG_FRAME \
- (MMAL_BUFFER_HEADER_FLAG_FRAME_START|MMAL_BUFFER_HEADER_FLAG_FRAME_END)
--/** Signals that the current payload is a keyframe (i.e. self decodable) */
-+/* Signals that the current payload is a keyframe (i.e. self decodable) */
- #define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3)
--/** Signals a discontinuity in the stream of data (e.g. after a seek).
-+/*
-+ * Signals a discontinuity in the stream of data (e.g. after a seek).
- * Can be used for instance by a decoder to reset its state
- */
- #define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY BIT(4)
--/** Signals a buffer containing some kind of config data for the component
-+/*
-+ * Signals a buffer containing some kind of config data for the component
- * (e.g. codec config data)
- */
- #define MMAL_BUFFER_HEADER_FLAG_CONFIG BIT(5)
--/** Signals an encrypted payload */
-+/* Signals an encrypted payload */
- #define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED BIT(6)
--/** Signals a buffer containing side information */
-+/* Signals a buffer containing side information */
- #define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO BIT(7)
--/** Signals a buffer which is the snapshot/postview image from a stills
-+/*
-+ * Signals a buffer which is the snapshot/postview image from a stills
- * capture
- */
- #define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT BIT(8)
--/** Signals a buffer which contains data known to be corrupted */
-+/* Signals a buffer which contains data known to be corrupted */
- #define MMAL_BUFFER_HEADER_FLAG_CORRUPTED BIT(9)
--/** Signals that a buffer failed to be transmitted */
-+/* Signals that a buffer failed to be transmitted */
- #define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED BIT(10)
-
- struct mmal_driver_buffer {
-@@ -255,8 +259,8 @@ struct mmal_driver_buffer {
-
- /* buffer header */
- struct mmal_buffer_header {
-- u32 next; /* next header */
-- u32 priv; /* framework private data */
-+ u32 next; /* next header */
-+ u32 priv; /* framework private data */
- u32 cmd;
- u32 data;
- u32 alloc_size;
-@@ -281,7 +285,8 @@ struct mmal_buffer_header_type_specific
- };
-
- struct mmal_msg_buffer_from_host {
-- /* The front 32 bytes of the buffer header are copied
-+ /*
-+ *The front 32 bytes of the buffer header are copied
- * back to us in the reply to allow for context. This
- * area is used to store two mmal_driver_buffer structures to
- * allow for multiple concurrent service users.
-@@ -296,7 +301,7 @@ struct mmal_msg_buffer_from_host {
- s32 is_zero_copy;
- s32 has_reference;
-
-- /** allows short data to be xfered in control message */
-+ /* allows short data to be xfered in control message */
- u32 payload_in_message;
- u8 short_data[MMAL_VC_SHORT_DATA];
- };
-@@ -306,10 +311,10 @@ struct mmal_msg_buffer_from_host {
- #define MMAL_WORKER_PORT_PARAMETER_SPACE 96
-
- struct mmal_msg_port_parameter_set {
-- u32 component_handle; /* component */
-- u32 port_handle; /* port */
-- u32 id; /* Parameter ID */
-- u32 size; /* Parameter size */
-+ u32 component_handle; /* component */
-+ u32 port_handle; /* port */
-+ u32 id; /* Parameter ID */
-+ u32 size; /* Parameter size */
- uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
- };
-
-@@ -322,16 +327,16 @@ struct mmal_msg_port_parameter_set_reply
- /* port parameter getting */
-
- struct mmal_msg_port_parameter_get {
-- u32 component_handle; /* component */
-- u32 port_handle; /* port */
-- u32 id; /* Parameter ID */
-- u32 size; /* Parameter size */
-+ u32 component_handle; /* component */
-+ u32 port_handle; /* port */
-+ u32 id; /* Parameter ID */
-+ u32 size; /* Parameter size */
- };
-
- struct mmal_msg_port_parameter_get_reply {
-- u32 status; /* Status of mmal_port_parameter_get call */
-- u32 id; /* Parameter ID */
-- u32 size; /* Parameter size */
-+ u32 status; /* Status of mmal_port_parameter_get call */
-+ u32 id; /* Parameter ID */
-+ u32 size; /* Parameter size */
- uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
- };
-
-@@ -339,7 +344,7 @@ struct mmal_msg_port_parameter_get_reply
- #define MMAL_WORKER_EVENT_SPACE 256
-
- struct mmal_msg_event_to_host {
-- u32 client_component; /* component context */
-+ u32 client_component; /* component context */
-
- u32 port_type;
- u32 port_num;
--- /dev/null
+From 75aca02c1449e3a97ec32de9974ad410f5d34463 Mon Sep 17 00:00:00 2001
+Date: Wed, 21 Feb 2018 15:23:35 +0000
+Subject: [PATCH] staging: bcm2835-camera: Reduce length of enum names
+
+We have numerous lines over 80 chars, or oddly split. Many
+of these are due to using long enum names such as
+MMAL_COMPONENT_CAMERA.
+Reduce the length of these enum names.
+
+---
+ .../bcm2835-camera/bcm2835-camera.c | 165 +++++++++---------
+ .../bcm2835-camera/bcm2835-camera.h | 20 +--
+ .../vc04_services/bcm2835-camera/controls.c | 47 +++--
+ 3 files changed, 114 insertions(+), 118 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -80,7 +80,7 @@ static struct mmal_fmt formats[] = {
+ .flags = 0,
+ .mmal = MMAL_ENCODING_I420,
+ .depth = 12,
+- .mmal_component = MMAL_COMPONENT_CAMERA,
++ .mmal_component = COMP_CAMERA,
+ .ybbp = 1,
+ .remove_padding = 1,
+ }, {
+@@ -89,7 +89,7 @@ static struct mmal_fmt formats[] = {
+ .flags = 0,
+ .mmal = MMAL_ENCODING_YUYV,
+ .depth = 16,
+- .mmal_component = MMAL_COMPONENT_CAMERA,
++ .mmal_component = COMP_CAMERA,
+ .ybbp = 2,
+ .remove_padding = 0,
+ }, {
+@@ -98,7 +98,7 @@ static struct mmal_fmt formats[] = {
+ .flags = 0,
+ .mmal = MMAL_ENCODING_RGB24,
+ .depth = 24,
+- .mmal_component = MMAL_COMPONENT_CAMERA,
++ .mmal_component = COMP_CAMERA,
+ .ybbp = 3,
+ .remove_padding = 0,
+ }, {
+@@ -107,7 +107,7 @@ static struct mmal_fmt formats[] = {
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+ .mmal = MMAL_ENCODING_JPEG,
+ .depth = 8,
+- .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE,
++ .mmal_component = COMP_IMAGE_ENCODE,
+ .ybbp = 0,
+ .remove_padding = 0,
+ }, {
+@@ -116,7 +116,7 @@ static struct mmal_fmt formats[] = {
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+ .mmal = MMAL_ENCODING_H264,
+ .depth = 8,
+- .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
++ .mmal_component = COMP_VIDEO_ENCODE,
+ .ybbp = 0,
+ .remove_padding = 0,
+ }, {
+@@ -125,7 +125,7 @@ static struct mmal_fmt formats[] = {
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+ .mmal = MMAL_ENCODING_MJPEG,
+ .depth = 8,
+- .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
++ .mmal_component = COMP_VIDEO_ENCODE,
+ .ybbp = 0,
+ .remove_padding = 0,
+ }, {
+@@ -134,7 +134,7 @@ static struct mmal_fmt formats[] = {
+ .flags = 0,
+ .mmal = MMAL_ENCODING_YVYU,
+ .depth = 16,
+- .mmal_component = MMAL_COMPONENT_CAMERA,
++ .mmal_component = COMP_CAMERA,
+ .ybbp = 2,
+ .remove_padding = 0,
+ }, {
+@@ -143,7 +143,7 @@ static struct mmal_fmt formats[] = {
+ .flags = 0,
+ .mmal = MMAL_ENCODING_VYUY,
+ .depth = 16,
+- .mmal_component = MMAL_COMPONENT_CAMERA,
++ .mmal_component = COMP_CAMERA,
+ .ybbp = 2,
+ .remove_padding = 0,
+ }, {
+@@ -152,7 +152,7 @@ static struct mmal_fmt formats[] = {
+ .flags = 0,
+ .mmal = MMAL_ENCODING_UYVY,
+ .depth = 16,
+- .mmal_component = MMAL_COMPONENT_CAMERA,
++ .mmal_component = COMP_CAMERA,
+ .ybbp = 2,
+ .remove_padding = 0,
+ }, {
+@@ -161,7 +161,7 @@ static struct mmal_fmt formats[] = {
+ .flags = 0,
+ .mmal = MMAL_ENCODING_NV12,
+ .depth = 12,
+- .mmal_component = MMAL_COMPONENT_CAMERA,
++ .mmal_component = COMP_CAMERA,
+ .ybbp = 1,
+ .remove_padding = 1,
+ }, {
+@@ -170,7 +170,7 @@ static struct mmal_fmt formats[] = {
+ .flags = 0,
+ .mmal = MMAL_ENCODING_BGR24,
+ .depth = 24,
+- .mmal_component = MMAL_COMPONENT_CAMERA,
++ .mmal_component = COMP_CAMERA,
+ .ybbp = 3,
+ .remove_padding = 0,
+ }, {
+@@ -179,7 +179,7 @@ static struct mmal_fmt formats[] = {
+ .flags = 0,
+ .mmal = MMAL_ENCODING_YV12,
+ .depth = 12,
+- .mmal_component = MMAL_COMPONENT_CAMERA,
++ .mmal_component = COMP_CAMERA,
+ .ybbp = 1,
+ .remove_padding = 1,
+ }, {
+@@ -188,7 +188,7 @@ static struct mmal_fmt formats[] = {
+ .flags = 0,
+ .mmal = MMAL_ENCODING_NV21,
+ .depth = 12,
+- .mmal_component = MMAL_COMPONENT_CAMERA,
++ .mmal_component = COMP_CAMERA,
+ .ybbp = 1,
+ .remove_padding = 1,
+ }, {
+@@ -197,7 +197,7 @@ static struct mmal_fmt formats[] = {
+ .flags = 0,
+ .mmal = MMAL_ENCODING_BGRA,
+ .depth = 32,
+- .mmal_component = MMAL_COMPONENT_CAMERA,
++ .mmal_component = COMP_CAMERA,
+ .ybbp = 4,
+ .remove_padding = 0,
+ },
+@@ -314,7 +314,7 @@ static inline bool is_capturing(struct b
+ {
+ return dev->capture.camera_port ==
+ &dev->
+- component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
++ component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
+ }
+
+ static void buffer_cb(struct vchiq_mmal_instance *instance,
+@@ -439,7 +439,7 @@ static int enable_camera(struct bm2835_m
+ if (!dev->camera_use_count) {
+ ret = vchiq_mmal_port_parameter_set(
+ dev->instance,
+- &dev->component[MMAL_COMPONENT_CAMERA]->control,
++ &dev->component[COMP_CAMERA]->control,
+ MMAL_PARAMETER_CAMERA_NUM, &dev->camera_num,
+ sizeof(dev->camera_num));
+ if (ret < 0) {
+@@ -450,7 +450,7 @@ static int enable_camera(struct bm2835_m
+
+ ret = vchiq_mmal_component_enable(
+ dev->instance,
+- dev->component[MMAL_COMPONENT_CAMERA]);
++ dev->component[COMP_CAMERA]);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed enabling camera, ret %d\n", ret);
+@@ -482,7 +482,7 @@ static int disable_camera(struct bm2835_
+ ret =
+ vchiq_mmal_component_disable(
+ dev->instance,
+- dev->component[MMAL_COMPONENT_CAMERA]);
++ dev->component[COMP_CAMERA]);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed disabling camera, ret %d\n", ret);
+@@ -490,7 +490,7 @@ static int disable_camera(struct bm2835_
+ }
+ vchiq_mmal_port_parameter_set(
+ dev->instance,
+- &dev->component[MMAL_COMPONENT_CAMERA]->control,
++ &dev->component[COMP_CAMERA]->control,
+ MMAL_PARAMETER_CAMERA_NUM, &i,
+ sizeof(i));
+ }
+@@ -542,7 +542,7 @@ static int start_streaming(struct vb2_qu
+ /* if the preview is not already running, wait for a few frames for AGC
+ * to settle down.
+ */
+- if (!dev->component[MMAL_COMPONENT_PREVIEW]->enabled)
++ if (!dev->component[COMP_PREVIEW]->enabled)
+ msleep(300);
+
+ /* enable the connection from camera to encoder (if applicable) */
+@@ -775,9 +775,9 @@ static int vidioc_s_fmt_vid_overlay(stru
+ vidioc_try_fmt_vid_overlay(file, priv, f);
+
+ dev->overlay = f->fmt.win;
+- if (dev->component[MMAL_COMPONENT_PREVIEW]->enabled) {
++ if (dev->component[COMP_PREVIEW]->enabled) {
+ set_overlay_params(dev,
+- &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
++ &dev->component[COMP_PREVIEW]->input[0]);
+ }
+
+ return 0;
+@@ -790,13 +790,13 @@ static int vidioc_overlay(struct file *f
+ struct vchiq_mmal_port *src;
+ struct vchiq_mmal_port *dst;
+
+- if ((on && dev->component[MMAL_COMPONENT_PREVIEW]->enabled) ||
+- (!on && !dev->component[MMAL_COMPONENT_PREVIEW]->enabled))
++ if ((on && dev->component[COMP_PREVIEW]->enabled) ||
++ (!on && !dev->component[COMP_PREVIEW]->enabled))
+ return 0; /* already in requested state */
+
+ src =
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_PREVIEW];
++ &dev->component[COMP_CAMERA]->
++ output[CAM_PORT_PREVIEW];
+
+ if (!on) {
+ /* disconnect preview ports and disable component */
+@@ -808,14 +808,14 @@ static int vidioc_overlay(struct file *f
+ if (ret >= 0)
+ ret = vchiq_mmal_component_disable(
+ dev->instance,
+- dev->component[MMAL_COMPONENT_PREVIEW]);
++ dev->component[COMP_PREVIEW]);
+
+ disable_camera(dev);
+ return ret;
+ }
+
+ /* set preview port format and connect it to output */
+- dst = &dev->component[MMAL_COMPONENT_PREVIEW]->input[0];
++ dst = &dev->component[COMP_PREVIEW]->input[0];
+
+ ret = vchiq_mmal_port_set_format(dev->instance, src);
+ if (ret < 0)
+@@ -832,7 +832,7 @@ static int vidioc_overlay(struct file *f
+
+ ret = vchiq_mmal_component_enable(
+ dev->instance,
+- dev->component[MMAL_COMPONENT_PREVIEW]);
++ dev->component[COMP_PREVIEW]);
+ if (ret < 0)
+ return ret;
+
+@@ -853,8 +853,8 @@ static int vidioc_g_fbuf(struct file *fi
+ */
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ struct vchiq_mmal_port *preview_port =
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_PREVIEW];
++ &dev->component[COMP_CAMERA]->
++ output[CAM_PORT_PREVIEW];
+
+ a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
+ V4L2_FBUF_CAP_GLOBAL_ALPHA;
+@@ -1057,31 +1057,31 @@ static int mmal_setup_components(struct
+ }
+ /* format dependent port setup */
+ switch (mfmt->mmal_component) {
+- case MMAL_COMPONENT_CAMERA:
++ case COMP_CAMERA:
+ /* Make a further decision on port based on resolution */
+ if (f->fmt.pix.width <= max_video_width
+ && f->fmt.pix.height <= max_video_height)
+ camera_port = port =
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_VIDEO];
++ &dev->component[COMP_CAMERA]->
++ output[CAM_PORT_VIDEO];
+ else
+ camera_port = port =
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_CAPTURE];
++ &dev->component[COMP_CAMERA]->
++ output[CAM_PORT_CAPTURE];
+ break;
+- case MMAL_COMPONENT_IMAGE_ENCODE:
+- encode_component = dev->component[MMAL_COMPONENT_IMAGE_ENCODE];
+- port = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
++ case COMP_IMAGE_ENCODE:
++ encode_component = dev->component[COMP_IMAGE_ENCODE];
++ port = &dev->component[COMP_IMAGE_ENCODE]->output[0];
+ camera_port =
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_CAPTURE];
++ &dev->component[COMP_CAMERA]->
++ output[CAM_PORT_CAPTURE];
+ break;
+- case MMAL_COMPONENT_VIDEO_ENCODE:
+- encode_component = dev->component[MMAL_COMPONENT_VIDEO_ENCODE];
+- port = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++ case COMP_VIDEO_ENCODE:
++ encode_component = dev->component[COMP_VIDEO_ENCODE];
++ port = &dev->component[COMP_VIDEO_ENCODE]->output[0];
+ camera_port =
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_VIDEO];
++ &dev->component[COMP_CAMERA]->
++ output[CAM_PORT_VIDEO];
+ break;
+ default:
+ break;
+@@ -1123,13 +1123,12 @@ static int mmal_setup_components(struct
+
+ if (!ret
+ && camera_port ==
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_VIDEO]) {
++ &dev->component[COMP_CAMERA]->
++ output[CAM_PORT_VIDEO]) {
+ bool overlay_enabled =
+- !!dev->component[MMAL_COMPONENT_PREVIEW]->enabled;
++ !!dev->component[COMP_PREVIEW]->enabled;
+ struct vchiq_mmal_port *preview_port =
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_PREVIEW];
++ &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
+ /* Preview and encode ports need to match on resolution */
+ if (overlay_enabled) {
+ /* Need to disable the overlay before we can update
+@@ -1160,7 +1159,7 @@ static int mmal_setup_components(struct
+ ret = vchiq_mmal_port_connect_tunnel(
+ dev->instance,
+ preview_port,
+- &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
++ &dev->component[COMP_PREVIEW]->input[0]);
+ if (!ret)
+ ret = vchiq_mmal_port_enable(dev->instance,
+ preview_port,
+@@ -1214,11 +1213,11 @@ static int mmal_setup_components(struct
+ port->format.encoding_variant = 0;
+ /* Set any encoding specific parameters */
+ switch (mfmt->mmal_component) {
+- case MMAL_COMPONENT_VIDEO_ENCODE:
++ case COMP_VIDEO_ENCODE:
+ port->format.bitrate =
+ dev->capture.encode_bitrate;
+ break;
+- case MMAL_COMPONENT_IMAGE_ENCODE:
++ case COMP_IMAGE_ENCODE:
+ /* Could set EXIF parameters here */
+ break;
+ default:
+@@ -1593,14 +1592,14 @@ static int mmal_init(struct bm2835_mmal_
+
+ /* get the camera component ready */
+ ret = vchiq_mmal_component_init(dev->instance, "ril.camera",
+- &dev->component[MMAL_COMPONENT_CAMERA]);
++ &dev->component[COMP_CAMERA]);
+ if (ret < 0)
+ goto unreg_mmal;
+
+- camera = dev->component[MMAL_COMPONENT_CAMERA];
+- if (camera->outputs < MMAL_CAMERA_PORT_COUNT) {
++ camera = dev->component[COMP_CAMERA];
++ if (camera->outputs < CAM_PORT_COUNT) {
+ v4l2_err(&dev->v4l2_dev, "%s: too few camera outputs %d needed %d\n",
+- __func__, camera->outputs, MMAL_CAMERA_PORT_COUNT);
++ __func__, camera->outputs, CAM_PORT_COUNT);
+ ret = -EINVAL;
+ goto unreg_camera;
+ }
+@@ -1622,7 +1621,7 @@ static int mmal_init(struct bm2835_mmal_
+ dev->rgb_bgr_swapped = true;
+ param_size = sizeof(supported_encodings);
+ ret = vchiq_mmal_port_parameter_get(dev->instance,
+- &camera->output[MMAL_CAMERA_PORT_CAPTURE],
++ &camera->output[CAM_PORT_CAPTURE],
+ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
+ &supported_encodings,
+ ¶m_size);
+@@ -1643,7 +1642,7 @@ static int mmal_init(struct bm2835_mmal_
+ }
+ }
+ }
+- format = &camera->output[MMAL_CAMERA_PORT_PREVIEW].format;
++ format = &camera->output[CAM_PORT_PREVIEW].format;
+
+ format->encoding = MMAL_ENCODING_OPAQUE;
+ format->encoding_variant = MMAL_ENCODING_I420;
+@@ -1657,7 +1656,7 @@ static int mmal_init(struct bm2835_mmal_
+ format->es->video.frame_rate.num = 0; /* Rely on fps_range */
+ format->es->video.frame_rate.den = 1;
+
+- format = &camera->output[MMAL_CAMERA_PORT_VIDEO].format;
++ format = &camera->output[CAM_PORT_VIDEO].format;
+
+ format->encoding = MMAL_ENCODING_OPAQUE;
+ format->encoding_variant = MMAL_ENCODING_I420;
+@@ -1671,7 +1670,7 @@ static int mmal_init(struct bm2835_mmal_
+ format->es->video.frame_rate.num = 0; /* Rely on fps_range */
+ format->es->video.frame_rate.den = 1;
+
+- format = &camera->output[MMAL_CAMERA_PORT_CAPTURE].format;
++ format = &camera->output[CAM_PORT_CAPTURE].format;
+
+ format->encoding = MMAL_ENCODING_OPAQUE;
+
+@@ -1695,28 +1694,28 @@ static int mmal_init(struct bm2835_mmal_
+ /* get the preview component ready */
+ ret = vchiq_mmal_component_init(
+ dev->instance, "ril.video_render",
+- &dev->component[MMAL_COMPONENT_PREVIEW]);
++ &dev->component[COMP_PREVIEW]);
+ if (ret < 0)
+ goto unreg_camera;
+
+- if (dev->component[MMAL_COMPONENT_PREVIEW]->inputs < 1) {
++ if (dev->component[COMP_PREVIEW]->inputs < 1) {
+ ret = -EINVAL;
+ v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
+- __func__, dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
++ __func__, dev->component[COMP_PREVIEW]->inputs, 1);
+ goto unreg_preview;
+ }
+
+ /* get the image encoder component ready */
+ ret = vchiq_mmal_component_init(
+ dev->instance, "ril.image_encode",
+- &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
++ &dev->component[COMP_IMAGE_ENCODE]);
+ if (ret < 0)
+ goto unreg_preview;
+
+- if (dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs < 1) {
++ if (dev->component[COMP_IMAGE_ENCODE]->inputs < 1) {
+ ret = -EINVAL;
+ v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
+- __func__, dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
++ __func__, dev->component[COMP_IMAGE_ENCODE]->inputs,
+ 1);
+ goto unreg_image_encoder;
+ }
+@@ -1724,21 +1723,21 @@ static int mmal_init(struct bm2835_mmal_
+ /* get the video encoder component ready */
+ ret = vchiq_mmal_component_init(dev->instance, "ril.video_encode",
+ &dev->
+- component[MMAL_COMPONENT_VIDEO_ENCODE]);
++ component[COMP_VIDEO_ENCODE]);
+ if (ret < 0)
+ goto unreg_image_encoder;
+
+- if (dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs < 1) {
++ if (dev->component[COMP_VIDEO_ENCODE]->inputs < 1) {
+ ret = -EINVAL;
+ v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
+- __func__, dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
++ __func__, dev->component[COMP_VIDEO_ENCODE]->inputs,
+ 1);
+ goto unreg_vid_encoder;
+ }
+
+ {
+ struct vchiq_mmal_port *encoder_port =
+- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++ &dev->component[COMP_VIDEO_ENCODE]->output[0];
+ encoder_port->format.encoding = MMAL_ENCODING_H264;
+ ret = vchiq_mmal_port_set_format(dev->instance,
+ encoder_port);
+@@ -1749,12 +1748,12 @@ static int mmal_init(struct bm2835_mmal_
+
+ vchiq_mmal_port_parameter_set(
+ dev->instance,
+- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
++ &dev->component[COMP_VIDEO_ENCODE]->control,
+ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
+ &enable, sizeof(enable));
+
+ vchiq_mmal_port_parameter_set(dev->instance,
+- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
++ &dev->component[COMP_VIDEO_ENCODE]->control,
+ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
+ &enable,
+ sizeof(enable));
+@@ -1772,23 +1771,23 @@ unreg_vid_encoder:
+ pr_err("Cleanup: Destroy video encoder\n");
+ vchiq_mmal_component_finalise(
+ dev->instance,
+- dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
++ dev->component[COMP_VIDEO_ENCODE]);
+
+ unreg_image_encoder:
+ pr_err("Cleanup: Destroy image encoder\n");
+ vchiq_mmal_component_finalise(
+ dev->instance,
+- dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
++ dev->component[COMP_IMAGE_ENCODE]);
+
+ unreg_preview:
+ pr_err("Cleanup: Destroy video render\n");
+ vchiq_mmal_component_finalise(dev->instance,
+- dev->component[MMAL_COMPONENT_PREVIEW]);
++ dev->component[COMP_PREVIEW]);
+
+ unreg_camera:
+ pr_err("Cleanup: Destroy camera\n");
+ vchiq_mmal_component_finalise(dev->instance,
+- dev->component[MMAL_COMPONENT_CAMERA]);
++ dev->component[COMP_CAMERA]);
+
+ unreg_mmal:
+ vchiq_mmal_finalise(dev->instance);
+@@ -1844,21 +1843,21 @@ static void bcm2835_cleanup_instance(str
+ dev->capture.encode_component);
+ }
+ vchiq_mmal_component_disable(dev->instance,
+- dev->component[MMAL_COMPONENT_CAMERA]);
++ dev->component[COMP_CAMERA]);
+
+ vchiq_mmal_component_finalise(dev->instance,
+ dev->
+- component[MMAL_COMPONENT_VIDEO_ENCODE]);
++ component[COMP_VIDEO_ENCODE]);
+
+ vchiq_mmal_component_finalise(dev->instance,
+ dev->
+- component[MMAL_COMPONENT_IMAGE_ENCODE]);
++ component[COMP_IMAGE_ENCODE]);
+
+ vchiq_mmal_component_finalise(dev->instance,
+- dev->component[MMAL_COMPONENT_PREVIEW]);
++ dev->component[COMP_PREVIEW]);
+
+ vchiq_mmal_component_finalise(dev->instance,
+- dev->component[MMAL_COMPONENT_CAMERA]);
++ dev->component[COMP_CAMERA]);
+
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
+@@ -16,18 +16,18 @@
+ #define V4L2_CTRL_COUNT 29 /* number of v4l controls */
+
+ enum {
+- MMAL_COMPONENT_CAMERA = 0,
+- MMAL_COMPONENT_PREVIEW,
+- MMAL_COMPONENT_IMAGE_ENCODE,
+- MMAL_COMPONENT_VIDEO_ENCODE,
+- MMAL_COMPONENT_COUNT
++ COMP_CAMERA = 0,
++ COMP_PREVIEW,
++ COMP_IMAGE_ENCODE,
++ COMP_VIDEO_ENCODE,
++ COMP_COUNT
+ };
+
+ enum {
+- MMAL_CAMERA_PORT_PREVIEW = 0,
+- MMAL_CAMERA_PORT_VIDEO,
+- MMAL_CAMERA_PORT_CAPTURE,
+- MMAL_CAMERA_PORT_COUNT
++ CAM_PORT_PREVIEW = 0,
++ CAM_PORT_VIDEO,
++ CAM_PORT_CAPTURE,
++ CAM_PORT_COUNT
+ };
+
+ #define PREVIEW_LAYER 2
+@@ -61,7 +61,7 @@ struct bm2835_mmal_dev {
+
+ /* allocated mmal instance and components */
+ struct vchiq_mmal_instance *instance;
+- struct vchiq_mmal_component *component[MMAL_COMPONENT_COUNT];
++ struct vchiq_mmal_component *component[COMP_COUNT];
+ int camera_use_count;
+
+ struct v4l2_window overlay;
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -176,7 +176,7 @@ static int ctrl_set_rational(struct bm28
+ struct mmal_parameter_rational rational_value;
+ struct vchiq_mmal_port *control;
+
+- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++ control = &dev->component[COMP_CAMERA]->control;
+
+ rational_value.num = ctrl->val;
+ rational_value.den = 100;
+@@ -194,7 +194,7 @@ static int ctrl_set_value(struct bm2835_
+ u32 u32_value;
+ struct vchiq_mmal_port *control;
+
+- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++ control = &dev->component[COMP_CAMERA]->control;
+
+ u32_value = ctrl->val;
+
+@@ -219,7 +219,7 @@ static int ctrl_set_iso(struct bm2835_mm
+ dev->manual_iso_enabled =
+ (ctrl->val == V4L2_ISO_SENSITIVITY_MANUAL);
+
+- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++ control = &dev->component[COMP_CAMERA]->control;
+
+ if (dev->manual_iso_enabled)
+ u32_value = dev->iso;
+@@ -238,7 +238,7 @@ static int ctrl_set_value_ev(struct bm28
+ s32 s32_value;
+ struct vchiq_mmal_port *control;
+
+- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++ control = &dev->component[COMP_CAMERA]->control;
+
+ s32_value = (ctrl->val - 12) * 2; /* Convert from index to 1/6ths */
+
+@@ -255,7 +255,7 @@ static int ctrl_set_rotate(struct bm2835
+ u32 u32_value;
+ struct vchiq_mmal_component *camera;
+
+- camera = dev->component[MMAL_COMPONENT_CAMERA];
++ camera = dev->component[COMP_CAMERA];
+
+ u32_value = ((ctrl->val % 360) / 90) * 90;
+
+@@ -291,7 +291,7 @@ static int ctrl_set_flip(struct bm2835_m
+ else
+ dev->vflip = ctrl->val;
+
+- camera = dev->component[MMAL_COMPONENT_CAMERA];
++ camera = dev->component[COMP_CAMERA];
+
+ if (dev->hflip && dev->vflip)
+ u32_value = MMAL_PARAM_MIRROR_BOTH;
+@@ -330,7 +330,7 @@ static int ctrl_set_exposure(struct bm28
+ struct vchiq_mmal_port *control;
+ int ret = 0;
+
+- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++ control = &dev->component[COMP_CAMERA]->control;
+
+ if (mmal_ctrl->mmal_id == MMAL_PARAMETER_SHUTTER_SPEED) {
+ /* V4L2 is in 100usec increments.
+@@ -405,7 +405,7 @@ static int ctrl_set_metering_mode(struct
+ struct vchiq_mmal_port *control;
+ u32 u32_value = dev->metering_mode;
+
+- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++ control = &dev->component[COMP_CAMERA]->control;
+
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+ mmal_ctrl->mmal_id,
+@@ -421,7 +421,7 @@ static int ctrl_set_flicker_avoidance(st
+ u32 u32_value;
+ struct vchiq_mmal_port *control;
+
+- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++ control = &dev->component[COMP_CAMERA]->control;
+
+ switch (ctrl->val) {
+ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
+@@ -450,7 +450,7 @@ static int ctrl_set_awb_mode(struct bm28
+ u32 u32_value;
+ struct vchiq_mmal_port *control;
+
+- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++ control = &dev->component[COMP_CAMERA]->control;
+
+ switch (ctrl->val) {
+ case V4L2_WHITE_BALANCE_MANUAL:
+@@ -506,7 +506,7 @@ static int ctrl_set_awb_gains(struct bm2
+ struct vchiq_mmal_port *control;
+ struct mmal_parameter_awbgains gains;
+
+- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++ control = &dev->component[COMP_CAMERA]->control;
+
+ if (ctrl->id == V4L2_CID_RED_BALANCE)
+ dev->red_gain = ctrl->val;
+@@ -554,7 +554,7 @@ static int ctrl_set_image_effect(struct
+ v4l2_to_mmal_effects_values[i].v;
+ }
+
+- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++ control = &dev->component[COMP_CAMERA]->control;
+
+ ret = vchiq_mmal_port_parameter_set(
+ dev->instance, control,
+@@ -587,7 +587,7 @@ static int ctrl_set_colfx(struct bm2835_
+ int ret = -EINVAL;
+ struct vchiq_mmal_port *control;
+
+- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++ control = &dev->component[COMP_CAMERA]->control;
+
+ dev->colourfx.enable = (ctrl->val & 0xff00) >> 8;
+ dev->colourfx.enable = ctrl->val & 0xff;
+@@ -613,7 +613,7 @@ static int ctrl_set_bitrate(struct bm283
+
+ dev->capture.encode_bitrate = ctrl->val;
+
+- encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++ encoder_out = &dev->component[COMP_VIDEO_ENCODE]->output[0];
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
+ mmal_ctrl->mmal_id,
+@@ -629,7 +629,7 @@ static int ctrl_set_bitrate_mode(struct
+ u32 bitrate_mode;
+ struct vchiq_mmal_port *encoder_out;
+
+- encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++ encoder_out = &dev->component[COMP_VIDEO_ENCODE]->output[0];
+
+ dev->capture.encode_bitrate_mode = ctrl->val;
+ switch (ctrl->val) {
+@@ -656,7 +656,7 @@ static int ctrl_set_image_encode_output(
+ u32 u32_value;
+ struct vchiq_mmal_port *jpeg_out;
+
+- jpeg_out = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
++ jpeg_out = &dev->component[COMP_IMAGE_ENCODE]->output[0];
+
+ u32_value = ctrl->val;
+
+@@ -672,7 +672,7 @@ static int ctrl_set_video_encode_param_o
+ u32 u32_value;
+ struct vchiq_mmal_port *vid_enc_ctl;
+
+- vid_enc_ctl = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
++ vid_enc_ctl = &dev->component[COMP_VIDEO_ENCODE]->output[0];
+
+ u32_value = ctrl->val;
+
+@@ -785,7 +785,7 @@ static int ctrl_set_video_encode_profile
+ }
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance,
+- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0],
++ &dev->component[COMP_VIDEO_ENCODE]->output[0],
+ mmal_ctrl->mmal_id,
+ ¶m, sizeof(param));
+ }
+@@ -803,7 +803,7 @@ static int ctrl_set_scene_mode(struct bm
+ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "scene mode selected %d, was %d\n", ctrl->val,
+ dev->scene_mode);
+- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
++ control = &dev->component[COMP_CAMERA]->control;
+
+ if (ctrl->val == dev->scene_mode)
+ return 0;
+@@ -1221,18 +1221,15 @@ int set_framerate_params(struct bm2835_m
+ fps_range.fps_high.den);
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance,
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_PREVIEW],
++ &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW],
+ MMAL_PARAMETER_FPS_RANGE,
+ &fps_range, sizeof(fps_range));
+ ret += vchiq_mmal_port_parameter_set(dev->instance,
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_VIDEO],
++ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO],
+ MMAL_PARAMETER_FPS_RANGE,
+ &fps_range, sizeof(fps_range));
+ ret += vchiq_mmal_port_parameter_set(dev->instance,
+- &dev->component[MMAL_COMPONENT_CAMERA]->
+- output[MMAL_CAMERA_PORT_CAPTURE],
++ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE],
+ MMAL_PARAMETER_FPS_RANGE,
+ &fps_range, sizeof(fps_range));
+ if (ret)
--- /dev/null
+From 2730c4538b6edbe1e9d4071a8a64aa62f655eeaa Mon Sep 17 00:00:00 2001
+Date: Wed, 21 Feb 2018 15:28:07 +0000
+Subject: [PATCH] staging: bcm2835-camera: Fix multiple line
+ dereference errors
+
+Fix checkpatch errors "Avoid multiple line dereference"
+
+---
+ .../bcm2835-camera/bcm2835-camera.c | 41 +++++++------------
+ 1 file changed, 14 insertions(+), 27 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -313,8 +313,7 @@ static void buffer_cleanup(struct vb2_bu
+ static inline bool is_capturing(struct bm2835_mmal_dev *dev)
+ {
+ return dev->capture.camera_port ==
+- &dev->
+- component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
++ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
+ }
+
+ static void buffer_cb(struct vchiq_mmal_instance *instance,
+@@ -795,8 +794,7 @@ static int vidioc_overlay(struct file *f
+ return 0; /* already in requested state */
+
+ src =
+- &dev->component[COMP_CAMERA]->
+- output[CAM_PORT_PREVIEW];
++ &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
+
+ if (!on) {
+ /* disconnect preview ports and disable component */
+@@ -853,8 +851,7 @@ static int vidioc_g_fbuf(struct file *fi
+ */
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ struct vchiq_mmal_port *preview_port =
+- &dev->component[COMP_CAMERA]->
+- output[CAM_PORT_PREVIEW];
++ &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
+
+ a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
+ V4L2_FBUF_CAP_GLOBAL_ALPHA;
+@@ -1046,8 +1043,7 @@ static int mmal_setup_components(struct
+ dev->capture.camera_port, NULL);
+ dev->capture.camera_port = NULL;
+ ret = vchiq_mmal_component_disable(dev->instance,
+- dev->capture.
+- encode_component);
++ dev->capture.encode_component);
+ if (ret)
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to disable encode component %d\n",
+@@ -1062,26 +1058,22 @@ static int mmal_setup_components(struct
+ if (f->fmt.pix.width <= max_video_width
+ && f->fmt.pix.height <= max_video_height)
+ camera_port = port =
+- &dev->component[COMP_CAMERA]->
+- output[CAM_PORT_VIDEO];
++ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
+ else
+ camera_port = port =
+- &dev->component[COMP_CAMERA]->
+- output[CAM_PORT_CAPTURE];
++ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
+ break;
+ case COMP_IMAGE_ENCODE:
+ encode_component = dev->component[COMP_IMAGE_ENCODE];
+ port = &dev->component[COMP_IMAGE_ENCODE]->output[0];
+ camera_port =
+- &dev->component[COMP_CAMERA]->
+- output[CAM_PORT_CAPTURE];
++ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
+ break;
+ case COMP_VIDEO_ENCODE:
+ encode_component = dev->component[COMP_VIDEO_ENCODE];
+ port = &dev->component[COMP_VIDEO_ENCODE]->output[0];
+ camera_port =
+- &dev->component[COMP_CAMERA]->
+- output[CAM_PORT_VIDEO];
++ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
+ break;
+ default:
+ break;
+@@ -1123,8 +1115,7 @@ static int mmal_setup_components(struct
+
+ if (!ret
+ && camera_port ==
+- &dev->component[COMP_CAMERA]->
+- output[CAM_PORT_VIDEO]) {
++ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO]) {
+ bool overlay_enabled =
+ !!dev->component[COMP_PREVIEW]->enabled;
+ struct vchiq_mmal_port *preview_port =
+@@ -1261,9 +1252,8 @@ static int mmal_setup_components(struct
+ port->current_buffer.size);
+ port->current_buffer.size =
+ (f->fmt.pix.sizeimage <
+- (100 << 10))
+- ? (100 << 10)
+- : f->fmt.pix.sizeimage;
++ (100 << 10)) ?
++ (100 << 10) : f->fmt.pix.sizeimage;
+ }
+ v4l2_dbg(1, bcm2835_v4l2_debug,
+ &dev->v4l2_dev,
+@@ -1722,8 +1712,7 @@ static int mmal_init(struct bm2835_mmal_
+
+ /* get the video encoder component ready */
+ ret = vchiq_mmal_component_init(dev->instance, "ril.video_encode",
+- &dev->
+- component[COMP_VIDEO_ENCODE]);
++ &dev->component[COMP_VIDEO_ENCODE]);
+ if (ret < 0)
+ goto unreg_image_encoder;
+
+@@ -1846,12 +1835,10 @@ static void bcm2835_cleanup_instance(str
+ dev->component[COMP_CAMERA]);
+
+ vchiq_mmal_component_finalise(dev->instance,
+- dev->
+- component[COMP_VIDEO_ENCODE]);
++ dev->component[COMP_VIDEO_ENCODE]);
+
+ vchiq_mmal_component_finalise(dev->instance,
+- dev->
+- component[COMP_IMAGE_ENCODE]);
++ dev->component[COMP_IMAGE_ENCODE]);
+
+ vchiq_mmal_component_finalise(dev->instance,
+ dev->component[COMP_PREVIEW]);
+++ /dev/null
-From 54fde7601287891754bef85efbbc9b5648d043f4 Mon Sep 17 00:00:00 2001
-Date: Wed, 21 Feb 2018 14:13:03 +0000
-Subject: [PATCH] staging: bcm2835-camera: Fix spacing around operators
-
-Fix checkpatch warnings over spaces around operators.
-Many were around operations that can be replaced with the
-BIT(x) macro, so replace with that where appropriate.
-
----
- .../vc04_services/bcm2835-camera/controls.c | 32 +++++++++----------
- .../vc04_services/bcm2835-camera/mmal-msg.h | 3 +-
- .../bcm2835-camera/mmal-parameters.h | 12 +++----
- 3 files changed, 24 insertions(+), 23 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -1123,10 +1123,10 @@ static const struct bm2835_mmal_v4l2_ctr
- {
- V4L2_CID_MPEG_VIDEO_H264_PROFILE,
- MMAL_CONTROL_TYPE_STD_MENU,
-- ~((1<<V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
-- (1<<V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
-- (1<<V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
-- (1<<V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
-+ ~(BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
-+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
-+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
-+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
- V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
- V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 1, NULL,
- MMAL_PARAMETER_PROFILE,
-@@ -1135,18 +1135,18 @@ static const struct bm2835_mmal_v4l2_ctr
- },
- {
- V4L2_CID_MPEG_VIDEO_H264_LEVEL, MMAL_CONTROL_TYPE_STD_MENU,
-- ~((1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
-- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
-- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
-- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
-- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
-- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
-- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
-- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
-- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
-- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
-- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
-- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
-+ ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
- V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
- V4L2_MPEG_VIDEO_H264_LEVEL_4_0, 1, NULL,
- MMAL_PARAMETER_PROFILE,
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
-@@ -223,7 +223,8 @@ struct mmal_msg_port_action_reply {
- #define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2)
- /* Signals that the current payload contains only complete frames (>1) */
- #define MMAL_BUFFER_HEADER_FLAG_FRAME \
-- (MMAL_BUFFER_HEADER_FLAG_FRAME_START|MMAL_BUFFER_HEADER_FLAG_FRAME_END)
-+ (MMAL_BUFFER_HEADER_FLAG_FRAME_START | \
-+ MMAL_BUFFER_HEADER_FLAG_FRAME_END)
- /* Signals that the current payload is a keyframe (i.e. self decodable) */
- #define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3)
- /*
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
-@@ -23,17 +23,17 @@
- #define __MMAL_PARAMETERS_H
-
- /** Common parameter ID group, used with many types of component. */
--#define MMAL_PARAMETER_GROUP_COMMON (0<<16)
-+#define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
- /** Camera-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_CAMERA (1<<16)
-+#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16)
- /** Video-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_VIDEO (2<<16)
-+#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16)
- /** Audio-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_AUDIO (3<<16)
-+#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16)
- /** Clock-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_CLOCK (4<<16)
-+#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16)
- /** Miracast-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_MIRACAST (5<<16)
-+#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16)
-
- /* Common parameters */
- enum mmal_parameter_common_type {
--- /dev/null
+From a023ee926b7e923058203e82edc5405c1e82842c Mon Sep 17 00:00:00 2001
+Date: Wed, 21 Feb 2018 15:37:11 +0000
+Subject: [PATCH] staging: bcm2835-camera: Fix brace style issues.
+
+Fix mismatched or missing brace issues flagged by checkpatch.
+
+---
+ drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 3 ++-
+ drivers/staging/vc04_services/bcm2835-camera/controls.c | 3 ++-
+ drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c | 3 ++-
+ 3 files changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -569,10 +569,11 @@ static int start_streaming(struct vb2_qu
+
+ /* Flag to indicate just to rely on kernel timestamps */
+ dev->capture.vc_start_timestamp = -1;
+- } else
++ } else {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Start time %lld size %d\n",
+ dev->capture.vc_start_timestamp, parameter_size);
++ }
+
+ dev->capture.kernel_start_ts = ktime_get();
+ dev->capture.last_timestamp = 0;
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -410,8 +410,9 @@ static int ctrl_set_metering_mode(struct
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+- } else
++ } else {
+ return 0;
++ }
+ }
+
+ static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev,
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
+@@ -1268,9 +1268,10 @@ static int port_parameter_get(struct vch
+ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
+ *value_size);
+ *value_size = rmsg->u.port_parameter_get_reply.size;
+- } else
++ } else {
+ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
+ rmsg->u.port_parameter_get_reply.size);
++ }
+
+ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
+ ret, port->component->handle, port->handle, parameter_id);
+++ /dev/null
-From 75aca02c1449e3a97ec32de9974ad410f5d34463 Mon Sep 17 00:00:00 2001
-Date: Wed, 21 Feb 2018 15:23:35 +0000
-Subject: [PATCH] staging: bcm2835-camera: Reduce length of enum names
-
-We have numerous lines over 80 chars, or oddly split. Many
-of these are due to using long enum names such as
-MMAL_COMPONENT_CAMERA.
-Reduce the length of these enum names.
-
----
- .../bcm2835-camera/bcm2835-camera.c | 165 +++++++++---------
- .../bcm2835-camera/bcm2835-camera.h | 20 +--
- .../vc04_services/bcm2835-camera/controls.c | 47 +++--
- 3 files changed, 114 insertions(+), 118 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -80,7 +80,7 @@ static struct mmal_fmt formats[] = {
- .flags = 0,
- .mmal = MMAL_ENCODING_I420,
- .depth = 12,
-- .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .mmal_component = COMP_CAMERA,
- .ybbp = 1,
- .remove_padding = 1,
- }, {
-@@ -89,7 +89,7 @@ static struct mmal_fmt formats[] = {
- .flags = 0,
- .mmal = MMAL_ENCODING_YUYV,
- .depth = 16,
-- .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .mmal_component = COMP_CAMERA,
- .ybbp = 2,
- .remove_padding = 0,
- }, {
-@@ -98,7 +98,7 @@ static struct mmal_fmt formats[] = {
- .flags = 0,
- .mmal = MMAL_ENCODING_RGB24,
- .depth = 24,
-- .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .mmal_component = COMP_CAMERA,
- .ybbp = 3,
- .remove_padding = 0,
- }, {
-@@ -107,7 +107,7 @@ static struct mmal_fmt formats[] = {
- .flags = V4L2_FMT_FLAG_COMPRESSED,
- .mmal = MMAL_ENCODING_JPEG,
- .depth = 8,
-- .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE,
-+ .mmal_component = COMP_IMAGE_ENCODE,
- .ybbp = 0,
- .remove_padding = 0,
- }, {
-@@ -116,7 +116,7 @@ static struct mmal_fmt formats[] = {
- .flags = V4L2_FMT_FLAG_COMPRESSED,
- .mmal = MMAL_ENCODING_H264,
- .depth = 8,
-- .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
-+ .mmal_component = COMP_VIDEO_ENCODE,
- .ybbp = 0,
- .remove_padding = 0,
- }, {
-@@ -125,7 +125,7 @@ static struct mmal_fmt formats[] = {
- .flags = V4L2_FMT_FLAG_COMPRESSED,
- .mmal = MMAL_ENCODING_MJPEG,
- .depth = 8,
-- .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
-+ .mmal_component = COMP_VIDEO_ENCODE,
- .ybbp = 0,
- .remove_padding = 0,
- }, {
-@@ -134,7 +134,7 @@ static struct mmal_fmt formats[] = {
- .flags = 0,
- .mmal = MMAL_ENCODING_YVYU,
- .depth = 16,
-- .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .mmal_component = COMP_CAMERA,
- .ybbp = 2,
- .remove_padding = 0,
- }, {
-@@ -143,7 +143,7 @@ static struct mmal_fmt formats[] = {
- .flags = 0,
- .mmal = MMAL_ENCODING_VYUY,
- .depth = 16,
-- .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .mmal_component = COMP_CAMERA,
- .ybbp = 2,
- .remove_padding = 0,
- }, {
-@@ -152,7 +152,7 @@ static struct mmal_fmt formats[] = {
- .flags = 0,
- .mmal = MMAL_ENCODING_UYVY,
- .depth = 16,
-- .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .mmal_component = COMP_CAMERA,
- .ybbp = 2,
- .remove_padding = 0,
- }, {
-@@ -161,7 +161,7 @@ static struct mmal_fmt formats[] = {
- .flags = 0,
- .mmal = MMAL_ENCODING_NV12,
- .depth = 12,
-- .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .mmal_component = COMP_CAMERA,
- .ybbp = 1,
- .remove_padding = 1,
- }, {
-@@ -170,7 +170,7 @@ static struct mmal_fmt formats[] = {
- .flags = 0,
- .mmal = MMAL_ENCODING_BGR24,
- .depth = 24,
-- .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .mmal_component = COMP_CAMERA,
- .ybbp = 3,
- .remove_padding = 0,
- }, {
-@@ -179,7 +179,7 @@ static struct mmal_fmt formats[] = {
- .flags = 0,
- .mmal = MMAL_ENCODING_YV12,
- .depth = 12,
-- .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .mmal_component = COMP_CAMERA,
- .ybbp = 1,
- .remove_padding = 1,
- }, {
-@@ -188,7 +188,7 @@ static struct mmal_fmt formats[] = {
- .flags = 0,
- .mmal = MMAL_ENCODING_NV21,
- .depth = 12,
-- .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .mmal_component = COMP_CAMERA,
- .ybbp = 1,
- .remove_padding = 1,
- }, {
-@@ -197,7 +197,7 @@ static struct mmal_fmt formats[] = {
- .flags = 0,
- .mmal = MMAL_ENCODING_BGRA,
- .depth = 32,
-- .mmal_component = MMAL_COMPONENT_CAMERA,
-+ .mmal_component = COMP_CAMERA,
- .ybbp = 4,
- .remove_padding = 0,
- },
-@@ -314,7 +314,7 @@ static inline bool is_capturing(struct b
- {
- return dev->capture.camera_port ==
- &dev->
-- component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
-+ component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
- }
-
- static void buffer_cb(struct vchiq_mmal_instance *instance,
-@@ -439,7 +439,7 @@ static int enable_camera(struct bm2835_m
- if (!dev->camera_use_count) {
- ret = vchiq_mmal_port_parameter_set(
- dev->instance,
-- &dev->component[MMAL_COMPONENT_CAMERA]->control,
-+ &dev->component[COMP_CAMERA]->control,
- MMAL_PARAMETER_CAMERA_NUM, &dev->camera_num,
- sizeof(dev->camera_num));
- if (ret < 0) {
-@@ -450,7 +450,7 @@ static int enable_camera(struct bm2835_m
-
- ret = vchiq_mmal_component_enable(
- dev->instance,
-- dev->component[MMAL_COMPONENT_CAMERA]);
-+ dev->component[COMP_CAMERA]);
- if (ret < 0) {
- v4l2_err(&dev->v4l2_dev,
- "Failed enabling camera, ret %d\n", ret);
-@@ -482,7 +482,7 @@ static int disable_camera(struct bm2835_
- ret =
- vchiq_mmal_component_disable(
- dev->instance,
-- dev->component[MMAL_COMPONENT_CAMERA]);
-+ dev->component[COMP_CAMERA]);
- if (ret < 0) {
- v4l2_err(&dev->v4l2_dev,
- "Failed disabling camera, ret %d\n", ret);
-@@ -490,7 +490,7 @@ static int disable_camera(struct bm2835_
- }
- vchiq_mmal_port_parameter_set(
- dev->instance,
-- &dev->component[MMAL_COMPONENT_CAMERA]->control,
-+ &dev->component[COMP_CAMERA]->control,
- MMAL_PARAMETER_CAMERA_NUM, &i,
- sizeof(i));
- }
-@@ -542,7 +542,7 @@ static int start_streaming(struct vb2_qu
- /* if the preview is not already running, wait for a few frames for AGC
- * to settle down.
- */
-- if (!dev->component[MMAL_COMPONENT_PREVIEW]->enabled)
-+ if (!dev->component[COMP_PREVIEW]->enabled)
- msleep(300);
-
- /* enable the connection from camera to encoder (if applicable) */
-@@ -775,9 +775,9 @@ static int vidioc_s_fmt_vid_overlay(stru
- vidioc_try_fmt_vid_overlay(file, priv, f);
-
- dev->overlay = f->fmt.win;
-- if (dev->component[MMAL_COMPONENT_PREVIEW]->enabled) {
-+ if (dev->component[COMP_PREVIEW]->enabled) {
- set_overlay_params(dev,
-- &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
-+ &dev->component[COMP_PREVIEW]->input[0]);
- }
-
- return 0;
-@@ -790,13 +790,13 @@ static int vidioc_overlay(struct file *f
- struct vchiq_mmal_port *src;
- struct vchiq_mmal_port *dst;
-
-- if ((on && dev->component[MMAL_COMPONENT_PREVIEW]->enabled) ||
-- (!on && !dev->component[MMAL_COMPONENT_PREVIEW]->enabled))
-+ if ((on && dev->component[COMP_PREVIEW]->enabled) ||
-+ (!on && !dev->component[COMP_PREVIEW]->enabled))
- return 0; /* already in requested state */
-
- src =
-- &dev->component[MMAL_COMPONENT_CAMERA]->
-- output[MMAL_CAMERA_PORT_PREVIEW];
-+ &dev->component[COMP_CAMERA]->
-+ output[CAM_PORT_PREVIEW];
-
- if (!on) {
- /* disconnect preview ports and disable component */
-@@ -808,14 +808,14 @@ static int vidioc_overlay(struct file *f
- if (ret >= 0)
- ret = vchiq_mmal_component_disable(
- dev->instance,
-- dev->component[MMAL_COMPONENT_PREVIEW]);
-+ dev->component[COMP_PREVIEW]);
-
- disable_camera(dev);
- return ret;
- }
-
- /* set preview port format and connect it to output */
-- dst = &dev->component[MMAL_COMPONENT_PREVIEW]->input[0];
-+ dst = &dev->component[COMP_PREVIEW]->input[0];
-
- ret = vchiq_mmal_port_set_format(dev->instance, src);
- if (ret < 0)
-@@ -832,7 +832,7 @@ static int vidioc_overlay(struct file *f
-
- ret = vchiq_mmal_component_enable(
- dev->instance,
-- dev->component[MMAL_COMPONENT_PREVIEW]);
-+ dev->component[COMP_PREVIEW]);
- if (ret < 0)
- return ret;
-
-@@ -853,8 +853,8 @@ static int vidioc_g_fbuf(struct file *fi
- */
- struct bm2835_mmal_dev *dev = video_drvdata(file);
- struct vchiq_mmal_port *preview_port =
-- &dev->component[MMAL_COMPONENT_CAMERA]->
-- output[MMAL_CAMERA_PORT_PREVIEW];
-+ &dev->component[COMP_CAMERA]->
-+ output[CAM_PORT_PREVIEW];
-
- a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
- V4L2_FBUF_CAP_GLOBAL_ALPHA;
-@@ -1057,31 +1057,31 @@ static int mmal_setup_components(struct
- }
- /* format dependent port setup */
- switch (mfmt->mmal_component) {
-- case MMAL_COMPONENT_CAMERA:
-+ case COMP_CAMERA:
- /* Make a further decision on port based on resolution */
- if (f->fmt.pix.width <= max_video_width
- && f->fmt.pix.height <= max_video_height)
- camera_port = port =
-- &dev->component[MMAL_COMPONENT_CAMERA]->
-- output[MMAL_CAMERA_PORT_VIDEO];
-+ &dev->component[COMP_CAMERA]->
-+ output[CAM_PORT_VIDEO];
- else
- camera_port = port =
-- &dev->component[MMAL_COMPONENT_CAMERA]->
-- output[MMAL_CAMERA_PORT_CAPTURE];
-+ &dev->component[COMP_CAMERA]->
-+ output[CAM_PORT_CAPTURE];
- break;
-- case MMAL_COMPONENT_IMAGE_ENCODE:
-- encode_component = dev->component[MMAL_COMPONENT_IMAGE_ENCODE];
-- port = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
-+ case COMP_IMAGE_ENCODE:
-+ encode_component = dev->component[COMP_IMAGE_ENCODE];
-+ port = &dev->component[COMP_IMAGE_ENCODE]->output[0];
- camera_port =
-- &dev->component[MMAL_COMPONENT_CAMERA]->
-- output[MMAL_CAMERA_PORT_CAPTURE];
-+ &dev->component[COMP_CAMERA]->
-+ output[CAM_PORT_CAPTURE];
- break;
-- case MMAL_COMPONENT_VIDEO_ENCODE:
-- encode_component = dev->component[MMAL_COMPONENT_VIDEO_ENCODE];
-- port = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
-+ case COMP_VIDEO_ENCODE:
-+ encode_component = dev->component[COMP_VIDEO_ENCODE];
-+ port = &dev->component[COMP_VIDEO_ENCODE]->output[0];
- camera_port =
-- &dev->component[MMAL_COMPONENT_CAMERA]->
-- output[MMAL_CAMERA_PORT_VIDEO];
-+ &dev->component[COMP_CAMERA]->
-+ output[CAM_PORT_VIDEO];
- break;
- default:
- break;
-@@ -1123,13 +1123,12 @@ static int mmal_setup_components(struct
-
- if (!ret
- && camera_port ==
-- &dev->component[MMAL_COMPONENT_CAMERA]->
-- output[MMAL_CAMERA_PORT_VIDEO]) {
-+ &dev->component[COMP_CAMERA]->
-+ output[CAM_PORT_VIDEO]) {
- bool overlay_enabled =
-- !!dev->component[MMAL_COMPONENT_PREVIEW]->enabled;
-+ !!dev->component[COMP_PREVIEW]->enabled;
- struct vchiq_mmal_port *preview_port =
-- &dev->component[MMAL_COMPONENT_CAMERA]->
-- output[MMAL_CAMERA_PORT_PREVIEW];
-+ &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
- /* Preview and encode ports need to match on resolution */
- if (overlay_enabled) {
- /* Need to disable the overlay before we can update
-@@ -1160,7 +1159,7 @@ static int mmal_setup_components(struct
- ret = vchiq_mmal_port_connect_tunnel(
- dev->instance,
- preview_port,
-- &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
-+ &dev->component[COMP_PREVIEW]->input[0]);
- if (!ret)
- ret = vchiq_mmal_port_enable(dev->instance,
- preview_port,
-@@ -1214,11 +1213,11 @@ static int mmal_setup_components(struct
- port->format.encoding_variant = 0;
- /* Set any encoding specific parameters */
- switch (mfmt->mmal_component) {
-- case MMAL_COMPONENT_VIDEO_ENCODE:
-+ case COMP_VIDEO_ENCODE:
- port->format.bitrate =
- dev->capture.encode_bitrate;
- break;
-- case MMAL_COMPONENT_IMAGE_ENCODE:
-+ case COMP_IMAGE_ENCODE:
- /* Could set EXIF parameters here */
- break;
- default:
-@@ -1593,14 +1592,14 @@ static int mmal_init(struct bm2835_mmal_
-
- /* get the camera component ready */
- ret = vchiq_mmal_component_init(dev->instance, "ril.camera",
-- &dev->component[MMAL_COMPONENT_CAMERA]);
-+ &dev->component[COMP_CAMERA]);
- if (ret < 0)
- goto unreg_mmal;
-
-- camera = dev->component[MMAL_COMPONENT_CAMERA];
-- if (camera->outputs < MMAL_CAMERA_PORT_COUNT) {
-+ camera = dev->component[COMP_CAMERA];
-+ if (camera->outputs < CAM_PORT_COUNT) {
- v4l2_err(&dev->v4l2_dev, "%s: too few camera outputs %d needed %d\n",
-- __func__, camera->outputs, MMAL_CAMERA_PORT_COUNT);
-+ __func__, camera->outputs, CAM_PORT_COUNT);
- ret = -EINVAL;
- goto unreg_camera;
- }
-@@ -1622,7 +1621,7 @@ static int mmal_init(struct bm2835_mmal_
- dev->rgb_bgr_swapped = true;
- param_size = sizeof(supported_encodings);
- ret = vchiq_mmal_port_parameter_get(dev->instance,
-- &camera->output[MMAL_CAMERA_PORT_CAPTURE],
-+ &camera->output[CAM_PORT_CAPTURE],
- MMAL_PARAMETER_SUPPORTED_ENCODINGS,
- &supported_encodings,
- ¶m_size);
-@@ -1643,7 +1642,7 @@ static int mmal_init(struct bm2835_mmal_
- }
- }
- }
-- format = &camera->output[MMAL_CAMERA_PORT_PREVIEW].format;
-+ format = &camera->output[CAM_PORT_PREVIEW].format;
-
- format->encoding = MMAL_ENCODING_OPAQUE;
- format->encoding_variant = MMAL_ENCODING_I420;
-@@ -1657,7 +1656,7 @@ static int mmal_init(struct bm2835_mmal_
- format->es->video.frame_rate.num = 0; /* Rely on fps_range */
- format->es->video.frame_rate.den = 1;
-
-- format = &camera->output[MMAL_CAMERA_PORT_VIDEO].format;
-+ format = &camera->output[CAM_PORT_VIDEO].format;
-
- format->encoding = MMAL_ENCODING_OPAQUE;
- format->encoding_variant = MMAL_ENCODING_I420;
-@@ -1671,7 +1670,7 @@ static int mmal_init(struct bm2835_mmal_
- format->es->video.frame_rate.num = 0; /* Rely on fps_range */
- format->es->video.frame_rate.den = 1;
-
-- format = &camera->output[MMAL_CAMERA_PORT_CAPTURE].format;
-+ format = &camera->output[CAM_PORT_CAPTURE].format;
-
- format->encoding = MMAL_ENCODING_OPAQUE;
-
-@@ -1695,28 +1694,28 @@ static int mmal_init(struct bm2835_mmal_
- /* get the preview component ready */
- ret = vchiq_mmal_component_init(
- dev->instance, "ril.video_render",
-- &dev->component[MMAL_COMPONENT_PREVIEW]);
-+ &dev->component[COMP_PREVIEW]);
- if (ret < 0)
- goto unreg_camera;
-
-- if (dev->component[MMAL_COMPONENT_PREVIEW]->inputs < 1) {
-+ if (dev->component[COMP_PREVIEW]->inputs < 1) {
- ret = -EINVAL;
- v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
-- __func__, dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
-+ __func__, dev->component[COMP_PREVIEW]->inputs, 1);
- goto unreg_preview;
- }
-
- /* get the image encoder component ready */
- ret = vchiq_mmal_component_init(
- dev->instance, "ril.image_encode",
-- &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
-+ &dev->component[COMP_IMAGE_ENCODE]);
- if (ret < 0)
- goto unreg_preview;
-
-- if (dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs < 1) {
-+ if (dev->component[COMP_IMAGE_ENCODE]->inputs < 1) {
- ret = -EINVAL;
- v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
-- __func__, dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
-+ __func__, dev->component[COMP_IMAGE_ENCODE]->inputs,
- 1);
- goto unreg_image_encoder;
- }
-@@ -1724,21 +1723,21 @@ static int mmal_init(struct bm2835_mmal_
- /* get the video encoder component ready */
- ret = vchiq_mmal_component_init(dev->instance, "ril.video_encode",
- &dev->
-- component[MMAL_COMPONENT_VIDEO_ENCODE]);
-+ component[COMP_VIDEO_ENCODE]);
- if (ret < 0)
- goto unreg_image_encoder;
-
-- if (dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs < 1) {
-+ if (dev->component[COMP_VIDEO_ENCODE]->inputs < 1) {
- ret = -EINVAL;
- v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
-- __func__, dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
-+ __func__, dev->component[COMP_VIDEO_ENCODE]->inputs,
- 1);
- goto unreg_vid_encoder;
- }
-
- {
- struct vchiq_mmal_port *encoder_port =
-- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
-+ &dev->component[COMP_VIDEO_ENCODE]->output[0];
- encoder_port->format.encoding = MMAL_ENCODING_H264;
- ret = vchiq_mmal_port_set_format(dev->instance,
- encoder_port);
-@@ -1749,12 +1748,12 @@ static int mmal_init(struct bm2835_mmal_
-
- vchiq_mmal_port_parameter_set(
- dev->instance,
-- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
-+ &dev->component[COMP_VIDEO_ENCODE]->control,
- MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
- &enable, sizeof(enable));
-
- vchiq_mmal_port_parameter_set(dev->instance,
-- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
-+ &dev->component[COMP_VIDEO_ENCODE]->control,
- MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
- &enable,
- sizeof(enable));
-@@ -1772,23 +1771,23 @@ unreg_vid_encoder:
- pr_err("Cleanup: Destroy video encoder\n");
- vchiq_mmal_component_finalise(
- dev->instance,
-- dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
-+ dev->component[COMP_VIDEO_ENCODE]);
-
- unreg_image_encoder:
- pr_err("Cleanup: Destroy image encoder\n");
- vchiq_mmal_component_finalise(
- dev->instance,
-- dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
-+ dev->component[COMP_IMAGE_ENCODE]);
-
- unreg_preview:
- pr_err("Cleanup: Destroy video render\n");
- vchiq_mmal_component_finalise(dev->instance,
-- dev->component[MMAL_COMPONENT_PREVIEW]);
-+ dev->component[COMP_PREVIEW]);
-
- unreg_camera:
- pr_err("Cleanup: Destroy camera\n");
- vchiq_mmal_component_finalise(dev->instance,
-- dev->component[MMAL_COMPONENT_CAMERA]);
-+ dev->component[COMP_CAMERA]);
-
- unreg_mmal:
- vchiq_mmal_finalise(dev->instance);
-@@ -1844,21 +1843,21 @@ static void bcm2835_cleanup_instance(str
- dev->capture.encode_component);
- }
- vchiq_mmal_component_disable(dev->instance,
-- dev->component[MMAL_COMPONENT_CAMERA]);
-+ dev->component[COMP_CAMERA]);
-
- vchiq_mmal_component_finalise(dev->instance,
- dev->
-- component[MMAL_COMPONENT_VIDEO_ENCODE]);
-+ component[COMP_VIDEO_ENCODE]);
-
- vchiq_mmal_component_finalise(dev->instance,
- dev->
-- component[MMAL_COMPONENT_IMAGE_ENCODE]);
-+ component[COMP_IMAGE_ENCODE]);
-
- vchiq_mmal_component_finalise(dev->instance,
-- dev->component[MMAL_COMPONENT_PREVIEW]);
-+ dev->component[COMP_PREVIEW]);
-
- vchiq_mmal_component_finalise(dev->instance,
-- dev->component[MMAL_COMPONENT_CAMERA]);
-+ dev->component[COMP_CAMERA]);
-
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
-@@ -16,18 +16,18 @@
- #define V4L2_CTRL_COUNT 29 /* number of v4l controls */
-
- enum {
-- MMAL_COMPONENT_CAMERA = 0,
-- MMAL_COMPONENT_PREVIEW,
-- MMAL_COMPONENT_IMAGE_ENCODE,
-- MMAL_COMPONENT_VIDEO_ENCODE,
-- MMAL_COMPONENT_COUNT
-+ COMP_CAMERA = 0,
-+ COMP_PREVIEW,
-+ COMP_IMAGE_ENCODE,
-+ COMP_VIDEO_ENCODE,
-+ COMP_COUNT
- };
-
- enum {
-- MMAL_CAMERA_PORT_PREVIEW = 0,
-- MMAL_CAMERA_PORT_VIDEO,
-- MMAL_CAMERA_PORT_CAPTURE,
-- MMAL_CAMERA_PORT_COUNT
-+ CAM_PORT_PREVIEW = 0,
-+ CAM_PORT_VIDEO,
-+ CAM_PORT_CAPTURE,
-+ CAM_PORT_COUNT
- };
-
- #define PREVIEW_LAYER 2
-@@ -61,7 +61,7 @@ struct bm2835_mmal_dev {
-
- /* allocated mmal instance and components */
- struct vchiq_mmal_instance *instance;
-- struct vchiq_mmal_component *component[MMAL_COMPONENT_COUNT];
-+ struct vchiq_mmal_component *component[COMP_COUNT];
- int camera_use_count;
-
- struct v4l2_window overlay;
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -176,7 +176,7 @@ static int ctrl_set_rational(struct bm28
- struct mmal_parameter_rational rational_value;
- struct vchiq_mmal_port *control;
-
-- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+ control = &dev->component[COMP_CAMERA]->control;
-
- rational_value.num = ctrl->val;
- rational_value.den = 100;
-@@ -194,7 +194,7 @@ static int ctrl_set_value(struct bm2835_
- u32 u32_value;
- struct vchiq_mmal_port *control;
-
-- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+ control = &dev->component[COMP_CAMERA]->control;
-
- u32_value = ctrl->val;
-
-@@ -219,7 +219,7 @@ static int ctrl_set_iso(struct bm2835_mm
- dev->manual_iso_enabled =
- (ctrl->val == V4L2_ISO_SENSITIVITY_MANUAL);
-
-- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+ control = &dev->component[COMP_CAMERA]->control;
-
- if (dev->manual_iso_enabled)
- u32_value = dev->iso;
-@@ -238,7 +238,7 @@ static int ctrl_set_value_ev(struct bm28
- s32 s32_value;
- struct vchiq_mmal_port *control;
-
-- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+ control = &dev->component[COMP_CAMERA]->control;
-
- s32_value = (ctrl->val - 12) * 2; /* Convert from index to 1/6ths */
-
-@@ -255,7 +255,7 @@ static int ctrl_set_rotate(struct bm2835
- u32 u32_value;
- struct vchiq_mmal_component *camera;
-
-- camera = dev->component[MMAL_COMPONENT_CAMERA];
-+ camera = dev->component[COMP_CAMERA];
-
- u32_value = ((ctrl->val % 360) / 90) * 90;
-
-@@ -291,7 +291,7 @@ static int ctrl_set_flip(struct bm2835_m
- else
- dev->vflip = ctrl->val;
-
-- camera = dev->component[MMAL_COMPONENT_CAMERA];
-+ camera = dev->component[COMP_CAMERA];
-
- if (dev->hflip && dev->vflip)
- u32_value = MMAL_PARAM_MIRROR_BOTH;
-@@ -330,7 +330,7 @@ static int ctrl_set_exposure(struct bm28
- struct vchiq_mmal_port *control;
- int ret = 0;
-
-- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+ control = &dev->component[COMP_CAMERA]->control;
-
- if (mmal_ctrl->mmal_id == MMAL_PARAMETER_SHUTTER_SPEED) {
- /* V4L2 is in 100usec increments.
-@@ -405,7 +405,7 @@ static int ctrl_set_metering_mode(struct
- struct vchiq_mmal_port *control;
- u32 u32_value = dev->metering_mode;
-
-- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+ control = &dev->component[COMP_CAMERA]->control;
-
- return vchiq_mmal_port_parameter_set(dev->instance, control,
- mmal_ctrl->mmal_id,
-@@ -421,7 +421,7 @@ static int ctrl_set_flicker_avoidance(st
- u32 u32_value;
- struct vchiq_mmal_port *control;
-
-- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+ control = &dev->component[COMP_CAMERA]->control;
-
- switch (ctrl->val) {
- case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
-@@ -450,7 +450,7 @@ static int ctrl_set_awb_mode(struct bm28
- u32 u32_value;
- struct vchiq_mmal_port *control;
-
-- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+ control = &dev->component[COMP_CAMERA]->control;
-
- switch (ctrl->val) {
- case V4L2_WHITE_BALANCE_MANUAL:
-@@ -506,7 +506,7 @@ static int ctrl_set_awb_gains(struct bm2
- struct vchiq_mmal_port *control;
- struct mmal_parameter_awbgains gains;
-
-- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+ control = &dev->component[COMP_CAMERA]->control;
-
- if (ctrl->id == V4L2_CID_RED_BALANCE)
- dev->red_gain = ctrl->val;
-@@ -554,7 +554,7 @@ static int ctrl_set_image_effect(struct
- v4l2_to_mmal_effects_values[i].v;
- }
-
-- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+ control = &dev->component[COMP_CAMERA]->control;
-
- ret = vchiq_mmal_port_parameter_set(
- dev->instance, control,
-@@ -587,7 +587,7 @@ static int ctrl_set_colfx(struct bm2835_
- int ret = -EINVAL;
- struct vchiq_mmal_port *control;
-
-- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+ control = &dev->component[COMP_CAMERA]->control;
-
- dev->colourfx.enable = (ctrl->val & 0xff00) >> 8;
- dev->colourfx.enable = ctrl->val & 0xff;
-@@ -613,7 +613,7 @@ static int ctrl_set_bitrate(struct bm283
-
- dev->capture.encode_bitrate = ctrl->val;
-
-- encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
-+ encoder_out = &dev->component[COMP_VIDEO_ENCODE]->output[0];
-
- ret = vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
- mmal_ctrl->mmal_id,
-@@ -629,7 +629,7 @@ static int ctrl_set_bitrate_mode(struct
- u32 bitrate_mode;
- struct vchiq_mmal_port *encoder_out;
-
-- encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
-+ encoder_out = &dev->component[COMP_VIDEO_ENCODE]->output[0];
-
- dev->capture.encode_bitrate_mode = ctrl->val;
- switch (ctrl->val) {
-@@ -656,7 +656,7 @@ static int ctrl_set_image_encode_output(
- u32 u32_value;
- struct vchiq_mmal_port *jpeg_out;
-
-- jpeg_out = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
-+ jpeg_out = &dev->component[COMP_IMAGE_ENCODE]->output[0];
-
- u32_value = ctrl->val;
-
-@@ -672,7 +672,7 @@ static int ctrl_set_video_encode_param_o
- u32 u32_value;
- struct vchiq_mmal_port *vid_enc_ctl;
-
-- vid_enc_ctl = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
-+ vid_enc_ctl = &dev->component[COMP_VIDEO_ENCODE]->output[0];
-
- u32_value = ctrl->val;
-
-@@ -785,7 +785,7 @@ static int ctrl_set_video_encode_profile
- }
-
- ret = vchiq_mmal_port_parameter_set(dev->instance,
-- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0],
-+ &dev->component[COMP_VIDEO_ENCODE]->output[0],
- mmal_ctrl->mmal_id,
- ¶m, sizeof(param));
- }
-@@ -803,7 +803,7 @@ static int ctrl_set_scene_mode(struct bm
- v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "scene mode selected %d, was %d\n", ctrl->val,
- dev->scene_mode);
-- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
-+ control = &dev->component[COMP_CAMERA]->control;
-
- if (ctrl->val == dev->scene_mode)
- return 0;
-@@ -1221,18 +1221,15 @@ int set_framerate_params(struct bm2835_m
- fps_range.fps_high.den);
-
- ret = vchiq_mmal_port_parameter_set(dev->instance,
-- &dev->component[MMAL_COMPONENT_CAMERA]->
-- output[MMAL_CAMERA_PORT_PREVIEW],
-+ &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW],
- MMAL_PARAMETER_FPS_RANGE,
- &fps_range, sizeof(fps_range));
- ret += vchiq_mmal_port_parameter_set(dev->instance,
-- &dev->component[MMAL_COMPONENT_CAMERA]->
-- output[MMAL_CAMERA_PORT_VIDEO],
-+ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO],
- MMAL_PARAMETER_FPS_RANGE,
- &fps_range, sizeof(fps_range));
- ret += vchiq_mmal_port_parameter_set(dev->instance,
-- &dev->component[MMAL_COMPONENT_CAMERA]->
-- output[MMAL_CAMERA_PORT_CAPTURE],
-+ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE],
- MMAL_PARAMETER_FPS_RANGE,
- &fps_range, sizeof(fps_range));
- if (ret)
--- /dev/null
+From 6974c0c97b821c30af9f6f4ff9b4b6989cb5a573 Mon Sep 17 00:00:00 2001
+Date: Wed, 21 Feb 2018 15:39:26 +0000
+Subject: [PATCH] staging: bcm2835-camera: Fix missing lines between
+ items
+
+Fix checkpatch errors for missing blank lines after variable
+or structure declarations.
+
+---
+ drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h | 1 +
+ drivers/staging/vc04_services/bcm2835-camera/controls.c | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
+@@ -130,6 +130,7 @@ int set_framerate_params(struct bm2835_m
+ (pix_fmt)->pixelformat, (pix_fmt)->bytesperline, \
+ (pix_fmt)->sizeimage, (pix_fmt)->colorspace, (pix_fmt)->priv); \
+ }
++
+ #define v4l2_dump_win_format(level, debug, dev, win_fmt, desc) \
+ { \
+ v4l2_dbg(level, debug, dev, \
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -53,6 +53,7 @@ static const s64 ev_bias_qmenu[] = {
+ static const s64 iso_qmenu[] = {
+ 0, 100000, 200000, 400000, 800000,
+ };
++
+ static const uint32_t iso_values[] = {
+ 0, 100, 200, 400, 800,
+ };
+++ /dev/null
-From 2730c4538b6edbe1e9d4071a8a64aa62f655eeaa Mon Sep 17 00:00:00 2001
-Date: Wed, 21 Feb 2018 15:28:07 +0000
-Subject: [PATCH] staging: bcm2835-camera: Fix multiple line
- dereference errors
-
-Fix checkpatch errors "Avoid multiple line dereference"
-
----
- .../bcm2835-camera/bcm2835-camera.c | 41 +++++++------------
- 1 file changed, 14 insertions(+), 27 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -313,8 +313,7 @@ static void buffer_cleanup(struct vb2_bu
- static inline bool is_capturing(struct bm2835_mmal_dev *dev)
- {
- return dev->capture.camera_port ==
-- &dev->
-- component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
-+ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
- }
-
- static void buffer_cb(struct vchiq_mmal_instance *instance,
-@@ -795,8 +794,7 @@ static int vidioc_overlay(struct file *f
- return 0; /* already in requested state */
-
- src =
-- &dev->component[COMP_CAMERA]->
-- output[CAM_PORT_PREVIEW];
-+ &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
-
- if (!on) {
- /* disconnect preview ports and disable component */
-@@ -853,8 +851,7 @@ static int vidioc_g_fbuf(struct file *fi
- */
- struct bm2835_mmal_dev *dev = video_drvdata(file);
- struct vchiq_mmal_port *preview_port =
-- &dev->component[COMP_CAMERA]->
-- output[CAM_PORT_PREVIEW];
-+ &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
-
- a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
- V4L2_FBUF_CAP_GLOBAL_ALPHA;
-@@ -1046,8 +1043,7 @@ static int mmal_setup_components(struct
- dev->capture.camera_port, NULL);
- dev->capture.camera_port = NULL;
- ret = vchiq_mmal_component_disable(dev->instance,
-- dev->capture.
-- encode_component);
-+ dev->capture.encode_component);
- if (ret)
- v4l2_err(&dev->v4l2_dev,
- "Failed to disable encode component %d\n",
-@@ -1062,26 +1058,22 @@ static int mmal_setup_components(struct
- if (f->fmt.pix.width <= max_video_width
- && f->fmt.pix.height <= max_video_height)
- camera_port = port =
-- &dev->component[COMP_CAMERA]->
-- output[CAM_PORT_VIDEO];
-+ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
- else
- camera_port = port =
-- &dev->component[COMP_CAMERA]->
-- output[CAM_PORT_CAPTURE];
-+ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
- break;
- case COMP_IMAGE_ENCODE:
- encode_component = dev->component[COMP_IMAGE_ENCODE];
- port = &dev->component[COMP_IMAGE_ENCODE]->output[0];
- camera_port =
-- &dev->component[COMP_CAMERA]->
-- output[CAM_PORT_CAPTURE];
-+ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
- break;
- case COMP_VIDEO_ENCODE:
- encode_component = dev->component[COMP_VIDEO_ENCODE];
- port = &dev->component[COMP_VIDEO_ENCODE]->output[0];
- camera_port =
-- &dev->component[COMP_CAMERA]->
-- output[CAM_PORT_VIDEO];
-+ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
- break;
- default:
- break;
-@@ -1123,8 +1115,7 @@ static int mmal_setup_components(struct
-
- if (!ret
- && camera_port ==
-- &dev->component[COMP_CAMERA]->
-- output[CAM_PORT_VIDEO]) {
-+ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO]) {
- bool overlay_enabled =
- !!dev->component[COMP_PREVIEW]->enabled;
- struct vchiq_mmal_port *preview_port =
-@@ -1261,9 +1252,8 @@ static int mmal_setup_components(struct
- port->current_buffer.size);
- port->current_buffer.size =
- (f->fmt.pix.sizeimage <
-- (100 << 10))
-- ? (100 << 10)
-- : f->fmt.pix.sizeimage;
-+ (100 << 10)) ?
-+ (100 << 10) : f->fmt.pix.sizeimage;
- }
- v4l2_dbg(1, bcm2835_v4l2_debug,
- &dev->v4l2_dev,
-@@ -1722,8 +1712,7 @@ static int mmal_init(struct bm2835_mmal_
-
- /* get the video encoder component ready */
- ret = vchiq_mmal_component_init(dev->instance, "ril.video_encode",
-- &dev->
-- component[COMP_VIDEO_ENCODE]);
-+ &dev->component[COMP_VIDEO_ENCODE]);
- if (ret < 0)
- goto unreg_image_encoder;
-
-@@ -1846,12 +1835,10 @@ static void bcm2835_cleanup_instance(str
- dev->component[COMP_CAMERA]);
-
- vchiq_mmal_component_finalise(dev->instance,
-- dev->
-- component[COMP_VIDEO_ENCODE]);
-+ dev->component[COMP_VIDEO_ENCODE]);
-
- vchiq_mmal_component_finalise(dev->instance,
-- dev->
-- component[COMP_IMAGE_ENCODE]);
-+ dev->component[COMP_IMAGE_ENCODE]);
-
- vchiq_mmal_component_finalise(dev->instance,
- dev->component[COMP_PREVIEW]);
+++ /dev/null
-From a023ee926b7e923058203e82edc5405c1e82842c Mon Sep 17 00:00:00 2001
-Date: Wed, 21 Feb 2018 15:37:11 +0000
-Subject: [PATCH] staging: bcm2835-camera: Fix brace style issues.
-
-Fix mismatched or missing brace issues flagged by checkpatch.
-
----
- drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 3 ++-
- drivers/staging/vc04_services/bcm2835-camera/controls.c | 3 ++-
- drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c | 3 ++-
- 3 files changed, 6 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -569,10 +569,11 @@ static int start_streaming(struct vb2_qu
-
- /* Flag to indicate just to rely on kernel timestamps */
- dev->capture.vc_start_timestamp = -1;
-- } else
-+ } else {
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Start time %lld size %d\n",
- dev->capture.vc_start_timestamp, parameter_size);
-+ }
-
- dev->capture.kernel_start_ts = ktime_get();
- dev->capture.last_timestamp = 0;
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -410,8 +410,9 @@ static int ctrl_set_metering_mode(struct
- return vchiq_mmal_port_parameter_set(dev->instance, control,
- mmal_ctrl->mmal_id,
- &u32_value, sizeof(u32_value));
-- } else
-+ } else {
- return 0;
-+ }
- }
-
- static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev,
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
-@@ -1268,9 +1268,10 @@ static int port_parameter_get(struct vch
- memcpy(value, &rmsg->u.port_parameter_get_reply.value,
- *value_size);
- *value_size = rmsg->u.port_parameter_get_reply.size;
-- } else
-+ } else {
- memcpy(value, &rmsg->u.port_parameter_get_reply.value,
- rmsg->u.port_parameter_get_reply.size);
-+ }
-
- pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
- ret, port->component->handle, port->handle, parameter_id);
--- /dev/null
+From 5056b62708ac730f36114e1d792d0cc878b43561 Mon Sep 17 00:00:00 2001
+Date: Wed, 21 Feb 2018 15:48:54 +0000
+Subject: [PATCH] staging: bcm2835-camera: Fix logical continuation
+ splits
+
+Fix checkpatch errors for "Logical continuations should be
+on the previous line".
+
+---
+ .../vc04_services/bcm2835-camera/bcm2835-camera.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -545,8 +545,8 @@ static int start_streaming(struct vb2_qu
+ msleep(300);
+
+ /* enable the connection from camera to encoder (if applicable) */
+- if (dev->capture.camera_port != dev->capture.port
+- && dev->capture.camera_port) {
++ if (dev->capture.camera_port != dev->capture.port &&
++ dev->capture.camera_port) {
+ ret = vchiq_mmal_port_enable(dev->instance,
+ dev->capture.camera_port, NULL);
+ if (ret) {
+@@ -1056,8 +1056,8 @@ static int mmal_setup_components(struct
+ switch (mfmt->mmal_component) {
+ case COMP_CAMERA:
+ /* Make a further decision on port based on resolution */
+- if (f->fmt.pix.width <= max_video_width
+- && f->fmt.pix.height <= max_video_height)
++ if (f->fmt.pix.width <= max_video_width &&
++ f->fmt.pix.height <= max_video_height)
+ camera_port = port =
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
+ else
+@@ -1114,8 +1114,8 @@ static int mmal_setup_components(struct
+
+ ret = vchiq_mmal_port_set_format(dev->instance, camera_port);
+
+- if (!ret
+- && camera_port ==
++ if (!ret &&
++ camera_port ==
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO]) {
+ bool overlay_enabled =
+ !!dev->component[COMP_PREVIEW]->enabled;
+++ /dev/null
-From 6974c0c97b821c30af9f6f4ff9b4b6989cb5a573 Mon Sep 17 00:00:00 2001
-Date: Wed, 21 Feb 2018 15:39:26 +0000
-Subject: [PATCH] staging: bcm2835-camera: Fix missing lines between
- items
-
-Fix checkpatch errors for missing blank lines after variable
-or structure declarations.
-
----
- drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h | 1 +
- drivers/staging/vc04_services/bcm2835-camera/controls.c | 1 +
- 2 files changed, 2 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
-@@ -130,6 +130,7 @@ int set_framerate_params(struct bm2835_m
- (pix_fmt)->pixelformat, (pix_fmt)->bytesperline, \
- (pix_fmt)->sizeimage, (pix_fmt)->colorspace, (pix_fmt)->priv); \
- }
-+
- #define v4l2_dump_win_format(level, debug, dev, win_fmt, desc) \
- { \
- v4l2_dbg(level, debug, dev, \
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -53,6 +53,7 @@ static const s64 ev_bias_qmenu[] = {
- static const s64 iso_qmenu[] = {
- 0, 100000, 200000, 400000, 800000,
- };
-+
- static const uint32_t iso_values[] = {
- 0, 100, 200, 400, 800,
- };
--- /dev/null
+From 4ed895c5c9f55f565d5ecc19e799e109673db44f Mon Sep 17 00:00:00 2001
+Date: Wed, 21 Feb 2018 15:53:59 +0000
+Subject: [PATCH] staging: bcm2835-camera: Fix open parenthesis
+ alignment
+
+Fix checkpatch "Alignment should match open parenthesis"
+errors.
+
+---
+ .../bcm2835-camera/bcm2835-camera.c | 12 ++++-----
+ .../vc04_services/bcm2835-camera/controls.c | 25 ++++++++++++-------
+ .../vc04_services/bcm2835-camera/mmal-vchiq.c | 2 +-
+ .../vc04_services/bcm2835-camera/mmal-vchiq.h | 6 ++---
+ 4 files changed, 25 insertions(+), 20 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -415,8 +415,7 @@ static void buffer_cb(struct vchiq_mmal_
+ buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+- "Buffer has ts %llu",
+- dev->capture.last_timestamp);
++ "Buffer has ts %llu", dev->capture.last_timestamp);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
+@@ -584,8 +583,8 @@ static int start_streaming(struct vb2_qu
+ vchiq_mmal_port_enable(dev->instance, dev->capture.port, buffer_cb);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev,
+- "Failed to enable capture port - error %d. Disabling camera port again\n",
+- ret);
++ "Failed to enable capture port - error %d. Disabling camera port again\n",
++ ret);
+
+ vchiq_mmal_port_disable(dev->instance,
+ dev->capture.camera_port);
+@@ -991,8 +990,7 @@ static int vidioc_try_fmt_vid_cap(struct
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.bytesperline + align_mask) & ~align_mask;
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+- "Not removing padding, so bytes/line = %d, "
+- "(align_mask %d)\n",
++ "Not removing padding, so bytes/line = %d, (align_mask %d)\n",
+ f->fmt.pix.bytesperline, align_mask);
+ }
+
+@@ -1338,7 +1336,7 @@ static int vidioc_s_fmt_vid_cap(struct f
+ }
+
+ static int vidioc_enum_framesizes(struct file *file, void *fh,
+- struct v4l2_frmsizeenum *fsize)
++ struct v4l2_frmsizeenum *fsize)
+ {
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ static const struct v4l2_frmsize_stepwise sizes = {
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -1254,9 +1254,12 @@ int bm2835_mmal_init_controls(struct bm2
+
+ switch (ctrl->type) {
+ case MMAL_CONTROL_TYPE_STD:
+- dev->ctrls[c] = v4l2_ctrl_new_std(hdl,
+- &bm2835_mmal_ctrl_ops, ctrl->id,
+- ctrl->min, ctrl->max, ctrl->step, ctrl->def);
++ dev->ctrls[c] =
++ v4l2_ctrl_new_std(hdl,
++ &bm2835_mmal_ctrl_ops,
++ ctrl->id, ctrl->min,
++ ctrl->max, ctrl->step,
++ ctrl->def);
+ break;
+
+ case MMAL_CONTROL_TYPE_STD_MENU:
+@@ -1280,16 +1283,20 @@ int bm2835_mmal_init_controls(struct bm2
+ mask = ~mask;
+ }
+
+- dev->ctrls[c] = v4l2_ctrl_new_std_menu(hdl,
+- &bm2835_mmal_ctrl_ops, ctrl->id,
+- ctrl->max, mask, ctrl->def);
++ dev->ctrls[c] =
++ v4l2_ctrl_new_std_menu(hdl,
++ &bm2835_mmal_ctrl_ops,
++ ctrl->id, ctrl->max,
++ mask, ctrl->def);
+ break;
+ }
+
+ case MMAL_CONTROL_TYPE_INT_MENU:
+- dev->ctrls[c] = v4l2_ctrl_new_int_menu(hdl,
+- &bm2835_mmal_ctrl_ops, ctrl->id,
+- ctrl->max, ctrl->def, ctrl->imenu);
++ dev->ctrls[c] =
++ v4l2_ctrl_new_int_menu(hdl,
++ &bm2835_mmal_ctrl_ops,
++ ctrl->id, ctrl->max,
++ ctrl->def, ctrl->imenu);
+ break;
+
+ case MMAL_CONTROL_TYPE_CLUSTER:
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
+@@ -651,7 +651,7 @@ static int send_synchronous_mmal_msg(str
+ if (payload_len >
+ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
+ pr_err("payload length %d exceeds max:%d\n", payload_len,
+- (int)(MMAL_MSG_MAX_SIZE -
++ (int)(MMAL_MSG_MAX_SIZE -
+ sizeof(struct mmal_msg_header)));
+ return -EINVAL;
+ }
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
+@@ -131,7 +131,7 @@ int vchiq_mmal_port_enable(
+ * disable a port will dequeue any pending buffers
+ */
+ int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port);
++ struct vchiq_mmal_port *port);
+
+ int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+@@ -149,8 +149,8 @@ int vchiq_mmal_port_set_format(struct vc
+ struct vchiq_mmal_port *port);
+
+ int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *src,
+- struct vchiq_mmal_port *dst);
++ struct vchiq_mmal_port *src,
++ struct vchiq_mmal_port *dst);
+
+ int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
+ u32 *major_out,
+++ /dev/null
-From 5056b62708ac730f36114e1d792d0cc878b43561 Mon Sep 17 00:00:00 2001
-Date: Wed, 21 Feb 2018 15:48:54 +0000
-Subject: [PATCH] staging: bcm2835-camera: Fix logical continuation
- splits
-
-Fix checkpatch errors for "Logical continuations should be
-on the previous line".
-
----
- .../vc04_services/bcm2835-camera/bcm2835-camera.c | 12 ++++++------
- 1 file changed, 6 insertions(+), 6 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -545,8 +545,8 @@ static int start_streaming(struct vb2_qu
- msleep(300);
-
- /* enable the connection from camera to encoder (if applicable) */
-- if (dev->capture.camera_port != dev->capture.port
-- && dev->capture.camera_port) {
-+ if (dev->capture.camera_port != dev->capture.port &&
-+ dev->capture.camera_port) {
- ret = vchiq_mmal_port_enable(dev->instance,
- dev->capture.camera_port, NULL);
- if (ret) {
-@@ -1056,8 +1056,8 @@ static int mmal_setup_components(struct
- switch (mfmt->mmal_component) {
- case COMP_CAMERA:
- /* Make a further decision on port based on resolution */
-- if (f->fmt.pix.width <= max_video_width
-- && f->fmt.pix.height <= max_video_height)
-+ if (f->fmt.pix.width <= max_video_width &&
-+ f->fmt.pix.height <= max_video_height)
- camera_port = port =
- &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
- else
-@@ -1114,8 +1114,8 @@ static int mmal_setup_components(struct
-
- ret = vchiq_mmal_port_set_format(dev->instance, camera_port);
-
-- if (!ret
-- && camera_port ==
-+ if (!ret &&
-+ camera_port ==
- &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO]) {
- bool overlay_enabled =
- !!dev->component[COMP_PREVIEW]->enabled;
--- /dev/null
+From ba37d62e7bbdf42c2fa9ac3655354992da199a4b Mon Sep 17 00:00:00 2001
+Date: Thu, 21 Jun 2018 17:02:14 +0100
+Subject: [PATCH] staging: bcm2835-camera: Set sequence number
+ correctly
+
+Set the sequence number in vb2_v4l2_buffer mainly so the
+latest v4l2-ctl reports the frame rate correctly.
+
+---
+ drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 4 ++++
+ drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h | 2 ++
+ 2 files changed, 6 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -409,6 +409,7 @@ static void buffer_cb(struct vchiq_mmal_
+ }
+ }
+ dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
++ buf->vb.sequence = dev->capture.sequence++;
+
+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
+ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+@@ -537,6 +538,9 @@ static int start_streaming(struct vb2_qu
+ /* enable frame capture */
+ dev->capture.frame_count = 1;
+
++ /* reset sequence number */
++ dev->capture.sequence = 0;
++
+ /* if the preview is not already running, wait for a few frames for AGC
+ * to settle down.
+ */
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
+@@ -93,6 +93,8 @@ struct bm2835_mmal_dev {
+ ktime_t kernel_start_ts;
+ /* Timestamp of last frame */
+ u64 last_timestamp;
++ /* Sequence number of last buffer */
++ u32 sequence;
+
+ struct vchiq_mmal_port *port; /* port being used for capture */
+ /* camera port being used for capture */
--- /dev/null
+From 0d0b7a58ab065f72ffa55fbc7ab5436628694919 Mon Sep 17 00:00:00 2001
+Date: Tue, 24 Jul 2018 12:08:29 +0100
+Subject: [PATCH] staging: bcm2835-camera: Ensure timestamps never go
+ backwards.
+
+There is an awkward situation with H264 header bytes. Currently
+they are returned with a PTS of 0 because they aren't associated
+with a timestamped frame to encode. These are handled by either
+returning the timestamp of the last buffer to have been received,
+or in the case of the first buffer the timestamp taken at
+start_streaming.
+This results in a race where the current frame may have started
+before we take the start time, which results in the first encoded
+frame having an earlier timestamp than the header bytes.
+
+Ensure that we never return a negative delta to the user by checking
+against the previous timestamp.
+
+---
+ .../staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -393,6 +393,11 @@ static void buffer_cb(struct vchiq_mmal_
+ ktime_to_ns(dev->capture.kernel_start_ts),
+ dev->capture.vc_start_timestamp, pts,
+ ktime_to_ns(timestamp));
++ if (timestamp < dev->capture.last_timestamp) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "Negative delta - using last time\n");
++ timestamp = dev->capture.last_timestamp;
++ }
+ buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
+ } else {
+ if (dev->capture.last_timestamp) {
+++ /dev/null
-From 4ed895c5c9f55f565d5ecc19e799e109673db44f Mon Sep 17 00:00:00 2001
-Date: Wed, 21 Feb 2018 15:53:59 +0000
-Subject: [PATCH] staging: bcm2835-camera: Fix open parenthesis
- alignment
-
-Fix checkpatch "Alignment should match open parenthesis"
-errors.
-
----
- .../bcm2835-camera/bcm2835-camera.c | 12 ++++-----
- .../vc04_services/bcm2835-camera/controls.c | 25 ++++++++++++-------
- .../vc04_services/bcm2835-camera/mmal-vchiq.c | 2 +-
- .../vc04_services/bcm2835-camera/mmal-vchiq.h | 6 ++---
- 4 files changed, 25 insertions(+), 20 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -415,8 +415,7 @@ static void buffer_cb(struct vchiq_mmal_
- buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
-
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-- "Buffer has ts %llu",
-- dev->capture.last_timestamp);
-+ "Buffer has ts %llu", dev->capture.last_timestamp);
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
-
- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
-@@ -584,8 +583,8 @@ static int start_streaming(struct vb2_qu
- vchiq_mmal_port_enable(dev->instance, dev->capture.port, buffer_cb);
- if (ret) {
- v4l2_err(&dev->v4l2_dev,
-- "Failed to enable capture port - error %d. Disabling camera port again\n",
-- ret);
-+ "Failed to enable capture port - error %d. Disabling camera port again\n",
-+ ret);
-
- vchiq_mmal_port_disable(dev->instance,
- dev->capture.camera_port);
-@@ -991,8 +990,7 @@ static int vidioc_try_fmt_vid_cap(struct
- f->fmt.pix.bytesperline =
- (f->fmt.pix.bytesperline + align_mask) & ~align_mask;
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-- "Not removing padding, so bytes/line = %d, "
-- "(align_mask %d)\n",
-+ "Not removing padding, so bytes/line = %d, (align_mask %d)\n",
- f->fmt.pix.bytesperline, align_mask);
- }
-
-@@ -1338,7 +1336,7 @@ static int vidioc_s_fmt_vid_cap(struct f
- }
-
- static int vidioc_enum_framesizes(struct file *file, void *fh,
-- struct v4l2_frmsizeenum *fsize)
-+ struct v4l2_frmsizeenum *fsize)
- {
- struct bm2835_mmal_dev *dev = video_drvdata(file);
- static const struct v4l2_frmsize_stepwise sizes = {
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -1254,9 +1254,12 @@ int bm2835_mmal_init_controls(struct bm2
-
- switch (ctrl->type) {
- case MMAL_CONTROL_TYPE_STD:
-- dev->ctrls[c] = v4l2_ctrl_new_std(hdl,
-- &bm2835_mmal_ctrl_ops, ctrl->id,
-- ctrl->min, ctrl->max, ctrl->step, ctrl->def);
-+ dev->ctrls[c] =
-+ v4l2_ctrl_new_std(hdl,
-+ &bm2835_mmal_ctrl_ops,
-+ ctrl->id, ctrl->min,
-+ ctrl->max, ctrl->step,
-+ ctrl->def);
- break;
-
- case MMAL_CONTROL_TYPE_STD_MENU:
-@@ -1280,16 +1283,20 @@ int bm2835_mmal_init_controls(struct bm2
- mask = ~mask;
- }
-
-- dev->ctrls[c] = v4l2_ctrl_new_std_menu(hdl,
-- &bm2835_mmal_ctrl_ops, ctrl->id,
-- ctrl->max, mask, ctrl->def);
-+ dev->ctrls[c] =
-+ v4l2_ctrl_new_std_menu(hdl,
-+ &bm2835_mmal_ctrl_ops,
-+ ctrl->id, ctrl->max,
-+ mask, ctrl->def);
- break;
- }
-
- case MMAL_CONTROL_TYPE_INT_MENU:
-- dev->ctrls[c] = v4l2_ctrl_new_int_menu(hdl,
-- &bm2835_mmal_ctrl_ops, ctrl->id,
-- ctrl->max, ctrl->def, ctrl->imenu);
-+ dev->ctrls[c] =
-+ v4l2_ctrl_new_int_menu(hdl,
-+ &bm2835_mmal_ctrl_ops,
-+ ctrl->id, ctrl->max,
-+ ctrl->def, ctrl->imenu);
- break;
-
- case MMAL_CONTROL_TYPE_CLUSTER:
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
-@@ -651,7 +651,7 @@ static int send_synchronous_mmal_msg(str
- if (payload_len >
- (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
- pr_err("payload length %d exceeds max:%d\n", payload_len,
-- (int)(MMAL_MSG_MAX_SIZE -
-+ (int)(MMAL_MSG_MAX_SIZE -
- sizeof(struct mmal_msg_header)));
- return -EINVAL;
- }
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
-@@ -131,7 +131,7 @@ int vchiq_mmal_port_enable(
- * disable a port will dequeue any pending buffers
- */
- int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port);
-+ struct vchiq_mmal_port *port);
-
- int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
- struct vchiq_mmal_port *port,
-@@ -149,8 +149,8 @@ int vchiq_mmal_port_set_format(struct vc
- struct vchiq_mmal_port *port);
-
- int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *src,
-- struct vchiq_mmal_port *dst);
-+ struct vchiq_mmal_port *src,
-+ struct vchiq_mmal_port *dst);
-
- int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
- u32 *major_out,
--- /dev/null
+From f658f48d662c5ecd84af235f47cc48636b9a55e2 Mon Sep 17 00:00:00 2001
+Date: Thu, 27 Sep 2018 17:50:39 -0700
+Subject: [PATCH] staging: bcm2835-camera: Avoid unneeded internal
+ declaration warning
+
+Clang warns:
+
+drivers/staging/vc04_services/bcm2835-camera/controls.c:59:18: warning:
+variable 'mains_freq_qmenu' is not needed and will not be emitted
+[-Wunneeded-internal-declaration]
+static const s64 mains_freq_qmenu[] = {
+ ^
+1 warning generated.
+
+This is because mains_freq_qmenu is currently only used in an ARRAY_SIZE
+macro, which is a compile time evaluation in this case. Avoid this by
+adding mains_freq_qmenu as the imenu member of this structure, which
+matches all other controls that uses the ARRAY_SIZE macro in v4l2_ctrls.
+This turns out to be a no-op because V4L2_CID_MPEG_VIDEO_BITRATE_MODE is
+defined as a MMAL_CONTROL_TYPE_STD_MENU, which does not pass the imenu
+definition along to v4l2_ctrl_new in bm2835_mmal_init_controls.
+
+Link: https://github.com/ClangBuiltLinux/linux/issues/122
+---
+ drivers/staging/vc04_services/bcm2835-camera/controls.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -1109,7 +1109,7 @@ static const struct bm2835_mmal_v4l2_ctr
+ {
+ V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU,
+ 0, ARRAY_SIZE(mains_freq_qmenu) - 1,
+- 1, 1, NULL,
++ 1, 1, mains_freq_qmenu,
+ MMAL_PARAMETER_FLICKER_AVOID,
+ &ctrl_set_flicker_avoidance,
+ false
+++ /dev/null
-From ba37d62e7bbdf42c2fa9ac3655354992da199a4b Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Jun 2018 17:02:14 +0100
-Subject: [PATCH] staging: bcm2835-camera: Set sequence number
- correctly
-
-Set the sequence number in vb2_v4l2_buffer mainly so the
-latest v4l2-ctl reports the frame rate correctly.
-
----
- drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 4 ++++
- drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h | 2 ++
- 2 files changed, 6 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -409,6 +409,7 @@ static void buffer_cb(struct vchiq_mmal_
- }
- }
- dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
-+ buf->vb.sequence = dev->capture.sequence++;
-
- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
-@@ -537,6 +538,9 @@ static int start_streaming(struct vb2_qu
- /* enable frame capture */
- dev->capture.frame_count = 1;
-
-+ /* reset sequence number */
-+ dev->capture.sequence = 0;
-+
- /* if the preview is not already running, wait for a few frames for AGC
- * to settle down.
- */
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
-@@ -93,6 +93,8 @@ struct bm2835_mmal_dev {
- ktime_t kernel_start_ts;
- /* Timestamp of last frame */
- u64 last_timestamp;
-+ /* Sequence number of last buffer */
-+ u32 sequence;
-
- struct vchiq_mmal_port *port; /* port being used for capture */
- /* camera port being used for capture */
--- /dev/null
+From c37e8c9137e4858ed86e211f3fddbb9d9af08532 Mon Sep 17 00:00:00 2001
+Date: Mon, 24 Sep 2018 16:21:06 +0100
+Subject: [PATCH] staging: bcm2835-camera: Add multiple inclusion
+ protection to headers
+
+mmal-common.h and mmal-msg.h didn't have the normal
+ifndef FOO / define FOO / endif protection to stop it being
+included multiple times. Add it.
+
+---
+ drivers/staging/vc04_services/bcm2835-camera/mmal-common.h | 3 +++
+ drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h | 3 +++
+ 2 files changed, 6 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
+@@ -13,6 +13,8 @@
+ * MMAL structures
+ *
+ */
++#ifndef MMAL_COMMON_H
++#define MMAL_COMMON_H
+
+ #define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
+ #define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l')
+@@ -56,3 +58,4 @@ struct mmal_colourfx {
+ u32 u;
+ u32 v;
+ };
++#endif
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
+@@ -23,6 +23,8 @@
+ * implementation uses fixed size types and not the enums (though the
+ * comments have the actual enum type
+ */
++#ifndef MMAL_MSG_H
++#define MMAL_MSG_H
+
+ #define VC_MMAL_VER 15
+ #define VC_MMAL_MIN_VER 10
+@@ -401,3 +403,4 @@ struct mmal_msg {
+ u8 payload[MMAL_MSG_MAX_PAYLOAD];
+ } u;
+ };
++#endif
+++ /dev/null
-From 0d0b7a58ab065f72ffa55fbc7ab5436628694919 Mon Sep 17 00:00:00 2001
-Date: Tue, 24 Jul 2018 12:08:29 +0100
-Subject: [PATCH] staging: bcm2835-camera: Ensure timestamps never go
- backwards.
-
-There is an awkward situation with H264 header bytes. Currently
-they are returned with a PTS of 0 because they aren't associated
-with a timestamped frame to encode. These are handled by either
-returning the timestamp of the last buffer to have been received,
-or in the case of the first buffer the timestamp taken at
-start_streaming.
-This results in a race where the current frame may have started
-before we take the start time, which results in the first encoded
-frame having an earlier timestamp than the header bytes.
-
-Ensure that we never return a negative delta to the user by checking
-against the previous timestamp.
-
----
- .../staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -393,6 +393,11 @@ static void buffer_cb(struct vchiq_mmal_
- ktime_to_ns(dev->capture.kernel_start_ts),
- dev->capture.vc_start_timestamp, pts,
- ktime_to_ns(timestamp));
-+ if (timestamp < dev->capture.last_timestamp) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "Negative delta - using last time\n");
-+ timestamp = dev->capture.last_timestamp;
-+ }
- buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
- } else {
- if (dev->capture.last_timestamp) {
+++ /dev/null
-From f658f48d662c5ecd84af235f47cc48636b9a55e2 Mon Sep 17 00:00:00 2001
-Date: Thu, 27 Sep 2018 17:50:39 -0700
-Subject: [PATCH] staging: bcm2835-camera: Avoid unneeded internal
- declaration warning
-
-Clang warns:
-
-drivers/staging/vc04_services/bcm2835-camera/controls.c:59:18: warning:
-variable 'mains_freq_qmenu' is not needed and will not be emitted
-[-Wunneeded-internal-declaration]
-static const s64 mains_freq_qmenu[] = {
- ^
-1 warning generated.
-
-This is because mains_freq_qmenu is currently only used in an ARRAY_SIZE
-macro, which is a compile time evaluation in this case. Avoid this by
-adding mains_freq_qmenu as the imenu member of this structure, which
-matches all other controls that uses the ARRAY_SIZE macro in v4l2_ctrls.
-This turns out to be a no-op because V4L2_CID_MPEG_VIDEO_BITRATE_MODE is
-defined as a MMAL_CONTROL_TYPE_STD_MENU, which does not pass the imenu
-definition along to v4l2_ctrl_new in bm2835_mmal_init_controls.
-
-Link: https://github.com/ClangBuiltLinux/linux/issues/122
----
- drivers/staging/vc04_services/bcm2835-camera/controls.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -1109,7 +1109,7 @@ static const struct bm2835_mmal_v4l2_ctr
- {
- V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU,
- 0, ARRAY_SIZE(mains_freq_qmenu) - 1,
-- 1, 1, NULL,
-+ 1, 1, mains_freq_qmenu,
- MMAL_PARAMETER_FLICKER_AVOID,
- &ctrl_set_flicker_avoidance,
- false
--- /dev/null
+From 925b969a16a2e3503803c47a87f093f88d1b2060 Mon Sep 17 00:00:00 2001
+Date: Mon, 3 Dec 2018 13:15:20 +0000
+Subject: [PATCH] staging: bcm2835-camera: Unify header inclusion
+ defines
+
+Most of the headers use ifndef FOO_H, whilst mmal-parameters.h
+used ifndef __FOO_H.
+
+Revise mmal-parameters.h to drop the underscores and make the
+headers all consistent.
+
+---
+ .../staging/vc04_services/bcm2835-camera/mmal-parameters.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
+@@ -19,8 +19,8 @@
+ * @{
+ */
+
+-#ifndef __MMAL_PARAMETERS_H
+-#define __MMAL_PARAMETERS_H
++#ifndef MMAL_PARAMETERS_H
++#define MMAL_PARAMETERS_H
+
+ /** Common parameter ID group, used with many types of component. */
+ #define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
+++ /dev/null
-From c37e8c9137e4858ed86e211f3fddbb9d9af08532 Mon Sep 17 00:00:00 2001
-Date: Mon, 24 Sep 2018 16:21:06 +0100
-Subject: [PATCH] staging: bcm2835-camera: Add multiple inclusion
- protection to headers
-
-mmal-common.h and mmal-msg.h didn't have the normal
-ifndef FOO / define FOO / endif protection to stop it being
-included multiple times. Add it.
-
----
- drivers/staging/vc04_services/bcm2835-camera/mmal-common.h | 3 +++
- drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h | 3 +++
- 2 files changed, 6 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
-@@ -13,6 +13,8 @@
- * MMAL structures
- *
- */
-+#ifndef MMAL_COMMON_H
-+#define MMAL_COMMON_H
-
- #define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
- #define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l')
-@@ -56,3 +58,4 @@ struct mmal_colourfx {
- u32 u;
- u32 v;
- };
-+#endif
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
-@@ -23,6 +23,8 @@
- * implementation uses fixed size types and not the enums (though the
- * comments have the actual enum type
- */
-+#ifndef MMAL_MSG_H
-+#define MMAL_MSG_H
-
- #define VC_MMAL_VER 15
- #define VC_MMAL_MIN_VER 10
-@@ -401,3 +403,4 @@ struct mmal_msg {
- u8 payload[MMAL_MSG_MAX_PAYLOAD];
- } u;
- };
-+#endif
--- /dev/null
+From 11129d36669a3efee5dd0d49f969f11c42764f9d Mon Sep 17 00:00:00 2001
+Date: Mon, 29 Oct 2018 15:55:42 +0000
+Subject: [PATCH] staging: bcm2835-camera: Fix alignment should match
+ open parenthesis
+
+Fix up checkpatch "Alignment should match open parenthesis" errors
+
+---
+ .../staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -1934,7 +1934,7 @@ static int bcm2835_mmal_probe(struct pla
+ ret = bm2835_mmal_init_controls(dev, &dev->ctrl_handler);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev, "%s: could not init controls: %d\n",
+- __func__, ret);
++ __func__, ret);
+ goto unreg_dev;
+ }
+ dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
+@@ -1944,7 +1944,7 @@ static int bcm2835_mmal_probe(struct pla
+ ret = mmal_init(dev);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev, "%s: mmal init failed: %d\n",
+- __func__, ret);
++ __func__, ret);
+ goto unreg_dev;
+ }
+ /* initialize queue */
+@@ -1966,7 +1966,7 @@ static int bcm2835_mmal_probe(struct pla
+ ret = bm2835_mmal_init_device(dev, &dev->vdev);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev, "%s: could not init device: %d\n",
+- __func__, ret);
++ __func__, ret);
+ goto unreg_dev;
+ }
+
+@@ -1976,7 +1976,7 @@ static int bcm2835_mmal_probe(struct pla
+ ret = mmal_setup_components(dev, &default_v4l2_format);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev, "%s: could not setup components: %d\n",
+- __func__, ret);
++ __func__, ret);
+ goto unreg_dev;
+ }
+
--- /dev/null
+From d1f9d21346c642fadb2676077b050106afaf7579 Mon Sep 17 00:00:00 2001
+Date: Mon, 29 Oct 2018 15:58:14 +0000
+Subject: [PATCH] staging: bcm2835-camera: Fix multiple assignments
+ should be avoided
+
+Clear checkpatch complaints of "multiple assignments should be avoided"
+
+---
+ .../staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -1065,11 +1065,12 @@ static int mmal_setup_components(struct
+ /* Make a further decision on port based on resolution */
+ if (f->fmt.pix.width <= max_video_width &&
+ f->fmt.pix.height <= max_video_height)
+- camera_port = port =
++ camera_port =
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
+ else
+- camera_port = port =
++ camera_port =
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
++ port = camera_port;
+ break;
+ case COMP_IMAGE_ENCODE:
+ encode_component = dev->component[COMP_IMAGE_ENCODE];
+++ /dev/null
-From 925b969a16a2e3503803c47a87f093f88d1b2060 Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Dec 2018 13:15:20 +0000
-Subject: [PATCH] staging: bcm2835-camera: Unify header inclusion
- defines
-
-Most of the headers use ifndef FOO_H, whilst mmal-parameters.h
-used ifndef __FOO_H.
-
-Revise mmal-parameters.h to drop the underscores and make the
-headers all consistent.
-
----
- .../staging/vc04_services/bcm2835-camera/mmal-parameters.h | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
-@@ -19,8 +19,8 @@
- * @{
- */
-
--#ifndef __MMAL_PARAMETERS_H
--#define __MMAL_PARAMETERS_H
-+#ifndef MMAL_PARAMETERS_H
-+#define MMAL_PARAMETERS_H
-
- /** Common parameter ID group, used with many types of component. */
- #define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
+++ /dev/null
-From 11129d36669a3efee5dd0d49f969f11c42764f9d Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Oct 2018 15:55:42 +0000
-Subject: [PATCH] staging: bcm2835-camera: Fix alignment should match
- open parenthesis
-
-Fix up checkpatch "Alignment should match open parenthesis" errors
-
----
- .../staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -1934,7 +1934,7 @@ static int bcm2835_mmal_probe(struct pla
- ret = bm2835_mmal_init_controls(dev, &dev->ctrl_handler);
- if (ret < 0) {
- v4l2_err(&dev->v4l2_dev, "%s: could not init controls: %d\n",
-- __func__, ret);
-+ __func__, ret);
- goto unreg_dev;
- }
- dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
-@@ -1944,7 +1944,7 @@ static int bcm2835_mmal_probe(struct pla
- ret = mmal_init(dev);
- if (ret < 0) {
- v4l2_err(&dev->v4l2_dev, "%s: mmal init failed: %d\n",
-- __func__, ret);
-+ __func__, ret);
- goto unreg_dev;
- }
- /* initialize queue */
-@@ -1966,7 +1966,7 @@ static int bcm2835_mmal_probe(struct pla
- ret = bm2835_mmal_init_device(dev, &dev->vdev);
- if (ret < 0) {
- v4l2_err(&dev->v4l2_dev, "%s: could not init device: %d\n",
-- __func__, ret);
-+ __func__, ret);
- goto unreg_dev;
- }
-
-@@ -1976,7 +1976,7 @@ static int bcm2835_mmal_probe(struct pla
- ret = mmal_setup_components(dev, &default_v4l2_format);
- if (ret < 0) {
- v4l2_err(&dev->v4l2_dev, "%s: could not setup components: %d\n",
-- __func__, ret);
-+ __func__, ret);
- goto unreg_dev;
- }
-
--- /dev/null
+From be10ef41af683e175521f80b49b99d7ddeac2f2c Mon Sep 17 00:00:00 2001
+Date: Mon, 29 Oct 2018 16:08:41 +0000
+Subject: [PATCH] staging: bcm2835-camera: Fix up all formatting in
+ mmal-paramters.h
+
+Fixes up all checkpatch errors in mmal-parameters.h
+
+---
+ .../bcm2835-camera/mmal-parameters.h | 273 +++++++++++-------
+ 1 file changed, 165 insertions(+), 108 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
++++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
+@@ -23,148 +23,204 @@
+ #define MMAL_PARAMETERS_H
+
+ /** Common parameter ID group, used with many types of component. */
+-#define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
++#define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
+ /** Camera-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16)
++#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16)
+ /** Video-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16)
++#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16)
+ /** Audio-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16)
++#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16)
+ /** Clock-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16)
++#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16)
+ /** Miracast-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16)
++#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16)
+
+ /* Common parameters */
+ enum mmal_parameter_common_type {
+- MMAL_PARAMETER_UNUSED /**< Never a valid parameter ID */
+- = MMAL_PARAMETER_GROUP_COMMON,
+- MMAL_PARAMETER_SUPPORTED_ENCODINGS, /**< MMAL_PARAMETER_ENCODING_T */
+- MMAL_PARAMETER_URI, /**< MMAL_PARAMETER_URI_T */
++ /**< Never a valid parameter ID */
++ MMAL_PARAMETER_UNUSED = MMAL_PARAMETER_GROUP_COMMON,
+
+- /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
++ /**< MMAL_PARAMETER_ENCODING_T */
++ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
++ /**< MMAL_PARAMETER_URI_T */
++ MMAL_PARAMETER_URI,
++ /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
+ MMAL_PARAMETER_CHANGE_EVENT_REQUEST,
+-
+- /** MMAL_PARAMETER_BOOLEAN_T */
++ /** MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_ZERO_COPY,
+-
+- /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
++ /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
+ MMAL_PARAMETER_BUFFER_REQUIREMENTS,
+-
+- MMAL_PARAMETER_STATISTICS, /**< MMAL_PARAMETER_STATISTICS_T */
+- MMAL_PARAMETER_CORE_STATISTICS, /**< MMAL_PARAMETER_CORE_STATISTICS_T */
+- MMAL_PARAMETER_MEM_USAGE, /**< MMAL_PARAMETER_MEM_USAGE_T */
+- MMAL_PARAMETER_BUFFER_FLAG_FILTER, /**< MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_SEEK, /**< MMAL_PARAMETER_SEEK_T */
+- MMAL_PARAMETER_POWERMON_ENABLE, /**< MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_LOGGING, /**< MMAL_PARAMETER_LOGGING_T */
+- MMAL_PARAMETER_SYSTEM_TIME, /**< MMAL_PARAMETER_UINT64_T */
+- MMAL_PARAMETER_NO_IMAGE_PADDING /**< MMAL_PARAMETER_BOOLEAN_T */
++ /**< MMAL_PARAMETER_STATISTICS_T */
++ MMAL_PARAMETER_STATISTICS,
++ /**< MMAL_PARAMETER_CORE_STATISTICS_T */
++ MMAL_PARAMETER_CORE_STATISTICS,
++ /**< MMAL_PARAMETER_MEM_USAGE_T */
++ MMAL_PARAMETER_MEM_USAGE,
++ /**< MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_BUFFER_FLAG_FILTER,
++ /**< MMAL_PARAMETER_SEEK_T */
++ MMAL_PARAMETER_SEEK,
++ /**< MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_POWERMON_ENABLE,
++ /**< MMAL_PARAMETER_LOGGING_T */
++ MMAL_PARAMETER_LOGGING,
++ /**< MMAL_PARAMETER_UINT64_T */
++ MMAL_PARAMETER_SYSTEM_TIME,
++ /**< MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_NO_IMAGE_PADDING,
+ };
+
+ /* camera parameters */
+
+ enum mmal_parameter_camera_type {
+ /* 0 */
+- /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
+- MMAL_PARAMETER_THUMBNAIL_CONFIGURATION
+- = MMAL_PARAMETER_GROUP_CAMERA,
+- MMAL_PARAMETER_CAPTURE_QUALITY, /**< Unused? */
+- MMAL_PARAMETER_ROTATION, /**< @ref MMAL_PARAMETER_INT32_T */
+- MMAL_PARAMETER_EXIF_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_EXIF, /**< @ref MMAL_PARAMETER_EXIF_T */
+- MMAL_PARAMETER_AWB_MODE, /**< @ref MMAL_PARAM_AWBMODE_T */
+- MMAL_PARAMETER_IMAGE_EFFECT, /**< @ref MMAL_PARAMETER_IMAGEFX_T */
+- MMAL_PARAMETER_COLOUR_EFFECT, /**< @ref MMAL_PARAMETER_COLOURFX_T */
+- MMAL_PARAMETER_FLICKER_AVOID, /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
+- MMAL_PARAMETER_FLASH, /**< @ref MMAL_PARAMETER_FLASH_T */
+- MMAL_PARAMETER_REDEYE, /**< @ref MMAL_PARAMETER_REDEYE_T */
+- MMAL_PARAMETER_FOCUS, /**< @ref MMAL_PARAMETER_FOCUS_T */
+- MMAL_PARAMETER_FOCAL_LENGTHS, /**< Unused? */
+- MMAL_PARAMETER_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
+- MMAL_PARAMETER_ZOOM, /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
+- MMAL_PARAMETER_MIRROR, /**< @ref MMAL_PARAMETER_MIRROR_T */
++ /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
++ MMAL_PARAMETER_THUMBNAIL_CONFIGURATION =
++ MMAL_PARAMETER_GROUP_CAMERA,
++ /**< Unused? */
++ MMAL_PARAMETER_CAPTURE_QUALITY,
++ /**< @ref MMAL_PARAMETER_INT32_T */
++ MMAL_PARAMETER_ROTATION,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_EXIF_DISABLE,
++ /**< @ref MMAL_PARAMETER_EXIF_T */
++ MMAL_PARAMETER_EXIF,
++ /**< @ref MMAL_PARAM_AWBMODE_T */
++ MMAL_PARAMETER_AWB_MODE,
++ /**< @ref MMAL_PARAMETER_IMAGEFX_T */
++ MMAL_PARAMETER_IMAGE_EFFECT,
++ /**< @ref MMAL_PARAMETER_COLOURFX_T */
++ MMAL_PARAMETER_COLOUR_EFFECT,
++ /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
++ MMAL_PARAMETER_FLICKER_AVOID,
++ /**< @ref MMAL_PARAMETER_FLASH_T */
++ MMAL_PARAMETER_FLASH,
++ /**< @ref MMAL_PARAMETER_REDEYE_T */
++ MMAL_PARAMETER_REDEYE,
++ /**< @ref MMAL_PARAMETER_FOCUS_T */
++ MMAL_PARAMETER_FOCUS,
++ /**< Unused? */
++ MMAL_PARAMETER_FOCAL_LENGTHS,
++ /**< @ref MMAL_PARAMETER_INT32_T */
++ MMAL_PARAMETER_EXPOSURE_COMP,
++ /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
++ MMAL_PARAMETER_ZOOM,
++ /**< @ref MMAL_PARAMETER_MIRROR_T */
++ MMAL_PARAMETER_MIRROR,
+
+ /* 0x10 */
+- MMAL_PARAMETER_CAMERA_NUM, /**< @ref MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_EXPOSURE_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
+- MMAL_PARAMETER_EXP_METERING_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
+- MMAL_PARAMETER_FOCUS_STATUS, /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
+- MMAL_PARAMETER_CAMERA_CONFIG, /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
+- MMAL_PARAMETER_CAPTURE_STATUS, /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
+- MMAL_PARAMETER_FACE_TRACK, /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
+- MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_JPEG_Q_FACTOR, /**< @ref MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_FRAME_RATE, /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
+- MMAL_PARAMETER_USE_STC, /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
+- MMAL_PARAMETER_CAMERA_INFO, /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
+- MMAL_PARAMETER_VIDEO_STABILISATION, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_FACE_TRACK_RESULTS, /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
+- MMAL_PARAMETER_ENABLE_RAW_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ /**< @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_CAMERA_NUM,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_CAPTURE,
++ /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
++ MMAL_PARAMETER_EXPOSURE_MODE,
++ /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
++ MMAL_PARAMETER_EXP_METERING_MODE,
++ /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
++ MMAL_PARAMETER_FOCUS_STATUS,
++ /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
++ MMAL_PARAMETER_CAMERA_CONFIG,
++ /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
++ MMAL_PARAMETER_CAPTURE_STATUS,
++ /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
++ MMAL_PARAMETER_FACE_TRACK,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS,
++ /**< @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_JPEG_Q_FACTOR,
++ /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
++ MMAL_PARAMETER_FRAME_RATE,
++ /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
++ MMAL_PARAMETER_USE_STC,
++ /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
++ MMAL_PARAMETER_CAMERA_INFO,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_STABILISATION,
++ /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
++ MMAL_PARAMETER_FACE_TRACK_RESULTS,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ENABLE_RAW_CAPTURE,
+
+ /* 0x20 */
+- MMAL_PARAMETER_DPF_FILE, /**< @ref MMAL_PARAMETER_URI_T */
+- MMAL_PARAMETER_ENABLE_DPF_FILE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_DPF_FAIL_IS_FATAL, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_CAPTURE_MODE, /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
+- MMAL_PARAMETER_FOCUS_REGIONS, /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
+- MMAL_PARAMETER_INPUT_CROP, /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
+- MMAL_PARAMETER_SENSOR_INFORMATION, /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
+- MMAL_PARAMETER_FLASH_SELECT, /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
+- MMAL_PARAMETER_FIELD_OF_VIEW, /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
+- MMAL_PARAMETER_HIGH_DYNAMIC_RANGE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, /**< @ref MMAL_PARAMETER_DRC_T */
+- MMAL_PARAMETER_ALGORITHM_CONTROL, /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
+- MMAL_PARAMETER_SHARPNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
+- MMAL_PARAMETER_CONTRAST, /**< @ref MMAL_PARAMETER_RATIONAL_T */
+- MMAL_PARAMETER_BRIGHTNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
+- MMAL_PARAMETER_SATURATION, /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ /**< @ref MMAL_PARAMETER_URI_T */
++ MMAL_PARAMETER_DPF_FILE,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ENABLE_DPF_FILE,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_DPF_FAIL_IS_FATAL,
++ /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
++ MMAL_PARAMETER_CAPTURE_MODE,
++ /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
++ MMAL_PARAMETER_FOCUS_REGIONS,
++ /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
++ MMAL_PARAMETER_INPUT_CROP,
++ /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
++ MMAL_PARAMETER_SENSOR_INFORMATION,
++ /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
++ MMAL_PARAMETER_FLASH_SELECT,
++ /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
++ MMAL_PARAMETER_FIELD_OF_VIEW,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,
++ /**< @ref MMAL_PARAMETER_DRC_T */
++ MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION,
++ /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
++ MMAL_PARAMETER_ALGORITHM_CONTROL,
++ /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_SHARPNESS,
++ /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_CONTRAST,
++ /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_BRIGHTNESS,
++ /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_SATURATION,
+
+ /* 0x30 */
+- MMAL_PARAMETER_ISO, /**< @ref MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_ANTISHAKE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+-
+- /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
++ /**< @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_ISO,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ANTISHAKE,
++ /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
+ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
+-
+- /** @ref MMAL_PARAMETER_UINT32_T */
++ /** @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_CAMERA_MIN_ISO,
+-
+- /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
++ /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
+ MMAL_PARAMETER_CAMERA_USE_CASE,
+-
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_CAPTURE_STATS_PASS,
+-
+- /** @ref MMAL_PARAMETER_UINT32_T */
++ /** @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_ENABLE_REGISTER_FILE,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
+-
+- /** @ref MMAL_PARAMETER_CONFIGFILE_T */
++ /** @ref MMAL_PARAMETER_CONFIGFILE_T */
+ MMAL_PARAMETER_CONFIGFILE_REGISTERS,
+-
+- /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
++ /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
+ MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,
+- MMAL_PARAMETER_JPEG_ATTACH_LOG, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_ZERO_SHUTTER_LAG, /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
+- MMAL_PARAMETER_FPS_RANGE, /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
+- MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_JPEG_ATTACH_LOG,
++ /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
++ MMAL_PARAMETER_ZERO_SHUTTER_LAG,
++ /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
++ MMAL_PARAMETER_FPS_RANGE,
++ /**< @ref MMAL_PARAMETER_INT32_T */
++ MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP,
+
+ /* 0x40 */
+- MMAL_PARAMETER_SW_SHARPEN_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_FLASH_REQUIRED, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_SW_SATURATION_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_SHUTTER_SPEED, /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_CUSTOM_AWB_GAINS, /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_SW_SHARPEN_DISABLE,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_FLASH_REQUIRED,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_SW_SATURATION_DISABLE,
++ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_SHUTTER_SPEED,
++ /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
++ MMAL_PARAMETER_CUSTOM_AWB_GAINS,
+ };
+
+ struct mmal_parameter_rational {
+@@ -411,7 +467,8 @@ enum mmal_parameter_video_type {
+ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
+
+ /** @ref MMAL_PARAMETER_UINT32_T.
+- * Setting the value to zero resets to the default (one slice per frame).
++ * Setting the value to zero resets to the default (one slice per
++ * frame).
+ */
+ MMAL_PARAMETER_MB_ROWS_PER_SLICE,
+
+++ /dev/null
-From d1f9d21346c642fadb2676077b050106afaf7579 Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Oct 2018 15:58:14 +0000
-Subject: [PATCH] staging: bcm2835-camera: Fix multiple assignments
- should be avoided
-
-Clear checkpatch complaints of "multiple assignments should be avoided"
-
----
- .../staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -1065,11 +1065,12 @@ static int mmal_setup_components(struct
- /* Make a further decision on port based on resolution */
- if (f->fmt.pix.width <= max_video_width &&
- f->fmt.pix.height <= max_video_height)
-- camera_port = port =
-+ camera_port =
- &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
- else
-- camera_port = port =
-+ camera_port =
- &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
-+ port = camera_port;
- break;
- case COMP_IMAGE_ENCODE:
- encode_component = dev->component[COMP_IMAGE_ENCODE];
--- /dev/null
+From 316725374b7c221f5d43b31ee9cbe738d3df4709 Mon Sep 17 00:00:00 2001
+Date: Fri, 28 Sep 2018 10:17:11 +0100
+Subject: [PATCH] staging: bcm2835-camera: Use enums for max value in
+ controls
+
+Controls of type MMAL_CONTROL_TYPE_STD_MENU call v4l2_ctrl_new_std_menu
+with a max value and a mask. The max value is one of the defined
+values for the control, however in the config array there are several
+entries where raw numbers have been used instead. Replace these
+with the appropriate enum.
+
+---
+ .../vc04_services/bcm2835-camera/controls.c | 37 +++++++------------
+ 1 file changed, 13 insertions(+), 24 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -58,19 +58,6 @@ static const uint32_t iso_values[] = {
+ 0, 100, 200, 400, 800,
+ };
+
+-static const s64 mains_freq_qmenu[] = {
+- V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
+- V4L2_CID_POWER_LINE_FREQUENCY_50HZ,
+- V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+- V4L2_CID_POWER_LINE_FREQUENCY_AUTO
+-};
+-
+-/* Supported video encode modes */
+-static const s64 bitrate_mode_qmenu[] = {
+- (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+- (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+-};
+-
+ enum bm2835_mmal_ctrl_type {
+ MMAL_CONTROL_TYPE_STD,
+ MMAL_CONTROL_TYPE_STD_MENU,
+@@ -966,8 +953,8 @@ static const struct bm2835_mmal_v4l2_ctr
+ },
+ {
+ V4L2_CID_ISO_SENSITIVITY_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
+- 0, 1, V4L2_ISO_SENSITIVITY_AUTO, 1, NULL,
+- MMAL_PARAMETER_ISO,
++ 0, V4L2_ISO_SENSITIVITY_AUTO, V4L2_ISO_SENSITIVITY_AUTO, 1,
++ NULL, MMAL_PARAMETER_ISO,
+ &ctrl_set_iso,
+ false
+ },
+@@ -984,8 +971,8 @@ static const struct bm2835_mmal_v4l2_ctr
+ */
+ {
+ V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
+- ~0x03, 3, V4L2_EXPOSURE_AUTO, 0, NULL,
+- MMAL_PARAMETER_EXPOSURE_MODE,
++ ~0x03, V4L2_EXPOSURE_APERTURE_PRIORITY, V4L2_EXPOSURE_AUTO, 0,
++ NULL, MMAL_PARAMETER_EXPOSURE_MODE,
+ &ctrl_set_exposure,
+ false
+ },
+@@ -1021,7 +1008,8 @@ static const struct bm2835_mmal_v4l2_ctr
+ {
+ V4L2_CID_EXPOSURE_METERING,
+ MMAL_CONTROL_TYPE_STD_MENU,
+- ~0x7, 2, V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
++ ~0x7, V4L2_EXPOSURE_METERING_SPOT,
++ V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
+ MMAL_PARAMETER_EXP_METERING_MODE,
+ &ctrl_set_metering_mode,
+ false
+@@ -1029,7 +1017,8 @@ static const struct bm2835_mmal_v4l2_ctr
+ {
+ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+ MMAL_CONTROL_TYPE_STD_MENU,
+- ~0x3ff, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL,
++ ~0x3ff, V4L2_WHITE_BALANCE_SHADE, V4L2_WHITE_BALANCE_AUTO, 0,
++ NULL,
+ MMAL_PARAMETER_AWB_MODE,
+ &ctrl_set_awb_mode,
+ false
+@@ -1050,7 +1039,7 @@ static const struct bm2835_mmal_v4l2_ctr
+ },
+ {
+ V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU,
+- 0, 15, V4L2_COLORFX_NONE, 0, NULL,
++ 0, V4L2_COLORFX_SET_CBCR, V4L2_COLORFX_NONE, 0, NULL,
+ MMAL_PARAMETER_IMAGE_EFFECT,
+ &ctrl_set_image_effect,
+ false
+@@ -1085,8 +1074,8 @@ static const struct bm2835_mmal_v4l2_ctr
+ },
+ {
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
+- 0, ARRAY_SIZE(bitrate_mode_qmenu) - 1,
+- 0, 0, bitrate_mode_qmenu,
++ 0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
++ 0, 0, NULL,
+ MMAL_PARAMETER_RATECONTROL,
+ &ctrl_set_bitrate_mode,
+ false
+@@ -1108,8 +1097,8 @@ static const struct bm2835_mmal_v4l2_ctr
+ },
+ {
+ V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU,
+- 0, ARRAY_SIZE(mains_freq_qmenu) - 1,
+- 1, 1, mains_freq_qmenu,
++ 0, V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
++ 1, 1, NULL,
+ MMAL_PARAMETER_FLICKER_AVOID,
+ &ctrl_set_flicker_avoidance,
+ false
--- /dev/null
+From f07147faddeb0e99bfe181af78fcda9ea7f06c3d Mon Sep 17 00:00:00 2001
+Date: Mon, 8 Oct 2018 18:26:15 +0100
+Subject: [PATCH] staging: bcm2835-camera: Correct
+ V4L2_CID_COLORFX_CBCR behaviour
+
+With V4L2_CID_COLORFX_CBCR calling ctrl_set_colfx it was incorrectly
+assigning the colour values to the enable field of dev->colourfx
+instead of the u and v fields.
+
+Correct the assignments.
+
+Reported as a Coverity issue
+Detected by CoverityScan CID#1419711 ("Unused value")
+
+---
+ drivers/staging/vc04_services/bcm2835-camera/controls.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -578,8 +578,8 @@ static int ctrl_set_colfx(struct bm2835_
+
+ control = &dev->component[COMP_CAMERA]->control;
+
+- dev->colourfx.enable = (ctrl->val & 0xff00) >> 8;
+- dev->colourfx.enable = ctrl->val & 0xff;
++ dev->colourfx.u = (ctrl->val & 0xff00) >> 8;
++ dev->colourfx.v = ctrl->val & 0xff;
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance, control,
+ MMAL_PARAMETER_COLOUR_EFFECT,
+++ /dev/null
-From be10ef41af683e175521f80b49b99d7ddeac2f2c Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Oct 2018 16:08:41 +0000
-Subject: [PATCH] staging: bcm2835-camera: Fix up all formatting in
- mmal-paramters.h
-
-Fixes up all checkpatch errors in mmal-parameters.h
-
----
- .../bcm2835-camera/mmal-parameters.h | 273 +++++++++++-------
- 1 file changed, 165 insertions(+), 108 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
-+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
-@@ -23,148 +23,204 @@
- #define MMAL_PARAMETERS_H
-
- /** Common parameter ID group, used with many types of component. */
--#define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
-+#define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
- /** Camera-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16)
-+#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16)
- /** Video-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16)
-+#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16)
- /** Audio-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16)
-+#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16)
- /** Clock-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16)
-+#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16)
- /** Miracast-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16)
-+#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16)
-
- /* Common parameters */
- enum mmal_parameter_common_type {
-- MMAL_PARAMETER_UNUSED /**< Never a valid parameter ID */
-- = MMAL_PARAMETER_GROUP_COMMON,
-- MMAL_PARAMETER_SUPPORTED_ENCODINGS, /**< MMAL_PARAMETER_ENCODING_T */
-- MMAL_PARAMETER_URI, /**< MMAL_PARAMETER_URI_T */
-+ /**< Never a valid parameter ID */
-+ MMAL_PARAMETER_UNUSED = MMAL_PARAMETER_GROUP_COMMON,
-
-- /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
-+ /**< MMAL_PARAMETER_ENCODING_T */
-+ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
-+ /**< MMAL_PARAMETER_URI_T */
-+ MMAL_PARAMETER_URI,
-+ /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
- MMAL_PARAMETER_CHANGE_EVENT_REQUEST,
--
-- /** MMAL_PARAMETER_BOOLEAN_T */
-+ /** MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_ZERO_COPY,
--
-- /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
-+ /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
- MMAL_PARAMETER_BUFFER_REQUIREMENTS,
--
-- MMAL_PARAMETER_STATISTICS, /**< MMAL_PARAMETER_STATISTICS_T */
-- MMAL_PARAMETER_CORE_STATISTICS, /**< MMAL_PARAMETER_CORE_STATISTICS_T */
-- MMAL_PARAMETER_MEM_USAGE, /**< MMAL_PARAMETER_MEM_USAGE_T */
-- MMAL_PARAMETER_BUFFER_FLAG_FILTER, /**< MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_SEEK, /**< MMAL_PARAMETER_SEEK_T */
-- MMAL_PARAMETER_POWERMON_ENABLE, /**< MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_LOGGING, /**< MMAL_PARAMETER_LOGGING_T */
-- MMAL_PARAMETER_SYSTEM_TIME, /**< MMAL_PARAMETER_UINT64_T */
-- MMAL_PARAMETER_NO_IMAGE_PADDING /**< MMAL_PARAMETER_BOOLEAN_T */
-+ /**< MMAL_PARAMETER_STATISTICS_T */
-+ MMAL_PARAMETER_STATISTICS,
-+ /**< MMAL_PARAMETER_CORE_STATISTICS_T */
-+ MMAL_PARAMETER_CORE_STATISTICS,
-+ /**< MMAL_PARAMETER_MEM_USAGE_T */
-+ MMAL_PARAMETER_MEM_USAGE,
-+ /**< MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_BUFFER_FLAG_FILTER,
-+ /**< MMAL_PARAMETER_SEEK_T */
-+ MMAL_PARAMETER_SEEK,
-+ /**< MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_POWERMON_ENABLE,
-+ /**< MMAL_PARAMETER_LOGGING_T */
-+ MMAL_PARAMETER_LOGGING,
-+ /**< MMAL_PARAMETER_UINT64_T */
-+ MMAL_PARAMETER_SYSTEM_TIME,
-+ /**< MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_NO_IMAGE_PADDING,
- };
-
- /* camera parameters */
-
- enum mmal_parameter_camera_type {
- /* 0 */
-- /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
-- MMAL_PARAMETER_THUMBNAIL_CONFIGURATION
-- = MMAL_PARAMETER_GROUP_CAMERA,
-- MMAL_PARAMETER_CAPTURE_QUALITY, /**< Unused? */
-- MMAL_PARAMETER_ROTATION, /**< @ref MMAL_PARAMETER_INT32_T */
-- MMAL_PARAMETER_EXIF_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_EXIF, /**< @ref MMAL_PARAMETER_EXIF_T */
-- MMAL_PARAMETER_AWB_MODE, /**< @ref MMAL_PARAM_AWBMODE_T */
-- MMAL_PARAMETER_IMAGE_EFFECT, /**< @ref MMAL_PARAMETER_IMAGEFX_T */
-- MMAL_PARAMETER_COLOUR_EFFECT, /**< @ref MMAL_PARAMETER_COLOURFX_T */
-- MMAL_PARAMETER_FLICKER_AVOID, /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
-- MMAL_PARAMETER_FLASH, /**< @ref MMAL_PARAMETER_FLASH_T */
-- MMAL_PARAMETER_REDEYE, /**< @ref MMAL_PARAMETER_REDEYE_T */
-- MMAL_PARAMETER_FOCUS, /**< @ref MMAL_PARAMETER_FOCUS_T */
-- MMAL_PARAMETER_FOCAL_LENGTHS, /**< Unused? */
-- MMAL_PARAMETER_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
-- MMAL_PARAMETER_ZOOM, /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
-- MMAL_PARAMETER_MIRROR, /**< @ref MMAL_PARAMETER_MIRROR_T */
-+ /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
-+ MMAL_PARAMETER_THUMBNAIL_CONFIGURATION =
-+ MMAL_PARAMETER_GROUP_CAMERA,
-+ /**< Unused? */
-+ MMAL_PARAMETER_CAPTURE_QUALITY,
-+ /**< @ref MMAL_PARAMETER_INT32_T */
-+ MMAL_PARAMETER_ROTATION,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_EXIF_DISABLE,
-+ /**< @ref MMAL_PARAMETER_EXIF_T */
-+ MMAL_PARAMETER_EXIF,
-+ /**< @ref MMAL_PARAM_AWBMODE_T */
-+ MMAL_PARAMETER_AWB_MODE,
-+ /**< @ref MMAL_PARAMETER_IMAGEFX_T */
-+ MMAL_PARAMETER_IMAGE_EFFECT,
-+ /**< @ref MMAL_PARAMETER_COLOURFX_T */
-+ MMAL_PARAMETER_COLOUR_EFFECT,
-+ /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
-+ MMAL_PARAMETER_FLICKER_AVOID,
-+ /**< @ref MMAL_PARAMETER_FLASH_T */
-+ MMAL_PARAMETER_FLASH,
-+ /**< @ref MMAL_PARAMETER_REDEYE_T */
-+ MMAL_PARAMETER_REDEYE,
-+ /**< @ref MMAL_PARAMETER_FOCUS_T */
-+ MMAL_PARAMETER_FOCUS,
-+ /**< Unused? */
-+ MMAL_PARAMETER_FOCAL_LENGTHS,
-+ /**< @ref MMAL_PARAMETER_INT32_T */
-+ MMAL_PARAMETER_EXPOSURE_COMP,
-+ /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
-+ MMAL_PARAMETER_ZOOM,
-+ /**< @ref MMAL_PARAMETER_MIRROR_T */
-+ MMAL_PARAMETER_MIRROR,
-
- /* 0x10 */
-- MMAL_PARAMETER_CAMERA_NUM, /**< @ref MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_EXPOSURE_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
-- MMAL_PARAMETER_EXP_METERING_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
-- MMAL_PARAMETER_FOCUS_STATUS, /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
-- MMAL_PARAMETER_CAMERA_CONFIG, /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
-- MMAL_PARAMETER_CAPTURE_STATUS, /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
-- MMAL_PARAMETER_FACE_TRACK, /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
-- MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_JPEG_Q_FACTOR, /**< @ref MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_FRAME_RATE, /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
-- MMAL_PARAMETER_USE_STC, /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
-- MMAL_PARAMETER_CAMERA_INFO, /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
-- MMAL_PARAMETER_VIDEO_STABILISATION, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_FACE_TRACK_RESULTS, /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
-- MMAL_PARAMETER_ENABLE_RAW_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ /**< @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_CAMERA_NUM,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_CAPTURE,
-+ /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
-+ MMAL_PARAMETER_EXPOSURE_MODE,
-+ /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
-+ MMAL_PARAMETER_EXP_METERING_MODE,
-+ /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
-+ MMAL_PARAMETER_FOCUS_STATUS,
-+ /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
-+ MMAL_PARAMETER_CAMERA_CONFIG,
-+ /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
-+ MMAL_PARAMETER_CAPTURE_STATUS,
-+ /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
-+ MMAL_PARAMETER_FACE_TRACK,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS,
-+ /**< @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_JPEG_Q_FACTOR,
-+ /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
-+ MMAL_PARAMETER_FRAME_RATE,
-+ /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
-+ MMAL_PARAMETER_USE_STC,
-+ /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
-+ MMAL_PARAMETER_CAMERA_INFO,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_STABILISATION,
-+ /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
-+ MMAL_PARAMETER_FACE_TRACK_RESULTS,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_ENABLE_RAW_CAPTURE,
-
- /* 0x20 */
-- MMAL_PARAMETER_DPF_FILE, /**< @ref MMAL_PARAMETER_URI_T */
-- MMAL_PARAMETER_ENABLE_DPF_FILE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_DPF_FAIL_IS_FATAL, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_CAPTURE_MODE, /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
-- MMAL_PARAMETER_FOCUS_REGIONS, /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
-- MMAL_PARAMETER_INPUT_CROP, /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
-- MMAL_PARAMETER_SENSOR_INFORMATION, /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
-- MMAL_PARAMETER_FLASH_SELECT, /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
-- MMAL_PARAMETER_FIELD_OF_VIEW, /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
-- MMAL_PARAMETER_HIGH_DYNAMIC_RANGE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, /**< @ref MMAL_PARAMETER_DRC_T */
-- MMAL_PARAMETER_ALGORITHM_CONTROL, /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
-- MMAL_PARAMETER_SHARPNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
-- MMAL_PARAMETER_CONTRAST, /**< @ref MMAL_PARAMETER_RATIONAL_T */
-- MMAL_PARAMETER_BRIGHTNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
-- MMAL_PARAMETER_SATURATION, /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+ /**< @ref MMAL_PARAMETER_URI_T */
-+ MMAL_PARAMETER_DPF_FILE,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_ENABLE_DPF_FILE,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_DPF_FAIL_IS_FATAL,
-+ /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
-+ MMAL_PARAMETER_CAPTURE_MODE,
-+ /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
-+ MMAL_PARAMETER_FOCUS_REGIONS,
-+ /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
-+ MMAL_PARAMETER_INPUT_CROP,
-+ /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
-+ MMAL_PARAMETER_SENSOR_INFORMATION,
-+ /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
-+ MMAL_PARAMETER_FLASH_SELECT,
-+ /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
-+ MMAL_PARAMETER_FIELD_OF_VIEW,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,
-+ /**< @ref MMAL_PARAMETER_DRC_T */
-+ MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION,
-+ /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
-+ MMAL_PARAMETER_ALGORITHM_CONTROL,
-+ /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+ MMAL_PARAMETER_SHARPNESS,
-+ /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+ MMAL_PARAMETER_CONTRAST,
-+ /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+ MMAL_PARAMETER_BRIGHTNESS,
-+ /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+ MMAL_PARAMETER_SATURATION,
-
- /* 0x30 */
-- MMAL_PARAMETER_ISO, /**< @ref MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_ANTISHAKE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
--
-- /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
-+ /**< @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_ISO,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_ANTISHAKE,
-+ /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
- MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
--
-- /** @ref MMAL_PARAMETER_UINT32_T */
-+ /** @ref MMAL_PARAMETER_UINT32_T */
- MMAL_PARAMETER_CAMERA_MIN_ISO,
--
-- /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
-+ /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
- MMAL_PARAMETER_CAMERA_USE_CASE,
--
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_CAPTURE_STATS_PASS,
--
-- /** @ref MMAL_PARAMETER_UINT32_T */
-+ /** @ref MMAL_PARAMETER_UINT32_T */
- MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_ENABLE_REGISTER_FILE,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
--
-- /** @ref MMAL_PARAMETER_CONFIGFILE_T */
-+ /** @ref MMAL_PARAMETER_CONFIGFILE_T */
- MMAL_PARAMETER_CONFIGFILE_REGISTERS,
--
-- /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
-+ /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
- MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,
-- MMAL_PARAMETER_JPEG_ATTACH_LOG, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_ZERO_SHUTTER_LAG, /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
-- MMAL_PARAMETER_FPS_RANGE, /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
-- MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_JPEG_ATTACH_LOG,
-+ /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
-+ MMAL_PARAMETER_ZERO_SHUTTER_LAG,
-+ /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
-+ MMAL_PARAMETER_FPS_RANGE,
-+ /**< @ref MMAL_PARAMETER_INT32_T */
-+ MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP,
-
- /* 0x40 */
-- MMAL_PARAMETER_SW_SHARPEN_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_FLASH_REQUIRED, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_SW_SATURATION_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_SHUTTER_SPEED, /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_CUSTOM_AWB_GAINS, /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_SW_SHARPEN_DISABLE,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_FLASH_REQUIRED,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_SW_SATURATION_DISABLE,
-+ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_SHUTTER_SPEED,
-+ /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
-+ MMAL_PARAMETER_CUSTOM_AWB_GAINS,
- };
-
- struct mmal_parameter_rational {
-@@ -411,7 +467,8 @@ enum mmal_parameter_video_type {
- MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
-
- /** @ref MMAL_PARAMETER_UINT32_T.
-- * Setting the value to zero resets to the default (one slice per frame).
-+ * Setting the value to zero resets to the default (one slice per
-+ * frame).
- */
- MMAL_PARAMETER_MB_ROWS_PER_SLICE,
-
--- /dev/null
+From 37ede4f6a1771b09dea6e8b2fc4d2c5f085a33f3 Mon Sep 17 00:00:00 2001
+Date: Fri, 28 Sep 2018 10:22:26 +0100
+Subject: [PATCH] staging: bcm2835-camera: Remove/amend some obsolete
+ comments
+
+Remove a todo which has been done.
+Remove a template line that was redundant.
+Make a comment clearer as to the non-obvious meaning of a field.
+
+---
+ .../staging/vc04_services/bcm2835-camera/controls.c | 11 +----------
+ 1 file changed, 1 insertion(+), 10 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -965,10 +965,6 @@ static const struct bm2835_mmal_v4l2_ctr
+ &ctrl_set_value,
+ false
+ },
+-/* {
+- * 0, MMAL_CONTROL_TYPE_CLUSTER, 3, 1, 0, NULL, 0, NULL
+- * },
+- */
+ {
+ V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
+ ~0x03, V4L2_EXPOSURE_APERTURE_PRIORITY, V4L2_EXPOSURE_AUTO, 0,
+@@ -976,11 +972,6 @@ static const struct bm2835_mmal_v4l2_ctr
+ &ctrl_set_exposure,
+ false
+ },
+-/* todo this needs mixing in with set exposure
+- * {
+- * V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
+- * },
+- */
+ {
+ V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD,
+ /* Units of 100usecs */
+@@ -1146,7 +1137,7 @@ static const struct bm2835_mmal_v4l2_ctr
+ },
+ {
+ V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
+- -1, /* Min is computed at runtime */
++ -1, /* Min (mask) is computed at runtime */
+ V4L2_SCENE_MODE_TEXT,
+ V4L2_SCENE_MODE_NONE, 1, NULL,
+ MMAL_PARAMETER_PROFILE,
+++ /dev/null
-From 316725374b7c221f5d43b31ee9cbe738d3df4709 Mon Sep 17 00:00:00 2001
-Date: Fri, 28 Sep 2018 10:17:11 +0100
-Subject: [PATCH] staging: bcm2835-camera: Use enums for max value in
- controls
-
-Controls of type MMAL_CONTROL_TYPE_STD_MENU call v4l2_ctrl_new_std_menu
-with a max value and a mask. The max value is one of the defined
-values for the control, however in the config array there are several
-entries where raw numbers have been used instead. Replace these
-with the appropriate enum.
-
----
- .../vc04_services/bcm2835-camera/controls.c | 37 +++++++------------
- 1 file changed, 13 insertions(+), 24 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -58,19 +58,6 @@ static const uint32_t iso_values[] = {
- 0, 100, 200, 400, 800,
- };
-
--static const s64 mains_freq_qmenu[] = {
-- V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
-- V4L2_CID_POWER_LINE_FREQUENCY_50HZ,
-- V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
-- V4L2_CID_POWER_LINE_FREQUENCY_AUTO
--};
--
--/* Supported video encode modes */
--static const s64 bitrate_mode_qmenu[] = {
-- (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
-- (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
--};
--
- enum bm2835_mmal_ctrl_type {
- MMAL_CONTROL_TYPE_STD,
- MMAL_CONTROL_TYPE_STD_MENU,
-@@ -966,8 +953,8 @@ static const struct bm2835_mmal_v4l2_ctr
- },
- {
- V4L2_CID_ISO_SENSITIVITY_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
-- 0, 1, V4L2_ISO_SENSITIVITY_AUTO, 1, NULL,
-- MMAL_PARAMETER_ISO,
-+ 0, V4L2_ISO_SENSITIVITY_AUTO, V4L2_ISO_SENSITIVITY_AUTO, 1,
-+ NULL, MMAL_PARAMETER_ISO,
- &ctrl_set_iso,
- false
- },
-@@ -984,8 +971,8 @@ static const struct bm2835_mmal_v4l2_ctr
- */
- {
- V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
-- ~0x03, 3, V4L2_EXPOSURE_AUTO, 0, NULL,
-- MMAL_PARAMETER_EXPOSURE_MODE,
-+ ~0x03, V4L2_EXPOSURE_APERTURE_PRIORITY, V4L2_EXPOSURE_AUTO, 0,
-+ NULL, MMAL_PARAMETER_EXPOSURE_MODE,
- &ctrl_set_exposure,
- false
- },
-@@ -1021,7 +1008,8 @@ static const struct bm2835_mmal_v4l2_ctr
- {
- V4L2_CID_EXPOSURE_METERING,
- MMAL_CONTROL_TYPE_STD_MENU,
-- ~0x7, 2, V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
-+ ~0x7, V4L2_EXPOSURE_METERING_SPOT,
-+ V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
- MMAL_PARAMETER_EXP_METERING_MODE,
- &ctrl_set_metering_mode,
- false
-@@ -1029,7 +1017,8 @@ static const struct bm2835_mmal_v4l2_ctr
- {
- V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
- MMAL_CONTROL_TYPE_STD_MENU,
-- ~0x3ff, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL,
-+ ~0x3ff, V4L2_WHITE_BALANCE_SHADE, V4L2_WHITE_BALANCE_AUTO, 0,
-+ NULL,
- MMAL_PARAMETER_AWB_MODE,
- &ctrl_set_awb_mode,
- false
-@@ -1050,7 +1039,7 @@ static const struct bm2835_mmal_v4l2_ctr
- },
- {
- V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU,
-- 0, 15, V4L2_COLORFX_NONE, 0, NULL,
-+ 0, V4L2_COLORFX_SET_CBCR, V4L2_COLORFX_NONE, 0, NULL,
- MMAL_PARAMETER_IMAGE_EFFECT,
- &ctrl_set_image_effect,
- false
-@@ -1085,8 +1074,8 @@ static const struct bm2835_mmal_v4l2_ctr
- },
- {
- V4L2_CID_MPEG_VIDEO_BITRATE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
-- 0, ARRAY_SIZE(bitrate_mode_qmenu) - 1,
-- 0, 0, bitrate_mode_qmenu,
-+ 0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
-+ 0, 0, NULL,
- MMAL_PARAMETER_RATECONTROL,
- &ctrl_set_bitrate_mode,
- false
-@@ -1108,8 +1097,8 @@ static const struct bm2835_mmal_v4l2_ctr
- },
- {
- V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU,
-- 0, ARRAY_SIZE(mains_freq_qmenu) - 1,
-- 1, 1, mains_freq_qmenu,
-+ 0, V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
-+ 1, 1, NULL,
- MMAL_PARAMETER_FLICKER_AVOID,
- &ctrl_set_flicker_avoidance,
- false
+++ /dev/null
-From f07147faddeb0e99bfe181af78fcda9ea7f06c3d Mon Sep 17 00:00:00 2001
-Date: Mon, 8 Oct 2018 18:26:15 +0100
-Subject: [PATCH] staging: bcm2835-camera: Correct
- V4L2_CID_COLORFX_CBCR behaviour
-
-With V4L2_CID_COLORFX_CBCR calling ctrl_set_colfx it was incorrectly
-assigning the colour values to the enable field of dev->colourfx
-instead of the u and v fields.
-
-Correct the assignments.
-
-Reported as a Coverity issue
-Detected by CoverityScan CID#1419711 ("Unused value")
-
----
- drivers/staging/vc04_services/bcm2835-camera/controls.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -578,8 +578,8 @@ static int ctrl_set_colfx(struct bm2835_
-
- control = &dev->component[COMP_CAMERA]->control;
-
-- dev->colourfx.enable = (ctrl->val & 0xff00) >> 8;
-- dev->colourfx.enable = ctrl->val & 0xff;
-+ dev->colourfx.u = (ctrl->val & 0xff00) >> 8;
-+ dev->colourfx.v = ctrl->val & 0xff;
-
- ret = vchiq_mmal_port_parameter_set(dev->instance, control,
- MMAL_PARAMETER_COLOUR_EFFECT,
--- /dev/null
+From e7723c6bcf31a440b8762e9e22497ff3fbbb7056 Mon Sep 17 00:00:00 2001
+Date: Mon, 24 Sep 2018 16:30:37 +0100
+Subject: [PATCH] staging: vc04_services: Split vchiq-mmal into a
+ module
+
+In preparation for adding a video codec V4L2 module which also
+wants to use vchiq-mmal functions, split it out into an
+independent module.
+The minimum number of changes have been made to achieve this
+(eg straight moves where possible) so existing checkpatch
+errors will still be present.
+
+---
+ drivers/staging/vc04_services/Kconfig | 1 +
+ drivers/staging/vc04_services/Makefile | 1 +
+ .../vc04_services/bcm2835-camera/Kconfig | 2 +-
+ .../vc04_services/bcm2835-camera/Makefile | 4 ++--
+ .../staging/vc04_services/vchiq-mmal/Kconfig | 7 ++++++
+ .../staging/vc04_services/vchiq-mmal/Makefile | 8 +++++++
+ .../mmal-common.h | 0
+ .../mmal-encodings.h | 0
+ .../mmal-msg-common.h | 0
+ .../mmal-msg-format.h | 0
+ .../mmal-msg-port.h | 0
+ .../{bcm2835-camera => vchiq-mmal}/mmal-msg.h | 0
+ .../mmal-parameters.h | 0
+ .../mmal-vchiq.c | 22 +++++++++++++++++++
+ .../mmal-vchiq.h | 0
+ 15 files changed, 42 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/staging/vc04_services/vchiq-mmal/Kconfig
+ create mode 100644 drivers/staging/vc04_services/vchiq-mmal/Makefile
+ rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-common.h (100%)
+ rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-encodings.h (100%)
+ rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg-common.h (100%)
+ rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg-format.h (100%)
+ rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg-port.h (100%)
+ rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg.h (100%)
+ rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-parameters.h (100%)
+ rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-vchiq.c (98%)
+ rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-vchiq.h (100%)
+
+--- a/drivers/staging/vc04_services/Kconfig
++++ b/drivers/staging/vc04_services/Kconfig
+@@ -21,6 +21,7 @@ config BCM2835_VCHIQ
+ source "drivers/staging/vc04_services/bcm2835-audio/Kconfig"
+
+ source "drivers/staging/vc04_services/bcm2835-camera/Kconfig"
++source "drivers/staging/vc04_services/vchiq-mmal/Kconfig"
+
+ endif
+
+--- a/drivers/staging/vc04_services/Makefile
++++ b/drivers/staging/vc04_services/Makefile
+@@ -12,6 +12,7 @@ vchiq-objs := \
+
+ obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
+ obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
++obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
+
+ ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/Kconfig
++++ b/drivers/staging/vc04_services/bcm2835-camera/Kconfig
+@@ -2,7 +2,7 @@ config VIDEO_BCM2835
+ tristate "BCM2835 Camera"
+ depends on MEDIA_SUPPORT
+ depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST)
+- select BCM2835_VCHIQ
++ select BCM2835_VCHIQ_MMAL
+ select VIDEOBUF2_VMALLOC
+ select BTREE
+ help
+--- a/drivers/staging/vc04_services/bcm2835-camera/Makefile
++++ b/drivers/staging/vc04_services/bcm2835-camera/Makefile
+@@ -1,11 +1,11 @@
+ # SPDX-License-Identifier: GPL-2.0
+ bcm2835-v4l2-$(CONFIG_VIDEO_BCM2835) := \
+ bcm2835-camera.o \
+- controls.o \
+- mmal-vchiq.o
++ controls.o
+
+ obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-v4l2.o
+
+ ccflags-y += \
+ -Idrivers/staging/vc04_services \
++ -Idrivers/staging/vc04_services/vchiq-mmal \
+ -D__VCCOREVER__=0x04000000
+--- /dev/null
++++ b/drivers/staging/vc04_services/vchiq-mmal/Kconfig
+@@ -0,0 +1,7 @@
++config BCM2835_VCHIQ_MMAL
++ tristate "BCM2835 MMAL VCHIQ service"
++ depends on (ARCH_BCM2835 || COMPILE_TEST)
++ select BCM2835_VCHIQ
++ help
++ Enables the MMAL API over VCHIQ as used for the
++ majority of the multimedia services on VideoCore.
+--- /dev/null
++++ b/drivers/staging/vc04_services/vchiq-mmal/Makefile
+@@ -0,0 +1,8 @@
++# SPDX-License-Identifier: GPL-2.0
++bcm2835-mmal-vchiq-objs := mmal-vchiq.o
++
++obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += bcm2835-mmal-vchiq.o
++
++ccflags-y += \
++ -Idrivers/staging/vc04_services \
++ -D__VCCOREVER__=0x04000000
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
++++ /dev/null
+@@ -1,1899 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/*
+- * Broadcom BM2835 V4L2 driver
+- *
+- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+- *
+- * Authors: Vincent Sanders @ Collabora
+- * Dave Stevenson @ Broadcom
+- * Simon Mellor @ Broadcom
+- * Luke Diamand @ Broadcom
+- *
+- * V4L2 driver MMAL vchiq interface code
+- */
+-
+-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+-
+-#include <linux/errno.h>
+-#include <linux/kernel.h>
+-#include <linux/mutex.h>
+-#include <linux/mm.h>
+-#include <linux/slab.h>
+-#include <linux/completion.h>
+-#include <linux/vmalloc.h>
+-#include <asm/cacheflush.h>
+-#include <media/videobuf2-vmalloc.h>
+-
+-#include "mmal-common.h"
+-#include "mmal-vchiq.h"
+-#include "mmal-msg.h"
+-
+-#define USE_VCHIQ_ARM
+-#include "interface/vchi/vchi.h"
+-
+-/* maximum number of components supported */
+-#define VCHIQ_MMAL_MAX_COMPONENTS 4
+-
+-/*#define FULL_MSG_DUMP 1*/
+-
+-#ifdef DEBUG
+-static const char *const msg_type_names[] = {
+- "UNKNOWN",
+- "QUIT",
+- "SERVICE_CLOSED",
+- "GET_VERSION",
+- "COMPONENT_CREATE",
+- "COMPONENT_DESTROY",
+- "COMPONENT_ENABLE",
+- "COMPONENT_DISABLE",
+- "PORT_INFO_GET",
+- "PORT_INFO_SET",
+- "PORT_ACTION",
+- "BUFFER_FROM_HOST",
+- "BUFFER_TO_HOST",
+- "GET_STATS",
+- "PORT_PARAMETER_SET",
+- "PORT_PARAMETER_GET",
+- "EVENT_TO_HOST",
+- "GET_CORE_STATS_FOR_PORT",
+- "OPAQUE_ALLOCATOR",
+- "CONSUME_MEM",
+- "LMK",
+- "OPAQUE_ALLOCATOR_DESC",
+- "DRM_GET_LHS32",
+- "DRM_GET_TIME",
+- "BUFFER_FROM_HOST_ZEROLEN",
+- "PORT_FLUSH",
+- "HOST_LOG",
+-};
+-#endif
+-
+-static const char *const port_action_type_names[] = {
+- "UNKNOWN",
+- "ENABLE",
+- "DISABLE",
+- "FLUSH",
+- "CONNECT",
+- "DISCONNECT",
+- "SET_REQUIREMENTS",
+-};
+-
+-#if defined(DEBUG)
+-#if defined(FULL_MSG_DUMP)
+-#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
+- do { \
+- pr_debug(TITLE" type:%s(%d) length:%d\n", \
+- msg_type_names[(MSG)->h.type], \
+- (MSG)->h.type, (MSG_LEN)); \
+- print_hex_dump(KERN_DEBUG, "<<h: ", DUMP_PREFIX_OFFSET, \
+- 16, 4, (MSG), \
+- sizeof(struct mmal_msg_header), 1); \
+- print_hex_dump(KERN_DEBUG, "<<p: ", DUMP_PREFIX_OFFSET, \
+- 16, 4, \
+- ((u8 *)(MSG)) + sizeof(struct mmal_msg_header),\
+- (MSG_LEN) - sizeof(struct mmal_msg_header), 1); \
+- } while (0)
+-#else
+-#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
+- { \
+- pr_debug(TITLE" type:%s(%d) length:%d\n", \
+- msg_type_names[(MSG)->h.type], \
+- (MSG)->h.type, (MSG_LEN)); \
+- }
+-#endif
+-#else
+-#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE)
+-#endif
+-
+-struct vchiq_mmal_instance;
+-
+-/* normal message context */
+-struct mmal_msg_context {
+- struct vchiq_mmal_instance *instance;
+-
+- /* Index in the context_map idr so that we can find the
+- * mmal_msg_context again when servicing the VCHI reply.
+- */
+- int handle;
+-
+- union {
+- struct {
+- /* work struct for buffer_cb callback */
+- struct work_struct work;
+- /* work struct for deferred callback */
+- struct work_struct buffer_to_host_work;
+- /* mmal instance */
+- struct vchiq_mmal_instance *instance;
+- /* mmal port */
+- struct vchiq_mmal_port *port;
+- /* actual buffer used to store bulk reply */
+- struct mmal_buffer *buffer;
+- /* amount of buffer used */
+- unsigned long buffer_used;
+- /* MMAL buffer flags */
+- u32 mmal_flags;
+- /* Presentation and Decode timestamps */
+- s64 pts;
+- s64 dts;
+-
+- int status; /* context status */
+-
+- } bulk; /* bulk data */
+-
+- struct {
+- /* message handle to release */
+- VCHI_HELD_MSG_T msg_handle;
+- /* pointer to received message */
+- struct mmal_msg *msg;
+- /* received message length */
+- u32 msg_len;
+- /* completion upon reply */
+- struct completion cmplt;
+- } sync; /* synchronous response */
+- } u;
+-
+-};
+-
+-struct vchiq_mmal_instance {
+- VCHI_SERVICE_HANDLE_T handle;
+-
+- /* ensure serialised access to service */
+- struct mutex vchiq_mutex;
+-
+- /* vmalloc page to receive scratch bulk xfers into */
+- void *bulk_scratch;
+-
+- struct idr context_map;
+- /* protect accesses to context_map */
+- struct mutex context_map_lock;
+-
+- /* component to use next */
+- int component_idx;
+- struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
+-
+- /* ordered workqueue to process all bulk operations */
+- struct workqueue_struct *bulk_wq;
+-};
+-
+-static struct mmal_msg_context *
+-get_msg_context(struct vchiq_mmal_instance *instance)
+-{
+- struct mmal_msg_context *msg_context;
+- int handle;
+-
+- /* todo: should this be allocated from a pool to avoid kzalloc */
+- msg_context = kzalloc(sizeof(*msg_context), GFP_KERNEL);
+-
+- if (!msg_context)
+- return ERR_PTR(-ENOMEM);
+-
+- /* Create an ID that will be passed along with our message so
+- * that when we service the VCHI reply, we can look up what
+- * message is being replied to.
+- */
+- mutex_lock(&instance->context_map_lock);
+- handle = idr_alloc(&instance->context_map, msg_context,
+- 0, 0, GFP_KERNEL);
+- mutex_unlock(&instance->context_map_lock);
+-
+- if (handle < 0) {
+- kfree(msg_context);
+- return ERR_PTR(handle);
+- }
+-
+- msg_context->instance = instance;
+- msg_context->handle = handle;
+-
+- return msg_context;
+-}
+-
+-static struct mmal_msg_context *
+-lookup_msg_context(struct vchiq_mmal_instance *instance, int handle)
+-{
+- return idr_find(&instance->context_map, handle);
+-}
+-
+-static void
+-release_msg_context(struct mmal_msg_context *msg_context)
+-{
+- struct vchiq_mmal_instance *instance = msg_context->instance;
+-
+- mutex_lock(&instance->context_map_lock);
+- idr_remove(&instance->context_map, msg_context->handle);
+- mutex_unlock(&instance->context_map_lock);
+- kfree(msg_context);
+-}
+-
+-/* deals with receipt of event to host message */
+-static void event_to_host_cb(struct vchiq_mmal_instance *instance,
+- struct mmal_msg *msg, u32 msg_len)
+-{
+- pr_debug("unhandled event\n");
+- pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n",
+- msg->u.event_to_host.client_component,
+- msg->u.event_to_host.port_type,
+- msg->u.event_to_host.port_num,
+- msg->u.event_to_host.cmd, msg->u.event_to_host.length);
+-}
+-
+-/* workqueue scheduled callback
+- *
+- * we do this because it is important we do not call any other vchiq
+- * sync calls from witin the message delivery thread
+- */
+-static void buffer_work_cb(struct work_struct *work)
+-{
+- struct mmal_msg_context *msg_context =
+- container_of(work, struct mmal_msg_context, u.bulk.work);
+-
+- atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
+-
+- msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
+- msg_context->u.bulk.port,
+- msg_context->u.bulk.status,
+- msg_context->u.bulk.buffer,
+- msg_context->u.bulk.buffer_used,
+- msg_context->u.bulk.mmal_flags,
+- msg_context->u.bulk.dts,
+- msg_context->u.bulk.pts);
+-}
+-
+-/* workqueue scheduled callback to handle receiving buffers
+- *
+- * VCHI will allow up to 4 bulk receives to be scheduled before blocking.
+- * If we block in the service_callback context then we can't process the
+- * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked
+- * vchi_bulk_queue_receive() call to complete.
+- */
+-static void buffer_to_host_work_cb(struct work_struct *work)
+-{
+- struct mmal_msg_context *msg_context =
+- container_of(work, struct mmal_msg_context,
+- u.bulk.buffer_to_host_work);
+- struct vchiq_mmal_instance *instance = msg_context->instance;
+- unsigned long len = msg_context->u.bulk.buffer_used;
+- int ret;
+-
+- if (!len)
+- /* Dummy receive to ensure the buffers remain in order */
+- len = 8;
+- /* queue the bulk submission */
+- vchi_service_use(instance->handle);
+- ret = vchi_bulk_queue_receive(instance->handle,
+- msg_context->u.bulk.buffer->buffer,
+- /* Actual receive needs to be a multiple
+- * of 4 bytes
+- */
+- (len + 3) & ~3,
+- VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
+- VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
+- msg_context);
+-
+- vchi_service_release(instance->handle);
+-
+- if (ret != 0)
+- pr_err("%s: ctx: %p, vchi_bulk_queue_receive failed %d\n",
+- __func__, msg_context, ret);
+-}
+-
+-/* enqueue a bulk receive for a given message context */
+-static int bulk_receive(struct vchiq_mmal_instance *instance,
+- struct mmal_msg *msg,
+- struct mmal_msg_context *msg_context)
+-{
+- unsigned long rd_len;
+-
+- rd_len = msg->u.buffer_from_host.buffer_header.length;
+-
+- if (!msg_context->u.bulk.buffer) {
+- pr_err("bulk.buffer not configured - error in buffer_from_host\n");
+-
+- /* todo: this is a serious error, we should never have
+- * committed a buffer_to_host operation to the mmal
+- * port without the buffer to back it up (underflow
+- * handling) and there is no obvious way to deal with
+- * this - how is the mmal servie going to react when
+- * we fail to do the xfer and reschedule a buffer when
+- * it arrives? perhaps a starved flag to indicate a
+- * waiting bulk receive?
+- */
+-
+- return -EINVAL;
+- }
+-
+- /* ensure we do not overrun the available buffer */
+- if (rd_len > msg_context->u.bulk.buffer->buffer_size) {
+- rd_len = msg_context->u.bulk.buffer->buffer_size;
+- pr_warn("short read as not enough receive buffer space\n");
+- /* todo: is this the correct response, what happens to
+- * the rest of the message data?
+- */
+- }
+-
+- /* store length */
+- msg_context->u.bulk.buffer_used = rd_len;
+- msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
+- msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
+-
+- queue_work(msg_context->instance->bulk_wq,
+- &msg_context->u.bulk.buffer_to_host_work);
+-
+- return 0;
+-}
+-
+-/* data in message, memcpy from packet into output buffer */
+-static int inline_receive(struct vchiq_mmal_instance *instance,
+- struct mmal_msg *msg,
+- struct mmal_msg_context *msg_context)
+-{
+- memcpy(msg_context->u.bulk.buffer->buffer,
+- msg->u.buffer_from_host.short_data,
+- msg->u.buffer_from_host.payload_in_message);
+-
+- msg_context->u.bulk.buffer_used =
+- msg->u.buffer_from_host.payload_in_message;
+-
+- return 0;
+-}
+-
+-/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */
+-static int
+-buffer_from_host(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port, struct mmal_buffer *buf)
+-{
+- struct mmal_msg_context *msg_context;
+- struct mmal_msg m;
+- int ret;
+-
+- if (!port->enabled)
+- return -EINVAL;
+-
+- pr_debug("instance:%p buffer:%p\n", instance->handle, buf);
+-
+- /* get context */
+- if (!buf->msg_context) {
+- pr_err("%s: msg_context not allocated, buf %p\n", __func__,
+- buf);
+- return -EINVAL;
+- }
+- msg_context = buf->msg_context;
+-
+- /* store bulk message context for when data arrives */
+- msg_context->u.bulk.instance = instance;
+- msg_context->u.bulk.port = port;
+- msg_context->u.bulk.buffer = buf;
+- msg_context->u.bulk.buffer_used = 0;
+-
+- /* initialise work structure ready to schedule callback */
+- INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
+- INIT_WORK(&msg_context->u.bulk.buffer_to_host_work,
+- buffer_to_host_work_cb);
+-
+- atomic_inc(&port->buffers_with_vpu);
+-
+- /* prep the buffer from host message */
+- memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */
+-
+- m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST;
+- m.h.magic = MMAL_MAGIC;
+- m.h.context = msg_context->handle;
+- m.h.status = 0;
+-
+- /* drvbuf is our private data passed back */
+- m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC;
+- m.u.buffer_from_host.drvbuf.component_handle = port->component->handle;
+- m.u.buffer_from_host.drvbuf.port_handle = port->handle;
+- m.u.buffer_from_host.drvbuf.client_context = msg_context->handle;
+-
+- /* buffer header */
+- m.u.buffer_from_host.buffer_header.cmd = 0;
+- m.u.buffer_from_host.buffer_header.data =
+- (u32)(unsigned long)buf->buffer;
+- m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
+- m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */
+- m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */
+- m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */
+- m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
+- m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
+-
+- /* clear buffer type sepecific data */
+- memset(&m.u.buffer_from_host.buffer_header_type_specific, 0,
+- sizeof(m.u.buffer_from_host.buffer_header_type_specific));
+-
+- /* no payload in message */
+- m.u.buffer_from_host.payload_in_message = 0;
+-
+- vchi_service_use(instance->handle);
+-
+- ret = vchi_queue_kernel_message(instance->handle,
+- &m,
+- sizeof(struct mmal_msg_header) +
+- sizeof(m.u.buffer_from_host));
+-
+- vchi_service_release(instance->handle);
+-
+- return ret;
+-}
+-
+-/* deals with receipt of buffer to host message */
+-static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
+- struct mmal_msg *msg, u32 msg_len)
+-{
+- struct mmal_msg_context *msg_context;
+- u32 handle;
+-
+- pr_debug("%s: instance:%p msg:%p msg_len:%d\n",
+- __func__, instance, msg, msg_len);
+-
+- if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
+- handle = msg->u.buffer_from_host.drvbuf.client_context;
+- msg_context = lookup_msg_context(instance, handle);
+-
+- if (!msg_context) {
+- pr_err("drvbuf.client_context(%u) is invalid\n",
+- handle);
+- return;
+- }
+- } else {
+- pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n");
+- return;
+- }
+-
+- msg_context->u.bulk.mmal_flags =
+- msg->u.buffer_from_host.buffer_header.flags;
+-
+- if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
+- /* message reception had an error */
+- pr_warn("error %d in reply\n", msg->h.status);
+-
+- msg_context->u.bulk.status = msg->h.status;
+-
+- } else if (msg->u.buffer_from_host.buffer_header.length == 0) {
+- /* empty buffer */
+- if (msg->u.buffer_from_host.buffer_header.flags &
+- MMAL_BUFFER_HEADER_FLAG_EOS) {
+- msg_context->u.bulk.status =
+- bulk_receive(instance, msg, msg_context);
+- if (msg_context->u.bulk.status == 0)
+- return; /* successful bulk submission, bulk
+- * completion will trigger callback
+- */
+- } else {
+- /* do callback with empty buffer - not EOS though */
+- msg_context->u.bulk.status = 0;
+- msg_context->u.bulk.buffer_used = 0;
+- }
+- } else if (msg->u.buffer_from_host.payload_in_message == 0) {
+- /* data is not in message, queue a bulk receive */
+- msg_context->u.bulk.status =
+- bulk_receive(instance, msg, msg_context);
+- if (msg_context->u.bulk.status == 0)
+- return; /* successful bulk submission, bulk
+- * completion will trigger callback
+- */
+-
+- /* failed to submit buffer, this will end badly */
+- pr_err("error %d on bulk submission\n",
+- msg_context->u.bulk.status);
+-
+- } else if (msg->u.buffer_from_host.payload_in_message <=
+- MMAL_VC_SHORT_DATA) {
+- /* data payload within message */
+- msg_context->u.bulk.status = inline_receive(instance, msg,
+- msg_context);
+- } else {
+- pr_err("message with invalid short payload\n");
+-
+- /* signal error */
+- msg_context->u.bulk.status = -EINVAL;
+- msg_context->u.bulk.buffer_used =
+- msg->u.buffer_from_host.payload_in_message;
+- }
+-
+- /* schedule the port callback */
+- schedule_work(&msg_context->u.bulk.work);
+-}
+-
+-static void bulk_receive_cb(struct vchiq_mmal_instance *instance,
+- struct mmal_msg_context *msg_context)
+-{
+- msg_context->u.bulk.status = 0;
+-
+- /* schedule the port callback */
+- schedule_work(&msg_context->u.bulk.work);
+-}
+-
+-static void bulk_abort_cb(struct vchiq_mmal_instance *instance,
+- struct mmal_msg_context *msg_context)
+-{
+- pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context);
+-
+- msg_context->u.bulk.status = -EINTR;
+-
+- schedule_work(&msg_context->u.bulk.work);
+-}
+-
+-/* incoming event service callback */
+-static void service_callback(void *param,
+- const VCHI_CALLBACK_REASON_T reason,
+- void *bulk_ctx)
+-{
+- struct vchiq_mmal_instance *instance = param;
+- int status;
+- u32 msg_len;
+- struct mmal_msg *msg;
+- VCHI_HELD_MSG_T msg_handle;
+- struct mmal_msg_context *msg_context;
+-
+- if (!instance) {
+- pr_err("Message callback passed NULL instance\n");
+- return;
+- }
+-
+- switch (reason) {
+- case VCHI_CALLBACK_MSG_AVAILABLE:
+- status = vchi_msg_hold(instance->handle, (void **)&msg,
+- &msg_len, VCHI_FLAGS_NONE, &msg_handle);
+- if (status) {
+- pr_err("Unable to dequeue a message (%d)\n", status);
+- break;
+- }
+-
+- DBG_DUMP_MSG(msg, msg_len, "<<< reply message");
+-
+- /* handling is different for buffer messages */
+- switch (msg->h.type) {
+- case MMAL_MSG_TYPE_BUFFER_FROM_HOST:
+- vchi_held_msg_release(&msg_handle);
+- break;
+-
+- case MMAL_MSG_TYPE_EVENT_TO_HOST:
+- event_to_host_cb(instance, msg, msg_len);
+- vchi_held_msg_release(&msg_handle);
+-
+- break;
+-
+- case MMAL_MSG_TYPE_BUFFER_TO_HOST:
+- buffer_to_host_cb(instance, msg, msg_len);
+- vchi_held_msg_release(&msg_handle);
+- break;
+-
+- default:
+- /* messages dependent on header context to complete */
+- if (!msg->h.context) {
+- pr_err("received message context was null!\n");
+- vchi_held_msg_release(&msg_handle);
+- break;
+- }
+-
+- msg_context = lookup_msg_context(instance,
+- msg->h.context);
+- if (!msg_context) {
+- pr_err("received invalid message context %u!\n",
+- msg->h.context);
+- vchi_held_msg_release(&msg_handle);
+- break;
+- }
+-
+- /* fill in context values */
+- msg_context->u.sync.msg_handle = msg_handle;
+- msg_context->u.sync.msg = msg;
+- msg_context->u.sync.msg_len = msg_len;
+-
+- /* todo: should this check (completion_done()
+- * == 1) for no one waiting? or do we need a
+- * flag to tell us the completion has been
+- * interrupted so we can free the message and
+- * its context. This probably also solves the
+- * message arriving after interruption todo
+- * below
+- */
+-
+- /* complete message so caller knows it happened */
+- complete(&msg_context->u.sync.cmplt);
+- break;
+- }
+-
+- break;
+-
+- case VCHI_CALLBACK_BULK_RECEIVED:
+- bulk_receive_cb(instance, bulk_ctx);
+- break;
+-
+- case VCHI_CALLBACK_BULK_RECEIVE_ABORTED:
+- bulk_abort_cb(instance, bulk_ctx);
+- break;
+-
+- case VCHI_CALLBACK_SERVICE_CLOSED:
+- /* TODO: consider if this requires action if received when
+- * driver is not explicitly closing the service
+- */
+- break;
+-
+- default:
+- pr_err("Received unhandled message reason %d\n", reason);
+- break;
+- }
+-}
+-
+-static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
+- struct mmal_msg *msg,
+- unsigned int payload_len,
+- struct mmal_msg **msg_out,
+- VCHI_HELD_MSG_T *msg_handle_out)
+-{
+- struct mmal_msg_context *msg_context;
+- int ret;
+- unsigned long timeout;
+-
+- /* payload size must not cause message to exceed max size */
+- if (payload_len >
+- (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
+- pr_err("payload length %d exceeds max:%d\n", payload_len,
+- (int)(MMAL_MSG_MAX_SIZE -
+- sizeof(struct mmal_msg_header)));
+- return -EINVAL;
+- }
+-
+- msg_context = get_msg_context(instance);
+- if (IS_ERR(msg_context))
+- return PTR_ERR(msg_context);
+-
+- init_completion(&msg_context->u.sync.cmplt);
+-
+- msg->h.magic = MMAL_MAGIC;
+- msg->h.context = msg_context->handle;
+- msg->h.status = 0;
+-
+- DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len),
+- ">>> sync message");
+-
+- vchi_service_use(instance->handle);
+-
+- ret = vchi_queue_kernel_message(instance->handle,
+- msg,
+- sizeof(struct mmal_msg_header) +
+- payload_len);
+-
+- vchi_service_release(instance->handle);
+-
+- if (ret) {
+- pr_err("error %d queuing message\n", ret);
+- release_msg_context(msg_context);
+- return ret;
+- }
+-
+- timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt,
+- 3 * HZ);
+- if (timeout == 0) {
+- pr_err("timed out waiting for sync completion\n");
+- ret = -ETIME;
+- /* todo: what happens if the message arrives after aborting */
+- release_msg_context(msg_context);
+- return ret;
+- }
+-
+- *msg_out = msg_context->u.sync.msg;
+- *msg_handle_out = msg_context->u.sync.msg_handle;
+- release_msg_context(msg_context);
+-
+- return 0;
+-}
+-
+-static void dump_port_info(struct vchiq_mmal_port *port)
+-{
+- pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled);
+-
+- pr_debug("buffer minimum num:%d size:%d align:%d\n",
+- port->minimum_buffer.num,
+- port->minimum_buffer.size, port->minimum_buffer.alignment);
+-
+- pr_debug("buffer recommended num:%d size:%d align:%d\n",
+- port->recommended_buffer.num,
+- port->recommended_buffer.size,
+- port->recommended_buffer.alignment);
+-
+- pr_debug("buffer current values num:%d size:%d align:%d\n",
+- port->current_buffer.num,
+- port->current_buffer.size, port->current_buffer.alignment);
+-
+- pr_debug("elementary stream: type:%d encoding:0x%x variant:0x%x\n",
+- port->format.type,
+- port->format.encoding, port->format.encoding_variant);
+-
+- pr_debug(" bitrate:%d flags:0x%x\n",
+- port->format.bitrate, port->format.flags);
+-
+- if (port->format.type == MMAL_ES_TYPE_VIDEO) {
+- pr_debug
+- ("es video format: width:%d height:%d colourspace:0x%x\n",
+- port->es.video.width, port->es.video.height,
+- port->es.video.color_space);
+-
+- pr_debug(" : crop xywh %d,%d,%d,%d\n",
+- port->es.video.crop.x,
+- port->es.video.crop.y,
+- port->es.video.crop.width, port->es.video.crop.height);
+- pr_debug(" : framerate %d/%d aspect %d/%d\n",
+- port->es.video.frame_rate.num,
+- port->es.video.frame_rate.den,
+- port->es.video.par.num, port->es.video.par.den);
+- }
+-}
+-
+-static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p)
+-{
+- /* todo do readonly fields need setting at all? */
+- p->type = port->type;
+- p->index = port->index;
+- p->index_all = 0;
+- p->is_enabled = port->enabled;
+- p->buffer_num_min = port->minimum_buffer.num;
+- p->buffer_size_min = port->minimum_buffer.size;
+- p->buffer_alignment_min = port->minimum_buffer.alignment;
+- p->buffer_num_recommended = port->recommended_buffer.num;
+- p->buffer_size_recommended = port->recommended_buffer.size;
+-
+- /* only three writable fields in a port */
+- p->buffer_num = port->current_buffer.num;
+- p->buffer_size = port->current_buffer.size;
+- p->userdata = (u32)(unsigned long)port;
+-}
+-
+-static int port_info_set(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port)
+-{
+- int ret;
+- struct mmal_msg m;
+- struct mmal_msg *rmsg;
+- VCHI_HELD_MSG_T rmsg_handle;
+-
+- pr_debug("setting port info port %p\n", port);
+- if (!port)
+- return -1;
+- dump_port_info(port);
+-
+- m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET;
+-
+- m.u.port_info_set.component_handle = port->component->handle;
+- m.u.port_info_set.port_type = port->type;
+- m.u.port_info_set.port_index = port->index;
+-
+- port_to_mmal_msg(port, &m.u.port_info_set.port);
+-
+- /* elementary stream format setup */
+- m.u.port_info_set.format.type = port->format.type;
+- m.u.port_info_set.format.encoding = port->format.encoding;
+- m.u.port_info_set.format.encoding_variant =
+- port->format.encoding_variant;
+- m.u.port_info_set.format.bitrate = port->format.bitrate;
+- m.u.port_info_set.format.flags = port->format.flags;
+-
+- memcpy(&m.u.port_info_set.es, &port->es,
+- sizeof(union mmal_es_specific_format));
+-
+- m.u.port_info_set.format.extradata_size = port->format.extradata_size;
+- memcpy(&m.u.port_info_set.extradata, port->format.extradata,
+- port->format.extradata_size);
+-
+- ret = send_synchronous_mmal_msg(instance, &m,
+- sizeof(m.u.port_info_set),
+- &rmsg, &rmsg_handle);
+- if (ret)
+- return ret;
+-
+- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) {
+- /* got an unexpected message type in reply */
+- ret = -EINVAL;
+- goto release_msg;
+- }
+-
+- /* return operation status */
+- ret = -rmsg->u.port_info_get_reply.status;
+-
+- pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret,
+- port->component->handle, port->handle);
+-
+-release_msg:
+- vchi_held_msg_release(&rmsg_handle);
+-
+- return ret;
+-}
+-
+-/* use port info get message to retrieve port information */
+-static int port_info_get(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port)
+-{
+- int ret;
+- struct mmal_msg m;
+- struct mmal_msg *rmsg;
+- VCHI_HELD_MSG_T rmsg_handle;
+-
+- /* port info time */
+- m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET;
+- m.u.port_info_get.component_handle = port->component->handle;
+- m.u.port_info_get.port_type = port->type;
+- m.u.port_info_get.index = port->index;
+-
+- ret = send_synchronous_mmal_msg(instance, &m,
+- sizeof(m.u.port_info_get),
+- &rmsg, &rmsg_handle);
+- if (ret)
+- return ret;
+-
+- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) {
+- /* got an unexpected message type in reply */
+- ret = -EINVAL;
+- goto release_msg;
+- }
+-
+- /* return operation status */
+- ret = -rmsg->u.port_info_get_reply.status;
+- if (ret != MMAL_MSG_STATUS_SUCCESS)
+- goto release_msg;
+-
+- if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
+- port->enabled = false;
+- else
+- port->enabled = true;
+-
+- /* copy the values out of the message */
+- port->handle = rmsg->u.port_info_get_reply.port_handle;
+-
+- /* port type and index cached to use on port info set because
+- * it does not use a port handle
+- */
+- port->type = rmsg->u.port_info_get_reply.port_type;
+- port->index = rmsg->u.port_info_get_reply.port_index;
+-
+- port->minimum_buffer.num =
+- rmsg->u.port_info_get_reply.port.buffer_num_min;
+- port->minimum_buffer.size =
+- rmsg->u.port_info_get_reply.port.buffer_size_min;
+- port->minimum_buffer.alignment =
+- rmsg->u.port_info_get_reply.port.buffer_alignment_min;
+-
+- port->recommended_buffer.alignment =
+- rmsg->u.port_info_get_reply.port.buffer_alignment_min;
+- port->recommended_buffer.num =
+- rmsg->u.port_info_get_reply.port.buffer_num_recommended;
+-
+- port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num;
+- port->current_buffer.size =
+- rmsg->u.port_info_get_reply.port.buffer_size;
+-
+- /* stream format */
+- port->format.type = rmsg->u.port_info_get_reply.format.type;
+- port->format.encoding = rmsg->u.port_info_get_reply.format.encoding;
+- port->format.encoding_variant =
+- rmsg->u.port_info_get_reply.format.encoding_variant;
+- port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate;
+- port->format.flags = rmsg->u.port_info_get_reply.format.flags;
+-
+- /* elementary stream format */
+- memcpy(&port->es,
+- &rmsg->u.port_info_get_reply.es,
+- sizeof(union mmal_es_specific_format));
+- port->format.es = &port->es;
+-
+- port->format.extradata_size =
+- rmsg->u.port_info_get_reply.format.extradata_size;
+- memcpy(port->format.extradata,
+- rmsg->u.port_info_get_reply.extradata,
+- port->format.extradata_size);
+-
+- pr_debug("received port info\n");
+- dump_port_info(port);
+-
+-release_msg:
+-
+- pr_debug("%s:result:%d component:0x%x port:%d\n",
+- __func__, ret, port->component->handle, port->handle);
+-
+- vchi_held_msg_release(&rmsg_handle);
+-
+- return ret;
+-}
+-
+-/* create comonent on vc */
+-static int create_component(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_component *component,
+- const char *name)
+-{
+- int ret;
+- struct mmal_msg m;
+- struct mmal_msg *rmsg;
+- VCHI_HELD_MSG_T rmsg_handle;
+-
+- /* build component create message */
+- m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE;
+- m.u.component_create.client_component = (u32)(unsigned long)component;
+- strncpy(m.u.component_create.name, name,
+- sizeof(m.u.component_create.name));
+-
+- ret = send_synchronous_mmal_msg(instance, &m,
+- sizeof(m.u.component_create),
+- &rmsg, &rmsg_handle);
+- if (ret)
+- return ret;
+-
+- if (rmsg->h.type != m.h.type) {
+- /* got an unexpected message type in reply */
+- ret = -EINVAL;
+- goto release_msg;
+- }
+-
+- ret = -rmsg->u.component_create_reply.status;
+- if (ret != MMAL_MSG_STATUS_SUCCESS)
+- goto release_msg;
+-
+- /* a valid component response received */
+- component->handle = rmsg->u.component_create_reply.component_handle;
+- component->inputs = rmsg->u.component_create_reply.input_num;
+- component->outputs = rmsg->u.component_create_reply.output_num;
+- component->clocks = rmsg->u.component_create_reply.clock_num;
+-
+- pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n",
+- component->handle,
+- component->inputs, component->outputs, component->clocks);
+-
+-release_msg:
+- vchi_held_msg_release(&rmsg_handle);
+-
+- return ret;
+-}
+-
+-/* destroys a component on vc */
+-static int destroy_component(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_component *component)
+-{
+- int ret;
+- struct mmal_msg m;
+- struct mmal_msg *rmsg;
+- VCHI_HELD_MSG_T rmsg_handle;
+-
+- m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY;
+- m.u.component_destroy.component_handle = component->handle;
+-
+- ret = send_synchronous_mmal_msg(instance, &m,
+- sizeof(m.u.component_destroy),
+- &rmsg, &rmsg_handle);
+- if (ret)
+- return ret;
+-
+- if (rmsg->h.type != m.h.type) {
+- /* got an unexpected message type in reply */
+- ret = -EINVAL;
+- goto release_msg;
+- }
+-
+- ret = -rmsg->u.component_destroy_reply.status;
+-
+-release_msg:
+-
+- vchi_held_msg_release(&rmsg_handle);
+-
+- return ret;
+-}
+-
+-/* enable a component on vc */
+-static int enable_component(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_component *component)
+-{
+- int ret;
+- struct mmal_msg m;
+- struct mmal_msg *rmsg;
+- VCHI_HELD_MSG_T rmsg_handle;
+-
+- m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE;
+- m.u.component_enable.component_handle = component->handle;
+-
+- ret = send_synchronous_mmal_msg(instance, &m,
+- sizeof(m.u.component_enable),
+- &rmsg, &rmsg_handle);
+- if (ret)
+- return ret;
+-
+- if (rmsg->h.type != m.h.type) {
+- /* got an unexpected message type in reply */
+- ret = -EINVAL;
+- goto release_msg;
+- }
+-
+- ret = -rmsg->u.component_enable_reply.status;
+-
+-release_msg:
+- vchi_held_msg_release(&rmsg_handle);
+-
+- return ret;
+-}
+-
+-/* disable a component on vc */
+-static int disable_component(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_component *component)
+-{
+- int ret;
+- struct mmal_msg m;
+- struct mmal_msg *rmsg;
+- VCHI_HELD_MSG_T rmsg_handle;
+-
+- m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE;
+- m.u.component_disable.component_handle = component->handle;
+-
+- ret = send_synchronous_mmal_msg(instance, &m,
+- sizeof(m.u.component_disable),
+- &rmsg, &rmsg_handle);
+- if (ret)
+- return ret;
+-
+- if (rmsg->h.type != m.h.type) {
+- /* got an unexpected message type in reply */
+- ret = -EINVAL;
+- goto release_msg;
+- }
+-
+- ret = -rmsg->u.component_disable_reply.status;
+-
+-release_msg:
+-
+- vchi_held_msg_release(&rmsg_handle);
+-
+- return ret;
+-}
+-
+-/* get version of mmal implementation */
+-static int get_version(struct vchiq_mmal_instance *instance,
+- u32 *major_out, u32 *minor_out)
+-{
+- int ret;
+- struct mmal_msg m;
+- struct mmal_msg *rmsg;
+- VCHI_HELD_MSG_T rmsg_handle;
+-
+- m.h.type = MMAL_MSG_TYPE_GET_VERSION;
+-
+- ret = send_synchronous_mmal_msg(instance, &m,
+- sizeof(m.u.version),
+- &rmsg, &rmsg_handle);
+- if (ret)
+- return ret;
+-
+- if (rmsg->h.type != m.h.type) {
+- /* got an unexpected message type in reply */
+- ret = -EINVAL;
+- goto release_msg;
+- }
+-
+- *major_out = rmsg->u.version.major;
+- *minor_out = rmsg->u.version.minor;
+-
+-release_msg:
+- vchi_held_msg_release(&rmsg_handle);
+-
+- return ret;
+-}
+-
+-/* do a port action with a port as a parameter */
+-static int port_action_port(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- enum mmal_msg_port_action_type action_type)
+-{
+- int ret;
+- struct mmal_msg m;
+- struct mmal_msg *rmsg;
+- VCHI_HELD_MSG_T rmsg_handle;
+-
+- m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
+- m.u.port_action_port.component_handle = port->component->handle;
+- m.u.port_action_port.port_handle = port->handle;
+- m.u.port_action_port.action = action_type;
+-
+- port_to_mmal_msg(port, &m.u.port_action_port.port);
+-
+- ret = send_synchronous_mmal_msg(instance, &m,
+- sizeof(m.u.port_action_port),
+- &rmsg, &rmsg_handle);
+- if (ret)
+- return ret;
+-
+- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
+- /* got an unexpected message type in reply */
+- ret = -EINVAL;
+- goto release_msg;
+- }
+-
+- ret = -rmsg->u.port_action_reply.status;
+-
+- pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n",
+- __func__,
+- ret, port->component->handle, port->handle,
+- port_action_type_names[action_type], action_type);
+-
+-release_msg:
+- vchi_held_msg_release(&rmsg_handle);
+-
+- return ret;
+-}
+-
+-/* do a port action with handles as parameters */
+-static int port_action_handle(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- enum mmal_msg_port_action_type action_type,
+- u32 connect_component_handle,
+- u32 connect_port_handle)
+-{
+- int ret;
+- struct mmal_msg m;
+- struct mmal_msg *rmsg;
+- VCHI_HELD_MSG_T rmsg_handle;
+-
+- m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
+-
+- m.u.port_action_handle.component_handle = port->component->handle;
+- m.u.port_action_handle.port_handle = port->handle;
+- m.u.port_action_handle.action = action_type;
+-
+- m.u.port_action_handle.connect_component_handle =
+- connect_component_handle;
+- m.u.port_action_handle.connect_port_handle = connect_port_handle;
+-
+- ret = send_synchronous_mmal_msg(instance, &m,
+- sizeof(m.u.port_action_handle),
+- &rmsg, &rmsg_handle);
+- if (ret)
+- return ret;
+-
+- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
+- /* got an unexpected message type in reply */
+- ret = -EINVAL;
+- goto release_msg;
+- }
+-
+- ret = -rmsg->u.port_action_reply.status;
+-
+- pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d) connect component:0x%x connect port:%d\n",
+- __func__,
+- ret, port->component->handle, port->handle,
+- port_action_type_names[action_type],
+- action_type, connect_component_handle, connect_port_handle);
+-
+-release_msg:
+- vchi_held_msg_release(&rmsg_handle);
+-
+- return ret;
+-}
+-
+-static int port_parameter_set(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- u32 parameter_id, void *value, u32 value_size)
+-{
+- int ret;
+- struct mmal_msg m;
+- struct mmal_msg *rmsg;
+- VCHI_HELD_MSG_T rmsg_handle;
+-
+- m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET;
+-
+- m.u.port_parameter_set.component_handle = port->component->handle;
+- m.u.port_parameter_set.port_handle = port->handle;
+- m.u.port_parameter_set.id = parameter_id;
+- m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size;
+- memcpy(&m.u.port_parameter_set.value, value, value_size);
+-
+- ret = send_synchronous_mmal_msg(instance, &m,
+- (4 * sizeof(u32)) + value_size,
+- &rmsg, &rmsg_handle);
+- if (ret)
+- return ret;
+-
+- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) {
+- /* got an unexpected message type in reply */
+- ret = -EINVAL;
+- goto release_msg;
+- }
+-
+- ret = -rmsg->u.port_parameter_set_reply.status;
+-
+- pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n",
+- __func__,
+- ret, port->component->handle, port->handle, parameter_id);
+-
+-release_msg:
+- vchi_held_msg_release(&rmsg_handle);
+-
+- return ret;
+-}
+-
+-static int port_parameter_get(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- u32 parameter_id, void *value, u32 *value_size)
+-{
+- int ret;
+- struct mmal_msg m;
+- struct mmal_msg *rmsg;
+- VCHI_HELD_MSG_T rmsg_handle;
+-
+- m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET;
+-
+- m.u.port_parameter_get.component_handle = port->component->handle;
+- m.u.port_parameter_get.port_handle = port->handle;
+- m.u.port_parameter_get.id = parameter_id;
+- m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size;
+-
+- ret = send_synchronous_mmal_msg(instance, &m,
+- sizeof(struct
+- mmal_msg_port_parameter_get),
+- &rmsg, &rmsg_handle);
+- if (ret)
+- return ret;
+-
+- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) {
+- /* got an unexpected message type in reply */
+- pr_err("Incorrect reply type %d\n", rmsg->h.type);
+- ret = -EINVAL;
+- goto release_msg;
+- }
+-
+- ret = -rmsg->u.port_parameter_get_reply.status;
+- /* port_parameter_get_reply.size includes the header,
+- * whilst *value_size doesn't.
+- */
+- rmsg->u.port_parameter_get_reply.size -= (2 * sizeof(u32));
+-
+- if (ret || rmsg->u.port_parameter_get_reply.size > *value_size) {
+- /* Copy only as much as we have space for
+- * but report true size of parameter
+- */
+- memcpy(value, &rmsg->u.port_parameter_get_reply.value,
+- *value_size);
+- *value_size = rmsg->u.port_parameter_get_reply.size;
+- } else {
+- memcpy(value, &rmsg->u.port_parameter_get_reply.value,
+- rmsg->u.port_parameter_get_reply.size);
+- }
+-
+- pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
+- ret, port->component->handle, port->handle, parameter_id);
+-
+-release_msg:
+- vchi_held_msg_release(&rmsg_handle);
+-
+- return ret;
+-}
+-
+-/* disables a port and drains buffers from it */
+-static int port_disable(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port)
+-{
+- int ret;
+- struct list_head *q, *buf_head;
+- unsigned long flags = 0;
+-
+- if (!port->enabled)
+- return 0;
+-
+- port->enabled = false;
+-
+- ret = port_action_port(instance, port,
+- MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
+- if (ret == 0) {
+- /*
+- * Drain all queued buffers on port. This should only
+- * apply to buffers that have been queued before the port
+- * has been enabled. If the port has been enabled and buffers
+- * passed, then the buffers should have been removed from this
+- * list, and we should get the relevant callbacks via VCHIQ
+- * to release the buffers.
+- */
+- spin_lock_irqsave(&port->slock, flags);
+-
+- list_for_each_safe(buf_head, q, &port->buffers) {
+- struct mmal_buffer *mmalbuf;
+-
+- mmalbuf = list_entry(buf_head, struct mmal_buffer,
+- list);
+- list_del(buf_head);
+- if (port->buffer_cb)
+- port->buffer_cb(instance,
+- port, 0, mmalbuf, 0, 0,
+- MMAL_TIME_UNKNOWN,
+- MMAL_TIME_UNKNOWN);
+- }
+-
+- spin_unlock_irqrestore(&port->slock, flags);
+-
+- ret = port_info_get(instance, port);
+- }
+-
+- return ret;
+-}
+-
+-/* enable a port */
+-static int port_enable(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port)
+-{
+- unsigned int hdr_count;
+- struct list_head *q, *buf_head;
+- int ret;
+-
+- if (port->enabled)
+- return 0;
+-
+- ret = port_action_port(instance, port,
+- MMAL_MSG_PORT_ACTION_TYPE_ENABLE);
+- if (ret)
+- goto done;
+-
+- port->enabled = true;
+-
+- if (port->buffer_cb) {
+- /* send buffer headers to videocore */
+- hdr_count = 1;
+- list_for_each_safe(buf_head, q, &port->buffers) {
+- struct mmal_buffer *mmalbuf;
+-
+- mmalbuf = list_entry(buf_head, struct mmal_buffer,
+- list);
+- ret = buffer_from_host(instance, port, mmalbuf);
+- if (ret)
+- goto done;
+-
+- list_del(buf_head);
+- hdr_count++;
+- if (hdr_count > port->current_buffer.num)
+- break;
+- }
+- }
+-
+- ret = port_info_get(instance, port);
+-
+-done:
+- return ret;
+-}
+-
+-/* ------------------------------------------------------------------
+- * Exported API
+- *------------------------------------------------------------------
+- */
+-
+-int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port)
+-{
+- int ret;
+-
+- if (mutex_lock_interruptible(&instance->vchiq_mutex))
+- return -EINTR;
+-
+- ret = port_info_set(instance, port);
+- if (ret)
+- goto release_unlock;
+-
+- /* read what has actually been set */
+- ret = port_info_get(instance, port);
+-
+-release_unlock:
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- return ret;
+-}
+-
+-int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- u32 parameter, void *value, u32 value_size)
+-{
+- int ret;
+-
+- if (mutex_lock_interruptible(&instance->vchiq_mutex))
+- return -EINTR;
+-
+- ret = port_parameter_set(instance, port, parameter, value, value_size);
+-
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- return ret;
+-}
+-
+-int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- u32 parameter, void *value, u32 *value_size)
+-{
+- int ret;
+-
+- if (mutex_lock_interruptible(&instance->vchiq_mutex))
+- return -EINTR;
+-
+- ret = port_parameter_get(instance, port, parameter, value, value_size);
+-
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- return ret;
+-}
+-
+-/* enable a port
+- *
+- * enables a port and queues buffers for satisfying callbacks if we
+- * provide a callback handler
+- */
+-int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- vchiq_mmal_buffer_cb buffer_cb)
+-{
+- int ret;
+-
+- if (mutex_lock_interruptible(&instance->vchiq_mutex))
+- return -EINTR;
+-
+- /* already enabled - noop */
+- if (port->enabled) {
+- ret = 0;
+- goto unlock;
+- }
+-
+- port->buffer_cb = buffer_cb;
+-
+- ret = port_enable(instance, port);
+-
+-unlock:
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- return ret;
+-}
+-
+-int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port)
+-{
+- int ret;
+-
+- if (mutex_lock_interruptible(&instance->vchiq_mutex))
+- return -EINTR;
+-
+- if (!port->enabled) {
+- mutex_unlock(&instance->vchiq_mutex);
+- return 0;
+- }
+-
+- ret = port_disable(instance, port);
+-
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- return ret;
+-}
+-
+-/* ports will be connected in a tunneled manner so data buffers
+- * are not handled by client.
+- */
+-int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *src,
+- struct vchiq_mmal_port *dst)
+-{
+- int ret;
+-
+- if (mutex_lock_interruptible(&instance->vchiq_mutex))
+- return -EINTR;
+-
+- /* disconnect ports if connected */
+- if (src->connected) {
+- ret = port_disable(instance, src);
+- if (ret) {
+- pr_err("failed disabling src port(%d)\n", ret);
+- goto release_unlock;
+- }
+-
+- /* do not need to disable the destination port as they
+- * are connected and it is done automatically
+- */
+-
+- ret = port_action_handle(instance, src,
+- MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT,
+- src->connected->component->handle,
+- src->connected->handle);
+- if (ret < 0) {
+- pr_err("failed disconnecting src port\n");
+- goto release_unlock;
+- }
+- src->connected->enabled = false;
+- src->connected = NULL;
+- }
+-
+- if (!dst) {
+- /* do not make new connection */
+- ret = 0;
+- pr_debug("not making new connection\n");
+- goto release_unlock;
+- }
+-
+- /* copy src port format to dst */
+- dst->format.encoding = src->format.encoding;
+- dst->es.video.width = src->es.video.width;
+- dst->es.video.height = src->es.video.height;
+- dst->es.video.crop.x = src->es.video.crop.x;
+- dst->es.video.crop.y = src->es.video.crop.y;
+- dst->es.video.crop.width = src->es.video.crop.width;
+- dst->es.video.crop.height = src->es.video.crop.height;
+- dst->es.video.frame_rate.num = src->es.video.frame_rate.num;
+- dst->es.video.frame_rate.den = src->es.video.frame_rate.den;
+-
+- /* set new format */
+- ret = port_info_set(instance, dst);
+- if (ret) {
+- pr_debug("setting port info failed\n");
+- goto release_unlock;
+- }
+-
+- /* read what has actually been set */
+- ret = port_info_get(instance, dst);
+- if (ret) {
+- pr_debug("read back port info failed\n");
+- goto release_unlock;
+- }
+-
+- /* connect two ports together */
+- ret = port_action_handle(instance, src,
+- MMAL_MSG_PORT_ACTION_TYPE_CONNECT,
+- dst->component->handle, dst->handle);
+- if (ret < 0) {
+- pr_debug("connecting port %d:%d to %d:%d failed\n",
+- src->component->handle, src->handle,
+- dst->component->handle, dst->handle);
+- goto release_unlock;
+- }
+- src->connected = dst;
+-
+-release_unlock:
+-
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- return ret;
+-}
+-
+-int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- struct mmal_buffer *buffer)
+-{
+- unsigned long flags = 0;
+- int ret;
+-
+- ret = buffer_from_host(instance, port, buffer);
+- if (ret == -EINVAL) {
+- /* Port is disabled. Queue for when it is enabled. */
+- spin_lock_irqsave(&port->slock, flags);
+- list_add_tail(&buffer->list, &port->buffers);
+- spin_unlock_irqrestore(&port->slock, flags);
+- }
+-
+- return 0;
+-}
+-
+-int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance,
+- struct mmal_buffer *buf)
+-{
+- struct mmal_msg_context *msg_context = get_msg_context(instance);
+-
+- if (IS_ERR(msg_context))
+- return (PTR_ERR(msg_context));
+-
+- buf->msg_context = msg_context;
+- return 0;
+-}
+-
+-int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf)
+-{
+- struct mmal_msg_context *msg_context = buf->msg_context;
+-
+- if (msg_context)
+- release_msg_context(msg_context);
+- buf->msg_context = NULL;
+-
+- return 0;
+-}
+-
+-/* Initialise a mmal component and its ports
+- *
+- */
+-int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance,
+- const char *name,
+- struct vchiq_mmal_component **component_out)
+-{
+- int ret;
+- int idx; /* port index */
+- struct vchiq_mmal_component *component;
+-
+- if (mutex_lock_interruptible(&instance->vchiq_mutex))
+- return -EINTR;
+-
+- if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) {
+- ret = -EINVAL; /* todo is this correct error? */
+- goto unlock;
+- }
+-
+- component = &instance->component[instance->component_idx];
+-
+- ret = create_component(instance, component, name);
+- if (ret < 0) {
+- pr_err("%s: failed to create component %d (Not enough GPU mem?)\n",
+- __func__, ret);
+- goto unlock;
+- }
+-
+- /* ports info needs gathering */
+- component->control.type = MMAL_PORT_TYPE_CONTROL;
+- component->control.index = 0;
+- component->control.component = component;
+- spin_lock_init(&component->control.slock);
+- INIT_LIST_HEAD(&component->control.buffers);
+- ret = port_info_get(instance, &component->control);
+- if (ret < 0)
+- goto release_component;
+-
+- for (idx = 0; idx < component->inputs; idx++) {
+- component->input[idx].type = MMAL_PORT_TYPE_INPUT;
+- component->input[idx].index = idx;
+- component->input[idx].component = component;
+- spin_lock_init(&component->input[idx].slock);
+- INIT_LIST_HEAD(&component->input[idx].buffers);
+- ret = port_info_get(instance, &component->input[idx]);
+- if (ret < 0)
+- goto release_component;
+- }
+-
+- for (idx = 0; idx < component->outputs; idx++) {
+- component->output[idx].type = MMAL_PORT_TYPE_OUTPUT;
+- component->output[idx].index = idx;
+- component->output[idx].component = component;
+- spin_lock_init(&component->output[idx].slock);
+- INIT_LIST_HEAD(&component->output[idx].buffers);
+- ret = port_info_get(instance, &component->output[idx]);
+- if (ret < 0)
+- goto release_component;
+- }
+-
+- for (idx = 0; idx < component->clocks; idx++) {
+- component->clock[idx].type = MMAL_PORT_TYPE_CLOCK;
+- component->clock[idx].index = idx;
+- component->clock[idx].component = component;
+- spin_lock_init(&component->clock[idx].slock);
+- INIT_LIST_HEAD(&component->clock[idx].buffers);
+- ret = port_info_get(instance, &component->clock[idx]);
+- if (ret < 0)
+- goto release_component;
+- }
+-
+- instance->component_idx++;
+-
+- *component_out = component;
+-
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- return 0;
+-
+-release_component:
+- destroy_component(instance, component);
+-unlock:
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- return ret;
+-}
+-
+-/*
+- * cause a mmal component to be destroyed
+- */
+-int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_component *component)
+-{
+- int ret;
+-
+- if (mutex_lock_interruptible(&instance->vchiq_mutex))
+- return -EINTR;
+-
+- if (component->enabled)
+- ret = disable_component(instance, component);
+-
+- ret = destroy_component(instance, component);
+-
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- return ret;
+-}
+-
+-/*
+- * cause a mmal component to be enabled
+- */
+-int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_component *component)
+-{
+- int ret;
+-
+- if (mutex_lock_interruptible(&instance->vchiq_mutex))
+- return -EINTR;
+-
+- if (component->enabled) {
+- mutex_unlock(&instance->vchiq_mutex);
+- return 0;
+- }
+-
+- ret = enable_component(instance, component);
+- if (ret == 0)
+- component->enabled = true;
+-
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- return ret;
+-}
+-
+-/*
+- * cause a mmal component to be enabled
+- */
+-int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_component *component)
+-{
+- int ret;
+-
+- if (mutex_lock_interruptible(&instance->vchiq_mutex))
+- return -EINTR;
+-
+- if (!component->enabled) {
+- mutex_unlock(&instance->vchiq_mutex);
+- return 0;
+- }
+-
+- ret = disable_component(instance, component);
+- if (ret == 0)
+- component->enabled = false;
+-
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- return ret;
+-}
+-
+-int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
+- u32 *major_out, u32 *minor_out)
+-{
+- int ret;
+-
+- if (mutex_lock_interruptible(&instance->vchiq_mutex))
+- return -EINTR;
+-
+- ret = get_version(instance, major_out, minor_out);
+-
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- return ret;
+-}
+-
+-int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
+-{
+- int status = 0;
+-
+- if (!instance)
+- return -EINVAL;
+-
+- if (mutex_lock_interruptible(&instance->vchiq_mutex))
+- return -EINTR;
+-
+- vchi_service_use(instance->handle);
+-
+- status = vchi_service_close(instance->handle);
+- if (status != 0)
+- pr_err("mmal-vchiq: VCHIQ close failed\n");
+-
+- mutex_unlock(&instance->vchiq_mutex);
+-
+- flush_workqueue(instance->bulk_wq);
+- destroy_workqueue(instance->bulk_wq);
+-
+- vfree(instance->bulk_scratch);
+-
+- idr_destroy(&instance->context_map);
+-
+- kfree(instance);
+-
+- return status;
+-}
+-
+-int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
+-{
+- int status;
+- struct vchiq_mmal_instance *instance;
+- static VCHI_CONNECTION_T *vchi_connection;
+- static VCHI_INSTANCE_T vchi_instance;
+- SERVICE_CREATION_T params = {
+- .version = VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER),
+- .service_id = VC_MMAL_SERVER_NAME,
+- .connection = vchi_connection,
+- .rx_fifo_size = 0,
+- .tx_fifo_size = 0,
+- .callback = service_callback,
+- .callback_param = NULL,
+- .want_unaligned_bulk_rx = 1,
+- .want_unaligned_bulk_tx = 1,
+- .want_crc = 0
+- };
+-
+- /* compile time checks to ensure structure size as they are
+- * directly (de)serialised from memory.
+- */
+-
+- /* ensure the header structure has packed to the correct size */
+- BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24);
+-
+- /* ensure message structure does not exceed maximum length */
+- BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE);
+-
+- /* mmal port struct is correct size */
+- BUILD_BUG_ON(sizeof(struct mmal_port) != 64);
+-
+- /* create a vchi instance */
+- status = vchi_initialise(&vchi_instance);
+- if (status) {
+- pr_err("Failed to initialise VCHI instance (status=%d)\n",
+- status);
+- return -EIO;
+- }
+-
+- status = vchi_connect(NULL, 0, vchi_instance);
+- if (status) {
+- pr_err("Failed to connect VCHI instance (status=%d)\n", status);
+- return -EIO;
+- }
+-
+- instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+-
+- if (!instance)
+- return -ENOMEM;
+-
+- mutex_init(&instance->vchiq_mutex);
+-
+- instance->bulk_scratch = vmalloc(PAGE_SIZE);
+-
+- mutex_init(&instance->context_map_lock);
+- idr_init_base(&instance->context_map, 1);
+-
+- params.callback_param = instance;
+-
+- instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq",
+- WQ_MEM_RECLAIM);
+- if (!instance->bulk_wq)
+- goto err_free;
+-
+- status = vchi_service_open(vchi_instance, ¶ms, &instance->handle);
+- if (status) {
+- pr_err("Failed to open VCHI service connection (status=%d)\n",
+- status);
+- goto err_close_services;
+- }
+-
+- vchi_service_release(instance->handle);
+-
+- *out_instance = instance;
+-
+- return 0;
+-
+-err_close_services:
+- vchi_service_close(instance->handle);
+- destroy_workqueue(instance->bulk_wq);
+-err_free:
+- vfree(instance->bulk_scratch);
+- kfree(instance);
+- return -ENODEV;
+-}
+--- /dev/null
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -0,0 +1,1921 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
++ *
++ * V4L2 driver MMAL vchiq interface code
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/completion.h>
++#include <linux/vmalloc.h>
++#include <asm/cacheflush.h>
++#include <media/videobuf2-vmalloc.h>
++
++#include "mmal-common.h"
++#include "mmal-vchiq.h"
++#include "mmal-msg.h"
++
++#define USE_VCHIQ_ARM
++#include "interface/vchi/vchi.h"
++
++MODULE_DESCRIPTION("BCM2835 MMAL VCHIQ interface");
++MODULE_LICENSE("GPL");
++MODULE_VERSION("0.0.1");
++
++/* maximum number of components supported */
++#define VCHIQ_MMAL_MAX_COMPONENTS 4
++
++/*#define FULL_MSG_DUMP 1*/
++
++#ifdef DEBUG
++static const char *const msg_type_names[] = {
++ "UNKNOWN",
++ "QUIT",
++ "SERVICE_CLOSED",
++ "GET_VERSION",
++ "COMPONENT_CREATE",
++ "COMPONENT_DESTROY",
++ "COMPONENT_ENABLE",
++ "COMPONENT_DISABLE",
++ "PORT_INFO_GET",
++ "PORT_INFO_SET",
++ "PORT_ACTION",
++ "BUFFER_FROM_HOST",
++ "BUFFER_TO_HOST",
++ "GET_STATS",
++ "PORT_PARAMETER_SET",
++ "PORT_PARAMETER_GET",
++ "EVENT_TO_HOST",
++ "GET_CORE_STATS_FOR_PORT",
++ "OPAQUE_ALLOCATOR",
++ "CONSUME_MEM",
++ "LMK",
++ "OPAQUE_ALLOCATOR_DESC",
++ "DRM_GET_LHS32",
++ "DRM_GET_TIME",
++ "BUFFER_FROM_HOST_ZEROLEN",
++ "PORT_FLUSH",
++ "HOST_LOG",
++};
++#endif
++
++static const char *const port_action_type_names[] = {
++ "UNKNOWN",
++ "ENABLE",
++ "DISABLE",
++ "FLUSH",
++ "CONNECT",
++ "DISCONNECT",
++ "SET_REQUIREMENTS",
++};
++
++#if defined(DEBUG)
++#if defined(FULL_MSG_DUMP)
++#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
++ do { \
++ pr_debug(TITLE" type:%s(%d) length:%d\n", \
++ msg_type_names[(MSG)->h.type], \
++ (MSG)->h.type, (MSG_LEN)); \
++ print_hex_dump(KERN_DEBUG, "<<h: ", DUMP_PREFIX_OFFSET, \
++ 16, 4, (MSG), \
++ sizeof(struct mmal_msg_header), 1); \
++ print_hex_dump(KERN_DEBUG, "<<p: ", DUMP_PREFIX_OFFSET, \
++ 16, 4, \
++ ((u8 *)(MSG)) + sizeof(struct mmal_msg_header),\
++ (MSG_LEN) - sizeof(struct mmal_msg_header), 1); \
++ } while (0)
++#else
++#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
++ { \
++ pr_debug(TITLE" type:%s(%d) length:%d\n", \
++ msg_type_names[(MSG)->h.type], \
++ (MSG)->h.type, (MSG_LEN)); \
++ }
++#endif
++#else
++#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE)
++#endif
++
++struct vchiq_mmal_instance;
++
++/* normal message context */
++struct mmal_msg_context {
++ struct vchiq_mmal_instance *instance;
++
++ /* Index in the context_map idr so that we can find the
++ * mmal_msg_context again when servicing the VCHI reply.
++ */
++ int handle;
++
++ union {
++ struct {
++ /* work struct for buffer_cb callback */
++ struct work_struct work;
++ /* work struct for deferred callback */
++ struct work_struct buffer_to_host_work;
++ /* mmal instance */
++ struct vchiq_mmal_instance *instance;
++ /* mmal port */
++ struct vchiq_mmal_port *port;
++ /* actual buffer used to store bulk reply */
++ struct mmal_buffer *buffer;
++ /* amount of buffer used */
++ unsigned long buffer_used;
++ /* MMAL buffer flags */
++ u32 mmal_flags;
++ /* Presentation and Decode timestamps */
++ s64 pts;
++ s64 dts;
++
++ int status; /* context status */
++
++ } bulk; /* bulk data */
++
++ struct {
++ /* message handle to release */
++ VCHI_HELD_MSG_T msg_handle;
++ /* pointer to received message */
++ struct mmal_msg *msg;
++ /* received message length */
++ u32 msg_len;
++ /* completion upon reply */
++ struct completion cmplt;
++ } sync; /* synchronous response */
++ } u;
++
++};
++
++struct vchiq_mmal_instance {
++ VCHI_SERVICE_HANDLE_T handle;
++
++ /* ensure serialised access to service */
++ struct mutex vchiq_mutex;
++
++ /* vmalloc page to receive scratch bulk xfers into */
++ void *bulk_scratch;
++
++ struct idr context_map;
++ /* protect accesses to context_map */
++ struct mutex context_map_lock;
++
++ /* component to use next */
++ int component_idx;
++ struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
++
++ /* ordered workqueue to process all bulk operations */
++ struct workqueue_struct *bulk_wq;
++};
++
++static struct mmal_msg_context *
++get_msg_context(struct vchiq_mmal_instance *instance)
++{
++ struct mmal_msg_context *msg_context;
++ int handle;
++
++ /* todo: should this be allocated from a pool to avoid kzalloc */
++ msg_context = kzalloc(sizeof(*msg_context), GFP_KERNEL);
++
++ if (!msg_context)
++ return ERR_PTR(-ENOMEM);
++
++ /* Create an ID that will be passed along with our message so
++ * that when we service the VCHI reply, we can look up what
++ * message is being replied to.
++ */
++ mutex_lock(&instance->context_map_lock);
++ handle = idr_alloc(&instance->context_map, msg_context,
++ 0, 0, GFP_KERNEL);
++ mutex_unlock(&instance->context_map_lock);
++
++ if (handle < 0) {
++ kfree(msg_context);
++ return ERR_PTR(handle);
++ }
++
++ msg_context->instance = instance;
++ msg_context->handle = handle;
++
++ return msg_context;
++}
++
++static struct mmal_msg_context *
++lookup_msg_context(struct vchiq_mmal_instance *instance, int handle)
++{
++ return idr_find(&instance->context_map, handle);
++}
++
++static void
++release_msg_context(struct mmal_msg_context *msg_context)
++{
++ struct vchiq_mmal_instance *instance = msg_context->instance;
++
++ mutex_lock(&instance->context_map_lock);
++ idr_remove(&instance->context_map, msg_context->handle);
++ mutex_unlock(&instance->context_map_lock);
++ kfree(msg_context);
++}
++
++/* deals with receipt of event to host message */
++static void event_to_host_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg, u32 msg_len)
++{
++ pr_debug("unhandled event\n");
++ pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n",
++ msg->u.event_to_host.client_component,
++ msg->u.event_to_host.port_type,
++ msg->u.event_to_host.port_num,
++ msg->u.event_to_host.cmd, msg->u.event_to_host.length);
++}
++
++/* workqueue scheduled callback
++ *
++ * we do this because it is important we do not call any other vchiq
++ * sync calls from witin the message delivery thread
++ */
++static void buffer_work_cb(struct work_struct *work)
++{
++ struct mmal_msg_context *msg_context =
++ container_of(work, struct mmal_msg_context, u.bulk.work);
++
++ atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
++
++ msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
++ msg_context->u.bulk.port,
++ msg_context->u.bulk.status,
++ msg_context->u.bulk.buffer,
++ msg_context->u.bulk.buffer_used,
++ msg_context->u.bulk.mmal_flags,
++ msg_context->u.bulk.dts,
++ msg_context->u.bulk.pts);
++}
++
++/* workqueue scheduled callback to handle receiving buffers
++ *
++ * VCHI will allow up to 4 bulk receives to be scheduled before blocking.
++ * If we block in the service_callback context then we can't process the
++ * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked
++ * vchi_bulk_queue_receive() call to complete.
++ */
++static void buffer_to_host_work_cb(struct work_struct *work)
++{
++ struct mmal_msg_context *msg_context =
++ container_of(work, struct mmal_msg_context,
++ u.bulk.buffer_to_host_work);
++ struct vchiq_mmal_instance *instance = msg_context->instance;
++ unsigned long len = msg_context->u.bulk.buffer_used;
++ int ret;
++
++ if (!len)
++ /* Dummy receive to ensure the buffers remain in order */
++ len = 8;
++ /* queue the bulk submission */
++ vchi_service_use(instance->handle);
++ ret = vchi_bulk_queue_receive(instance->handle,
++ msg_context->u.bulk.buffer->buffer,
++ /* Actual receive needs to be a multiple
++ * of 4 bytes
++ */
++ (len + 3) & ~3,
++ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
++ msg_context);
++
++ vchi_service_release(instance->handle);
++
++ if (ret != 0)
++ pr_err("%s: ctx: %p, vchi_bulk_queue_receive failed %d\n",
++ __func__, msg_context, ret);
++}
++
++/* enqueue a bulk receive for a given message context */
++static int bulk_receive(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg,
++ struct mmal_msg_context *msg_context)
++{
++ unsigned long rd_len;
++
++ rd_len = msg->u.buffer_from_host.buffer_header.length;
++
++ if (!msg_context->u.bulk.buffer) {
++ pr_err("bulk.buffer not configured - error in buffer_from_host\n");
++
++ /* todo: this is a serious error, we should never have
++ * committed a buffer_to_host operation to the mmal
++ * port without the buffer to back it up (underflow
++ * handling) and there is no obvious way to deal with
++ * this - how is the mmal servie going to react when
++ * we fail to do the xfer and reschedule a buffer when
++ * it arrives? perhaps a starved flag to indicate a
++ * waiting bulk receive?
++ */
++
++ return -EINVAL;
++ }
++
++ /* ensure we do not overrun the available buffer */
++ if (rd_len > msg_context->u.bulk.buffer->buffer_size) {
++ rd_len = msg_context->u.bulk.buffer->buffer_size;
++ pr_warn("short read as not enough receive buffer space\n");
++ /* todo: is this the correct response, what happens to
++ * the rest of the message data?
++ */
++ }
++
++ /* store length */
++ msg_context->u.bulk.buffer_used = rd_len;
++ msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
++ msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
++
++ queue_work(msg_context->instance->bulk_wq,
++ &msg_context->u.bulk.buffer_to_host_work);
++
++ return 0;
++}
++
++/* data in message, memcpy from packet into output buffer */
++static int inline_receive(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg,
++ struct mmal_msg_context *msg_context)
++{
++ memcpy(msg_context->u.bulk.buffer->buffer,
++ msg->u.buffer_from_host.short_data,
++ msg->u.buffer_from_host.payload_in_message);
++
++ msg_context->u.bulk.buffer_used =
++ msg->u.buffer_from_host.payload_in_message;
++
++ return 0;
++}
++
++/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */
++static int
++buffer_from_host(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port, struct mmal_buffer *buf)
++{
++ struct mmal_msg_context *msg_context;
++ struct mmal_msg m;
++ int ret;
++
++ if (!port->enabled)
++ return -EINVAL;
++
++ pr_debug("instance:%p buffer:%p\n", instance->handle, buf);
++
++ /* get context */
++ if (!buf->msg_context) {
++ pr_err("%s: msg_context not allocated, buf %p\n", __func__,
++ buf);
++ return -EINVAL;
++ }
++ msg_context = buf->msg_context;
++
++ /* store bulk message context for when data arrives */
++ msg_context->u.bulk.instance = instance;
++ msg_context->u.bulk.port = port;
++ msg_context->u.bulk.buffer = buf;
++ msg_context->u.bulk.buffer_used = 0;
++
++ /* initialise work structure ready to schedule callback */
++ INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
++ INIT_WORK(&msg_context->u.bulk.buffer_to_host_work,
++ buffer_to_host_work_cb);
++
++ atomic_inc(&port->buffers_with_vpu);
++
++ /* prep the buffer from host message */
++ memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */
++
++ m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST;
++ m.h.magic = MMAL_MAGIC;
++ m.h.context = msg_context->handle;
++ m.h.status = 0;
++
++ /* drvbuf is our private data passed back */
++ m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC;
++ m.u.buffer_from_host.drvbuf.component_handle = port->component->handle;
++ m.u.buffer_from_host.drvbuf.port_handle = port->handle;
++ m.u.buffer_from_host.drvbuf.client_context = msg_context->handle;
++
++ /* buffer header */
++ m.u.buffer_from_host.buffer_header.cmd = 0;
++ m.u.buffer_from_host.buffer_header.data =
++ (u32)(unsigned long)buf->buffer;
++ m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
++ m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */
++ m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */
++ m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */
++ m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
++ m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
++
++ /* clear buffer type sepecific data */
++ memset(&m.u.buffer_from_host.buffer_header_type_specific, 0,
++ sizeof(m.u.buffer_from_host.buffer_header_type_specific));
++
++ /* no payload in message */
++ m.u.buffer_from_host.payload_in_message = 0;
++
++ vchi_service_use(instance->handle);
++
++ ret = vchi_queue_kernel_message(instance->handle,
++ &m,
++ sizeof(struct mmal_msg_header) +
++ sizeof(m.u.buffer_from_host));
++
++ vchi_service_release(instance->handle);
++
++ return ret;
++}
++
++/* deals with receipt of buffer to host message */
++static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg, u32 msg_len)
++{
++ struct mmal_msg_context *msg_context;
++ u32 handle;
++
++ pr_debug("%s: instance:%p msg:%p msg_len:%d\n",
++ __func__, instance, msg, msg_len);
++
++ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
++ handle = msg->u.buffer_from_host.drvbuf.client_context;
++ msg_context = lookup_msg_context(instance, handle);
++
++ if (!msg_context) {
++ pr_err("drvbuf.client_context(%u) is invalid\n",
++ handle);
++ return;
++ }
++ } else {
++ pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n");
++ return;
++ }
++
++ msg_context->u.bulk.mmal_flags =
++ msg->u.buffer_from_host.buffer_header.flags;
++
++ if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
++ /* message reception had an error */
++ pr_warn("error %d in reply\n", msg->h.status);
++
++ msg_context->u.bulk.status = msg->h.status;
++
++ } else if (msg->u.buffer_from_host.buffer_header.length == 0) {
++ /* empty buffer */
++ if (msg->u.buffer_from_host.buffer_header.flags &
++ MMAL_BUFFER_HEADER_FLAG_EOS) {
++ msg_context->u.bulk.status =
++ bulk_receive(instance, msg, msg_context);
++ if (msg_context->u.bulk.status == 0)
++ return; /* successful bulk submission, bulk
++ * completion will trigger callback
++ */
++ } else {
++ /* do callback with empty buffer - not EOS though */
++ msg_context->u.bulk.status = 0;
++ msg_context->u.bulk.buffer_used = 0;
++ }
++ } else if (msg->u.buffer_from_host.payload_in_message == 0) {
++ /* data is not in message, queue a bulk receive */
++ msg_context->u.bulk.status =
++ bulk_receive(instance, msg, msg_context);
++ if (msg_context->u.bulk.status == 0)
++ return; /* successful bulk submission, bulk
++ * completion will trigger callback
++ */
++
++ /* failed to submit buffer, this will end badly */
++ pr_err("error %d on bulk submission\n",
++ msg_context->u.bulk.status);
++
++ } else if (msg->u.buffer_from_host.payload_in_message <=
++ MMAL_VC_SHORT_DATA) {
++ /* data payload within message */
++ msg_context->u.bulk.status = inline_receive(instance, msg,
++ msg_context);
++ } else {
++ pr_err("message with invalid short payload\n");
++
++ /* signal error */
++ msg_context->u.bulk.status = -EINVAL;
++ msg_context->u.bulk.buffer_used =
++ msg->u.buffer_from_host.payload_in_message;
++ }
++
++ /* schedule the port callback */
++ schedule_work(&msg_context->u.bulk.work);
++}
++
++static void bulk_receive_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg_context *msg_context)
++{
++ msg_context->u.bulk.status = 0;
++
++ /* schedule the port callback */
++ schedule_work(&msg_context->u.bulk.work);
++}
++
++static void bulk_abort_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg_context *msg_context)
++{
++ pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context);
++
++ msg_context->u.bulk.status = -EINTR;
++
++ schedule_work(&msg_context->u.bulk.work);
++}
++
++/* incoming event service callback */
++static void service_callback(void *param,
++ const VCHI_CALLBACK_REASON_T reason,
++ void *bulk_ctx)
++{
++ struct vchiq_mmal_instance *instance = param;
++ int status;
++ u32 msg_len;
++ struct mmal_msg *msg;
++ VCHI_HELD_MSG_T msg_handle;
++ struct mmal_msg_context *msg_context;
++
++ if (!instance) {
++ pr_err("Message callback passed NULL instance\n");
++ return;
++ }
++
++ switch (reason) {
++ case VCHI_CALLBACK_MSG_AVAILABLE:
++ status = vchi_msg_hold(instance->handle, (void **)&msg,
++ &msg_len, VCHI_FLAGS_NONE, &msg_handle);
++ if (status) {
++ pr_err("Unable to dequeue a message (%d)\n", status);
++ break;
++ }
++
++ DBG_DUMP_MSG(msg, msg_len, "<<< reply message");
++
++ /* handling is different for buffer messages */
++ switch (msg->h.type) {
++ case MMAL_MSG_TYPE_BUFFER_FROM_HOST:
++ vchi_held_msg_release(&msg_handle);
++ break;
++
++ case MMAL_MSG_TYPE_EVENT_TO_HOST:
++ event_to_host_cb(instance, msg, msg_len);
++ vchi_held_msg_release(&msg_handle);
++
++ break;
++
++ case MMAL_MSG_TYPE_BUFFER_TO_HOST:
++ buffer_to_host_cb(instance, msg, msg_len);
++ vchi_held_msg_release(&msg_handle);
++ break;
++
++ default:
++ /* messages dependent on header context to complete */
++ if (!msg->h.context) {
++ pr_err("received message context was null!\n");
++ vchi_held_msg_release(&msg_handle);
++ break;
++ }
++
++ msg_context = lookup_msg_context(instance,
++ msg->h.context);
++ if (!msg_context) {
++ pr_err("received invalid message context %u!\n",
++ msg->h.context);
++ vchi_held_msg_release(&msg_handle);
++ break;
++ }
++
++ /* fill in context values */
++ msg_context->u.sync.msg_handle = msg_handle;
++ msg_context->u.sync.msg = msg;
++ msg_context->u.sync.msg_len = msg_len;
++
++ /* todo: should this check (completion_done()
++ * == 1) for no one waiting? or do we need a
++ * flag to tell us the completion has been
++ * interrupted so we can free the message and
++ * its context. This probably also solves the
++ * message arriving after interruption todo
++ * below
++ */
++
++ /* complete message so caller knows it happened */
++ complete(&msg_context->u.sync.cmplt);
++ break;
++ }
++
++ break;
++
++ case VCHI_CALLBACK_BULK_RECEIVED:
++ bulk_receive_cb(instance, bulk_ctx);
++ break;
++
++ case VCHI_CALLBACK_BULK_RECEIVE_ABORTED:
++ bulk_abort_cb(instance, bulk_ctx);
++ break;
++
++ case VCHI_CALLBACK_SERVICE_CLOSED:
++ /* TODO: consider if this requires action if received when
++ * driver is not explicitly closing the service
++ */
++ break;
++
++ default:
++ pr_err("Received unhandled message reason %d\n", reason);
++ break;
++ }
++}
++
++static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg,
++ unsigned int payload_len,
++ struct mmal_msg **msg_out,
++ VCHI_HELD_MSG_T *msg_handle_out)
++{
++ struct mmal_msg_context *msg_context;
++ int ret;
++ unsigned long timeout;
++
++ /* payload size must not cause message to exceed max size */
++ if (payload_len >
++ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
++ pr_err("payload length %d exceeds max:%d\n", payload_len,
++ (int)(MMAL_MSG_MAX_SIZE -
++ sizeof(struct mmal_msg_header)));
++ return -EINVAL;
++ }
++
++ msg_context = get_msg_context(instance);
++ if (IS_ERR(msg_context))
++ return PTR_ERR(msg_context);
++
++ init_completion(&msg_context->u.sync.cmplt);
++
++ msg->h.magic = MMAL_MAGIC;
++ msg->h.context = msg_context->handle;
++ msg->h.status = 0;
++
++ DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len),
++ ">>> sync message");
++
++ vchi_service_use(instance->handle);
++
++ ret = vchi_queue_kernel_message(instance->handle,
++ msg,
++ sizeof(struct mmal_msg_header) +
++ payload_len);
++
++ vchi_service_release(instance->handle);
++
++ if (ret) {
++ pr_err("error %d queuing message\n", ret);
++ release_msg_context(msg_context);
++ return ret;
++ }
++
++ timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt,
++ 3 * HZ);
++ if (timeout == 0) {
++ pr_err("timed out waiting for sync completion\n");
++ ret = -ETIME;
++ /* todo: what happens if the message arrives after aborting */
++ release_msg_context(msg_context);
++ return ret;
++ }
++
++ *msg_out = msg_context->u.sync.msg;
++ *msg_handle_out = msg_context->u.sync.msg_handle;
++ release_msg_context(msg_context);
++
++ return 0;
++}
++
++static void dump_port_info(struct vchiq_mmal_port *port)
++{
++ pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled);
++
++ pr_debug("buffer minimum num:%d size:%d align:%d\n",
++ port->minimum_buffer.num,
++ port->minimum_buffer.size, port->minimum_buffer.alignment);
++
++ pr_debug("buffer recommended num:%d size:%d align:%d\n",
++ port->recommended_buffer.num,
++ port->recommended_buffer.size,
++ port->recommended_buffer.alignment);
++
++ pr_debug("buffer current values num:%d size:%d align:%d\n",
++ port->current_buffer.num,
++ port->current_buffer.size, port->current_buffer.alignment);
++
++ pr_debug("elementary stream: type:%d encoding:0x%x variant:0x%x\n",
++ port->format.type,
++ port->format.encoding, port->format.encoding_variant);
++
++ pr_debug(" bitrate:%d flags:0x%x\n",
++ port->format.bitrate, port->format.flags);
++
++ if (port->format.type == MMAL_ES_TYPE_VIDEO) {
++ pr_debug
++ ("es video format: width:%d height:%d colourspace:0x%x\n",
++ port->es.video.width, port->es.video.height,
++ port->es.video.color_space);
++
++ pr_debug(" : crop xywh %d,%d,%d,%d\n",
++ port->es.video.crop.x,
++ port->es.video.crop.y,
++ port->es.video.crop.width, port->es.video.crop.height);
++ pr_debug(" : framerate %d/%d aspect %d/%d\n",
++ port->es.video.frame_rate.num,
++ port->es.video.frame_rate.den,
++ port->es.video.par.num, port->es.video.par.den);
++ }
++}
++
++static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p)
++{
++ /* todo do readonly fields need setting at all? */
++ p->type = port->type;
++ p->index = port->index;
++ p->index_all = 0;
++ p->is_enabled = port->enabled;
++ p->buffer_num_min = port->minimum_buffer.num;
++ p->buffer_size_min = port->minimum_buffer.size;
++ p->buffer_alignment_min = port->minimum_buffer.alignment;
++ p->buffer_num_recommended = port->recommended_buffer.num;
++ p->buffer_size_recommended = port->recommended_buffer.size;
++
++ /* only three writable fields in a port */
++ p->buffer_num = port->current_buffer.num;
++ p->buffer_size = port->current_buffer.size;
++ p->userdata = (u32)(unsigned long)port;
++}
++
++static int port_info_set(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ pr_debug("setting port info port %p\n", port);
++ if (!port)
++ return -1;
++ dump_port_info(port);
++
++ m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET;
++
++ m.u.port_info_set.component_handle = port->component->handle;
++ m.u.port_info_set.port_type = port->type;
++ m.u.port_info_set.port_index = port->index;
++
++ port_to_mmal_msg(port, &m.u.port_info_set.port);
++
++ /* elementary stream format setup */
++ m.u.port_info_set.format.type = port->format.type;
++ m.u.port_info_set.format.encoding = port->format.encoding;
++ m.u.port_info_set.format.encoding_variant =
++ port->format.encoding_variant;
++ m.u.port_info_set.format.bitrate = port->format.bitrate;
++ m.u.port_info_set.format.flags = port->format.flags;
++
++ memcpy(&m.u.port_info_set.es, &port->es,
++ sizeof(union mmal_es_specific_format));
++
++ m.u.port_info_set.format.extradata_size = port->format.extradata_size;
++ memcpy(&m.u.port_info_set.extradata, port->format.extradata,
++ port->format.extradata_size);
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.port_info_set),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ /* return operation status */
++ ret = -rmsg->u.port_info_get_reply.status;
++
++ pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret,
++ port->component->handle, port->handle);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* use port info get message to retrieve port information */
++static int port_info_get(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ /* port info time */
++ m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET;
++ m.u.port_info_get.component_handle = port->component->handle;
++ m.u.port_info_get.port_type = port->type;
++ m.u.port_info_get.index = port->index;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.port_info_get),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ /* return operation status */
++ ret = -rmsg->u.port_info_get_reply.status;
++ if (ret != MMAL_MSG_STATUS_SUCCESS)
++ goto release_msg;
++
++ if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
++ port->enabled = false;
++ else
++ port->enabled = true;
++
++ /* copy the values out of the message */
++ port->handle = rmsg->u.port_info_get_reply.port_handle;
++
++ /* port type and index cached to use on port info set because
++ * it does not use a port handle
++ */
++ port->type = rmsg->u.port_info_get_reply.port_type;
++ port->index = rmsg->u.port_info_get_reply.port_index;
++
++ port->minimum_buffer.num =
++ rmsg->u.port_info_get_reply.port.buffer_num_min;
++ port->minimum_buffer.size =
++ rmsg->u.port_info_get_reply.port.buffer_size_min;
++ port->minimum_buffer.alignment =
++ rmsg->u.port_info_get_reply.port.buffer_alignment_min;
++
++ port->recommended_buffer.alignment =
++ rmsg->u.port_info_get_reply.port.buffer_alignment_min;
++ port->recommended_buffer.num =
++ rmsg->u.port_info_get_reply.port.buffer_num_recommended;
++
++ port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num;
++ port->current_buffer.size =
++ rmsg->u.port_info_get_reply.port.buffer_size;
++
++ /* stream format */
++ port->format.type = rmsg->u.port_info_get_reply.format.type;
++ port->format.encoding = rmsg->u.port_info_get_reply.format.encoding;
++ port->format.encoding_variant =
++ rmsg->u.port_info_get_reply.format.encoding_variant;
++ port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate;
++ port->format.flags = rmsg->u.port_info_get_reply.format.flags;
++
++ /* elementary stream format */
++ memcpy(&port->es,
++ &rmsg->u.port_info_get_reply.es,
++ sizeof(union mmal_es_specific_format));
++ port->format.es = &port->es;
++
++ port->format.extradata_size =
++ rmsg->u.port_info_get_reply.format.extradata_size;
++ memcpy(port->format.extradata,
++ rmsg->u.port_info_get_reply.extradata,
++ port->format.extradata_size);
++
++ pr_debug("received port info\n");
++ dump_port_info(port);
++
++release_msg:
++
++ pr_debug("%s:result:%d component:0x%x port:%d\n",
++ __func__, ret, port->component->handle, port->handle);
++
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* create comonent on vc */
++static int create_component(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component,
++ const char *name)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ /* build component create message */
++ m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE;
++ m.u.component_create.client_component = (u32)(unsigned long)component;
++ strncpy(m.u.component_create.name, name,
++ sizeof(m.u.component_create.name));
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.component_create),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.component_create_reply.status;
++ if (ret != MMAL_MSG_STATUS_SUCCESS)
++ goto release_msg;
++
++ /* a valid component response received */
++ component->handle = rmsg->u.component_create_reply.component_handle;
++ component->inputs = rmsg->u.component_create_reply.input_num;
++ component->outputs = rmsg->u.component_create_reply.output_num;
++ component->clocks = rmsg->u.component_create_reply.clock_num;
++
++ pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n",
++ component->handle,
++ component->inputs, component->outputs, component->clocks);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* destroys a component on vc */
++static int destroy_component(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY;
++ m.u.component_destroy.component_handle = component->handle;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.component_destroy),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.component_destroy_reply.status;
++
++release_msg:
++
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* enable a component on vc */
++static int enable_component(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE;
++ m.u.component_enable.component_handle = component->handle;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.component_enable),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.component_enable_reply.status;
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* disable a component on vc */
++static int disable_component(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE;
++ m.u.component_disable.component_handle = component->handle;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.component_disable),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.component_disable_reply.status;
++
++release_msg:
++
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* get version of mmal implementation */
++static int get_version(struct vchiq_mmal_instance *instance,
++ u32 *major_out, u32 *minor_out)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_GET_VERSION;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.version),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != m.h.type) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ *major_out = rmsg->u.version.major;
++ *minor_out = rmsg->u.version.minor;
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* do a port action with a port as a parameter */
++static int port_action_port(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ enum mmal_msg_port_action_type action_type)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
++ m.u.port_action_port.component_handle = port->component->handle;
++ m.u.port_action_port.port_handle = port->handle;
++ m.u.port_action_port.action = action_type;
++
++ port_to_mmal_msg(port, &m.u.port_action_port.port);
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.port_action_port),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.port_action_reply.status;
++
++ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n",
++ __func__,
++ ret, port->component->handle, port->handle,
++ port_action_type_names[action_type], action_type);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* do a port action with handles as parameters */
++static int port_action_handle(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ enum mmal_msg_port_action_type action_type,
++ u32 connect_component_handle,
++ u32 connect_port_handle)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
++
++ m.u.port_action_handle.component_handle = port->component->handle;
++ m.u.port_action_handle.port_handle = port->handle;
++ m.u.port_action_handle.action = action_type;
++
++ m.u.port_action_handle.connect_component_handle =
++ connect_component_handle;
++ m.u.port_action_handle.connect_port_handle = connect_port_handle;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(m.u.port_action_handle),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.port_action_reply.status;
++
++ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d) connect component:0x%x connect port:%d\n",
++ __func__,
++ ret, port->component->handle, port->handle,
++ port_action_type_names[action_type],
++ action_type, connect_component_handle, connect_port_handle);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++static int port_parameter_set(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter_id, void *value, u32 value_size)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET;
++
++ m.u.port_parameter_set.component_handle = port->component->handle;
++ m.u.port_parameter_set.port_handle = port->handle;
++ m.u.port_parameter_set.id = parameter_id;
++ m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size;
++ memcpy(&m.u.port_parameter_set.value, value, value_size);
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ (4 * sizeof(u32)) + value_size,
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) {
++ /* got an unexpected message type in reply */
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.port_parameter_set_reply.status;
++
++ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n",
++ __func__,
++ ret, port->component->handle, port->handle, parameter_id);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++static int port_parameter_get(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter_id, void *value, u32 *value_size)
++{
++ int ret;
++ struct mmal_msg m;
++ struct mmal_msg *rmsg;
++ VCHI_HELD_MSG_T rmsg_handle;
++
++ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET;
++
++ m.u.port_parameter_get.component_handle = port->component->handle;
++ m.u.port_parameter_get.port_handle = port->handle;
++ m.u.port_parameter_get.id = parameter_id;
++ m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size;
++
++ ret = send_synchronous_mmal_msg(instance, &m,
++ sizeof(struct
++ mmal_msg_port_parameter_get),
++ &rmsg, &rmsg_handle);
++ if (ret)
++ return ret;
++
++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) {
++ /* got an unexpected message type in reply */
++ pr_err("Incorrect reply type %d\n", rmsg->h.type);
++ ret = -EINVAL;
++ goto release_msg;
++ }
++
++ ret = -rmsg->u.port_parameter_get_reply.status;
++ /* port_parameter_get_reply.size includes the header,
++ * whilst *value_size doesn't.
++ */
++ rmsg->u.port_parameter_get_reply.size -= (2 * sizeof(u32));
++
++ if (ret || rmsg->u.port_parameter_get_reply.size > *value_size) {
++ /* Copy only as much as we have space for
++ * but report true size of parameter
++ */
++ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
++ *value_size);
++ *value_size = rmsg->u.port_parameter_get_reply.size;
++ } else {
++ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
++ rmsg->u.port_parameter_get_reply.size);
++ }
++
++ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
++ ret, port->component->handle, port->handle, parameter_id);
++
++release_msg:
++ vchi_held_msg_release(&rmsg_handle);
++
++ return ret;
++}
++
++/* disables a port and drains buffers from it */
++static int port_disable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++ struct list_head *q, *buf_head;
++ unsigned long flags = 0;
++
++ if (!port->enabled)
++ return 0;
++
++ port->enabled = false;
++
++ ret = port_action_port(instance, port,
++ MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
++ if (ret == 0) {
++ /*
++ * Drain all queued buffers on port. This should only
++ * apply to buffers that have been queued before the port
++ * has been enabled. If the port has been enabled and buffers
++ * passed, then the buffers should have been removed from this
++ * list, and we should get the relevant callbacks via VCHIQ
++ * to release the buffers.
++ */
++ spin_lock_irqsave(&port->slock, flags);
++
++ list_for_each_safe(buf_head, q, &port->buffers) {
++ struct mmal_buffer *mmalbuf;
++
++ mmalbuf = list_entry(buf_head, struct mmal_buffer,
++ list);
++ list_del(buf_head);
++ if (port->buffer_cb)
++ port->buffer_cb(instance,
++ port, 0, mmalbuf, 0, 0,
++ MMAL_TIME_UNKNOWN,
++ MMAL_TIME_UNKNOWN);
++ }
++
++ spin_unlock_irqrestore(&port->slock, flags);
++
++ ret = port_info_get(instance, port);
++ }
++
++ return ret;
++}
++
++/* enable a port */
++static int port_enable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ unsigned int hdr_count;
++ struct list_head *q, *buf_head;
++ int ret;
++
++ if (port->enabled)
++ return 0;
++
++ ret = port_action_port(instance, port,
++ MMAL_MSG_PORT_ACTION_TYPE_ENABLE);
++ if (ret)
++ goto done;
++
++ port->enabled = true;
++
++ if (port->buffer_cb) {
++ /* send buffer headers to videocore */
++ hdr_count = 1;
++ list_for_each_safe(buf_head, q, &port->buffers) {
++ struct mmal_buffer *mmalbuf;
++
++ mmalbuf = list_entry(buf_head, struct mmal_buffer,
++ list);
++ ret = buffer_from_host(instance, port, mmalbuf);
++ if (ret)
++ goto done;
++
++ list_del(buf_head);
++ hdr_count++;
++ if (hdr_count > port->current_buffer.num)
++ break;
++ }
++ }
++
++ ret = port_info_get(instance, port);
++
++done:
++ return ret;
++}
++
++/* ------------------------------------------------------------------
++ * Exported API
++ *------------------------------------------------------------------
++ */
++
++int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ ret = port_info_set(instance, port);
++ if (ret)
++ goto release_unlock;
++
++ /* read what has actually been set */
++ ret = port_info_get(instance, port);
++
++release_unlock:
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_port_set_format);
++
++int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter, void *value, u32 value_size)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ ret = port_parameter_set(instance, port, parameter, value, value_size);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_set);
++
++int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter, void *value, u32 *value_size)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ ret = port_parameter_get(instance, port, parameter, value, value_size);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_get);
++
++/* enable a port
++ *
++ * enables a port and queues buffers for satisfying callbacks if we
++ * provide a callback handler
++ */
++int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ vchiq_mmal_buffer_cb buffer_cb)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ /* already enabled - noop */
++ if (port->enabled) {
++ ret = 0;
++ goto unlock;
++ }
++
++ port->buffer_cb = buffer_cb;
++
++ ret = port_enable(instance, port);
++
++unlock:
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_port_enable);
++
++int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (!port->enabled) {
++ mutex_unlock(&instance->vchiq_mutex);
++ return 0;
++ }
++
++ ret = port_disable(instance, port);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_port_disable);
++
++/* ports will be connected in a tunneled manner so data buffers
++ * are not handled by client.
++ */
++int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *src,
++ struct vchiq_mmal_port *dst)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ /* disconnect ports if connected */
++ if (src->connected) {
++ ret = port_disable(instance, src);
++ if (ret) {
++ pr_err("failed disabling src port(%d)\n", ret);
++ goto release_unlock;
++ }
++
++ /* do not need to disable the destination port as they
++ * are connected and it is done automatically
++ */
++
++ ret = port_action_handle(instance, src,
++ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT,
++ src->connected->component->handle,
++ src->connected->handle);
++ if (ret < 0) {
++ pr_err("failed disconnecting src port\n");
++ goto release_unlock;
++ }
++ src->connected->enabled = false;
++ src->connected = NULL;
++ }
++
++ if (!dst) {
++ /* do not make new connection */
++ ret = 0;
++ pr_debug("not making new connection\n");
++ goto release_unlock;
++ }
++
++ /* copy src port format to dst */
++ dst->format.encoding = src->format.encoding;
++ dst->es.video.width = src->es.video.width;
++ dst->es.video.height = src->es.video.height;
++ dst->es.video.crop.x = src->es.video.crop.x;
++ dst->es.video.crop.y = src->es.video.crop.y;
++ dst->es.video.crop.width = src->es.video.crop.width;
++ dst->es.video.crop.height = src->es.video.crop.height;
++ dst->es.video.frame_rate.num = src->es.video.frame_rate.num;
++ dst->es.video.frame_rate.den = src->es.video.frame_rate.den;
++
++ /* set new format */
++ ret = port_info_set(instance, dst);
++ if (ret) {
++ pr_debug("setting port info failed\n");
++ goto release_unlock;
++ }
++
++ /* read what has actually been set */
++ ret = port_info_get(instance, dst);
++ if (ret) {
++ pr_debug("read back port info failed\n");
++ goto release_unlock;
++ }
++
++ /* connect two ports together */
++ ret = port_action_handle(instance, src,
++ MMAL_MSG_PORT_ACTION_TYPE_CONNECT,
++ dst->component->handle, dst->handle);
++ if (ret < 0) {
++ pr_debug("connecting port %d:%d to %d:%d failed\n",
++ src->component->handle, src->handle,
++ dst->component->handle, dst->handle);
++ goto release_unlock;
++ }
++ src->connected = dst;
++
++release_unlock:
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_port_connect_tunnel);
++
++int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ struct mmal_buffer *buffer)
++{
++ unsigned long flags = 0;
++ int ret;
++
++ ret = buffer_from_host(instance, port, buffer);
++ if (ret == -EINVAL) {
++ /* Port is disabled. Queue for when it is enabled. */
++ spin_lock_irqsave(&port->slock, flags);
++ list_add_tail(&buffer->list, &port->buffers);
++ spin_unlock_irqrestore(&port->slock, flags);
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_submit_buffer);
++
++int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance,
++ struct mmal_buffer *buf)
++{
++ struct mmal_msg_context *msg_context = get_msg_context(instance);
++
++ if (IS_ERR(msg_context))
++ return (PTR_ERR(msg_context));
++
++ buf->msg_context = msg_context;
++ return 0;
++}
++EXPORT_SYMBOL_GPL(mmal_vchi_buffer_init);
++
++int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf)
++{
++ struct mmal_msg_context *msg_context = buf->msg_context;
++
++ if (msg_context)
++ release_msg_context(msg_context);
++ buf->msg_context = NULL;
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup);
++
++/* Initialise a mmal component and its ports
++ *
++ */
++int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance,
++ const char *name,
++ struct vchiq_mmal_component **component_out)
++{
++ int ret;
++ int idx; /* port index */
++ struct vchiq_mmal_component *component;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) {
++ ret = -EINVAL; /* todo is this correct error? */
++ goto unlock;
++ }
++
++ component = &instance->component[instance->component_idx];
++
++ ret = create_component(instance, component, name);
++ if (ret < 0) {
++ pr_err("%s: failed to create component %d (Not enough GPU mem?)\n",
++ __func__, ret);
++ goto unlock;
++ }
++
++ /* ports info needs gathering */
++ component->control.type = MMAL_PORT_TYPE_CONTROL;
++ component->control.index = 0;
++ component->control.component = component;
++ spin_lock_init(&component->control.slock);
++ INIT_LIST_HEAD(&component->control.buffers);
++ ret = port_info_get(instance, &component->control);
++ if (ret < 0)
++ goto release_component;
++
++ for (idx = 0; idx < component->inputs; idx++) {
++ component->input[idx].type = MMAL_PORT_TYPE_INPUT;
++ component->input[idx].index = idx;
++ component->input[idx].component = component;
++ spin_lock_init(&component->input[idx].slock);
++ INIT_LIST_HEAD(&component->input[idx].buffers);
++ ret = port_info_get(instance, &component->input[idx]);
++ if (ret < 0)
++ goto release_component;
++ }
++
++ for (idx = 0; idx < component->outputs; idx++) {
++ component->output[idx].type = MMAL_PORT_TYPE_OUTPUT;
++ component->output[idx].index = idx;
++ component->output[idx].component = component;
++ spin_lock_init(&component->output[idx].slock);
++ INIT_LIST_HEAD(&component->output[idx].buffers);
++ ret = port_info_get(instance, &component->output[idx]);
++ if (ret < 0)
++ goto release_component;
++ }
++
++ for (idx = 0; idx < component->clocks; idx++) {
++ component->clock[idx].type = MMAL_PORT_TYPE_CLOCK;
++ component->clock[idx].index = idx;
++ component->clock[idx].component = component;
++ spin_lock_init(&component->clock[idx].slock);
++ INIT_LIST_HEAD(&component->clock[idx].buffers);
++ ret = port_info_get(instance, &component->clock[idx]);
++ if (ret < 0)
++ goto release_component;
++ }
++
++ instance->component_idx++;
++
++ *component_out = component;
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return 0;
++
++release_component:
++ destroy_component(instance, component);
++unlock:
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_component_init);
++
++/*
++ * cause a mmal component to be destroyed
++ */
++int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (component->enabled)
++ ret = disable_component(instance, component);
++
++ ret = destroy_component(instance, component);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_component_finalise);
++
++/*
++ * cause a mmal component to be enabled
++ */
++int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (component->enabled) {
++ mutex_unlock(&instance->vchiq_mutex);
++ return 0;
++ }
++
++ ret = enable_component(instance, component);
++ if (ret == 0)
++ component->enabled = true;
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_component_enable);
++
++/*
++ * cause a mmal component to be enabled
++ */
++int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ if (!component->enabled) {
++ mutex_unlock(&instance->vchiq_mutex);
++ return 0;
++ }
++
++ ret = disable_component(instance, component);
++ if (ret == 0)
++ component->enabled = false;
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_component_disable);
++
++int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
++ u32 *major_out, u32 *minor_out)
++{
++ int ret;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ ret = get_version(instance, major_out, minor_out);
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_version);
++
++int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
++{
++ int status = 0;
++
++ if (!instance)
++ return -EINVAL;
++
++ if (mutex_lock_interruptible(&instance->vchiq_mutex))
++ return -EINTR;
++
++ vchi_service_use(instance->handle);
++
++ status = vchi_service_close(instance->handle);
++ if (status != 0)
++ pr_err("mmal-vchiq: VCHIQ close failed\n");
++
++ mutex_unlock(&instance->vchiq_mutex);
++
++ flush_workqueue(instance->bulk_wq);
++ destroy_workqueue(instance->bulk_wq);
++
++ vfree(instance->bulk_scratch);
++
++ idr_destroy(&instance->context_map);
++
++ kfree(instance);
++
++ return status;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_finalise);
++
++int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
++{
++ int status;
++ struct vchiq_mmal_instance *instance;
++ static VCHI_CONNECTION_T *vchi_connection;
++ static VCHI_INSTANCE_T vchi_instance;
++ SERVICE_CREATION_T params = {
++ .version = VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER),
++ .service_id = VC_MMAL_SERVER_NAME,
++ .connection = vchi_connection,
++ .rx_fifo_size = 0,
++ .tx_fifo_size = 0,
++ .callback = service_callback,
++ .callback_param = NULL,
++ .want_unaligned_bulk_rx = 1,
++ .want_unaligned_bulk_tx = 1,
++ .want_crc = 0
++ };
++
++ /* compile time checks to ensure structure size as they are
++ * directly (de)serialised from memory.
++ */
++
++ /* ensure the header structure has packed to the correct size */
++ BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24);
++
++ /* ensure message structure does not exceed maximum length */
++ BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE);
++
++ /* mmal port struct is correct size */
++ BUILD_BUG_ON(sizeof(struct mmal_port) != 64);
++
++ /* create a vchi instance */
++ status = vchi_initialise(&vchi_instance);
++ if (status) {
++ pr_err("Failed to initialise VCHI instance (status=%d)\n",
++ status);
++ return -EIO;
++ }
++
++ status = vchi_connect(NULL, 0, vchi_instance);
++ if (status) {
++ pr_err("Failed to connect VCHI instance (status=%d)\n", status);
++ return -EIO;
++ }
++
++ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
++
++ if (!instance)
++ return -ENOMEM;
++
++ mutex_init(&instance->vchiq_mutex);
++
++ instance->bulk_scratch = vmalloc(PAGE_SIZE);
++
++ mutex_init(&instance->context_map_lock);
++ idr_init_base(&instance->context_map, 1);
++
++ params.callback_param = instance;
++
++ instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq",
++ WQ_MEM_RECLAIM);
++ if (!instance->bulk_wq)
++ goto err_free;
++
++ status = vchi_service_open(vchi_instance, ¶ms, &instance->handle);
++ if (status) {
++ pr_err("Failed to open VCHI service connection (status=%d)\n",
++ status);
++ goto err_close_services;
++ }
++
++ vchi_service_release(instance->handle);
++
++ *out_instance = instance;
++
++ return 0;
++
++err_close_services:
++ vchi_service_close(instance->handle);
++ destroy_workqueue(instance->bulk_wq);
++err_free:
++ vfree(instance->bulk_scratch);
++ kfree(instance);
++ return -ENODEV;
++}
++EXPORT_SYMBOL_GPL(vchiq_mmal_init);
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
++++ /dev/null
+@@ -1,61 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Broadcom BM2835 V4L2 driver
+- *
+- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+- *
+- * Authors: Vincent Sanders @ Collabora
+- * Dave Stevenson @ Broadcom
+- * Simon Mellor @ Broadcom
+- * Luke Diamand @ Broadcom
+- *
+- * MMAL structures
+- *
+- */
+-#ifndef MMAL_COMMON_H
+-#define MMAL_COMMON_H
+-
+-#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
+-#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l')
+-
+-/** Special value signalling that time is not known */
+-#define MMAL_TIME_UNKNOWN BIT_ULL(63)
+-
+-struct mmal_msg_context;
+-
+-/* mapping between v4l and mmal video modes */
+-struct mmal_fmt {
+- char *name;
+- u32 fourcc; /* v4l2 format id */
+- int flags; /* v4l2 flags field */
+- u32 mmal;
+- int depth;
+- u32 mmal_component; /* MMAL component index to be used to encode */
+- u32 ybbp; /* depth of first Y plane for planar formats */
+- bool remove_padding; /* Does the GPU have to remove padding,
+- * or can we do hide padding via bytesperline.
+- */
+-};
+-
+-/* buffer for one video frame */
+-struct mmal_buffer {
+- /* v4l buffer data -- must be first */
+- struct vb2_v4l2_buffer vb;
+-
+- /* list of buffers available */
+- struct list_head list;
+-
+- void *buffer; /* buffer pointer */
+- unsigned long buffer_size; /* size of allocated buffer */
+-
+- struct mmal_msg_context *msg_context;
+-};
+-
+-/* */
+-struct mmal_colourfx {
+- s32 enable;
+- u32 u;
+- u32 v;
+-};
+-#endif
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h
++++ /dev/null
+@@ -1,124 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Broadcom BM2835 V4L2 driver
+- *
+- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+- *
+- * Authors: Vincent Sanders @ Collabora
+- * Dave Stevenson @ Broadcom
+- * Simon Mellor @ Broadcom
+- * Luke Diamand @ Broadcom
+- */
+-#ifndef MMAL_ENCODINGS_H
+-#define MMAL_ENCODINGS_H
+-
+-#define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4')
+-#define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3')
+-#define MMAL_ENCODING_MP4V MMAL_FOURCC('M', 'P', '4', 'V')
+-#define MMAL_ENCODING_MP2V MMAL_FOURCC('M', 'P', '2', 'V')
+-#define MMAL_ENCODING_MP1V MMAL_FOURCC('M', 'P', '1', 'V')
+-#define MMAL_ENCODING_WMV3 MMAL_FOURCC('W', 'M', 'V', '3')
+-#define MMAL_ENCODING_WMV2 MMAL_FOURCC('W', 'M', 'V', '2')
+-#define MMAL_ENCODING_WMV1 MMAL_FOURCC('W', 'M', 'V', '1')
+-#define MMAL_ENCODING_WVC1 MMAL_FOURCC('W', 'V', 'C', '1')
+-#define MMAL_ENCODING_VP8 MMAL_FOURCC('V', 'P', '8', ' ')
+-#define MMAL_ENCODING_VP7 MMAL_FOURCC('V', 'P', '7', ' ')
+-#define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ')
+-#define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O')
+-#define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K')
+-#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G')
+-
+-#define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G')
+-#define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ')
+-#define MMAL_ENCODING_PNG MMAL_FOURCC('P', 'N', 'G', ' ')
+-#define MMAL_ENCODING_PPM MMAL_FOURCC('P', 'P', 'M', ' ')
+-#define MMAL_ENCODING_TGA MMAL_FOURCC('T', 'G', 'A', ' ')
+-#define MMAL_ENCODING_BMP MMAL_FOURCC('B', 'M', 'P', ' ')
+-
+-#define MMAL_ENCODING_I420 MMAL_FOURCC('I', '4', '2', '0')
+-#define MMAL_ENCODING_I420_SLICE MMAL_FOURCC('S', '4', '2', '0')
+-#define MMAL_ENCODING_YV12 MMAL_FOURCC('Y', 'V', '1', '2')
+-#define MMAL_ENCODING_I422 MMAL_FOURCC('I', '4', '2', '2')
+-#define MMAL_ENCODING_I422_SLICE MMAL_FOURCC('S', '4', '2', '2')
+-#define MMAL_ENCODING_YUYV MMAL_FOURCC('Y', 'U', 'Y', 'V')
+-#define MMAL_ENCODING_YVYU MMAL_FOURCC('Y', 'V', 'Y', 'U')
+-#define MMAL_ENCODING_UYVY MMAL_FOURCC('U', 'Y', 'V', 'Y')
+-#define MMAL_ENCODING_VYUY MMAL_FOURCC('V', 'Y', 'U', 'Y')
+-#define MMAL_ENCODING_NV12 MMAL_FOURCC('N', 'V', '1', '2')
+-#define MMAL_ENCODING_NV21 MMAL_FOURCC('N', 'V', '2', '1')
+-#define MMAL_ENCODING_ARGB MMAL_FOURCC('A', 'R', 'G', 'B')
+-#define MMAL_ENCODING_RGBA MMAL_FOURCC('R', 'G', 'B', 'A')
+-#define MMAL_ENCODING_ABGR MMAL_FOURCC('A', 'B', 'G', 'R')
+-#define MMAL_ENCODING_BGRA MMAL_FOURCC('B', 'G', 'R', 'A')
+-#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R', 'G', 'B', '2')
+-#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R', 'G', 'B', '3')
+-#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R', 'G', 'B', '4')
+-#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B', 'G', 'R', '2')
+-#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B', 'G', 'R', '3')
+-#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B', 'G', 'R', '4')
+-
+-/** SAND Video (YUVUV128) format, native format understood by VideoCore.
+- * This format is *not* opaque - if requested you will receive full frames
+- * of YUV_UV video.
+- */
+-#define MMAL_ENCODING_YUVUV128 MMAL_FOURCC('S', 'A', 'N', 'D')
+-
+-/** VideoCore opaque image format, image handles are returned to
+- * the host but not the actual image data.
+- */
+-#define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V')
+-
+-/** An EGL image handle
+- */
+-#define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I')
+-
+-/* }@ */
+-
+-/** \name Pre-defined audio encodings */
+-/* @{ */
+-#define MMAL_ENCODING_PCM_UNSIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'U')
+-#define MMAL_ENCODING_PCM_UNSIGNED_LE MMAL_FOURCC('p', 'c', 'm', 'u')
+-#define MMAL_ENCODING_PCM_SIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'S')
+-#define MMAL_ENCODING_PCM_SIGNED_LE MMAL_FOURCC('p', 'c', 'm', 's')
+-#define MMAL_ENCODING_PCM_FLOAT_BE MMAL_FOURCC('P', 'C', 'M', 'F')
+-#define MMAL_ENCODING_PCM_FLOAT_LE MMAL_FOURCC('p', 'c', 'm', 'f')
+-
+-/* Pre-defined H264 encoding variants */
+-
+-/** ISO 14496-10 Annex B byte stream format */
+-#define MMAL_ENCODING_VARIANT_H264_DEFAULT 0
+-/** ISO 14496-15 AVC stream format */
+-#define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1')
+-/** Implicitly delineated NAL units without emulation prevention */
+-#define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ')
+-
+-/** \defgroup MmalColorSpace List of pre-defined video color spaces
+- * This defines a list of common color spaces. This list isn't exhaustive and
+- * is only provided as a convenience to avoid clients having to use FourCC
+- * codes directly. However components are allowed to define and use their own
+- * FourCC codes.
+- */
+-/* @{ */
+-
+-/** Unknown color space */
+-#define MMAL_COLOR_SPACE_UNKNOWN 0
+-/** ITU-R BT.601-5 [SDTV] */
+-#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1')
+-/** ITU-R BT.709-3 [HDTV] */
+-#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9')
+-/** JPEG JFIF */
+-#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I')
+-/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
+-#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C')
+-/** Society of Motion Picture and Television Engineers 240M (1999) */
+-#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0')
+-/** ITU-R BT.470-2 System M */
+-#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M')
+-/** ITU-R BT.470-2 System BG */
+-#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G')
+-/** JPEG JFIF, but with 16..255 luma */
+-#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6')
+-/* @} MmalColorSpace List */
+-
+-#endif /* MMAL_ENCODINGS_H */
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h
++++ /dev/null
+@@ -1,48 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Broadcom BM2835 V4L2 driver
+- *
+- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+- *
+- * Authors: Vincent Sanders @ Collabora
+- * Dave Stevenson @ Broadcom
+- * Simon Mellor @ Broadcom
+- * Luke Diamand @ Broadcom
+- */
+-
+-#ifndef MMAL_MSG_COMMON_H
+-#define MMAL_MSG_COMMON_H
+-
+-enum mmal_msg_status {
+- MMAL_MSG_STATUS_SUCCESS = 0, /**< Success */
+- MMAL_MSG_STATUS_ENOMEM, /**< Out of memory */
+- MMAL_MSG_STATUS_ENOSPC, /**< Out of resources other than memory */
+- MMAL_MSG_STATUS_EINVAL, /**< Argument is invalid */
+- MMAL_MSG_STATUS_ENOSYS, /**< Function not implemented */
+- MMAL_MSG_STATUS_ENOENT, /**< No such file or directory */
+- MMAL_MSG_STATUS_ENXIO, /**< No such device or address */
+- MMAL_MSG_STATUS_EIO, /**< I/O error */
+- MMAL_MSG_STATUS_ESPIPE, /**< Illegal seek */
+- MMAL_MSG_STATUS_ECORRUPT, /**< Data is corrupt \attention */
+- MMAL_MSG_STATUS_ENOTREADY, /**< Component is not ready */
+- MMAL_MSG_STATUS_ECONFIG, /**< Component is not configured */
+- MMAL_MSG_STATUS_EISCONN, /**< Port is already connected */
+- MMAL_MSG_STATUS_ENOTCONN, /**< Port is disconnected */
+- MMAL_MSG_STATUS_EAGAIN, /**< Resource temporarily unavailable. */
+- MMAL_MSG_STATUS_EFAULT, /**< Bad address */
+-};
+-
+-struct mmal_rect {
+- s32 x; /**< x coordinate (from left) */
+- s32 y; /**< y coordinate (from top) */
+- s32 width; /**< width */
+- s32 height; /**< height */
+-};
+-
+-struct mmal_rational {
+- s32 num; /**< Numerator */
+- s32 den; /**< Denominator */
+-};
+-
+-#endif /* MMAL_MSG_COMMON_H */
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
++++ /dev/null
+@@ -1,106 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Broadcom BM2835 V4L2 driver
+- *
+- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+- *
+- * Authors: Vincent Sanders @ Collabora
+- * Dave Stevenson @ Broadcom
+- * Simon Mellor @ Broadcom
+- * Luke Diamand @ Broadcom
+- */
+-
+-#ifndef MMAL_MSG_FORMAT_H
+-#define MMAL_MSG_FORMAT_H
+-
+-#include "mmal-msg-common.h"
+-
+-/* MMAL_ES_FORMAT_T */
+-
+-struct mmal_audio_format {
+- u32 channels; /* Number of audio channels */
+- u32 sample_rate; /* Sample rate */
+-
+- u32 bits_per_sample; /* Bits per sample */
+- u32 block_align; /* Size of a block of data */
+-};
+-
+-struct mmal_video_format {
+- u32 width; /* Width of frame in pixels */
+- u32 height; /* Height of frame in rows of pixels */
+- struct mmal_rect crop; /* Visible region of the frame */
+- struct mmal_rational frame_rate; /* Frame rate */
+- struct mmal_rational par; /* Pixel aspect ratio */
+-
+- /*
+- * FourCC specifying the color space of the video stream. See the
+- * MmalColorSpace "pre-defined color spaces" for some examples.
+- */
+- u32 color_space;
+-};
+-
+-struct mmal_subpicture_format {
+- u32 x_offset;
+- u32 y_offset;
+-};
+-
+-union mmal_es_specific_format {
+- struct mmal_audio_format audio;
+- struct mmal_video_format video;
+- struct mmal_subpicture_format subpicture;
+-};
+-
+-/* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
+-struct mmal_es_format_local {
+- u32 type; /* enum mmal_es_type */
+-
+- u32 encoding; /* FourCC specifying encoding of the elementary
+- * stream.
+- */
+- u32 encoding_variant; /* FourCC specifying the specific
+- * encoding variant of the elementary
+- * stream.
+- */
+-
+- union mmal_es_specific_format *es; /* Type specific
+- * information for the
+- * elementary stream
+- */
+-
+- u32 bitrate; /* Bitrate in bits per second */
+- u32 flags; /* Flags describing properties of the elementary
+- * stream.
+- */
+-
+- u32 extradata_size; /* Size of the codec specific data */
+- u8 *extradata; /* Codec specific data */
+-};
+-
+-/* Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
+-struct mmal_es_format {
+- u32 type; /* enum mmal_es_type */
+-
+- u32 encoding; /* FourCC specifying encoding of the elementary
+- * stream.
+- */
+- u32 encoding_variant; /* FourCC specifying the specific
+- * encoding variant of the elementary
+- * stream.
+- */
+-
+- u32 es; /* Type specific
+- * information for the
+- * elementary stream
+- */
+-
+- u32 bitrate; /* Bitrate in bits per second */
+- u32 flags; /* Flags describing properties of the elementary
+- * stream.
+- */
+-
+- u32 extradata_size; /* Size of the codec specific data */
+- u32 extradata; /* Codec specific data */
+-};
+-
+-#endif /* MMAL_MSG_FORMAT_H */
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
++++ /dev/null
+@@ -1,109 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Broadcom BM2835 V4L2 driver
+- *
+- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+- *
+- * Authors: Vincent Sanders @ Collabora
+- * Dave Stevenson @ Broadcom
+- * Simon Mellor @ Broadcom
+- * Luke Diamand @ Broadcom
+- */
+-
+-/* MMAL_PORT_TYPE_T */
+-enum mmal_port_type {
+- MMAL_PORT_TYPE_UNKNOWN = 0, /* Unknown port type */
+- MMAL_PORT_TYPE_CONTROL, /* Control port */
+- MMAL_PORT_TYPE_INPUT, /* Input port */
+- MMAL_PORT_TYPE_OUTPUT, /* Output port */
+- MMAL_PORT_TYPE_CLOCK, /* Clock port */
+-};
+-
+-/* The port is pass-through and doesn't need buffer headers allocated */
+-#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01
+-/*
+- *The port wants to allocate the buffer payloads.
+- * This signals a preference that payload allocation should be done
+- * on this port for efficiency reasons.
+- */
+-#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02
+-/*
+- * The port supports format change events.
+- * This applies to input ports and is used to let the client know
+- * whether the port supports being reconfigured via a format
+- * change event (i.e. without having to disable the port).
+- */
+-#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04
+-
+-/*
+- * mmal port structure (MMAL_PORT_T)
+- *
+- * most elements are informational only, the pointer values for
+- * interogation messages are generally provided as additional
+- * structures within the message. When used to set values only the
+- * buffer_num, buffer_size and userdata parameters are writable.
+- */
+-struct mmal_port {
+- u32 priv; /* Private member used by the framework */
+- u32 name; /* Port name. Used for debugging purposes (RO) */
+-
+- u32 type; /* Type of the port (RO) enum mmal_port_type */
+- u16 index; /* Index of the port in its type list (RO) */
+- u16 index_all; /* Index of the port in the list of all ports (RO) */
+-
+- u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
+- u32 format; /* Format of the elementary stream */
+-
+- u32 buffer_num_min; /* Minimum number of buffers the port
+- * requires (RO). This is set by the
+- * component.
+- */
+-
+- u32 buffer_size_min; /* Minimum size of buffers the port
+- * requires (RO). This is set by the
+- * component.
+- */
+-
+- u32 buffer_alignment_min;/* Minimum alignment requirement for
+- * the buffers (RO). A value of
+- * zero means no special alignment
+- * requirements. This is set by the
+- * component.
+- */
+-
+- u32 buffer_num_recommended; /* Number of buffers the port
+- * recommends for optimal
+- * performance (RO). A value of
+- * zero means no special
+- * recommendation. This is set
+- * by the component.
+- */
+-
+- u32 buffer_size_recommended; /* Size of buffers the port
+- * recommends for optimal
+- * performance (RO). A value of
+- * zero means no special
+- * recommendation. This is set
+- * by the component.
+- */
+-
+- u32 buffer_num; /* Actual number of buffers the port will use.
+- * This is set by the client.
+- */
+-
+- u32 buffer_size; /* Actual maximum size of the buffers that
+- * will be sent to the port. This is set by
+- * the client.
+- */
+-
+- u32 component; /* Component this port belongs to (Read Only) */
+-
+- u32 userdata; /* Field reserved for use by the client */
+-
+- u32 capabilities; /* Flags describing the capabilities of a
+- * port (RO). Bitwise combination of \ref
+- * portcapabilities "Port capabilities"
+- * values.
+- */
+-};
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
++++ /dev/null
+@@ -1,406 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Broadcom BM2835 V4L2 driver
+- *
+- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+- *
+- * Authors: Vincent Sanders @ Collabora
+- * Dave Stevenson @ Broadcom
+- * Simon Mellor @ Broadcom
+- * Luke Diamand @ Broadcom
+- */
+-
+-/*
+- * all the data structures which serialise the MMAL protocol. note
+- * these are directly mapped onto the recived message data.
+- *
+- * BEWARE: They seem to *assume* pointers are u32 and that there is no
+- * structure padding!
+- *
+- * NOTE: this implementation uses kernel types to ensure sizes. Rather
+- * than assigning values to enums to force their size the
+- * implementation uses fixed size types and not the enums (though the
+- * comments have the actual enum type
+- */
+-#ifndef MMAL_MSG_H
+-#define MMAL_MSG_H
+-
+-#define VC_MMAL_VER 15
+-#define VC_MMAL_MIN_VER 10
+-#define VC_MMAL_SERVER_NAME MAKE_FOURCC("mmal")
+-
+-/* max total message size is 512 bytes */
+-#define MMAL_MSG_MAX_SIZE 512
+-/* with six 32bit header elements max payload is therefore 488 bytes */
+-#define MMAL_MSG_MAX_PAYLOAD 488
+-
+-#include "mmal-msg-common.h"
+-#include "mmal-msg-format.h"
+-#include "mmal-msg-port.h"
+-
+-enum mmal_msg_type {
+- MMAL_MSG_TYPE_QUIT = 1,
+- MMAL_MSG_TYPE_SERVICE_CLOSED,
+- MMAL_MSG_TYPE_GET_VERSION,
+- MMAL_MSG_TYPE_COMPONENT_CREATE,
+- MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
+- MMAL_MSG_TYPE_COMPONENT_ENABLE,
+- MMAL_MSG_TYPE_COMPONENT_DISABLE,
+- MMAL_MSG_TYPE_PORT_INFO_GET,
+- MMAL_MSG_TYPE_PORT_INFO_SET,
+- MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
+- MMAL_MSG_TYPE_BUFFER_FROM_HOST,
+- MMAL_MSG_TYPE_BUFFER_TO_HOST,
+- MMAL_MSG_TYPE_GET_STATS,
+- MMAL_MSG_TYPE_PORT_PARAMETER_SET,
+- MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
+- MMAL_MSG_TYPE_EVENT_TO_HOST,
+- MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT,
+- MMAL_MSG_TYPE_OPAQUE_ALLOCATOR,
+- MMAL_MSG_TYPE_CONSUME_MEM,
+- MMAL_MSG_TYPE_LMK, /* 20 */
+- MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC,
+- MMAL_MSG_TYPE_DRM_GET_LHS32,
+- MMAL_MSG_TYPE_DRM_GET_TIME,
+- MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN,
+- MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
+- MMAL_MSG_TYPE_HOST_LOG,
+- MMAL_MSG_TYPE_MSG_LAST
+-};
+-
+-/* port action request messages differ depending on the action type */
+-enum mmal_msg_port_action_type {
+- MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */
+- MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
+- MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
+- MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
+- MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
+- MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
+- MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/
+-};
+-
+-struct mmal_msg_header {
+- u32 magic;
+- u32 type; /* enum mmal_msg_type */
+-
+- /* Opaque handle to the control service */
+- u32 control_service;
+-
+- u32 context; /* a u32 per message context */
+- u32 status; /* The status of the vchiq operation */
+- u32 padding;
+-};
+-
+-/* Send from VC to host to report version */
+-struct mmal_msg_version {
+- u32 flags;
+- u32 major;
+- u32 minor;
+- u32 minimum;
+-};
+-
+-/* request to VC to create component */
+-struct mmal_msg_component_create {
+- u32 client_component; /* component context */
+- char name[128];
+- u32 pid; /* For debug */
+-};
+-
+-/* reply from VC to component creation request */
+-struct mmal_msg_component_create_reply {
+- u32 status; /* enum mmal_msg_status - how does this differ to
+- * the one in the header?
+- */
+- u32 component_handle; /* VideoCore handle for component */
+- u32 input_num; /* Number of input ports */
+- u32 output_num; /* Number of output ports */
+- u32 clock_num; /* Number of clock ports */
+-};
+-
+-/* request to VC to destroy a component */
+-struct mmal_msg_component_destroy {
+- u32 component_handle;
+-};
+-
+-struct mmal_msg_component_destroy_reply {
+- u32 status; /* The component destruction status */
+-};
+-
+-/* request and reply to VC to enable a component */
+-struct mmal_msg_component_enable {
+- u32 component_handle;
+-};
+-
+-struct mmal_msg_component_enable_reply {
+- u32 status; /* The component enable status */
+-};
+-
+-/* request and reply to VC to disable a component */
+-struct mmal_msg_component_disable {
+- u32 component_handle;
+-};
+-
+-struct mmal_msg_component_disable_reply {
+- u32 status; /* The component disable status */
+-};
+-
+-/* request to VC to get port information */
+-struct mmal_msg_port_info_get {
+- u32 component_handle; /* component handle port is associated with */
+- u32 port_type; /* enum mmal_msg_port_type */
+- u32 index; /* port index to query */
+-};
+-
+-/* reply from VC to get port info request */
+-struct mmal_msg_port_info_get_reply {
+- u32 status; /* enum mmal_msg_status */
+- u32 component_handle; /* component handle port is associated with */
+- u32 port_type; /* enum mmal_msg_port_type */
+- u32 port_index; /* port indexed in query */
+- s32 found; /* unused */
+- u32 port_handle; /* Handle to use for this port */
+- struct mmal_port port;
+- struct mmal_es_format format; /* elementary stream format */
+- union mmal_es_specific_format es; /* es type specific data */
+- u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; /* es extra data */
+-};
+-
+-/* request to VC to set port information */
+-struct mmal_msg_port_info_set {
+- u32 component_handle;
+- u32 port_type; /* enum mmal_msg_port_type */
+- u32 port_index; /* port indexed in query */
+- struct mmal_port port;
+- struct mmal_es_format format;
+- union mmal_es_specific_format es;
+- u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
+-};
+-
+-/* reply from VC to port info set request */
+-struct mmal_msg_port_info_set_reply {
+- u32 status;
+- u32 component_handle; /* component handle port is associated with */
+- u32 port_type; /* enum mmal_msg_port_type */
+- u32 index; /* port indexed in query */
+- s32 found; /* unused */
+- u32 port_handle; /* Handle to use for this port */
+- struct mmal_port port;
+- struct mmal_es_format format;
+- union mmal_es_specific_format es;
+- u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
+-};
+-
+-/* port action requests that take a mmal_port as a parameter */
+-struct mmal_msg_port_action_port {
+- u32 component_handle;
+- u32 port_handle;
+- u32 action; /* enum mmal_msg_port_action_type */
+- struct mmal_port port;
+-};
+-
+-/* port action requests that take handles as a parameter */
+-struct mmal_msg_port_action_handle {
+- u32 component_handle;
+- u32 port_handle;
+- u32 action; /* enum mmal_msg_port_action_type */
+- u32 connect_component_handle;
+- u32 connect_port_handle;
+-};
+-
+-struct mmal_msg_port_action_reply {
+- u32 status; /* The port action operation status */
+-};
+-
+-/* MMAL buffer transfer */
+-
+-/* Size of space reserved in a buffer message for short messages. */
+-#define MMAL_VC_SHORT_DATA 128
+-
+-/* Signals that the current payload is the end of the stream of data */
+-#define MMAL_BUFFER_HEADER_FLAG_EOS BIT(0)
+-/* Signals that the start of the current payload starts a frame */
+-#define MMAL_BUFFER_HEADER_FLAG_FRAME_START BIT(1)
+-/* Signals that the end of the current payload ends a frame */
+-#define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2)
+-/* Signals that the current payload contains only complete frames (>1) */
+-#define MMAL_BUFFER_HEADER_FLAG_FRAME \
+- (MMAL_BUFFER_HEADER_FLAG_FRAME_START | \
+- MMAL_BUFFER_HEADER_FLAG_FRAME_END)
+-/* Signals that the current payload is a keyframe (i.e. self decodable) */
+-#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3)
+-/*
+- * Signals a discontinuity in the stream of data (e.g. after a seek).
+- * Can be used for instance by a decoder to reset its state
+- */
+-#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY BIT(4)
+-/*
+- * Signals a buffer containing some kind of config data for the component
+- * (e.g. codec config data)
+- */
+-#define MMAL_BUFFER_HEADER_FLAG_CONFIG BIT(5)
+-/* Signals an encrypted payload */
+-#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED BIT(6)
+-/* Signals a buffer containing side information */
+-#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO BIT(7)
+-/*
+- * Signals a buffer which is the snapshot/postview image from a stills
+- * capture
+- */
+-#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT BIT(8)
+-/* Signals a buffer which contains data known to be corrupted */
+-#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED BIT(9)
+-/* Signals that a buffer failed to be transmitted */
+-#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED BIT(10)
+-
+-struct mmal_driver_buffer {
+- u32 magic;
+- u32 component_handle;
+- u32 port_handle;
+- u32 client_context;
+-};
+-
+-/* buffer header */
+-struct mmal_buffer_header {
+- u32 next; /* next header */
+- u32 priv; /* framework private data */
+- u32 cmd;
+- u32 data;
+- u32 alloc_size;
+- u32 length;
+- u32 offset;
+- u32 flags;
+- s64 pts;
+- s64 dts;
+- u32 type;
+- u32 user_data;
+-};
+-
+-struct mmal_buffer_header_type_specific {
+- union {
+- struct {
+- u32 planes;
+- u32 offset[4];
+- u32 pitch[4];
+- u32 flags;
+- } video;
+- } u;
+-};
+-
+-struct mmal_msg_buffer_from_host {
+- /*
+- *The front 32 bytes of the buffer header are copied
+- * back to us in the reply to allow for context. This
+- * area is used to store two mmal_driver_buffer structures to
+- * allow for multiple concurrent service users.
+- */
+- /* control data */
+- struct mmal_driver_buffer drvbuf;
+-
+- /* referenced control data for passthrough buffer management */
+- struct mmal_driver_buffer drvbuf_ref;
+- struct mmal_buffer_header buffer_header; /* buffer header itself */
+- struct mmal_buffer_header_type_specific buffer_header_type_specific;
+- s32 is_zero_copy;
+- s32 has_reference;
+-
+- /* allows short data to be xfered in control message */
+- u32 payload_in_message;
+- u8 short_data[MMAL_VC_SHORT_DATA];
+-};
+-
+-/* port parameter setting */
+-
+-#define MMAL_WORKER_PORT_PARAMETER_SPACE 96
+-
+-struct mmal_msg_port_parameter_set {
+- u32 component_handle; /* component */
+- u32 port_handle; /* port */
+- u32 id; /* Parameter ID */
+- u32 size; /* Parameter size */
+- uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
+-};
+-
+-struct mmal_msg_port_parameter_set_reply {
+- u32 status; /* enum mmal_msg_status todo: how does this
+- * differ to the one in the header?
+- */
+-};
+-
+-/* port parameter getting */
+-
+-struct mmal_msg_port_parameter_get {
+- u32 component_handle; /* component */
+- u32 port_handle; /* port */
+- u32 id; /* Parameter ID */
+- u32 size; /* Parameter size */
+-};
+-
+-struct mmal_msg_port_parameter_get_reply {
+- u32 status; /* Status of mmal_port_parameter_get call */
+- u32 id; /* Parameter ID */
+- u32 size; /* Parameter size */
+- uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
+-};
+-
+-/* event messages */
+-#define MMAL_WORKER_EVENT_SPACE 256
+-
+-struct mmal_msg_event_to_host {
+- u32 client_component; /* component context */
+-
+- u32 port_type;
+- u32 port_num;
+-
+- u32 cmd;
+- u32 length;
+- u8 data[MMAL_WORKER_EVENT_SPACE];
+- u32 delayed_buffer;
+-};
+-
+-/* all mmal messages are serialised through this structure */
+-struct mmal_msg {
+- /* header */
+- struct mmal_msg_header h;
+- /* payload */
+- union {
+- struct mmal_msg_version version;
+-
+- struct mmal_msg_component_create component_create;
+- struct mmal_msg_component_create_reply component_create_reply;
+-
+- struct mmal_msg_component_destroy component_destroy;
+- struct mmal_msg_component_destroy_reply component_destroy_reply;
+-
+- struct mmal_msg_component_enable component_enable;
+- struct mmal_msg_component_enable_reply component_enable_reply;
+-
+- struct mmal_msg_component_disable component_disable;
+- struct mmal_msg_component_disable_reply component_disable_reply;
+-
+- struct mmal_msg_port_info_get port_info_get;
+- struct mmal_msg_port_info_get_reply port_info_get_reply;
+-
+- struct mmal_msg_port_info_set port_info_set;
+- struct mmal_msg_port_info_set_reply port_info_set_reply;
+-
+- struct mmal_msg_port_action_port port_action_port;
+- struct mmal_msg_port_action_handle port_action_handle;
+- struct mmal_msg_port_action_reply port_action_reply;
+-
+- struct mmal_msg_buffer_from_host buffer_from_host;
+-
+- struct mmal_msg_port_parameter_set port_parameter_set;
+- struct mmal_msg_port_parameter_set_reply
+- port_parameter_set_reply;
+- struct mmal_msg_port_parameter_get
+- port_parameter_get;
+- struct mmal_msg_port_parameter_get_reply
+- port_parameter_get_reply;
+-
+- struct mmal_msg_event_to_host event_to_host;
+-
+- u8 payload[MMAL_MSG_MAX_PAYLOAD];
+- } u;
+-};
+-#endif
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
++++ /dev/null
+@@ -1,755 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Broadcom BM2835 V4L2 driver
+- *
+- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+- *
+- * Authors: Vincent Sanders @ Collabora
+- * Dave Stevenson @ Broadcom
+- * Simon Mellor @ Broadcom
+- * Luke Diamand @ Broadcom
+- */
+-
+-/* common parameters */
+-
+-/** @name Parameter groups
+- * Parameters are divided into groups, and then allocated sequentially within
+- * a group using an enum.
+- * @{
+- */
+-
+-#ifndef MMAL_PARAMETERS_H
+-#define MMAL_PARAMETERS_H
+-
+-/** Common parameter ID group, used with many types of component. */
+-#define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
+-/** Camera-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16)
+-/** Video-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16)
+-/** Audio-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16)
+-/** Clock-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16)
+-/** Miracast-specific parameter ID group. */
+-#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16)
+-
+-/* Common parameters */
+-enum mmal_parameter_common_type {
+- /**< Never a valid parameter ID */
+- MMAL_PARAMETER_UNUSED = MMAL_PARAMETER_GROUP_COMMON,
+-
+- /**< MMAL_PARAMETER_ENCODING_T */
+- MMAL_PARAMETER_SUPPORTED_ENCODINGS,
+- /**< MMAL_PARAMETER_URI_T */
+- MMAL_PARAMETER_URI,
+- /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
+- MMAL_PARAMETER_CHANGE_EVENT_REQUEST,
+- /** MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_ZERO_COPY,
+- /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
+- MMAL_PARAMETER_BUFFER_REQUIREMENTS,
+- /**< MMAL_PARAMETER_STATISTICS_T */
+- MMAL_PARAMETER_STATISTICS,
+- /**< MMAL_PARAMETER_CORE_STATISTICS_T */
+- MMAL_PARAMETER_CORE_STATISTICS,
+- /**< MMAL_PARAMETER_MEM_USAGE_T */
+- MMAL_PARAMETER_MEM_USAGE,
+- /**< MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_BUFFER_FLAG_FILTER,
+- /**< MMAL_PARAMETER_SEEK_T */
+- MMAL_PARAMETER_SEEK,
+- /**< MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_POWERMON_ENABLE,
+- /**< MMAL_PARAMETER_LOGGING_T */
+- MMAL_PARAMETER_LOGGING,
+- /**< MMAL_PARAMETER_UINT64_T */
+- MMAL_PARAMETER_SYSTEM_TIME,
+- /**< MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_NO_IMAGE_PADDING,
+-};
+-
+-/* camera parameters */
+-
+-enum mmal_parameter_camera_type {
+- /* 0 */
+- /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
+- MMAL_PARAMETER_THUMBNAIL_CONFIGURATION =
+- MMAL_PARAMETER_GROUP_CAMERA,
+- /**< Unused? */
+- MMAL_PARAMETER_CAPTURE_QUALITY,
+- /**< @ref MMAL_PARAMETER_INT32_T */
+- MMAL_PARAMETER_ROTATION,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_EXIF_DISABLE,
+- /**< @ref MMAL_PARAMETER_EXIF_T */
+- MMAL_PARAMETER_EXIF,
+- /**< @ref MMAL_PARAM_AWBMODE_T */
+- MMAL_PARAMETER_AWB_MODE,
+- /**< @ref MMAL_PARAMETER_IMAGEFX_T */
+- MMAL_PARAMETER_IMAGE_EFFECT,
+- /**< @ref MMAL_PARAMETER_COLOURFX_T */
+- MMAL_PARAMETER_COLOUR_EFFECT,
+- /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
+- MMAL_PARAMETER_FLICKER_AVOID,
+- /**< @ref MMAL_PARAMETER_FLASH_T */
+- MMAL_PARAMETER_FLASH,
+- /**< @ref MMAL_PARAMETER_REDEYE_T */
+- MMAL_PARAMETER_REDEYE,
+- /**< @ref MMAL_PARAMETER_FOCUS_T */
+- MMAL_PARAMETER_FOCUS,
+- /**< Unused? */
+- MMAL_PARAMETER_FOCAL_LENGTHS,
+- /**< @ref MMAL_PARAMETER_INT32_T */
+- MMAL_PARAMETER_EXPOSURE_COMP,
+- /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
+- MMAL_PARAMETER_ZOOM,
+- /**< @ref MMAL_PARAMETER_MIRROR_T */
+- MMAL_PARAMETER_MIRROR,
+-
+- /* 0x10 */
+- /**< @ref MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_CAMERA_NUM,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_CAPTURE,
+- /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
+- MMAL_PARAMETER_EXPOSURE_MODE,
+- /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
+- MMAL_PARAMETER_EXP_METERING_MODE,
+- /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
+- MMAL_PARAMETER_FOCUS_STATUS,
+- /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
+- MMAL_PARAMETER_CAMERA_CONFIG,
+- /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
+- MMAL_PARAMETER_CAPTURE_STATUS,
+- /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
+- MMAL_PARAMETER_FACE_TRACK,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS,
+- /**< @ref MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_JPEG_Q_FACTOR,
+- /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
+- MMAL_PARAMETER_FRAME_RATE,
+- /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
+- MMAL_PARAMETER_USE_STC,
+- /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
+- MMAL_PARAMETER_CAMERA_INFO,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_VIDEO_STABILISATION,
+- /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
+- MMAL_PARAMETER_FACE_TRACK_RESULTS,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_ENABLE_RAW_CAPTURE,
+-
+- /* 0x20 */
+- /**< @ref MMAL_PARAMETER_URI_T */
+- MMAL_PARAMETER_DPF_FILE,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_ENABLE_DPF_FILE,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_DPF_FAIL_IS_FATAL,
+- /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
+- MMAL_PARAMETER_CAPTURE_MODE,
+- /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
+- MMAL_PARAMETER_FOCUS_REGIONS,
+- /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
+- MMAL_PARAMETER_INPUT_CROP,
+- /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
+- MMAL_PARAMETER_SENSOR_INFORMATION,
+- /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
+- MMAL_PARAMETER_FLASH_SELECT,
+- /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
+- MMAL_PARAMETER_FIELD_OF_VIEW,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,
+- /**< @ref MMAL_PARAMETER_DRC_T */
+- MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION,
+- /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
+- MMAL_PARAMETER_ALGORITHM_CONTROL,
+- /**< @ref MMAL_PARAMETER_RATIONAL_T */
+- MMAL_PARAMETER_SHARPNESS,
+- /**< @ref MMAL_PARAMETER_RATIONAL_T */
+- MMAL_PARAMETER_CONTRAST,
+- /**< @ref MMAL_PARAMETER_RATIONAL_T */
+- MMAL_PARAMETER_BRIGHTNESS,
+- /**< @ref MMAL_PARAMETER_RATIONAL_T */
+- MMAL_PARAMETER_SATURATION,
+-
+- /* 0x30 */
+- /**< @ref MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_ISO,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_ANTISHAKE,
+- /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
+- MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
+- /** @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
+- /** @ref MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_CAMERA_MIN_ISO,
+- /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
+- MMAL_PARAMETER_CAMERA_USE_CASE,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_CAPTURE_STATS_PASS,
+- /** @ref MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG,
+- /** @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_ENABLE_REGISTER_FILE,
+- /** @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
+- /** @ref MMAL_PARAMETER_CONFIGFILE_T */
+- MMAL_PARAMETER_CONFIGFILE_REGISTERS,
+- /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
+- MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_JPEG_ATTACH_LOG,
+- /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
+- MMAL_PARAMETER_ZERO_SHUTTER_LAG,
+- /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
+- MMAL_PARAMETER_FPS_RANGE,
+- /**< @ref MMAL_PARAMETER_INT32_T */
+- MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP,
+-
+- /* 0x40 */
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_SW_SHARPEN_DISABLE,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_FLASH_REQUIRED,
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_SW_SATURATION_DISABLE,
+- /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_SHUTTER_SPEED,
+- /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
+- MMAL_PARAMETER_CUSTOM_AWB_GAINS,
+-};
+-
+-struct mmal_parameter_rational {
+- s32 num; /**< Numerator */
+- s32 den; /**< Denominator */
+-};
+-
+-enum mmal_parameter_camera_config_timestamp_mode {
+- MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */
+- MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value
+- * for the frame timestamp
+- */
+- MMAL_PARAM_TIMESTAMP_MODE_RESET_STC, /* Use the STC timestamp
+- * but subtract the
+- * timestamp of the first
+- * frame sent to give a
+- * zero based timestamp.
+- */
+-};
+-
+-struct mmal_parameter_fps_range {
+- /**< Low end of the permitted framerate range */
+- struct mmal_parameter_rational fps_low;
+- /**< High end of the permitted framerate range */
+- struct mmal_parameter_rational fps_high;
+-};
+-
+-/* camera configuration parameter */
+-struct mmal_parameter_camera_config {
+- /* Parameters for setting up the image pools */
+- u32 max_stills_w; /* Max size of stills capture */
+- u32 max_stills_h;
+- u32 stills_yuv422; /* Allow YUV422 stills capture */
+- u32 one_shot_stills; /* Continuous or one shot stills captures. */
+-
+- u32 max_preview_video_w; /* Max size of the preview or video
+- * capture frames
+- */
+- u32 max_preview_video_h;
+- u32 num_preview_video_frames;
+-
+- /** Sets the height of the circular buffer for stills capture. */
+- u32 stills_capture_circular_buffer_height;
+-
+- /** Allows preview/encode to resume as fast as possible after the stills
+- * input frame has been received, and then processes the still frame in
+- * the background whilst preview/encode has resumed.
+- * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE.
+- */
+- u32 fast_preview_resume;
+-
+- /** Selects algorithm for timestamping frames if
+- * there is no clock component connected.
+- * enum mmal_parameter_camera_config_timestamp_mode
+- */
+- s32 use_stc_timestamp;
+-};
+-
+-enum mmal_parameter_exposuremode {
+- MMAL_PARAM_EXPOSUREMODE_OFF,
+- MMAL_PARAM_EXPOSUREMODE_AUTO,
+- MMAL_PARAM_EXPOSUREMODE_NIGHT,
+- MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,
+- MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,
+- MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,
+- MMAL_PARAM_EXPOSUREMODE_SPORTS,
+- MMAL_PARAM_EXPOSUREMODE_SNOW,
+- MMAL_PARAM_EXPOSUREMODE_BEACH,
+- MMAL_PARAM_EXPOSUREMODE_VERYLONG,
+- MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,
+- MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,
+- MMAL_PARAM_EXPOSUREMODE_FIREWORKS,
+-};
+-
+-enum mmal_parameter_exposuremeteringmode {
+- MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE,
+- MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT,
+- MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT,
+- MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX,
+-};
+-
+-enum mmal_parameter_awbmode {
+- MMAL_PARAM_AWBMODE_OFF,
+- MMAL_PARAM_AWBMODE_AUTO,
+- MMAL_PARAM_AWBMODE_SUNLIGHT,
+- MMAL_PARAM_AWBMODE_CLOUDY,
+- MMAL_PARAM_AWBMODE_SHADE,
+- MMAL_PARAM_AWBMODE_TUNGSTEN,
+- MMAL_PARAM_AWBMODE_FLUORESCENT,
+- MMAL_PARAM_AWBMODE_INCANDESCENT,
+- MMAL_PARAM_AWBMODE_FLASH,
+- MMAL_PARAM_AWBMODE_HORIZON,
+-};
+-
+-enum mmal_parameter_imagefx {
+- MMAL_PARAM_IMAGEFX_NONE,
+- MMAL_PARAM_IMAGEFX_NEGATIVE,
+- MMAL_PARAM_IMAGEFX_SOLARIZE,
+- MMAL_PARAM_IMAGEFX_POSTERIZE,
+- MMAL_PARAM_IMAGEFX_WHITEBOARD,
+- MMAL_PARAM_IMAGEFX_BLACKBOARD,
+- MMAL_PARAM_IMAGEFX_SKETCH,
+- MMAL_PARAM_IMAGEFX_DENOISE,
+- MMAL_PARAM_IMAGEFX_EMBOSS,
+- MMAL_PARAM_IMAGEFX_OILPAINT,
+- MMAL_PARAM_IMAGEFX_HATCH,
+- MMAL_PARAM_IMAGEFX_GPEN,
+- MMAL_PARAM_IMAGEFX_PASTEL,
+- MMAL_PARAM_IMAGEFX_WATERCOLOUR,
+- MMAL_PARAM_IMAGEFX_FILM,
+- MMAL_PARAM_IMAGEFX_BLUR,
+- MMAL_PARAM_IMAGEFX_SATURATION,
+- MMAL_PARAM_IMAGEFX_COLOURSWAP,
+- MMAL_PARAM_IMAGEFX_WASHEDOUT,
+- MMAL_PARAM_IMAGEFX_POSTERISE,
+- MMAL_PARAM_IMAGEFX_COLOURPOINT,
+- MMAL_PARAM_IMAGEFX_COLOURBALANCE,
+- MMAL_PARAM_IMAGEFX_CARTOON,
+-};
+-
+-enum MMAL_PARAM_FLICKERAVOID_T {
+- MMAL_PARAM_FLICKERAVOID_OFF,
+- MMAL_PARAM_FLICKERAVOID_AUTO,
+- MMAL_PARAM_FLICKERAVOID_50HZ,
+- MMAL_PARAM_FLICKERAVOID_60HZ,
+- MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF
+-};
+-
+-struct mmal_parameter_awbgains {
+- struct mmal_parameter_rational r_gain; /**< Red gain */
+- struct mmal_parameter_rational b_gain; /**< Blue gain */
+-};
+-
+-/** Manner of video rate control */
+-enum mmal_parameter_rate_control_mode {
+- MMAL_VIDEO_RATECONTROL_DEFAULT,
+- MMAL_VIDEO_RATECONTROL_VARIABLE,
+- MMAL_VIDEO_RATECONTROL_CONSTANT,
+- MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES,
+- MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES
+-};
+-
+-enum mmal_video_profile {
+- MMAL_VIDEO_PROFILE_H263_BASELINE,
+- MMAL_VIDEO_PROFILE_H263_H320CODING,
+- MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE,
+- MMAL_VIDEO_PROFILE_H263_ISWV2,
+- MMAL_VIDEO_PROFILE_H263_ISWV3,
+- MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION,
+- MMAL_VIDEO_PROFILE_H263_INTERNET,
+- MMAL_VIDEO_PROFILE_H263_INTERLACE,
+- MMAL_VIDEO_PROFILE_H263_HIGHLATENCY,
+- MMAL_VIDEO_PROFILE_MP4V_SIMPLE,
+- MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE,
+- MMAL_VIDEO_PROFILE_MP4V_CORE,
+- MMAL_VIDEO_PROFILE_MP4V_MAIN,
+- MMAL_VIDEO_PROFILE_MP4V_NBIT,
+- MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE,
+- MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE,
+- MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA,
+- MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED,
+- MMAL_VIDEO_PROFILE_MP4V_HYBRID,
+- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME,
+- MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE,
+- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING,
+- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE,
+- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE,
+- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE,
+- MMAL_VIDEO_PROFILE_H264_BASELINE,
+- MMAL_VIDEO_PROFILE_H264_MAIN,
+- MMAL_VIDEO_PROFILE_H264_EXTENDED,
+- MMAL_VIDEO_PROFILE_H264_HIGH,
+- MMAL_VIDEO_PROFILE_H264_HIGH10,
+- MMAL_VIDEO_PROFILE_H264_HIGH422,
+- MMAL_VIDEO_PROFILE_H264_HIGH444,
+- MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE,
+- MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF
+-};
+-
+-enum mmal_video_level {
+- MMAL_VIDEO_LEVEL_H263_10,
+- MMAL_VIDEO_LEVEL_H263_20,
+- MMAL_VIDEO_LEVEL_H263_30,
+- MMAL_VIDEO_LEVEL_H263_40,
+- MMAL_VIDEO_LEVEL_H263_45,
+- MMAL_VIDEO_LEVEL_H263_50,
+- MMAL_VIDEO_LEVEL_H263_60,
+- MMAL_VIDEO_LEVEL_H263_70,
+- MMAL_VIDEO_LEVEL_MP4V_0,
+- MMAL_VIDEO_LEVEL_MP4V_0b,
+- MMAL_VIDEO_LEVEL_MP4V_1,
+- MMAL_VIDEO_LEVEL_MP4V_2,
+- MMAL_VIDEO_LEVEL_MP4V_3,
+- MMAL_VIDEO_LEVEL_MP4V_4,
+- MMAL_VIDEO_LEVEL_MP4V_4a,
+- MMAL_VIDEO_LEVEL_MP4V_5,
+- MMAL_VIDEO_LEVEL_MP4V_6,
+- MMAL_VIDEO_LEVEL_H264_1,
+- MMAL_VIDEO_LEVEL_H264_1b,
+- MMAL_VIDEO_LEVEL_H264_11,
+- MMAL_VIDEO_LEVEL_H264_12,
+- MMAL_VIDEO_LEVEL_H264_13,
+- MMAL_VIDEO_LEVEL_H264_2,
+- MMAL_VIDEO_LEVEL_H264_21,
+- MMAL_VIDEO_LEVEL_H264_22,
+- MMAL_VIDEO_LEVEL_H264_3,
+- MMAL_VIDEO_LEVEL_H264_31,
+- MMAL_VIDEO_LEVEL_H264_32,
+- MMAL_VIDEO_LEVEL_H264_4,
+- MMAL_VIDEO_LEVEL_H264_41,
+- MMAL_VIDEO_LEVEL_H264_42,
+- MMAL_VIDEO_LEVEL_H264_5,
+- MMAL_VIDEO_LEVEL_H264_51,
+- MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF
+-};
+-
+-struct mmal_parameter_video_profile {
+- enum mmal_video_profile profile;
+- enum mmal_video_level level;
+-};
+-
+-/* video parameters */
+-
+-enum mmal_parameter_video_type {
+- /** @ref MMAL_DISPLAYREGION_T */
+- MMAL_PARAMETER_DISPLAYREGION = MMAL_PARAMETER_GROUP_VIDEO,
+-
+- /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
+- MMAL_PARAMETER_SUPPORTED_PROFILES,
+-
+- /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
+- MMAL_PARAMETER_PROFILE,
+-
+- /** @ref MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_INTRAPERIOD,
+-
+- /** @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */
+- MMAL_PARAMETER_RATECONTROL,
+-
+- /** @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */
+- MMAL_PARAMETER_NALUNITFORMAT,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
+-
+- /** @ref MMAL_PARAMETER_UINT32_T.
+- * Setting the value to zero resets to the default (one slice per
+- * frame).
+- */
+- MMAL_PARAMETER_MB_ROWS_PER_SLICE,
+-
+- /** @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */
+- MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION,
+-
+- /** @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */
+- MMAL_PARAMETER_VIDEO_EEDE_ENABLE,
+-
+- /** @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */
+- MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T. Request an I-frame. */
+- MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
+- /** @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */
+- MMAL_PARAMETER_VIDEO_INTRA_REFRESH,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T. */
+- MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
+-
+- /** @ref MMAL_PARAMETER_UINT32_T. Run-time bit rate control */
+- MMAL_PARAMETER_VIDEO_BIT_RATE,
+-
+- /** @ref MMAL_PARAMETER_FRAME_RATE_T */
+- MMAL_PARAMETER_VIDEO_FRAME_RATE,
+-
+- /** @ref MMAL_PARAMETER_UINT32_T. */
+- MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT,
+-
+- /** @ref MMAL_PARAMETER_UINT32_T. */
+- MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT,
+-
+- /** @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */
+- MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL,
+-
+- MMAL_PARAMETER_EXTRA_BUFFERS, /**< @ref MMAL_PARAMETER_UINT32_T. */
+- /** @ref MMAL_PARAMETER_UINT32_T.
+- * Changing this parameter from the default can reduce frame rate
+- * because image buffers need to be re-pitched.
+- */
+- MMAL_PARAMETER_VIDEO_ALIGN_HORIZ,
+-
+- /** @ref MMAL_PARAMETER_UINT32_T.
+- * Changing this parameter from the default can reduce frame rate
+- * because image buffers need to be re-pitched.
+- */
+- MMAL_PARAMETER_VIDEO_ALIGN_VERT,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T. */
+- MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES,
+-
+- /** @ref MMAL_PARAMETER_UINT32_T. */
+- MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT,
+-
+- /**< @ref MMAL_PARAMETER_UINT32_T. */
+- MMAL_PARAMETER_VIDEO_ENCODE_QP_P,
+-
+- /**< @ref MMAL_PARAMETER_UINT32_T. */
+- MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT,
+-
+- /** @ref MMAL_PARAMETER_UINT32_T */
+- MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS,
+-
+- /** @ref MMAL_PARAMETER_UINT32_T. */
+- MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE,
+-
+- /* H264 specific parameters */
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T. */
+- MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T. */
+- MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T. */
+- MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS,
+-
+- /** @ref MMAL_PARAMETER_UINT32_T. */
+- MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC,
+-
+- /** @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */
+- MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP,
+-
+- /** @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */
+- MMAL_PARAMETER_VIDEO_DRM_INIT_INFO,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO,
+-
+- /** @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT,
+-
+- /** @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */
+- MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER,
+-
+- /** @ref MMAL_PARAMETER_BYTES_T */
+- MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3,
+-
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS,
+-
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG,
+-
+- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER
+-};
+-
+-/** Valid mirror modes */
+-enum mmal_parameter_mirror {
+- MMAL_PARAM_MIRROR_NONE,
+- MMAL_PARAM_MIRROR_VERTICAL,
+- MMAL_PARAM_MIRROR_HORIZONTAL,
+- MMAL_PARAM_MIRROR_BOTH,
+-};
+-
+-enum mmal_parameter_displaytransform {
+- MMAL_DISPLAY_ROT0 = 0,
+- MMAL_DISPLAY_MIRROR_ROT0 = 1,
+- MMAL_DISPLAY_MIRROR_ROT180 = 2,
+- MMAL_DISPLAY_ROT180 = 3,
+- MMAL_DISPLAY_MIRROR_ROT90 = 4,
+- MMAL_DISPLAY_ROT270 = 5,
+- MMAL_DISPLAY_ROT90 = 6,
+- MMAL_DISPLAY_MIRROR_ROT270 = 7,
+-};
+-
+-enum mmal_parameter_displaymode {
+- MMAL_DISPLAY_MODE_FILL = 0,
+- MMAL_DISPLAY_MODE_LETTERBOX = 1,
+-};
+-
+-enum mmal_parameter_displayset {
+- MMAL_DISPLAY_SET_NONE = 0,
+- MMAL_DISPLAY_SET_NUM = 1,
+- MMAL_DISPLAY_SET_FULLSCREEN = 2,
+- MMAL_DISPLAY_SET_TRANSFORM = 4,
+- MMAL_DISPLAY_SET_DEST_RECT = 8,
+- MMAL_DISPLAY_SET_SRC_RECT = 0x10,
+- MMAL_DISPLAY_SET_MODE = 0x20,
+- MMAL_DISPLAY_SET_PIXEL = 0x40,
+- MMAL_DISPLAY_SET_NOASPECT = 0x80,
+- MMAL_DISPLAY_SET_LAYER = 0x100,
+- MMAL_DISPLAY_SET_COPYPROTECT = 0x200,
+- MMAL_DISPLAY_SET_ALPHA = 0x400,
+-};
+-
+-/* rectangle, used lots so it gets its own struct */
+-struct vchiq_mmal_rect {
+- s32 x;
+- s32 y;
+- s32 width;
+- s32 height;
+-};
+-
+-struct mmal_parameter_displayregion {
+- /** Bitfield that indicates which fields are set and should be
+- * used. All other fields will maintain their current value.
+- * \ref MMAL_DISPLAYSET_T defines the bits that can be
+- * combined.
+- */
+- u32 set;
+-
+- /** Describes the display output device, with 0 typically
+- * being a directly connected LCD display. The actual values
+- * will depend on the hardware. Code using hard-wired numbers
+- * (e.g. 2) is certain to fail.
+- */
+-
+- u32 display_num;
+- /** Indicates that we are using the full device screen area,
+- * rather than a window of the display. If zero, then
+- * dest_rect is used to specify a region of the display to
+- * use.
+- */
+-
+- s32 fullscreen;
+- /** Indicates any rotation or flipping used to map frames onto
+- * the natural display orientation.
+- */
+- u32 transform; /* enum mmal_parameter_displaytransform */
+-
+- /** Where to display the frame within the screen, if
+- * fullscreen is zero.
+- */
+- struct vchiq_mmal_rect dest_rect;
+-
+- /** Indicates which area of the frame to display. If all
+- * values are zero, the whole frame will be used.
+- */
+- struct vchiq_mmal_rect src_rect;
+-
+- /** If set to non-zero, indicates that any display scaling
+- * should disregard the aspect ratio of the frame region being
+- * displayed.
+- */
+- s32 noaspect;
+-
+- /** Indicates how the image should be scaled to fit the
+- * display. \code MMAL_DISPLAY_MODE_FILL \endcode indicates
+- * that the image should fill the screen by potentially
+- * cropping the frames. Setting \code mode \endcode to \code
+- * MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the
+- * source region should be displayed and black bars added if
+- * necessary.
+- */
+- u32 mode; /* enum mmal_parameter_displaymode */
+-
+- /** If non-zero, defines the width of a source pixel relative
+- * to \code pixel_y \endcode. If zero, then pixels default to
+- * being square.
+- */
+- u32 pixel_x;
+-
+- /** If non-zero, defines the height of a source pixel relative
+- * to \code pixel_x \endcode. If zero, then pixels default to
+- * being square.
+- */
+- u32 pixel_y;
+-
+- /** Sets the relative depth of the images, with greater values
+- * being in front of smaller values.
+- */
+- u32 layer;
+-
+- /** Set to non-zero to ensure copy protection is used on
+- * output.
+- */
+- s32 copyprotect_required;
+-
+- /** Level of opacity of the layer, where zero is fully
+- * transparent and 255 is fully opaque.
+- */
+- u32 alpha;
+-};
+-
+-#define MMAL_MAX_IMAGEFX_PARAMETERS 5
+-
+-struct mmal_parameter_imagefx_parameters {
+- enum mmal_parameter_imagefx effect;
+- u32 num_effect_params;
+- u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS];
+-};
+-
+-#define MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS 4
+-#define MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES 2
+-#define MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN 16
+-
+-struct mmal_parameter_camera_info_camera_t {
+- u32 port_id;
+- u32 max_width;
+- u32 max_height;
+- u32 lens_present;
+- u8 camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN];
+-};
+-
+-enum mmal_parameter_camera_info_flash_type_t {
+- /* Make values explicit to ensure they match values in config ini */
+- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON = 0,
+- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED = 1,
+- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER = 2,
+- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_MAX = 0x7FFFFFFF
+-};
+-
+-struct mmal_parameter_camera_info_flash_t {
+- enum mmal_parameter_camera_info_flash_type_t flash_type;
+-};
+-
+-struct mmal_parameter_camera_info_t {
+- u32 num_cameras;
+- u32 num_flashes;
+- struct mmal_parameter_camera_info_camera_t
+- cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS];
+- struct mmal_parameter_camera_info_flash_t
+- flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES];
+-};
+-
+-#endif
+--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
++++ /dev/null
+@@ -1,166 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Broadcom BM2835 V4L2 driver
+- *
+- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+- *
+- * Authors: Vincent Sanders @ Collabora
+- * Dave Stevenson @ Broadcom
+- * Simon Mellor @ Broadcom
+- * Luke Diamand @ Broadcom
+- *
+- * MMAL interface to VCHIQ message passing
+- */
+-
+-#ifndef MMAL_VCHIQ_H
+-#define MMAL_VCHIQ_H
+-
+-#include "mmal-msg-format.h"
+-
+-#define MAX_PORT_COUNT 4
+-
+-/* Maximum size of the format extradata. */
+-#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128
+-
+-struct vchiq_mmal_instance;
+-
+-enum vchiq_mmal_es_type {
+- MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */
+- MMAL_ES_TYPE_CONTROL, /**< Elementary stream of control commands */
+- MMAL_ES_TYPE_AUDIO, /**< Audio elementary stream */
+- MMAL_ES_TYPE_VIDEO, /**< Video elementary stream */
+- MMAL_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream */
+-};
+-
+-struct vchiq_mmal_port_buffer {
+- unsigned int num; /* number of buffers */
+- u32 size; /* size of buffers */
+- u32 alignment; /* alignment of buffers */
+-};
+-
+-struct vchiq_mmal_port;
+-
+-typedef void (*vchiq_mmal_buffer_cb)(
+- struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- int status, struct mmal_buffer *buffer,
+- unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
+-
+-struct vchiq_mmal_port {
+- bool enabled;
+- u32 handle;
+- u32 type; /* port type, cached to use on port info set */
+- u32 index; /* port index, cached to use on port info set */
+-
+- /* component port belongs to, allows simple deref */
+- struct vchiq_mmal_component *component;
+-
+- struct vchiq_mmal_port *connected; /* port conencted to */
+-
+- /* buffer info */
+- struct vchiq_mmal_port_buffer minimum_buffer;
+- struct vchiq_mmal_port_buffer recommended_buffer;
+- struct vchiq_mmal_port_buffer current_buffer;
+-
+- /* stream format */
+- struct mmal_es_format_local format;
+- /* elementary stream format */
+- union mmal_es_specific_format es;
+-
+- /* data buffers to fill */
+- struct list_head buffers;
+- /* lock to serialise adding and removing buffers from list */
+- spinlock_t slock;
+-
+- /* Count of buffers the VPU has yet to return */
+- atomic_t buffers_with_vpu;
+- /* callback on buffer completion */
+- vchiq_mmal_buffer_cb buffer_cb;
+- /* callback context */
+- void *cb_ctx;
+-};
+-
+-struct vchiq_mmal_component {
+- bool enabled;
+- u32 handle; /* VideoCore handle for component */
+- u32 inputs; /* Number of input ports */
+- u32 outputs; /* Number of output ports */
+- u32 clocks; /* Number of clock ports */
+- struct vchiq_mmal_port control; /* control port */
+- struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */
+- struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */
+- struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */
+-};
+-
+-int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance);
+-int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance);
+-
+-/* Initialise a mmal component and its ports
+- *
+- */
+-int vchiq_mmal_component_init(
+- struct vchiq_mmal_instance *instance,
+- const char *name,
+- struct vchiq_mmal_component **component_out);
+-
+-int vchiq_mmal_component_finalise(
+- struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_component *component);
+-
+-int vchiq_mmal_component_enable(
+- struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_component *component);
+-
+-int vchiq_mmal_component_disable(
+- struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_component *component);
+-
+-/* enable a mmal port
+- *
+- * enables a port and if a buffer callback provided enque buffer
+- * headers as appropriate for the port.
+- */
+-int vchiq_mmal_port_enable(
+- struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- vchiq_mmal_buffer_cb buffer_cb);
+-
+-/* disable a port
+- *
+- * disable a port will dequeue any pending buffers
+- */
+-int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port);
+-
+-int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- u32 parameter,
+- void *value,
+- u32 value_size);
+-
+-int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- u32 parameter,
+- void *value,
+- u32 *value_size);
+-
+-int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port);
+-
+-int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *src,
+- struct vchiq_mmal_port *dst);
+-
+-int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
+- u32 *major_out,
+- u32 *minor_out);
+-
+-int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
+- struct vchiq_mmal_port *port,
+- struct mmal_buffer *buf);
+-
+-int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance,
+- struct mmal_buffer *buf);
+-int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf);
+-#endif /* MMAL_VCHIQ_H */
+--- /dev/null
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
+@@ -0,0 +1,61 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
++ *
++ * MMAL structures
++ *
++ */
++#ifndef MMAL_COMMON_H
++#define MMAL_COMMON_H
++
++#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
++#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l')
++
++/** Special value signalling that time is not known */
++#define MMAL_TIME_UNKNOWN BIT_ULL(63)
++
++struct mmal_msg_context;
++
++/* mapping between v4l and mmal video modes */
++struct mmal_fmt {
++ char *name;
++ u32 fourcc; /* v4l2 format id */
++ int flags; /* v4l2 flags field */
++ u32 mmal;
++ int depth;
++ u32 mmal_component; /* MMAL component index to be used to encode */
++ u32 ybbp; /* depth of first Y plane for planar formats */
++ bool remove_padding; /* Does the GPU have to remove padding,
++ * or can we do hide padding via bytesperline.
++ */
++};
++
++/* buffer for one video frame */
++struct mmal_buffer {
++ /* v4l buffer data -- must be first */
++ struct vb2_v4l2_buffer vb;
++
++ /* list of buffers available */
++ struct list_head list;
++
++ void *buffer; /* buffer pointer */
++ unsigned long buffer_size; /* size of allocated buffer */
++
++ struct mmal_msg_context *msg_context;
++};
++
++/* */
++struct mmal_colourfx {
++ s32 enable;
++ u32 u;
++ u32 v;
++};
++#endif
+--- /dev/null
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h
+@@ -0,0 +1,124 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
++ */
++#ifndef MMAL_ENCODINGS_H
++#define MMAL_ENCODINGS_H
++
++#define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4')
++#define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3')
++#define MMAL_ENCODING_MP4V MMAL_FOURCC('M', 'P', '4', 'V')
++#define MMAL_ENCODING_MP2V MMAL_FOURCC('M', 'P', '2', 'V')
++#define MMAL_ENCODING_MP1V MMAL_FOURCC('M', 'P', '1', 'V')
++#define MMAL_ENCODING_WMV3 MMAL_FOURCC('W', 'M', 'V', '3')
++#define MMAL_ENCODING_WMV2 MMAL_FOURCC('W', 'M', 'V', '2')
++#define MMAL_ENCODING_WMV1 MMAL_FOURCC('W', 'M', 'V', '1')
++#define MMAL_ENCODING_WVC1 MMAL_FOURCC('W', 'V', 'C', '1')
++#define MMAL_ENCODING_VP8 MMAL_FOURCC('V', 'P', '8', ' ')
++#define MMAL_ENCODING_VP7 MMAL_FOURCC('V', 'P', '7', ' ')
++#define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ')
++#define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O')
++#define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K')
++#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G')
++
++#define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G')
++#define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ')
++#define MMAL_ENCODING_PNG MMAL_FOURCC('P', 'N', 'G', ' ')
++#define MMAL_ENCODING_PPM MMAL_FOURCC('P', 'P', 'M', ' ')
++#define MMAL_ENCODING_TGA MMAL_FOURCC('T', 'G', 'A', ' ')
++#define MMAL_ENCODING_BMP MMAL_FOURCC('B', 'M', 'P', ' ')
++
++#define MMAL_ENCODING_I420 MMAL_FOURCC('I', '4', '2', '0')
++#define MMAL_ENCODING_I420_SLICE MMAL_FOURCC('S', '4', '2', '0')
++#define MMAL_ENCODING_YV12 MMAL_FOURCC('Y', 'V', '1', '2')
++#define MMAL_ENCODING_I422 MMAL_FOURCC('I', '4', '2', '2')
++#define MMAL_ENCODING_I422_SLICE MMAL_FOURCC('S', '4', '2', '2')
++#define MMAL_ENCODING_YUYV MMAL_FOURCC('Y', 'U', 'Y', 'V')
++#define MMAL_ENCODING_YVYU MMAL_FOURCC('Y', 'V', 'Y', 'U')
++#define MMAL_ENCODING_UYVY MMAL_FOURCC('U', 'Y', 'V', 'Y')
++#define MMAL_ENCODING_VYUY MMAL_FOURCC('V', 'Y', 'U', 'Y')
++#define MMAL_ENCODING_NV12 MMAL_FOURCC('N', 'V', '1', '2')
++#define MMAL_ENCODING_NV21 MMAL_FOURCC('N', 'V', '2', '1')
++#define MMAL_ENCODING_ARGB MMAL_FOURCC('A', 'R', 'G', 'B')
++#define MMAL_ENCODING_RGBA MMAL_FOURCC('R', 'G', 'B', 'A')
++#define MMAL_ENCODING_ABGR MMAL_FOURCC('A', 'B', 'G', 'R')
++#define MMAL_ENCODING_BGRA MMAL_FOURCC('B', 'G', 'R', 'A')
++#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R', 'G', 'B', '2')
++#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R', 'G', 'B', '3')
++#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R', 'G', 'B', '4')
++#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B', 'G', 'R', '2')
++#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B', 'G', 'R', '3')
++#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B', 'G', 'R', '4')
++
++/** SAND Video (YUVUV128) format, native format understood by VideoCore.
++ * This format is *not* opaque - if requested you will receive full frames
++ * of YUV_UV video.
++ */
++#define MMAL_ENCODING_YUVUV128 MMAL_FOURCC('S', 'A', 'N', 'D')
++
++/** VideoCore opaque image format, image handles are returned to
++ * the host but not the actual image data.
++ */
++#define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V')
++
++/** An EGL image handle
++ */
++#define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I')
++
++/* }@ */
++
++/** \name Pre-defined audio encodings */
++/* @{ */
++#define MMAL_ENCODING_PCM_UNSIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'U')
++#define MMAL_ENCODING_PCM_UNSIGNED_LE MMAL_FOURCC('p', 'c', 'm', 'u')
++#define MMAL_ENCODING_PCM_SIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'S')
++#define MMAL_ENCODING_PCM_SIGNED_LE MMAL_FOURCC('p', 'c', 'm', 's')
++#define MMAL_ENCODING_PCM_FLOAT_BE MMAL_FOURCC('P', 'C', 'M', 'F')
++#define MMAL_ENCODING_PCM_FLOAT_LE MMAL_FOURCC('p', 'c', 'm', 'f')
++
++/* Pre-defined H264 encoding variants */
++
++/** ISO 14496-10 Annex B byte stream format */
++#define MMAL_ENCODING_VARIANT_H264_DEFAULT 0
++/** ISO 14496-15 AVC stream format */
++#define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1')
++/** Implicitly delineated NAL units without emulation prevention */
++#define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ')
++
++/** \defgroup MmalColorSpace List of pre-defined video color spaces
++ * This defines a list of common color spaces. This list isn't exhaustive and
++ * is only provided as a convenience to avoid clients having to use FourCC
++ * codes directly. However components are allowed to define and use their own
++ * FourCC codes.
++ */
++/* @{ */
++
++/** Unknown color space */
++#define MMAL_COLOR_SPACE_UNKNOWN 0
++/** ITU-R BT.601-5 [SDTV] */
++#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1')
++/** ITU-R BT.709-3 [HDTV] */
++#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9')
++/** JPEG JFIF */
++#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I')
++/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
++#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C')
++/** Society of Motion Picture and Television Engineers 240M (1999) */
++#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0')
++/** ITU-R BT.470-2 System M */
++#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M')
++/** ITU-R BT.470-2 System BG */
++#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G')
++/** JPEG JFIF, but with 16..255 luma */
++#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6')
++/* @} MmalColorSpace List */
++
++#endif /* MMAL_ENCODINGS_H */
+--- /dev/null
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-common.h
+@@ -0,0 +1,48 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
++ */
++
++#ifndef MMAL_MSG_COMMON_H
++#define MMAL_MSG_COMMON_H
++
++enum mmal_msg_status {
++ MMAL_MSG_STATUS_SUCCESS = 0, /**< Success */
++ MMAL_MSG_STATUS_ENOMEM, /**< Out of memory */
++ MMAL_MSG_STATUS_ENOSPC, /**< Out of resources other than memory */
++ MMAL_MSG_STATUS_EINVAL, /**< Argument is invalid */
++ MMAL_MSG_STATUS_ENOSYS, /**< Function not implemented */
++ MMAL_MSG_STATUS_ENOENT, /**< No such file or directory */
++ MMAL_MSG_STATUS_ENXIO, /**< No such device or address */
++ MMAL_MSG_STATUS_EIO, /**< I/O error */
++ MMAL_MSG_STATUS_ESPIPE, /**< Illegal seek */
++ MMAL_MSG_STATUS_ECORRUPT, /**< Data is corrupt \attention */
++ MMAL_MSG_STATUS_ENOTREADY, /**< Component is not ready */
++ MMAL_MSG_STATUS_ECONFIG, /**< Component is not configured */
++ MMAL_MSG_STATUS_EISCONN, /**< Port is already connected */
++ MMAL_MSG_STATUS_ENOTCONN, /**< Port is disconnected */
++ MMAL_MSG_STATUS_EAGAIN, /**< Resource temporarily unavailable. */
++ MMAL_MSG_STATUS_EFAULT, /**< Bad address */
++};
++
++struct mmal_rect {
++ s32 x; /**< x coordinate (from left) */
++ s32 y; /**< y coordinate (from top) */
++ s32 width; /**< width */
++ s32 height; /**< height */
++};
++
++struct mmal_rational {
++ s32 num; /**< Numerator */
++ s32 den; /**< Denominator */
++};
++
++#endif /* MMAL_MSG_COMMON_H */
+--- /dev/null
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-format.h
+@@ -0,0 +1,106 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
++ */
++
++#ifndef MMAL_MSG_FORMAT_H
++#define MMAL_MSG_FORMAT_H
++
++#include "mmal-msg-common.h"
++
++/* MMAL_ES_FORMAT_T */
++
++struct mmal_audio_format {
++ u32 channels; /* Number of audio channels */
++ u32 sample_rate; /* Sample rate */
++
++ u32 bits_per_sample; /* Bits per sample */
++ u32 block_align; /* Size of a block of data */
++};
++
++struct mmal_video_format {
++ u32 width; /* Width of frame in pixels */
++ u32 height; /* Height of frame in rows of pixels */
++ struct mmal_rect crop; /* Visible region of the frame */
++ struct mmal_rational frame_rate; /* Frame rate */
++ struct mmal_rational par; /* Pixel aspect ratio */
++
++ /*
++ * FourCC specifying the color space of the video stream. See the
++ * MmalColorSpace "pre-defined color spaces" for some examples.
++ */
++ u32 color_space;
++};
++
++struct mmal_subpicture_format {
++ u32 x_offset;
++ u32 y_offset;
++};
++
++union mmal_es_specific_format {
++ struct mmal_audio_format audio;
++ struct mmal_video_format video;
++ struct mmal_subpicture_format subpicture;
++};
++
++/* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
++struct mmal_es_format_local {
++ u32 type; /* enum mmal_es_type */
++
++ u32 encoding; /* FourCC specifying encoding of the elementary
++ * stream.
++ */
++ u32 encoding_variant; /* FourCC specifying the specific
++ * encoding variant of the elementary
++ * stream.
++ */
++
++ union mmal_es_specific_format *es; /* Type specific
++ * information for the
++ * elementary stream
++ */
++
++ u32 bitrate; /* Bitrate in bits per second */
++ u32 flags; /* Flags describing properties of the elementary
++ * stream.
++ */
++
++ u32 extradata_size; /* Size of the codec specific data */
++ u8 *extradata; /* Codec specific data */
++};
++
++/* Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
++struct mmal_es_format {
++ u32 type; /* enum mmal_es_type */
++
++ u32 encoding; /* FourCC specifying encoding of the elementary
++ * stream.
++ */
++ u32 encoding_variant; /* FourCC specifying the specific
++ * encoding variant of the elementary
++ * stream.
++ */
++
++ u32 es; /* Type specific
++ * information for the
++ * elementary stream
++ */
++
++ u32 bitrate; /* Bitrate in bits per second */
++ u32 flags; /* Flags describing properties of the elementary
++ * stream.
++ */
++
++ u32 extradata_size; /* Size of the codec specific data */
++ u32 extradata; /* Codec specific data */
++};
++
++#endif /* MMAL_MSG_FORMAT_H */
+--- /dev/null
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-port.h
+@@ -0,0 +1,109 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
++ */
++
++/* MMAL_PORT_TYPE_T */
++enum mmal_port_type {
++ MMAL_PORT_TYPE_UNKNOWN = 0, /* Unknown port type */
++ MMAL_PORT_TYPE_CONTROL, /* Control port */
++ MMAL_PORT_TYPE_INPUT, /* Input port */
++ MMAL_PORT_TYPE_OUTPUT, /* Output port */
++ MMAL_PORT_TYPE_CLOCK, /* Clock port */
++};
++
++/* The port is pass-through and doesn't need buffer headers allocated */
++#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01
++/*
++ *The port wants to allocate the buffer payloads.
++ * This signals a preference that payload allocation should be done
++ * on this port for efficiency reasons.
++ */
++#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02
++/*
++ * The port supports format change events.
++ * This applies to input ports and is used to let the client know
++ * whether the port supports being reconfigured via a format
++ * change event (i.e. without having to disable the port).
++ */
++#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04
++
++/*
++ * mmal port structure (MMAL_PORT_T)
++ *
++ * most elements are informational only, the pointer values for
++ * interogation messages are generally provided as additional
++ * structures within the message. When used to set values only the
++ * buffer_num, buffer_size and userdata parameters are writable.
++ */
++struct mmal_port {
++ u32 priv; /* Private member used by the framework */
++ u32 name; /* Port name. Used for debugging purposes (RO) */
++
++ u32 type; /* Type of the port (RO) enum mmal_port_type */
++ u16 index; /* Index of the port in its type list (RO) */
++ u16 index_all; /* Index of the port in the list of all ports (RO) */
++
++ u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
++ u32 format; /* Format of the elementary stream */
++
++ u32 buffer_num_min; /* Minimum number of buffers the port
++ * requires (RO). This is set by the
++ * component.
++ */
++
++ u32 buffer_size_min; /* Minimum size of buffers the port
++ * requires (RO). This is set by the
++ * component.
++ */
++
++ u32 buffer_alignment_min;/* Minimum alignment requirement for
++ * the buffers (RO). A value of
++ * zero means no special alignment
++ * requirements. This is set by the
++ * component.
++ */
++
++ u32 buffer_num_recommended; /* Number of buffers the port
++ * recommends for optimal
++ * performance (RO). A value of
++ * zero means no special
++ * recommendation. This is set
++ * by the component.
++ */
++
++ u32 buffer_size_recommended; /* Size of buffers the port
++ * recommends for optimal
++ * performance (RO). A value of
++ * zero means no special
++ * recommendation. This is set
++ * by the component.
++ */
++
++ u32 buffer_num; /* Actual number of buffers the port will use.
++ * This is set by the client.
++ */
++
++ u32 buffer_size; /* Actual maximum size of the buffers that
++ * will be sent to the port. This is set by
++ * the client.
++ */
++
++ u32 component; /* Component this port belongs to (Read Only) */
++
++ u32 userdata; /* Field reserved for use by the client */
++
++ u32 capabilities; /* Flags describing the capabilities of a
++ * port (RO). Bitwise combination of \ref
++ * portcapabilities "Port capabilities"
++ * values.
++ */
++};
+--- /dev/null
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h
+@@ -0,0 +1,406 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
++ */
++
++/*
++ * all the data structures which serialise the MMAL protocol. note
++ * these are directly mapped onto the recived message data.
++ *
++ * BEWARE: They seem to *assume* pointers are u32 and that there is no
++ * structure padding!
++ *
++ * NOTE: this implementation uses kernel types to ensure sizes. Rather
++ * than assigning values to enums to force their size the
++ * implementation uses fixed size types and not the enums (though the
++ * comments have the actual enum type
++ */
++#ifndef MMAL_MSG_H
++#define MMAL_MSG_H
++
++#define VC_MMAL_VER 15
++#define VC_MMAL_MIN_VER 10
++#define VC_MMAL_SERVER_NAME MAKE_FOURCC("mmal")
++
++/* max total message size is 512 bytes */
++#define MMAL_MSG_MAX_SIZE 512
++/* with six 32bit header elements max payload is therefore 488 bytes */
++#define MMAL_MSG_MAX_PAYLOAD 488
++
++#include "mmal-msg-common.h"
++#include "mmal-msg-format.h"
++#include "mmal-msg-port.h"
++
++enum mmal_msg_type {
++ MMAL_MSG_TYPE_QUIT = 1,
++ MMAL_MSG_TYPE_SERVICE_CLOSED,
++ MMAL_MSG_TYPE_GET_VERSION,
++ MMAL_MSG_TYPE_COMPONENT_CREATE,
++ MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
++ MMAL_MSG_TYPE_COMPONENT_ENABLE,
++ MMAL_MSG_TYPE_COMPONENT_DISABLE,
++ MMAL_MSG_TYPE_PORT_INFO_GET,
++ MMAL_MSG_TYPE_PORT_INFO_SET,
++ MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
++ MMAL_MSG_TYPE_BUFFER_FROM_HOST,
++ MMAL_MSG_TYPE_BUFFER_TO_HOST,
++ MMAL_MSG_TYPE_GET_STATS,
++ MMAL_MSG_TYPE_PORT_PARAMETER_SET,
++ MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
++ MMAL_MSG_TYPE_EVENT_TO_HOST,
++ MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT,
++ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR,
++ MMAL_MSG_TYPE_CONSUME_MEM,
++ MMAL_MSG_TYPE_LMK, /* 20 */
++ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC,
++ MMAL_MSG_TYPE_DRM_GET_LHS32,
++ MMAL_MSG_TYPE_DRM_GET_TIME,
++ MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN,
++ MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
++ MMAL_MSG_TYPE_HOST_LOG,
++ MMAL_MSG_TYPE_MSG_LAST
++};
++
++/* port action request messages differ depending on the action type */
++enum mmal_msg_port_action_type {
++ MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */
++ MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
++ MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
++ MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
++ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
++ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
++ MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/
++};
++
++struct mmal_msg_header {
++ u32 magic;
++ u32 type; /* enum mmal_msg_type */
++
++ /* Opaque handle to the control service */
++ u32 control_service;
++
++ u32 context; /* a u32 per message context */
++ u32 status; /* The status of the vchiq operation */
++ u32 padding;
++};
++
++/* Send from VC to host to report version */
++struct mmal_msg_version {
++ u32 flags;
++ u32 major;
++ u32 minor;
++ u32 minimum;
++};
++
++/* request to VC to create component */
++struct mmal_msg_component_create {
++ u32 client_component; /* component context */
++ char name[128];
++ u32 pid; /* For debug */
++};
++
++/* reply from VC to component creation request */
++struct mmal_msg_component_create_reply {
++ u32 status; /* enum mmal_msg_status - how does this differ to
++ * the one in the header?
++ */
++ u32 component_handle; /* VideoCore handle for component */
++ u32 input_num; /* Number of input ports */
++ u32 output_num; /* Number of output ports */
++ u32 clock_num; /* Number of clock ports */
++};
++
++/* request to VC to destroy a component */
++struct mmal_msg_component_destroy {
++ u32 component_handle;
++};
++
++struct mmal_msg_component_destroy_reply {
++ u32 status; /* The component destruction status */
++};
++
++/* request and reply to VC to enable a component */
++struct mmal_msg_component_enable {
++ u32 component_handle;
++};
++
++struct mmal_msg_component_enable_reply {
++ u32 status; /* The component enable status */
++};
++
++/* request and reply to VC to disable a component */
++struct mmal_msg_component_disable {
++ u32 component_handle;
++};
++
++struct mmal_msg_component_disable_reply {
++ u32 status; /* The component disable status */
++};
++
++/* request to VC to get port information */
++struct mmal_msg_port_info_get {
++ u32 component_handle; /* component handle port is associated with */
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 index; /* port index to query */
++};
++
++/* reply from VC to get port info request */
++struct mmal_msg_port_info_get_reply {
++ u32 status; /* enum mmal_msg_status */
++ u32 component_handle; /* component handle port is associated with */
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 port_index; /* port indexed in query */
++ s32 found; /* unused */
++ u32 port_handle; /* Handle to use for this port */
++ struct mmal_port port;
++ struct mmal_es_format format; /* elementary stream format */
++ union mmal_es_specific_format es; /* es type specific data */
++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; /* es extra data */
++};
++
++/* request to VC to set port information */
++struct mmal_msg_port_info_set {
++ u32 component_handle;
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 port_index; /* port indexed in query */
++ struct mmal_port port;
++ struct mmal_es_format format;
++ union mmal_es_specific_format es;
++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
++};
++
++/* reply from VC to port info set request */
++struct mmal_msg_port_info_set_reply {
++ u32 status;
++ u32 component_handle; /* component handle port is associated with */
++ u32 port_type; /* enum mmal_msg_port_type */
++ u32 index; /* port indexed in query */
++ s32 found; /* unused */
++ u32 port_handle; /* Handle to use for this port */
++ struct mmal_port port;
++ struct mmal_es_format format;
++ union mmal_es_specific_format es;
++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
++};
++
++/* port action requests that take a mmal_port as a parameter */
++struct mmal_msg_port_action_port {
++ u32 component_handle;
++ u32 port_handle;
++ u32 action; /* enum mmal_msg_port_action_type */
++ struct mmal_port port;
++};
++
++/* port action requests that take handles as a parameter */
++struct mmal_msg_port_action_handle {
++ u32 component_handle;
++ u32 port_handle;
++ u32 action; /* enum mmal_msg_port_action_type */
++ u32 connect_component_handle;
++ u32 connect_port_handle;
++};
++
++struct mmal_msg_port_action_reply {
++ u32 status; /* The port action operation status */
++};
++
++/* MMAL buffer transfer */
++
++/* Size of space reserved in a buffer message for short messages. */
++#define MMAL_VC_SHORT_DATA 128
++
++/* Signals that the current payload is the end of the stream of data */
++#define MMAL_BUFFER_HEADER_FLAG_EOS BIT(0)
++/* Signals that the start of the current payload starts a frame */
++#define MMAL_BUFFER_HEADER_FLAG_FRAME_START BIT(1)
++/* Signals that the end of the current payload ends a frame */
++#define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2)
++/* Signals that the current payload contains only complete frames (>1) */
++#define MMAL_BUFFER_HEADER_FLAG_FRAME \
++ (MMAL_BUFFER_HEADER_FLAG_FRAME_START | \
++ MMAL_BUFFER_HEADER_FLAG_FRAME_END)
++/* Signals that the current payload is a keyframe (i.e. self decodable) */
++#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3)
++/*
++ * Signals a discontinuity in the stream of data (e.g. after a seek).
++ * Can be used for instance by a decoder to reset its state
++ */
++#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY BIT(4)
++/*
++ * Signals a buffer containing some kind of config data for the component
++ * (e.g. codec config data)
++ */
++#define MMAL_BUFFER_HEADER_FLAG_CONFIG BIT(5)
++/* Signals an encrypted payload */
++#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED BIT(6)
++/* Signals a buffer containing side information */
++#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO BIT(7)
++/*
++ * Signals a buffer which is the snapshot/postview image from a stills
++ * capture
++ */
++#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT BIT(8)
++/* Signals a buffer which contains data known to be corrupted */
++#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED BIT(9)
++/* Signals that a buffer failed to be transmitted */
++#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED BIT(10)
++
++struct mmal_driver_buffer {
++ u32 magic;
++ u32 component_handle;
++ u32 port_handle;
++ u32 client_context;
++};
++
++/* buffer header */
++struct mmal_buffer_header {
++ u32 next; /* next header */
++ u32 priv; /* framework private data */
++ u32 cmd;
++ u32 data;
++ u32 alloc_size;
++ u32 length;
++ u32 offset;
++ u32 flags;
++ s64 pts;
++ s64 dts;
++ u32 type;
++ u32 user_data;
++};
++
++struct mmal_buffer_header_type_specific {
++ union {
++ struct {
++ u32 planes;
++ u32 offset[4];
++ u32 pitch[4];
++ u32 flags;
++ } video;
++ } u;
++};
++
++struct mmal_msg_buffer_from_host {
++ /*
++ *The front 32 bytes of the buffer header are copied
++ * back to us in the reply to allow for context. This
++ * area is used to store two mmal_driver_buffer structures to
++ * allow for multiple concurrent service users.
++ */
++ /* control data */
++ struct mmal_driver_buffer drvbuf;
++
++ /* referenced control data for passthrough buffer management */
++ struct mmal_driver_buffer drvbuf_ref;
++ struct mmal_buffer_header buffer_header; /* buffer header itself */
++ struct mmal_buffer_header_type_specific buffer_header_type_specific;
++ s32 is_zero_copy;
++ s32 has_reference;
++
++ /* allows short data to be xfered in control message */
++ u32 payload_in_message;
++ u8 short_data[MMAL_VC_SHORT_DATA];
++};
++
++/* port parameter setting */
++
++#define MMAL_WORKER_PORT_PARAMETER_SPACE 96
++
++struct mmal_msg_port_parameter_set {
++ u32 component_handle; /* component */
++ u32 port_handle; /* port */
++ u32 id; /* Parameter ID */
++ u32 size; /* Parameter size */
++ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
++};
++
++struct mmal_msg_port_parameter_set_reply {
++ u32 status; /* enum mmal_msg_status todo: how does this
++ * differ to the one in the header?
++ */
++};
++
++/* port parameter getting */
++
++struct mmal_msg_port_parameter_get {
++ u32 component_handle; /* component */
++ u32 port_handle; /* port */
++ u32 id; /* Parameter ID */
++ u32 size; /* Parameter size */
++};
++
++struct mmal_msg_port_parameter_get_reply {
++ u32 status; /* Status of mmal_port_parameter_get call */
++ u32 id; /* Parameter ID */
++ u32 size; /* Parameter size */
++ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
++};
++
++/* event messages */
++#define MMAL_WORKER_EVENT_SPACE 256
++
++struct mmal_msg_event_to_host {
++ u32 client_component; /* component context */
++
++ u32 port_type;
++ u32 port_num;
++
++ u32 cmd;
++ u32 length;
++ u8 data[MMAL_WORKER_EVENT_SPACE];
++ u32 delayed_buffer;
++};
++
++/* all mmal messages are serialised through this structure */
++struct mmal_msg {
++ /* header */
++ struct mmal_msg_header h;
++ /* payload */
++ union {
++ struct mmal_msg_version version;
++
++ struct mmal_msg_component_create component_create;
++ struct mmal_msg_component_create_reply component_create_reply;
++
++ struct mmal_msg_component_destroy component_destroy;
++ struct mmal_msg_component_destroy_reply component_destroy_reply;
++
++ struct mmal_msg_component_enable component_enable;
++ struct mmal_msg_component_enable_reply component_enable_reply;
++
++ struct mmal_msg_component_disable component_disable;
++ struct mmal_msg_component_disable_reply component_disable_reply;
++
++ struct mmal_msg_port_info_get port_info_get;
++ struct mmal_msg_port_info_get_reply port_info_get_reply;
++
++ struct mmal_msg_port_info_set port_info_set;
++ struct mmal_msg_port_info_set_reply port_info_set_reply;
++
++ struct mmal_msg_port_action_port port_action_port;
++ struct mmal_msg_port_action_handle port_action_handle;
++ struct mmal_msg_port_action_reply port_action_reply;
++
++ struct mmal_msg_buffer_from_host buffer_from_host;
++
++ struct mmal_msg_port_parameter_set port_parameter_set;
++ struct mmal_msg_port_parameter_set_reply
++ port_parameter_set_reply;
++ struct mmal_msg_port_parameter_get
++ port_parameter_get;
++ struct mmal_msg_port_parameter_get_reply
++ port_parameter_get_reply;
++
++ struct mmal_msg_event_to_host event_to_host;
++
++ u8 payload[MMAL_MSG_MAX_PAYLOAD];
++ } u;
++};
++#endif
+--- /dev/null
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
+@@ -0,0 +1,755 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
++ */
++
++/* common parameters */
++
++/** @name Parameter groups
++ * Parameters are divided into groups, and then allocated sequentially within
++ * a group using an enum.
++ * @{
++ */
++
++#ifndef MMAL_PARAMETERS_H
++#define MMAL_PARAMETERS_H
++
++/** Common parameter ID group, used with many types of component. */
++#define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
++/** Camera-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16)
++/** Video-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16)
++/** Audio-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16)
++/** Clock-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16)
++/** Miracast-specific parameter ID group. */
++#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16)
++
++/* Common parameters */
++enum mmal_parameter_common_type {
++ /**< Never a valid parameter ID */
++ MMAL_PARAMETER_UNUSED = MMAL_PARAMETER_GROUP_COMMON,
++
++ /**< MMAL_PARAMETER_ENCODING_T */
++ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
++ /**< MMAL_PARAMETER_URI_T */
++ MMAL_PARAMETER_URI,
++ /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
++ MMAL_PARAMETER_CHANGE_EVENT_REQUEST,
++ /** MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ZERO_COPY,
++ /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
++ MMAL_PARAMETER_BUFFER_REQUIREMENTS,
++ /**< MMAL_PARAMETER_STATISTICS_T */
++ MMAL_PARAMETER_STATISTICS,
++ /**< MMAL_PARAMETER_CORE_STATISTICS_T */
++ MMAL_PARAMETER_CORE_STATISTICS,
++ /**< MMAL_PARAMETER_MEM_USAGE_T */
++ MMAL_PARAMETER_MEM_USAGE,
++ /**< MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_BUFFER_FLAG_FILTER,
++ /**< MMAL_PARAMETER_SEEK_T */
++ MMAL_PARAMETER_SEEK,
++ /**< MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_POWERMON_ENABLE,
++ /**< MMAL_PARAMETER_LOGGING_T */
++ MMAL_PARAMETER_LOGGING,
++ /**< MMAL_PARAMETER_UINT64_T */
++ MMAL_PARAMETER_SYSTEM_TIME,
++ /**< MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_NO_IMAGE_PADDING,
++};
++
++/* camera parameters */
++
++enum mmal_parameter_camera_type {
++ /* 0 */
++ /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
++ MMAL_PARAMETER_THUMBNAIL_CONFIGURATION =
++ MMAL_PARAMETER_GROUP_CAMERA,
++ /**< Unused? */
++ MMAL_PARAMETER_CAPTURE_QUALITY,
++ /**< @ref MMAL_PARAMETER_INT32_T */
++ MMAL_PARAMETER_ROTATION,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_EXIF_DISABLE,
++ /**< @ref MMAL_PARAMETER_EXIF_T */
++ MMAL_PARAMETER_EXIF,
++ /**< @ref MMAL_PARAM_AWBMODE_T */
++ MMAL_PARAMETER_AWB_MODE,
++ /**< @ref MMAL_PARAMETER_IMAGEFX_T */
++ MMAL_PARAMETER_IMAGE_EFFECT,
++ /**< @ref MMAL_PARAMETER_COLOURFX_T */
++ MMAL_PARAMETER_COLOUR_EFFECT,
++ /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
++ MMAL_PARAMETER_FLICKER_AVOID,
++ /**< @ref MMAL_PARAMETER_FLASH_T */
++ MMAL_PARAMETER_FLASH,
++ /**< @ref MMAL_PARAMETER_REDEYE_T */
++ MMAL_PARAMETER_REDEYE,
++ /**< @ref MMAL_PARAMETER_FOCUS_T */
++ MMAL_PARAMETER_FOCUS,
++ /**< Unused? */
++ MMAL_PARAMETER_FOCAL_LENGTHS,
++ /**< @ref MMAL_PARAMETER_INT32_T */
++ MMAL_PARAMETER_EXPOSURE_COMP,
++ /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
++ MMAL_PARAMETER_ZOOM,
++ /**< @ref MMAL_PARAMETER_MIRROR_T */
++ MMAL_PARAMETER_MIRROR,
++
++ /* 0x10 */
++ /**< @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_CAMERA_NUM,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_CAPTURE,
++ /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
++ MMAL_PARAMETER_EXPOSURE_MODE,
++ /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
++ MMAL_PARAMETER_EXP_METERING_MODE,
++ /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
++ MMAL_PARAMETER_FOCUS_STATUS,
++ /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
++ MMAL_PARAMETER_CAMERA_CONFIG,
++ /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
++ MMAL_PARAMETER_CAPTURE_STATUS,
++ /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
++ MMAL_PARAMETER_FACE_TRACK,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS,
++ /**< @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_JPEG_Q_FACTOR,
++ /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
++ MMAL_PARAMETER_FRAME_RATE,
++ /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
++ MMAL_PARAMETER_USE_STC,
++ /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
++ MMAL_PARAMETER_CAMERA_INFO,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_STABILISATION,
++ /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
++ MMAL_PARAMETER_FACE_TRACK_RESULTS,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ENABLE_RAW_CAPTURE,
++
++ /* 0x20 */
++ /**< @ref MMAL_PARAMETER_URI_T */
++ MMAL_PARAMETER_DPF_FILE,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ENABLE_DPF_FILE,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_DPF_FAIL_IS_FATAL,
++ /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
++ MMAL_PARAMETER_CAPTURE_MODE,
++ /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
++ MMAL_PARAMETER_FOCUS_REGIONS,
++ /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
++ MMAL_PARAMETER_INPUT_CROP,
++ /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
++ MMAL_PARAMETER_SENSOR_INFORMATION,
++ /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
++ MMAL_PARAMETER_FLASH_SELECT,
++ /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
++ MMAL_PARAMETER_FIELD_OF_VIEW,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,
++ /**< @ref MMAL_PARAMETER_DRC_T */
++ MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION,
++ /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
++ MMAL_PARAMETER_ALGORITHM_CONTROL,
++ /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_SHARPNESS,
++ /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_CONTRAST,
++ /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_BRIGHTNESS,
++ /**< @ref MMAL_PARAMETER_RATIONAL_T */
++ MMAL_PARAMETER_SATURATION,
++
++ /* 0x30 */
++ /**< @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_ISO,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ANTISHAKE,
++ /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
++ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
++ /** @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_CAMERA_MIN_ISO,
++ /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
++ MMAL_PARAMETER_CAMERA_USE_CASE,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_CAPTURE_STATS_PASS,
++ /** @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG,
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_ENABLE_REGISTER_FILE,
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
++ /** @ref MMAL_PARAMETER_CONFIGFILE_T */
++ MMAL_PARAMETER_CONFIGFILE_REGISTERS,
++ /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
++ MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_JPEG_ATTACH_LOG,
++ /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
++ MMAL_PARAMETER_ZERO_SHUTTER_LAG,
++ /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
++ MMAL_PARAMETER_FPS_RANGE,
++ /**< @ref MMAL_PARAMETER_INT32_T */
++ MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP,
++
++ /* 0x40 */
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_SW_SHARPEN_DISABLE,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_FLASH_REQUIRED,
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_SW_SATURATION_DISABLE,
++ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_SHUTTER_SPEED,
++ /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
++ MMAL_PARAMETER_CUSTOM_AWB_GAINS,
++};
++
++struct mmal_parameter_rational {
++ s32 num; /**< Numerator */
++ s32 den; /**< Denominator */
++};
++
++enum mmal_parameter_camera_config_timestamp_mode {
++ MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */
++ MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value
++ * for the frame timestamp
++ */
++ MMAL_PARAM_TIMESTAMP_MODE_RESET_STC, /* Use the STC timestamp
++ * but subtract the
++ * timestamp of the first
++ * frame sent to give a
++ * zero based timestamp.
++ */
++};
++
++struct mmal_parameter_fps_range {
++ /**< Low end of the permitted framerate range */
++ struct mmal_parameter_rational fps_low;
++ /**< High end of the permitted framerate range */
++ struct mmal_parameter_rational fps_high;
++};
++
++/* camera configuration parameter */
++struct mmal_parameter_camera_config {
++ /* Parameters for setting up the image pools */
++ u32 max_stills_w; /* Max size of stills capture */
++ u32 max_stills_h;
++ u32 stills_yuv422; /* Allow YUV422 stills capture */
++ u32 one_shot_stills; /* Continuous or one shot stills captures. */
++
++ u32 max_preview_video_w; /* Max size of the preview or video
++ * capture frames
++ */
++ u32 max_preview_video_h;
++ u32 num_preview_video_frames;
++
++ /** Sets the height of the circular buffer for stills capture. */
++ u32 stills_capture_circular_buffer_height;
++
++ /** Allows preview/encode to resume as fast as possible after the stills
++ * input frame has been received, and then processes the still frame in
++ * the background whilst preview/encode has resumed.
++ * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE.
++ */
++ u32 fast_preview_resume;
++
++ /** Selects algorithm for timestamping frames if
++ * there is no clock component connected.
++ * enum mmal_parameter_camera_config_timestamp_mode
++ */
++ s32 use_stc_timestamp;
++};
++
++enum mmal_parameter_exposuremode {
++ MMAL_PARAM_EXPOSUREMODE_OFF,
++ MMAL_PARAM_EXPOSUREMODE_AUTO,
++ MMAL_PARAM_EXPOSUREMODE_NIGHT,
++ MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,
++ MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,
++ MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,
++ MMAL_PARAM_EXPOSUREMODE_SPORTS,
++ MMAL_PARAM_EXPOSUREMODE_SNOW,
++ MMAL_PARAM_EXPOSUREMODE_BEACH,
++ MMAL_PARAM_EXPOSUREMODE_VERYLONG,
++ MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,
++ MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,
++ MMAL_PARAM_EXPOSUREMODE_FIREWORKS,
++};
++
++enum mmal_parameter_exposuremeteringmode {
++ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE,
++ MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT,
++ MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT,
++ MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX,
++};
++
++enum mmal_parameter_awbmode {
++ MMAL_PARAM_AWBMODE_OFF,
++ MMAL_PARAM_AWBMODE_AUTO,
++ MMAL_PARAM_AWBMODE_SUNLIGHT,
++ MMAL_PARAM_AWBMODE_CLOUDY,
++ MMAL_PARAM_AWBMODE_SHADE,
++ MMAL_PARAM_AWBMODE_TUNGSTEN,
++ MMAL_PARAM_AWBMODE_FLUORESCENT,
++ MMAL_PARAM_AWBMODE_INCANDESCENT,
++ MMAL_PARAM_AWBMODE_FLASH,
++ MMAL_PARAM_AWBMODE_HORIZON,
++};
++
++enum mmal_parameter_imagefx {
++ MMAL_PARAM_IMAGEFX_NONE,
++ MMAL_PARAM_IMAGEFX_NEGATIVE,
++ MMAL_PARAM_IMAGEFX_SOLARIZE,
++ MMAL_PARAM_IMAGEFX_POSTERIZE,
++ MMAL_PARAM_IMAGEFX_WHITEBOARD,
++ MMAL_PARAM_IMAGEFX_BLACKBOARD,
++ MMAL_PARAM_IMAGEFX_SKETCH,
++ MMAL_PARAM_IMAGEFX_DENOISE,
++ MMAL_PARAM_IMAGEFX_EMBOSS,
++ MMAL_PARAM_IMAGEFX_OILPAINT,
++ MMAL_PARAM_IMAGEFX_HATCH,
++ MMAL_PARAM_IMAGEFX_GPEN,
++ MMAL_PARAM_IMAGEFX_PASTEL,
++ MMAL_PARAM_IMAGEFX_WATERCOLOUR,
++ MMAL_PARAM_IMAGEFX_FILM,
++ MMAL_PARAM_IMAGEFX_BLUR,
++ MMAL_PARAM_IMAGEFX_SATURATION,
++ MMAL_PARAM_IMAGEFX_COLOURSWAP,
++ MMAL_PARAM_IMAGEFX_WASHEDOUT,
++ MMAL_PARAM_IMAGEFX_POSTERISE,
++ MMAL_PARAM_IMAGEFX_COLOURPOINT,
++ MMAL_PARAM_IMAGEFX_COLOURBALANCE,
++ MMAL_PARAM_IMAGEFX_CARTOON,
++};
++
++enum MMAL_PARAM_FLICKERAVOID_T {
++ MMAL_PARAM_FLICKERAVOID_OFF,
++ MMAL_PARAM_FLICKERAVOID_AUTO,
++ MMAL_PARAM_FLICKERAVOID_50HZ,
++ MMAL_PARAM_FLICKERAVOID_60HZ,
++ MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF
++};
++
++struct mmal_parameter_awbgains {
++ struct mmal_parameter_rational r_gain; /**< Red gain */
++ struct mmal_parameter_rational b_gain; /**< Blue gain */
++};
++
++/** Manner of video rate control */
++enum mmal_parameter_rate_control_mode {
++ MMAL_VIDEO_RATECONTROL_DEFAULT,
++ MMAL_VIDEO_RATECONTROL_VARIABLE,
++ MMAL_VIDEO_RATECONTROL_CONSTANT,
++ MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES,
++ MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES
++};
++
++enum mmal_video_profile {
++ MMAL_VIDEO_PROFILE_H263_BASELINE,
++ MMAL_VIDEO_PROFILE_H263_H320CODING,
++ MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE,
++ MMAL_VIDEO_PROFILE_H263_ISWV2,
++ MMAL_VIDEO_PROFILE_H263_ISWV3,
++ MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION,
++ MMAL_VIDEO_PROFILE_H263_INTERNET,
++ MMAL_VIDEO_PROFILE_H263_INTERLACE,
++ MMAL_VIDEO_PROFILE_H263_HIGHLATENCY,
++ MMAL_VIDEO_PROFILE_MP4V_SIMPLE,
++ MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE,
++ MMAL_VIDEO_PROFILE_MP4V_CORE,
++ MMAL_VIDEO_PROFILE_MP4V_MAIN,
++ MMAL_VIDEO_PROFILE_MP4V_NBIT,
++ MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE,
++ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE,
++ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA,
++ MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED,
++ MMAL_VIDEO_PROFILE_MP4V_HYBRID,
++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME,
++ MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE,
++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING,
++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE,
++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE,
++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE,
++ MMAL_VIDEO_PROFILE_H264_BASELINE,
++ MMAL_VIDEO_PROFILE_H264_MAIN,
++ MMAL_VIDEO_PROFILE_H264_EXTENDED,
++ MMAL_VIDEO_PROFILE_H264_HIGH,
++ MMAL_VIDEO_PROFILE_H264_HIGH10,
++ MMAL_VIDEO_PROFILE_H264_HIGH422,
++ MMAL_VIDEO_PROFILE_H264_HIGH444,
++ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE,
++ MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF
++};
++
++enum mmal_video_level {
++ MMAL_VIDEO_LEVEL_H263_10,
++ MMAL_VIDEO_LEVEL_H263_20,
++ MMAL_VIDEO_LEVEL_H263_30,
++ MMAL_VIDEO_LEVEL_H263_40,
++ MMAL_VIDEO_LEVEL_H263_45,
++ MMAL_VIDEO_LEVEL_H263_50,
++ MMAL_VIDEO_LEVEL_H263_60,
++ MMAL_VIDEO_LEVEL_H263_70,
++ MMAL_VIDEO_LEVEL_MP4V_0,
++ MMAL_VIDEO_LEVEL_MP4V_0b,
++ MMAL_VIDEO_LEVEL_MP4V_1,
++ MMAL_VIDEO_LEVEL_MP4V_2,
++ MMAL_VIDEO_LEVEL_MP4V_3,
++ MMAL_VIDEO_LEVEL_MP4V_4,
++ MMAL_VIDEO_LEVEL_MP4V_4a,
++ MMAL_VIDEO_LEVEL_MP4V_5,
++ MMAL_VIDEO_LEVEL_MP4V_6,
++ MMAL_VIDEO_LEVEL_H264_1,
++ MMAL_VIDEO_LEVEL_H264_1b,
++ MMAL_VIDEO_LEVEL_H264_11,
++ MMAL_VIDEO_LEVEL_H264_12,
++ MMAL_VIDEO_LEVEL_H264_13,
++ MMAL_VIDEO_LEVEL_H264_2,
++ MMAL_VIDEO_LEVEL_H264_21,
++ MMAL_VIDEO_LEVEL_H264_22,
++ MMAL_VIDEO_LEVEL_H264_3,
++ MMAL_VIDEO_LEVEL_H264_31,
++ MMAL_VIDEO_LEVEL_H264_32,
++ MMAL_VIDEO_LEVEL_H264_4,
++ MMAL_VIDEO_LEVEL_H264_41,
++ MMAL_VIDEO_LEVEL_H264_42,
++ MMAL_VIDEO_LEVEL_H264_5,
++ MMAL_VIDEO_LEVEL_H264_51,
++ MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF
++};
++
++struct mmal_parameter_video_profile {
++ enum mmal_video_profile profile;
++ enum mmal_video_level level;
++};
++
++/* video parameters */
++
++enum mmal_parameter_video_type {
++ /** @ref MMAL_DISPLAYREGION_T */
++ MMAL_PARAMETER_DISPLAYREGION = MMAL_PARAMETER_GROUP_VIDEO,
++
++ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
++ MMAL_PARAMETER_SUPPORTED_PROFILES,
++
++ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
++ MMAL_PARAMETER_PROFILE,
++
++ /** @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_INTRAPERIOD,
++
++ /** @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */
++ MMAL_PARAMETER_RATECONTROL,
++
++ /** @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */
++ MMAL_PARAMETER_NALUNITFORMAT,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
++
++ /** @ref MMAL_PARAMETER_UINT32_T.
++ * Setting the value to zero resets to the default (one slice per
++ * frame).
++ */
++ MMAL_PARAMETER_MB_ROWS_PER_SLICE,
++
++ /** @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */
++ MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION,
++
++ /** @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */
++ MMAL_PARAMETER_VIDEO_EEDE_ENABLE,
++
++ /** @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */
++ MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. Request an I-frame. */
++ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
++ /** @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */
++ MMAL_PARAMETER_VIDEO_INTRA_REFRESH,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. Run-time bit rate control */
++ MMAL_PARAMETER_VIDEO_BIT_RATE,
++
++ /** @ref MMAL_PARAMETER_FRAME_RATE_T */
++ MMAL_PARAMETER_VIDEO_FRAME_RATE,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT,
++
++ /** @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL,
++
++ MMAL_PARAMETER_EXTRA_BUFFERS, /**< @ref MMAL_PARAMETER_UINT32_T. */
++ /** @ref MMAL_PARAMETER_UINT32_T.
++ * Changing this parameter from the default can reduce frame rate
++ * because image buffers need to be re-pitched.
++ */
++ MMAL_PARAMETER_VIDEO_ALIGN_HORIZ,
++
++ /** @ref MMAL_PARAMETER_UINT32_T.
++ * Changing this parameter from the default can reduce frame rate
++ * because image buffers need to be re-pitched.
++ */
++ MMAL_PARAMETER_VIDEO_ALIGN_VERT,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT,
++
++ /**< @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_QP_P,
++
++ /**< @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT,
++
++ /** @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE,
++
++ /* H264 specific parameters */
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS,
++
++ /** @ref MMAL_PARAMETER_UINT32_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC,
++
++ /** @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP,
++
++ /** @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */
++ MMAL_PARAMETER_VIDEO_DRM_INIT_INFO,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO,
++
++ /** @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT,
++
++ /** @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */
++ MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER,
++
++ /** @ref MMAL_PARAMETER_BYTES_T */
++ MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3,
++
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS,
++
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG,
++
++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER
++};
++
++/** Valid mirror modes */
++enum mmal_parameter_mirror {
++ MMAL_PARAM_MIRROR_NONE,
++ MMAL_PARAM_MIRROR_VERTICAL,
++ MMAL_PARAM_MIRROR_HORIZONTAL,
++ MMAL_PARAM_MIRROR_BOTH,
++};
++
++enum mmal_parameter_displaytransform {
++ MMAL_DISPLAY_ROT0 = 0,
++ MMAL_DISPLAY_MIRROR_ROT0 = 1,
++ MMAL_DISPLAY_MIRROR_ROT180 = 2,
++ MMAL_DISPLAY_ROT180 = 3,
++ MMAL_DISPLAY_MIRROR_ROT90 = 4,
++ MMAL_DISPLAY_ROT270 = 5,
++ MMAL_DISPLAY_ROT90 = 6,
++ MMAL_DISPLAY_MIRROR_ROT270 = 7,
++};
++
++enum mmal_parameter_displaymode {
++ MMAL_DISPLAY_MODE_FILL = 0,
++ MMAL_DISPLAY_MODE_LETTERBOX = 1,
++};
++
++enum mmal_parameter_displayset {
++ MMAL_DISPLAY_SET_NONE = 0,
++ MMAL_DISPLAY_SET_NUM = 1,
++ MMAL_DISPLAY_SET_FULLSCREEN = 2,
++ MMAL_DISPLAY_SET_TRANSFORM = 4,
++ MMAL_DISPLAY_SET_DEST_RECT = 8,
++ MMAL_DISPLAY_SET_SRC_RECT = 0x10,
++ MMAL_DISPLAY_SET_MODE = 0x20,
++ MMAL_DISPLAY_SET_PIXEL = 0x40,
++ MMAL_DISPLAY_SET_NOASPECT = 0x80,
++ MMAL_DISPLAY_SET_LAYER = 0x100,
++ MMAL_DISPLAY_SET_COPYPROTECT = 0x200,
++ MMAL_DISPLAY_SET_ALPHA = 0x400,
++};
++
++/* rectangle, used lots so it gets its own struct */
++struct vchiq_mmal_rect {
++ s32 x;
++ s32 y;
++ s32 width;
++ s32 height;
++};
++
++struct mmal_parameter_displayregion {
++ /** Bitfield that indicates which fields are set and should be
++ * used. All other fields will maintain their current value.
++ * \ref MMAL_DISPLAYSET_T defines the bits that can be
++ * combined.
++ */
++ u32 set;
++
++ /** Describes the display output device, with 0 typically
++ * being a directly connected LCD display. The actual values
++ * will depend on the hardware. Code using hard-wired numbers
++ * (e.g. 2) is certain to fail.
++ */
++
++ u32 display_num;
++ /** Indicates that we are using the full device screen area,
++ * rather than a window of the display. If zero, then
++ * dest_rect is used to specify a region of the display to
++ * use.
++ */
++
++ s32 fullscreen;
++ /** Indicates any rotation or flipping used to map frames onto
++ * the natural display orientation.
++ */
++ u32 transform; /* enum mmal_parameter_displaytransform */
++
++ /** Where to display the frame within the screen, if
++ * fullscreen is zero.
++ */
++ struct vchiq_mmal_rect dest_rect;
++
++ /** Indicates which area of the frame to display. If all
++ * values are zero, the whole frame will be used.
++ */
++ struct vchiq_mmal_rect src_rect;
++
++ /** If set to non-zero, indicates that any display scaling
++ * should disregard the aspect ratio of the frame region being
++ * displayed.
++ */
++ s32 noaspect;
++
++ /** Indicates how the image should be scaled to fit the
++ * display. \code MMAL_DISPLAY_MODE_FILL \endcode indicates
++ * that the image should fill the screen by potentially
++ * cropping the frames. Setting \code mode \endcode to \code
++ * MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the
++ * source region should be displayed and black bars added if
++ * necessary.
++ */
++ u32 mode; /* enum mmal_parameter_displaymode */
++
++ /** If non-zero, defines the width of a source pixel relative
++ * to \code pixel_y \endcode. If zero, then pixels default to
++ * being square.
++ */
++ u32 pixel_x;
++
++ /** If non-zero, defines the height of a source pixel relative
++ * to \code pixel_x \endcode. If zero, then pixels default to
++ * being square.
++ */
++ u32 pixel_y;
++
++ /** Sets the relative depth of the images, with greater values
++ * being in front of smaller values.
++ */
++ u32 layer;
++
++ /** Set to non-zero to ensure copy protection is used on
++ * output.
++ */
++ s32 copyprotect_required;
++
++ /** Level of opacity of the layer, where zero is fully
++ * transparent and 255 is fully opaque.
++ */
++ u32 alpha;
++};
++
++#define MMAL_MAX_IMAGEFX_PARAMETERS 5
++
++struct mmal_parameter_imagefx_parameters {
++ enum mmal_parameter_imagefx effect;
++ u32 num_effect_params;
++ u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS];
++};
++
++#define MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS 4
++#define MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES 2
++#define MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN 16
++
++struct mmal_parameter_camera_info_camera_t {
++ u32 port_id;
++ u32 max_width;
++ u32 max_height;
++ u32 lens_present;
++ u8 camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN];
++};
++
++enum mmal_parameter_camera_info_flash_type_t {
++ /* Make values explicit to ensure they match values in config ini */
++ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON = 0,
++ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED = 1,
++ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER = 2,
++ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_MAX = 0x7FFFFFFF
++};
++
++struct mmal_parameter_camera_info_flash_t {
++ enum mmal_parameter_camera_info_flash_type_t flash_type;
++};
++
++struct mmal_parameter_camera_info_t {
++ u32 num_cameras;
++ u32 num_flashes;
++ struct mmal_parameter_camera_info_camera_t
++ cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS];
++ struct mmal_parameter_camera_info_flash_t
++ flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES];
++};
++
++#endif
+--- /dev/null
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
+@@ -0,0 +1,166 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Broadcom BM2835 V4L2 driver
++ *
++ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
++ *
++ * Authors: Vincent Sanders @ Collabora
++ * Dave Stevenson @ Broadcom
++ * Simon Mellor @ Broadcom
++ * Luke Diamand @ Broadcom
++ *
++ * MMAL interface to VCHIQ message passing
++ */
++
++#ifndef MMAL_VCHIQ_H
++#define MMAL_VCHIQ_H
++
++#include "mmal-msg-format.h"
++
++#define MAX_PORT_COUNT 4
++
++/* Maximum size of the format extradata. */
++#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128
++
++struct vchiq_mmal_instance;
++
++enum vchiq_mmal_es_type {
++ MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */
++ MMAL_ES_TYPE_CONTROL, /**< Elementary stream of control commands */
++ MMAL_ES_TYPE_AUDIO, /**< Audio elementary stream */
++ MMAL_ES_TYPE_VIDEO, /**< Video elementary stream */
++ MMAL_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream */
++};
++
++struct vchiq_mmal_port_buffer {
++ unsigned int num; /* number of buffers */
++ u32 size; /* size of buffers */
++ u32 alignment; /* alignment of buffers */
++};
++
++struct vchiq_mmal_port;
++
++typedef void (*vchiq_mmal_buffer_cb)(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ int status, struct mmal_buffer *buffer,
++ unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
++
++struct vchiq_mmal_port {
++ bool enabled;
++ u32 handle;
++ u32 type; /* port type, cached to use on port info set */
++ u32 index; /* port index, cached to use on port info set */
++
++ /* component port belongs to, allows simple deref */
++ struct vchiq_mmal_component *component;
++
++ struct vchiq_mmal_port *connected; /* port conencted to */
++
++ /* buffer info */
++ struct vchiq_mmal_port_buffer minimum_buffer;
++ struct vchiq_mmal_port_buffer recommended_buffer;
++ struct vchiq_mmal_port_buffer current_buffer;
++
++ /* stream format */
++ struct mmal_es_format_local format;
++ /* elementary stream format */
++ union mmal_es_specific_format es;
++
++ /* data buffers to fill */
++ struct list_head buffers;
++ /* lock to serialise adding and removing buffers from list */
++ spinlock_t slock;
++
++ /* Count of buffers the VPU has yet to return */
++ atomic_t buffers_with_vpu;
++ /* callback on buffer completion */
++ vchiq_mmal_buffer_cb buffer_cb;
++ /* callback context */
++ void *cb_ctx;
++};
++
++struct vchiq_mmal_component {
++ bool enabled;
++ u32 handle; /* VideoCore handle for component */
++ u32 inputs; /* Number of input ports */
++ u32 outputs; /* Number of output ports */
++ u32 clocks; /* Number of clock ports */
++ struct vchiq_mmal_port control; /* control port */
++ struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */
++ struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */
++ struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */
++};
++
++int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance);
++int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance);
++
++/* Initialise a mmal component and its ports
++ *
++ */
++int vchiq_mmal_component_init(
++ struct vchiq_mmal_instance *instance,
++ const char *name,
++ struct vchiq_mmal_component **component_out);
++
++int vchiq_mmal_component_finalise(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component);
++
++int vchiq_mmal_component_enable(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component);
++
++int vchiq_mmal_component_disable(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_component *component);
++
++/* enable a mmal port
++ *
++ * enables a port and if a buffer callback provided enque buffer
++ * headers as appropriate for the port.
++ */
++int vchiq_mmal_port_enable(
++ struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ vchiq_mmal_buffer_cb buffer_cb);
++
++/* disable a port
++ *
++ * disable a port will dequeue any pending buffers
++ */
++int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port);
++
++int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter,
++ void *value,
++ u32 value_size);
++
++int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ u32 parameter,
++ void *value,
++ u32 *value_size);
++
++int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port);
++
++int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *src,
++ struct vchiq_mmal_port *dst);
++
++int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
++ u32 *major_out,
++ u32 *minor_out);
++
++int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port,
++ struct mmal_buffer *buf);
++
++int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance,
++ struct mmal_buffer *buf);
++int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf);
++#endif /* MMAL_VCHIQ_H */
+++ /dev/null
-From 37ede4f6a1771b09dea6e8b2fc4d2c5f085a33f3 Mon Sep 17 00:00:00 2001
-Date: Fri, 28 Sep 2018 10:22:26 +0100
-Subject: [PATCH] staging: bcm2835-camera: Remove/amend some obsolete
- comments
-
-Remove a todo which has been done.
-Remove a template line that was redundant.
-Make a comment clearer as to the non-obvious meaning of a field.
-
----
- .../staging/vc04_services/bcm2835-camera/controls.c | 11 +----------
- 1 file changed, 1 insertion(+), 10 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -965,10 +965,6 @@ static const struct bm2835_mmal_v4l2_ctr
- &ctrl_set_value,
- false
- },
--/* {
-- * 0, MMAL_CONTROL_TYPE_CLUSTER, 3, 1, 0, NULL, 0, NULL
-- * },
-- */
- {
- V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
- ~0x03, V4L2_EXPOSURE_APERTURE_PRIORITY, V4L2_EXPOSURE_AUTO, 0,
-@@ -976,11 +972,6 @@ static const struct bm2835_mmal_v4l2_ctr
- &ctrl_set_exposure,
- false
- },
--/* todo this needs mixing in with set exposure
-- * {
-- * V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
-- * },
-- */
- {
- V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD,
- /* Units of 100usecs */
-@@ -1146,7 +1137,7 @@ static const struct bm2835_mmal_v4l2_ctr
- },
- {
- V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
-- -1, /* Min is computed at runtime */
-+ -1, /* Min (mask) is computed at runtime */
- V4L2_SCENE_MODE_TEXT,
- V4L2_SCENE_MODE_NONE, 1, NULL,
- MMAL_PARAMETER_PROFILE,
--- /dev/null
+From f94642597f63c71b2ccffddd4f447190c131af56 Mon Sep 17 00:00:00 2001
+Date: Mon, 24 Sep 2018 16:51:13 +0100
+Subject: [PATCH] staging: mmal-vchiq: Allocate and free components as
+ required
+
+The existing code assumed that there would only ever be 4 components,
+and never freed the entries once used.
+Allow arbitrary creation and destruction of components.
+
+---
+ .../vc04_services/vchiq-mmal/mmal-vchiq.c | 29 ++++++++++++-------
+ .../vc04_services/vchiq-mmal/mmal-vchiq.h | 1 +
+ 2 files changed, 20 insertions(+), 10 deletions(-)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -38,8 +38,11 @@ MODULE_AUTHOR("Dave Stevenson, <dave.ste
+ MODULE_LICENSE("GPL");
+ MODULE_VERSION("0.0.1");
+
+-/* maximum number of components supported */
+-#define VCHIQ_MMAL_MAX_COMPONENTS 4
++/*
++ * maximum number of components supported.
++ * This matches the maximum permitted by default on the VPU
++ */
++#define VCHIQ_MMAL_MAX_COMPONENTS 64
+
+ /*#define FULL_MSG_DUMP 1*/
+
+@@ -174,8 +177,6 @@ struct vchiq_mmal_instance {
+ /* protect accesses to context_map */
+ struct mutex context_map_lock;
+
+- /* component to use next */
+- int component_idx;
+ struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
+
+ /* ordered workqueue to process all bulk operations */
+@@ -1632,18 +1633,24 @@ int vchiq_mmal_component_init(struct vch
+ {
+ int ret;
+ int idx; /* port index */
+- struct vchiq_mmal_component *component;
++ struct vchiq_mmal_component *component = NULL;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+- if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) {
++ for (idx = 0; idx < VCHIQ_MMAL_MAX_COMPONENTS; idx++) {
++ if (!instance->component[idx].in_use) {
++ component = &instance->component[idx];
++ component->in_use = 1;
++ break;
++ }
++ }
++
++ if (!component) {
+ ret = -EINVAL; /* todo is this correct error? */
+ goto unlock;
+ }
+
+- component = &instance->component[instance->component_idx];
+-
+ ret = create_component(instance, component, name);
+ if (ret < 0) {
+ pr_err("%s: failed to create component %d (Not enough GPU mem?)\n",
+@@ -1694,8 +1701,6 @@ int vchiq_mmal_component_init(struct vch
+ goto release_component;
+ }
+
+- instance->component_idx++;
+-
+ *component_out = component;
+
+ mutex_unlock(&instance->vchiq_mutex);
+@@ -1705,6 +1710,8 @@ int vchiq_mmal_component_init(struct vch
+ release_component:
+ destroy_component(instance, component);
+ unlock:
++ if (component)
++ component->in_use = 0;
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+@@ -1727,6 +1734,8 @@ int vchiq_mmal_component_finalise(struct
+
+ ret = destroy_component(instance, component);
+
++ component->in_use = 0;
++
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
+@@ -82,6 +82,7 @@ struct vchiq_mmal_port {
+ };
+
+ struct vchiq_mmal_component {
++ u32 in_use:1;
+ bool enabled;
+ u32 handle; /* VideoCore handle for component */
+ u32 inputs; /* Number of input ports */
--- /dev/null
+From 3789c3b08b56f471878c493fd80a2eee776b527c Mon Sep 17 00:00:00 2001
+Date: Mon, 29 Oct 2018 16:20:46 +0000
+Subject: [PATCH] staging: mmal-vchiq: Avoid use of bool in structures
+
+Fixes up a checkpatch error "Avoid using bool structure members
+because of possible alignment issues".
+
+---
+ .../staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 14 +++++++-------
+ .../staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 4 ++--
+ 2 files changed, 9 insertions(+), 9 deletions(-)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -861,9 +861,9 @@ static int port_info_get(struct vchiq_mm
+ goto release_msg;
+
+ if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
+- port->enabled = false;
++ port->enabled = 0;
+ else
+- port->enabled = true;
++ port->enabled = 1;
+
+ /* copy the values out of the message */
+ port->handle = rmsg->u.port_info_get_reply.port_handle;
+@@ -1300,7 +1300,7 @@ static int port_disable(struct vchiq_mma
+ if (!port->enabled)
+ return 0;
+
+- port->enabled = false;
++ port->enabled = 0;
+
+ ret = port_action_port(instance, port,
+ MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
+@@ -1352,7 +1352,7 @@ static int port_enable(struct vchiq_mmal
+ if (ret)
+ goto done;
+
+- port->enabled = true;
++ port->enabled = 1;
+
+ if (port->buffer_cb) {
+ /* send buffer headers to videocore */
+@@ -1524,7 +1524,7 @@ int vchiq_mmal_port_connect_tunnel(struc
+ pr_err("failed disconnecting src port\n");
+ goto release_unlock;
+ }
+- src->connected->enabled = false;
++ src->connected->enabled = 0;
+ src->connected = NULL;
+ }
+
+@@ -1760,7 +1760,7 @@ int vchiq_mmal_component_enable(struct v
+
+ ret = enable_component(instance, component);
+ if (ret == 0)
+- component->enabled = true;
++ component->enabled = 1;
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+@@ -1786,7 +1786,7 @@ int vchiq_mmal_component_disable(struct
+
+ ret = disable_component(instance, component);
+ if (ret == 0)
+- component->enabled = false;
++ component->enabled = 0;
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
+@@ -48,7 +48,7 @@ typedef void (*vchiq_mmal_buffer_cb)(
+ unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
+
+ struct vchiq_mmal_port {
+- bool enabled;
++ u32 enabled:1;
+ u32 handle;
+ u32 type; /* port type, cached to use on port info set */
+ u32 index; /* port index, cached to use on port info set */
+@@ -83,7 +83,7 @@ struct vchiq_mmal_port {
+
+ struct vchiq_mmal_component {
+ u32 in_use:1;
+- bool enabled;
++ u32 enabled:1;
+ u32 handle; /* VideoCore handle for component */
+ u32 inputs; /* Number of input ports */
+ u32 outputs; /* Number of output ports */
+++ /dev/null
-From e7723c6bcf31a440b8762e9e22497ff3fbbb7056 Mon Sep 17 00:00:00 2001
-Date: Mon, 24 Sep 2018 16:30:37 +0100
-Subject: [PATCH] staging: vc04_services: Split vchiq-mmal into a
- module
-
-In preparation for adding a video codec V4L2 module which also
-wants to use vchiq-mmal functions, split it out into an
-independent module.
-The minimum number of changes have been made to achieve this
-(eg straight moves where possible) so existing checkpatch
-errors will still be present.
-
----
- drivers/staging/vc04_services/Kconfig | 1 +
- drivers/staging/vc04_services/Makefile | 1 +
- .../vc04_services/bcm2835-camera/Kconfig | 2 +-
- .../vc04_services/bcm2835-camera/Makefile | 4 ++--
- .../staging/vc04_services/vchiq-mmal/Kconfig | 7 ++++++
- .../staging/vc04_services/vchiq-mmal/Makefile | 8 +++++++
- .../mmal-common.h | 0
- .../mmal-encodings.h | 0
- .../mmal-msg-common.h | 0
- .../mmal-msg-format.h | 0
- .../mmal-msg-port.h | 0
- .../{bcm2835-camera => vchiq-mmal}/mmal-msg.h | 0
- .../mmal-parameters.h | 0
- .../mmal-vchiq.c | 22 +++++++++++++++++++
- .../mmal-vchiq.h | 0
- 15 files changed, 42 insertions(+), 3 deletions(-)
- create mode 100644 drivers/staging/vc04_services/vchiq-mmal/Kconfig
- create mode 100644 drivers/staging/vc04_services/vchiq-mmal/Makefile
- rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-common.h (100%)
- rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-encodings.h (100%)
- rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg-common.h (100%)
- rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg-format.h (100%)
- rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg-port.h (100%)
- rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg.h (100%)
- rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-parameters.h (100%)
- rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-vchiq.c (98%)
- rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-vchiq.h (100%)
-
---- a/drivers/staging/vc04_services/Kconfig
-+++ b/drivers/staging/vc04_services/Kconfig
-@@ -21,6 +21,7 @@ config BCM2835_VCHIQ
- source "drivers/staging/vc04_services/bcm2835-audio/Kconfig"
-
- source "drivers/staging/vc04_services/bcm2835-camera/Kconfig"
-+source "drivers/staging/vc04_services/vchiq-mmal/Kconfig"
-
- endif
-
---- a/drivers/staging/vc04_services/Makefile
-+++ b/drivers/staging/vc04_services/Makefile
-@@ -12,6 +12,7 @@ vchiq-objs := \
-
- obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
- obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
-+obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
-
- ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000
-
---- a/drivers/staging/vc04_services/bcm2835-camera/Kconfig
-+++ b/drivers/staging/vc04_services/bcm2835-camera/Kconfig
-@@ -2,7 +2,7 @@ config VIDEO_BCM2835
- tristate "BCM2835 Camera"
- depends on MEDIA_SUPPORT
- depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST)
-- select BCM2835_VCHIQ
-+ select BCM2835_VCHIQ_MMAL
- select VIDEOBUF2_VMALLOC
- select BTREE
- help
---- a/drivers/staging/vc04_services/bcm2835-camera/Makefile
-+++ b/drivers/staging/vc04_services/bcm2835-camera/Makefile
-@@ -1,11 +1,11 @@
- # SPDX-License-Identifier: GPL-2.0
- bcm2835-v4l2-$(CONFIG_VIDEO_BCM2835) := \
- bcm2835-camera.o \
-- controls.o \
-- mmal-vchiq.o
-+ controls.o
-
- obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-v4l2.o
-
- ccflags-y += \
- -Idrivers/staging/vc04_services \
-+ -Idrivers/staging/vc04_services/vchiq-mmal \
- -D__VCCOREVER__=0x04000000
---- /dev/null
-+++ b/drivers/staging/vc04_services/vchiq-mmal/Kconfig
-@@ -0,0 +1,7 @@
-+config BCM2835_VCHIQ_MMAL
-+ tristate "BCM2835 MMAL VCHIQ service"
-+ depends on (ARCH_BCM2835 || COMPILE_TEST)
-+ select BCM2835_VCHIQ
-+ help
-+ Enables the MMAL API over VCHIQ as used for the
-+ majority of the multimedia services on VideoCore.
---- /dev/null
-+++ b/drivers/staging/vc04_services/vchiq-mmal/Makefile
-@@ -0,0 +1,8 @@
-+# SPDX-License-Identifier: GPL-2.0
-+bcm2835-mmal-vchiq-objs := mmal-vchiq.o
-+
-+obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += bcm2835-mmal-vchiq.o
-+
-+ccflags-y += \
-+ -Idrivers/staging/vc04_services \
-+ -D__VCCOREVER__=0x04000000
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
-+++ /dev/null
-@@ -1,1899 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0
--/*
-- * Broadcom BM2835 V4L2 driver
-- *
-- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-- *
-- * Authors: Vincent Sanders @ Collabora
-- * Dave Stevenson @ Broadcom
-- * Simon Mellor @ Broadcom
-- * Luke Diamand @ Broadcom
-- *
-- * V4L2 driver MMAL vchiq interface code
-- */
--
--#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
--
--#include <linux/errno.h>
--#include <linux/kernel.h>
--#include <linux/mutex.h>
--#include <linux/mm.h>
--#include <linux/slab.h>
--#include <linux/completion.h>
--#include <linux/vmalloc.h>
--#include <asm/cacheflush.h>
--#include <media/videobuf2-vmalloc.h>
--
--#include "mmal-common.h"
--#include "mmal-vchiq.h"
--#include "mmal-msg.h"
--
--#define USE_VCHIQ_ARM
--#include "interface/vchi/vchi.h"
--
--/* maximum number of components supported */
--#define VCHIQ_MMAL_MAX_COMPONENTS 4
--
--/*#define FULL_MSG_DUMP 1*/
--
--#ifdef DEBUG
--static const char *const msg_type_names[] = {
-- "UNKNOWN",
-- "QUIT",
-- "SERVICE_CLOSED",
-- "GET_VERSION",
-- "COMPONENT_CREATE",
-- "COMPONENT_DESTROY",
-- "COMPONENT_ENABLE",
-- "COMPONENT_DISABLE",
-- "PORT_INFO_GET",
-- "PORT_INFO_SET",
-- "PORT_ACTION",
-- "BUFFER_FROM_HOST",
-- "BUFFER_TO_HOST",
-- "GET_STATS",
-- "PORT_PARAMETER_SET",
-- "PORT_PARAMETER_GET",
-- "EVENT_TO_HOST",
-- "GET_CORE_STATS_FOR_PORT",
-- "OPAQUE_ALLOCATOR",
-- "CONSUME_MEM",
-- "LMK",
-- "OPAQUE_ALLOCATOR_DESC",
-- "DRM_GET_LHS32",
-- "DRM_GET_TIME",
-- "BUFFER_FROM_HOST_ZEROLEN",
-- "PORT_FLUSH",
-- "HOST_LOG",
--};
--#endif
--
--static const char *const port_action_type_names[] = {
-- "UNKNOWN",
-- "ENABLE",
-- "DISABLE",
-- "FLUSH",
-- "CONNECT",
-- "DISCONNECT",
-- "SET_REQUIREMENTS",
--};
--
--#if defined(DEBUG)
--#if defined(FULL_MSG_DUMP)
--#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
-- do { \
-- pr_debug(TITLE" type:%s(%d) length:%d\n", \
-- msg_type_names[(MSG)->h.type], \
-- (MSG)->h.type, (MSG_LEN)); \
-- print_hex_dump(KERN_DEBUG, "<<h: ", DUMP_PREFIX_OFFSET, \
-- 16, 4, (MSG), \
-- sizeof(struct mmal_msg_header), 1); \
-- print_hex_dump(KERN_DEBUG, "<<p: ", DUMP_PREFIX_OFFSET, \
-- 16, 4, \
-- ((u8 *)(MSG)) + sizeof(struct mmal_msg_header),\
-- (MSG_LEN) - sizeof(struct mmal_msg_header), 1); \
-- } while (0)
--#else
--#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
-- { \
-- pr_debug(TITLE" type:%s(%d) length:%d\n", \
-- msg_type_names[(MSG)->h.type], \
-- (MSG)->h.type, (MSG_LEN)); \
-- }
--#endif
--#else
--#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE)
--#endif
--
--struct vchiq_mmal_instance;
--
--/* normal message context */
--struct mmal_msg_context {
-- struct vchiq_mmal_instance *instance;
--
-- /* Index in the context_map idr so that we can find the
-- * mmal_msg_context again when servicing the VCHI reply.
-- */
-- int handle;
--
-- union {
-- struct {
-- /* work struct for buffer_cb callback */
-- struct work_struct work;
-- /* work struct for deferred callback */
-- struct work_struct buffer_to_host_work;
-- /* mmal instance */
-- struct vchiq_mmal_instance *instance;
-- /* mmal port */
-- struct vchiq_mmal_port *port;
-- /* actual buffer used to store bulk reply */
-- struct mmal_buffer *buffer;
-- /* amount of buffer used */
-- unsigned long buffer_used;
-- /* MMAL buffer flags */
-- u32 mmal_flags;
-- /* Presentation and Decode timestamps */
-- s64 pts;
-- s64 dts;
--
-- int status; /* context status */
--
-- } bulk; /* bulk data */
--
-- struct {
-- /* message handle to release */
-- VCHI_HELD_MSG_T msg_handle;
-- /* pointer to received message */
-- struct mmal_msg *msg;
-- /* received message length */
-- u32 msg_len;
-- /* completion upon reply */
-- struct completion cmplt;
-- } sync; /* synchronous response */
-- } u;
--
--};
--
--struct vchiq_mmal_instance {
-- VCHI_SERVICE_HANDLE_T handle;
--
-- /* ensure serialised access to service */
-- struct mutex vchiq_mutex;
--
-- /* vmalloc page to receive scratch bulk xfers into */
-- void *bulk_scratch;
--
-- struct idr context_map;
-- /* protect accesses to context_map */
-- struct mutex context_map_lock;
--
-- /* component to use next */
-- int component_idx;
-- struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
--
-- /* ordered workqueue to process all bulk operations */
-- struct workqueue_struct *bulk_wq;
--};
--
--static struct mmal_msg_context *
--get_msg_context(struct vchiq_mmal_instance *instance)
--{
-- struct mmal_msg_context *msg_context;
-- int handle;
--
-- /* todo: should this be allocated from a pool to avoid kzalloc */
-- msg_context = kzalloc(sizeof(*msg_context), GFP_KERNEL);
--
-- if (!msg_context)
-- return ERR_PTR(-ENOMEM);
--
-- /* Create an ID that will be passed along with our message so
-- * that when we service the VCHI reply, we can look up what
-- * message is being replied to.
-- */
-- mutex_lock(&instance->context_map_lock);
-- handle = idr_alloc(&instance->context_map, msg_context,
-- 0, 0, GFP_KERNEL);
-- mutex_unlock(&instance->context_map_lock);
--
-- if (handle < 0) {
-- kfree(msg_context);
-- return ERR_PTR(handle);
-- }
--
-- msg_context->instance = instance;
-- msg_context->handle = handle;
--
-- return msg_context;
--}
--
--static struct mmal_msg_context *
--lookup_msg_context(struct vchiq_mmal_instance *instance, int handle)
--{
-- return idr_find(&instance->context_map, handle);
--}
--
--static void
--release_msg_context(struct mmal_msg_context *msg_context)
--{
-- struct vchiq_mmal_instance *instance = msg_context->instance;
--
-- mutex_lock(&instance->context_map_lock);
-- idr_remove(&instance->context_map, msg_context->handle);
-- mutex_unlock(&instance->context_map_lock);
-- kfree(msg_context);
--}
--
--/* deals with receipt of event to host message */
--static void event_to_host_cb(struct vchiq_mmal_instance *instance,
-- struct mmal_msg *msg, u32 msg_len)
--{
-- pr_debug("unhandled event\n");
-- pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n",
-- msg->u.event_to_host.client_component,
-- msg->u.event_to_host.port_type,
-- msg->u.event_to_host.port_num,
-- msg->u.event_to_host.cmd, msg->u.event_to_host.length);
--}
--
--/* workqueue scheduled callback
-- *
-- * we do this because it is important we do not call any other vchiq
-- * sync calls from witin the message delivery thread
-- */
--static void buffer_work_cb(struct work_struct *work)
--{
-- struct mmal_msg_context *msg_context =
-- container_of(work, struct mmal_msg_context, u.bulk.work);
--
-- atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
--
-- msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
-- msg_context->u.bulk.port,
-- msg_context->u.bulk.status,
-- msg_context->u.bulk.buffer,
-- msg_context->u.bulk.buffer_used,
-- msg_context->u.bulk.mmal_flags,
-- msg_context->u.bulk.dts,
-- msg_context->u.bulk.pts);
--}
--
--/* workqueue scheduled callback to handle receiving buffers
-- *
-- * VCHI will allow up to 4 bulk receives to be scheduled before blocking.
-- * If we block in the service_callback context then we can't process the
-- * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked
-- * vchi_bulk_queue_receive() call to complete.
-- */
--static void buffer_to_host_work_cb(struct work_struct *work)
--{
-- struct mmal_msg_context *msg_context =
-- container_of(work, struct mmal_msg_context,
-- u.bulk.buffer_to_host_work);
-- struct vchiq_mmal_instance *instance = msg_context->instance;
-- unsigned long len = msg_context->u.bulk.buffer_used;
-- int ret;
--
-- if (!len)
-- /* Dummy receive to ensure the buffers remain in order */
-- len = 8;
-- /* queue the bulk submission */
-- vchi_service_use(instance->handle);
-- ret = vchi_bulk_queue_receive(instance->handle,
-- msg_context->u.bulk.buffer->buffer,
-- /* Actual receive needs to be a multiple
-- * of 4 bytes
-- */
-- (len + 3) & ~3,
-- VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
-- VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
-- msg_context);
--
-- vchi_service_release(instance->handle);
--
-- if (ret != 0)
-- pr_err("%s: ctx: %p, vchi_bulk_queue_receive failed %d\n",
-- __func__, msg_context, ret);
--}
--
--/* enqueue a bulk receive for a given message context */
--static int bulk_receive(struct vchiq_mmal_instance *instance,
-- struct mmal_msg *msg,
-- struct mmal_msg_context *msg_context)
--{
-- unsigned long rd_len;
--
-- rd_len = msg->u.buffer_from_host.buffer_header.length;
--
-- if (!msg_context->u.bulk.buffer) {
-- pr_err("bulk.buffer not configured - error in buffer_from_host\n");
--
-- /* todo: this is a serious error, we should never have
-- * committed a buffer_to_host operation to the mmal
-- * port without the buffer to back it up (underflow
-- * handling) and there is no obvious way to deal with
-- * this - how is the mmal servie going to react when
-- * we fail to do the xfer and reschedule a buffer when
-- * it arrives? perhaps a starved flag to indicate a
-- * waiting bulk receive?
-- */
--
-- return -EINVAL;
-- }
--
-- /* ensure we do not overrun the available buffer */
-- if (rd_len > msg_context->u.bulk.buffer->buffer_size) {
-- rd_len = msg_context->u.bulk.buffer->buffer_size;
-- pr_warn("short read as not enough receive buffer space\n");
-- /* todo: is this the correct response, what happens to
-- * the rest of the message data?
-- */
-- }
--
-- /* store length */
-- msg_context->u.bulk.buffer_used = rd_len;
-- msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
-- msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
--
-- queue_work(msg_context->instance->bulk_wq,
-- &msg_context->u.bulk.buffer_to_host_work);
--
-- return 0;
--}
--
--/* data in message, memcpy from packet into output buffer */
--static int inline_receive(struct vchiq_mmal_instance *instance,
-- struct mmal_msg *msg,
-- struct mmal_msg_context *msg_context)
--{
-- memcpy(msg_context->u.bulk.buffer->buffer,
-- msg->u.buffer_from_host.short_data,
-- msg->u.buffer_from_host.payload_in_message);
--
-- msg_context->u.bulk.buffer_used =
-- msg->u.buffer_from_host.payload_in_message;
--
-- return 0;
--}
--
--/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */
--static int
--buffer_from_host(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port, struct mmal_buffer *buf)
--{
-- struct mmal_msg_context *msg_context;
-- struct mmal_msg m;
-- int ret;
--
-- if (!port->enabled)
-- return -EINVAL;
--
-- pr_debug("instance:%p buffer:%p\n", instance->handle, buf);
--
-- /* get context */
-- if (!buf->msg_context) {
-- pr_err("%s: msg_context not allocated, buf %p\n", __func__,
-- buf);
-- return -EINVAL;
-- }
-- msg_context = buf->msg_context;
--
-- /* store bulk message context for when data arrives */
-- msg_context->u.bulk.instance = instance;
-- msg_context->u.bulk.port = port;
-- msg_context->u.bulk.buffer = buf;
-- msg_context->u.bulk.buffer_used = 0;
--
-- /* initialise work structure ready to schedule callback */
-- INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
-- INIT_WORK(&msg_context->u.bulk.buffer_to_host_work,
-- buffer_to_host_work_cb);
--
-- atomic_inc(&port->buffers_with_vpu);
--
-- /* prep the buffer from host message */
-- memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */
--
-- m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST;
-- m.h.magic = MMAL_MAGIC;
-- m.h.context = msg_context->handle;
-- m.h.status = 0;
--
-- /* drvbuf is our private data passed back */
-- m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC;
-- m.u.buffer_from_host.drvbuf.component_handle = port->component->handle;
-- m.u.buffer_from_host.drvbuf.port_handle = port->handle;
-- m.u.buffer_from_host.drvbuf.client_context = msg_context->handle;
--
-- /* buffer header */
-- m.u.buffer_from_host.buffer_header.cmd = 0;
-- m.u.buffer_from_host.buffer_header.data =
-- (u32)(unsigned long)buf->buffer;
-- m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
-- m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */
-- m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */
-- m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */
-- m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
-- m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
--
-- /* clear buffer type sepecific data */
-- memset(&m.u.buffer_from_host.buffer_header_type_specific, 0,
-- sizeof(m.u.buffer_from_host.buffer_header_type_specific));
--
-- /* no payload in message */
-- m.u.buffer_from_host.payload_in_message = 0;
--
-- vchi_service_use(instance->handle);
--
-- ret = vchi_queue_kernel_message(instance->handle,
-- &m,
-- sizeof(struct mmal_msg_header) +
-- sizeof(m.u.buffer_from_host));
--
-- vchi_service_release(instance->handle);
--
-- return ret;
--}
--
--/* deals with receipt of buffer to host message */
--static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
-- struct mmal_msg *msg, u32 msg_len)
--{
-- struct mmal_msg_context *msg_context;
-- u32 handle;
--
-- pr_debug("%s: instance:%p msg:%p msg_len:%d\n",
-- __func__, instance, msg, msg_len);
--
-- if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
-- handle = msg->u.buffer_from_host.drvbuf.client_context;
-- msg_context = lookup_msg_context(instance, handle);
--
-- if (!msg_context) {
-- pr_err("drvbuf.client_context(%u) is invalid\n",
-- handle);
-- return;
-- }
-- } else {
-- pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n");
-- return;
-- }
--
-- msg_context->u.bulk.mmal_flags =
-- msg->u.buffer_from_host.buffer_header.flags;
--
-- if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
-- /* message reception had an error */
-- pr_warn("error %d in reply\n", msg->h.status);
--
-- msg_context->u.bulk.status = msg->h.status;
--
-- } else if (msg->u.buffer_from_host.buffer_header.length == 0) {
-- /* empty buffer */
-- if (msg->u.buffer_from_host.buffer_header.flags &
-- MMAL_BUFFER_HEADER_FLAG_EOS) {
-- msg_context->u.bulk.status =
-- bulk_receive(instance, msg, msg_context);
-- if (msg_context->u.bulk.status == 0)
-- return; /* successful bulk submission, bulk
-- * completion will trigger callback
-- */
-- } else {
-- /* do callback with empty buffer - not EOS though */
-- msg_context->u.bulk.status = 0;
-- msg_context->u.bulk.buffer_used = 0;
-- }
-- } else if (msg->u.buffer_from_host.payload_in_message == 0) {
-- /* data is not in message, queue a bulk receive */
-- msg_context->u.bulk.status =
-- bulk_receive(instance, msg, msg_context);
-- if (msg_context->u.bulk.status == 0)
-- return; /* successful bulk submission, bulk
-- * completion will trigger callback
-- */
--
-- /* failed to submit buffer, this will end badly */
-- pr_err("error %d on bulk submission\n",
-- msg_context->u.bulk.status);
--
-- } else if (msg->u.buffer_from_host.payload_in_message <=
-- MMAL_VC_SHORT_DATA) {
-- /* data payload within message */
-- msg_context->u.bulk.status = inline_receive(instance, msg,
-- msg_context);
-- } else {
-- pr_err("message with invalid short payload\n");
--
-- /* signal error */
-- msg_context->u.bulk.status = -EINVAL;
-- msg_context->u.bulk.buffer_used =
-- msg->u.buffer_from_host.payload_in_message;
-- }
--
-- /* schedule the port callback */
-- schedule_work(&msg_context->u.bulk.work);
--}
--
--static void bulk_receive_cb(struct vchiq_mmal_instance *instance,
-- struct mmal_msg_context *msg_context)
--{
-- msg_context->u.bulk.status = 0;
--
-- /* schedule the port callback */
-- schedule_work(&msg_context->u.bulk.work);
--}
--
--static void bulk_abort_cb(struct vchiq_mmal_instance *instance,
-- struct mmal_msg_context *msg_context)
--{
-- pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context);
--
-- msg_context->u.bulk.status = -EINTR;
--
-- schedule_work(&msg_context->u.bulk.work);
--}
--
--/* incoming event service callback */
--static void service_callback(void *param,
-- const VCHI_CALLBACK_REASON_T reason,
-- void *bulk_ctx)
--{
-- struct vchiq_mmal_instance *instance = param;
-- int status;
-- u32 msg_len;
-- struct mmal_msg *msg;
-- VCHI_HELD_MSG_T msg_handle;
-- struct mmal_msg_context *msg_context;
--
-- if (!instance) {
-- pr_err("Message callback passed NULL instance\n");
-- return;
-- }
--
-- switch (reason) {
-- case VCHI_CALLBACK_MSG_AVAILABLE:
-- status = vchi_msg_hold(instance->handle, (void **)&msg,
-- &msg_len, VCHI_FLAGS_NONE, &msg_handle);
-- if (status) {
-- pr_err("Unable to dequeue a message (%d)\n", status);
-- break;
-- }
--
-- DBG_DUMP_MSG(msg, msg_len, "<<< reply message");
--
-- /* handling is different for buffer messages */
-- switch (msg->h.type) {
-- case MMAL_MSG_TYPE_BUFFER_FROM_HOST:
-- vchi_held_msg_release(&msg_handle);
-- break;
--
-- case MMAL_MSG_TYPE_EVENT_TO_HOST:
-- event_to_host_cb(instance, msg, msg_len);
-- vchi_held_msg_release(&msg_handle);
--
-- break;
--
-- case MMAL_MSG_TYPE_BUFFER_TO_HOST:
-- buffer_to_host_cb(instance, msg, msg_len);
-- vchi_held_msg_release(&msg_handle);
-- break;
--
-- default:
-- /* messages dependent on header context to complete */
-- if (!msg->h.context) {
-- pr_err("received message context was null!\n");
-- vchi_held_msg_release(&msg_handle);
-- break;
-- }
--
-- msg_context = lookup_msg_context(instance,
-- msg->h.context);
-- if (!msg_context) {
-- pr_err("received invalid message context %u!\n",
-- msg->h.context);
-- vchi_held_msg_release(&msg_handle);
-- break;
-- }
--
-- /* fill in context values */
-- msg_context->u.sync.msg_handle = msg_handle;
-- msg_context->u.sync.msg = msg;
-- msg_context->u.sync.msg_len = msg_len;
--
-- /* todo: should this check (completion_done()
-- * == 1) for no one waiting? or do we need a
-- * flag to tell us the completion has been
-- * interrupted so we can free the message and
-- * its context. This probably also solves the
-- * message arriving after interruption todo
-- * below
-- */
--
-- /* complete message so caller knows it happened */
-- complete(&msg_context->u.sync.cmplt);
-- break;
-- }
--
-- break;
--
-- case VCHI_CALLBACK_BULK_RECEIVED:
-- bulk_receive_cb(instance, bulk_ctx);
-- break;
--
-- case VCHI_CALLBACK_BULK_RECEIVE_ABORTED:
-- bulk_abort_cb(instance, bulk_ctx);
-- break;
--
-- case VCHI_CALLBACK_SERVICE_CLOSED:
-- /* TODO: consider if this requires action if received when
-- * driver is not explicitly closing the service
-- */
-- break;
--
-- default:
-- pr_err("Received unhandled message reason %d\n", reason);
-- break;
-- }
--}
--
--static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
-- struct mmal_msg *msg,
-- unsigned int payload_len,
-- struct mmal_msg **msg_out,
-- VCHI_HELD_MSG_T *msg_handle_out)
--{
-- struct mmal_msg_context *msg_context;
-- int ret;
-- unsigned long timeout;
--
-- /* payload size must not cause message to exceed max size */
-- if (payload_len >
-- (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
-- pr_err("payload length %d exceeds max:%d\n", payload_len,
-- (int)(MMAL_MSG_MAX_SIZE -
-- sizeof(struct mmal_msg_header)));
-- return -EINVAL;
-- }
--
-- msg_context = get_msg_context(instance);
-- if (IS_ERR(msg_context))
-- return PTR_ERR(msg_context);
--
-- init_completion(&msg_context->u.sync.cmplt);
--
-- msg->h.magic = MMAL_MAGIC;
-- msg->h.context = msg_context->handle;
-- msg->h.status = 0;
--
-- DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len),
-- ">>> sync message");
--
-- vchi_service_use(instance->handle);
--
-- ret = vchi_queue_kernel_message(instance->handle,
-- msg,
-- sizeof(struct mmal_msg_header) +
-- payload_len);
--
-- vchi_service_release(instance->handle);
--
-- if (ret) {
-- pr_err("error %d queuing message\n", ret);
-- release_msg_context(msg_context);
-- return ret;
-- }
--
-- timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt,
-- 3 * HZ);
-- if (timeout == 0) {
-- pr_err("timed out waiting for sync completion\n");
-- ret = -ETIME;
-- /* todo: what happens if the message arrives after aborting */
-- release_msg_context(msg_context);
-- return ret;
-- }
--
-- *msg_out = msg_context->u.sync.msg;
-- *msg_handle_out = msg_context->u.sync.msg_handle;
-- release_msg_context(msg_context);
--
-- return 0;
--}
--
--static void dump_port_info(struct vchiq_mmal_port *port)
--{
-- pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled);
--
-- pr_debug("buffer minimum num:%d size:%d align:%d\n",
-- port->minimum_buffer.num,
-- port->minimum_buffer.size, port->minimum_buffer.alignment);
--
-- pr_debug("buffer recommended num:%d size:%d align:%d\n",
-- port->recommended_buffer.num,
-- port->recommended_buffer.size,
-- port->recommended_buffer.alignment);
--
-- pr_debug("buffer current values num:%d size:%d align:%d\n",
-- port->current_buffer.num,
-- port->current_buffer.size, port->current_buffer.alignment);
--
-- pr_debug("elementary stream: type:%d encoding:0x%x variant:0x%x\n",
-- port->format.type,
-- port->format.encoding, port->format.encoding_variant);
--
-- pr_debug(" bitrate:%d flags:0x%x\n",
-- port->format.bitrate, port->format.flags);
--
-- if (port->format.type == MMAL_ES_TYPE_VIDEO) {
-- pr_debug
-- ("es video format: width:%d height:%d colourspace:0x%x\n",
-- port->es.video.width, port->es.video.height,
-- port->es.video.color_space);
--
-- pr_debug(" : crop xywh %d,%d,%d,%d\n",
-- port->es.video.crop.x,
-- port->es.video.crop.y,
-- port->es.video.crop.width, port->es.video.crop.height);
-- pr_debug(" : framerate %d/%d aspect %d/%d\n",
-- port->es.video.frame_rate.num,
-- port->es.video.frame_rate.den,
-- port->es.video.par.num, port->es.video.par.den);
-- }
--}
--
--static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p)
--{
-- /* todo do readonly fields need setting at all? */
-- p->type = port->type;
-- p->index = port->index;
-- p->index_all = 0;
-- p->is_enabled = port->enabled;
-- p->buffer_num_min = port->minimum_buffer.num;
-- p->buffer_size_min = port->minimum_buffer.size;
-- p->buffer_alignment_min = port->minimum_buffer.alignment;
-- p->buffer_num_recommended = port->recommended_buffer.num;
-- p->buffer_size_recommended = port->recommended_buffer.size;
--
-- /* only three writable fields in a port */
-- p->buffer_num = port->current_buffer.num;
-- p->buffer_size = port->current_buffer.size;
-- p->userdata = (u32)(unsigned long)port;
--}
--
--static int port_info_set(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port)
--{
-- int ret;
-- struct mmal_msg m;
-- struct mmal_msg *rmsg;
-- VCHI_HELD_MSG_T rmsg_handle;
--
-- pr_debug("setting port info port %p\n", port);
-- if (!port)
-- return -1;
-- dump_port_info(port);
--
-- m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET;
--
-- m.u.port_info_set.component_handle = port->component->handle;
-- m.u.port_info_set.port_type = port->type;
-- m.u.port_info_set.port_index = port->index;
--
-- port_to_mmal_msg(port, &m.u.port_info_set.port);
--
-- /* elementary stream format setup */
-- m.u.port_info_set.format.type = port->format.type;
-- m.u.port_info_set.format.encoding = port->format.encoding;
-- m.u.port_info_set.format.encoding_variant =
-- port->format.encoding_variant;
-- m.u.port_info_set.format.bitrate = port->format.bitrate;
-- m.u.port_info_set.format.flags = port->format.flags;
--
-- memcpy(&m.u.port_info_set.es, &port->es,
-- sizeof(union mmal_es_specific_format));
--
-- m.u.port_info_set.format.extradata_size = port->format.extradata_size;
-- memcpy(&m.u.port_info_set.extradata, port->format.extradata,
-- port->format.extradata_size);
--
-- ret = send_synchronous_mmal_msg(instance, &m,
-- sizeof(m.u.port_info_set),
-- &rmsg, &rmsg_handle);
-- if (ret)
-- return ret;
--
-- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) {
-- /* got an unexpected message type in reply */
-- ret = -EINVAL;
-- goto release_msg;
-- }
--
-- /* return operation status */
-- ret = -rmsg->u.port_info_get_reply.status;
--
-- pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret,
-- port->component->handle, port->handle);
--
--release_msg:
-- vchi_held_msg_release(&rmsg_handle);
--
-- return ret;
--}
--
--/* use port info get message to retrieve port information */
--static int port_info_get(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port)
--{
-- int ret;
-- struct mmal_msg m;
-- struct mmal_msg *rmsg;
-- VCHI_HELD_MSG_T rmsg_handle;
--
-- /* port info time */
-- m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET;
-- m.u.port_info_get.component_handle = port->component->handle;
-- m.u.port_info_get.port_type = port->type;
-- m.u.port_info_get.index = port->index;
--
-- ret = send_synchronous_mmal_msg(instance, &m,
-- sizeof(m.u.port_info_get),
-- &rmsg, &rmsg_handle);
-- if (ret)
-- return ret;
--
-- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) {
-- /* got an unexpected message type in reply */
-- ret = -EINVAL;
-- goto release_msg;
-- }
--
-- /* return operation status */
-- ret = -rmsg->u.port_info_get_reply.status;
-- if (ret != MMAL_MSG_STATUS_SUCCESS)
-- goto release_msg;
--
-- if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
-- port->enabled = false;
-- else
-- port->enabled = true;
--
-- /* copy the values out of the message */
-- port->handle = rmsg->u.port_info_get_reply.port_handle;
--
-- /* port type and index cached to use on port info set because
-- * it does not use a port handle
-- */
-- port->type = rmsg->u.port_info_get_reply.port_type;
-- port->index = rmsg->u.port_info_get_reply.port_index;
--
-- port->minimum_buffer.num =
-- rmsg->u.port_info_get_reply.port.buffer_num_min;
-- port->minimum_buffer.size =
-- rmsg->u.port_info_get_reply.port.buffer_size_min;
-- port->minimum_buffer.alignment =
-- rmsg->u.port_info_get_reply.port.buffer_alignment_min;
--
-- port->recommended_buffer.alignment =
-- rmsg->u.port_info_get_reply.port.buffer_alignment_min;
-- port->recommended_buffer.num =
-- rmsg->u.port_info_get_reply.port.buffer_num_recommended;
--
-- port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num;
-- port->current_buffer.size =
-- rmsg->u.port_info_get_reply.port.buffer_size;
--
-- /* stream format */
-- port->format.type = rmsg->u.port_info_get_reply.format.type;
-- port->format.encoding = rmsg->u.port_info_get_reply.format.encoding;
-- port->format.encoding_variant =
-- rmsg->u.port_info_get_reply.format.encoding_variant;
-- port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate;
-- port->format.flags = rmsg->u.port_info_get_reply.format.flags;
--
-- /* elementary stream format */
-- memcpy(&port->es,
-- &rmsg->u.port_info_get_reply.es,
-- sizeof(union mmal_es_specific_format));
-- port->format.es = &port->es;
--
-- port->format.extradata_size =
-- rmsg->u.port_info_get_reply.format.extradata_size;
-- memcpy(port->format.extradata,
-- rmsg->u.port_info_get_reply.extradata,
-- port->format.extradata_size);
--
-- pr_debug("received port info\n");
-- dump_port_info(port);
--
--release_msg:
--
-- pr_debug("%s:result:%d component:0x%x port:%d\n",
-- __func__, ret, port->component->handle, port->handle);
--
-- vchi_held_msg_release(&rmsg_handle);
--
-- return ret;
--}
--
--/* create comonent on vc */
--static int create_component(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_component *component,
-- const char *name)
--{
-- int ret;
-- struct mmal_msg m;
-- struct mmal_msg *rmsg;
-- VCHI_HELD_MSG_T rmsg_handle;
--
-- /* build component create message */
-- m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE;
-- m.u.component_create.client_component = (u32)(unsigned long)component;
-- strncpy(m.u.component_create.name, name,
-- sizeof(m.u.component_create.name));
--
-- ret = send_synchronous_mmal_msg(instance, &m,
-- sizeof(m.u.component_create),
-- &rmsg, &rmsg_handle);
-- if (ret)
-- return ret;
--
-- if (rmsg->h.type != m.h.type) {
-- /* got an unexpected message type in reply */
-- ret = -EINVAL;
-- goto release_msg;
-- }
--
-- ret = -rmsg->u.component_create_reply.status;
-- if (ret != MMAL_MSG_STATUS_SUCCESS)
-- goto release_msg;
--
-- /* a valid component response received */
-- component->handle = rmsg->u.component_create_reply.component_handle;
-- component->inputs = rmsg->u.component_create_reply.input_num;
-- component->outputs = rmsg->u.component_create_reply.output_num;
-- component->clocks = rmsg->u.component_create_reply.clock_num;
--
-- pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n",
-- component->handle,
-- component->inputs, component->outputs, component->clocks);
--
--release_msg:
-- vchi_held_msg_release(&rmsg_handle);
--
-- return ret;
--}
--
--/* destroys a component on vc */
--static int destroy_component(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_component *component)
--{
-- int ret;
-- struct mmal_msg m;
-- struct mmal_msg *rmsg;
-- VCHI_HELD_MSG_T rmsg_handle;
--
-- m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY;
-- m.u.component_destroy.component_handle = component->handle;
--
-- ret = send_synchronous_mmal_msg(instance, &m,
-- sizeof(m.u.component_destroy),
-- &rmsg, &rmsg_handle);
-- if (ret)
-- return ret;
--
-- if (rmsg->h.type != m.h.type) {
-- /* got an unexpected message type in reply */
-- ret = -EINVAL;
-- goto release_msg;
-- }
--
-- ret = -rmsg->u.component_destroy_reply.status;
--
--release_msg:
--
-- vchi_held_msg_release(&rmsg_handle);
--
-- return ret;
--}
--
--/* enable a component on vc */
--static int enable_component(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_component *component)
--{
-- int ret;
-- struct mmal_msg m;
-- struct mmal_msg *rmsg;
-- VCHI_HELD_MSG_T rmsg_handle;
--
-- m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE;
-- m.u.component_enable.component_handle = component->handle;
--
-- ret = send_synchronous_mmal_msg(instance, &m,
-- sizeof(m.u.component_enable),
-- &rmsg, &rmsg_handle);
-- if (ret)
-- return ret;
--
-- if (rmsg->h.type != m.h.type) {
-- /* got an unexpected message type in reply */
-- ret = -EINVAL;
-- goto release_msg;
-- }
--
-- ret = -rmsg->u.component_enable_reply.status;
--
--release_msg:
-- vchi_held_msg_release(&rmsg_handle);
--
-- return ret;
--}
--
--/* disable a component on vc */
--static int disable_component(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_component *component)
--{
-- int ret;
-- struct mmal_msg m;
-- struct mmal_msg *rmsg;
-- VCHI_HELD_MSG_T rmsg_handle;
--
-- m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE;
-- m.u.component_disable.component_handle = component->handle;
--
-- ret = send_synchronous_mmal_msg(instance, &m,
-- sizeof(m.u.component_disable),
-- &rmsg, &rmsg_handle);
-- if (ret)
-- return ret;
--
-- if (rmsg->h.type != m.h.type) {
-- /* got an unexpected message type in reply */
-- ret = -EINVAL;
-- goto release_msg;
-- }
--
-- ret = -rmsg->u.component_disable_reply.status;
--
--release_msg:
--
-- vchi_held_msg_release(&rmsg_handle);
--
-- return ret;
--}
--
--/* get version of mmal implementation */
--static int get_version(struct vchiq_mmal_instance *instance,
-- u32 *major_out, u32 *minor_out)
--{
-- int ret;
-- struct mmal_msg m;
-- struct mmal_msg *rmsg;
-- VCHI_HELD_MSG_T rmsg_handle;
--
-- m.h.type = MMAL_MSG_TYPE_GET_VERSION;
--
-- ret = send_synchronous_mmal_msg(instance, &m,
-- sizeof(m.u.version),
-- &rmsg, &rmsg_handle);
-- if (ret)
-- return ret;
--
-- if (rmsg->h.type != m.h.type) {
-- /* got an unexpected message type in reply */
-- ret = -EINVAL;
-- goto release_msg;
-- }
--
-- *major_out = rmsg->u.version.major;
-- *minor_out = rmsg->u.version.minor;
--
--release_msg:
-- vchi_held_msg_release(&rmsg_handle);
--
-- return ret;
--}
--
--/* do a port action with a port as a parameter */
--static int port_action_port(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- enum mmal_msg_port_action_type action_type)
--{
-- int ret;
-- struct mmal_msg m;
-- struct mmal_msg *rmsg;
-- VCHI_HELD_MSG_T rmsg_handle;
--
-- m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
-- m.u.port_action_port.component_handle = port->component->handle;
-- m.u.port_action_port.port_handle = port->handle;
-- m.u.port_action_port.action = action_type;
--
-- port_to_mmal_msg(port, &m.u.port_action_port.port);
--
-- ret = send_synchronous_mmal_msg(instance, &m,
-- sizeof(m.u.port_action_port),
-- &rmsg, &rmsg_handle);
-- if (ret)
-- return ret;
--
-- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
-- /* got an unexpected message type in reply */
-- ret = -EINVAL;
-- goto release_msg;
-- }
--
-- ret = -rmsg->u.port_action_reply.status;
--
-- pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n",
-- __func__,
-- ret, port->component->handle, port->handle,
-- port_action_type_names[action_type], action_type);
--
--release_msg:
-- vchi_held_msg_release(&rmsg_handle);
--
-- return ret;
--}
--
--/* do a port action with handles as parameters */
--static int port_action_handle(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- enum mmal_msg_port_action_type action_type,
-- u32 connect_component_handle,
-- u32 connect_port_handle)
--{
-- int ret;
-- struct mmal_msg m;
-- struct mmal_msg *rmsg;
-- VCHI_HELD_MSG_T rmsg_handle;
--
-- m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
--
-- m.u.port_action_handle.component_handle = port->component->handle;
-- m.u.port_action_handle.port_handle = port->handle;
-- m.u.port_action_handle.action = action_type;
--
-- m.u.port_action_handle.connect_component_handle =
-- connect_component_handle;
-- m.u.port_action_handle.connect_port_handle = connect_port_handle;
--
-- ret = send_synchronous_mmal_msg(instance, &m,
-- sizeof(m.u.port_action_handle),
-- &rmsg, &rmsg_handle);
-- if (ret)
-- return ret;
--
-- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
-- /* got an unexpected message type in reply */
-- ret = -EINVAL;
-- goto release_msg;
-- }
--
-- ret = -rmsg->u.port_action_reply.status;
--
-- pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d) connect component:0x%x connect port:%d\n",
-- __func__,
-- ret, port->component->handle, port->handle,
-- port_action_type_names[action_type],
-- action_type, connect_component_handle, connect_port_handle);
--
--release_msg:
-- vchi_held_msg_release(&rmsg_handle);
--
-- return ret;
--}
--
--static int port_parameter_set(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- u32 parameter_id, void *value, u32 value_size)
--{
-- int ret;
-- struct mmal_msg m;
-- struct mmal_msg *rmsg;
-- VCHI_HELD_MSG_T rmsg_handle;
--
-- m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET;
--
-- m.u.port_parameter_set.component_handle = port->component->handle;
-- m.u.port_parameter_set.port_handle = port->handle;
-- m.u.port_parameter_set.id = parameter_id;
-- m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size;
-- memcpy(&m.u.port_parameter_set.value, value, value_size);
--
-- ret = send_synchronous_mmal_msg(instance, &m,
-- (4 * sizeof(u32)) + value_size,
-- &rmsg, &rmsg_handle);
-- if (ret)
-- return ret;
--
-- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) {
-- /* got an unexpected message type in reply */
-- ret = -EINVAL;
-- goto release_msg;
-- }
--
-- ret = -rmsg->u.port_parameter_set_reply.status;
--
-- pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n",
-- __func__,
-- ret, port->component->handle, port->handle, parameter_id);
--
--release_msg:
-- vchi_held_msg_release(&rmsg_handle);
--
-- return ret;
--}
--
--static int port_parameter_get(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- u32 parameter_id, void *value, u32 *value_size)
--{
-- int ret;
-- struct mmal_msg m;
-- struct mmal_msg *rmsg;
-- VCHI_HELD_MSG_T rmsg_handle;
--
-- m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET;
--
-- m.u.port_parameter_get.component_handle = port->component->handle;
-- m.u.port_parameter_get.port_handle = port->handle;
-- m.u.port_parameter_get.id = parameter_id;
-- m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size;
--
-- ret = send_synchronous_mmal_msg(instance, &m,
-- sizeof(struct
-- mmal_msg_port_parameter_get),
-- &rmsg, &rmsg_handle);
-- if (ret)
-- return ret;
--
-- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) {
-- /* got an unexpected message type in reply */
-- pr_err("Incorrect reply type %d\n", rmsg->h.type);
-- ret = -EINVAL;
-- goto release_msg;
-- }
--
-- ret = -rmsg->u.port_parameter_get_reply.status;
-- /* port_parameter_get_reply.size includes the header,
-- * whilst *value_size doesn't.
-- */
-- rmsg->u.port_parameter_get_reply.size -= (2 * sizeof(u32));
--
-- if (ret || rmsg->u.port_parameter_get_reply.size > *value_size) {
-- /* Copy only as much as we have space for
-- * but report true size of parameter
-- */
-- memcpy(value, &rmsg->u.port_parameter_get_reply.value,
-- *value_size);
-- *value_size = rmsg->u.port_parameter_get_reply.size;
-- } else {
-- memcpy(value, &rmsg->u.port_parameter_get_reply.value,
-- rmsg->u.port_parameter_get_reply.size);
-- }
--
-- pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
-- ret, port->component->handle, port->handle, parameter_id);
--
--release_msg:
-- vchi_held_msg_release(&rmsg_handle);
--
-- return ret;
--}
--
--/* disables a port and drains buffers from it */
--static int port_disable(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port)
--{
-- int ret;
-- struct list_head *q, *buf_head;
-- unsigned long flags = 0;
--
-- if (!port->enabled)
-- return 0;
--
-- port->enabled = false;
--
-- ret = port_action_port(instance, port,
-- MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
-- if (ret == 0) {
-- /*
-- * Drain all queued buffers on port. This should only
-- * apply to buffers that have been queued before the port
-- * has been enabled. If the port has been enabled and buffers
-- * passed, then the buffers should have been removed from this
-- * list, and we should get the relevant callbacks via VCHIQ
-- * to release the buffers.
-- */
-- spin_lock_irqsave(&port->slock, flags);
--
-- list_for_each_safe(buf_head, q, &port->buffers) {
-- struct mmal_buffer *mmalbuf;
--
-- mmalbuf = list_entry(buf_head, struct mmal_buffer,
-- list);
-- list_del(buf_head);
-- if (port->buffer_cb)
-- port->buffer_cb(instance,
-- port, 0, mmalbuf, 0, 0,
-- MMAL_TIME_UNKNOWN,
-- MMAL_TIME_UNKNOWN);
-- }
--
-- spin_unlock_irqrestore(&port->slock, flags);
--
-- ret = port_info_get(instance, port);
-- }
--
-- return ret;
--}
--
--/* enable a port */
--static int port_enable(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port)
--{
-- unsigned int hdr_count;
-- struct list_head *q, *buf_head;
-- int ret;
--
-- if (port->enabled)
-- return 0;
--
-- ret = port_action_port(instance, port,
-- MMAL_MSG_PORT_ACTION_TYPE_ENABLE);
-- if (ret)
-- goto done;
--
-- port->enabled = true;
--
-- if (port->buffer_cb) {
-- /* send buffer headers to videocore */
-- hdr_count = 1;
-- list_for_each_safe(buf_head, q, &port->buffers) {
-- struct mmal_buffer *mmalbuf;
--
-- mmalbuf = list_entry(buf_head, struct mmal_buffer,
-- list);
-- ret = buffer_from_host(instance, port, mmalbuf);
-- if (ret)
-- goto done;
--
-- list_del(buf_head);
-- hdr_count++;
-- if (hdr_count > port->current_buffer.num)
-- break;
-- }
-- }
--
-- ret = port_info_get(instance, port);
--
--done:
-- return ret;
--}
--
--/* ------------------------------------------------------------------
-- * Exported API
-- *------------------------------------------------------------------
-- */
--
--int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port)
--{
-- int ret;
--
-- if (mutex_lock_interruptible(&instance->vchiq_mutex))
-- return -EINTR;
--
-- ret = port_info_set(instance, port);
-- if (ret)
-- goto release_unlock;
--
-- /* read what has actually been set */
-- ret = port_info_get(instance, port);
--
--release_unlock:
-- mutex_unlock(&instance->vchiq_mutex);
--
-- return ret;
--}
--
--int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- u32 parameter, void *value, u32 value_size)
--{
-- int ret;
--
-- if (mutex_lock_interruptible(&instance->vchiq_mutex))
-- return -EINTR;
--
-- ret = port_parameter_set(instance, port, parameter, value, value_size);
--
-- mutex_unlock(&instance->vchiq_mutex);
--
-- return ret;
--}
--
--int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- u32 parameter, void *value, u32 *value_size)
--{
-- int ret;
--
-- if (mutex_lock_interruptible(&instance->vchiq_mutex))
-- return -EINTR;
--
-- ret = port_parameter_get(instance, port, parameter, value, value_size);
--
-- mutex_unlock(&instance->vchiq_mutex);
--
-- return ret;
--}
--
--/* enable a port
-- *
-- * enables a port and queues buffers for satisfying callbacks if we
-- * provide a callback handler
-- */
--int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- vchiq_mmal_buffer_cb buffer_cb)
--{
-- int ret;
--
-- if (mutex_lock_interruptible(&instance->vchiq_mutex))
-- return -EINTR;
--
-- /* already enabled - noop */
-- if (port->enabled) {
-- ret = 0;
-- goto unlock;
-- }
--
-- port->buffer_cb = buffer_cb;
--
-- ret = port_enable(instance, port);
--
--unlock:
-- mutex_unlock(&instance->vchiq_mutex);
--
-- return ret;
--}
--
--int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port)
--{
-- int ret;
--
-- if (mutex_lock_interruptible(&instance->vchiq_mutex))
-- return -EINTR;
--
-- if (!port->enabled) {
-- mutex_unlock(&instance->vchiq_mutex);
-- return 0;
-- }
--
-- ret = port_disable(instance, port);
--
-- mutex_unlock(&instance->vchiq_mutex);
--
-- return ret;
--}
--
--/* ports will be connected in a tunneled manner so data buffers
-- * are not handled by client.
-- */
--int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *src,
-- struct vchiq_mmal_port *dst)
--{
-- int ret;
--
-- if (mutex_lock_interruptible(&instance->vchiq_mutex))
-- return -EINTR;
--
-- /* disconnect ports if connected */
-- if (src->connected) {
-- ret = port_disable(instance, src);
-- if (ret) {
-- pr_err("failed disabling src port(%d)\n", ret);
-- goto release_unlock;
-- }
--
-- /* do not need to disable the destination port as they
-- * are connected and it is done automatically
-- */
--
-- ret = port_action_handle(instance, src,
-- MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT,
-- src->connected->component->handle,
-- src->connected->handle);
-- if (ret < 0) {
-- pr_err("failed disconnecting src port\n");
-- goto release_unlock;
-- }
-- src->connected->enabled = false;
-- src->connected = NULL;
-- }
--
-- if (!dst) {
-- /* do not make new connection */
-- ret = 0;
-- pr_debug("not making new connection\n");
-- goto release_unlock;
-- }
--
-- /* copy src port format to dst */
-- dst->format.encoding = src->format.encoding;
-- dst->es.video.width = src->es.video.width;
-- dst->es.video.height = src->es.video.height;
-- dst->es.video.crop.x = src->es.video.crop.x;
-- dst->es.video.crop.y = src->es.video.crop.y;
-- dst->es.video.crop.width = src->es.video.crop.width;
-- dst->es.video.crop.height = src->es.video.crop.height;
-- dst->es.video.frame_rate.num = src->es.video.frame_rate.num;
-- dst->es.video.frame_rate.den = src->es.video.frame_rate.den;
--
-- /* set new format */
-- ret = port_info_set(instance, dst);
-- if (ret) {
-- pr_debug("setting port info failed\n");
-- goto release_unlock;
-- }
--
-- /* read what has actually been set */
-- ret = port_info_get(instance, dst);
-- if (ret) {
-- pr_debug("read back port info failed\n");
-- goto release_unlock;
-- }
--
-- /* connect two ports together */
-- ret = port_action_handle(instance, src,
-- MMAL_MSG_PORT_ACTION_TYPE_CONNECT,
-- dst->component->handle, dst->handle);
-- if (ret < 0) {
-- pr_debug("connecting port %d:%d to %d:%d failed\n",
-- src->component->handle, src->handle,
-- dst->component->handle, dst->handle);
-- goto release_unlock;
-- }
-- src->connected = dst;
--
--release_unlock:
--
-- mutex_unlock(&instance->vchiq_mutex);
--
-- return ret;
--}
--
--int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- struct mmal_buffer *buffer)
--{
-- unsigned long flags = 0;
-- int ret;
--
-- ret = buffer_from_host(instance, port, buffer);
-- if (ret == -EINVAL) {
-- /* Port is disabled. Queue for when it is enabled. */
-- spin_lock_irqsave(&port->slock, flags);
-- list_add_tail(&buffer->list, &port->buffers);
-- spin_unlock_irqrestore(&port->slock, flags);
-- }
--
-- return 0;
--}
--
--int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance,
-- struct mmal_buffer *buf)
--{
-- struct mmal_msg_context *msg_context = get_msg_context(instance);
--
-- if (IS_ERR(msg_context))
-- return (PTR_ERR(msg_context));
--
-- buf->msg_context = msg_context;
-- return 0;
--}
--
--int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf)
--{
-- struct mmal_msg_context *msg_context = buf->msg_context;
--
-- if (msg_context)
-- release_msg_context(msg_context);
-- buf->msg_context = NULL;
--
-- return 0;
--}
--
--/* Initialise a mmal component and its ports
-- *
-- */
--int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance,
-- const char *name,
-- struct vchiq_mmal_component **component_out)
--{
-- int ret;
-- int idx; /* port index */
-- struct vchiq_mmal_component *component;
--
-- if (mutex_lock_interruptible(&instance->vchiq_mutex))
-- return -EINTR;
--
-- if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) {
-- ret = -EINVAL; /* todo is this correct error? */
-- goto unlock;
-- }
--
-- component = &instance->component[instance->component_idx];
--
-- ret = create_component(instance, component, name);
-- if (ret < 0) {
-- pr_err("%s: failed to create component %d (Not enough GPU mem?)\n",
-- __func__, ret);
-- goto unlock;
-- }
--
-- /* ports info needs gathering */
-- component->control.type = MMAL_PORT_TYPE_CONTROL;
-- component->control.index = 0;
-- component->control.component = component;
-- spin_lock_init(&component->control.slock);
-- INIT_LIST_HEAD(&component->control.buffers);
-- ret = port_info_get(instance, &component->control);
-- if (ret < 0)
-- goto release_component;
--
-- for (idx = 0; idx < component->inputs; idx++) {
-- component->input[idx].type = MMAL_PORT_TYPE_INPUT;
-- component->input[idx].index = idx;
-- component->input[idx].component = component;
-- spin_lock_init(&component->input[idx].slock);
-- INIT_LIST_HEAD(&component->input[idx].buffers);
-- ret = port_info_get(instance, &component->input[idx]);
-- if (ret < 0)
-- goto release_component;
-- }
--
-- for (idx = 0; idx < component->outputs; idx++) {
-- component->output[idx].type = MMAL_PORT_TYPE_OUTPUT;
-- component->output[idx].index = idx;
-- component->output[idx].component = component;
-- spin_lock_init(&component->output[idx].slock);
-- INIT_LIST_HEAD(&component->output[idx].buffers);
-- ret = port_info_get(instance, &component->output[idx]);
-- if (ret < 0)
-- goto release_component;
-- }
--
-- for (idx = 0; idx < component->clocks; idx++) {
-- component->clock[idx].type = MMAL_PORT_TYPE_CLOCK;
-- component->clock[idx].index = idx;
-- component->clock[idx].component = component;
-- spin_lock_init(&component->clock[idx].slock);
-- INIT_LIST_HEAD(&component->clock[idx].buffers);
-- ret = port_info_get(instance, &component->clock[idx]);
-- if (ret < 0)
-- goto release_component;
-- }
--
-- instance->component_idx++;
--
-- *component_out = component;
--
-- mutex_unlock(&instance->vchiq_mutex);
--
-- return 0;
--
--release_component:
-- destroy_component(instance, component);
--unlock:
-- mutex_unlock(&instance->vchiq_mutex);
--
-- return ret;
--}
--
--/*
-- * cause a mmal component to be destroyed
-- */
--int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_component *component)
--{
-- int ret;
--
-- if (mutex_lock_interruptible(&instance->vchiq_mutex))
-- return -EINTR;
--
-- if (component->enabled)
-- ret = disable_component(instance, component);
--
-- ret = destroy_component(instance, component);
--
-- mutex_unlock(&instance->vchiq_mutex);
--
-- return ret;
--}
--
--/*
-- * cause a mmal component to be enabled
-- */
--int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_component *component)
--{
-- int ret;
--
-- if (mutex_lock_interruptible(&instance->vchiq_mutex))
-- return -EINTR;
--
-- if (component->enabled) {
-- mutex_unlock(&instance->vchiq_mutex);
-- return 0;
-- }
--
-- ret = enable_component(instance, component);
-- if (ret == 0)
-- component->enabled = true;
--
-- mutex_unlock(&instance->vchiq_mutex);
--
-- return ret;
--}
--
--/*
-- * cause a mmal component to be enabled
-- */
--int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_component *component)
--{
-- int ret;
--
-- if (mutex_lock_interruptible(&instance->vchiq_mutex))
-- return -EINTR;
--
-- if (!component->enabled) {
-- mutex_unlock(&instance->vchiq_mutex);
-- return 0;
-- }
--
-- ret = disable_component(instance, component);
-- if (ret == 0)
-- component->enabled = false;
--
-- mutex_unlock(&instance->vchiq_mutex);
--
-- return ret;
--}
--
--int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
-- u32 *major_out, u32 *minor_out)
--{
-- int ret;
--
-- if (mutex_lock_interruptible(&instance->vchiq_mutex))
-- return -EINTR;
--
-- ret = get_version(instance, major_out, minor_out);
--
-- mutex_unlock(&instance->vchiq_mutex);
--
-- return ret;
--}
--
--int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
--{
-- int status = 0;
--
-- if (!instance)
-- return -EINVAL;
--
-- if (mutex_lock_interruptible(&instance->vchiq_mutex))
-- return -EINTR;
--
-- vchi_service_use(instance->handle);
--
-- status = vchi_service_close(instance->handle);
-- if (status != 0)
-- pr_err("mmal-vchiq: VCHIQ close failed\n");
--
-- mutex_unlock(&instance->vchiq_mutex);
--
-- flush_workqueue(instance->bulk_wq);
-- destroy_workqueue(instance->bulk_wq);
--
-- vfree(instance->bulk_scratch);
--
-- idr_destroy(&instance->context_map);
--
-- kfree(instance);
--
-- return status;
--}
--
--int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
--{
-- int status;
-- struct vchiq_mmal_instance *instance;
-- static VCHI_CONNECTION_T *vchi_connection;
-- static VCHI_INSTANCE_T vchi_instance;
-- SERVICE_CREATION_T params = {
-- .version = VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER),
-- .service_id = VC_MMAL_SERVER_NAME,
-- .connection = vchi_connection,
-- .rx_fifo_size = 0,
-- .tx_fifo_size = 0,
-- .callback = service_callback,
-- .callback_param = NULL,
-- .want_unaligned_bulk_rx = 1,
-- .want_unaligned_bulk_tx = 1,
-- .want_crc = 0
-- };
--
-- /* compile time checks to ensure structure size as they are
-- * directly (de)serialised from memory.
-- */
--
-- /* ensure the header structure has packed to the correct size */
-- BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24);
--
-- /* ensure message structure does not exceed maximum length */
-- BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE);
--
-- /* mmal port struct is correct size */
-- BUILD_BUG_ON(sizeof(struct mmal_port) != 64);
--
-- /* create a vchi instance */
-- status = vchi_initialise(&vchi_instance);
-- if (status) {
-- pr_err("Failed to initialise VCHI instance (status=%d)\n",
-- status);
-- return -EIO;
-- }
--
-- status = vchi_connect(NULL, 0, vchi_instance);
-- if (status) {
-- pr_err("Failed to connect VCHI instance (status=%d)\n", status);
-- return -EIO;
-- }
--
-- instance = kzalloc(sizeof(*instance), GFP_KERNEL);
--
-- if (!instance)
-- return -ENOMEM;
--
-- mutex_init(&instance->vchiq_mutex);
--
-- instance->bulk_scratch = vmalloc(PAGE_SIZE);
--
-- mutex_init(&instance->context_map_lock);
-- idr_init_base(&instance->context_map, 1);
--
-- params.callback_param = instance;
--
-- instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq",
-- WQ_MEM_RECLAIM);
-- if (!instance->bulk_wq)
-- goto err_free;
--
-- status = vchi_service_open(vchi_instance, ¶ms, &instance->handle);
-- if (status) {
-- pr_err("Failed to open VCHI service connection (status=%d)\n",
-- status);
-- goto err_close_services;
-- }
--
-- vchi_service_release(instance->handle);
--
-- *out_instance = instance;
--
-- return 0;
--
--err_close_services:
-- vchi_service_close(instance->handle);
-- destroy_workqueue(instance->bulk_wq);
--err_free:
-- vfree(instance->bulk_scratch);
-- kfree(instance);
-- return -ENODEV;
--}
---- /dev/null
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -0,0 +1,1921 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
-+ *
-+ * V4L2 driver MMAL vchiq interface code
-+ */
-+
-+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-+
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/mutex.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/completion.h>
-+#include <linux/vmalloc.h>
-+#include <asm/cacheflush.h>
-+#include <media/videobuf2-vmalloc.h>
-+
-+#include "mmal-common.h"
-+#include "mmal-vchiq.h"
-+#include "mmal-msg.h"
-+
-+#define USE_VCHIQ_ARM
-+#include "interface/vchi/vchi.h"
-+
-+MODULE_DESCRIPTION("BCM2835 MMAL VCHIQ interface");
-+MODULE_LICENSE("GPL");
-+MODULE_VERSION("0.0.1");
-+
-+/* maximum number of components supported */
-+#define VCHIQ_MMAL_MAX_COMPONENTS 4
-+
-+/*#define FULL_MSG_DUMP 1*/
-+
-+#ifdef DEBUG
-+static const char *const msg_type_names[] = {
-+ "UNKNOWN",
-+ "QUIT",
-+ "SERVICE_CLOSED",
-+ "GET_VERSION",
-+ "COMPONENT_CREATE",
-+ "COMPONENT_DESTROY",
-+ "COMPONENT_ENABLE",
-+ "COMPONENT_DISABLE",
-+ "PORT_INFO_GET",
-+ "PORT_INFO_SET",
-+ "PORT_ACTION",
-+ "BUFFER_FROM_HOST",
-+ "BUFFER_TO_HOST",
-+ "GET_STATS",
-+ "PORT_PARAMETER_SET",
-+ "PORT_PARAMETER_GET",
-+ "EVENT_TO_HOST",
-+ "GET_CORE_STATS_FOR_PORT",
-+ "OPAQUE_ALLOCATOR",
-+ "CONSUME_MEM",
-+ "LMK",
-+ "OPAQUE_ALLOCATOR_DESC",
-+ "DRM_GET_LHS32",
-+ "DRM_GET_TIME",
-+ "BUFFER_FROM_HOST_ZEROLEN",
-+ "PORT_FLUSH",
-+ "HOST_LOG",
-+};
-+#endif
-+
-+static const char *const port_action_type_names[] = {
-+ "UNKNOWN",
-+ "ENABLE",
-+ "DISABLE",
-+ "FLUSH",
-+ "CONNECT",
-+ "DISCONNECT",
-+ "SET_REQUIREMENTS",
-+};
-+
-+#if defined(DEBUG)
-+#if defined(FULL_MSG_DUMP)
-+#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
-+ do { \
-+ pr_debug(TITLE" type:%s(%d) length:%d\n", \
-+ msg_type_names[(MSG)->h.type], \
-+ (MSG)->h.type, (MSG_LEN)); \
-+ print_hex_dump(KERN_DEBUG, "<<h: ", DUMP_PREFIX_OFFSET, \
-+ 16, 4, (MSG), \
-+ sizeof(struct mmal_msg_header), 1); \
-+ print_hex_dump(KERN_DEBUG, "<<p: ", DUMP_PREFIX_OFFSET, \
-+ 16, 4, \
-+ ((u8 *)(MSG)) + sizeof(struct mmal_msg_header),\
-+ (MSG_LEN) - sizeof(struct mmal_msg_header), 1); \
-+ } while (0)
-+#else
-+#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
-+ { \
-+ pr_debug(TITLE" type:%s(%d) length:%d\n", \
-+ msg_type_names[(MSG)->h.type], \
-+ (MSG)->h.type, (MSG_LEN)); \
-+ }
-+#endif
-+#else
-+#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE)
-+#endif
-+
-+struct vchiq_mmal_instance;
-+
-+/* normal message context */
-+struct mmal_msg_context {
-+ struct vchiq_mmal_instance *instance;
-+
-+ /* Index in the context_map idr so that we can find the
-+ * mmal_msg_context again when servicing the VCHI reply.
-+ */
-+ int handle;
-+
-+ union {
-+ struct {
-+ /* work struct for buffer_cb callback */
-+ struct work_struct work;
-+ /* work struct for deferred callback */
-+ struct work_struct buffer_to_host_work;
-+ /* mmal instance */
-+ struct vchiq_mmal_instance *instance;
-+ /* mmal port */
-+ struct vchiq_mmal_port *port;
-+ /* actual buffer used to store bulk reply */
-+ struct mmal_buffer *buffer;
-+ /* amount of buffer used */
-+ unsigned long buffer_used;
-+ /* MMAL buffer flags */
-+ u32 mmal_flags;
-+ /* Presentation and Decode timestamps */
-+ s64 pts;
-+ s64 dts;
-+
-+ int status; /* context status */
-+
-+ } bulk; /* bulk data */
-+
-+ struct {
-+ /* message handle to release */
-+ VCHI_HELD_MSG_T msg_handle;
-+ /* pointer to received message */
-+ struct mmal_msg *msg;
-+ /* received message length */
-+ u32 msg_len;
-+ /* completion upon reply */
-+ struct completion cmplt;
-+ } sync; /* synchronous response */
-+ } u;
-+
-+};
-+
-+struct vchiq_mmal_instance {
-+ VCHI_SERVICE_HANDLE_T handle;
-+
-+ /* ensure serialised access to service */
-+ struct mutex vchiq_mutex;
-+
-+ /* vmalloc page to receive scratch bulk xfers into */
-+ void *bulk_scratch;
-+
-+ struct idr context_map;
-+ /* protect accesses to context_map */
-+ struct mutex context_map_lock;
-+
-+ /* component to use next */
-+ int component_idx;
-+ struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
-+
-+ /* ordered workqueue to process all bulk operations */
-+ struct workqueue_struct *bulk_wq;
-+};
-+
-+static struct mmal_msg_context *
-+get_msg_context(struct vchiq_mmal_instance *instance)
-+{
-+ struct mmal_msg_context *msg_context;
-+ int handle;
-+
-+ /* todo: should this be allocated from a pool to avoid kzalloc */
-+ msg_context = kzalloc(sizeof(*msg_context), GFP_KERNEL);
-+
-+ if (!msg_context)
-+ return ERR_PTR(-ENOMEM);
-+
-+ /* Create an ID that will be passed along with our message so
-+ * that when we service the VCHI reply, we can look up what
-+ * message is being replied to.
-+ */
-+ mutex_lock(&instance->context_map_lock);
-+ handle = idr_alloc(&instance->context_map, msg_context,
-+ 0, 0, GFP_KERNEL);
-+ mutex_unlock(&instance->context_map_lock);
-+
-+ if (handle < 0) {
-+ kfree(msg_context);
-+ return ERR_PTR(handle);
-+ }
-+
-+ msg_context->instance = instance;
-+ msg_context->handle = handle;
-+
-+ return msg_context;
-+}
-+
-+static struct mmal_msg_context *
-+lookup_msg_context(struct vchiq_mmal_instance *instance, int handle)
-+{
-+ return idr_find(&instance->context_map, handle);
-+}
-+
-+static void
-+release_msg_context(struct mmal_msg_context *msg_context)
-+{
-+ struct vchiq_mmal_instance *instance = msg_context->instance;
-+
-+ mutex_lock(&instance->context_map_lock);
-+ idr_remove(&instance->context_map, msg_context->handle);
-+ mutex_unlock(&instance->context_map_lock);
-+ kfree(msg_context);
-+}
-+
-+/* deals with receipt of event to host message */
-+static void event_to_host_cb(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg *msg, u32 msg_len)
-+{
-+ pr_debug("unhandled event\n");
-+ pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n",
-+ msg->u.event_to_host.client_component,
-+ msg->u.event_to_host.port_type,
-+ msg->u.event_to_host.port_num,
-+ msg->u.event_to_host.cmd, msg->u.event_to_host.length);
-+}
-+
-+/* workqueue scheduled callback
-+ *
-+ * we do this because it is important we do not call any other vchiq
-+ * sync calls from witin the message delivery thread
-+ */
-+static void buffer_work_cb(struct work_struct *work)
-+{
-+ struct mmal_msg_context *msg_context =
-+ container_of(work, struct mmal_msg_context, u.bulk.work);
-+
-+ atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
-+
-+ msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
-+ msg_context->u.bulk.port,
-+ msg_context->u.bulk.status,
-+ msg_context->u.bulk.buffer,
-+ msg_context->u.bulk.buffer_used,
-+ msg_context->u.bulk.mmal_flags,
-+ msg_context->u.bulk.dts,
-+ msg_context->u.bulk.pts);
-+}
-+
-+/* workqueue scheduled callback to handle receiving buffers
-+ *
-+ * VCHI will allow up to 4 bulk receives to be scheduled before blocking.
-+ * If we block in the service_callback context then we can't process the
-+ * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked
-+ * vchi_bulk_queue_receive() call to complete.
-+ */
-+static void buffer_to_host_work_cb(struct work_struct *work)
-+{
-+ struct mmal_msg_context *msg_context =
-+ container_of(work, struct mmal_msg_context,
-+ u.bulk.buffer_to_host_work);
-+ struct vchiq_mmal_instance *instance = msg_context->instance;
-+ unsigned long len = msg_context->u.bulk.buffer_used;
-+ int ret;
-+
-+ if (!len)
-+ /* Dummy receive to ensure the buffers remain in order */
-+ len = 8;
-+ /* queue the bulk submission */
-+ vchi_service_use(instance->handle);
-+ ret = vchi_bulk_queue_receive(instance->handle,
-+ msg_context->u.bulk.buffer->buffer,
-+ /* Actual receive needs to be a multiple
-+ * of 4 bytes
-+ */
-+ (len + 3) & ~3,
-+ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
-+ msg_context);
-+
-+ vchi_service_release(instance->handle);
-+
-+ if (ret != 0)
-+ pr_err("%s: ctx: %p, vchi_bulk_queue_receive failed %d\n",
-+ __func__, msg_context, ret);
-+}
-+
-+/* enqueue a bulk receive for a given message context */
-+static int bulk_receive(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg *msg,
-+ struct mmal_msg_context *msg_context)
-+{
-+ unsigned long rd_len;
-+
-+ rd_len = msg->u.buffer_from_host.buffer_header.length;
-+
-+ if (!msg_context->u.bulk.buffer) {
-+ pr_err("bulk.buffer not configured - error in buffer_from_host\n");
-+
-+ /* todo: this is a serious error, we should never have
-+ * committed a buffer_to_host operation to the mmal
-+ * port without the buffer to back it up (underflow
-+ * handling) and there is no obvious way to deal with
-+ * this - how is the mmal servie going to react when
-+ * we fail to do the xfer and reschedule a buffer when
-+ * it arrives? perhaps a starved flag to indicate a
-+ * waiting bulk receive?
-+ */
-+
-+ return -EINVAL;
-+ }
-+
-+ /* ensure we do not overrun the available buffer */
-+ if (rd_len > msg_context->u.bulk.buffer->buffer_size) {
-+ rd_len = msg_context->u.bulk.buffer->buffer_size;
-+ pr_warn("short read as not enough receive buffer space\n");
-+ /* todo: is this the correct response, what happens to
-+ * the rest of the message data?
-+ */
-+ }
-+
-+ /* store length */
-+ msg_context->u.bulk.buffer_used = rd_len;
-+ msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
-+ msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
-+
-+ queue_work(msg_context->instance->bulk_wq,
-+ &msg_context->u.bulk.buffer_to_host_work);
-+
-+ return 0;
-+}
-+
-+/* data in message, memcpy from packet into output buffer */
-+static int inline_receive(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg *msg,
-+ struct mmal_msg_context *msg_context)
-+{
-+ memcpy(msg_context->u.bulk.buffer->buffer,
-+ msg->u.buffer_from_host.short_data,
-+ msg->u.buffer_from_host.payload_in_message);
-+
-+ msg_context->u.bulk.buffer_used =
-+ msg->u.buffer_from_host.payload_in_message;
-+
-+ return 0;
-+}
-+
-+/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */
-+static int
-+buffer_from_host(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port, struct mmal_buffer *buf)
-+{
-+ struct mmal_msg_context *msg_context;
-+ struct mmal_msg m;
-+ int ret;
-+
-+ if (!port->enabled)
-+ return -EINVAL;
-+
-+ pr_debug("instance:%p buffer:%p\n", instance->handle, buf);
-+
-+ /* get context */
-+ if (!buf->msg_context) {
-+ pr_err("%s: msg_context not allocated, buf %p\n", __func__,
-+ buf);
-+ return -EINVAL;
-+ }
-+ msg_context = buf->msg_context;
-+
-+ /* store bulk message context for when data arrives */
-+ msg_context->u.bulk.instance = instance;
-+ msg_context->u.bulk.port = port;
-+ msg_context->u.bulk.buffer = buf;
-+ msg_context->u.bulk.buffer_used = 0;
-+
-+ /* initialise work structure ready to schedule callback */
-+ INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
-+ INIT_WORK(&msg_context->u.bulk.buffer_to_host_work,
-+ buffer_to_host_work_cb);
-+
-+ atomic_inc(&port->buffers_with_vpu);
-+
-+ /* prep the buffer from host message */
-+ memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */
-+
-+ m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST;
-+ m.h.magic = MMAL_MAGIC;
-+ m.h.context = msg_context->handle;
-+ m.h.status = 0;
-+
-+ /* drvbuf is our private data passed back */
-+ m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC;
-+ m.u.buffer_from_host.drvbuf.component_handle = port->component->handle;
-+ m.u.buffer_from_host.drvbuf.port_handle = port->handle;
-+ m.u.buffer_from_host.drvbuf.client_context = msg_context->handle;
-+
-+ /* buffer header */
-+ m.u.buffer_from_host.buffer_header.cmd = 0;
-+ m.u.buffer_from_host.buffer_header.data =
-+ (u32)(unsigned long)buf->buffer;
-+ m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
-+ m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */
-+ m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */
-+ m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */
-+ m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
-+ m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
-+
-+ /* clear buffer type sepecific data */
-+ memset(&m.u.buffer_from_host.buffer_header_type_specific, 0,
-+ sizeof(m.u.buffer_from_host.buffer_header_type_specific));
-+
-+ /* no payload in message */
-+ m.u.buffer_from_host.payload_in_message = 0;
-+
-+ vchi_service_use(instance->handle);
-+
-+ ret = vchi_queue_kernel_message(instance->handle,
-+ &m,
-+ sizeof(struct mmal_msg_header) +
-+ sizeof(m.u.buffer_from_host));
-+
-+ vchi_service_release(instance->handle);
-+
-+ return ret;
-+}
-+
-+/* deals with receipt of buffer to host message */
-+static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg *msg, u32 msg_len)
-+{
-+ struct mmal_msg_context *msg_context;
-+ u32 handle;
-+
-+ pr_debug("%s: instance:%p msg:%p msg_len:%d\n",
-+ __func__, instance, msg, msg_len);
-+
-+ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
-+ handle = msg->u.buffer_from_host.drvbuf.client_context;
-+ msg_context = lookup_msg_context(instance, handle);
-+
-+ if (!msg_context) {
-+ pr_err("drvbuf.client_context(%u) is invalid\n",
-+ handle);
-+ return;
-+ }
-+ } else {
-+ pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n");
-+ return;
-+ }
-+
-+ msg_context->u.bulk.mmal_flags =
-+ msg->u.buffer_from_host.buffer_header.flags;
-+
-+ if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
-+ /* message reception had an error */
-+ pr_warn("error %d in reply\n", msg->h.status);
-+
-+ msg_context->u.bulk.status = msg->h.status;
-+
-+ } else if (msg->u.buffer_from_host.buffer_header.length == 0) {
-+ /* empty buffer */
-+ if (msg->u.buffer_from_host.buffer_header.flags &
-+ MMAL_BUFFER_HEADER_FLAG_EOS) {
-+ msg_context->u.bulk.status =
-+ bulk_receive(instance, msg, msg_context);
-+ if (msg_context->u.bulk.status == 0)
-+ return; /* successful bulk submission, bulk
-+ * completion will trigger callback
-+ */
-+ } else {
-+ /* do callback with empty buffer - not EOS though */
-+ msg_context->u.bulk.status = 0;
-+ msg_context->u.bulk.buffer_used = 0;
-+ }
-+ } else if (msg->u.buffer_from_host.payload_in_message == 0) {
-+ /* data is not in message, queue a bulk receive */
-+ msg_context->u.bulk.status =
-+ bulk_receive(instance, msg, msg_context);
-+ if (msg_context->u.bulk.status == 0)
-+ return; /* successful bulk submission, bulk
-+ * completion will trigger callback
-+ */
-+
-+ /* failed to submit buffer, this will end badly */
-+ pr_err("error %d on bulk submission\n",
-+ msg_context->u.bulk.status);
-+
-+ } else if (msg->u.buffer_from_host.payload_in_message <=
-+ MMAL_VC_SHORT_DATA) {
-+ /* data payload within message */
-+ msg_context->u.bulk.status = inline_receive(instance, msg,
-+ msg_context);
-+ } else {
-+ pr_err("message with invalid short payload\n");
-+
-+ /* signal error */
-+ msg_context->u.bulk.status = -EINVAL;
-+ msg_context->u.bulk.buffer_used =
-+ msg->u.buffer_from_host.payload_in_message;
-+ }
-+
-+ /* schedule the port callback */
-+ schedule_work(&msg_context->u.bulk.work);
-+}
-+
-+static void bulk_receive_cb(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg_context *msg_context)
-+{
-+ msg_context->u.bulk.status = 0;
-+
-+ /* schedule the port callback */
-+ schedule_work(&msg_context->u.bulk.work);
-+}
-+
-+static void bulk_abort_cb(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg_context *msg_context)
-+{
-+ pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context);
-+
-+ msg_context->u.bulk.status = -EINTR;
-+
-+ schedule_work(&msg_context->u.bulk.work);
-+}
-+
-+/* incoming event service callback */
-+static void service_callback(void *param,
-+ const VCHI_CALLBACK_REASON_T reason,
-+ void *bulk_ctx)
-+{
-+ struct vchiq_mmal_instance *instance = param;
-+ int status;
-+ u32 msg_len;
-+ struct mmal_msg *msg;
-+ VCHI_HELD_MSG_T msg_handle;
-+ struct mmal_msg_context *msg_context;
-+
-+ if (!instance) {
-+ pr_err("Message callback passed NULL instance\n");
-+ return;
-+ }
-+
-+ switch (reason) {
-+ case VCHI_CALLBACK_MSG_AVAILABLE:
-+ status = vchi_msg_hold(instance->handle, (void **)&msg,
-+ &msg_len, VCHI_FLAGS_NONE, &msg_handle);
-+ if (status) {
-+ pr_err("Unable to dequeue a message (%d)\n", status);
-+ break;
-+ }
-+
-+ DBG_DUMP_MSG(msg, msg_len, "<<< reply message");
-+
-+ /* handling is different for buffer messages */
-+ switch (msg->h.type) {
-+ case MMAL_MSG_TYPE_BUFFER_FROM_HOST:
-+ vchi_held_msg_release(&msg_handle);
-+ break;
-+
-+ case MMAL_MSG_TYPE_EVENT_TO_HOST:
-+ event_to_host_cb(instance, msg, msg_len);
-+ vchi_held_msg_release(&msg_handle);
-+
-+ break;
-+
-+ case MMAL_MSG_TYPE_BUFFER_TO_HOST:
-+ buffer_to_host_cb(instance, msg, msg_len);
-+ vchi_held_msg_release(&msg_handle);
-+ break;
-+
-+ default:
-+ /* messages dependent on header context to complete */
-+ if (!msg->h.context) {
-+ pr_err("received message context was null!\n");
-+ vchi_held_msg_release(&msg_handle);
-+ break;
-+ }
-+
-+ msg_context = lookup_msg_context(instance,
-+ msg->h.context);
-+ if (!msg_context) {
-+ pr_err("received invalid message context %u!\n",
-+ msg->h.context);
-+ vchi_held_msg_release(&msg_handle);
-+ break;
-+ }
-+
-+ /* fill in context values */
-+ msg_context->u.sync.msg_handle = msg_handle;
-+ msg_context->u.sync.msg = msg;
-+ msg_context->u.sync.msg_len = msg_len;
-+
-+ /* todo: should this check (completion_done()
-+ * == 1) for no one waiting? or do we need a
-+ * flag to tell us the completion has been
-+ * interrupted so we can free the message and
-+ * its context. This probably also solves the
-+ * message arriving after interruption todo
-+ * below
-+ */
-+
-+ /* complete message so caller knows it happened */
-+ complete(&msg_context->u.sync.cmplt);
-+ break;
-+ }
-+
-+ break;
-+
-+ case VCHI_CALLBACK_BULK_RECEIVED:
-+ bulk_receive_cb(instance, bulk_ctx);
-+ break;
-+
-+ case VCHI_CALLBACK_BULK_RECEIVE_ABORTED:
-+ bulk_abort_cb(instance, bulk_ctx);
-+ break;
-+
-+ case VCHI_CALLBACK_SERVICE_CLOSED:
-+ /* TODO: consider if this requires action if received when
-+ * driver is not explicitly closing the service
-+ */
-+ break;
-+
-+ default:
-+ pr_err("Received unhandled message reason %d\n", reason);
-+ break;
-+ }
-+}
-+
-+static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg *msg,
-+ unsigned int payload_len,
-+ struct mmal_msg **msg_out,
-+ VCHI_HELD_MSG_T *msg_handle_out)
-+{
-+ struct mmal_msg_context *msg_context;
-+ int ret;
-+ unsigned long timeout;
-+
-+ /* payload size must not cause message to exceed max size */
-+ if (payload_len >
-+ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
-+ pr_err("payload length %d exceeds max:%d\n", payload_len,
-+ (int)(MMAL_MSG_MAX_SIZE -
-+ sizeof(struct mmal_msg_header)));
-+ return -EINVAL;
-+ }
-+
-+ msg_context = get_msg_context(instance);
-+ if (IS_ERR(msg_context))
-+ return PTR_ERR(msg_context);
-+
-+ init_completion(&msg_context->u.sync.cmplt);
-+
-+ msg->h.magic = MMAL_MAGIC;
-+ msg->h.context = msg_context->handle;
-+ msg->h.status = 0;
-+
-+ DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len),
-+ ">>> sync message");
-+
-+ vchi_service_use(instance->handle);
-+
-+ ret = vchi_queue_kernel_message(instance->handle,
-+ msg,
-+ sizeof(struct mmal_msg_header) +
-+ payload_len);
-+
-+ vchi_service_release(instance->handle);
-+
-+ if (ret) {
-+ pr_err("error %d queuing message\n", ret);
-+ release_msg_context(msg_context);
-+ return ret;
-+ }
-+
-+ timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt,
-+ 3 * HZ);
-+ if (timeout == 0) {
-+ pr_err("timed out waiting for sync completion\n");
-+ ret = -ETIME;
-+ /* todo: what happens if the message arrives after aborting */
-+ release_msg_context(msg_context);
-+ return ret;
-+ }
-+
-+ *msg_out = msg_context->u.sync.msg;
-+ *msg_handle_out = msg_context->u.sync.msg_handle;
-+ release_msg_context(msg_context);
-+
-+ return 0;
-+}
-+
-+static void dump_port_info(struct vchiq_mmal_port *port)
-+{
-+ pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled);
-+
-+ pr_debug("buffer minimum num:%d size:%d align:%d\n",
-+ port->minimum_buffer.num,
-+ port->minimum_buffer.size, port->minimum_buffer.alignment);
-+
-+ pr_debug("buffer recommended num:%d size:%d align:%d\n",
-+ port->recommended_buffer.num,
-+ port->recommended_buffer.size,
-+ port->recommended_buffer.alignment);
-+
-+ pr_debug("buffer current values num:%d size:%d align:%d\n",
-+ port->current_buffer.num,
-+ port->current_buffer.size, port->current_buffer.alignment);
-+
-+ pr_debug("elementary stream: type:%d encoding:0x%x variant:0x%x\n",
-+ port->format.type,
-+ port->format.encoding, port->format.encoding_variant);
-+
-+ pr_debug(" bitrate:%d flags:0x%x\n",
-+ port->format.bitrate, port->format.flags);
-+
-+ if (port->format.type == MMAL_ES_TYPE_VIDEO) {
-+ pr_debug
-+ ("es video format: width:%d height:%d colourspace:0x%x\n",
-+ port->es.video.width, port->es.video.height,
-+ port->es.video.color_space);
-+
-+ pr_debug(" : crop xywh %d,%d,%d,%d\n",
-+ port->es.video.crop.x,
-+ port->es.video.crop.y,
-+ port->es.video.crop.width, port->es.video.crop.height);
-+ pr_debug(" : framerate %d/%d aspect %d/%d\n",
-+ port->es.video.frame_rate.num,
-+ port->es.video.frame_rate.den,
-+ port->es.video.par.num, port->es.video.par.den);
-+ }
-+}
-+
-+static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p)
-+{
-+ /* todo do readonly fields need setting at all? */
-+ p->type = port->type;
-+ p->index = port->index;
-+ p->index_all = 0;
-+ p->is_enabled = port->enabled;
-+ p->buffer_num_min = port->minimum_buffer.num;
-+ p->buffer_size_min = port->minimum_buffer.size;
-+ p->buffer_alignment_min = port->minimum_buffer.alignment;
-+ p->buffer_num_recommended = port->recommended_buffer.num;
-+ p->buffer_size_recommended = port->recommended_buffer.size;
-+
-+ /* only three writable fields in a port */
-+ p->buffer_num = port->current_buffer.num;
-+ p->buffer_size = port->current_buffer.size;
-+ p->userdata = (u32)(unsigned long)port;
-+}
-+
-+static int port_info_set(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ pr_debug("setting port info port %p\n", port);
-+ if (!port)
-+ return -1;
-+ dump_port_info(port);
-+
-+ m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET;
-+
-+ m.u.port_info_set.component_handle = port->component->handle;
-+ m.u.port_info_set.port_type = port->type;
-+ m.u.port_info_set.port_index = port->index;
-+
-+ port_to_mmal_msg(port, &m.u.port_info_set.port);
-+
-+ /* elementary stream format setup */
-+ m.u.port_info_set.format.type = port->format.type;
-+ m.u.port_info_set.format.encoding = port->format.encoding;
-+ m.u.port_info_set.format.encoding_variant =
-+ port->format.encoding_variant;
-+ m.u.port_info_set.format.bitrate = port->format.bitrate;
-+ m.u.port_info_set.format.flags = port->format.flags;
-+
-+ memcpy(&m.u.port_info_set.es, &port->es,
-+ sizeof(union mmal_es_specific_format));
-+
-+ m.u.port_info_set.format.extradata_size = port->format.extradata_size;
-+ memcpy(&m.u.port_info_set.extradata, port->format.extradata,
-+ port->format.extradata_size);
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.port_info_set),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ /* return operation status */
-+ ret = -rmsg->u.port_info_get_reply.status;
-+
-+ pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret,
-+ port->component->handle, port->handle);
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* use port info get message to retrieve port information */
-+static int port_info_get(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ /* port info time */
-+ m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET;
-+ m.u.port_info_get.component_handle = port->component->handle;
-+ m.u.port_info_get.port_type = port->type;
-+ m.u.port_info_get.index = port->index;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.port_info_get),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ /* return operation status */
-+ ret = -rmsg->u.port_info_get_reply.status;
-+ if (ret != MMAL_MSG_STATUS_SUCCESS)
-+ goto release_msg;
-+
-+ if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
-+ port->enabled = false;
-+ else
-+ port->enabled = true;
-+
-+ /* copy the values out of the message */
-+ port->handle = rmsg->u.port_info_get_reply.port_handle;
-+
-+ /* port type and index cached to use on port info set because
-+ * it does not use a port handle
-+ */
-+ port->type = rmsg->u.port_info_get_reply.port_type;
-+ port->index = rmsg->u.port_info_get_reply.port_index;
-+
-+ port->minimum_buffer.num =
-+ rmsg->u.port_info_get_reply.port.buffer_num_min;
-+ port->minimum_buffer.size =
-+ rmsg->u.port_info_get_reply.port.buffer_size_min;
-+ port->minimum_buffer.alignment =
-+ rmsg->u.port_info_get_reply.port.buffer_alignment_min;
-+
-+ port->recommended_buffer.alignment =
-+ rmsg->u.port_info_get_reply.port.buffer_alignment_min;
-+ port->recommended_buffer.num =
-+ rmsg->u.port_info_get_reply.port.buffer_num_recommended;
-+
-+ port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num;
-+ port->current_buffer.size =
-+ rmsg->u.port_info_get_reply.port.buffer_size;
-+
-+ /* stream format */
-+ port->format.type = rmsg->u.port_info_get_reply.format.type;
-+ port->format.encoding = rmsg->u.port_info_get_reply.format.encoding;
-+ port->format.encoding_variant =
-+ rmsg->u.port_info_get_reply.format.encoding_variant;
-+ port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate;
-+ port->format.flags = rmsg->u.port_info_get_reply.format.flags;
-+
-+ /* elementary stream format */
-+ memcpy(&port->es,
-+ &rmsg->u.port_info_get_reply.es,
-+ sizeof(union mmal_es_specific_format));
-+ port->format.es = &port->es;
-+
-+ port->format.extradata_size =
-+ rmsg->u.port_info_get_reply.format.extradata_size;
-+ memcpy(port->format.extradata,
-+ rmsg->u.port_info_get_reply.extradata,
-+ port->format.extradata_size);
-+
-+ pr_debug("received port info\n");
-+ dump_port_info(port);
-+
-+release_msg:
-+
-+ pr_debug("%s:result:%d component:0x%x port:%d\n",
-+ __func__, ret, port->component->handle, port->handle);
-+
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* create comonent on vc */
-+static int create_component(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component,
-+ const char *name)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ /* build component create message */
-+ m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE;
-+ m.u.component_create.client_component = (u32)(unsigned long)component;
-+ strncpy(m.u.component_create.name, name,
-+ sizeof(m.u.component_create.name));
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.component_create),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != m.h.type) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.component_create_reply.status;
-+ if (ret != MMAL_MSG_STATUS_SUCCESS)
-+ goto release_msg;
-+
-+ /* a valid component response received */
-+ component->handle = rmsg->u.component_create_reply.component_handle;
-+ component->inputs = rmsg->u.component_create_reply.input_num;
-+ component->outputs = rmsg->u.component_create_reply.output_num;
-+ component->clocks = rmsg->u.component_create_reply.clock_num;
-+
-+ pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n",
-+ component->handle,
-+ component->inputs, component->outputs, component->clocks);
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* destroys a component on vc */
-+static int destroy_component(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY;
-+ m.u.component_destroy.component_handle = component->handle;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.component_destroy),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != m.h.type) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.component_destroy_reply.status;
-+
-+release_msg:
-+
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* enable a component on vc */
-+static int enable_component(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE;
-+ m.u.component_enable.component_handle = component->handle;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.component_enable),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != m.h.type) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.component_enable_reply.status;
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* disable a component on vc */
-+static int disable_component(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE;
-+ m.u.component_disable.component_handle = component->handle;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.component_disable),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != m.h.type) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.component_disable_reply.status;
-+
-+release_msg:
-+
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* get version of mmal implementation */
-+static int get_version(struct vchiq_mmal_instance *instance,
-+ u32 *major_out, u32 *minor_out)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_GET_VERSION;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.version),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != m.h.type) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ *major_out = rmsg->u.version.major;
-+ *minor_out = rmsg->u.version.minor;
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* do a port action with a port as a parameter */
-+static int port_action_port(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ enum mmal_msg_port_action_type action_type)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
-+ m.u.port_action_port.component_handle = port->component->handle;
-+ m.u.port_action_port.port_handle = port->handle;
-+ m.u.port_action_port.action = action_type;
-+
-+ port_to_mmal_msg(port, &m.u.port_action_port.port);
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.port_action_port),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.port_action_reply.status;
-+
-+ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n",
-+ __func__,
-+ ret, port->component->handle, port->handle,
-+ port_action_type_names[action_type], action_type);
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* do a port action with handles as parameters */
-+static int port_action_handle(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ enum mmal_msg_port_action_type action_type,
-+ u32 connect_component_handle,
-+ u32 connect_port_handle)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
-+
-+ m.u.port_action_handle.component_handle = port->component->handle;
-+ m.u.port_action_handle.port_handle = port->handle;
-+ m.u.port_action_handle.action = action_type;
-+
-+ m.u.port_action_handle.connect_component_handle =
-+ connect_component_handle;
-+ m.u.port_action_handle.connect_port_handle = connect_port_handle;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(m.u.port_action_handle),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.port_action_reply.status;
-+
-+ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d) connect component:0x%x connect port:%d\n",
-+ __func__,
-+ ret, port->component->handle, port->handle,
-+ port_action_type_names[action_type],
-+ action_type, connect_component_handle, connect_port_handle);
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+static int port_parameter_set(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ u32 parameter_id, void *value, u32 value_size)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET;
-+
-+ m.u.port_parameter_set.component_handle = port->component->handle;
-+ m.u.port_parameter_set.port_handle = port->handle;
-+ m.u.port_parameter_set.id = parameter_id;
-+ m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size;
-+ memcpy(&m.u.port_parameter_set.value, value, value_size);
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ (4 * sizeof(u32)) + value_size,
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) {
-+ /* got an unexpected message type in reply */
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.port_parameter_set_reply.status;
-+
-+ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n",
-+ __func__,
-+ ret, port->component->handle, port->handle, parameter_id);
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+static int port_parameter_get(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ u32 parameter_id, void *value, u32 *value_size)
-+{
-+ int ret;
-+ struct mmal_msg m;
-+ struct mmal_msg *rmsg;
-+ VCHI_HELD_MSG_T rmsg_handle;
-+
-+ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET;
-+
-+ m.u.port_parameter_get.component_handle = port->component->handle;
-+ m.u.port_parameter_get.port_handle = port->handle;
-+ m.u.port_parameter_get.id = parameter_id;
-+ m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size;
-+
-+ ret = send_synchronous_mmal_msg(instance, &m,
-+ sizeof(struct
-+ mmal_msg_port_parameter_get),
-+ &rmsg, &rmsg_handle);
-+ if (ret)
-+ return ret;
-+
-+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) {
-+ /* got an unexpected message type in reply */
-+ pr_err("Incorrect reply type %d\n", rmsg->h.type);
-+ ret = -EINVAL;
-+ goto release_msg;
-+ }
-+
-+ ret = -rmsg->u.port_parameter_get_reply.status;
-+ /* port_parameter_get_reply.size includes the header,
-+ * whilst *value_size doesn't.
-+ */
-+ rmsg->u.port_parameter_get_reply.size -= (2 * sizeof(u32));
-+
-+ if (ret || rmsg->u.port_parameter_get_reply.size > *value_size) {
-+ /* Copy only as much as we have space for
-+ * but report true size of parameter
-+ */
-+ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
-+ *value_size);
-+ *value_size = rmsg->u.port_parameter_get_reply.size;
-+ } else {
-+ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
-+ rmsg->u.port_parameter_get_reply.size);
-+ }
-+
-+ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
-+ ret, port->component->handle, port->handle, parameter_id);
-+
-+release_msg:
-+ vchi_held_msg_release(&rmsg_handle);
-+
-+ return ret;
-+}
-+
-+/* disables a port and drains buffers from it */
-+static int port_disable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ int ret;
-+ struct list_head *q, *buf_head;
-+ unsigned long flags = 0;
-+
-+ if (!port->enabled)
-+ return 0;
-+
-+ port->enabled = false;
-+
-+ ret = port_action_port(instance, port,
-+ MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
-+ if (ret == 0) {
-+ /*
-+ * Drain all queued buffers on port. This should only
-+ * apply to buffers that have been queued before the port
-+ * has been enabled. If the port has been enabled and buffers
-+ * passed, then the buffers should have been removed from this
-+ * list, and we should get the relevant callbacks via VCHIQ
-+ * to release the buffers.
-+ */
-+ spin_lock_irqsave(&port->slock, flags);
-+
-+ list_for_each_safe(buf_head, q, &port->buffers) {
-+ struct mmal_buffer *mmalbuf;
-+
-+ mmalbuf = list_entry(buf_head, struct mmal_buffer,
-+ list);
-+ list_del(buf_head);
-+ if (port->buffer_cb)
-+ port->buffer_cb(instance,
-+ port, 0, mmalbuf, 0, 0,
-+ MMAL_TIME_UNKNOWN,
-+ MMAL_TIME_UNKNOWN);
-+ }
-+
-+ spin_unlock_irqrestore(&port->slock, flags);
-+
-+ ret = port_info_get(instance, port);
-+ }
-+
-+ return ret;
-+}
-+
-+/* enable a port */
-+static int port_enable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ unsigned int hdr_count;
-+ struct list_head *q, *buf_head;
-+ int ret;
-+
-+ if (port->enabled)
-+ return 0;
-+
-+ ret = port_action_port(instance, port,
-+ MMAL_MSG_PORT_ACTION_TYPE_ENABLE);
-+ if (ret)
-+ goto done;
-+
-+ port->enabled = true;
-+
-+ if (port->buffer_cb) {
-+ /* send buffer headers to videocore */
-+ hdr_count = 1;
-+ list_for_each_safe(buf_head, q, &port->buffers) {
-+ struct mmal_buffer *mmalbuf;
-+
-+ mmalbuf = list_entry(buf_head, struct mmal_buffer,
-+ list);
-+ ret = buffer_from_host(instance, port, mmalbuf);
-+ if (ret)
-+ goto done;
-+
-+ list_del(buf_head);
-+ hdr_count++;
-+ if (hdr_count > port->current_buffer.num)
-+ break;
-+ }
-+ }
-+
-+ ret = port_info_get(instance, port);
-+
-+done:
-+ return ret;
-+}
-+
-+/* ------------------------------------------------------------------
-+ * Exported API
-+ *------------------------------------------------------------------
-+ */
-+
-+int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ ret = port_info_set(instance, port);
-+ if (ret)
-+ goto release_unlock;
-+
-+ /* read what has actually been set */
-+ ret = port_info_get(instance, port);
-+
-+release_unlock:
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_port_set_format);
-+
-+int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ u32 parameter, void *value, u32 value_size)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ ret = port_parameter_set(instance, port, parameter, value, value_size);
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_set);
-+
-+int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ u32 parameter, void *value, u32 *value_size)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ ret = port_parameter_get(instance, port, parameter, value, value_size);
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_get);
-+
-+/* enable a port
-+ *
-+ * enables a port and queues buffers for satisfying callbacks if we
-+ * provide a callback handler
-+ */
-+int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ vchiq_mmal_buffer_cb buffer_cb)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ /* already enabled - noop */
-+ if (port->enabled) {
-+ ret = 0;
-+ goto unlock;
-+ }
-+
-+ port->buffer_cb = buffer_cb;
-+
-+ ret = port_enable(instance, port);
-+
-+unlock:
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_port_enable);
-+
-+int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ if (!port->enabled) {
-+ mutex_unlock(&instance->vchiq_mutex);
-+ return 0;
-+ }
-+
-+ ret = port_disable(instance, port);
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_port_disable);
-+
-+/* ports will be connected in a tunneled manner so data buffers
-+ * are not handled by client.
-+ */
-+int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *src,
-+ struct vchiq_mmal_port *dst)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ /* disconnect ports if connected */
-+ if (src->connected) {
-+ ret = port_disable(instance, src);
-+ if (ret) {
-+ pr_err("failed disabling src port(%d)\n", ret);
-+ goto release_unlock;
-+ }
-+
-+ /* do not need to disable the destination port as they
-+ * are connected and it is done automatically
-+ */
-+
-+ ret = port_action_handle(instance, src,
-+ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT,
-+ src->connected->component->handle,
-+ src->connected->handle);
-+ if (ret < 0) {
-+ pr_err("failed disconnecting src port\n");
-+ goto release_unlock;
-+ }
-+ src->connected->enabled = false;
-+ src->connected = NULL;
-+ }
-+
-+ if (!dst) {
-+ /* do not make new connection */
-+ ret = 0;
-+ pr_debug("not making new connection\n");
-+ goto release_unlock;
-+ }
-+
-+ /* copy src port format to dst */
-+ dst->format.encoding = src->format.encoding;
-+ dst->es.video.width = src->es.video.width;
-+ dst->es.video.height = src->es.video.height;
-+ dst->es.video.crop.x = src->es.video.crop.x;
-+ dst->es.video.crop.y = src->es.video.crop.y;
-+ dst->es.video.crop.width = src->es.video.crop.width;
-+ dst->es.video.crop.height = src->es.video.crop.height;
-+ dst->es.video.frame_rate.num = src->es.video.frame_rate.num;
-+ dst->es.video.frame_rate.den = src->es.video.frame_rate.den;
-+
-+ /* set new format */
-+ ret = port_info_set(instance, dst);
-+ if (ret) {
-+ pr_debug("setting port info failed\n");
-+ goto release_unlock;
-+ }
-+
-+ /* read what has actually been set */
-+ ret = port_info_get(instance, dst);
-+ if (ret) {
-+ pr_debug("read back port info failed\n");
-+ goto release_unlock;
-+ }
-+
-+ /* connect two ports together */
-+ ret = port_action_handle(instance, src,
-+ MMAL_MSG_PORT_ACTION_TYPE_CONNECT,
-+ dst->component->handle, dst->handle);
-+ if (ret < 0) {
-+ pr_debug("connecting port %d:%d to %d:%d failed\n",
-+ src->component->handle, src->handle,
-+ dst->component->handle, dst->handle);
-+ goto release_unlock;
-+ }
-+ src->connected = dst;
-+
-+release_unlock:
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_port_connect_tunnel);
-+
-+int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ struct mmal_buffer *buffer)
-+{
-+ unsigned long flags = 0;
-+ int ret;
-+
-+ ret = buffer_from_host(instance, port, buffer);
-+ if (ret == -EINVAL) {
-+ /* Port is disabled. Queue for when it is enabled. */
-+ spin_lock_irqsave(&port->slock, flags);
-+ list_add_tail(&buffer->list, &port->buffers);
-+ spin_unlock_irqrestore(&port->slock, flags);
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_submit_buffer);
-+
-+int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance,
-+ struct mmal_buffer *buf)
-+{
-+ struct mmal_msg_context *msg_context = get_msg_context(instance);
-+
-+ if (IS_ERR(msg_context))
-+ return (PTR_ERR(msg_context));
-+
-+ buf->msg_context = msg_context;
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(mmal_vchi_buffer_init);
-+
-+int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf)
-+{
-+ struct mmal_msg_context *msg_context = buf->msg_context;
-+
-+ if (msg_context)
-+ release_msg_context(msg_context);
-+ buf->msg_context = NULL;
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup);
-+
-+/* Initialise a mmal component and its ports
-+ *
-+ */
-+int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance,
-+ const char *name,
-+ struct vchiq_mmal_component **component_out)
-+{
-+ int ret;
-+ int idx; /* port index */
-+ struct vchiq_mmal_component *component;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) {
-+ ret = -EINVAL; /* todo is this correct error? */
-+ goto unlock;
-+ }
-+
-+ component = &instance->component[instance->component_idx];
-+
-+ ret = create_component(instance, component, name);
-+ if (ret < 0) {
-+ pr_err("%s: failed to create component %d (Not enough GPU mem?)\n",
-+ __func__, ret);
-+ goto unlock;
-+ }
-+
-+ /* ports info needs gathering */
-+ component->control.type = MMAL_PORT_TYPE_CONTROL;
-+ component->control.index = 0;
-+ component->control.component = component;
-+ spin_lock_init(&component->control.slock);
-+ INIT_LIST_HEAD(&component->control.buffers);
-+ ret = port_info_get(instance, &component->control);
-+ if (ret < 0)
-+ goto release_component;
-+
-+ for (idx = 0; idx < component->inputs; idx++) {
-+ component->input[idx].type = MMAL_PORT_TYPE_INPUT;
-+ component->input[idx].index = idx;
-+ component->input[idx].component = component;
-+ spin_lock_init(&component->input[idx].slock);
-+ INIT_LIST_HEAD(&component->input[idx].buffers);
-+ ret = port_info_get(instance, &component->input[idx]);
-+ if (ret < 0)
-+ goto release_component;
-+ }
-+
-+ for (idx = 0; idx < component->outputs; idx++) {
-+ component->output[idx].type = MMAL_PORT_TYPE_OUTPUT;
-+ component->output[idx].index = idx;
-+ component->output[idx].component = component;
-+ spin_lock_init(&component->output[idx].slock);
-+ INIT_LIST_HEAD(&component->output[idx].buffers);
-+ ret = port_info_get(instance, &component->output[idx]);
-+ if (ret < 0)
-+ goto release_component;
-+ }
-+
-+ for (idx = 0; idx < component->clocks; idx++) {
-+ component->clock[idx].type = MMAL_PORT_TYPE_CLOCK;
-+ component->clock[idx].index = idx;
-+ component->clock[idx].component = component;
-+ spin_lock_init(&component->clock[idx].slock);
-+ INIT_LIST_HEAD(&component->clock[idx].buffers);
-+ ret = port_info_get(instance, &component->clock[idx]);
-+ if (ret < 0)
-+ goto release_component;
-+ }
-+
-+ instance->component_idx++;
-+
-+ *component_out = component;
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return 0;
-+
-+release_component:
-+ destroy_component(instance, component);
-+unlock:
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_component_init);
-+
-+/*
-+ * cause a mmal component to be destroyed
-+ */
-+int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ if (component->enabled)
-+ ret = disable_component(instance, component);
-+
-+ ret = destroy_component(instance, component);
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_component_finalise);
-+
-+/*
-+ * cause a mmal component to be enabled
-+ */
-+int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ if (component->enabled) {
-+ mutex_unlock(&instance->vchiq_mutex);
-+ return 0;
-+ }
-+
-+ ret = enable_component(instance, component);
-+ if (ret == 0)
-+ component->enabled = true;
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_component_enable);
-+
-+/*
-+ * cause a mmal component to be enabled
-+ */
-+int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ if (!component->enabled) {
-+ mutex_unlock(&instance->vchiq_mutex);
-+ return 0;
-+ }
-+
-+ ret = disable_component(instance, component);
-+ if (ret == 0)
-+ component->enabled = false;
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_component_disable);
-+
-+int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
-+ u32 *major_out, u32 *minor_out)
-+{
-+ int ret;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ ret = get_version(instance, major_out, minor_out);
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_version);
-+
-+int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
-+{
-+ int status = 0;
-+
-+ if (!instance)
-+ return -EINVAL;
-+
-+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
-+ return -EINTR;
-+
-+ vchi_service_use(instance->handle);
-+
-+ status = vchi_service_close(instance->handle);
-+ if (status != 0)
-+ pr_err("mmal-vchiq: VCHIQ close failed\n");
-+
-+ mutex_unlock(&instance->vchiq_mutex);
-+
-+ flush_workqueue(instance->bulk_wq);
-+ destroy_workqueue(instance->bulk_wq);
-+
-+ vfree(instance->bulk_scratch);
-+
-+ idr_destroy(&instance->context_map);
-+
-+ kfree(instance);
-+
-+ return status;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_finalise);
-+
-+int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
-+{
-+ int status;
-+ struct vchiq_mmal_instance *instance;
-+ static VCHI_CONNECTION_T *vchi_connection;
-+ static VCHI_INSTANCE_T vchi_instance;
-+ SERVICE_CREATION_T params = {
-+ .version = VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER),
-+ .service_id = VC_MMAL_SERVER_NAME,
-+ .connection = vchi_connection,
-+ .rx_fifo_size = 0,
-+ .tx_fifo_size = 0,
-+ .callback = service_callback,
-+ .callback_param = NULL,
-+ .want_unaligned_bulk_rx = 1,
-+ .want_unaligned_bulk_tx = 1,
-+ .want_crc = 0
-+ };
-+
-+ /* compile time checks to ensure structure size as they are
-+ * directly (de)serialised from memory.
-+ */
-+
-+ /* ensure the header structure has packed to the correct size */
-+ BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24);
-+
-+ /* ensure message structure does not exceed maximum length */
-+ BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE);
-+
-+ /* mmal port struct is correct size */
-+ BUILD_BUG_ON(sizeof(struct mmal_port) != 64);
-+
-+ /* create a vchi instance */
-+ status = vchi_initialise(&vchi_instance);
-+ if (status) {
-+ pr_err("Failed to initialise VCHI instance (status=%d)\n",
-+ status);
-+ return -EIO;
-+ }
-+
-+ status = vchi_connect(NULL, 0, vchi_instance);
-+ if (status) {
-+ pr_err("Failed to connect VCHI instance (status=%d)\n", status);
-+ return -EIO;
-+ }
-+
-+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
-+
-+ if (!instance)
-+ return -ENOMEM;
-+
-+ mutex_init(&instance->vchiq_mutex);
-+
-+ instance->bulk_scratch = vmalloc(PAGE_SIZE);
-+
-+ mutex_init(&instance->context_map_lock);
-+ idr_init_base(&instance->context_map, 1);
-+
-+ params.callback_param = instance;
-+
-+ instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq",
-+ WQ_MEM_RECLAIM);
-+ if (!instance->bulk_wq)
-+ goto err_free;
-+
-+ status = vchi_service_open(vchi_instance, ¶ms, &instance->handle);
-+ if (status) {
-+ pr_err("Failed to open VCHI service connection (status=%d)\n",
-+ status);
-+ goto err_close_services;
-+ }
-+
-+ vchi_service_release(instance->handle);
-+
-+ *out_instance = instance;
-+
-+ return 0;
-+
-+err_close_services:
-+ vchi_service_close(instance->handle);
-+ destroy_workqueue(instance->bulk_wq);
-+err_free:
-+ vfree(instance->bulk_scratch);
-+ kfree(instance);
-+ return -ENODEV;
-+}
-+EXPORT_SYMBOL_GPL(vchiq_mmal_init);
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
-+++ /dev/null
-@@ -1,61 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0 */
--/*
-- * Broadcom BM2835 V4L2 driver
-- *
-- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-- *
-- * Authors: Vincent Sanders @ Collabora
-- * Dave Stevenson @ Broadcom
-- * Simon Mellor @ Broadcom
-- * Luke Diamand @ Broadcom
-- *
-- * MMAL structures
-- *
-- */
--#ifndef MMAL_COMMON_H
--#define MMAL_COMMON_H
--
--#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
--#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l')
--
--/** Special value signalling that time is not known */
--#define MMAL_TIME_UNKNOWN BIT_ULL(63)
--
--struct mmal_msg_context;
--
--/* mapping between v4l and mmal video modes */
--struct mmal_fmt {
-- char *name;
-- u32 fourcc; /* v4l2 format id */
-- int flags; /* v4l2 flags field */
-- u32 mmal;
-- int depth;
-- u32 mmal_component; /* MMAL component index to be used to encode */
-- u32 ybbp; /* depth of first Y plane for planar formats */
-- bool remove_padding; /* Does the GPU have to remove padding,
-- * or can we do hide padding via bytesperline.
-- */
--};
--
--/* buffer for one video frame */
--struct mmal_buffer {
-- /* v4l buffer data -- must be first */
-- struct vb2_v4l2_buffer vb;
--
-- /* list of buffers available */
-- struct list_head list;
--
-- void *buffer; /* buffer pointer */
-- unsigned long buffer_size; /* size of allocated buffer */
--
-- struct mmal_msg_context *msg_context;
--};
--
--/* */
--struct mmal_colourfx {
-- s32 enable;
-- u32 u;
-- u32 v;
--};
--#endif
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h
-+++ /dev/null
-@@ -1,124 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0 */
--/*
-- * Broadcom BM2835 V4L2 driver
-- *
-- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-- *
-- * Authors: Vincent Sanders @ Collabora
-- * Dave Stevenson @ Broadcom
-- * Simon Mellor @ Broadcom
-- * Luke Diamand @ Broadcom
-- */
--#ifndef MMAL_ENCODINGS_H
--#define MMAL_ENCODINGS_H
--
--#define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4')
--#define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3')
--#define MMAL_ENCODING_MP4V MMAL_FOURCC('M', 'P', '4', 'V')
--#define MMAL_ENCODING_MP2V MMAL_FOURCC('M', 'P', '2', 'V')
--#define MMAL_ENCODING_MP1V MMAL_FOURCC('M', 'P', '1', 'V')
--#define MMAL_ENCODING_WMV3 MMAL_FOURCC('W', 'M', 'V', '3')
--#define MMAL_ENCODING_WMV2 MMAL_FOURCC('W', 'M', 'V', '2')
--#define MMAL_ENCODING_WMV1 MMAL_FOURCC('W', 'M', 'V', '1')
--#define MMAL_ENCODING_WVC1 MMAL_FOURCC('W', 'V', 'C', '1')
--#define MMAL_ENCODING_VP8 MMAL_FOURCC('V', 'P', '8', ' ')
--#define MMAL_ENCODING_VP7 MMAL_FOURCC('V', 'P', '7', ' ')
--#define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ')
--#define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O')
--#define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K')
--#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G')
--
--#define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G')
--#define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ')
--#define MMAL_ENCODING_PNG MMAL_FOURCC('P', 'N', 'G', ' ')
--#define MMAL_ENCODING_PPM MMAL_FOURCC('P', 'P', 'M', ' ')
--#define MMAL_ENCODING_TGA MMAL_FOURCC('T', 'G', 'A', ' ')
--#define MMAL_ENCODING_BMP MMAL_FOURCC('B', 'M', 'P', ' ')
--
--#define MMAL_ENCODING_I420 MMAL_FOURCC('I', '4', '2', '0')
--#define MMAL_ENCODING_I420_SLICE MMAL_FOURCC('S', '4', '2', '0')
--#define MMAL_ENCODING_YV12 MMAL_FOURCC('Y', 'V', '1', '2')
--#define MMAL_ENCODING_I422 MMAL_FOURCC('I', '4', '2', '2')
--#define MMAL_ENCODING_I422_SLICE MMAL_FOURCC('S', '4', '2', '2')
--#define MMAL_ENCODING_YUYV MMAL_FOURCC('Y', 'U', 'Y', 'V')
--#define MMAL_ENCODING_YVYU MMAL_FOURCC('Y', 'V', 'Y', 'U')
--#define MMAL_ENCODING_UYVY MMAL_FOURCC('U', 'Y', 'V', 'Y')
--#define MMAL_ENCODING_VYUY MMAL_FOURCC('V', 'Y', 'U', 'Y')
--#define MMAL_ENCODING_NV12 MMAL_FOURCC('N', 'V', '1', '2')
--#define MMAL_ENCODING_NV21 MMAL_FOURCC('N', 'V', '2', '1')
--#define MMAL_ENCODING_ARGB MMAL_FOURCC('A', 'R', 'G', 'B')
--#define MMAL_ENCODING_RGBA MMAL_FOURCC('R', 'G', 'B', 'A')
--#define MMAL_ENCODING_ABGR MMAL_FOURCC('A', 'B', 'G', 'R')
--#define MMAL_ENCODING_BGRA MMAL_FOURCC('B', 'G', 'R', 'A')
--#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R', 'G', 'B', '2')
--#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R', 'G', 'B', '3')
--#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R', 'G', 'B', '4')
--#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B', 'G', 'R', '2')
--#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B', 'G', 'R', '3')
--#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B', 'G', 'R', '4')
--
--/** SAND Video (YUVUV128) format, native format understood by VideoCore.
-- * This format is *not* opaque - if requested you will receive full frames
-- * of YUV_UV video.
-- */
--#define MMAL_ENCODING_YUVUV128 MMAL_FOURCC('S', 'A', 'N', 'D')
--
--/** VideoCore opaque image format, image handles are returned to
-- * the host but not the actual image data.
-- */
--#define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V')
--
--/** An EGL image handle
-- */
--#define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I')
--
--/* }@ */
--
--/** \name Pre-defined audio encodings */
--/* @{ */
--#define MMAL_ENCODING_PCM_UNSIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'U')
--#define MMAL_ENCODING_PCM_UNSIGNED_LE MMAL_FOURCC('p', 'c', 'm', 'u')
--#define MMAL_ENCODING_PCM_SIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'S')
--#define MMAL_ENCODING_PCM_SIGNED_LE MMAL_FOURCC('p', 'c', 'm', 's')
--#define MMAL_ENCODING_PCM_FLOAT_BE MMAL_FOURCC('P', 'C', 'M', 'F')
--#define MMAL_ENCODING_PCM_FLOAT_LE MMAL_FOURCC('p', 'c', 'm', 'f')
--
--/* Pre-defined H264 encoding variants */
--
--/** ISO 14496-10 Annex B byte stream format */
--#define MMAL_ENCODING_VARIANT_H264_DEFAULT 0
--/** ISO 14496-15 AVC stream format */
--#define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1')
--/** Implicitly delineated NAL units without emulation prevention */
--#define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ')
--
--/** \defgroup MmalColorSpace List of pre-defined video color spaces
-- * This defines a list of common color spaces. This list isn't exhaustive and
-- * is only provided as a convenience to avoid clients having to use FourCC
-- * codes directly. However components are allowed to define and use their own
-- * FourCC codes.
-- */
--/* @{ */
--
--/** Unknown color space */
--#define MMAL_COLOR_SPACE_UNKNOWN 0
--/** ITU-R BT.601-5 [SDTV] */
--#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1')
--/** ITU-R BT.709-3 [HDTV] */
--#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9')
--/** JPEG JFIF */
--#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I')
--/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
--#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C')
--/** Society of Motion Picture and Television Engineers 240M (1999) */
--#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0')
--/** ITU-R BT.470-2 System M */
--#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M')
--/** ITU-R BT.470-2 System BG */
--#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G')
--/** JPEG JFIF, but with 16..255 luma */
--#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6')
--/* @} MmalColorSpace List */
--
--#endif /* MMAL_ENCODINGS_H */
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h
-+++ /dev/null
-@@ -1,48 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0 */
--/*
-- * Broadcom BM2835 V4L2 driver
-- *
-- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-- *
-- * Authors: Vincent Sanders @ Collabora
-- * Dave Stevenson @ Broadcom
-- * Simon Mellor @ Broadcom
-- * Luke Diamand @ Broadcom
-- */
--
--#ifndef MMAL_MSG_COMMON_H
--#define MMAL_MSG_COMMON_H
--
--enum mmal_msg_status {
-- MMAL_MSG_STATUS_SUCCESS = 0, /**< Success */
-- MMAL_MSG_STATUS_ENOMEM, /**< Out of memory */
-- MMAL_MSG_STATUS_ENOSPC, /**< Out of resources other than memory */
-- MMAL_MSG_STATUS_EINVAL, /**< Argument is invalid */
-- MMAL_MSG_STATUS_ENOSYS, /**< Function not implemented */
-- MMAL_MSG_STATUS_ENOENT, /**< No such file or directory */
-- MMAL_MSG_STATUS_ENXIO, /**< No such device or address */
-- MMAL_MSG_STATUS_EIO, /**< I/O error */
-- MMAL_MSG_STATUS_ESPIPE, /**< Illegal seek */
-- MMAL_MSG_STATUS_ECORRUPT, /**< Data is corrupt \attention */
-- MMAL_MSG_STATUS_ENOTREADY, /**< Component is not ready */
-- MMAL_MSG_STATUS_ECONFIG, /**< Component is not configured */
-- MMAL_MSG_STATUS_EISCONN, /**< Port is already connected */
-- MMAL_MSG_STATUS_ENOTCONN, /**< Port is disconnected */
-- MMAL_MSG_STATUS_EAGAIN, /**< Resource temporarily unavailable. */
-- MMAL_MSG_STATUS_EFAULT, /**< Bad address */
--};
--
--struct mmal_rect {
-- s32 x; /**< x coordinate (from left) */
-- s32 y; /**< y coordinate (from top) */
-- s32 width; /**< width */
-- s32 height; /**< height */
--};
--
--struct mmal_rational {
-- s32 num; /**< Numerator */
-- s32 den; /**< Denominator */
--};
--
--#endif /* MMAL_MSG_COMMON_H */
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
-+++ /dev/null
-@@ -1,106 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0 */
--/*
-- * Broadcom BM2835 V4L2 driver
-- *
-- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-- *
-- * Authors: Vincent Sanders @ Collabora
-- * Dave Stevenson @ Broadcom
-- * Simon Mellor @ Broadcom
-- * Luke Diamand @ Broadcom
-- */
--
--#ifndef MMAL_MSG_FORMAT_H
--#define MMAL_MSG_FORMAT_H
--
--#include "mmal-msg-common.h"
--
--/* MMAL_ES_FORMAT_T */
--
--struct mmal_audio_format {
-- u32 channels; /* Number of audio channels */
-- u32 sample_rate; /* Sample rate */
--
-- u32 bits_per_sample; /* Bits per sample */
-- u32 block_align; /* Size of a block of data */
--};
--
--struct mmal_video_format {
-- u32 width; /* Width of frame in pixels */
-- u32 height; /* Height of frame in rows of pixels */
-- struct mmal_rect crop; /* Visible region of the frame */
-- struct mmal_rational frame_rate; /* Frame rate */
-- struct mmal_rational par; /* Pixel aspect ratio */
--
-- /*
-- * FourCC specifying the color space of the video stream. See the
-- * MmalColorSpace "pre-defined color spaces" for some examples.
-- */
-- u32 color_space;
--};
--
--struct mmal_subpicture_format {
-- u32 x_offset;
-- u32 y_offset;
--};
--
--union mmal_es_specific_format {
-- struct mmal_audio_format audio;
-- struct mmal_video_format video;
-- struct mmal_subpicture_format subpicture;
--};
--
--/* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
--struct mmal_es_format_local {
-- u32 type; /* enum mmal_es_type */
--
-- u32 encoding; /* FourCC specifying encoding of the elementary
-- * stream.
-- */
-- u32 encoding_variant; /* FourCC specifying the specific
-- * encoding variant of the elementary
-- * stream.
-- */
--
-- union mmal_es_specific_format *es; /* Type specific
-- * information for the
-- * elementary stream
-- */
--
-- u32 bitrate; /* Bitrate in bits per second */
-- u32 flags; /* Flags describing properties of the elementary
-- * stream.
-- */
--
-- u32 extradata_size; /* Size of the codec specific data */
-- u8 *extradata; /* Codec specific data */
--};
--
--/* Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
--struct mmal_es_format {
-- u32 type; /* enum mmal_es_type */
--
-- u32 encoding; /* FourCC specifying encoding of the elementary
-- * stream.
-- */
-- u32 encoding_variant; /* FourCC specifying the specific
-- * encoding variant of the elementary
-- * stream.
-- */
--
-- u32 es; /* Type specific
-- * information for the
-- * elementary stream
-- */
--
-- u32 bitrate; /* Bitrate in bits per second */
-- u32 flags; /* Flags describing properties of the elementary
-- * stream.
-- */
--
-- u32 extradata_size; /* Size of the codec specific data */
-- u32 extradata; /* Codec specific data */
--};
--
--#endif /* MMAL_MSG_FORMAT_H */
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
-+++ /dev/null
-@@ -1,109 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0 */
--/*
-- * Broadcom BM2835 V4L2 driver
-- *
-- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-- *
-- * Authors: Vincent Sanders @ Collabora
-- * Dave Stevenson @ Broadcom
-- * Simon Mellor @ Broadcom
-- * Luke Diamand @ Broadcom
-- */
--
--/* MMAL_PORT_TYPE_T */
--enum mmal_port_type {
-- MMAL_PORT_TYPE_UNKNOWN = 0, /* Unknown port type */
-- MMAL_PORT_TYPE_CONTROL, /* Control port */
-- MMAL_PORT_TYPE_INPUT, /* Input port */
-- MMAL_PORT_TYPE_OUTPUT, /* Output port */
-- MMAL_PORT_TYPE_CLOCK, /* Clock port */
--};
--
--/* The port is pass-through and doesn't need buffer headers allocated */
--#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01
--/*
-- *The port wants to allocate the buffer payloads.
-- * This signals a preference that payload allocation should be done
-- * on this port for efficiency reasons.
-- */
--#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02
--/*
-- * The port supports format change events.
-- * This applies to input ports and is used to let the client know
-- * whether the port supports being reconfigured via a format
-- * change event (i.e. without having to disable the port).
-- */
--#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04
--
--/*
-- * mmal port structure (MMAL_PORT_T)
-- *
-- * most elements are informational only, the pointer values for
-- * interogation messages are generally provided as additional
-- * structures within the message. When used to set values only the
-- * buffer_num, buffer_size and userdata parameters are writable.
-- */
--struct mmal_port {
-- u32 priv; /* Private member used by the framework */
-- u32 name; /* Port name. Used for debugging purposes (RO) */
--
-- u32 type; /* Type of the port (RO) enum mmal_port_type */
-- u16 index; /* Index of the port in its type list (RO) */
-- u16 index_all; /* Index of the port in the list of all ports (RO) */
--
-- u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
-- u32 format; /* Format of the elementary stream */
--
-- u32 buffer_num_min; /* Minimum number of buffers the port
-- * requires (RO). This is set by the
-- * component.
-- */
--
-- u32 buffer_size_min; /* Minimum size of buffers the port
-- * requires (RO). This is set by the
-- * component.
-- */
--
-- u32 buffer_alignment_min;/* Minimum alignment requirement for
-- * the buffers (RO). A value of
-- * zero means no special alignment
-- * requirements. This is set by the
-- * component.
-- */
--
-- u32 buffer_num_recommended; /* Number of buffers the port
-- * recommends for optimal
-- * performance (RO). A value of
-- * zero means no special
-- * recommendation. This is set
-- * by the component.
-- */
--
-- u32 buffer_size_recommended; /* Size of buffers the port
-- * recommends for optimal
-- * performance (RO). A value of
-- * zero means no special
-- * recommendation. This is set
-- * by the component.
-- */
--
-- u32 buffer_num; /* Actual number of buffers the port will use.
-- * This is set by the client.
-- */
--
-- u32 buffer_size; /* Actual maximum size of the buffers that
-- * will be sent to the port. This is set by
-- * the client.
-- */
--
-- u32 component; /* Component this port belongs to (Read Only) */
--
-- u32 userdata; /* Field reserved for use by the client */
--
-- u32 capabilities; /* Flags describing the capabilities of a
-- * port (RO). Bitwise combination of \ref
-- * portcapabilities "Port capabilities"
-- * values.
-- */
--};
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
-+++ /dev/null
-@@ -1,406 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0 */
--/*
-- * Broadcom BM2835 V4L2 driver
-- *
-- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-- *
-- * Authors: Vincent Sanders @ Collabora
-- * Dave Stevenson @ Broadcom
-- * Simon Mellor @ Broadcom
-- * Luke Diamand @ Broadcom
-- */
--
--/*
-- * all the data structures which serialise the MMAL protocol. note
-- * these are directly mapped onto the recived message data.
-- *
-- * BEWARE: They seem to *assume* pointers are u32 and that there is no
-- * structure padding!
-- *
-- * NOTE: this implementation uses kernel types to ensure sizes. Rather
-- * than assigning values to enums to force their size the
-- * implementation uses fixed size types and not the enums (though the
-- * comments have the actual enum type
-- */
--#ifndef MMAL_MSG_H
--#define MMAL_MSG_H
--
--#define VC_MMAL_VER 15
--#define VC_MMAL_MIN_VER 10
--#define VC_MMAL_SERVER_NAME MAKE_FOURCC("mmal")
--
--/* max total message size is 512 bytes */
--#define MMAL_MSG_MAX_SIZE 512
--/* with six 32bit header elements max payload is therefore 488 bytes */
--#define MMAL_MSG_MAX_PAYLOAD 488
--
--#include "mmal-msg-common.h"
--#include "mmal-msg-format.h"
--#include "mmal-msg-port.h"
--
--enum mmal_msg_type {
-- MMAL_MSG_TYPE_QUIT = 1,
-- MMAL_MSG_TYPE_SERVICE_CLOSED,
-- MMAL_MSG_TYPE_GET_VERSION,
-- MMAL_MSG_TYPE_COMPONENT_CREATE,
-- MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
-- MMAL_MSG_TYPE_COMPONENT_ENABLE,
-- MMAL_MSG_TYPE_COMPONENT_DISABLE,
-- MMAL_MSG_TYPE_PORT_INFO_GET,
-- MMAL_MSG_TYPE_PORT_INFO_SET,
-- MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
-- MMAL_MSG_TYPE_BUFFER_FROM_HOST,
-- MMAL_MSG_TYPE_BUFFER_TO_HOST,
-- MMAL_MSG_TYPE_GET_STATS,
-- MMAL_MSG_TYPE_PORT_PARAMETER_SET,
-- MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
-- MMAL_MSG_TYPE_EVENT_TO_HOST,
-- MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT,
-- MMAL_MSG_TYPE_OPAQUE_ALLOCATOR,
-- MMAL_MSG_TYPE_CONSUME_MEM,
-- MMAL_MSG_TYPE_LMK, /* 20 */
-- MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC,
-- MMAL_MSG_TYPE_DRM_GET_LHS32,
-- MMAL_MSG_TYPE_DRM_GET_TIME,
-- MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN,
-- MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
-- MMAL_MSG_TYPE_HOST_LOG,
-- MMAL_MSG_TYPE_MSG_LAST
--};
--
--/* port action request messages differ depending on the action type */
--enum mmal_msg_port_action_type {
-- MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */
-- MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
-- MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
-- MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
-- MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
-- MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
-- MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/
--};
--
--struct mmal_msg_header {
-- u32 magic;
-- u32 type; /* enum mmal_msg_type */
--
-- /* Opaque handle to the control service */
-- u32 control_service;
--
-- u32 context; /* a u32 per message context */
-- u32 status; /* The status of the vchiq operation */
-- u32 padding;
--};
--
--/* Send from VC to host to report version */
--struct mmal_msg_version {
-- u32 flags;
-- u32 major;
-- u32 minor;
-- u32 minimum;
--};
--
--/* request to VC to create component */
--struct mmal_msg_component_create {
-- u32 client_component; /* component context */
-- char name[128];
-- u32 pid; /* For debug */
--};
--
--/* reply from VC to component creation request */
--struct mmal_msg_component_create_reply {
-- u32 status; /* enum mmal_msg_status - how does this differ to
-- * the one in the header?
-- */
-- u32 component_handle; /* VideoCore handle for component */
-- u32 input_num; /* Number of input ports */
-- u32 output_num; /* Number of output ports */
-- u32 clock_num; /* Number of clock ports */
--};
--
--/* request to VC to destroy a component */
--struct mmal_msg_component_destroy {
-- u32 component_handle;
--};
--
--struct mmal_msg_component_destroy_reply {
-- u32 status; /* The component destruction status */
--};
--
--/* request and reply to VC to enable a component */
--struct mmal_msg_component_enable {
-- u32 component_handle;
--};
--
--struct mmal_msg_component_enable_reply {
-- u32 status; /* The component enable status */
--};
--
--/* request and reply to VC to disable a component */
--struct mmal_msg_component_disable {
-- u32 component_handle;
--};
--
--struct mmal_msg_component_disable_reply {
-- u32 status; /* The component disable status */
--};
--
--/* request to VC to get port information */
--struct mmal_msg_port_info_get {
-- u32 component_handle; /* component handle port is associated with */
-- u32 port_type; /* enum mmal_msg_port_type */
-- u32 index; /* port index to query */
--};
--
--/* reply from VC to get port info request */
--struct mmal_msg_port_info_get_reply {
-- u32 status; /* enum mmal_msg_status */
-- u32 component_handle; /* component handle port is associated with */
-- u32 port_type; /* enum mmal_msg_port_type */
-- u32 port_index; /* port indexed in query */
-- s32 found; /* unused */
-- u32 port_handle; /* Handle to use for this port */
-- struct mmal_port port;
-- struct mmal_es_format format; /* elementary stream format */
-- union mmal_es_specific_format es; /* es type specific data */
-- u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; /* es extra data */
--};
--
--/* request to VC to set port information */
--struct mmal_msg_port_info_set {
-- u32 component_handle;
-- u32 port_type; /* enum mmal_msg_port_type */
-- u32 port_index; /* port indexed in query */
-- struct mmal_port port;
-- struct mmal_es_format format;
-- union mmal_es_specific_format es;
-- u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
--};
--
--/* reply from VC to port info set request */
--struct mmal_msg_port_info_set_reply {
-- u32 status;
-- u32 component_handle; /* component handle port is associated with */
-- u32 port_type; /* enum mmal_msg_port_type */
-- u32 index; /* port indexed in query */
-- s32 found; /* unused */
-- u32 port_handle; /* Handle to use for this port */
-- struct mmal_port port;
-- struct mmal_es_format format;
-- union mmal_es_specific_format es;
-- u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
--};
--
--/* port action requests that take a mmal_port as a parameter */
--struct mmal_msg_port_action_port {
-- u32 component_handle;
-- u32 port_handle;
-- u32 action; /* enum mmal_msg_port_action_type */
-- struct mmal_port port;
--};
--
--/* port action requests that take handles as a parameter */
--struct mmal_msg_port_action_handle {
-- u32 component_handle;
-- u32 port_handle;
-- u32 action; /* enum mmal_msg_port_action_type */
-- u32 connect_component_handle;
-- u32 connect_port_handle;
--};
--
--struct mmal_msg_port_action_reply {
-- u32 status; /* The port action operation status */
--};
--
--/* MMAL buffer transfer */
--
--/* Size of space reserved in a buffer message for short messages. */
--#define MMAL_VC_SHORT_DATA 128
--
--/* Signals that the current payload is the end of the stream of data */
--#define MMAL_BUFFER_HEADER_FLAG_EOS BIT(0)
--/* Signals that the start of the current payload starts a frame */
--#define MMAL_BUFFER_HEADER_FLAG_FRAME_START BIT(1)
--/* Signals that the end of the current payload ends a frame */
--#define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2)
--/* Signals that the current payload contains only complete frames (>1) */
--#define MMAL_BUFFER_HEADER_FLAG_FRAME \
-- (MMAL_BUFFER_HEADER_FLAG_FRAME_START | \
-- MMAL_BUFFER_HEADER_FLAG_FRAME_END)
--/* Signals that the current payload is a keyframe (i.e. self decodable) */
--#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3)
--/*
-- * Signals a discontinuity in the stream of data (e.g. after a seek).
-- * Can be used for instance by a decoder to reset its state
-- */
--#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY BIT(4)
--/*
-- * Signals a buffer containing some kind of config data for the component
-- * (e.g. codec config data)
-- */
--#define MMAL_BUFFER_HEADER_FLAG_CONFIG BIT(5)
--/* Signals an encrypted payload */
--#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED BIT(6)
--/* Signals a buffer containing side information */
--#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO BIT(7)
--/*
-- * Signals a buffer which is the snapshot/postview image from a stills
-- * capture
-- */
--#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT BIT(8)
--/* Signals a buffer which contains data known to be corrupted */
--#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED BIT(9)
--/* Signals that a buffer failed to be transmitted */
--#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED BIT(10)
--
--struct mmal_driver_buffer {
-- u32 magic;
-- u32 component_handle;
-- u32 port_handle;
-- u32 client_context;
--};
--
--/* buffer header */
--struct mmal_buffer_header {
-- u32 next; /* next header */
-- u32 priv; /* framework private data */
-- u32 cmd;
-- u32 data;
-- u32 alloc_size;
-- u32 length;
-- u32 offset;
-- u32 flags;
-- s64 pts;
-- s64 dts;
-- u32 type;
-- u32 user_data;
--};
--
--struct mmal_buffer_header_type_specific {
-- union {
-- struct {
-- u32 planes;
-- u32 offset[4];
-- u32 pitch[4];
-- u32 flags;
-- } video;
-- } u;
--};
--
--struct mmal_msg_buffer_from_host {
-- /*
-- *The front 32 bytes of the buffer header are copied
-- * back to us in the reply to allow for context. This
-- * area is used to store two mmal_driver_buffer structures to
-- * allow for multiple concurrent service users.
-- */
-- /* control data */
-- struct mmal_driver_buffer drvbuf;
--
-- /* referenced control data for passthrough buffer management */
-- struct mmal_driver_buffer drvbuf_ref;
-- struct mmal_buffer_header buffer_header; /* buffer header itself */
-- struct mmal_buffer_header_type_specific buffer_header_type_specific;
-- s32 is_zero_copy;
-- s32 has_reference;
--
-- /* allows short data to be xfered in control message */
-- u32 payload_in_message;
-- u8 short_data[MMAL_VC_SHORT_DATA];
--};
--
--/* port parameter setting */
--
--#define MMAL_WORKER_PORT_PARAMETER_SPACE 96
--
--struct mmal_msg_port_parameter_set {
-- u32 component_handle; /* component */
-- u32 port_handle; /* port */
-- u32 id; /* Parameter ID */
-- u32 size; /* Parameter size */
-- uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
--};
--
--struct mmal_msg_port_parameter_set_reply {
-- u32 status; /* enum mmal_msg_status todo: how does this
-- * differ to the one in the header?
-- */
--};
--
--/* port parameter getting */
--
--struct mmal_msg_port_parameter_get {
-- u32 component_handle; /* component */
-- u32 port_handle; /* port */
-- u32 id; /* Parameter ID */
-- u32 size; /* Parameter size */
--};
--
--struct mmal_msg_port_parameter_get_reply {
-- u32 status; /* Status of mmal_port_parameter_get call */
-- u32 id; /* Parameter ID */
-- u32 size; /* Parameter size */
-- uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
--};
--
--/* event messages */
--#define MMAL_WORKER_EVENT_SPACE 256
--
--struct mmal_msg_event_to_host {
-- u32 client_component; /* component context */
--
-- u32 port_type;
-- u32 port_num;
--
-- u32 cmd;
-- u32 length;
-- u8 data[MMAL_WORKER_EVENT_SPACE];
-- u32 delayed_buffer;
--};
--
--/* all mmal messages are serialised through this structure */
--struct mmal_msg {
-- /* header */
-- struct mmal_msg_header h;
-- /* payload */
-- union {
-- struct mmal_msg_version version;
--
-- struct mmal_msg_component_create component_create;
-- struct mmal_msg_component_create_reply component_create_reply;
--
-- struct mmal_msg_component_destroy component_destroy;
-- struct mmal_msg_component_destroy_reply component_destroy_reply;
--
-- struct mmal_msg_component_enable component_enable;
-- struct mmal_msg_component_enable_reply component_enable_reply;
--
-- struct mmal_msg_component_disable component_disable;
-- struct mmal_msg_component_disable_reply component_disable_reply;
--
-- struct mmal_msg_port_info_get port_info_get;
-- struct mmal_msg_port_info_get_reply port_info_get_reply;
--
-- struct mmal_msg_port_info_set port_info_set;
-- struct mmal_msg_port_info_set_reply port_info_set_reply;
--
-- struct mmal_msg_port_action_port port_action_port;
-- struct mmal_msg_port_action_handle port_action_handle;
-- struct mmal_msg_port_action_reply port_action_reply;
--
-- struct mmal_msg_buffer_from_host buffer_from_host;
--
-- struct mmal_msg_port_parameter_set port_parameter_set;
-- struct mmal_msg_port_parameter_set_reply
-- port_parameter_set_reply;
-- struct mmal_msg_port_parameter_get
-- port_parameter_get;
-- struct mmal_msg_port_parameter_get_reply
-- port_parameter_get_reply;
--
-- struct mmal_msg_event_to_host event_to_host;
--
-- u8 payload[MMAL_MSG_MAX_PAYLOAD];
-- } u;
--};
--#endif
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
-+++ /dev/null
-@@ -1,755 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0 */
--/*
-- * Broadcom BM2835 V4L2 driver
-- *
-- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-- *
-- * Authors: Vincent Sanders @ Collabora
-- * Dave Stevenson @ Broadcom
-- * Simon Mellor @ Broadcom
-- * Luke Diamand @ Broadcom
-- */
--
--/* common parameters */
--
--/** @name Parameter groups
-- * Parameters are divided into groups, and then allocated sequentially within
-- * a group using an enum.
-- * @{
-- */
--
--#ifndef MMAL_PARAMETERS_H
--#define MMAL_PARAMETERS_H
--
--/** Common parameter ID group, used with many types of component. */
--#define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
--/** Camera-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16)
--/** Video-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16)
--/** Audio-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16)
--/** Clock-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16)
--/** Miracast-specific parameter ID group. */
--#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16)
--
--/* Common parameters */
--enum mmal_parameter_common_type {
-- /**< Never a valid parameter ID */
-- MMAL_PARAMETER_UNUSED = MMAL_PARAMETER_GROUP_COMMON,
--
-- /**< MMAL_PARAMETER_ENCODING_T */
-- MMAL_PARAMETER_SUPPORTED_ENCODINGS,
-- /**< MMAL_PARAMETER_URI_T */
-- MMAL_PARAMETER_URI,
-- /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
-- MMAL_PARAMETER_CHANGE_EVENT_REQUEST,
-- /** MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_ZERO_COPY,
-- /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
-- MMAL_PARAMETER_BUFFER_REQUIREMENTS,
-- /**< MMAL_PARAMETER_STATISTICS_T */
-- MMAL_PARAMETER_STATISTICS,
-- /**< MMAL_PARAMETER_CORE_STATISTICS_T */
-- MMAL_PARAMETER_CORE_STATISTICS,
-- /**< MMAL_PARAMETER_MEM_USAGE_T */
-- MMAL_PARAMETER_MEM_USAGE,
-- /**< MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_BUFFER_FLAG_FILTER,
-- /**< MMAL_PARAMETER_SEEK_T */
-- MMAL_PARAMETER_SEEK,
-- /**< MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_POWERMON_ENABLE,
-- /**< MMAL_PARAMETER_LOGGING_T */
-- MMAL_PARAMETER_LOGGING,
-- /**< MMAL_PARAMETER_UINT64_T */
-- MMAL_PARAMETER_SYSTEM_TIME,
-- /**< MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_NO_IMAGE_PADDING,
--};
--
--/* camera parameters */
--
--enum mmal_parameter_camera_type {
-- /* 0 */
-- /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
-- MMAL_PARAMETER_THUMBNAIL_CONFIGURATION =
-- MMAL_PARAMETER_GROUP_CAMERA,
-- /**< Unused? */
-- MMAL_PARAMETER_CAPTURE_QUALITY,
-- /**< @ref MMAL_PARAMETER_INT32_T */
-- MMAL_PARAMETER_ROTATION,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_EXIF_DISABLE,
-- /**< @ref MMAL_PARAMETER_EXIF_T */
-- MMAL_PARAMETER_EXIF,
-- /**< @ref MMAL_PARAM_AWBMODE_T */
-- MMAL_PARAMETER_AWB_MODE,
-- /**< @ref MMAL_PARAMETER_IMAGEFX_T */
-- MMAL_PARAMETER_IMAGE_EFFECT,
-- /**< @ref MMAL_PARAMETER_COLOURFX_T */
-- MMAL_PARAMETER_COLOUR_EFFECT,
-- /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
-- MMAL_PARAMETER_FLICKER_AVOID,
-- /**< @ref MMAL_PARAMETER_FLASH_T */
-- MMAL_PARAMETER_FLASH,
-- /**< @ref MMAL_PARAMETER_REDEYE_T */
-- MMAL_PARAMETER_REDEYE,
-- /**< @ref MMAL_PARAMETER_FOCUS_T */
-- MMAL_PARAMETER_FOCUS,
-- /**< Unused? */
-- MMAL_PARAMETER_FOCAL_LENGTHS,
-- /**< @ref MMAL_PARAMETER_INT32_T */
-- MMAL_PARAMETER_EXPOSURE_COMP,
-- /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
-- MMAL_PARAMETER_ZOOM,
-- /**< @ref MMAL_PARAMETER_MIRROR_T */
-- MMAL_PARAMETER_MIRROR,
--
-- /* 0x10 */
-- /**< @ref MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_CAMERA_NUM,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_CAPTURE,
-- /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
-- MMAL_PARAMETER_EXPOSURE_MODE,
-- /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
-- MMAL_PARAMETER_EXP_METERING_MODE,
-- /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
-- MMAL_PARAMETER_FOCUS_STATUS,
-- /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
-- MMAL_PARAMETER_CAMERA_CONFIG,
-- /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
-- MMAL_PARAMETER_CAPTURE_STATUS,
-- /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
-- MMAL_PARAMETER_FACE_TRACK,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS,
-- /**< @ref MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_JPEG_Q_FACTOR,
-- /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
-- MMAL_PARAMETER_FRAME_RATE,
-- /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
-- MMAL_PARAMETER_USE_STC,
-- /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
-- MMAL_PARAMETER_CAMERA_INFO,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_VIDEO_STABILISATION,
-- /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
-- MMAL_PARAMETER_FACE_TRACK_RESULTS,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_ENABLE_RAW_CAPTURE,
--
-- /* 0x20 */
-- /**< @ref MMAL_PARAMETER_URI_T */
-- MMAL_PARAMETER_DPF_FILE,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_ENABLE_DPF_FILE,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_DPF_FAIL_IS_FATAL,
-- /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
-- MMAL_PARAMETER_CAPTURE_MODE,
-- /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
-- MMAL_PARAMETER_FOCUS_REGIONS,
-- /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
-- MMAL_PARAMETER_INPUT_CROP,
-- /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
-- MMAL_PARAMETER_SENSOR_INFORMATION,
-- /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
-- MMAL_PARAMETER_FLASH_SELECT,
-- /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
-- MMAL_PARAMETER_FIELD_OF_VIEW,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,
-- /**< @ref MMAL_PARAMETER_DRC_T */
-- MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION,
-- /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
-- MMAL_PARAMETER_ALGORITHM_CONTROL,
-- /**< @ref MMAL_PARAMETER_RATIONAL_T */
-- MMAL_PARAMETER_SHARPNESS,
-- /**< @ref MMAL_PARAMETER_RATIONAL_T */
-- MMAL_PARAMETER_CONTRAST,
-- /**< @ref MMAL_PARAMETER_RATIONAL_T */
-- MMAL_PARAMETER_BRIGHTNESS,
-- /**< @ref MMAL_PARAMETER_RATIONAL_T */
-- MMAL_PARAMETER_SATURATION,
--
-- /* 0x30 */
-- /**< @ref MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_ISO,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_ANTISHAKE,
-- /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
-- MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
-- /** @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
-- /** @ref MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_CAMERA_MIN_ISO,
-- /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
-- MMAL_PARAMETER_CAMERA_USE_CASE,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_CAPTURE_STATS_PASS,
-- /** @ref MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG,
-- /** @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_ENABLE_REGISTER_FILE,
-- /** @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
-- /** @ref MMAL_PARAMETER_CONFIGFILE_T */
-- MMAL_PARAMETER_CONFIGFILE_REGISTERS,
-- /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
-- MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_JPEG_ATTACH_LOG,
-- /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
-- MMAL_PARAMETER_ZERO_SHUTTER_LAG,
-- /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
-- MMAL_PARAMETER_FPS_RANGE,
-- /**< @ref MMAL_PARAMETER_INT32_T */
-- MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP,
--
-- /* 0x40 */
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_SW_SHARPEN_DISABLE,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_FLASH_REQUIRED,
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_SW_SATURATION_DISABLE,
-- /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_SHUTTER_SPEED,
-- /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
-- MMAL_PARAMETER_CUSTOM_AWB_GAINS,
--};
--
--struct mmal_parameter_rational {
-- s32 num; /**< Numerator */
-- s32 den; /**< Denominator */
--};
--
--enum mmal_parameter_camera_config_timestamp_mode {
-- MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */
-- MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value
-- * for the frame timestamp
-- */
-- MMAL_PARAM_TIMESTAMP_MODE_RESET_STC, /* Use the STC timestamp
-- * but subtract the
-- * timestamp of the first
-- * frame sent to give a
-- * zero based timestamp.
-- */
--};
--
--struct mmal_parameter_fps_range {
-- /**< Low end of the permitted framerate range */
-- struct mmal_parameter_rational fps_low;
-- /**< High end of the permitted framerate range */
-- struct mmal_parameter_rational fps_high;
--};
--
--/* camera configuration parameter */
--struct mmal_parameter_camera_config {
-- /* Parameters for setting up the image pools */
-- u32 max_stills_w; /* Max size of stills capture */
-- u32 max_stills_h;
-- u32 stills_yuv422; /* Allow YUV422 stills capture */
-- u32 one_shot_stills; /* Continuous or one shot stills captures. */
--
-- u32 max_preview_video_w; /* Max size of the preview or video
-- * capture frames
-- */
-- u32 max_preview_video_h;
-- u32 num_preview_video_frames;
--
-- /** Sets the height of the circular buffer for stills capture. */
-- u32 stills_capture_circular_buffer_height;
--
-- /** Allows preview/encode to resume as fast as possible after the stills
-- * input frame has been received, and then processes the still frame in
-- * the background whilst preview/encode has resumed.
-- * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE.
-- */
-- u32 fast_preview_resume;
--
-- /** Selects algorithm for timestamping frames if
-- * there is no clock component connected.
-- * enum mmal_parameter_camera_config_timestamp_mode
-- */
-- s32 use_stc_timestamp;
--};
--
--enum mmal_parameter_exposuremode {
-- MMAL_PARAM_EXPOSUREMODE_OFF,
-- MMAL_PARAM_EXPOSUREMODE_AUTO,
-- MMAL_PARAM_EXPOSUREMODE_NIGHT,
-- MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,
-- MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,
-- MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,
-- MMAL_PARAM_EXPOSUREMODE_SPORTS,
-- MMAL_PARAM_EXPOSUREMODE_SNOW,
-- MMAL_PARAM_EXPOSUREMODE_BEACH,
-- MMAL_PARAM_EXPOSUREMODE_VERYLONG,
-- MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,
-- MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,
-- MMAL_PARAM_EXPOSUREMODE_FIREWORKS,
--};
--
--enum mmal_parameter_exposuremeteringmode {
-- MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE,
-- MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT,
-- MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT,
-- MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX,
--};
--
--enum mmal_parameter_awbmode {
-- MMAL_PARAM_AWBMODE_OFF,
-- MMAL_PARAM_AWBMODE_AUTO,
-- MMAL_PARAM_AWBMODE_SUNLIGHT,
-- MMAL_PARAM_AWBMODE_CLOUDY,
-- MMAL_PARAM_AWBMODE_SHADE,
-- MMAL_PARAM_AWBMODE_TUNGSTEN,
-- MMAL_PARAM_AWBMODE_FLUORESCENT,
-- MMAL_PARAM_AWBMODE_INCANDESCENT,
-- MMAL_PARAM_AWBMODE_FLASH,
-- MMAL_PARAM_AWBMODE_HORIZON,
--};
--
--enum mmal_parameter_imagefx {
-- MMAL_PARAM_IMAGEFX_NONE,
-- MMAL_PARAM_IMAGEFX_NEGATIVE,
-- MMAL_PARAM_IMAGEFX_SOLARIZE,
-- MMAL_PARAM_IMAGEFX_POSTERIZE,
-- MMAL_PARAM_IMAGEFX_WHITEBOARD,
-- MMAL_PARAM_IMAGEFX_BLACKBOARD,
-- MMAL_PARAM_IMAGEFX_SKETCH,
-- MMAL_PARAM_IMAGEFX_DENOISE,
-- MMAL_PARAM_IMAGEFX_EMBOSS,
-- MMAL_PARAM_IMAGEFX_OILPAINT,
-- MMAL_PARAM_IMAGEFX_HATCH,
-- MMAL_PARAM_IMAGEFX_GPEN,
-- MMAL_PARAM_IMAGEFX_PASTEL,
-- MMAL_PARAM_IMAGEFX_WATERCOLOUR,
-- MMAL_PARAM_IMAGEFX_FILM,
-- MMAL_PARAM_IMAGEFX_BLUR,
-- MMAL_PARAM_IMAGEFX_SATURATION,
-- MMAL_PARAM_IMAGEFX_COLOURSWAP,
-- MMAL_PARAM_IMAGEFX_WASHEDOUT,
-- MMAL_PARAM_IMAGEFX_POSTERISE,
-- MMAL_PARAM_IMAGEFX_COLOURPOINT,
-- MMAL_PARAM_IMAGEFX_COLOURBALANCE,
-- MMAL_PARAM_IMAGEFX_CARTOON,
--};
--
--enum MMAL_PARAM_FLICKERAVOID_T {
-- MMAL_PARAM_FLICKERAVOID_OFF,
-- MMAL_PARAM_FLICKERAVOID_AUTO,
-- MMAL_PARAM_FLICKERAVOID_50HZ,
-- MMAL_PARAM_FLICKERAVOID_60HZ,
-- MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF
--};
--
--struct mmal_parameter_awbgains {
-- struct mmal_parameter_rational r_gain; /**< Red gain */
-- struct mmal_parameter_rational b_gain; /**< Blue gain */
--};
--
--/** Manner of video rate control */
--enum mmal_parameter_rate_control_mode {
-- MMAL_VIDEO_RATECONTROL_DEFAULT,
-- MMAL_VIDEO_RATECONTROL_VARIABLE,
-- MMAL_VIDEO_RATECONTROL_CONSTANT,
-- MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES,
-- MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES
--};
--
--enum mmal_video_profile {
-- MMAL_VIDEO_PROFILE_H263_BASELINE,
-- MMAL_VIDEO_PROFILE_H263_H320CODING,
-- MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE,
-- MMAL_VIDEO_PROFILE_H263_ISWV2,
-- MMAL_VIDEO_PROFILE_H263_ISWV3,
-- MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION,
-- MMAL_VIDEO_PROFILE_H263_INTERNET,
-- MMAL_VIDEO_PROFILE_H263_INTERLACE,
-- MMAL_VIDEO_PROFILE_H263_HIGHLATENCY,
-- MMAL_VIDEO_PROFILE_MP4V_SIMPLE,
-- MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE,
-- MMAL_VIDEO_PROFILE_MP4V_CORE,
-- MMAL_VIDEO_PROFILE_MP4V_MAIN,
-- MMAL_VIDEO_PROFILE_MP4V_NBIT,
-- MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE,
-- MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE,
-- MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA,
-- MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED,
-- MMAL_VIDEO_PROFILE_MP4V_HYBRID,
-- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME,
-- MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE,
-- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING,
-- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE,
-- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE,
-- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE,
-- MMAL_VIDEO_PROFILE_H264_BASELINE,
-- MMAL_VIDEO_PROFILE_H264_MAIN,
-- MMAL_VIDEO_PROFILE_H264_EXTENDED,
-- MMAL_VIDEO_PROFILE_H264_HIGH,
-- MMAL_VIDEO_PROFILE_H264_HIGH10,
-- MMAL_VIDEO_PROFILE_H264_HIGH422,
-- MMAL_VIDEO_PROFILE_H264_HIGH444,
-- MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE,
-- MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF
--};
--
--enum mmal_video_level {
-- MMAL_VIDEO_LEVEL_H263_10,
-- MMAL_VIDEO_LEVEL_H263_20,
-- MMAL_VIDEO_LEVEL_H263_30,
-- MMAL_VIDEO_LEVEL_H263_40,
-- MMAL_VIDEO_LEVEL_H263_45,
-- MMAL_VIDEO_LEVEL_H263_50,
-- MMAL_VIDEO_LEVEL_H263_60,
-- MMAL_VIDEO_LEVEL_H263_70,
-- MMAL_VIDEO_LEVEL_MP4V_0,
-- MMAL_VIDEO_LEVEL_MP4V_0b,
-- MMAL_VIDEO_LEVEL_MP4V_1,
-- MMAL_VIDEO_LEVEL_MP4V_2,
-- MMAL_VIDEO_LEVEL_MP4V_3,
-- MMAL_VIDEO_LEVEL_MP4V_4,
-- MMAL_VIDEO_LEVEL_MP4V_4a,
-- MMAL_VIDEO_LEVEL_MP4V_5,
-- MMAL_VIDEO_LEVEL_MP4V_6,
-- MMAL_VIDEO_LEVEL_H264_1,
-- MMAL_VIDEO_LEVEL_H264_1b,
-- MMAL_VIDEO_LEVEL_H264_11,
-- MMAL_VIDEO_LEVEL_H264_12,
-- MMAL_VIDEO_LEVEL_H264_13,
-- MMAL_VIDEO_LEVEL_H264_2,
-- MMAL_VIDEO_LEVEL_H264_21,
-- MMAL_VIDEO_LEVEL_H264_22,
-- MMAL_VIDEO_LEVEL_H264_3,
-- MMAL_VIDEO_LEVEL_H264_31,
-- MMAL_VIDEO_LEVEL_H264_32,
-- MMAL_VIDEO_LEVEL_H264_4,
-- MMAL_VIDEO_LEVEL_H264_41,
-- MMAL_VIDEO_LEVEL_H264_42,
-- MMAL_VIDEO_LEVEL_H264_5,
-- MMAL_VIDEO_LEVEL_H264_51,
-- MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF
--};
--
--struct mmal_parameter_video_profile {
-- enum mmal_video_profile profile;
-- enum mmal_video_level level;
--};
--
--/* video parameters */
--
--enum mmal_parameter_video_type {
-- /** @ref MMAL_DISPLAYREGION_T */
-- MMAL_PARAMETER_DISPLAYREGION = MMAL_PARAMETER_GROUP_VIDEO,
--
-- /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
-- MMAL_PARAMETER_SUPPORTED_PROFILES,
--
-- /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
-- MMAL_PARAMETER_PROFILE,
--
-- /** @ref MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_INTRAPERIOD,
--
-- /** @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */
-- MMAL_PARAMETER_RATECONTROL,
--
-- /** @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */
-- MMAL_PARAMETER_NALUNITFORMAT,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
--
-- /** @ref MMAL_PARAMETER_UINT32_T.
-- * Setting the value to zero resets to the default (one slice per
-- * frame).
-- */
-- MMAL_PARAMETER_MB_ROWS_PER_SLICE,
--
-- /** @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */
-- MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION,
--
-- /** @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */
-- MMAL_PARAMETER_VIDEO_EEDE_ENABLE,
--
-- /** @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */
-- MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T. Request an I-frame. */
-- MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
-- /** @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */
-- MMAL_PARAMETER_VIDEO_INTRA_REFRESH,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-- MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
--
-- /** @ref MMAL_PARAMETER_UINT32_T. Run-time bit rate control */
-- MMAL_PARAMETER_VIDEO_BIT_RATE,
--
-- /** @ref MMAL_PARAMETER_FRAME_RATE_T */
-- MMAL_PARAMETER_VIDEO_FRAME_RATE,
--
-- /** @ref MMAL_PARAMETER_UINT32_T. */
-- MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT,
--
-- /** @ref MMAL_PARAMETER_UINT32_T. */
-- MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT,
--
-- /** @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */
-- MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL,
--
-- MMAL_PARAMETER_EXTRA_BUFFERS, /**< @ref MMAL_PARAMETER_UINT32_T. */
-- /** @ref MMAL_PARAMETER_UINT32_T.
-- * Changing this parameter from the default can reduce frame rate
-- * because image buffers need to be re-pitched.
-- */
-- MMAL_PARAMETER_VIDEO_ALIGN_HORIZ,
--
-- /** @ref MMAL_PARAMETER_UINT32_T.
-- * Changing this parameter from the default can reduce frame rate
-- * because image buffers need to be re-pitched.
-- */
-- MMAL_PARAMETER_VIDEO_ALIGN_VERT,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-- MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES,
--
-- /** @ref MMAL_PARAMETER_UINT32_T. */
-- MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT,
--
-- /**< @ref MMAL_PARAMETER_UINT32_T. */
-- MMAL_PARAMETER_VIDEO_ENCODE_QP_P,
--
-- /**< @ref MMAL_PARAMETER_UINT32_T. */
-- MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT,
--
-- /** @ref MMAL_PARAMETER_UINT32_T */
-- MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS,
--
-- /** @ref MMAL_PARAMETER_UINT32_T. */
-- MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE,
--
-- /* H264 specific parameters */
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-- MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-- MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-- MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS,
--
-- /** @ref MMAL_PARAMETER_UINT32_T. */
-- MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC,
--
-- /** @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */
-- MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP,
--
-- /** @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */
-- MMAL_PARAMETER_VIDEO_DRM_INIT_INFO,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO,
--
-- /** @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT,
--
-- /** @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */
-- MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER,
--
-- /** @ref MMAL_PARAMETER_BYTES_T */
-- MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3,
--
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS,
--
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG,
--
-- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER
--};
--
--/** Valid mirror modes */
--enum mmal_parameter_mirror {
-- MMAL_PARAM_MIRROR_NONE,
-- MMAL_PARAM_MIRROR_VERTICAL,
-- MMAL_PARAM_MIRROR_HORIZONTAL,
-- MMAL_PARAM_MIRROR_BOTH,
--};
--
--enum mmal_parameter_displaytransform {
-- MMAL_DISPLAY_ROT0 = 0,
-- MMAL_DISPLAY_MIRROR_ROT0 = 1,
-- MMAL_DISPLAY_MIRROR_ROT180 = 2,
-- MMAL_DISPLAY_ROT180 = 3,
-- MMAL_DISPLAY_MIRROR_ROT90 = 4,
-- MMAL_DISPLAY_ROT270 = 5,
-- MMAL_DISPLAY_ROT90 = 6,
-- MMAL_DISPLAY_MIRROR_ROT270 = 7,
--};
--
--enum mmal_parameter_displaymode {
-- MMAL_DISPLAY_MODE_FILL = 0,
-- MMAL_DISPLAY_MODE_LETTERBOX = 1,
--};
--
--enum mmal_parameter_displayset {
-- MMAL_DISPLAY_SET_NONE = 0,
-- MMAL_DISPLAY_SET_NUM = 1,
-- MMAL_DISPLAY_SET_FULLSCREEN = 2,
-- MMAL_DISPLAY_SET_TRANSFORM = 4,
-- MMAL_DISPLAY_SET_DEST_RECT = 8,
-- MMAL_DISPLAY_SET_SRC_RECT = 0x10,
-- MMAL_DISPLAY_SET_MODE = 0x20,
-- MMAL_DISPLAY_SET_PIXEL = 0x40,
-- MMAL_DISPLAY_SET_NOASPECT = 0x80,
-- MMAL_DISPLAY_SET_LAYER = 0x100,
-- MMAL_DISPLAY_SET_COPYPROTECT = 0x200,
-- MMAL_DISPLAY_SET_ALPHA = 0x400,
--};
--
--/* rectangle, used lots so it gets its own struct */
--struct vchiq_mmal_rect {
-- s32 x;
-- s32 y;
-- s32 width;
-- s32 height;
--};
--
--struct mmal_parameter_displayregion {
-- /** Bitfield that indicates which fields are set and should be
-- * used. All other fields will maintain their current value.
-- * \ref MMAL_DISPLAYSET_T defines the bits that can be
-- * combined.
-- */
-- u32 set;
--
-- /** Describes the display output device, with 0 typically
-- * being a directly connected LCD display. The actual values
-- * will depend on the hardware. Code using hard-wired numbers
-- * (e.g. 2) is certain to fail.
-- */
--
-- u32 display_num;
-- /** Indicates that we are using the full device screen area,
-- * rather than a window of the display. If zero, then
-- * dest_rect is used to specify a region of the display to
-- * use.
-- */
--
-- s32 fullscreen;
-- /** Indicates any rotation or flipping used to map frames onto
-- * the natural display orientation.
-- */
-- u32 transform; /* enum mmal_parameter_displaytransform */
--
-- /** Where to display the frame within the screen, if
-- * fullscreen is zero.
-- */
-- struct vchiq_mmal_rect dest_rect;
--
-- /** Indicates which area of the frame to display. If all
-- * values are zero, the whole frame will be used.
-- */
-- struct vchiq_mmal_rect src_rect;
--
-- /** If set to non-zero, indicates that any display scaling
-- * should disregard the aspect ratio of the frame region being
-- * displayed.
-- */
-- s32 noaspect;
--
-- /** Indicates how the image should be scaled to fit the
-- * display. \code MMAL_DISPLAY_MODE_FILL \endcode indicates
-- * that the image should fill the screen by potentially
-- * cropping the frames. Setting \code mode \endcode to \code
-- * MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the
-- * source region should be displayed and black bars added if
-- * necessary.
-- */
-- u32 mode; /* enum mmal_parameter_displaymode */
--
-- /** If non-zero, defines the width of a source pixel relative
-- * to \code pixel_y \endcode. If zero, then pixels default to
-- * being square.
-- */
-- u32 pixel_x;
--
-- /** If non-zero, defines the height of a source pixel relative
-- * to \code pixel_x \endcode. If zero, then pixels default to
-- * being square.
-- */
-- u32 pixel_y;
--
-- /** Sets the relative depth of the images, with greater values
-- * being in front of smaller values.
-- */
-- u32 layer;
--
-- /** Set to non-zero to ensure copy protection is used on
-- * output.
-- */
-- s32 copyprotect_required;
--
-- /** Level of opacity of the layer, where zero is fully
-- * transparent and 255 is fully opaque.
-- */
-- u32 alpha;
--};
--
--#define MMAL_MAX_IMAGEFX_PARAMETERS 5
--
--struct mmal_parameter_imagefx_parameters {
-- enum mmal_parameter_imagefx effect;
-- u32 num_effect_params;
-- u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS];
--};
--
--#define MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS 4
--#define MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES 2
--#define MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN 16
--
--struct mmal_parameter_camera_info_camera_t {
-- u32 port_id;
-- u32 max_width;
-- u32 max_height;
-- u32 lens_present;
-- u8 camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN];
--};
--
--enum mmal_parameter_camera_info_flash_type_t {
-- /* Make values explicit to ensure they match values in config ini */
-- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON = 0,
-- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED = 1,
-- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER = 2,
-- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_MAX = 0x7FFFFFFF
--};
--
--struct mmal_parameter_camera_info_flash_t {
-- enum mmal_parameter_camera_info_flash_type_t flash_type;
--};
--
--struct mmal_parameter_camera_info_t {
-- u32 num_cameras;
-- u32 num_flashes;
-- struct mmal_parameter_camera_info_camera_t
-- cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS];
-- struct mmal_parameter_camera_info_flash_t
-- flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES];
--};
--
--#endif
---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
-+++ /dev/null
-@@ -1,166 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0 */
--/*
-- * Broadcom BM2835 V4L2 driver
-- *
-- * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-- *
-- * Authors: Vincent Sanders @ Collabora
-- * Dave Stevenson @ Broadcom
-- * Simon Mellor @ Broadcom
-- * Luke Diamand @ Broadcom
-- *
-- * MMAL interface to VCHIQ message passing
-- */
--
--#ifndef MMAL_VCHIQ_H
--#define MMAL_VCHIQ_H
--
--#include "mmal-msg-format.h"
--
--#define MAX_PORT_COUNT 4
--
--/* Maximum size of the format extradata. */
--#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128
--
--struct vchiq_mmal_instance;
--
--enum vchiq_mmal_es_type {
-- MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */
-- MMAL_ES_TYPE_CONTROL, /**< Elementary stream of control commands */
-- MMAL_ES_TYPE_AUDIO, /**< Audio elementary stream */
-- MMAL_ES_TYPE_VIDEO, /**< Video elementary stream */
-- MMAL_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream */
--};
--
--struct vchiq_mmal_port_buffer {
-- unsigned int num; /* number of buffers */
-- u32 size; /* size of buffers */
-- u32 alignment; /* alignment of buffers */
--};
--
--struct vchiq_mmal_port;
--
--typedef void (*vchiq_mmal_buffer_cb)(
-- struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- int status, struct mmal_buffer *buffer,
-- unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
--
--struct vchiq_mmal_port {
-- bool enabled;
-- u32 handle;
-- u32 type; /* port type, cached to use on port info set */
-- u32 index; /* port index, cached to use on port info set */
--
-- /* component port belongs to, allows simple deref */
-- struct vchiq_mmal_component *component;
--
-- struct vchiq_mmal_port *connected; /* port conencted to */
--
-- /* buffer info */
-- struct vchiq_mmal_port_buffer minimum_buffer;
-- struct vchiq_mmal_port_buffer recommended_buffer;
-- struct vchiq_mmal_port_buffer current_buffer;
--
-- /* stream format */
-- struct mmal_es_format_local format;
-- /* elementary stream format */
-- union mmal_es_specific_format es;
--
-- /* data buffers to fill */
-- struct list_head buffers;
-- /* lock to serialise adding and removing buffers from list */
-- spinlock_t slock;
--
-- /* Count of buffers the VPU has yet to return */
-- atomic_t buffers_with_vpu;
-- /* callback on buffer completion */
-- vchiq_mmal_buffer_cb buffer_cb;
-- /* callback context */
-- void *cb_ctx;
--};
--
--struct vchiq_mmal_component {
-- bool enabled;
-- u32 handle; /* VideoCore handle for component */
-- u32 inputs; /* Number of input ports */
-- u32 outputs; /* Number of output ports */
-- u32 clocks; /* Number of clock ports */
-- struct vchiq_mmal_port control; /* control port */
-- struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */
-- struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */
-- struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */
--};
--
--int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance);
--int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance);
--
--/* Initialise a mmal component and its ports
-- *
-- */
--int vchiq_mmal_component_init(
-- struct vchiq_mmal_instance *instance,
-- const char *name,
-- struct vchiq_mmal_component **component_out);
--
--int vchiq_mmal_component_finalise(
-- struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_component *component);
--
--int vchiq_mmal_component_enable(
-- struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_component *component);
--
--int vchiq_mmal_component_disable(
-- struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_component *component);
--
--/* enable a mmal port
-- *
-- * enables a port and if a buffer callback provided enque buffer
-- * headers as appropriate for the port.
-- */
--int vchiq_mmal_port_enable(
-- struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- vchiq_mmal_buffer_cb buffer_cb);
--
--/* disable a port
-- *
-- * disable a port will dequeue any pending buffers
-- */
--int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port);
--
--int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- u32 parameter,
-- void *value,
-- u32 value_size);
--
--int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- u32 parameter,
-- void *value,
-- u32 *value_size);
--
--int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port);
--
--int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *src,
-- struct vchiq_mmal_port *dst);
--
--int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
-- u32 *major_out,
-- u32 *minor_out);
--
--int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
-- struct vchiq_mmal_port *port,
-- struct mmal_buffer *buf);
--
--int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance,
-- struct mmal_buffer *buf);
--int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf);
--#endif /* MMAL_VCHIQ_H */
---- /dev/null
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
-@@ -0,0 +1,61 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
-+ *
-+ * MMAL structures
-+ *
-+ */
-+#ifndef MMAL_COMMON_H
-+#define MMAL_COMMON_H
-+
-+#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
-+#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l')
-+
-+/** Special value signalling that time is not known */
-+#define MMAL_TIME_UNKNOWN BIT_ULL(63)
-+
-+struct mmal_msg_context;
-+
-+/* mapping between v4l and mmal video modes */
-+struct mmal_fmt {
-+ char *name;
-+ u32 fourcc; /* v4l2 format id */
-+ int flags; /* v4l2 flags field */
-+ u32 mmal;
-+ int depth;
-+ u32 mmal_component; /* MMAL component index to be used to encode */
-+ u32 ybbp; /* depth of first Y plane for planar formats */
-+ bool remove_padding; /* Does the GPU have to remove padding,
-+ * or can we do hide padding via bytesperline.
-+ */
-+};
-+
-+/* buffer for one video frame */
-+struct mmal_buffer {
-+ /* v4l buffer data -- must be first */
-+ struct vb2_v4l2_buffer vb;
-+
-+ /* list of buffers available */
-+ struct list_head list;
-+
-+ void *buffer; /* buffer pointer */
-+ unsigned long buffer_size; /* size of allocated buffer */
-+
-+ struct mmal_msg_context *msg_context;
-+};
-+
-+/* */
-+struct mmal_colourfx {
-+ s32 enable;
-+ u32 u;
-+ u32 v;
-+};
-+#endif
---- /dev/null
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h
-@@ -0,0 +1,124 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
-+ */
-+#ifndef MMAL_ENCODINGS_H
-+#define MMAL_ENCODINGS_H
-+
-+#define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4')
-+#define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3')
-+#define MMAL_ENCODING_MP4V MMAL_FOURCC('M', 'P', '4', 'V')
-+#define MMAL_ENCODING_MP2V MMAL_FOURCC('M', 'P', '2', 'V')
-+#define MMAL_ENCODING_MP1V MMAL_FOURCC('M', 'P', '1', 'V')
-+#define MMAL_ENCODING_WMV3 MMAL_FOURCC('W', 'M', 'V', '3')
-+#define MMAL_ENCODING_WMV2 MMAL_FOURCC('W', 'M', 'V', '2')
-+#define MMAL_ENCODING_WMV1 MMAL_FOURCC('W', 'M', 'V', '1')
-+#define MMAL_ENCODING_WVC1 MMAL_FOURCC('W', 'V', 'C', '1')
-+#define MMAL_ENCODING_VP8 MMAL_FOURCC('V', 'P', '8', ' ')
-+#define MMAL_ENCODING_VP7 MMAL_FOURCC('V', 'P', '7', ' ')
-+#define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ')
-+#define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O')
-+#define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K')
-+#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G')
-+
-+#define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G')
-+#define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ')
-+#define MMAL_ENCODING_PNG MMAL_FOURCC('P', 'N', 'G', ' ')
-+#define MMAL_ENCODING_PPM MMAL_FOURCC('P', 'P', 'M', ' ')
-+#define MMAL_ENCODING_TGA MMAL_FOURCC('T', 'G', 'A', ' ')
-+#define MMAL_ENCODING_BMP MMAL_FOURCC('B', 'M', 'P', ' ')
-+
-+#define MMAL_ENCODING_I420 MMAL_FOURCC('I', '4', '2', '0')
-+#define MMAL_ENCODING_I420_SLICE MMAL_FOURCC('S', '4', '2', '0')
-+#define MMAL_ENCODING_YV12 MMAL_FOURCC('Y', 'V', '1', '2')
-+#define MMAL_ENCODING_I422 MMAL_FOURCC('I', '4', '2', '2')
-+#define MMAL_ENCODING_I422_SLICE MMAL_FOURCC('S', '4', '2', '2')
-+#define MMAL_ENCODING_YUYV MMAL_FOURCC('Y', 'U', 'Y', 'V')
-+#define MMAL_ENCODING_YVYU MMAL_FOURCC('Y', 'V', 'Y', 'U')
-+#define MMAL_ENCODING_UYVY MMAL_FOURCC('U', 'Y', 'V', 'Y')
-+#define MMAL_ENCODING_VYUY MMAL_FOURCC('V', 'Y', 'U', 'Y')
-+#define MMAL_ENCODING_NV12 MMAL_FOURCC('N', 'V', '1', '2')
-+#define MMAL_ENCODING_NV21 MMAL_FOURCC('N', 'V', '2', '1')
-+#define MMAL_ENCODING_ARGB MMAL_FOURCC('A', 'R', 'G', 'B')
-+#define MMAL_ENCODING_RGBA MMAL_FOURCC('R', 'G', 'B', 'A')
-+#define MMAL_ENCODING_ABGR MMAL_FOURCC('A', 'B', 'G', 'R')
-+#define MMAL_ENCODING_BGRA MMAL_FOURCC('B', 'G', 'R', 'A')
-+#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R', 'G', 'B', '2')
-+#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R', 'G', 'B', '3')
-+#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R', 'G', 'B', '4')
-+#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B', 'G', 'R', '2')
-+#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B', 'G', 'R', '3')
-+#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B', 'G', 'R', '4')
-+
-+/** SAND Video (YUVUV128) format, native format understood by VideoCore.
-+ * This format is *not* opaque - if requested you will receive full frames
-+ * of YUV_UV video.
-+ */
-+#define MMAL_ENCODING_YUVUV128 MMAL_FOURCC('S', 'A', 'N', 'D')
-+
-+/** VideoCore opaque image format, image handles are returned to
-+ * the host but not the actual image data.
-+ */
-+#define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V')
-+
-+/** An EGL image handle
-+ */
-+#define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I')
-+
-+/* }@ */
-+
-+/** \name Pre-defined audio encodings */
-+/* @{ */
-+#define MMAL_ENCODING_PCM_UNSIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'U')
-+#define MMAL_ENCODING_PCM_UNSIGNED_LE MMAL_FOURCC('p', 'c', 'm', 'u')
-+#define MMAL_ENCODING_PCM_SIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'S')
-+#define MMAL_ENCODING_PCM_SIGNED_LE MMAL_FOURCC('p', 'c', 'm', 's')
-+#define MMAL_ENCODING_PCM_FLOAT_BE MMAL_FOURCC('P', 'C', 'M', 'F')
-+#define MMAL_ENCODING_PCM_FLOAT_LE MMAL_FOURCC('p', 'c', 'm', 'f')
-+
-+/* Pre-defined H264 encoding variants */
-+
-+/** ISO 14496-10 Annex B byte stream format */
-+#define MMAL_ENCODING_VARIANT_H264_DEFAULT 0
-+/** ISO 14496-15 AVC stream format */
-+#define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1')
-+/** Implicitly delineated NAL units without emulation prevention */
-+#define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ')
-+
-+/** \defgroup MmalColorSpace List of pre-defined video color spaces
-+ * This defines a list of common color spaces. This list isn't exhaustive and
-+ * is only provided as a convenience to avoid clients having to use FourCC
-+ * codes directly. However components are allowed to define and use their own
-+ * FourCC codes.
-+ */
-+/* @{ */
-+
-+/** Unknown color space */
-+#define MMAL_COLOR_SPACE_UNKNOWN 0
-+/** ITU-R BT.601-5 [SDTV] */
-+#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1')
-+/** ITU-R BT.709-3 [HDTV] */
-+#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9')
-+/** JPEG JFIF */
-+#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I')
-+/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
-+#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C')
-+/** Society of Motion Picture and Television Engineers 240M (1999) */
-+#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0')
-+/** ITU-R BT.470-2 System M */
-+#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M')
-+/** ITU-R BT.470-2 System BG */
-+#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G')
-+/** JPEG JFIF, but with 16..255 luma */
-+#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6')
-+/* @} MmalColorSpace List */
-+
-+#endif /* MMAL_ENCODINGS_H */
---- /dev/null
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-common.h
-@@ -0,0 +1,48 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
-+ */
-+
-+#ifndef MMAL_MSG_COMMON_H
-+#define MMAL_MSG_COMMON_H
-+
-+enum mmal_msg_status {
-+ MMAL_MSG_STATUS_SUCCESS = 0, /**< Success */
-+ MMAL_MSG_STATUS_ENOMEM, /**< Out of memory */
-+ MMAL_MSG_STATUS_ENOSPC, /**< Out of resources other than memory */
-+ MMAL_MSG_STATUS_EINVAL, /**< Argument is invalid */
-+ MMAL_MSG_STATUS_ENOSYS, /**< Function not implemented */
-+ MMAL_MSG_STATUS_ENOENT, /**< No such file or directory */
-+ MMAL_MSG_STATUS_ENXIO, /**< No such device or address */
-+ MMAL_MSG_STATUS_EIO, /**< I/O error */
-+ MMAL_MSG_STATUS_ESPIPE, /**< Illegal seek */
-+ MMAL_MSG_STATUS_ECORRUPT, /**< Data is corrupt \attention */
-+ MMAL_MSG_STATUS_ENOTREADY, /**< Component is not ready */
-+ MMAL_MSG_STATUS_ECONFIG, /**< Component is not configured */
-+ MMAL_MSG_STATUS_EISCONN, /**< Port is already connected */
-+ MMAL_MSG_STATUS_ENOTCONN, /**< Port is disconnected */
-+ MMAL_MSG_STATUS_EAGAIN, /**< Resource temporarily unavailable. */
-+ MMAL_MSG_STATUS_EFAULT, /**< Bad address */
-+};
-+
-+struct mmal_rect {
-+ s32 x; /**< x coordinate (from left) */
-+ s32 y; /**< y coordinate (from top) */
-+ s32 width; /**< width */
-+ s32 height; /**< height */
-+};
-+
-+struct mmal_rational {
-+ s32 num; /**< Numerator */
-+ s32 den; /**< Denominator */
-+};
-+
-+#endif /* MMAL_MSG_COMMON_H */
---- /dev/null
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-format.h
-@@ -0,0 +1,106 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
-+ */
-+
-+#ifndef MMAL_MSG_FORMAT_H
-+#define MMAL_MSG_FORMAT_H
-+
-+#include "mmal-msg-common.h"
-+
-+/* MMAL_ES_FORMAT_T */
-+
-+struct mmal_audio_format {
-+ u32 channels; /* Number of audio channels */
-+ u32 sample_rate; /* Sample rate */
-+
-+ u32 bits_per_sample; /* Bits per sample */
-+ u32 block_align; /* Size of a block of data */
-+};
-+
-+struct mmal_video_format {
-+ u32 width; /* Width of frame in pixels */
-+ u32 height; /* Height of frame in rows of pixels */
-+ struct mmal_rect crop; /* Visible region of the frame */
-+ struct mmal_rational frame_rate; /* Frame rate */
-+ struct mmal_rational par; /* Pixel aspect ratio */
-+
-+ /*
-+ * FourCC specifying the color space of the video stream. See the
-+ * MmalColorSpace "pre-defined color spaces" for some examples.
-+ */
-+ u32 color_space;
-+};
-+
-+struct mmal_subpicture_format {
-+ u32 x_offset;
-+ u32 y_offset;
-+};
-+
-+union mmal_es_specific_format {
-+ struct mmal_audio_format audio;
-+ struct mmal_video_format video;
-+ struct mmal_subpicture_format subpicture;
-+};
-+
-+/* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
-+struct mmal_es_format_local {
-+ u32 type; /* enum mmal_es_type */
-+
-+ u32 encoding; /* FourCC specifying encoding of the elementary
-+ * stream.
-+ */
-+ u32 encoding_variant; /* FourCC specifying the specific
-+ * encoding variant of the elementary
-+ * stream.
-+ */
-+
-+ union mmal_es_specific_format *es; /* Type specific
-+ * information for the
-+ * elementary stream
-+ */
-+
-+ u32 bitrate; /* Bitrate in bits per second */
-+ u32 flags; /* Flags describing properties of the elementary
-+ * stream.
-+ */
-+
-+ u32 extradata_size; /* Size of the codec specific data */
-+ u8 *extradata; /* Codec specific data */
-+};
-+
-+/* Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
-+struct mmal_es_format {
-+ u32 type; /* enum mmal_es_type */
-+
-+ u32 encoding; /* FourCC specifying encoding of the elementary
-+ * stream.
-+ */
-+ u32 encoding_variant; /* FourCC specifying the specific
-+ * encoding variant of the elementary
-+ * stream.
-+ */
-+
-+ u32 es; /* Type specific
-+ * information for the
-+ * elementary stream
-+ */
-+
-+ u32 bitrate; /* Bitrate in bits per second */
-+ u32 flags; /* Flags describing properties of the elementary
-+ * stream.
-+ */
-+
-+ u32 extradata_size; /* Size of the codec specific data */
-+ u32 extradata; /* Codec specific data */
-+};
-+
-+#endif /* MMAL_MSG_FORMAT_H */
---- /dev/null
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-port.h
-@@ -0,0 +1,109 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
-+ */
-+
-+/* MMAL_PORT_TYPE_T */
-+enum mmal_port_type {
-+ MMAL_PORT_TYPE_UNKNOWN = 0, /* Unknown port type */
-+ MMAL_PORT_TYPE_CONTROL, /* Control port */
-+ MMAL_PORT_TYPE_INPUT, /* Input port */
-+ MMAL_PORT_TYPE_OUTPUT, /* Output port */
-+ MMAL_PORT_TYPE_CLOCK, /* Clock port */
-+};
-+
-+/* The port is pass-through and doesn't need buffer headers allocated */
-+#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01
-+/*
-+ *The port wants to allocate the buffer payloads.
-+ * This signals a preference that payload allocation should be done
-+ * on this port for efficiency reasons.
-+ */
-+#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02
-+/*
-+ * The port supports format change events.
-+ * This applies to input ports and is used to let the client know
-+ * whether the port supports being reconfigured via a format
-+ * change event (i.e. without having to disable the port).
-+ */
-+#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04
-+
-+/*
-+ * mmal port structure (MMAL_PORT_T)
-+ *
-+ * most elements are informational only, the pointer values for
-+ * interogation messages are generally provided as additional
-+ * structures within the message. When used to set values only the
-+ * buffer_num, buffer_size and userdata parameters are writable.
-+ */
-+struct mmal_port {
-+ u32 priv; /* Private member used by the framework */
-+ u32 name; /* Port name. Used for debugging purposes (RO) */
-+
-+ u32 type; /* Type of the port (RO) enum mmal_port_type */
-+ u16 index; /* Index of the port in its type list (RO) */
-+ u16 index_all; /* Index of the port in the list of all ports (RO) */
-+
-+ u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
-+ u32 format; /* Format of the elementary stream */
-+
-+ u32 buffer_num_min; /* Minimum number of buffers the port
-+ * requires (RO). This is set by the
-+ * component.
-+ */
-+
-+ u32 buffer_size_min; /* Minimum size of buffers the port
-+ * requires (RO). This is set by the
-+ * component.
-+ */
-+
-+ u32 buffer_alignment_min;/* Minimum alignment requirement for
-+ * the buffers (RO). A value of
-+ * zero means no special alignment
-+ * requirements. This is set by the
-+ * component.
-+ */
-+
-+ u32 buffer_num_recommended; /* Number of buffers the port
-+ * recommends for optimal
-+ * performance (RO). A value of
-+ * zero means no special
-+ * recommendation. This is set
-+ * by the component.
-+ */
-+
-+ u32 buffer_size_recommended; /* Size of buffers the port
-+ * recommends for optimal
-+ * performance (RO). A value of
-+ * zero means no special
-+ * recommendation. This is set
-+ * by the component.
-+ */
-+
-+ u32 buffer_num; /* Actual number of buffers the port will use.
-+ * This is set by the client.
-+ */
-+
-+ u32 buffer_size; /* Actual maximum size of the buffers that
-+ * will be sent to the port. This is set by
-+ * the client.
-+ */
-+
-+ u32 component; /* Component this port belongs to (Read Only) */
-+
-+ u32 userdata; /* Field reserved for use by the client */
-+
-+ u32 capabilities; /* Flags describing the capabilities of a
-+ * port (RO). Bitwise combination of \ref
-+ * portcapabilities "Port capabilities"
-+ * values.
-+ */
-+};
---- /dev/null
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h
-@@ -0,0 +1,406 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
-+ */
-+
-+/*
-+ * all the data structures which serialise the MMAL protocol. note
-+ * these are directly mapped onto the recived message data.
-+ *
-+ * BEWARE: They seem to *assume* pointers are u32 and that there is no
-+ * structure padding!
-+ *
-+ * NOTE: this implementation uses kernel types to ensure sizes. Rather
-+ * than assigning values to enums to force their size the
-+ * implementation uses fixed size types and not the enums (though the
-+ * comments have the actual enum type
-+ */
-+#ifndef MMAL_MSG_H
-+#define MMAL_MSG_H
-+
-+#define VC_MMAL_VER 15
-+#define VC_MMAL_MIN_VER 10
-+#define VC_MMAL_SERVER_NAME MAKE_FOURCC("mmal")
-+
-+/* max total message size is 512 bytes */
-+#define MMAL_MSG_MAX_SIZE 512
-+/* with six 32bit header elements max payload is therefore 488 bytes */
-+#define MMAL_MSG_MAX_PAYLOAD 488
-+
-+#include "mmal-msg-common.h"
-+#include "mmal-msg-format.h"
-+#include "mmal-msg-port.h"
-+
-+enum mmal_msg_type {
-+ MMAL_MSG_TYPE_QUIT = 1,
-+ MMAL_MSG_TYPE_SERVICE_CLOSED,
-+ MMAL_MSG_TYPE_GET_VERSION,
-+ MMAL_MSG_TYPE_COMPONENT_CREATE,
-+ MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
-+ MMAL_MSG_TYPE_COMPONENT_ENABLE,
-+ MMAL_MSG_TYPE_COMPONENT_DISABLE,
-+ MMAL_MSG_TYPE_PORT_INFO_GET,
-+ MMAL_MSG_TYPE_PORT_INFO_SET,
-+ MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
-+ MMAL_MSG_TYPE_BUFFER_FROM_HOST,
-+ MMAL_MSG_TYPE_BUFFER_TO_HOST,
-+ MMAL_MSG_TYPE_GET_STATS,
-+ MMAL_MSG_TYPE_PORT_PARAMETER_SET,
-+ MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
-+ MMAL_MSG_TYPE_EVENT_TO_HOST,
-+ MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT,
-+ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR,
-+ MMAL_MSG_TYPE_CONSUME_MEM,
-+ MMAL_MSG_TYPE_LMK, /* 20 */
-+ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC,
-+ MMAL_MSG_TYPE_DRM_GET_LHS32,
-+ MMAL_MSG_TYPE_DRM_GET_TIME,
-+ MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN,
-+ MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
-+ MMAL_MSG_TYPE_HOST_LOG,
-+ MMAL_MSG_TYPE_MSG_LAST
-+};
-+
-+/* port action request messages differ depending on the action type */
-+enum mmal_msg_port_action_type {
-+ MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */
-+ MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
-+ MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
-+ MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
-+ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
-+ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
-+ MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/
-+};
-+
-+struct mmal_msg_header {
-+ u32 magic;
-+ u32 type; /* enum mmal_msg_type */
-+
-+ /* Opaque handle to the control service */
-+ u32 control_service;
-+
-+ u32 context; /* a u32 per message context */
-+ u32 status; /* The status of the vchiq operation */
-+ u32 padding;
-+};
-+
-+/* Send from VC to host to report version */
-+struct mmal_msg_version {
-+ u32 flags;
-+ u32 major;
-+ u32 minor;
-+ u32 minimum;
-+};
-+
-+/* request to VC to create component */
-+struct mmal_msg_component_create {
-+ u32 client_component; /* component context */
-+ char name[128];
-+ u32 pid; /* For debug */
-+};
-+
-+/* reply from VC to component creation request */
-+struct mmal_msg_component_create_reply {
-+ u32 status; /* enum mmal_msg_status - how does this differ to
-+ * the one in the header?
-+ */
-+ u32 component_handle; /* VideoCore handle for component */
-+ u32 input_num; /* Number of input ports */
-+ u32 output_num; /* Number of output ports */
-+ u32 clock_num; /* Number of clock ports */
-+};
-+
-+/* request to VC to destroy a component */
-+struct mmal_msg_component_destroy {
-+ u32 component_handle;
-+};
-+
-+struct mmal_msg_component_destroy_reply {
-+ u32 status; /* The component destruction status */
-+};
-+
-+/* request and reply to VC to enable a component */
-+struct mmal_msg_component_enable {
-+ u32 component_handle;
-+};
-+
-+struct mmal_msg_component_enable_reply {
-+ u32 status; /* The component enable status */
-+};
-+
-+/* request and reply to VC to disable a component */
-+struct mmal_msg_component_disable {
-+ u32 component_handle;
-+};
-+
-+struct mmal_msg_component_disable_reply {
-+ u32 status; /* The component disable status */
-+};
-+
-+/* request to VC to get port information */
-+struct mmal_msg_port_info_get {
-+ u32 component_handle; /* component handle port is associated with */
-+ u32 port_type; /* enum mmal_msg_port_type */
-+ u32 index; /* port index to query */
-+};
-+
-+/* reply from VC to get port info request */
-+struct mmal_msg_port_info_get_reply {
-+ u32 status; /* enum mmal_msg_status */
-+ u32 component_handle; /* component handle port is associated with */
-+ u32 port_type; /* enum mmal_msg_port_type */
-+ u32 port_index; /* port indexed in query */
-+ s32 found; /* unused */
-+ u32 port_handle; /* Handle to use for this port */
-+ struct mmal_port port;
-+ struct mmal_es_format format; /* elementary stream format */
-+ union mmal_es_specific_format es; /* es type specific data */
-+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; /* es extra data */
-+};
-+
-+/* request to VC to set port information */
-+struct mmal_msg_port_info_set {
-+ u32 component_handle;
-+ u32 port_type; /* enum mmal_msg_port_type */
-+ u32 port_index; /* port indexed in query */
-+ struct mmal_port port;
-+ struct mmal_es_format format;
-+ union mmal_es_specific_format es;
-+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
-+};
-+
-+/* reply from VC to port info set request */
-+struct mmal_msg_port_info_set_reply {
-+ u32 status;
-+ u32 component_handle; /* component handle port is associated with */
-+ u32 port_type; /* enum mmal_msg_port_type */
-+ u32 index; /* port indexed in query */
-+ s32 found; /* unused */
-+ u32 port_handle; /* Handle to use for this port */
-+ struct mmal_port port;
-+ struct mmal_es_format format;
-+ union mmal_es_specific_format es;
-+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
-+};
-+
-+/* port action requests that take a mmal_port as a parameter */
-+struct mmal_msg_port_action_port {
-+ u32 component_handle;
-+ u32 port_handle;
-+ u32 action; /* enum mmal_msg_port_action_type */
-+ struct mmal_port port;
-+};
-+
-+/* port action requests that take handles as a parameter */
-+struct mmal_msg_port_action_handle {
-+ u32 component_handle;
-+ u32 port_handle;
-+ u32 action; /* enum mmal_msg_port_action_type */
-+ u32 connect_component_handle;
-+ u32 connect_port_handle;
-+};
-+
-+struct mmal_msg_port_action_reply {
-+ u32 status; /* The port action operation status */
-+};
-+
-+/* MMAL buffer transfer */
-+
-+/* Size of space reserved in a buffer message for short messages. */
-+#define MMAL_VC_SHORT_DATA 128
-+
-+/* Signals that the current payload is the end of the stream of data */
-+#define MMAL_BUFFER_HEADER_FLAG_EOS BIT(0)
-+/* Signals that the start of the current payload starts a frame */
-+#define MMAL_BUFFER_HEADER_FLAG_FRAME_START BIT(1)
-+/* Signals that the end of the current payload ends a frame */
-+#define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2)
-+/* Signals that the current payload contains only complete frames (>1) */
-+#define MMAL_BUFFER_HEADER_FLAG_FRAME \
-+ (MMAL_BUFFER_HEADER_FLAG_FRAME_START | \
-+ MMAL_BUFFER_HEADER_FLAG_FRAME_END)
-+/* Signals that the current payload is a keyframe (i.e. self decodable) */
-+#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3)
-+/*
-+ * Signals a discontinuity in the stream of data (e.g. after a seek).
-+ * Can be used for instance by a decoder to reset its state
-+ */
-+#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY BIT(4)
-+/*
-+ * Signals a buffer containing some kind of config data for the component
-+ * (e.g. codec config data)
-+ */
-+#define MMAL_BUFFER_HEADER_FLAG_CONFIG BIT(5)
-+/* Signals an encrypted payload */
-+#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED BIT(6)
-+/* Signals a buffer containing side information */
-+#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO BIT(7)
-+/*
-+ * Signals a buffer which is the snapshot/postview image from a stills
-+ * capture
-+ */
-+#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT BIT(8)
-+/* Signals a buffer which contains data known to be corrupted */
-+#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED BIT(9)
-+/* Signals that a buffer failed to be transmitted */
-+#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED BIT(10)
-+
-+struct mmal_driver_buffer {
-+ u32 magic;
-+ u32 component_handle;
-+ u32 port_handle;
-+ u32 client_context;
-+};
-+
-+/* buffer header */
-+struct mmal_buffer_header {
-+ u32 next; /* next header */
-+ u32 priv; /* framework private data */
-+ u32 cmd;
-+ u32 data;
-+ u32 alloc_size;
-+ u32 length;
-+ u32 offset;
-+ u32 flags;
-+ s64 pts;
-+ s64 dts;
-+ u32 type;
-+ u32 user_data;
-+};
-+
-+struct mmal_buffer_header_type_specific {
-+ union {
-+ struct {
-+ u32 planes;
-+ u32 offset[4];
-+ u32 pitch[4];
-+ u32 flags;
-+ } video;
-+ } u;
-+};
-+
-+struct mmal_msg_buffer_from_host {
-+ /*
-+ *The front 32 bytes of the buffer header are copied
-+ * back to us in the reply to allow for context. This
-+ * area is used to store two mmal_driver_buffer structures to
-+ * allow for multiple concurrent service users.
-+ */
-+ /* control data */
-+ struct mmal_driver_buffer drvbuf;
-+
-+ /* referenced control data for passthrough buffer management */
-+ struct mmal_driver_buffer drvbuf_ref;
-+ struct mmal_buffer_header buffer_header; /* buffer header itself */
-+ struct mmal_buffer_header_type_specific buffer_header_type_specific;
-+ s32 is_zero_copy;
-+ s32 has_reference;
-+
-+ /* allows short data to be xfered in control message */
-+ u32 payload_in_message;
-+ u8 short_data[MMAL_VC_SHORT_DATA];
-+};
-+
-+/* port parameter setting */
-+
-+#define MMAL_WORKER_PORT_PARAMETER_SPACE 96
-+
-+struct mmal_msg_port_parameter_set {
-+ u32 component_handle; /* component */
-+ u32 port_handle; /* port */
-+ u32 id; /* Parameter ID */
-+ u32 size; /* Parameter size */
-+ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
-+};
-+
-+struct mmal_msg_port_parameter_set_reply {
-+ u32 status; /* enum mmal_msg_status todo: how does this
-+ * differ to the one in the header?
-+ */
-+};
-+
-+/* port parameter getting */
-+
-+struct mmal_msg_port_parameter_get {
-+ u32 component_handle; /* component */
-+ u32 port_handle; /* port */
-+ u32 id; /* Parameter ID */
-+ u32 size; /* Parameter size */
-+};
-+
-+struct mmal_msg_port_parameter_get_reply {
-+ u32 status; /* Status of mmal_port_parameter_get call */
-+ u32 id; /* Parameter ID */
-+ u32 size; /* Parameter size */
-+ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
-+};
-+
-+/* event messages */
-+#define MMAL_WORKER_EVENT_SPACE 256
-+
-+struct mmal_msg_event_to_host {
-+ u32 client_component; /* component context */
-+
-+ u32 port_type;
-+ u32 port_num;
-+
-+ u32 cmd;
-+ u32 length;
-+ u8 data[MMAL_WORKER_EVENT_SPACE];
-+ u32 delayed_buffer;
-+};
-+
-+/* all mmal messages are serialised through this structure */
-+struct mmal_msg {
-+ /* header */
-+ struct mmal_msg_header h;
-+ /* payload */
-+ union {
-+ struct mmal_msg_version version;
-+
-+ struct mmal_msg_component_create component_create;
-+ struct mmal_msg_component_create_reply component_create_reply;
-+
-+ struct mmal_msg_component_destroy component_destroy;
-+ struct mmal_msg_component_destroy_reply component_destroy_reply;
-+
-+ struct mmal_msg_component_enable component_enable;
-+ struct mmal_msg_component_enable_reply component_enable_reply;
-+
-+ struct mmal_msg_component_disable component_disable;
-+ struct mmal_msg_component_disable_reply component_disable_reply;
-+
-+ struct mmal_msg_port_info_get port_info_get;
-+ struct mmal_msg_port_info_get_reply port_info_get_reply;
-+
-+ struct mmal_msg_port_info_set port_info_set;
-+ struct mmal_msg_port_info_set_reply port_info_set_reply;
-+
-+ struct mmal_msg_port_action_port port_action_port;
-+ struct mmal_msg_port_action_handle port_action_handle;
-+ struct mmal_msg_port_action_reply port_action_reply;
-+
-+ struct mmal_msg_buffer_from_host buffer_from_host;
-+
-+ struct mmal_msg_port_parameter_set port_parameter_set;
-+ struct mmal_msg_port_parameter_set_reply
-+ port_parameter_set_reply;
-+ struct mmal_msg_port_parameter_get
-+ port_parameter_get;
-+ struct mmal_msg_port_parameter_get_reply
-+ port_parameter_get_reply;
-+
-+ struct mmal_msg_event_to_host event_to_host;
-+
-+ u8 payload[MMAL_MSG_MAX_PAYLOAD];
-+ } u;
-+};
-+#endif
---- /dev/null
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
-@@ -0,0 +1,755 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
-+ */
-+
-+/* common parameters */
-+
-+/** @name Parameter groups
-+ * Parameters are divided into groups, and then allocated sequentially within
-+ * a group using an enum.
-+ * @{
-+ */
-+
-+#ifndef MMAL_PARAMETERS_H
-+#define MMAL_PARAMETERS_H
-+
-+/** Common parameter ID group, used with many types of component. */
-+#define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
-+/** Camera-specific parameter ID group. */
-+#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16)
-+/** Video-specific parameter ID group. */
-+#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16)
-+/** Audio-specific parameter ID group. */
-+#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16)
-+/** Clock-specific parameter ID group. */
-+#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16)
-+/** Miracast-specific parameter ID group. */
-+#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16)
-+
-+/* Common parameters */
-+enum mmal_parameter_common_type {
-+ /**< Never a valid parameter ID */
-+ MMAL_PARAMETER_UNUSED = MMAL_PARAMETER_GROUP_COMMON,
-+
-+ /**< MMAL_PARAMETER_ENCODING_T */
-+ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
-+ /**< MMAL_PARAMETER_URI_T */
-+ MMAL_PARAMETER_URI,
-+ /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
-+ MMAL_PARAMETER_CHANGE_EVENT_REQUEST,
-+ /** MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_ZERO_COPY,
-+ /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
-+ MMAL_PARAMETER_BUFFER_REQUIREMENTS,
-+ /**< MMAL_PARAMETER_STATISTICS_T */
-+ MMAL_PARAMETER_STATISTICS,
-+ /**< MMAL_PARAMETER_CORE_STATISTICS_T */
-+ MMAL_PARAMETER_CORE_STATISTICS,
-+ /**< MMAL_PARAMETER_MEM_USAGE_T */
-+ MMAL_PARAMETER_MEM_USAGE,
-+ /**< MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_BUFFER_FLAG_FILTER,
-+ /**< MMAL_PARAMETER_SEEK_T */
-+ MMAL_PARAMETER_SEEK,
-+ /**< MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_POWERMON_ENABLE,
-+ /**< MMAL_PARAMETER_LOGGING_T */
-+ MMAL_PARAMETER_LOGGING,
-+ /**< MMAL_PARAMETER_UINT64_T */
-+ MMAL_PARAMETER_SYSTEM_TIME,
-+ /**< MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_NO_IMAGE_PADDING,
-+};
-+
-+/* camera parameters */
-+
-+enum mmal_parameter_camera_type {
-+ /* 0 */
-+ /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
-+ MMAL_PARAMETER_THUMBNAIL_CONFIGURATION =
-+ MMAL_PARAMETER_GROUP_CAMERA,
-+ /**< Unused? */
-+ MMAL_PARAMETER_CAPTURE_QUALITY,
-+ /**< @ref MMAL_PARAMETER_INT32_T */
-+ MMAL_PARAMETER_ROTATION,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_EXIF_DISABLE,
-+ /**< @ref MMAL_PARAMETER_EXIF_T */
-+ MMAL_PARAMETER_EXIF,
-+ /**< @ref MMAL_PARAM_AWBMODE_T */
-+ MMAL_PARAMETER_AWB_MODE,
-+ /**< @ref MMAL_PARAMETER_IMAGEFX_T */
-+ MMAL_PARAMETER_IMAGE_EFFECT,
-+ /**< @ref MMAL_PARAMETER_COLOURFX_T */
-+ MMAL_PARAMETER_COLOUR_EFFECT,
-+ /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
-+ MMAL_PARAMETER_FLICKER_AVOID,
-+ /**< @ref MMAL_PARAMETER_FLASH_T */
-+ MMAL_PARAMETER_FLASH,
-+ /**< @ref MMAL_PARAMETER_REDEYE_T */
-+ MMAL_PARAMETER_REDEYE,
-+ /**< @ref MMAL_PARAMETER_FOCUS_T */
-+ MMAL_PARAMETER_FOCUS,
-+ /**< Unused? */
-+ MMAL_PARAMETER_FOCAL_LENGTHS,
-+ /**< @ref MMAL_PARAMETER_INT32_T */
-+ MMAL_PARAMETER_EXPOSURE_COMP,
-+ /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
-+ MMAL_PARAMETER_ZOOM,
-+ /**< @ref MMAL_PARAMETER_MIRROR_T */
-+ MMAL_PARAMETER_MIRROR,
-+
-+ /* 0x10 */
-+ /**< @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_CAMERA_NUM,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_CAPTURE,
-+ /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
-+ MMAL_PARAMETER_EXPOSURE_MODE,
-+ /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
-+ MMAL_PARAMETER_EXP_METERING_MODE,
-+ /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
-+ MMAL_PARAMETER_FOCUS_STATUS,
-+ /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
-+ MMAL_PARAMETER_CAMERA_CONFIG,
-+ /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
-+ MMAL_PARAMETER_CAPTURE_STATUS,
-+ /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
-+ MMAL_PARAMETER_FACE_TRACK,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS,
-+ /**< @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_JPEG_Q_FACTOR,
-+ /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
-+ MMAL_PARAMETER_FRAME_RATE,
-+ /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
-+ MMAL_PARAMETER_USE_STC,
-+ /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
-+ MMAL_PARAMETER_CAMERA_INFO,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_STABILISATION,
-+ /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
-+ MMAL_PARAMETER_FACE_TRACK_RESULTS,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_ENABLE_RAW_CAPTURE,
-+
-+ /* 0x20 */
-+ /**< @ref MMAL_PARAMETER_URI_T */
-+ MMAL_PARAMETER_DPF_FILE,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_ENABLE_DPF_FILE,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_DPF_FAIL_IS_FATAL,
-+ /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
-+ MMAL_PARAMETER_CAPTURE_MODE,
-+ /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
-+ MMAL_PARAMETER_FOCUS_REGIONS,
-+ /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
-+ MMAL_PARAMETER_INPUT_CROP,
-+ /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
-+ MMAL_PARAMETER_SENSOR_INFORMATION,
-+ /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
-+ MMAL_PARAMETER_FLASH_SELECT,
-+ /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
-+ MMAL_PARAMETER_FIELD_OF_VIEW,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,
-+ /**< @ref MMAL_PARAMETER_DRC_T */
-+ MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION,
-+ /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
-+ MMAL_PARAMETER_ALGORITHM_CONTROL,
-+ /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+ MMAL_PARAMETER_SHARPNESS,
-+ /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+ MMAL_PARAMETER_CONTRAST,
-+ /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+ MMAL_PARAMETER_BRIGHTNESS,
-+ /**< @ref MMAL_PARAMETER_RATIONAL_T */
-+ MMAL_PARAMETER_SATURATION,
-+
-+ /* 0x30 */
-+ /**< @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_ISO,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_ANTISHAKE,
-+ /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
-+ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
-+ /** @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_CAMERA_MIN_ISO,
-+ /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
-+ MMAL_PARAMETER_CAMERA_USE_CASE,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_CAPTURE_STATS_PASS,
-+ /** @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG,
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_ENABLE_REGISTER_FILE,
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
-+ /** @ref MMAL_PARAMETER_CONFIGFILE_T */
-+ MMAL_PARAMETER_CONFIGFILE_REGISTERS,
-+ /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
-+ MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_JPEG_ATTACH_LOG,
-+ /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
-+ MMAL_PARAMETER_ZERO_SHUTTER_LAG,
-+ /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
-+ MMAL_PARAMETER_FPS_RANGE,
-+ /**< @ref MMAL_PARAMETER_INT32_T */
-+ MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP,
-+
-+ /* 0x40 */
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_SW_SHARPEN_DISABLE,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_FLASH_REQUIRED,
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_SW_SATURATION_DISABLE,
-+ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_SHUTTER_SPEED,
-+ /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
-+ MMAL_PARAMETER_CUSTOM_AWB_GAINS,
-+};
-+
-+struct mmal_parameter_rational {
-+ s32 num; /**< Numerator */
-+ s32 den; /**< Denominator */
-+};
-+
-+enum mmal_parameter_camera_config_timestamp_mode {
-+ MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */
-+ MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value
-+ * for the frame timestamp
-+ */
-+ MMAL_PARAM_TIMESTAMP_MODE_RESET_STC, /* Use the STC timestamp
-+ * but subtract the
-+ * timestamp of the first
-+ * frame sent to give a
-+ * zero based timestamp.
-+ */
-+};
-+
-+struct mmal_parameter_fps_range {
-+ /**< Low end of the permitted framerate range */
-+ struct mmal_parameter_rational fps_low;
-+ /**< High end of the permitted framerate range */
-+ struct mmal_parameter_rational fps_high;
-+};
-+
-+/* camera configuration parameter */
-+struct mmal_parameter_camera_config {
-+ /* Parameters for setting up the image pools */
-+ u32 max_stills_w; /* Max size of stills capture */
-+ u32 max_stills_h;
-+ u32 stills_yuv422; /* Allow YUV422 stills capture */
-+ u32 one_shot_stills; /* Continuous or one shot stills captures. */
-+
-+ u32 max_preview_video_w; /* Max size of the preview or video
-+ * capture frames
-+ */
-+ u32 max_preview_video_h;
-+ u32 num_preview_video_frames;
-+
-+ /** Sets the height of the circular buffer for stills capture. */
-+ u32 stills_capture_circular_buffer_height;
-+
-+ /** Allows preview/encode to resume as fast as possible after the stills
-+ * input frame has been received, and then processes the still frame in
-+ * the background whilst preview/encode has resumed.
-+ * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE.
-+ */
-+ u32 fast_preview_resume;
-+
-+ /** Selects algorithm for timestamping frames if
-+ * there is no clock component connected.
-+ * enum mmal_parameter_camera_config_timestamp_mode
-+ */
-+ s32 use_stc_timestamp;
-+};
-+
-+enum mmal_parameter_exposuremode {
-+ MMAL_PARAM_EXPOSUREMODE_OFF,
-+ MMAL_PARAM_EXPOSUREMODE_AUTO,
-+ MMAL_PARAM_EXPOSUREMODE_NIGHT,
-+ MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,
-+ MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,
-+ MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,
-+ MMAL_PARAM_EXPOSUREMODE_SPORTS,
-+ MMAL_PARAM_EXPOSUREMODE_SNOW,
-+ MMAL_PARAM_EXPOSUREMODE_BEACH,
-+ MMAL_PARAM_EXPOSUREMODE_VERYLONG,
-+ MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,
-+ MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,
-+ MMAL_PARAM_EXPOSUREMODE_FIREWORKS,
-+};
-+
-+enum mmal_parameter_exposuremeteringmode {
-+ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE,
-+ MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT,
-+ MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT,
-+ MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX,
-+};
-+
-+enum mmal_parameter_awbmode {
-+ MMAL_PARAM_AWBMODE_OFF,
-+ MMAL_PARAM_AWBMODE_AUTO,
-+ MMAL_PARAM_AWBMODE_SUNLIGHT,
-+ MMAL_PARAM_AWBMODE_CLOUDY,
-+ MMAL_PARAM_AWBMODE_SHADE,
-+ MMAL_PARAM_AWBMODE_TUNGSTEN,
-+ MMAL_PARAM_AWBMODE_FLUORESCENT,
-+ MMAL_PARAM_AWBMODE_INCANDESCENT,
-+ MMAL_PARAM_AWBMODE_FLASH,
-+ MMAL_PARAM_AWBMODE_HORIZON,
-+};
-+
-+enum mmal_parameter_imagefx {
-+ MMAL_PARAM_IMAGEFX_NONE,
-+ MMAL_PARAM_IMAGEFX_NEGATIVE,
-+ MMAL_PARAM_IMAGEFX_SOLARIZE,
-+ MMAL_PARAM_IMAGEFX_POSTERIZE,
-+ MMAL_PARAM_IMAGEFX_WHITEBOARD,
-+ MMAL_PARAM_IMAGEFX_BLACKBOARD,
-+ MMAL_PARAM_IMAGEFX_SKETCH,
-+ MMAL_PARAM_IMAGEFX_DENOISE,
-+ MMAL_PARAM_IMAGEFX_EMBOSS,
-+ MMAL_PARAM_IMAGEFX_OILPAINT,
-+ MMAL_PARAM_IMAGEFX_HATCH,
-+ MMAL_PARAM_IMAGEFX_GPEN,
-+ MMAL_PARAM_IMAGEFX_PASTEL,
-+ MMAL_PARAM_IMAGEFX_WATERCOLOUR,
-+ MMAL_PARAM_IMAGEFX_FILM,
-+ MMAL_PARAM_IMAGEFX_BLUR,
-+ MMAL_PARAM_IMAGEFX_SATURATION,
-+ MMAL_PARAM_IMAGEFX_COLOURSWAP,
-+ MMAL_PARAM_IMAGEFX_WASHEDOUT,
-+ MMAL_PARAM_IMAGEFX_POSTERISE,
-+ MMAL_PARAM_IMAGEFX_COLOURPOINT,
-+ MMAL_PARAM_IMAGEFX_COLOURBALANCE,
-+ MMAL_PARAM_IMAGEFX_CARTOON,
-+};
-+
-+enum MMAL_PARAM_FLICKERAVOID_T {
-+ MMAL_PARAM_FLICKERAVOID_OFF,
-+ MMAL_PARAM_FLICKERAVOID_AUTO,
-+ MMAL_PARAM_FLICKERAVOID_50HZ,
-+ MMAL_PARAM_FLICKERAVOID_60HZ,
-+ MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF
-+};
-+
-+struct mmal_parameter_awbgains {
-+ struct mmal_parameter_rational r_gain; /**< Red gain */
-+ struct mmal_parameter_rational b_gain; /**< Blue gain */
-+};
-+
-+/** Manner of video rate control */
-+enum mmal_parameter_rate_control_mode {
-+ MMAL_VIDEO_RATECONTROL_DEFAULT,
-+ MMAL_VIDEO_RATECONTROL_VARIABLE,
-+ MMAL_VIDEO_RATECONTROL_CONSTANT,
-+ MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES,
-+ MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES
-+};
-+
-+enum mmal_video_profile {
-+ MMAL_VIDEO_PROFILE_H263_BASELINE,
-+ MMAL_VIDEO_PROFILE_H263_H320CODING,
-+ MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE,
-+ MMAL_VIDEO_PROFILE_H263_ISWV2,
-+ MMAL_VIDEO_PROFILE_H263_ISWV3,
-+ MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION,
-+ MMAL_VIDEO_PROFILE_H263_INTERNET,
-+ MMAL_VIDEO_PROFILE_H263_INTERLACE,
-+ MMAL_VIDEO_PROFILE_H263_HIGHLATENCY,
-+ MMAL_VIDEO_PROFILE_MP4V_SIMPLE,
-+ MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE,
-+ MMAL_VIDEO_PROFILE_MP4V_CORE,
-+ MMAL_VIDEO_PROFILE_MP4V_MAIN,
-+ MMAL_VIDEO_PROFILE_MP4V_NBIT,
-+ MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE,
-+ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE,
-+ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA,
-+ MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED,
-+ MMAL_VIDEO_PROFILE_MP4V_HYBRID,
-+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME,
-+ MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE,
-+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING,
-+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE,
-+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE,
-+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE,
-+ MMAL_VIDEO_PROFILE_H264_BASELINE,
-+ MMAL_VIDEO_PROFILE_H264_MAIN,
-+ MMAL_VIDEO_PROFILE_H264_EXTENDED,
-+ MMAL_VIDEO_PROFILE_H264_HIGH,
-+ MMAL_VIDEO_PROFILE_H264_HIGH10,
-+ MMAL_VIDEO_PROFILE_H264_HIGH422,
-+ MMAL_VIDEO_PROFILE_H264_HIGH444,
-+ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE,
-+ MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF
-+};
-+
-+enum mmal_video_level {
-+ MMAL_VIDEO_LEVEL_H263_10,
-+ MMAL_VIDEO_LEVEL_H263_20,
-+ MMAL_VIDEO_LEVEL_H263_30,
-+ MMAL_VIDEO_LEVEL_H263_40,
-+ MMAL_VIDEO_LEVEL_H263_45,
-+ MMAL_VIDEO_LEVEL_H263_50,
-+ MMAL_VIDEO_LEVEL_H263_60,
-+ MMAL_VIDEO_LEVEL_H263_70,
-+ MMAL_VIDEO_LEVEL_MP4V_0,
-+ MMAL_VIDEO_LEVEL_MP4V_0b,
-+ MMAL_VIDEO_LEVEL_MP4V_1,
-+ MMAL_VIDEO_LEVEL_MP4V_2,
-+ MMAL_VIDEO_LEVEL_MP4V_3,
-+ MMAL_VIDEO_LEVEL_MP4V_4,
-+ MMAL_VIDEO_LEVEL_MP4V_4a,
-+ MMAL_VIDEO_LEVEL_MP4V_5,
-+ MMAL_VIDEO_LEVEL_MP4V_6,
-+ MMAL_VIDEO_LEVEL_H264_1,
-+ MMAL_VIDEO_LEVEL_H264_1b,
-+ MMAL_VIDEO_LEVEL_H264_11,
-+ MMAL_VIDEO_LEVEL_H264_12,
-+ MMAL_VIDEO_LEVEL_H264_13,
-+ MMAL_VIDEO_LEVEL_H264_2,
-+ MMAL_VIDEO_LEVEL_H264_21,
-+ MMAL_VIDEO_LEVEL_H264_22,
-+ MMAL_VIDEO_LEVEL_H264_3,
-+ MMAL_VIDEO_LEVEL_H264_31,
-+ MMAL_VIDEO_LEVEL_H264_32,
-+ MMAL_VIDEO_LEVEL_H264_4,
-+ MMAL_VIDEO_LEVEL_H264_41,
-+ MMAL_VIDEO_LEVEL_H264_42,
-+ MMAL_VIDEO_LEVEL_H264_5,
-+ MMAL_VIDEO_LEVEL_H264_51,
-+ MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF
-+};
-+
-+struct mmal_parameter_video_profile {
-+ enum mmal_video_profile profile;
-+ enum mmal_video_level level;
-+};
-+
-+/* video parameters */
-+
-+enum mmal_parameter_video_type {
-+ /** @ref MMAL_DISPLAYREGION_T */
-+ MMAL_PARAMETER_DISPLAYREGION = MMAL_PARAMETER_GROUP_VIDEO,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
-+ MMAL_PARAMETER_SUPPORTED_PROFILES,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
-+ MMAL_PARAMETER_PROFILE,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_INTRAPERIOD,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */
-+ MMAL_PARAMETER_RATECONTROL,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */
-+ MMAL_PARAMETER_NALUNITFORMAT,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T.
-+ * Setting the value to zero resets to the default (one slice per
-+ * frame).
-+ */
-+ MMAL_PARAMETER_MB_ROWS_PER_SLICE,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */
-+ MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */
-+ MMAL_PARAMETER_VIDEO_EEDE_ENABLE,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */
-+ MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T. Request an I-frame. */
-+ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
-+ /** @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */
-+ MMAL_PARAMETER_VIDEO_INTRA_REFRESH,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-+ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T. Run-time bit rate control */
-+ MMAL_PARAMETER_VIDEO_BIT_RATE,
-+
-+ /** @ref MMAL_PARAMETER_FRAME_RATE_T */
-+ MMAL_PARAMETER_VIDEO_FRAME_RATE,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL,
-+
-+ MMAL_PARAMETER_EXTRA_BUFFERS, /**< @ref MMAL_PARAMETER_UINT32_T. */
-+ /** @ref MMAL_PARAMETER_UINT32_T.
-+ * Changing this parameter from the default can reduce frame rate
-+ * because image buffers need to be re-pitched.
-+ */
-+ MMAL_PARAMETER_VIDEO_ALIGN_HORIZ,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T.
-+ * Changing this parameter from the default can reduce frame rate
-+ * because image buffers need to be re-pitched.
-+ */
-+ MMAL_PARAMETER_VIDEO_ALIGN_VERT,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-+ MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT,
-+
-+ /**< @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_QP_P,
-+
-+ /**< @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE,
-+
-+ /* H264 specific parameters */
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS,
-+
-+ /** @ref MMAL_PARAMETER_UINT32_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */
-+ MMAL_PARAMETER_VIDEO_DRM_INIT_INFO,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO,
-+
-+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT,
-+
-+ /** @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */
-+ MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER,
-+
-+ /** @ref MMAL_PARAMETER_BYTES_T */
-+ MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3,
-+
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS,
-+
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG,
-+
-+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER
-+};
-+
-+/** Valid mirror modes */
-+enum mmal_parameter_mirror {
-+ MMAL_PARAM_MIRROR_NONE,
-+ MMAL_PARAM_MIRROR_VERTICAL,
-+ MMAL_PARAM_MIRROR_HORIZONTAL,
-+ MMAL_PARAM_MIRROR_BOTH,
-+};
-+
-+enum mmal_parameter_displaytransform {
-+ MMAL_DISPLAY_ROT0 = 0,
-+ MMAL_DISPLAY_MIRROR_ROT0 = 1,
-+ MMAL_DISPLAY_MIRROR_ROT180 = 2,
-+ MMAL_DISPLAY_ROT180 = 3,
-+ MMAL_DISPLAY_MIRROR_ROT90 = 4,
-+ MMAL_DISPLAY_ROT270 = 5,
-+ MMAL_DISPLAY_ROT90 = 6,
-+ MMAL_DISPLAY_MIRROR_ROT270 = 7,
-+};
-+
-+enum mmal_parameter_displaymode {
-+ MMAL_DISPLAY_MODE_FILL = 0,
-+ MMAL_DISPLAY_MODE_LETTERBOX = 1,
-+};
-+
-+enum mmal_parameter_displayset {
-+ MMAL_DISPLAY_SET_NONE = 0,
-+ MMAL_DISPLAY_SET_NUM = 1,
-+ MMAL_DISPLAY_SET_FULLSCREEN = 2,
-+ MMAL_DISPLAY_SET_TRANSFORM = 4,
-+ MMAL_DISPLAY_SET_DEST_RECT = 8,
-+ MMAL_DISPLAY_SET_SRC_RECT = 0x10,
-+ MMAL_DISPLAY_SET_MODE = 0x20,
-+ MMAL_DISPLAY_SET_PIXEL = 0x40,
-+ MMAL_DISPLAY_SET_NOASPECT = 0x80,
-+ MMAL_DISPLAY_SET_LAYER = 0x100,
-+ MMAL_DISPLAY_SET_COPYPROTECT = 0x200,
-+ MMAL_DISPLAY_SET_ALPHA = 0x400,
-+};
-+
-+/* rectangle, used lots so it gets its own struct */
-+struct vchiq_mmal_rect {
-+ s32 x;
-+ s32 y;
-+ s32 width;
-+ s32 height;
-+};
-+
-+struct mmal_parameter_displayregion {
-+ /** Bitfield that indicates which fields are set and should be
-+ * used. All other fields will maintain their current value.
-+ * \ref MMAL_DISPLAYSET_T defines the bits that can be
-+ * combined.
-+ */
-+ u32 set;
-+
-+ /** Describes the display output device, with 0 typically
-+ * being a directly connected LCD display. The actual values
-+ * will depend on the hardware. Code using hard-wired numbers
-+ * (e.g. 2) is certain to fail.
-+ */
-+
-+ u32 display_num;
-+ /** Indicates that we are using the full device screen area,
-+ * rather than a window of the display. If zero, then
-+ * dest_rect is used to specify a region of the display to
-+ * use.
-+ */
-+
-+ s32 fullscreen;
-+ /** Indicates any rotation or flipping used to map frames onto
-+ * the natural display orientation.
-+ */
-+ u32 transform; /* enum mmal_parameter_displaytransform */
-+
-+ /** Where to display the frame within the screen, if
-+ * fullscreen is zero.
-+ */
-+ struct vchiq_mmal_rect dest_rect;
-+
-+ /** Indicates which area of the frame to display. If all
-+ * values are zero, the whole frame will be used.
-+ */
-+ struct vchiq_mmal_rect src_rect;
-+
-+ /** If set to non-zero, indicates that any display scaling
-+ * should disregard the aspect ratio of the frame region being
-+ * displayed.
-+ */
-+ s32 noaspect;
-+
-+ /** Indicates how the image should be scaled to fit the
-+ * display. \code MMAL_DISPLAY_MODE_FILL \endcode indicates
-+ * that the image should fill the screen by potentially
-+ * cropping the frames. Setting \code mode \endcode to \code
-+ * MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the
-+ * source region should be displayed and black bars added if
-+ * necessary.
-+ */
-+ u32 mode; /* enum mmal_parameter_displaymode */
-+
-+ /** If non-zero, defines the width of a source pixel relative
-+ * to \code pixel_y \endcode. If zero, then pixels default to
-+ * being square.
-+ */
-+ u32 pixel_x;
-+
-+ /** If non-zero, defines the height of a source pixel relative
-+ * to \code pixel_x \endcode. If zero, then pixels default to
-+ * being square.
-+ */
-+ u32 pixel_y;
-+
-+ /** Sets the relative depth of the images, with greater values
-+ * being in front of smaller values.
-+ */
-+ u32 layer;
-+
-+ /** Set to non-zero to ensure copy protection is used on
-+ * output.
-+ */
-+ s32 copyprotect_required;
-+
-+ /** Level of opacity of the layer, where zero is fully
-+ * transparent and 255 is fully opaque.
-+ */
-+ u32 alpha;
-+};
-+
-+#define MMAL_MAX_IMAGEFX_PARAMETERS 5
-+
-+struct mmal_parameter_imagefx_parameters {
-+ enum mmal_parameter_imagefx effect;
-+ u32 num_effect_params;
-+ u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS];
-+};
-+
-+#define MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS 4
-+#define MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES 2
-+#define MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN 16
-+
-+struct mmal_parameter_camera_info_camera_t {
-+ u32 port_id;
-+ u32 max_width;
-+ u32 max_height;
-+ u32 lens_present;
-+ u8 camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN];
-+};
-+
-+enum mmal_parameter_camera_info_flash_type_t {
-+ /* Make values explicit to ensure they match values in config ini */
-+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON = 0,
-+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED = 1,
-+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER = 2,
-+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_MAX = 0x7FFFFFFF
-+};
-+
-+struct mmal_parameter_camera_info_flash_t {
-+ enum mmal_parameter_camera_info_flash_type_t flash_type;
-+};
-+
-+struct mmal_parameter_camera_info_t {
-+ u32 num_cameras;
-+ u32 num_flashes;
-+ struct mmal_parameter_camera_info_camera_t
-+ cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS];
-+ struct mmal_parameter_camera_info_flash_t
-+ flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES];
-+};
-+
-+#endif
---- /dev/null
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-@@ -0,0 +1,166 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Broadcom BM2835 V4L2 driver
-+ *
-+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
-+ *
-+ * Authors: Vincent Sanders @ Collabora
-+ * Dave Stevenson @ Broadcom
-+ * Simon Mellor @ Broadcom
-+ * Luke Diamand @ Broadcom
-+ *
-+ * MMAL interface to VCHIQ message passing
-+ */
-+
-+#ifndef MMAL_VCHIQ_H
-+#define MMAL_VCHIQ_H
-+
-+#include "mmal-msg-format.h"
-+
-+#define MAX_PORT_COUNT 4
-+
-+/* Maximum size of the format extradata. */
-+#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128
-+
-+struct vchiq_mmal_instance;
-+
-+enum vchiq_mmal_es_type {
-+ MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */
-+ MMAL_ES_TYPE_CONTROL, /**< Elementary stream of control commands */
-+ MMAL_ES_TYPE_AUDIO, /**< Audio elementary stream */
-+ MMAL_ES_TYPE_VIDEO, /**< Video elementary stream */
-+ MMAL_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream */
-+};
-+
-+struct vchiq_mmal_port_buffer {
-+ unsigned int num; /* number of buffers */
-+ u32 size; /* size of buffers */
-+ u32 alignment; /* alignment of buffers */
-+};
-+
-+struct vchiq_mmal_port;
-+
-+typedef void (*vchiq_mmal_buffer_cb)(
-+ struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ int status, struct mmal_buffer *buffer,
-+ unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
-+
-+struct vchiq_mmal_port {
-+ bool enabled;
-+ u32 handle;
-+ u32 type; /* port type, cached to use on port info set */
-+ u32 index; /* port index, cached to use on port info set */
-+
-+ /* component port belongs to, allows simple deref */
-+ struct vchiq_mmal_component *component;
-+
-+ struct vchiq_mmal_port *connected; /* port conencted to */
-+
-+ /* buffer info */
-+ struct vchiq_mmal_port_buffer minimum_buffer;
-+ struct vchiq_mmal_port_buffer recommended_buffer;
-+ struct vchiq_mmal_port_buffer current_buffer;
-+
-+ /* stream format */
-+ struct mmal_es_format_local format;
-+ /* elementary stream format */
-+ union mmal_es_specific_format es;
-+
-+ /* data buffers to fill */
-+ struct list_head buffers;
-+ /* lock to serialise adding and removing buffers from list */
-+ spinlock_t slock;
-+
-+ /* Count of buffers the VPU has yet to return */
-+ atomic_t buffers_with_vpu;
-+ /* callback on buffer completion */
-+ vchiq_mmal_buffer_cb buffer_cb;
-+ /* callback context */
-+ void *cb_ctx;
-+};
-+
-+struct vchiq_mmal_component {
-+ bool enabled;
-+ u32 handle; /* VideoCore handle for component */
-+ u32 inputs; /* Number of input ports */
-+ u32 outputs; /* Number of output ports */
-+ u32 clocks; /* Number of clock ports */
-+ struct vchiq_mmal_port control; /* control port */
-+ struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */
-+ struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */
-+ struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */
-+};
-+
-+int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance);
-+int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance);
-+
-+/* Initialise a mmal component and its ports
-+ *
-+ */
-+int vchiq_mmal_component_init(
-+ struct vchiq_mmal_instance *instance,
-+ const char *name,
-+ struct vchiq_mmal_component **component_out);
-+
-+int vchiq_mmal_component_finalise(
-+ struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component);
-+
-+int vchiq_mmal_component_enable(
-+ struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component);
-+
-+int vchiq_mmal_component_disable(
-+ struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_component *component);
-+
-+/* enable a mmal port
-+ *
-+ * enables a port and if a buffer callback provided enque buffer
-+ * headers as appropriate for the port.
-+ */
-+int vchiq_mmal_port_enable(
-+ struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ vchiq_mmal_buffer_cb buffer_cb);
-+
-+/* disable a port
-+ *
-+ * disable a port will dequeue any pending buffers
-+ */
-+int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port);
-+
-+int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ u32 parameter,
-+ void *value,
-+ u32 value_size);
-+
-+int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ u32 parameter,
-+ void *value,
-+ u32 *value_size);
-+
-+int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port);
-+
-+int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *src,
-+ struct vchiq_mmal_port *dst);
-+
-+int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
-+ u32 *major_out,
-+ u32 *minor_out);
-+
-+int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port,
-+ struct mmal_buffer *buf);
-+
-+int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance,
-+ struct mmal_buffer *buf);
-+int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf);
-+#endif /* MMAL_VCHIQ_H */
+++ /dev/null
-From f94642597f63c71b2ccffddd4f447190c131af56 Mon Sep 17 00:00:00 2001
-Date: Mon, 24 Sep 2018 16:51:13 +0100
-Subject: [PATCH] staging: mmal-vchiq: Allocate and free components as
- required
-
-The existing code assumed that there would only ever be 4 components,
-and never freed the entries once used.
-Allow arbitrary creation and destruction of components.
-
----
- .../vc04_services/vchiq-mmal/mmal-vchiq.c | 29 ++++++++++++-------
- .../vc04_services/vchiq-mmal/mmal-vchiq.h | 1 +
- 2 files changed, 20 insertions(+), 10 deletions(-)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -38,8 +38,11 @@ MODULE_AUTHOR("Dave Stevenson, <dave.ste
- MODULE_LICENSE("GPL");
- MODULE_VERSION("0.0.1");
-
--/* maximum number of components supported */
--#define VCHIQ_MMAL_MAX_COMPONENTS 4
-+/*
-+ * maximum number of components supported.
-+ * This matches the maximum permitted by default on the VPU
-+ */
-+#define VCHIQ_MMAL_MAX_COMPONENTS 64
-
- /*#define FULL_MSG_DUMP 1*/
-
-@@ -174,8 +177,6 @@ struct vchiq_mmal_instance {
- /* protect accesses to context_map */
- struct mutex context_map_lock;
-
-- /* component to use next */
-- int component_idx;
- struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
-
- /* ordered workqueue to process all bulk operations */
-@@ -1632,18 +1633,24 @@ int vchiq_mmal_component_init(struct vch
- {
- int ret;
- int idx; /* port index */
-- struct vchiq_mmal_component *component;
-+ struct vchiq_mmal_component *component = NULL;
-
- if (mutex_lock_interruptible(&instance->vchiq_mutex))
- return -EINTR;
-
-- if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) {
-+ for (idx = 0; idx < VCHIQ_MMAL_MAX_COMPONENTS; idx++) {
-+ if (!instance->component[idx].in_use) {
-+ component = &instance->component[idx];
-+ component->in_use = 1;
-+ break;
-+ }
-+ }
-+
-+ if (!component) {
- ret = -EINVAL; /* todo is this correct error? */
- goto unlock;
- }
-
-- component = &instance->component[instance->component_idx];
--
- ret = create_component(instance, component, name);
- if (ret < 0) {
- pr_err("%s: failed to create component %d (Not enough GPU mem?)\n",
-@@ -1694,8 +1701,6 @@ int vchiq_mmal_component_init(struct vch
- goto release_component;
- }
-
-- instance->component_idx++;
--
- *component_out = component;
-
- mutex_unlock(&instance->vchiq_mutex);
-@@ -1705,6 +1710,8 @@ int vchiq_mmal_component_init(struct vch
- release_component:
- destroy_component(instance, component);
- unlock:
-+ if (component)
-+ component->in_use = 0;
- mutex_unlock(&instance->vchiq_mutex);
-
- return ret;
-@@ -1727,6 +1734,8 @@ int vchiq_mmal_component_finalise(struct
-
- ret = destroy_component(instance, component);
-
-+ component->in_use = 0;
-+
- mutex_unlock(&instance->vchiq_mutex);
-
- return ret;
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-@@ -82,6 +82,7 @@ struct vchiq_mmal_port {
- };
-
- struct vchiq_mmal_component {
-+ u32 in_use:1;
- bool enabled;
- u32 handle; /* VideoCore handle for component */
- u32 inputs; /* Number of input ports */
--- /dev/null
+From 301a6a16ec8a8b1a7b89c0cc6df30e79a460214a Mon Sep 17 00:00:00 2001
+Date: Mon, 24 Sep 2018 16:57:09 +0100
+Subject: [PATCH] staging: mmal-vchiq: Make timeout a defined parameter
+
+The timeout period for VPU communications is a useful thing
+to extend when debugging.
+Set it via a define, rather than a magic number buried in the code.
+
+---
+ drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -44,6 +44,12 @@ MODULE_VERSION("0.0.1");
+ */
+ #define VCHIQ_MMAL_MAX_COMPONENTS 64
+
++/*
++ * Timeout for synchronous msg responses in seconds.
++ * Helpful to increase this if stopping in the VPU debugger.
++ */
++#define SYNC_MSG_TIMEOUT 3
++
+ /*#define FULL_MSG_DUMP 1*/
+
+ #ifdef DEBUG
+@@ -692,7 +698,7 @@ static int send_synchronous_mmal_msg(str
+ }
+
+ timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt,
+- 3 * HZ);
++ SYNC_MSG_TIMEOUT * HZ);
+ if (timeout == 0) {
+ pr_err("timed out waiting for sync completion\n");
+ ret = -ETIME;
+++ /dev/null
-From 3789c3b08b56f471878c493fd80a2eee776b527c Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Oct 2018 16:20:46 +0000
-Subject: [PATCH] staging: mmal-vchiq: Avoid use of bool in structures
-
-Fixes up a checkpatch error "Avoid using bool structure members
-because of possible alignment issues".
-
----
- .../staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 14 +++++++-------
- .../staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 4 ++--
- 2 files changed, 9 insertions(+), 9 deletions(-)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -861,9 +861,9 @@ static int port_info_get(struct vchiq_mm
- goto release_msg;
-
- if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
-- port->enabled = false;
-+ port->enabled = 0;
- else
-- port->enabled = true;
-+ port->enabled = 1;
-
- /* copy the values out of the message */
- port->handle = rmsg->u.port_info_get_reply.port_handle;
-@@ -1300,7 +1300,7 @@ static int port_disable(struct vchiq_mma
- if (!port->enabled)
- return 0;
-
-- port->enabled = false;
-+ port->enabled = 0;
-
- ret = port_action_port(instance, port,
- MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
-@@ -1352,7 +1352,7 @@ static int port_enable(struct vchiq_mmal
- if (ret)
- goto done;
-
-- port->enabled = true;
-+ port->enabled = 1;
-
- if (port->buffer_cb) {
- /* send buffer headers to videocore */
-@@ -1524,7 +1524,7 @@ int vchiq_mmal_port_connect_tunnel(struc
- pr_err("failed disconnecting src port\n");
- goto release_unlock;
- }
-- src->connected->enabled = false;
-+ src->connected->enabled = 0;
- src->connected = NULL;
- }
-
-@@ -1760,7 +1760,7 @@ int vchiq_mmal_component_enable(struct v
-
- ret = enable_component(instance, component);
- if (ret == 0)
-- component->enabled = true;
-+ component->enabled = 1;
-
- mutex_unlock(&instance->vchiq_mutex);
-
-@@ -1786,7 +1786,7 @@ int vchiq_mmal_component_disable(struct
-
- ret = disable_component(instance, component);
- if (ret == 0)
-- component->enabled = false;
-+ component->enabled = 0;
-
- mutex_unlock(&instance->vchiq_mutex);
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-@@ -48,7 +48,7 @@ typedef void (*vchiq_mmal_buffer_cb)(
- unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
-
- struct vchiq_mmal_port {
-- bool enabled;
-+ u32 enabled:1;
- u32 handle;
- u32 type; /* port type, cached to use on port info set */
- u32 index; /* port index, cached to use on port info set */
-@@ -83,7 +83,7 @@ struct vchiq_mmal_port {
-
- struct vchiq_mmal_component {
- u32 in_use:1;
-- bool enabled;
-+ u32 enabled:1;
- u32 handle; /* VideoCore handle for component */
- u32 inputs; /* Number of input ports */
- u32 outputs; /* Number of output ports */
--- /dev/null
+From 862ee4fbd8c6b984f920b88908e33951e51134ca Mon Sep 17 00:00:00 2001
+Date: Mon, 24 Sep 2018 17:33:37 +0100
+Subject: [PATCH] staging: mmal-vchiq: Make a mmal_buf struct for
+ passing parameters
+
+The callback from vchi_mmal to the client was growing lots of extra
+parameters. Consolidate them into a single struct instead of
+growing the list further.
+The struct is associated with the client buffer, therefore there
+are various changes to setup various containers for the struct,
+and pass the appropriate members.
+
+---
+ .../bcm2835-camera/bcm2835-camera.c | 62 ++++++++++++-------
+ .../vc04_services/vchiq-mmal/mmal-common.h | 5 ++
+ .../vc04_services/vchiq-mmal/mmal-vchiq.c | 29 ++++++---
+ .../vc04_services/vchiq-mmal/mmal-vchiq.h | 3 +-
+ 4 files changed, 64 insertions(+), 35 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -72,6 +72,12 @@ static const struct v4l2_fract
+ tpf_max = {.numerator = 1, .denominator = FPS_MIN},
+ tpf_default = {.numerator = 1000, .denominator = 30000};
+
++/* Container for MMAL and VB2 buffers*/
++struct vb2_mmal_buffer {
++ struct vb2_v4l2_buffer vb;
++ struct mmal_buffer mmal;
++};
++
+ /* video formats */
+ static struct mmal_fmt formats[] = {
+ {
+@@ -267,14 +273,15 @@ static int buffer_init(struct vb2_buffer
+ {
+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
+- struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb);
++ struct vb2_mmal_buffer *buf =
++ container_of(vb2, struct vb2_mmal_buffer, vb);
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n",
+ __func__, dev, vb);
+- buf->buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
+- buf->buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0);
++ buf->mmal.buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
++ buf->mmal.buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0);
+
+- return mmal_vchi_buffer_init(dev->instance, buf);
++ return mmal_vchi_buffer_init(dev->instance, &buf->mmal);
+ }
+
+ static int buffer_prepare(struct vb2_buffer *vb)
+@@ -303,11 +310,13 @@ static void buffer_cleanup(struct vb2_bu
+ {
+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
+- struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb);
++ struct vb2_mmal_buffer *buf =
++ container_of(vb2, struct vb2_mmal_buffer, vb);
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n",
+ __func__, dev, vb);
+- mmal_vchi_buffer_cleanup(buf);
++
++ mmal_vchi_buffer_cleanup(&buf->mmal);
+ }
+
+ static inline bool is_capturing(struct bm2835_mmal_dev *dev)
+@@ -319,14 +328,16 @@ static inline bool is_capturing(struct b
+ static void buffer_cb(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ int status,
+- struct mmal_buffer *buf,
+- unsigned long length, u32 mmal_flags, s64 dts, s64 pts)
++ struct mmal_buffer *mmal_buf)
+ {
+ struct bm2835_mmal_dev *dev = port->cb_ctx;
++ struct vb2_mmal_buffer *buf =
++ container_of(mmal_buf, struct vb2_mmal_buffer, mmal);
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
+- __func__, status, buf, length, mmal_flags, pts);
++ __func__, status, buf, mmal_buf->length, mmal_buf->mmal_flags,
++ mmal_buf->pts);
+
+ if (status != 0) {
+ /* error in transfer */
+@@ -337,7 +348,7 @@ static void buffer_cb(struct vchiq_mmal_
+ return;
+ }
+
+- if (length == 0) {
++ if (mmal_buf->length == 0) {
+ /* stream ended */
+ if (dev->capture.frame_count) {
+ /* empty buffer whilst capturing - expected to be an
+@@ -353,7 +364,8 @@ static void buffer_cb(struct vchiq_mmal_
+ &dev->capture.frame_count,
+ sizeof(dev->capture.frame_count));
+ }
+- if (vchiq_mmal_submit_buffer(instance, port, buf))
++ if (vchiq_mmal_submit_buffer(instance, port,
++ &buf->mmal))
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Failed to return EOS buffer");
+ } else {
+@@ -382,16 +394,16 @@ static void buffer_cb(struct vchiq_mmal_
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Buffer time set as current time - %lld",
+ buf->vb.vb2_buf.timestamp);
+- } else if (pts != 0) {
++ } else if (mmal_buf->pts != 0) {
+ ktime_t timestamp;
+- s64 runtime_us = pts -
++ s64 runtime_us = mmal_buf->pts -
+ dev->capture.vc_start_timestamp;
+ timestamp = ktime_add_us(dev->capture.kernel_start_ts,
+ runtime_us);
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Convert start time %llu and %llu with offset %llu to %llu\n",
+ ktime_to_ns(dev->capture.kernel_start_ts),
+- dev->capture.vc_start_timestamp, pts,
++ dev->capture.vc_start_timestamp, mmal_buf->pts,
+ ktime_to_ns(timestamp));
+ if (timestamp < dev->capture.last_timestamp) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+@@ -416,15 +428,15 @@ static void buffer_cb(struct vchiq_mmal_
+ dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
+ buf->vb.sequence = dev->capture.sequence++;
+
+- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
+- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
++ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, mmal_buf->length);
++ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+ buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Buffer has ts %llu", dev->capture.last_timestamp);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
++ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
+ is_capturing(dev)) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Grab another frame as buffer has EOS");
+@@ -507,14 +519,16 @@ static void buffer_queue(struct vb2_buff
+ {
+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
+- struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb);
++ struct vb2_mmal_buffer *buf =
++ container_of(vb2, struct vb2_mmal_buffer, vb);
+ int ret;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s: dev:%p buf:%p, idx %u\n",
+ __func__, dev, buf, vb2->vb2_buf.index);
+
+- ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port, buf);
++ ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port,
++ &buf->mmal);
+ if (ret < 0)
+ v4l2_err(&dev->v4l2_dev, "%s: error submitting buffer\n",
+ __func__);
+@@ -628,7 +642,7 @@ static void stop_streaming(struct vb2_qu
+ dev->capture.frame_count = 0;
+
+ /* ensure a format has actually been set */
+- if (!dev->capture.port) {
++ if (!port) {
+ v4l2_err(&dev->v4l2_dev,
+ "no capture port - stream not started?\n");
+ return;
+@@ -648,11 +662,11 @@ static void stop_streaming(struct vb2_qu
+
+ /* disable the connection from camera to encoder */
+ ret = vchiq_mmal_port_disable(dev->instance, dev->capture.camera_port);
+- if (!ret && dev->capture.camera_port != dev->capture.port) {
++ if (!ret && dev->capture.camera_port != port) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "disabling port\n");
+- ret = vchiq_mmal_port_disable(dev->instance, dev->capture.port);
+- } else if (dev->capture.camera_port != dev->capture.port) {
++ ret = vchiq_mmal_port_disable(dev->instance, port);
++ } else if (dev->capture.camera_port != port) {
+ v4l2_err(&dev->v4l2_dev, "port_disable failed, error %d\n",
+ ret);
+ }
+@@ -1954,7 +1968,7 @@ static int bcm2835_mmal_probe(struct pla
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ q->drv_priv = dev;
+- q->buf_struct_size = sizeof(struct mmal_buffer);
++ q->buf_struct_size = sizeof(struct vb2_mmal_buffer);
+ q->ops = &bm2835_mmal_video_qops;
+ q->mem_ops = &vb2_vmalloc_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
+@@ -50,6 +50,11 @@ struct mmal_buffer {
+ unsigned long buffer_size; /* size of allocated buffer */
+
+ struct mmal_msg_context *msg_context;
++
++ unsigned long length;
++ u32 mmal_flags;
++ s64 dts;
++ s64 pts;
+ };
+
+ /* */
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -259,17 +259,25 @@ static void buffer_work_cb(struct work_s
+ {
+ struct mmal_msg_context *msg_context =
+ container_of(work, struct mmal_msg_context, u.bulk.work);
++ struct mmal_buffer *buffer = msg_context->u.bulk.buffer;
++
++ if (!buffer) {
++ pr_err("%s: ctx: %p, No mmal buffer to pass details\n",
++ __func__, msg_context);
++ return;
++ }
++
++ buffer->length = msg_context->u.bulk.buffer_used;
++ buffer->mmal_flags = msg_context->u.bulk.mmal_flags;
++ buffer->dts = msg_context->u.bulk.dts;
++ buffer->pts = msg_context->u.bulk.pts;
+
+ atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
+
+ msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
+ msg_context->u.bulk.port,
+ msg_context->u.bulk.status,
+- msg_context->u.bulk.buffer,
+- msg_context->u.bulk.buffer_used,
+- msg_context->u.bulk.mmal_flags,
+- msg_context->u.bulk.dts,
+- msg_context->u.bulk.pts);
++ msg_context->u.bulk.buffer);
+ }
+
+ /* workqueue scheduled callback to handle receiving buffers
+@@ -1327,11 +1335,14 @@ static int port_disable(struct vchiq_mma
+ mmalbuf = list_entry(buf_head, struct mmal_buffer,
+ list);
+ list_del(buf_head);
+- if (port->buffer_cb)
++ if (port->buffer_cb) {
++ mmalbuf->length = 0;
++ mmalbuf->mmal_flags = 0;
++ mmalbuf->dts = MMAL_TIME_UNKNOWN;
++ mmalbuf->pts = MMAL_TIME_UNKNOWN;
+ port->buffer_cb(instance,
+- port, 0, mmalbuf, 0, 0,
+- MMAL_TIME_UNKNOWN,
+- MMAL_TIME_UNKNOWN);
++ port, 0, mmalbuf);
++ }
+ }
+
+ spin_unlock_irqrestore(&port->slock, flags);
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
+@@ -44,8 +44,7 @@ struct vchiq_mmal_port;
+ typedef void (*vchiq_mmal_buffer_cb)(
+ struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+- int status, struct mmal_buffer *buffer,
+- unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
++ int status, struct mmal_buffer *buffer);
+
+ struct vchiq_mmal_port {
+ u32 enabled:1;
--- /dev/null
+From adab474d1f91594d6d96d44054586ba36d7f26d4 Mon Sep 17 00:00:00 2001
+Date: Mon, 24 Sep 2018 18:15:38 +0100
+Subject: [PATCH] staging: mmal-vchiq: Add support for event callbacks.
+
+(Preparation for the codec driver).
+The codec uses the event mechanism to report things such as
+resolution changes. It is signalled by the cmd field of the buffer
+being non-zero.
+
+Add support for passing this information out to the client.
+
+---
+ .../vc04_services/vchiq-mmal/mmal-common.h | 1 +
+ .../vc04_services/vchiq-mmal/mmal-msg.h | 35 ++++
+ .../vc04_services/vchiq-mmal/mmal-vchiq.c | 170 ++++++++++++++++--
+ .../vc04_services/vchiq-mmal/mmal-vchiq.h | 4 +
+ 4 files changed, 196 insertions(+), 14 deletions(-)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
+@@ -51,6 +51,7 @@ struct mmal_buffer {
+
+ struct mmal_msg_context *msg_context;
+
++ u32 cmd; /* MMAL command. 0=data. */
+ unsigned long length;
+ u32 mmal_flags;
+ s64 dts;
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h
+@@ -346,6 +346,41 @@ struct mmal_msg_port_parameter_get_reply
+ /* event messages */
+ #define MMAL_WORKER_EVENT_SPACE 256
+
++/* Four CC's for events */
++#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
++
++#define MMAL_EVENT_ERROR MMAL_FOURCC('E', 'R', 'R', 'O')
++#define MMAL_EVENT_EOS MMAL_FOURCC('E', 'E', 'O', 'S')
++#define MMAL_EVENT_FORMAT_CHANGED MMAL_FOURCC('E', 'F', 'C', 'H')
++#define MMAL_EVENT_PARAMETER_CHANGED MMAL_FOURCC('E', 'P', 'C', 'H')
++
++/* Structs for each of the event message payloads */
++struct mmal_msg_event_eos {
++ u32 port_type; /**< Type of port that received the end of stream */
++ u32 port_index; /**< Index of port that received the end of stream */
++};
++
++/** Format changed event data. */
++struct mmal_msg_event_format_changed {
++ /* Minimum size of buffers the port requires */
++ u32 buffer_size_min;
++ /* Minimum number of buffers the port requires */
++ u32 buffer_num_min;
++ /* Size of buffers the port recommends for optimal performance.
++ * A value of zero means no special recommendation.
++ */
++ u32 buffer_size_recommended;
++ /* Number of buffers the port recommends for optimal
++ * performance. A value of zero means no special recommendation.
++ */
++ u32 buffer_num_recommended;
++
++ u32 es_ptr;
++ struct mmal_es_format format;
++ union mmal_es_specific_format es;
++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
++};
++
+ struct mmal_msg_event_to_host {
+ u32 client_component; /* component context */
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -151,6 +151,8 @@ struct mmal_msg_context {
+ /* Presentation and Decode timestamps */
+ s64 pts;
+ s64 dts;
++ /* MMAL buffer command flag */
++ u32 cmd;
+
+ int status; /* context status */
+
+@@ -238,18 +240,6 @@ release_msg_context(struct mmal_msg_cont
+ kfree(msg_context);
+ }
+
+-/* deals with receipt of event to host message */
+-static void event_to_host_cb(struct vchiq_mmal_instance *instance,
+- struct mmal_msg *msg, u32 msg_len)
+-{
+- pr_debug("unhandled event\n");
+- pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n",
+- msg->u.event_to_host.client_component,
+- msg->u.event_to_host.port_type,
+- msg->u.event_to_host.port_num,
+- msg->u.event_to_host.cmd, msg->u.event_to_host.length);
+-}
+-
+ /* workqueue scheduled callback
+ *
+ * we do this because it is important we do not call any other vchiq
+@@ -271,13 +261,18 @@ static void buffer_work_cb(struct work_s
+ buffer->mmal_flags = msg_context->u.bulk.mmal_flags;
+ buffer->dts = msg_context->u.bulk.dts;
+ buffer->pts = msg_context->u.bulk.pts;
++ buffer->cmd = msg_context->u.bulk.cmd;
+
+- atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
++ if (!buffer->cmd)
++ atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
+
+ msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
+ msg_context->u.bulk.port,
+ msg_context->u.bulk.status,
+ msg_context->u.bulk.buffer);
++
++ if (buffer->cmd)
++ mutex_unlock(&msg_context->u.bulk.port->event_context_mutex);
+ }
+
+ /* workqueue scheduled callback to handle receiving buffers
+@@ -356,6 +351,7 @@ static int bulk_receive(struct vchiq_mma
+ msg_context->u.bulk.buffer_used = rd_len;
+ msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
+ msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
++ msg_context->u.bulk.cmd = msg->u.buffer_from_host.buffer_header.cmd;
+
+ queue_work(msg_context->instance->bulk_wq,
+ &msg_context->u.bulk.buffer_to_host_work);
+@@ -457,6 +453,103 @@ buffer_from_host(struct vchiq_mmal_insta
+ return ret;
+ }
+
++/* deals with receipt of event to host message */
++static void event_to_host_cb(struct vchiq_mmal_instance *instance,
++ struct mmal_msg *msg, u32 msg_len)
++{
++ /* FIXME: Not going to work on 64 bit */
++ struct vchiq_mmal_component *component =
++ (struct vchiq_mmal_component *)msg->u.event_to_host.client_component;
++ struct vchiq_mmal_port *port = NULL;
++ struct mmal_msg_context *msg_context;
++ u32 port_num = msg->u.event_to_host.port_num;
++
++ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
++ pr_err("%s: MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n",
++ __func__);
++ return;
++ }
++
++ switch (msg->u.event_to_host.port_type) {
++ case MMAL_PORT_TYPE_CONTROL:
++ if (port_num) {
++ pr_err("%s: port_num of %u >= number of ports 1",
++ __func__, port_num);
++ return;
++ }
++ port = &component->control;
++ break;
++ case MMAL_PORT_TYPE_INPUT:
++ if (port_num >= component->inputs) {
++ pr_err("%s: port_num of %u >= number of ports %u",
++ __func__, port_num,
++ port_num >= component->inputs);
++ return;
++ }
++ port = &component->input[port_num];
++ break;
++ case MMAL_PORT_TYPE_OUTPUT:
++ if (port_num >= component->outputs) {
++ pr_err("%s: port_num of %u >= number of ports %u",
++ __func__, port_num,
++ port_num >= component->outputs);
++ return;
++ }
++ port = &component->output[port_num];
++ break;
++ case MMAL_PORT_TYPE_CLOCK:
++ if (port_num >= component->clocks) {
++ pr_err("%s: port_num of %u >= number of ports %u",
++ __func__, port_num,
++ port_num >= component->clocks);
++ return;
++ }
++ port = &component->clock[port_num];
++ break;
++ default:
++ break;
++ }
++
++ if (!mutex_trylock(&port->event_context_mutex)) {
++ pr_err("dropping event 0x%x\n", msg->u.event_to_host.cmd);
++ return;
++ }
++ msg_context = port->event_context;
++
++ if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
++ /* message reception had an error */
++ //pr_warn
++ pr_err("%s: error %d in reply\n", __func__, msg->h.status);
++
++ msg_context->u.bulk.status = msg->h.status;
++ } else if (msg->u.event_to_host.length > MMAL_WORKER_EVENT_SPACE) {
++ /* data is not in message, queue a bulk receive */
++ pr_err("%s: payload not in message - bulk receive??! NOT SUPPORTED\n",
++ __func__);
++ msg_context->u.bulk.status = -1;
++ } else {
++ memcpy(msg_context->u.bulk.buffer->buffer,
++ msg->u.event_to_host.data,
++ msg->u.event_to_host.length);
++
++ msg_context->u.bulk.buffer_used =
++ msg->u.event_to_host.length;
++
++ msg_context->u.bulk.mmal_flags = 0;
++ msg_context->u.bulk.dts = MMAL_TIME_UNKNOWN;
++ msg_context->u.bulk.pts = MMAL_TIME_UNKNOWN;
++ msg_context->u.bulk.cmd = msg->u.event_to_host.cmd;
++
++ pr_debug("event component:%u port type:%d num:%d cmd:0x%x length:%d\n",
++ msg->u.event_to_host.client_component,
++ msg->u.event_to_host.port_type,
++ msg->u.event_to_host.port_num,
++ msg->u.event_to_host.cmd, msg->u.event_to_host.length);
++ }
++
++ schedule_work(&msg_context->u.bulk.work);
++}
++
+ /* deals with receipt of buffer to host message */
+ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
+ struct mmal_msg *msg, u32 msg_len)
+@@ -1340,6 +1433,7 @@ static int port_disable(struct vchiq_mma
+ mmalbuf->mmal_flags = 0;
+ mmalbuf->dts = MMAL_TIME_UNKNOWN;
+ mmalbuf->pts = MMAL_TIME_UNKNOWN;
++ mmalbuf->cmd = 0;
+ port->buffer_cb(instance,
+ port, 0, mmalbuf);
+ }
+@@ -1641,6 +1735,43 @@ int mmal_vchi_buffer_cleanup(struct mmal
+ }
+ EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup);
+
++static void init_event_context(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port)
++{
++ struct mmal_msg_context *ctx = get_msg_context(instance);
++
++ mutex_init(&port->event_context_mutex);
++
++ port->event_context = ctx;
++ ctx->u.bulk.instance = instance;
++ ctx->u.bulk.port = port;
++ ctx->u.bulk.buffer =
++ kzalloc(sizeof(*ctx->u.bulk.buffer), GFP_KERNEL);
++ if (!ctx->u.bulk.buffer)
++ goto release_msg_context;
++ ctx->u.bulk.buffer->buffer = kzalloc(MMAL_WORKER_EVENT_SPACE,
++ GFP_KERNEL);
++ if (!ctx->u.bulk.buffer->buffer)
++ goto release_buffer;
++
++ INIT_WORK(&ctx->u.bulk.work, buffer_work_cb);
++ return;
++
++release_buffer:
++ kfree(ctx->u.bulk.buffer);
++release_msg_context:
++ release_msg_context(ctx);
++}
++
++static void free_event_context(struct vchiq_mmal_port *port)
++{
++ struct mmal_msg_context *ctx = port->event_context;
++
++ kfree(ctx->u.bulk.buffer->buffer);
++ kfree(ctx->u.bulk.buffer);
++ release_msg_context(ctx);
++}
++
+ /* Initialise a mmal component and its ports
+ *
+ */
+@@ -1684,6 +1815,7 @@ int vchiq_mmal_component_init(struct vch
+ ret = port_info_get(instance, &component->control);
+ if (ret < 0)
+ goto release_component;
++ init_event_context(instance, &component->control);
+
+ for (idx = 0; idx < component->inputs; idx++) {
+ component->input[idx].type = MMAL_PORT_TYPE_INPUT;
+@@ -1694,6 +1826,7 @@ int vchiq_mmal_component_init(struct vch
+ ret = port_info_get(instance, &component->input[idx]);
+ if (ret < 0)
+ goto release_component;
++ init_event_context(instance, &component->input[idx]);
+ }
+
+ for (idx = 0; idx < component->outputs; idx++) {
+@@ -1705,6 +1838,7 @@ int vchiq_mmal_component_init(struct vch
+ ret = port_info_get(instance, &component->output[idx]);
+ if (ret < 0)
+ goto release_component;
++ init_event_context(instance, &component->output[idx]);
+ }
+
+ for (idx = 0; idx < component->clocks; idx++) {
+@@ -1716,6 +1850,7 @@ int vchiq_mmal_component_init(struct vch
+ ret = port_info_get(instance, &component->clock[idx]);
+ if (ret < 0)
+ goto release_component;
++ init_event_context(instance, &component->clock[idx]);
+ }
+
+ *component_out = component;
+@@ -1741,7 +1876,7 @@ EXPORT_SYMBOL_GPL(vchiq_mmal_component_i
+ int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component)
+ {
+- int ret;
++ int ret, idx;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+@@ -1753,6 +1888,13 @@ int vchiq_mmal_component_finalise(struct
+
+ component->in_use = 0;
+
++ for (idx = 0; idx < component->inputs; idx++)
++ free_event_context(&component->input[idx]);
++ for (idx = 0; idx < component->outputs; idx++)
++ free_event_context(&component->output[idx]);
++ for (idx = 0; idx < component->clocks; idx++)
++ free_event_context(&component->clock[idx]);
++
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
+@@ -78,6 +78,10 @@ struct vchiq_mmal_port {
+ vchiq_mmal_buffer_cb buffer_cb;
+ /* callback context */
+ void *cb_ctx;
++
++ /* ensure serialised use of the one event context structure */
++ struct mutex event_context_mutex;
++ struct mmal_msg_context *event_context;
+ };
+
+ struct vchiq_mmal_component {
+++ /dev/null
-From 301a6a16ec8a8b1a7b89c0cc6df30e79a460214a Mon Sep 17 00:00:00 2001
-Date: Mon, 24 Sep 2018 16:57:09 +0100
-Subject: [PATCH] staging: mmal-vchiq: Make timeout a defined parameter
-
-The timeout period for VPU communications is a useful thing
-to extend when debugging.
-Set it via a define, rather than a magic number buried in the code.
-
----
- drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -44,6 +44,12 @@ MODULE_VERSION("0.0.1");
- */
- #define VCHIQ_MMAL_MAX_COMPONENTS 64
-
-+/*
-+ * Timeout for synchronous msg responses in seconds.
-+ * Helpful to increase this if stopping in the VPU debugger.
-+ */
-+#define SYNC_MSG_TIMEOUT 3
-+
- /*#define FULL_MSG_DUMP 1*/
-
- #ifdef DEBUG
-@@ -692,7 +698,7 @@ static int send_synchronous_mmal_msg(str
- }
-
- timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt,
-- 3 * HZ);
-+ SYNC_MSG_TIMEOUT * HZ);
- if (timeout == 0) {
- pr_err("timed out waiting for sync completion\n");
- ret = -ETIME;
+++ /dev/null
-From 862ee4fbd8c6b984f920b88908e33951e51134ca Mon Sep 17 00:00:00 2001
-Date: Mon, 24 Sep 2018 17:33:37 +0100
-Subject: [PATCH] staging: mmal-vchiq: Make a mmal_buf struct for
- passing parameters
-
-The callback from vchi_mmal to the client was growing lots of extra
-parameters. Consolidate them into a single struct instead of
-growing the list further.
-The struct is associated with the client buffer, therefore there
-are various changes to setup various containers for the struct,
-and pass the appropriate members.
-
----
- .../bcm2835-camera/bcm2835-camera.c | 62 ++++++++++++-------
- .../vc04_services/vchiq-mmal/mmal-common.h | 5 ++
- .../vc04_services/vchiq-mmal/mmal-vchiq.c | 29 ++++++---
- .../vc04_services/vchiq-mmal/mmal-vchiq.h | 3 +-
- 4 files changed, 64 insertions(+), 35 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -72,6 +72,12 @@ static const struct v4l2_fract
- tpf_max = {.numerator = 1, .denominator = FPS_MIN},
- tpf_default = {.numerator = 1000, .denominator = 30000};
-
-+/* Container for MMAL and VB2 buffers*/
-+struct vb2_mmal_buffer {
-+ struct vb2_v4l2_buffer vb;
-+ struct mmal_buffer mmal;
-+};
-+
- /* video formats */
- static struct mmal_fmt formats[] = {
- {
-@@ -267,14 +273,15 @@ static int buffer_init(struct vb2_buffer
- {
- struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
- struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
-- struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb);
-+ struct vb2_mmal_buffer *buf =
-+ container_of(vb2, struct vb2_mmal_buffer, vb);
-
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n",
- __func__, dev, vb);
-- buf->buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
-- buf->buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0);
-+ buf->mmal.buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
-+ buf->mmal.buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0);
-
-- return mmal_vchi_buffer_init(dev->instance, buf);
-+ return mmal_vchi_buffer_init(dev->instance, &buf->mmal);
- }
-
- static int buffer_prepare(struct vb2_buffer *vb)
-@@ -303,11 +310,13 @@ static void buffer_cleanup(struct vb2_bu
- {
- struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
- struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
-- struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb);
-+ struct vb2_mmal_buffer *buf =
-+ container_of(vb2, struct vb2_mmal_buffer, vb);
-
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n",
- __func__, dev, vb);
-- mmal_vchi_buffer_cleanup(buf);
-+
-+ mmal_vchi_buffer_cleanup(&buf->mmal);
- }
-
- static inline bool is_capturing(struct bm2835_mmal_dev *dev)
-@@ -319,14 +328,16 @@ static inline bool is_capturing(struct b
- static void buffer_cb(struct vchiq_mmal_instance *instance,
- struct vchiq_mmal_port *port,
- int status,
-- struct mmal_buffer *buf,
-- unsigned long length, u32 mmal_flags, s64 dts, s64 pts)
-+ struct mmal_buffer *mmal_buf)
- {
- struct bm2835_mmal_dev *dev = port->cb_ctx;
-+ struct vb2_mmal_buffer *buf =
-+ container_of(mmal_buf, struct vb2_mmal_buffer, mmal);
-
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
-- __func__, status, buf, length, mmal_flags, pts);
-+ __func__, status, buf, mmal_buf->length, mmal_buf->mmal_flags,
-+ mmal_buf->pts);
-
- if (status != 0) {
- /* error in transfer */
-@@ -337,7 +348,7 @@ static void buffer_cb(struct vchiq_mmal_
- return;
- }
-
-- if (length == 0) {
-+ if (mmal_buf->length == 0) {
- /* stream ended */
- if (dev->capture.frame_count) {
- /* empty buffer whilst capturing - expected to be an
-@@ -353,7 +364,8 @@ static void buffer_cb(struct vchiq_mmal_
- &dev->capture.frame_count,
- sizeof(dev->capture.frame_count));
- }
-- if (vchiq_mmal_submit_buffer(instance, port, buf))
-+ if (vchiq_mmal_submit_buffer(instance, port,
-+ &buf->mmal))
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Failed to return EOS buffer");
- } else {
-@@ -382,16 +394,16 @@ static void buffer_cb(struct vchiq_mmal_
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Buffer time set as current time - %lld",
- buf->vb.vb2_buf.timestamp);
-- } else if (pts != 0) {
-+ } else if (mmal_buf->pts != 0) {
- ktime_t timestamp;
-- s64 runtime_us = pts -
-+ s64 runtime_us = mmal_buf->pts -
- dev->capture.vc_start_timestamp;
- timestamp = ktime_add_us(dev->capture.kernel_start_ts,
- runtime_us);
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Convert start time %llu and %llu with offset %llu to %llu\n",
- ktime_to_ns(dev->capture.kernel_start_ts),
-- dev->capture.vc_start_timestamp, pts,
-+ dev->capture.vc_start_timestamp, mmal_buf->pts,
- ktime_to_ns(timestamp));
- if (timestamp < dev->capture.last_timestamp) {
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-@@ -416,15 +428,15 @@ static void buffer_cb(struct vchiq_mmal_
- dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
- buf->vb.sequence = dev->capture.sequence++;
-
-- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
-- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
-+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, mmal_buf->length);
-+ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
- buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
-
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Buffer has ts %llu", dev->capture.last_timestamp);
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
-
-- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
-+ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
- is_capturing(dev)) {
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Grab another frame as buffer has EOS");
-@@ -507,14 +519,16 @@ static void buffer_queue(struct vb2_buff
- {
- struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
- struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
-- struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb);
-+ struct vb2_mmal_buffer *buf =
-+ container_of(vb2, struct vb2_mmal_buffer, vb);
- int ret;
-
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "%s: dev:%p buf:%p, idx %u\n",
- __func__, dev, buf, vb2->vb2_buf.index);
-
-- ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port, buf);
-+ ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port,
-+ &buf->mmal);
- if (ret < 0)
- v4l2_err(&dev->v4l2_dev, "%s: error submitting buffer\n",
- __func__);
-@@ -628,7 +642,7 @@ static void stop_streaming(struct vb2_qu
- dev->capture.frame_count = 0;
-
- /* ensure a format has actually been set */
-- if (!dev->capture.port) {
-+ if (!port) {
- v4l2_err(&dev->v4l2_dev,
- "no capture port - stream not started?\n");
- return;
-@@ -648,11 +662,11 @@ static void stop_streaming(struct vb2_qu
-
- /* disable the connection from camera to encoder */
- ret = vchiq_mmal_port_disable(dev->instance, dev->capture.camera_port);
-- if (!ret && dev->capture.camera_port != dev->capture.port) {
-+ if (!ret && dev->capture.camera_port != port) {
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "disabling port\n");
-- ret = vchiq_mmal_port_disable(dev->instance, dev->capture.port);
-- } else if (dev->capture.camera_port != dev->capture.port) {
-+ ret = vchiq_mmal_port_disable(dev->instance, port);
-+ } else if (dev->capture.camera_port != port) {
- v4l2_err(&dev->v4l2_dev, "port_disable failed, error %d\n",
- ret);
- }
-@@ -1954,7 +1968,7 @@ static int bcm2835_mmal_probe(struct pla
- q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
- q->drv_priv = dev;
-- q->buf_struct_size = sizeof(struct mmal_buffer);
-+ q->buf_struct_size = sizeof(struct vb2_mmal_buffer);
- q->ops = &bm2835_mmal_video_qops;
- q->mem_ops = &vb2_vmalloc_memops;
- q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
-@@ -50,6 +50,11 @@ struct mmal_buffer {
- unsigned long buffer_size; /* size of allocated buffer */
-
- struct mmal_msg_context *msg_context;
-+
-+ unsigned long length;
-+ u32 mmal_flags;
-+ s64 dts;
-+ s64 pts;
- };
-
- /* */
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -259,17 +259,25 @@ static void buffer_work_cb(struct work_s
- {
- struct mmal_msg_context *msg_context =
- container_of(work, struct mmal_msg_context, u.bulk.work);
-+ struct mmal_buffer *buffer = msg_context->u.bulk.buffer;
-+
-+ if (!buffer) {
-+ pr_err("%s: ctx: %p, No mmal buffer to pass details\n",
-+ __func__, msg_context);
-+ return;
-+ }
-+
-+ buffer->length = msg_context->u.bulk.buffer_used;
-+ buffer->mmal_flags = msg_context->u.bulk.mmal_flags;
-+ buffer->dts = msg_context->u.bulk.dts;
-+ buffer->pts = msg_context->u.bulk.pts;
-
- atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
-
- msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
- msg_context->u.bulk.port,
- msg_context->u.bulk.status,
-- msg_context->u.bulk.buffer,
-- msg_context->u.bulk.buffer_used,
-- msg_context->u.bulk.mmal_flags,
-- msg_context->u.bulk.dts,
-- msg_context->u.bulk.pts);
-+ msg_context->u.bulk.buffer);
- }
-
- /* workqueue scheduled callback to handle receiving buffers
-@@ -1327,11 +1335,14 @@ static int port_disable(struct vchiq_mma
- mmalbuf = list_entry(buf_head, struct mmal_buffer,
- list);
- list_del(buf_head);
-- if (port->buffer_cb)
-+ if (port->buffer_cb) {
-+ mmalbuf->length = 0;
-+ mmalbuf->mmal_flags = 0;
-+ mmalbuf->dts = MMAL_TIME_UNKNOWN;
-+ mmalbuf->pts = MMAL_TIME_UNKNOWN;
- port->buffer_cb(instance,
-- port, 0, mmalbuf, 0, 0,
-- MMAL_TIME_UNKNOWN,
-- MMAL_TIME_UNKNOWN);
-+ port, 0, mmalbuf);
-+ }
- }
-
- spin_unlock_irqrestore(&port->slock, flags);
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-@@ -44,8 +44,7 @@ struct vchiq_mmal_port;
- typedef void (*vchiq_mmal_buffer_cb)(
- struct vchiq_mmal_instance *instance,
- struct vchiq_mmal_port *port,
-- int status, struct mmal_buffer *buffer,
-- unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
-+ int status, struct mmal_buffer *buffer);
-
- struct vchiq_mmal_port {
- u32 enabled:1;
--- /dev/null
+From 483bef9dcddc4bcb9f4e250d91b31361a919b7ed Mon Sep 17 00:00:00 2001
+Date: Mon, 24 Sep 2018 18:26:02 +0100
+Subject: [PATCH] staging: vc04_services: Support sending data to MMAL
+ ports
+
+Add the ability to send data to ports. This only supports
+zero copy mode as the required bulk transfer setup calls
+are not done.
+
+---
+ .../vc04_services/vchiq-mmal/mmal-vchiq.c | 18 +++++++++++++-----
+ 1 file changed, 13 insertions(+), 5 deletions(-)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -428,11 +428,19 @@ buffer_from_host(struct vchiq_mmal_insta
+ m.u.buffer_from_host.buffer_header.data =
+ (u32)(unsigned long)buf->buffer;
+ m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
+- m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */
+- m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */
+- m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */
+- m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
+- m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
++ if (port->type == MMAL_PORT_TYPE_OUTPUT) {
++ m.u.buffer_from_host.buffer_header.length = 0;
++ m.u.buffer_from_host.buffer_header.offset = 0;
++ m.u.buffer_from_host.buffer_header.flags = 0;
++ m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
++ m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
++ } else {
++ m.u.buffer_from_host.buffer_header.length = buf->length;
++ m.u.buffer_from_host.buffer_header.offset = 0;
++ m.u.buffer_from_host.buffer_header.flags = buf->mmal_flags;
++ m.u.buffer_from_host.buffer_header.pts = buf->pts;
++ m.u.buffer_from_host.buffer_header.dts = buf->dts;
++ }
+
+ /* clear buffer type sepecific data */
+ memset(&m.u.buffer_from_host.buffer_header_type_specific, 0,
+++ /dev/null
-From adab474d1f91594d6d96d44054586ba36d7f26d4 Mon Sep 17 00:00:00 2001
-Date: Mon, 24 Sep 2018 18:15:38 +0100
-Subject: [PATCH] staging: mmal-vchiq: Add support for event callbacks.
-
-(Preparation for the codec driver).
-The codec uses the event mechanism to report things such as
-resolution changes. It is signalled by the cmd field of the buffer
-being non-zero.
-
-Add support for passing this information out to the client.
-
----
- .../vc04_services/vchiq-mmal/mmal-common.h | 1 +
- .../vc04_services/vchiq-mmal/mmal-msg.h | 35 ++++
- .../vc04_services/vchiq-mmal/mmal-vchiq.c | 170 ++++++++++++++++--
- .../vc04_services/vchiq-mmal/mmal-vchiq.h | 4 +
- 4 files changed, 196 insertions(+), 14 deletions(-)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
-@@ -51,6 +51,7 @@ struct mmal_buffer {
-
- struct mmal_msg_context *msg_context;
-
-+ u32 cmd; /* MMAL command. 0=data. */
- unsigned long length;
- u32 mmal_flags;
- s64 dts;
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h
-@@ -346,6 +346,41 @@ struct mmal_msg_port_parameter_get_reply
- /* event messages */
- #define MMAL_WORKER_EVENT_SPACE 256
-
-+/* Four CC's for events */
-+#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
-+
-+#define MMAL_EVENT_ERROR MMAL_FOURCC('E', 'R', 'R', 'O')
-+#define MMAL_EVENT_EOS MMAL_FOURCC('E', 'E', 'O', 'S')
-+#define MMAL_EVENT_FORMAT_CHANGED MMAL_FOURCC('E', 'F', 'C', 'H')
-+#define MMAL_EVENT_PARAMETER_CHANGED MMAL_FOURCC('E', 'P', 'C', 'H')
-+
-+/* Structs for each of the event message payloads */
-+struct mmal_msg_event_eos {
-+ u32 port_type; /**< Type of port that received the end of stream */
-+ u32 port_index; /**< Index of port that received the end of stream */
-+};
-+
-+/** Format changed event data. */
-+struct mmal_msg_event_format_changed {
-+ /* Minimum size of buffers the port requires */
-+ u32 buffer_size_min;
-+ /* Minimum number of buffers the port requires */
-+ u32 buffer_num_min;
-+ /* Size of buffers the port recommends for optimal performance.
-+ * A value of zero means no special recommendation.
-+ */
-+ u32 buffer_size_recommended;
-+ /* Number of buffers the port recommends for optimal
-+ * performance. A value of zero means no special recommendation.
-+ */
-+ u32 buffer_num_recommended;
-+
-+ u32 es_ptr;
-+ struct mmal_es_format format;
-+ union mmal_es_specific_format es;
-+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
-+};
-+
- struct mmal_msg_event_to_host {
- u32 client_component; /* component context */
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -151,6 +151,8 @@ struct mmal_msg_context {
- /* Presentation and Decode timestamps */
- s64 pts;
- s64 dts;
-+ /* MMAL buffer command flag */
-+ u32 cmd;
-
- int status; /* context status */
-
-@@ -238,18 +240,6 @@ release_msg_context(struct mmal_msg_cont
- kfree(msg_context);
- }
-
--/* deals with receipt of event to host message */
--static void event_to_host_cb(struct vchiq_mmal_instance *instance,
-- struct mmal_msg *msg, u32 msg_len)
--{
-- pr_debug("unhandled event\n");
-- pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n",
-- msg->u.event_to_host.client_component,
-- msg->u.event_to_host.port_type,
-- msg->u.event_to_host.port_num,
-- msg->u.event_to_host.cmd, msg->u.event_to_host.length);
--}
--
- /* workqueue scheduled callback
- *
- * we do this because it is important we do not call any other vchiq
-@@ -271,13 +261,18 @@ static void buffer_work_cb(struct work_s
- buffer->mmal_flags = msg_context->u.bulk.mmal_flags;
- buffer->dts = msg_context->u.bulk.dts;
- buffer->pts = msg_context->u.bulk.pts;
-+ buffer->cmd = msg_context->u.bulk.cmd;
-
-- atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
-+ if (!buffer->cmd)
-+ atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
-
- msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
- msg_context->u.bulk.port,
- msg_context->u.bulk.status,
- msg_context->u.bulk.buffer);
-+
-+ if (buffer->cmd)
-+ mutex_unlock(&msg_context->u.bulk.port->event_context_mutex);
- }
-
- /* workqueue scheduled callback to handle receiving buffers
-@@ -356,6 +351,7 @@ static int bulk_receive(struct vchiq_mma
- msg_context->u.bulk.buffer_used = rd_len;
- msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
- msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
-+ msg_context->u.bulk.cmd = msg->u.buffer_from_host.buffer_header.cmd;
-
- queue_work(msg_context->instance->bulk_wq,
- &msg_context->u.bulk.buffer_to_host_work);
-@@ -457,6 +453,103 @@ buffer_from_host(struct vchiq_mmal_insta
- return ret;
- }
-
-+/* deals with receipt of event to host message */
-+static void event_to_host_cb(struct vchiq_mmal_instance *instance,
-+ struct mmal_msg *msg, u32 msg_len)
-+{
-+ /* FIXME: Not going to work on 64 bit */
-+ struct vchiq_mmal_component *component =
-+ (struct vchiq_mmal_component *)msg->u.event_to_host.client_component;
-+ struct vchiq_mmal_port *port = NULL;
-+ struct mmal_msg_context *msg_context;
-+ u32 port_num = msg->u.event_to_host.port_num;
-+
-+ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
-+ pr_err("%s: MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n",
-+ __func__);
-+ return;
-+ }
-+
-+ switch (msg->u.event_to_host.port_type) {
-+ case MMAL_PORT_TYPE_CONTROL:
-+ if (port_num) {
-+ pr_err("%s: port_num of %u >= number of ports 1",
-+ __func__, port_num);
-+ return;
-+ }
-+ port = &component->control;
-+ break;
-+ case MMAL_PORT_TYPE_INPUT:
-+ if (port_num >= component->inputs) {
-+ pr_err("%s: port_num of %u >= number of ports %u",
-+ __func__, port_num,
-+ port_num >= component->inputs);
-+ return;
-+ }
-+ port = &component->input[port_num];
-+ break;
-+ case MMAL_PORT_TYPE_OUTPUT:
-+ if (port_num >= component->outputs) {
-+ pr_err("%s: port_num of %u >= number of ports %u",
-+ __func__, port_num,
-+ port_num >= component->outputs);
-+ return;
-+ }
-+ port = &component->output[port_num];
-+ break;
-+ case MMAL_PORT_TYPE_CLOCK:
-+ if (port_num >= component->clocks) {
-+ pr_err("%s: port_num of %u >= number of ports %u",
-+ __func__, port_num,
-+ port_num >= component->clocks);
-+ return;
-+ }
-+ port = &component->clock[port_num];
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ if (!mutex_trylock(&port->event_context_mutex)) {
-+ pr_err("dropping event 0x%x\n", msg->u.event_to_host.cmd);
-+ return;
-+ }
-+ msg_context = port->event_context;
-+
-+ if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
-+ /* message reception had an error */
-+ //pr_warn
-+ pr_err("%s: error %d in reply\n", __func__, msg->h.status);
-+
-+ msg_context->u.bulk.status = msg->h.status;
-+ } else if (msg->u.event_to_host.length > MMAL_WORKER_EVENT_SPACE) {
-+ /* data is not in message, queue a bulk receive */
-+ pr_err("%s: payload not in message - bulk receive??! NOT SUPPORTED\n",
-+ __func__);
-+ msg_context->u.bulk.status = -1;
-+ } else {
-+ memcpy(msg_context->u.bulk.buffer->buffer,
-+ msg->u.event_to_host.data,
-+ msg->u.event_to_host.length);
-+
-+ msg_context->u.bulk.buffer_used =
-+ msg->u.event_to_host.length;
-+
-+ msg_context->u.bulk.mmal_flags = 0;
-+ msg_context->u.bulk.dts = MMAL_TIME_UNKNOWN;
-+ msg_context->u.bulk.pts = MMAL_TIME_UNKNOWN;
-+ msg_context->u.bulk.cmd = msg->u.event_to_host.cmd;
-+
-+ pr_debug("event component:%u port type:%d num:%d cmd:0x%x length:%d\n",
-+ msg->u.event_to_host.client_component,
-+ msg->u.event_to_host.port_type,
-+ msg->u.event_to_host.port_num,
-+ msg->u.event_to_host.cmd, msg->u.event_to_host.length);
-+ }
-+
-+ schedule_work(&msg_context->u.bulk.work);
-+}
-+
- /* deals with receipt of buffer to host message */
- static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
- struct mmal_msg *msg, u32 msg_len)
-@@ -1340,6 +1433,7 @@ static int port_disable(struct vchiq_mma
- mmalbuf->mmal_flags = 0;
- mmalbuf->dts = MMAL_TIME_UNKNOWN;
- mmalbuf->pts = MMAL_TIME_UNKNOWN;
-+ mmalbuf->cmd = 0;
- port->buffer_cb(instance,
- port, 0, mmalbuf);
- }
-@@ -1641,6 +1735,43 @@ int mmal_vchi_buffer_cleanup(struct mmal
- }
- EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup);
-
-+static void init_event_context(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port)
-+{
-+ struct mmal_msg_context *ctx = get_msg_context(instance);
-+
-+ mutex_init(&port->event_context_mutex);
-+
-+ port->event_context = ctx;
-+ ctx->u.bulk.instance = instance;
-+ ctx->u.bulk.port = port;
-+ ctx->u.bulk.buffer =
-+ kzalloc(sizeof(*ctx->u.bulk.buffer), GFP_KERNEL);
-+ if (!ctx->u.bulk.buffer)
-+ goto release_msg_context;
-+ ctx->u.bulk.buffer->buffer = kzalloc(MMAL_WORKER_EVENT_SPACE,
-+ GFP_KERNEL);
-+ if (!ctx->u.bulk.buffer->buffer)
-+ goto release_buffer;
-+
-+ INIT_WORK(&ctx->u.bulk.work, buffer_work_cb);
-+ return;
-+
-+release_buffer:
-+ kfree(ctx->u.bulk.buffer);
-+release_msg_context:
-+ release_msg_context(ctx);
-+}
-+
-+static void free_event_context(struct vchiq_mmal_port *port)
-+{
-+ struct mmal_msg_context *ctx = port->event_context;
-+
-+ kfree(ctx->u.bulk.buffer->buffer);
-+ kfree(ctx->u.bulk.buffer);
-+ release_msg_context(ctx);
-+}
-+
- /* Initialise a mmal component and its ports
- *
- */
-@@ -1684,6 +1815,7 @@ int vchiq_mmal_component_init(struct vch
- ret = port_info_get(instance, &component->control);
- if (ret < 0)
- goto release_component;
-+ init_event_context(instance, &component->control);
-
- for (idx = 0; idx < component->inputs; idx++) {
- component->input[idx].type = MMAL_PORT_TYPE_INPUT;
-@@ -1694,6 +1826,7 @@ int vchiq_mmal_component_init(struct vch
- ret = port_info_get(instance, &component->input[idx]);
- if (ret < 0)
- goto release_component;
-+ init_event_context(instance, &component->input[idx]);
- }
-
- for (idx = 0; idx < component->outputs; idx++) {
-@@ -1705,6 +1838,7 @@ int vchiq_mmal_component_init(struct vch
- ret = port_info_get(instance, &component->output[idx]);
- if (ret < 0)
- goto release_component;
-+ init_event_context(instance, &component->output[idx]);
- }
-
- for (idx = 0; idx < component->clocks; idx++) {
-@@ -1716,6 +1850,7 @@ int vchiq_mmal_component_init(struct vch
- ret = port_info_get(instance, &component->clock[idx]);
- if (ret < 0)
- goto release_component;
-+ init_event_context(instance, &component->clock[idx]);
- }
-
- *component_out = component;
-@@ -1741,7 +1876,7 @@ EXPORT_SYMBOL_GPL(vchiq_mmal_component_i
- int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
- struct vchiq_mmal_component *component)
- {
-- int ret;
-+ int ret, idx;
-
- if (mutex_lock_interruptible(&instance->vchiq_mutex))
- return -EINTR;
-@@ -1753,6 +1888,13 @@ int vchiq_mmal_component_finalise(struct
-
- component->in_use = 0;
-
-+ for (idx = 0; idx < component->inputs; idx++)
-+ free_event_context(&component->input[idx]);
-+ for (idx = 0; idx < component->outputs; idx++)
-+ free_event_context(&component->output[idx]);
-+ for (idx = 0; idx < component->clocks; idx++)
-+ free_event_context(&component->clock[idx]);
-+
- mutex_unlock(&instance->vchiq_mutex);
-
- return ret;
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-@@ -78,6 +78,10 @@ struct vchiq_mmal_port {
- vchiq_mmal_buffer_cb buffer_cb;
- /* callback context */
- void *cb_ctx;
-+
-+ /* ensure serialised use of the one event context structure */
-+ struct mutex event_context_mutex;
-+ struct mmal_msg_context *event_context;
- };
-
- struct vchiq_mmal_component {
--- /dev/null
+From 2a5a03926a8c6ae7375355de00814234e4e303ed Mon Sep 17 00:00:00 2001
+Date: Tue, 25 Sep 2018 16:57:40 +0100
+Subject: [PATCH] staging: vc04_services: Fixup vchiq-mmal include
+ ordering
+
+There were dependencies on including the headers in the correct
+order. Fix up the headers so that they include the other
+headers that they depend on themselves.
+
+---
+ drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h | 1 +
+ drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h
+@@ -38,6 +38,7 @@
+ #include "mmal-msg-common.h"
+ #include "mmal-msg-format.h"
+ #include "mmal-msg-port.h"
++#include "mmal-vchiq.h"
+
+ enum mmal_msg_type {
+ MMAL_MSG_TYPE_QUIT = 1,
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
+@@ -16,6 +16,7 @@
+ #ifndef MMAL_VCHIQ_H
+ #define MMAL_VCHIQ_H
+
++#include "mmal-common.h"
+ #include "mmal-msg-format.h"
+
+ #define MAX_PORT_COUNT 4
--- /dev/null
+From 2994fdc0a9d48be68d6e403bc8ddadecfc8d8796 Mon Sep 17 00:00:00 2001
+Date: Tue, 25 Sep 2018 10:27:11 +0100
+Subject: [PATCH] staging: vc04_services: Add new vc-sm-cma driver
+
+This new driver allows contiguous memory blocks to be imported
+into the VideoCore VPU memory map, and manages the lifetime of
+those objects, only releasing the source dmabuf once the VPU has
+confirmed it has finished with it.
+
+---
+ drivers/staging/vc04_services/Kconfig | 1 +
+ drivers/staging/vc04_services/Makefile | 1 +
+ .../staging/vc04_services/vc-sm-cma/Kconfig | 10 +
+ .../staging/vc04_services/vc-sm-cma/Makefile | 8 +
+ drivers/staging/vc04_services/vc-sm-cma/TODO | 2 +
+ .../staging/vc04_services/vc-sm-cma/vc_sm.c | 838 ++++++++++++++++++
+ .../staging/vc04_services/vc-sm-cma/vc_sm.h | 59 ++
+ .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 498 +++++++++++
+ .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.h | 59 ++
+ .../vc04_services/vc-sm-cma/vc_sm_defs.h | 298 +++++++
+ .../vc04_services/vc-sm-cma/vc_sm_knl.h | 28 +
+ 11 files changed, 1802 insertions(+)
+ create mode 100644 drivers/staging/vc04_services/vc-sm-cma/Kconfig
+ create mode 100644 drivers/staging/vc04_services/vc-sm-cma/Makefile
+ create mode 100644 drivers/staging/vc04_services/vc-sm-cma/TODO
+ create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+ create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
+ create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
+ create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h
+ create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h
+ create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h
+
+--- a/drivers/staging/vc04_services/Kconfig
++++ b/drivers/staging/vc04_services/Kconfig
+@@ -22,6 +22,7 @@ source "drivers/staging/vc04_services/bc
+
+ source "drivers/staging/vc04_services/bcm2835-camera/Kconfig"
+ source "drivers/staging/vc04_services/vchiq-mmal/Kconfig"
++source "drivers/staging/vc04_services/vc-sm-cma/Kconfig"
+
+ endif
+
+--- a/drivers/staging/vc04_services/Makefile
++++ b/drivers/staging/vc04_services/Makefile
+@@ -13,6 +13,7 @@ vchiq-objs := \
+ obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
+ obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
+ obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
++obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/
+
+ ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000
+
+--- /dev/null
++++ b/drivers/staging/vc04_services/vc-sm-cma/Kconfig
+@@ -0,0 +1,10 @@
++config BCM_VC_SM_CMA
++ tristate "VideoCore Shared Memory (CMA) driver"
++ depends on BCM2835_VCHIQ
++ select RBTREE
++ select DMA_SHARED_BUFFER
++ help
++ Say Y here to enable the shared memory interface that
++ supports sharing dmabufs with VideoCore.
++ This operates over the VCHIQ interface to a service
++ running on VideoCore.
+--- /dev/null
++++ b/drivers/staging/vc04_services/vc-sm-cma/Makefile
+@@ -0,0 +1,8 @@
++ccflags-y += -Idrivers/staging/vc04_services -Idrivers/staging/vc04_services/interface/vchi -Idrivers/staging/vc04_services/interface/vchiq_arm
++# -I"drivers/staging/android/ion/" -I"$(srctree)/fs/"
++ccflags-y += -D__VCCOREVER__=0
++
++vc-sm-cma-$(CONFIG_BCM_VC_SM_CMA) := \
++ vc_sm.o vc_sm_cma_vchi.o
++
++obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma.o
+--- /dev/null
++++ b/drivers/staging/vc04_services/vc-sm-cma/TODO
+@@ -0,0 +1,2 @@
++1) Convert to a platform driver.
++
+--- /dev/null
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -0,0 +1,838 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * VideoCore Shared Memory driver using CMA.
++ *
++ * Copyright: 2018, Raspberry Pi (Trading) Ltd
++ *
++ * Based on vmcs_sm driver from Broadcom Corporation for some API,
++ * and taking some code for CMA/dmabuf handling from the Android Ion
++ * driver (Google/Linaro).
++ *
++ * This is cut down version to only support import of dma_bufs from
++ * other kernel drivers. A more complete implementation of the old
++ * vmcs_sm functionality can follow later.
++ *
++ */
++
++/* ---- Include Files ----------------------------------------------------- */
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/debugfs.h>
++#include <linux/dma-mapping.h>
++#include <linux/dma-buf.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/proc_fs.h>
++#include <linux/slab.h>
++#include <linux/seq_file.h>
++#include <linux/syscalls.h>
++#include <linux/types.h>
++
++#include "vchiq_connected.h"
++#include "vc_sm_cma_vchi.h"
++
++#include "vc_sm.h"
++#include "vc_sm_knl.h"
++
++/* ---- Private Constants and Types --------------------------------------- */
++
++#define DEVICE_NAME "vcsm-cma"
++#define DEVICE_MINOR 0
++
++#define VC_SM_RESOURCE_NAME_DEFAULT "sm-host-resource"
++
++#define VC_SM_DIR_ROOT_NAME "vcsm-cma"
++#define VC_SM_STATE "state"
++
++/* Private file data associated with each opened device. */
++struct vc_sm_privdata_t {
++ pid_t pid; /* PID of creator. */
++
++ int restart_sys; /* Tracks restart on interrupt. */
++ enum vc_sm_msg_type int_action; /* Interrupted action. */
++ u32 int_trans_id; /* Interrupted transaction. */
++};
++
++typedef int (*VC_SM_SHOW) (struct seq_file *s, void *v);
++struct sm_pde_t {
++ VC_SM_SHOW show; /* Debug fs function hookup. */
++ struct dentry *dir_entry; /* Debug fs directory entry. */
++ void *priv_data; /* Private data */
++};
++
++/* Global state information. */
++struct sm_state_t {
++ struct platform_device *pdev;
++
++ struct miscdevice dev;
++ struct sm_instance *sm_handle; /* Handle for videocore service. */
++
++ struct mutex map_lock; /* Global map lock. */
++ struct list_head buffer_list; /* List of buffer. */
++
++ struct vc_sm_privdata_t *data_knl; /* Kernel internal data tracking. */
++ struct dentry *dir_root; /* Debug fs entries root. */
++ struct sm_pde_t dir_state; /* Debug fs entries state sub-tree. */
++
++ bool require_released_callback; /* VPU will send a released msg when it
++ * has finished with a resource.
++ */
++ u32 int_trans_id; /* Interrupted transaction. */
++};
++
++/* ---- Private Variables ----------------------------------------------- */
++
++static struct sm_state_t *sm_state;
++static int sm_inited;
++
++/* ---- Private Function Prototypes -------------------------------------- */
++
++/* ---- Private Functions ------------------------------------------------ */
++
++static int vc_sm_cma_seq_file_show(struct seq_file *s, void *v)
++{
++ struct sm_pde_t *sm_pde;
++
++ sm_pde = (struct sm_pde_t *)(s->private);
++
++ if (sm_pde && sm_pde->show)
++ sm_pde->show(s, v);
++
++ return 0;
++}
++
++static int vc_sm_cma_single_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, vc_sm_cma_seq_file_show, inode->i_private);
++}
++
++static const struct file_operations vc_sm_cma_debug_fs_fops = {
++ .open = vc_sm_cma_single_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int vc_sm_cma_global_state_show(struct seq_file *s, void *v)
++{
++ struct vc_sm_buffer *resource = NULL;
++ int resource_count = 0;
++
++ if (!sm_state)
++ return 0;
++
++ seq_printf(s, "\nVC-ServiceHandle 0x%x\n",
++ (unsigned int)sm_state->sm_handle);
++
++ /* Log all applicable mapping(s). */
++
++ mutex_lock(&sm_state->map_lock);
++ seq_puts(s, "\nResources\n");
++ if (!list_empty(&sm_state->buffer_list)) {
++ list_for_each_entry(resource, &sm_state->buffer_list,
++ global_buffer_list) {
++ resource_count++;
++
++ seq_printf(s, "\nResource %p\n",
++ resource);
++ seq_printf(s, " NAME %s\n",
++ resource->name);
++ seq_printf(s, " SIZE %d\n",
++ resource->size);
++ seq_printf(s, " DMABUF %p\n",
++ resource->dma_buf);
++ seq_printf(s, " ATTACH %p\n",
++ resource->attach);
++ seq_printf(s, " SG_TABLE %p\n",
++ resource->sg_table);
++ seq_printf(s, " SGT %p\n",
++ resource->sgt);
++ seq_printf(s, " DMA_ADDR %pad\n",
++ &resource->dma_addr);
++ seq_printf(s, " VC_HANDLE %08x\n",
++ resource->vc_handle);
++ seq_printf(s, " VC_MAPPING %d\n",
++ resource->vpu_state);
++ }
++ }
++ seq_printf(s, "\n\nTotal resource count: %d\n\n", resource_count);
++
++ mutex_unlock(&sm_state->map_lock);
++
++ return 0;
++}
++
++/*
++ * Adds a buffer to the private data list which tracks all the allocated
++ * data.
++ */
++static void vc_sm_add_resource(struct vc_sm_privdata_t *privdata,
++ struct vc_sm_buffer *buffer)
++{
++ mutex_lock(&sm_state->map_lock);
++ list_add(&buffer->global_buffer_list, &sm_state->buffer_list);
++ mutex_unlock(&sm_state->map_lock);
++
++ pr_debug("[%s]: added buffer %p (name %s, size %d)\n",
++ __func__, buffer, buffer->name, buffer->size);
++}
++
++/*
++ * Release an allocation.
++ * All refcounting is done via the dma buf object.
++ */
++static void vc_sm_release_resource(struct vc_sm_buffer *buffer, int force)
++{
++ mutex_lock(&sm_state->map_lock);
++ mutex_lock(&buffer->lock);
++
++ pr_debug("[%s]: buffer %p (name %s, size %d)\n",
++ __func__, buffer, buffer->name, buffer->size);
++
++ if (buffer->vc_handle && buffer->vpu_state == VPU_MAPPED) {
++ struct vc_sm_free_t free = { buffer->vc_handle, 0 };
++ int status = vc_sm_cma_vchi_free(sm_state->sm_handle, &free,
++ &sm_state->int_trans_id);
++ if (status != 0 && status != -EINTR) {
++ pr_err("[%s]: failed to free memory on videocore (status: %u, trans_id: %u)\n",
++ __func__, status, sm_state->int_trans_id);
++ }
++
++ if (sm_state->require_released_callback) {
++ /* Need to wait for the VPU to confirm the free */
++
++ /* Retain a reference on this until the VPU has
++ * released it
++ */
++ buffer->vpu_state = VPU_UNMAPPING;
++ goto defer;
++ }
++ buffer->vpu_state = VPU_NOT_MAPPED;
++ buffer->vc_handle = 0;
++ }
++ if (buffer->vc_handle) {
++ /* We've sent the unmap request but not had the response. */
++ pr_err("[%s]: Waiting for VPU unmap response on %p\n",
++ __func__, buffer);
++ goto defer;
++ }
++ if (buffer->in_use) {
++ /* Don't release dmabuf here - we await the release */
++ pr_err("[%s]: buffer %p is still in use\n",
++ __func__, buffer);
++ goto defer;
++ }
++
++ /* Handle cleaning up imported dmabufs */
++ if (buffer->sgt) {
++ dma_buf_unmap_attachment(buffer->attach, buffer->sgt,
++ DMA_BIDIRECTIONAL);
++ buffer->sgt = NULL;
++ }
++ if (buffer->attach) {
++ dma_buf_detach(buffer->dma_buf, buffer->attach);
++ buffer->attach = NULL;
++ }
++
++ /* Release the dma_buf (whether ours or imported) */
++ if (buffer->import_dma_buf) {
++ dma_buf_put(buffer->import_dma_buf);
++ buffer->import_dma_buf = NULL;
++ buffer->dma_buf = NULL;
++ } else if (buffer->dma_buf) {
++ dma_buf_put(buffer->dma_buf);
++ buffer->dma_buf = NULL;
++ }
++
++ if (buffer->sg_table && !buffer->import_dma_buf) {
++ /* Our own allocation that we need to dma_unmap_sg */
++ dma_unmap_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
++ buffer->sg_table->nents, DMA_BIDIRECTIONAL);
++ }
++
++ /* Free the local resource. Start by removing it from the list */
++ buffer->private = NULL;
++ list_del(&buffer->global_buffer_list);
++
++ mutex_unlock(&buffer->lock);
++ mutex_unlock(&sm_state->map_lock);
++
++ mutex_destroy(&buffer->lock);
++
++ kfree(buffer);
++ return;
++
++defer:
++ mutex_unlock(&buffer->lock);
++ mutex_unlock(&sm_state->map_lock);
++}
++
++/* Create support for private data tracking. */
++static struct vc_sm_privdata_t *vc_sm_cma_create_priv_data(pid_t id)
++{
++ char alloc_name[32];
++ struct vc_sm_privdata_t *file_data = NULL;
++
++ /* Allocate private structure. */
++ file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
++
++ if (!file_data)
++ return NULL;
++
++ snprintf(alloc_name, sizeof(alloc_name), "%d", id);
++
++ file_data->pid = id;
++
++ return file_data;
++}
++
++/* Dma_buf operations for chaining through to an imported dma_buf */
++static
++int vc_sm_import_dma_buf_attach(struct dma_buf *dmabuf,
++ struct dma_buf_attachment *attachment)
++{
++ struct vc_sm_buffer *res = dmabuf->priv;
++
++ if (!res->import_dma_buf)
++ return -EINVAL;
++ return res->import_dma_buf->ops->attach(res->import_dma_buf,
++ attachment);
++}
++
++static
++void vc_sm_import_dma_buf_detatch(struct dma_buf *dmabuf,
++ struct dma_buf_attachment *attachment)
++{
++ struct vc_sm_buffer *res = dmabuf->priv;
++
++ if (!res->import_dma_buf)
++ return;
++ res->import_dma_buf->ops->detach(res->import_dma_buf, attachment);
++}
++
++static
++struct sg_table *vc_sm_import_map_dma_buf(struct dma_buf_attachment *attachment,
++ enum dma_data_direction direction)
++{
++ struct vc_sm_buffer *res = attachment->dmabuf->priv;
++
++ if (!res->import_dma_buf)
++ return NULL;
++ return res->import_dma_buf->ops->map_dma_buf(attachment, direction);
++}
++
++static
++void vc_sm_import_unmap_dma_buf(struct dma_buf_attachment *attachment,
++ struct sg_table *table,
++ enum dma_data_direction direction)
++{
++ struct vc_sm_buffer *res = attachment->dmabuf->priv;
++
++ if (!res->import_dma_buf)
++ return;
++ res->import_dma_buf->ops->unmap_dma_buf(attachment, table, direction);
++}
++
++static
++int vc_sm_import_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
++{
++ struct vc_sm_buffer *res = dmabuf->priv;
++
++ pr_debug("%s: mmap dma_buf %p, res %p, imported db %p\n", __func__,
++ dmabuf, res, res->import_dma_buf);
++ if (!res->import_dma_buf) {
++ pr_err("%s: mmap dma_buf %p- not an imported buffer\n",
++ __func__, dmabuf);
++ return -EINVAL;
++ }
++ return res->import_dma_buf->ops->mmap(res->import_dma_buf, vma);
++}
++
++static
++void vc_sm_import_dma_buf_release(struct dma_buf *dmabuf)
++{
++ struct vc_sm_buffer *res = dmabuf->priv;
++
++ pr_debug("%s: Relasing dma_buf %p\n", __func__, dmabuf);
++ if (!res->import_dma_buf)
++ return;
++
++ res->in_use = 0;
++
++ vc_sm_release_resource(res, 0);
++}
++
++static
++void *vc_sm_import_dma_buf_kmap(struct dma_buf *dmabuf,
++ unsigned long offset)
++{
++ struct vc_sm_buffer *res = dmabuf->priv;
++
++ if (!res->import_dma_buf)
++ return NULL;
++ return res->import_dma_buf->ops->map(res->import_dma_buf,
++ offset);
++}
++
++static
++void vc_sm_import_dma_buf_kunmap(struct dma_buf *dmabuf,
++ unsigned long offset, void *ptr)
++{
++ struct vc_sm_buffer *res = dmabuf->priv;
++
++ if (!res->import_dma_buf)
++ return;
++ res->import_dma_buf->ops->unmap(res->import_dma_buf,
++ offset, ptr);
++}
++
++static
++int vc_sm_import_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
++ enum dma_data_direction direction)
++{
++ struct vc_sm_buffer *res = dmabuf->priv;
++
++ if (!res->import_dma_buf)
++ return -EINVAL;
++ return res->import_dma_buf->ops->begin_cpu_access(res->import_dma_buf,
++ direction);
++}
++
++static
++int vc_sm_import_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
++ enum dma_data_direction direction)
++{
++ struct vc_sm_buffer *res = dmabuf->priv;
++
++ if (!res->import_dma_buf)
++ return -EINVAL;
++ return res->import_dma_buf->ops->end_cpu_access(res->import_dma_buf,
++ direction);
++}
++
++static const struct dma_buf_ops dma_buf_import_ops = {
++ .map_dma_buf = vc_sm_import_map_dma_buf,
++ .unmap_dma_buf = vc_sm_import_unmap_dma_buf,
++ .mmap = vc_sm_import_dmabuf_mmap,
++ .release = vc_sm_import_dma_buf_release,
++ .attach = vc_sm_import_dma_buf_attach,
++ .detach = vc_sm_import_dma_buf_detatch,
++ .begin_cpu_access = vc_sm_import_dma_buf_begin_cpu_access,
++ .end_cpu_access = vc_sm_import_dma_buf_end_cpu_access,
++ .map = vc_sm_import_dma_buf_kmap,
++ .unmap = vc_sm_import_dma_buf_kunmap,
++};
++
++/* Import a dma_buf to be shared with VC. */
++int
++vc_sm_cma_import_dmabuf_internal(struct vc_sm_privdata_t *private,
++ struct dma_buf *dma_buf,
++ struct dma_buf **imported_buf)
++{
++ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
++ struct vc_sm_buffer *buffer = NULL;
++ struct vc_sm_import import = { };
++ struct vc_sm_import_result result = { };
++ struct dma_buf_attachment *attach = NULL;
++ struct sg_table *sgt = NULL;
++ int ret = 0;
++ int status;
++
++ /* Setup our allocation parameters */
++ pr_debug("%s: importing dma_buf %p\n", __func__, dma_buf);
++
++ get_dma_buf(dma_buf);
++ dma_buf = dma_buf;
++
++ attach = dma_buf_attach(dma_buf, &sm_state->pdev->dev);
++ if (IS_ERR(attach)) {
++ ret = PTR_ERR(attach);
++ goto error;
++ }
++
++ sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
++ if (IS_ERR(sgt)) {
++ ret = PTR_ERR(sgt);
++ goto error;
++ }
++
++ /* Verify that the address block is contiguous */
++ if (sgt->nents != 1) {
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ /* Allocate local buffer to track this allocation. */
++ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
++ if (!buffer) {
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ import.type = VC_SM_ALLOC_NON_CACHED;
++ import.addr = (uint32_t)sg_dma_address(sgt->sgl);
++ if ((import.addr & 0xC0000000) != 0xC0000000) {
++ pr_err("%s: Expecting an uncached alias for dma_addr %08x\n",
++ __func__, import.addr);
++ import.addr |= 0xC0000000;
++ }
++ import.size = sg_dma_len(sgt->sgl);
++ import.allocator = current->tgid;
++ import.kernel_id = (uint32_t)buffer; //FIXME: 64 bit support needed.
++
++ memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT,
++ sizeof(VC_SM_RESOURCE_NAME_DEFAULT));
++
++ pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %p, size %u\n",
++ __func__, import.name, import.type, (void *)import.addr,
++ import.size);
++
++ /* Allocate the videocore buffer. */
++ status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result,
++ &sm_state->int_trans_id);
++ if (status == -EINTR) {
++ pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n",
++ __func__, sm_state->int_trans_id);
++ ret = -ERESTARTSYS;
++ private->restart_sys = -EINTR;
++ private->int_action = VC_SM_MSG_TYPE_IMPORT;
++ goto error;
++ } else if (status || !result.res_handle) {
++ pr_debug("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n",
++ __func__, status, sm_state->int_trans_id);
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ mutex_init(&buffer->lock);
++ INIT_LIST_HEAD(&buffer->attachments);
++ memcpy(buffer->name, import.name,
++ min(sizeof(buffer->name), sizeof(import.name) - 1));
++
++ /* Keep track of the buffer we created. */
++ buffer->private = private;
++ buffer->vc_handle = result.res_handle;
++ buffer->size = import.size;
++ buffer->vpu_state = VPU_MAPPED;
++
++ buffer->import_dma_buf = dma_buf;
++
++ buffer->attach = attach;
++ buffer->sgt = sgt;
++ buffer->dma_addr = sg_dma_address(sgt->sgl);
++ buffer->in_use = 1;
++
++ /*
++ * We're done - we need to export a new dmabuf chaining through most
++ * functions, but enabling us to release our own internal references
++ * here.
++ */
++ exp_info.ops = &dma_buf_import_ops;
++ exp_info.size = import.size;
++ exp_info.flags = O_RDWR;
++ exp_info.priv = buffer;
++
++ buffer->dma_buf = dma_buf_export(&exp_info);
++ if (IS_ERR(buffer->dma_buf)) {
++ ret = PTR_ERR(buffer->dma_buf);
++ goto error;
++ }
++
++ vc_sm_add_resource(private, buffer);
++
++ *imported_buf = buffer->dma_buf;
++
++ return 0;
++
++error:
++ if (result.res_handle) {
++ struct vc_sm_free_t free = { result.res_handle, 0 };
++
++ vc_sm_cma_vchi_free(sm_state->sm_handle, &free,
++ &sm_state->int_trans_id);
++ }
++ kfree(buffer);
++ if (sgt)
++ dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
++ if (attach)
++ dma_buf_detach(dma_buf, attach);
++ dma_buf_put(dma_buf);
++ return ret;
++}
++
++/* FIXME: Pass a function pointer to this into vc_vchi_sm.c */
++void
++vc_sm_vpu_event(struct sm_instance *instance, struct vc_sm_result_t *reply,
++ int reply_len)
++{
++ switch (reply->trans_id & ~0x80000000) {
++ case VC_SM_MSG_TYPE_CLIENT_VERSION:
++ {
++ /* Acknowledge that the firmware supports the version command */
++ pr_debug("%s: firmware acked version msg. Require release cb\n",
++ __func__);
++ sm_state->require_released_callback = true;
++ }
++ break;
++ case VC_SM_MSG_TYPE_RELEASED:
++ {
++ struct vc_sm_released *release = (struct vc_sm_released *)reply;
++ struct vc_sm_buffer *buffer =
++ (struct vc_sm_buffer *)release->kernel_id;
++
++ /*
++ * FIXME: Need to check buffer is still valid and allocated
++ * before continuing
++ */
++ pr_debug("%s: Released addr %08x, size %u, id %08x, mem_handle %08x\n",
++ __func__, release->addr, release->size,
++ release->kernel_id, release->vc_handle);
++ mutex_lock(&buffer->lock);
++ buffer->vc_handle = 0;
++ buffer->vpu_state = VPU_NOT_MAPPED;
++ mutex_unlock(&buffer->lock);
++
++ vc_sm_release_resource(buffer, 0);
++ }
++ break;
++ default:
++ pr_err("%s: Unknown vpu cmd %x\n", __func__, reply->trans_id);
++ break;
++ }
++}
++
++/* Videocore connected. */
++static void vc_sm_connected_init(void)
++{
++ int ret;
++ VCHI_INSTANCE_T vchi_instance;
++ struct vc_sm_version version;
++ struct vc_sm_result_t version_result;
++
++ pr_info("[%s]: start\n", __func__);
++
++ /*
++ * Initialize and create a VCHI connection for the shared memory service
++ * running on videocore.
++ */
++ ret = vchi_initialise(&vchi_instance);
++ if (ret) {
++ pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
++ __func__, ret);
++
++ ret = -EIO;
++ goto err_free_mem;
++ }
++
++ ret = vchi_connect(vchi_instance);
++ if (ret) {
++ pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
++ __func__, ret);
++
++ ret = -EIO;
++ goto err_free_mem;
++ }
++
++ /* Initialize an instance of the shared memory service. */
++ sm_state->sm_handle = vc_sm_cma_vchi_init(vchi_instance, 1,
++ vc_sm_vpu_event);
++ if (!sm_state->sm_handle) {
++ pr_err("[%s]: failed to initialize shared memory service\n",
++ __func__);
++
++ ret = -EPERM;
++ goto err_free_mem;
++ }
++
++ /* Create a debug fs directory entry (root). */
++ sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL);
++ if (!sm_state->dir_root) {
++ pr_err("[%s]: failed to create \'%s\' directory entry\n",
++ __func__, VC_SM_DIR_ROOT_NAME);
++
++ ret = -EPERM;
++ goto err_stop_sm_service;
++ }
++
++ sm_state->dir_state.show = &vc_sm_cma_global_state_show;
++ sm_state->dir_state.dir_entry =
++ debugfs_create_file(VC_SM_STATE, 0444, sm_state->dir_root,
++ &sm_state->dir_state,
++ &vc_sm_cma_debug_fs_fops);
++
++ INIT_LIST_HEAD(&sm_state->buffer_list);
++
++ sm_state->data_knl = vc_sm_cma_create_priv_data(0);
++ if (!sm_state->data_knl) {
++ pr_err("[%s]: failed to create kernel private data tracker\n",
++ __func__);
++ goto err_remove_shared_memory;
++ }
++
++ version.version = 1;
++ ret = vc_sm_cma_vchi_client_version(sm_state->sm_handle, &version,
++ &version_result,
++ &sm_state->int_trans_id);
++ if (ret) {
++ pr_err("[%s]: Failed to send version request %d\n", __func__,
++ ret);
++ }
++
++ /* Done! */
++ sm_inited = 1;
++ pr_info("[%s]: installed successfully\n", __func__);
++ return;
++
++err_remove_shared_memory:
++ debugfs_remove_recursive(sm_state->dir_root);
++err_stop_sm_service:
++ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
++err_free_mem:
++ kfree(sm_state);
++ pr_info("[%s]: failed, ret %d\n", __func__, ret);
++}
++
++/* Driver loading. */
++static int bcm2835_vc_sm_cma_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ int err;
++
++ pr_info("%s: Videocore shared memory driver\n", __func__);
++
++ sm_state = kzalloc(sizeof(*sm_state), GFP_KERNEL);
++ if (!sm_state)
++ return -ENOMEM;
++ sm_state->pdev = pdev;
++ mutex_init(&sm_state->map_lock);
++
++ dev->coherent_dma_mask = DMA_BIT_MASK(32);
++ dev->dma_mask = &dev->coherent_dma_mask;
++ err = of_dma_configure(dev, NULL, true);
++ if (err) {
++ dev_err(dev, "Unable to setup DMA: %d\n", err);
++ return err;
++ }
++
++ vchiq_add_connected_callback(vc_sm_connected_init);
++ return 0;
++}
++
++/* Driver unloading. */
++static int bcm2835_vc_sm_cma_remove(struct platform_device *pdev)
++{
++ pr_debug("[%s]: start\n", __func__);
++ if (sm_inited) {
++ /* Remove shared memory device. */
++ misc_deregister(&sm_state->dev);
++
++ /* Remove all proc entries. */
++ //debugfs_remove_recursive(sm_state->dir_root);
++
++ /* Stop the videocore shared memory service. */
++ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
++
++ /* Free the memory for the state structure. */
++ mutex_destroy(&sm_state->map_lock);
++ kfree(sm_state);
++ }
++
++ pr_debug("[%s]: end\n", __func__);
++ return 0;
++}
++
++/* Get an internal resource handle mapped from the external one. */
++int vc_sm_cma_int_handle(int handle)
++{
++ struct dma_buf *dma_buf = (struct dma_buf *)handle;
++ struct vc_sm_buffer *res;
++
++ /* Validate we can work with this device. */
++ if (!sm_state || !handle) {
++ pr_err("[%s]: invalid input\n", __func__);
++ return 0;
++ }
++
++ res = (struct vc_sm_buffer *)dma_buf->priv;
++ return res->vc_handle;
++}
++EXPORT_SYMBOL_GPL(vc_sm_cma_int_handle);
++
++/* Free a previously allocated shared memory handle and block. */
++int vc_sm_cma_free(int handle)
++{
++ struct dma_buf *dma_buf = (struct dma_buf *)handle;
++
++ /* Validate we can work with this device. */
++ if (!sm_state || !handle) {
++ pr_err("[%s]: invalid input\n", __func__);
++ return -EPERM;
++ }
++
++ pr_debug("%s: handle %08x/dmabuf %p\n", __func__, handle, dma_buf);
++
++ dma_buf_put(dma_buf);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(vc_sm_cma_free);
++
++/* Import a dmabuf to be shared with VC. */
++int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, int *handle)
++{
++ struct dma_buf *new_dma_buf;
++ struct vc_sm_buffer *res;
++ int ret;
++
++ /* Validate we can work with this device. */
++ if (!sm_state || !src_dmabuf || !handle) {
++ pr_err("[%s]: invalid input\n", __func__);
++ return -EPERM;
++ }
++
++ ret = vc_sm_cma_import_dmabuf_internal(sm_state->data_knl, src_dmabuf,
++ &new_dma_buf);
++
++ if (!ret) {
++ pr_debug("%s: imported to ptr %p\n", __func__, new_dma_buf);
++ res = (struct vc_sm_buffer *)new_dma_buf->priv;
++
++ /* Assign valid handle at this time.*/
++ *handle = (int)new_dma_buf;
++ } else {
++ /*
++ * succeeded in importing the dma_buf, but then
++ * failed to look it up again. How?
++ * Release the fd again.
++ */
++ pr_err("%s: imported vc_sm_cma_get_buffer failed %d\n",
++ __func__, ret);
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(vc_sm_cma_import_dmabuf);
++
++static struct platform_driver bcm2835_vcsm_cma_driver = {
++ .probe = bcm2835_vc_sm_cma_probe,
++ .remove = bcm2835_vc_sm_cma_remove,
++ .driver = {
++ .name = DEVICE_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++module_platform_driver(bcm2835_vcsm_cma_driver);
++
++MODULE_AUTHOR("Dave Stevenson");
++MODULE_DESCRIPTION("VideoCore CMA Shared Memory Driver");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:vcsm-cma");
+--- /dev/null
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
+@@ -0,0 +1,59 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++
++/*
++ * VideoCore Shared Memory driver using CMA.
++ *
++ * Copyright: 2018, Raspberry Pi (Trading) Ltd
++ *
++ */
++
++#ifndef VC_SM_H
++#define VC_SM_H
++
++#include <linux/device.h>
++#include <linux/dma-direction.h>
++#include <linux/kref.h>
++#include <linux/mm_types.h>
++#include <linux/mutex.h>
++#include <linux/rbtree.h>
++#include <linux/sched.h>
++#include <linux/shrinker.h>
++#include <linux/types.h>
++#include <linux/miscdevice.h>
++
++#define VC_SM_MAX_NAME_LEN 32
++
++enum vc_sm_vpu_mapping_state {
++ VPU_NOT_MAPPED,
++ VPU_MAPPED,
++ VPU_UNMAPPING
++};
++
++struct vc_sm_buffer {
++ struct list_head global_buffer_list; /* Global list of buffers. */
++
++ size_t size;
++
++ /* Lock over all the following state for this buffer */
++ struct mutex lock;
++ struct sg_table *sg_table;
++ struct list_head attachments;
++
++ char name[VC_SM_MAX_NAME_LEN];
++
++ int in_use:1; /* Kernel is still using this resource */
++
++ enum vc_sm_vpu_mapping_state vpu_state;
++ u32 vc_handle; /* VideoCore handle for this buffer */
++
++ /* DMABUF related fields */
++ struct dma_buf *import_dma_buf;
++ struct dma_buf *dma_buf;
++ struct dma_buf_attachment *attach;
++ struct sg_table *sgt;
++ dma_addr_t dma_addr;
++
++ struct vc_sm_privdata_t *private;
++};
++
++#endif
+--- /dev/null
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
+@@ -0,0 +1,498 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * VideoCore Shared Memory CMA allocator
++ *
++ * Copyright: 2018, Raspberry Pi (Trading) Ltd
++ * Copyright 2011-2012 Broadcom Corporation. All rights reserved.
++ *
++ * Based on vmcs_sm driver from Broadcom Corporation.
++ *
++ */
++
++/* ---- Include Files ----------------------------------------------------- */
++#include <linux/completion.h>
++#include <linux/kernel.h>
++#include <linux/kthread.h>
++#include <linux/list.h>
++#include <linux/mutex.h>
++#include <linux/semaphore.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++
++#include "vc_sm_cma_vchi.h"
++
++#define VC_SM_VER 1
++#define VC_SM_MIN_VER 0
++
++/* ---- Private Constants and Types -------------------------------------- */
++
++/* Command blocks come from a pool */
++#define SM_MAX_NUM_CMD_RSP_BLKS 32
++
++struct sm_cmd_rsp_blk {
++ struct list_head head; /* To create lists */
++ /* To be signaled when the response is there */
++ struct completion cmplt;
++
++ u16 id;
++ u16 length;
++
++ u8 msg[VC_SM_MAX_MSG_LEN];
++
++ uint32_t wait:1;
++ uint32_t sent:1;
++ uint32_t alloc:1;
++
++};
++
++struct sm_instance {
++ u32 num_connections;
++ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
++ struct task_struct *io_thread;
++ struct completion io_cmplt;
++
++ vpu_event_cb vpu_event;
++
++ /* Mutex over the following lists */
++ struct mutex lock;
++ u32 trans_id;
++ struct list_head cmd_list;
++ struct list_head rsp_list;
++ struct list_head dead_list;
++
++ struct sm_cmd_rsp_blk free_blk[SM_MAX_NUM_CMD_RSP_BLKS];
++
++ /* Mutex over the free_list */
++ struct mutex free_lock;
++ struct list_head free_list;
++
++ struct semaphore free_sema;
++
++};
++
++/* ---- Private Variables ------------------------------------------------ */
++
++/* ---- Private Function Prototypes -------------------------------------- */
++
++/* ---- Private Functions ------------------------------------------------ */
++static int
++bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
++ void *data,
++ unsigned int size)
++{
++ return vchi_queue_kernel_message(handle,
++ data,
++ size);
++}
++
++static struct
++sm_cmd_rsp_blk *vc_vchi_cmd_create(struct sm_instance *instance,
++ enum vc_sm_msg_type id, void *msg,
++ u32 size, int wait)
++{
++ struct sm_cmd_rsp_blk *blk;
++ struct vc_sm_msg_hdr_t *hdr;
++
++ if (down_interruptible(&instance->free_sema)) {
++ blk = kmalloc(sizeof(*blk), GFP_KERNEL);
++ if (!blk)
++ return NULL;
++
++ blk->alloc = 1;
++ init_completion(&blk->cmplt);
++ } else {
++ mutex_lock(&instance->free_lock);
++ blk =
++ list_first_entry(&instance->free_list,
++ struct sm_cmd_rsp_blk, head);
++ list_del(&blk->head);
++ mutex_unlock(&instance->free_lock);
++ }
++
++ blk->sent = 0;
++ blk->wait = wait;
++ blk->length = sizeof(*hdr) + size;
++
++ hdr = (struct vc_sm_msg_hdr_t *)blk->msg;
++ hdr->type = id;
++ mutex_lock(&instance->lock);
++ instance->trans_id++;
++ /*
++ * Retain the top bit for identifying asynchronous events, or VPU cmds.
++ */
++ instance->trans_id &= ~0x80000000;
++ hdr->trans_id = instance->trans_id;
++ blk->id = instance->trans_id;
++ mutex_unlock(&instance->lock);
++
++ if (size)
++ memcpy(hdr->body, msg, size);
++
++ return blk;
++}
++
++static void
++vc_vchi_cmd_delete(struct sm_instance *instance, struct sm_cmd_rsp_blk *blk)
++{
++ if (blk->alloc) {
++ kfree(blk);
++ return;
++ }
++
++ mutex_lock(&instance->free_lock);
++ list_add(&blk->head, &instance->free_list);
++ mutex_unlock(&instance->free_lock);
++ up(&instance->free_sema);
++}
++
++static void vc_sm_cma_vchi_rx_ack(struct sm_instance *instance,
++ struct sm_cmd_rsp_blk *cmd,
++ struct vc_sm_result_t *reply,
++ u32 reply_len)
++{
++ mutex_lock(&instance->lock);
++ list_for_each_entry(cmd,
++ &instance->rsp_list,
++ head) {
++ if (cmd->id == reply->trans_id)
++ break;
++ }
++ mutex_unlock(&instance->lock);
++
++ if (&cmd->head == &instance->rsp_list) {
++ //pr_debug("%s: received response %u, throw away...",
++ pr_err("%s: received response %u, throw away...",
++ __func__,
++ reply->trans_id);
++ } else if (reply_len > sizeof(cmd->msg)) {
++ pr_err("%s: reply too big (%u) %u, throw away...",
++ __func__, reply_len,
++ reply->trans_id);
++ } else {
++ memcpy(cmd->msg, reply,
++ reply_len);
++ complete(&cmd->cmplt);
++ }
++}
++
++static int vc_sm_cma_vchi_videocore_io(void *arg)
++{
++ struct sm_instance *instance = arg;
++ struct sm_cmd_rsp_blk *cmd = NULL, *cmd_tmp;
++ struct vc_sm_result_t *reply;
++ u32 reply_len;
++ s32 status;
++ int svc_use = 1;
++
++ while (1) {
++ if (svc_use)
++ vchi_service_release(instance->vchi_handle[0]);
++ svc_use = 0;
++ if (!wait_for_completion_interruptible(&instance->io_cmplt)) {
++ vchi_service_use(instance->vchi_handle[0]);
++ svc_use = 1;
++
++ do {
++ /*
++ * Get new command and move it to response list
++ */
++ mutex_lock(&instance->lock);
++ if (list_empty(&instance->cmd_list)) {
++ /* no more commands to process */
++ mutex_unlock(&instance->lock);
++ break;
++ }
++ cmd =
++ list_first_entry(&instance->cmd_list,
++ struct sm_cmd_rsp_blk,
++ head);
++ list_move(&cmd->head, &instance->rsp_list);
++ cmd->sent = 1;
++ mutex_unlock(&instance->lock);
++
++ /* Send the command */
++ status = bcm2835_vchi_msg_queue(
++ instance->vchi_handle[0],
++ cmd->msg, cmd->length);
++ if (status) {
++ pr_err("%s: failed to queue message (%d)",
++ __func__, status);
++ }
++
++ /* If no reply is needed then we're done */
++ if (!cmd->wait) {
++ mutex_lock(&instance->lock);
++ list_del(&cmd->head);
++ mutex_unlock(&instance->lock);
++ vc_vchi_cmd_delete(instance, cmd);
++ continue;
++ }
++
++ if (status) {
++ complete(&cmd->cmplt);
++ continue;
++ }
++
++ } while (1);
++
++ while (!vchi_msg_peek(instance->vchi_handle[0],
++ (void **)&reply, &reply_len,
++ VCHI_FLAGS_NONE)) {
++ if (reply->trans_id & 0x80000000) {
++ /* Async event or cmd from the VPU */
++ if (instance->vpu_event)
++ instance->vpu_event(
++ instance, reply,
++ reply_len);
++ } else {
++ vc_sm_cma_vchi_rx_ack(instance, cmd,
++ reply, reply_len);
++ }
++
++ vchi_msg_remove(instance->vchi_handle[0]);
++ }
++
++ /* Go through the dead list and free them */
++ mutex_lock(&instance->lock);
++ list_for_each_entry_safe(cmd, cmd_tmp,
++ &instance->dead_list, head) {
++ list_del(&cmd->head);
++ vc_vchi_cmd_delete(instance, cmd);
++ }
++ mutex_unlock(&instance->lock);
++ }
++ }
++
++ return 0;
++}
++
++static void vc_sm_cma_vchi_callback(void *param,
++ const VCHI_CALLBACK_REASON_T reason,
++ void *msg_handle)
++{
++ struct sm_instance *instance = param;
++
++ (void)msg_handle;
++
++ switch (reason) {
++ case VCHI_CALLBACK_MSG_AVAILABLE:
++ complete(&instance->io_cmplt);
++ break;
++
++ case VCHI_CALLBACK_SERVICE_CLOSED:
++ pr_info("%s: service CLOSED!!", __func__);
++ default:
++ break;
++ }
++}
++
++struct sm_instance *vc_sm_cma_vchi_init(VCHI_INSTANCE_T vchi_instance,
++ unsigned int num_connections,
++ vpu_event_cb vpu_event)
++{
++ u32 i;
++ struct sm_instance *instance;
++ int status;
++
++ pr_debug("%s: start", __func__);
++
++ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
++ pr_err("%s: unsupported number of connections %u (max=%u)",
++ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
++
++ goto err_null;
++ }
++ /* Allocate memory for this instance */
++ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
++
++ /* Misc initialisations */
++ mutex_init(&instance->lock);
++ init_completion(&instance->io_cmplt);
++ INIT_LIST_HEAD(&instance->cmd_list);
++ INIT_LIST_HEAD(&instance->rsp_list);
++ INIT_LIST_HEAD(&instance->dead_list);
++ INIT_LIST_HEAD(&instance->free_list);
++ sema_init(&instance->free_sema, SM_MAX_NUM_CMD_RSP_BLKS);
++ mutex_init(&instance->free_lock);
++ for (i = 0; i < SM_MAX_NUM_CMD_RSP_BLKS; i++) {
++ init_completion(&instance->free_blk[i].cmplt);
++ list_add(&instance->free_blk[i].head, &instance->free_list);
++ }
++
++ /* Open the VCHI service connections */
++ instance->num_connections = num_connections;
++ for (i = 0; i < num_connections; i++) {
++ SERVICE_CREATION_T params = {
++ .version = VCHI_VERSION_EX(VC_SM_VER, VC_SM_MIN_VER),
++ .service_id = VC_SM_SERVER_NAME,
++ .callback = vc_sm_cma_vchi_callback,
++ .callback_param = instance,
++ };
++
++ status = vchi_service_open(vchi_instance,
++ ¶ms, &instance->vchi_handle[i]);
++ if (status) {
++ pr_err("%s: failed to open VCHI service (%d)",
++ __func__, status);
++
++ goto err_close_services;
++ }
++ }
++
++ /* Create the thread which takes care of all io to/from videoocore. */
++ instance->io_thread = kthread_create(&vc_sm_cma_vchi_videocore_io,
++ (void *)instance, "SMIO");
++ if (!instance->io_thread) {
++ pr_err("%s: failed to create SMIO thread", __func__);
++
++ goto err_close_services;
++ }
++ instance->vpu_event = vpu_event;
++ set_user_nice(instance->io_thread, -10);
++ wake_up_process(instance->io_thread);
++
++ pr_debug("%s: success - instance 0x%x", __func__,
++ (unsigned int)instance);
++ return instance;
++
++err_close_services:
++ for (i = 0; i < instance->num_connections; i++) {
++ if (instance->vchi_handle[i])
++ vchi_service_close(instance->vchi_handle[i]);
++ }
++ kfree(instance);
++err_null:
++ pr_debug("%s: FAILED", __func__);
++ return NULL;
++}
++
++int vc_sm_cma_vchi_stop(struct sm_instance **handle)
++{
++ struct sm_instance *instance;
++ u32 i;
++
++ if (!handle) {
++ pr_err("%s: invalid pointer to handle %p", __func__, handle);
++ goto lock;
++ }
++
++ if (!*handle) {
++ pr_err("%s: invalid handle %p", __func__, *handle);
++ goto lock;
++ }
++
++ instance = *handle;
++
++ /* Close all VCHI service connections */
++ for (i = 0; i < instance->num_connections; i++) {
++ s32 success;
++
++ vchi_service_use(instance->vchi_handle[i]);
++
++ success = vchi_service_close(instance->vchi_handle[i]);
++ }
++
++ kfree(instance);
++
++ *handle = NULL;
++ return 0;
++
++lock:
++ return -EINVAL;
++}
++
++static int vc_sm_cma_vchi_send_msg(struct sm_instance *handle,
++ enum vc_sm_msg_type msg_id, void *msg,
++ u32 msg_size, void *result, u32 result_size,
++ u32 *cur_trans_id, u8 wait_reply)
++{
++ int status = 0;
++ struct sm_instance *instance = handle;
++ struct sm_cmd_rsp_blk *cmd_blk;
++
++ if (!handle) {
++ pr_err("%s: invalid handle", __func__);
++ return -EINVAL;
++ }
++ if (!msg) {
++ pr_err("%s: invalid msg pointer", __func__);
++ return -EINVAL;
++ }
++
++ cmd_blk =
++ vc_vchi_cmd_create(instance, msg_id, msg, msg_size, wait_reply);
++ if (!cmd_blk) {
++ pr_err("[%s]: failed to allocate global tracking resource",
++ __func__);
++ return -ENOMEM;
++ }
++
++ if (cur_trans_id)
++ *cur_trans_id = cmd_blk->id;
++
++ mutex_lock(&instance->lock);
++ list_add_tail(&cmd_blk->head, &instance->cmd_list);
++ mutex_unlock(&instance->lock);
++ complete(&instance->io_cmplt);
++
++ if (!wait_reply)
++ /* We're done */
++ return 0;
++
++ /* Wait for the response */
++ if (wait_for_completion_interruptible(&cmd_blk->cmplt)) {
++ mutex_lock(&instance->lock);
++ if (!cmd_blk->sent) {
++ list_del(&cmd_blk->head);
++ mutex_unlock(&instance->lock);
++ vc_vchi_cmd_delete(instance, cmd_blk);
++ return -ENXIO;
++ }
++
++ list_move(&cmd_blk->head, &instance->dead_list);
++ mutex_unlock(&instance->lock);
++ complete(&instance->io_cmplt);
++ return -EINTR; /* We're done */
++ }
++
++ if (result && result_size) {
++ memcpy(result, cmd_blk->msg, result_size);
++ } else {
++ struct vc_sm_result_t *res =
++ (struct vc_sm_result_t *)cmd_blk->msg;
++ status = (res->success == 0) ? 0 : -ENXIO;
++ }
++
++ mutex_lock(&instance->lock);
++ list_del(&cmd_blk->head);
++ mutex_unlock(&instance->lock);
++ vc_vchi_cmd_delete(instance, cmd_blk);
++ return status;
++}
++
++int vc_sm_cma_vchi_free(struct sm_instance *handle, struct vc_sm_free_t *msg,
++ u32 *cur_trans_id)
++{
++ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_FREE,
++ msg, sizeof(*msg), 0, 0, cur_trans_id, 0);
++}
++
++int vc_sm_cma_vchi_import(struct sm_instance *handle, struct vc_sm_import *msg,
++ struct vc_sm_import_result *result, u32 *cur_trans_id)
++{
++ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_IMPORT,
++ msg, sizeof(*msg), result, sizeof(*result),
++ cur_trans_id, 1);
++}
++
++int vc_sm_cma_vchi_client_version(struct sm_instance *handle,
++ struct vc_sm_version *msg,
++ struct vc_sm_result_t *result,
++ u32 *cur_trans_id)
++{
++ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_CLIENT_VERSION,
++ //msg, sizeof(*msg), result, sizeof(*result),
++ //cur_trans_id, 1);
++ msg, sizeof(*msg), NULL, 0,
++ cur_trans_id, 0);
++}
+--- /dev/null
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h
+@@ -0,0 +1,59 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++
++/*
++ * VideoCore Shared Memory CMA allocator
++ *
++ * Copyright: 2018, Raspberry Pi (Trading) Ltd
++ * Copyright 2011-2012 Broadcom Corporation. All rights reserved.
++ *
++ * Based on vmcs_sm driver from Broadcom Corporation.
++ *
++ */
++
++#ifndef __VC_SM_CMA_VCHI_H__INCLUDED__
++#define __VC_SM_CMA_VCHI_H__INCLUDED__
++
++#include "interface/vchi/vchi.h"
++
++#include "vc_sm_defs.h"
++
++/*
++ * Forward declare.
++ */
++struct sm_instance;
++
++typedef void (*vpu_event_cb)(struct sm_instance *instance,
++ struct vc_sm_result_t *reply, int reply_len);
++
++/*
++ * Initialize the shared memory service, opens up vchi connection to talk to it.
++ */
++struct sm_instance *vc_sm_cma_vchi_init(VCHI_INSTANCE_T vchi_instance,
++ unsigned int num_connections,
++ vpu_event_cb vpu_event);
++
++/*
++ * Terminates the shared memory service.
++ */
++int vc_sm_cma_vchi_stop(struct sm_instance **handle);
++
++/*
++ * Ask the shared memory service to free up some memory that was previously
++ * allocated by the vc_sm_cma_vchi_alloc function call.
++ */
++int vc_sm_cma_vchi_free(struct sm_instance *handle, struct vc_sm_free_t *msg,
++ u32 *cur_trans_id);
++
++/*
++ * Import a contiguous block of memory and wrap it in a GPU MEM_HANDLE_T.
++ */
++int vc_sm_cma_vchi_import(struct sm_instance *handle, struct vc_sm_import *msg,
++ struct vc_sm_import_result *result,
++ u32 *cur_trans_id);
++
++int vc_sm_cma_vchi_client_version(struct sm_instance *handle,
++ struct vc_sm_version *msg,
++ struct vc_sm_result_t *result,
++ u32 *cur_trans_id);
++
++#endif /* __VC_SM_CMA_VCHI_H__INCLUDED__ */
+--- /dev/null
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h
+@@ -0,0 +1,298 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++
++/*
++ * VideoCore Shared Memory CMA allocator
++ *
++ * Copyright: 2018, Raspberry Pi (Trading) Ltd
++ *
++ * Based on vc_sm_defs.h from the vmcs_sm driver Copyright Broadcom Corporation.
++ * All IPC messages are copied across to this file, even if the vc-sm-cma
++ * driver is not currently using them.
++ *
++ ****************************************************************************
++ */
++
++#ifndef __VC_SM_DEFS_H__INCLUDED__
++#define __VC_SM_DEFS_H__INCLUDED__
++
++/* FourCC code used for VCHI connection */
++#define VC_SM_SERVER_NAME MAKE_FOURCC("SMEM")
++
++/* Maximum message length */
++#define VC_SM_MAX_MSG_LEN (sizeof(union vc_sm_msg_union_t) + \
++ sizeof(struct vc_sm_msg_hdr_t))
++#define VC_SM_MAX_RSP_LEN (sizeof(union vc_sm_msg_union_t))
++
++/* Resource name maximum size */
++#define VC_SM_RESOURCE_NAME 32
++
++/*
++ * Version to be reported to the VPU
++ * VPU assumes 0 (aka 1) which does not require the released callback, nor
++ * expect the client to handle VC_MEM_REQUESTS.
++ * Version 2 requires the released callback, and must support VC_MEM_REQUESTS.
++ */
++#define VC_SM_PROTOCOL_VERSION 2
++
++enum vc_sm_msg_type {
++ /* Message types supported for HOST->VC direction */
++
++ /* Allocate shared memory block */
++ VC_SM_MSG_TYPE_ALLOC,
++ /* Lock allocated shared memory block */
++ VC_SM_MSG_TYPE_LOCK,
++ /* Unlock allocated shared memory block */
++ VC_SM_MSG_TYPE_UNLOCK,
++ /* Unlock allocated shared memory block, do not answer command */
++ VC_SM_MSG_TYPE_UNLOCK_NOANS,
++ /* Free shared memory block */
++ VC_SM_MSG_TYPE_FREE,
++ /* Resize a shared memory block */
++ VC_SM_MSG_TYPE_RESIZE,
++ /* Walk the allocated shared memory block(s) */
++ VC_SM_MSG_TYPE_WALK_ALLOC,
++
++ /* A previously applied action will need to be reverted */
++ VC_SM_MSG_TYPE_ACTION_CLEAN,
++
++ /*
++ * Import a physical address and wrap into a MEM_HANDLE_T.
++ * Release with VC_SM_MSG_TYPE_FREE.
++ */
++ VC_SM_MSG_TYPE_IMPORT,
++ /*
++ *Tells VC the protocol version supported by this client.
++ * 2 supports the async/cmd messages from the VPU for final release
++ * of memory, and for VC allocations.
++ */
++ VC_SM_MSG_TYPE_CLIENT_VERSION,
++ /* Response to VC request for memory */
++ VC_SM_MSG_TYPE_VC_MEM_REQUEST_REPLY,
++
++ /*
++ * Asynchronous/cmd messages supported for VC->HOST direction.
++ * Signalled by setting the top bit in vc_sm_result_t trans_id.
++ */
++
++ /*
++ * VC has finished with an imported memory allocation.
++ * Release any Linux reference counts on the underlying block.
++ */
++ VC_SM_MSG_TYPE_RELEASED,
++ /* VC request for memory */
++ VC_SM_MSG_TYPE_VC_MEM_REQUEST,
++
++ VC_SM_MSG_TYPE_MAX
++};
++
++/* Type of memory to be allocated */
++enum vc_sm_alloc_type_t {
++ VC_SM_ALLOC_CACHED,
++ VC_SM_ALLOC_NON_CACHED,
++};
++
++/* Message header for all messages in HOST->VC direction */
++struct vc_sm_msg_hdr_t {
++ u32 type;
++ u32 trans_id;
++ u8 body[0];
++
++};
++
++/* Request to allocate memory (HOST->VC) */
++struct vc_sm_alloc_t {
++ /* type of memory to allocate */
++ enum vc_sm_alloc_type_t type;
++ /* byte amount of data to allocate per unit */
++ u32 base_unit;
++ /* number of unit to allocate */
++ u32 num_unit;
++ /* alignment to be applied on allocation */
++ u32 alignment;
++ /* identity of who allocated this block */
++ u32 allocator;
++ /* resource name (for easier tracking on vc side) */
++ char name[VC_SM_RESOURCE_NAME];
++
++};
++
++/* Result of a requested memory allocation (VC->HOST) */
++struct vc_sm_alloc_result_t {
++ /* Transaction identifier */
++ u32 trans_id;
++
++ /* Resource handle */
++ u32 res_handle;
++ /* Pointer to resource buffer */
++ u32 res_mem;
++ /* Resource base size (bytes) */
++ u32 res_base_size;
++ /* Resource number */
++ u32 res_num;
++
++};
++
++/* Request to free a previously allocated memory (HOST->VC) */
++struct vc_sm_free_t {
++ /* Resource handle (returned from alloc) */
++ u32 res_handle;
++ /* Resource buffer (returned from alloc) */
++ u32 res_mem;
++
++};
++
++/* Request to lock a previously allocated memory (HOST->VC) */
++struct vc_sm_lock_unlock_t {
++ /* Resource handle (returned from alloc) */
++ u32 res_handle;
++ /* Resource buffer (returned from alloc) */
++ u32 res_mem;
++
++};
++
++/* Request to resize a previously allocated memory (HOST->VC) */
++struct vc_sm_resize_t {
++ /* Resource handle (returned from alloc) */
++ u32 res_handle;
++ /* Resource buffer (returned from alloc) */
++ u32 res_mem;
++ /* Resource *new* size requested (bytes) */
++ u32 res_new_size;
++
++};
++
++/* Result of a requested memory lock (VC->HOST) */
++struct vc_sm_lock_result_t {
++ /* Transaction identifier */
++ u32 trans_id;
++
++ /* Resource handle */
++ u32 res_handle;
++ /* Pointer to resource buffer */
++ u32 res_mem;
++ /*
++ * Pointer to former resource buffer if the memory
++ * was reallocated
++ */
++ u32 res_old_mem;
++
++};
++
++/* Generic result for a request (VC->HOST) */
++struct vc_sm_result_t {
++ /* Transaction identifier */
++ u32 trans_id;
++
++ s32 success;
++
++};
++
++/* Request to revert a previously applied action (HOST->VC) */
++struct vc_sm_action_clean_t {
++ /* Action of interest */
++ enum vc_sm_msg_type res_action;
++ /* Transaction identifier for the action of interest */
++ u32 action_trans_id;
++
++};
++
++/* Request to remove all data associated with a given allocator (HOST->VC) */
++struct vc_sm_free_all_t {
++ /* Allocator identifier */
++ u32 allocator;
++};
++
++/* Request to import memory (HOST->VC) */
++struct vc_sm_import {
++ /* type of memory to allocate */
++ enum vc_sm_alloc_type_t type;
++ /* pointer to the VC (ie physical) address of the allocated memory */
++ u32 addr;
++ /* size of buffer */
++ u32 size;
++ /* opaque handle returned in RELEASED messages */
++ u32 kernel_id;
++ /* Allocator identifier */
++ u32 allocator;
++ /* resource name (for easier tracking on vc side) */
++ char name[VC_SM_RESOURCE_NAME];
++};
++
++/* Result of a requested memory import (VC->HOST) */
++struct vc_sm_import_result {
++ /* Transaction identifier */
++ u32 trans_id;
++
++ /* Resource handle */
++ u32 res_handle;
++};
++
++/* Notification that VC has finished with an allocation (VC->HOST) */
++struct vc_sm_released {
++ /* cmd type / trans_id */
++ u32 cmd;
++
++ /* pointer to the VC (ie physical) address of the allocated memory */
++ u32 addr;
++ /* size of buffer */
++ u32 size;
++ /* opaque handle returned in RELEASED messages */
++ u32 kernel_id;
++ u32 vc_handle;
++};
++
++/*
++ * Client informing VC as to the protocol version it supports.
++ * >=2 requires the released callback, and supports VC asking for memory.
++ * Failure means that the firmware doesn't support this call, and therefore the
++ * client should either fail, or NOT rely on getting the released callback.
++ */
++struct vc_sm_version {
++ u32 version;
++};
++
++/* Request FROM VideoCore for some memory */
++struct vc_sm_vc_mem_request {
++ /* cmd type */
++ u32 cmd;
++
++ /* trans_id (from VPU) */
++ u32 trans_id;
++ /* size of buffer */
++ u32 size;
++ /* alignment of buffer */
++ u32 align;
++ /* resource name (for easier tracking) */
++ char name[VC_SM_RESOURCE_NAME];
++};
++
++/* Response from the kernel to provide the VPU with some memory */
++struct vc_sm_vc_mem_request_result {
++ /* Transaction identifier for the VPU */
++ u32 trans_id;
++ /* pointer to the physical address of the allocated memory */
++ u32 addr;
++ /* opaque handle returned in RELEASED messages */
++ u32 kernel_id;
++};
++
++/* Union of ALL messages */
++union vc_sm_msg_union_t {
++ struct vc_sm_alloc_t alloc;
++ struct vc_sm_alloc_result_t alloc_result;
++ struct vc_sm_free_t free;
++ struct vc_sm_lock_unlock_t lock_unlock;
++ struct vc_sm_action_clean_t action_clean;
++ struct vc_sm_resize_t resize;
++ struct vc_sm_lock_result_t lock_result;
++ struct vc_sm_result_t result;
++ struct vc_sm_free_all_t free_all;
++ struct vc_sm_import import;
++ struct vc_sm_import_result import_result;
++ struct vc_sm_version version;
++ struct vc_sm_released released;
++ struct vc_sm_vc_mem_request vc_request;
++ struct vc_sm_vc_mem_request_result vc_request_result;
++};
++
++#endif /* __VC_SM_DEFS_H__INCLUDED__ */
+--- /dev/null
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h
+@@ -0,0 +1,28 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++
++/*
++ * VideoCore Shared Memory CMA allocator
++ *
++ * Copyright: 2018, Raspberry Pi (Trading) Ltd
++ *
++ * Based on vc_sm_defs.h from the vmcs_sm driver Copyright Broadcom Corporation.
++ *
++ */
++
++#ifndef __VC_SM_KNL_H__INCLUDED__
++#define __VC_SM_KNL_H__INCLUDED__
++
++#if !defined(__KERNEL__)
++#error "This interface is for kernel use only..."
++#endif
++
++/* Free a previously allocated or imported shared memory handle and block. */
++int vc_sm_cma_free(int handle);
++
++/* Get an internal resource handle mapped from the external one. */
++int vc_sm_cma_int_handle(int handle);
++
++/* Import a block of memory into the GPU space. */
++int vc_sm_cma_import_dmabuf(struct dma_buf *dmabuf, int *handle);
++
++#endif /* __VC_SM_KNL_H__INCLUDED__ */
+++ /dev/null
-From 483bef9dcddc4bcb9f4e250d91b31361a919b7ed Mon Sep 17 00:00:00 2001
-Date: Mon, 24 Sep 2018 18:26:02 +0100
-Subject: [PATCH] staging: vc04_services: Support sending data to MMAL
- ports
-
-Add the ability to send data to ports. This only supports
-zero copy mode as the required bulk transfer setup calls
-are not done.
-
----
- .../vc04_services/vchiq-mmal/mmal-vchiq.c | 18 +++++++++++++-----
- 1 file changed, 13 insertions(+), 5 deletions(-)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -428,11 +428,19 @@ buffer_from_host(struct vchiq_mmal_insta
- m.u.buffer_from_host.buffer_header.data =
- (u32)(unsigned long)buf->buffer;
- m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
-- m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */
-- m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */
-- m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */
-- m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
-- m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
-+ if (port->type == MMAL_PORT_TYPE_OUTPUT) {
-+ m.u.buffer_from_host.buffer_header.length = 0;
-+ m.u.buffer_from_host.buffer_header.offset = 0;
-+ m.u.buffer_from_host.buffer_header.flags = 0;
-+ m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
-+ m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
-+ } else {
-+ m.u.buffer_from_host.buffer_header.length = buf->length;
-+ m.u.buffer_from_host.buffer_header.offset = 0;
-+ m.u.buffer_from_host.buffer_header.flags = buf->mmal_flags;
-+ m.u.buffer_from_host.buffer_header.pts = buf->pts;
-+ m.u.buffer_from_host.buffer_header.dts = buf->dts;
-+ }
-
- /* clear buffer type sepecific data */
- memset(&m.u.buffer_from_host.buffer_header_type_specific, 0,
--- /dev/null
+From 9eb40722f3ef0d338ed97667a7391f3d74812332 Mon Sep 17 00:00:00 2001
+Date: Tue, 30 Oct 2018 11:42:48 +0000
+Subject: [PATCH] staging: vc-sm-cma: Fixup driver for older VCHI APIs
+
+Original patch was based off staging which included some cleanups
+of the VCHI APIs. Those aren't present here, so switch back to
+the older API.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 2 +-
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 5 +++++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -632,7 +632,7 @@ static void vc_sm_connected_init(void)
+ goto err_free_mem;
+ }
+
+- ret = vchi_connect(vchi_instance);
++ ret = vchi_connect(NULL, 0, vchi_instance);
+ if (ret) {
+ pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
+ __func__, ret);
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
+@@ -325,8 +325,13 @@ struct sm_instance *vc_sm_cma_vchi_init(
+ SERVICE_CREATION_T params = {
+ .version = VCHI_VERSION_EX(VC_SM_VER, VC_SM_MIN_VER),
+ .service_id = VC_SM_SERVER_NAME,
++ .rx_fifo_size = 0,
++ .tx_fifo_size = 0,
+ .callback = vc_sm_cma_vchi_callback,
+ .callback_param = instance,
++ .want_unaligned_bulk_rx = 0,
++ .want_unaligned_bulk_tx = 0,
++ .want_crc = 0
+ };
+
+ status = vchi_service_open(vchi_instance,
+++ /dev/null
-From 2a5a03926a8c6ae7375355de00814234e4e303ed Mon Sep 17 00:00:00 2001
-Date: Tue, 25 Sep 2018 16:57:40 +0100
-Subject: [PATCH] staging: vc04_services: Fixup vchiq-mmal include
- ordering
-
-There were dependencies on including the headers in the correct
-order. Fix up the headers so that they include the other
-headers that they depend on themselves.
-
----
- drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h | 1 +
- drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 1 +
- 2 files changed, 2 insertions(+)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h
-@@ -38,6 +38,7 @@
- #include "mmal-msg-common.h"
- #include "mmal-msg-format.h"
- #include "mmal-msg-port.h"
-+#include "mmal-vchiq.h"
-
- enum mmal_msg_type {
- MMAL_MSG_TYPE_QUIT = 1,
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-@@ -16,6 +16,7 @@
- #ifndef MMAL_VCHIQ_H
- #define MMAL_VCHIQ_H
-
-+#include "mmal-common.h"
- #include "mmal-msg-format.h"
-
- #define MAX_PORT_COUNT 4
+++ /dev/null
-From 2994fdc0a9d48be68d6e403bc8ddadecfc8d8796 Mon Sep 17 00:00:00 2001
-Date: Tue, 25 Sep 2018 10:27:11 +0100
-Subject: [PATCH] staging: vc04_services: Add new vc-sm-cma driver
-
-This new driver allows contiguous memory blocks to be imported
-into the VideoCore VPU memory map, and manages the lifetime of
-those objects, only releasing the source dmabuf once the VPU has
-confirmed it has finished with it.
-
----
- drivers/staging/vc04_services/Kconfig | 1 +
- drivers/staging/vc04_services/Makefile | 1 +
- .../staging/vc04_services/vc-sm-cma/Kconfig | 10 +
- .../staging/vc04_services/vc-sm-cma/Makefile | 8 +
- drivers/staging/vc04_services/vc-sm-cma/TODO | 2 +
- .../staging/vc04_services/vc-sm-cma/vc_sm.c | 838 ++++++++++++++++++
- .../staging/vc04_services/vc-sm-cma/vc_sm.h | 59 ++
- .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 498 +++++++++++
- .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.h | 59 ++
- .../vc04_services/vc-sm-cma/vc_sm_defs.h | 298 +++++++
- .../vc04_services/vc-sm-cma/vc_sm_knl.h | 28 +
- 11 files changed, 1802 insertions(+)
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/Kconfig
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/Makefile
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/TODO
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h
-
---- a/drivers/staging/vc04_services/Kconfig
-+++ b/drivers/staging/vc04_services/Kconfig
-@@ -22,6 +22,7 @@ source "drivers/staging/vc04_services/bc
-
- source "drivers/staging/vc04_services/bcm2835-camera/Kconfig"
- source "drivers/staging/vc04_services/vchiq-mmal/Kconfig"
-+source "drivers/staging/vc04_services/vc-sm-cma/Kconfig"
-
- endif
-
---- a/drivers/staging/vc04_services/Makefile
-+++ b/drivers/staging/vc04_services/Makefile
-@@ -13,6 +13,7 @@ vchiq-objs := \
- obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
- obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
- obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
-+obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/
-
- ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000
-
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/Kconfig
-@@ -0,0 +1,10 @@
-+config BCM_VC_SM_CMA
-+ tristate "VideoCore Shared Memory (CMA) driver"
-+ depends on BCM2835_VCHIQ
-+ select RBTREE
-+ select DMA_SHARED_BUFFER
-+ help
-+ Say Y here to enable the shared memory interface that
-+ supports sharing dmabufs with VideoCore.
-+ This operates over the VCHIQ interface to a service
-+ running on VideoCore.
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/Makefile
-@@ -0,0 +1,8 @@
-+ccflags-y += -Idrivers/staging/vc04_services -Idrivers/staging/vc04_services/interface/vchi -Idrivers/staging/vc04_services/interface/vchiq_arm
-+# -I"drivers/staging/android/ion/" -I"$(srctree)/fs/"
-+ccflags-y += -D__VCCOREVER__=0
-+
-+vc-sm-cma-$(CONFIG_BCM_VC_SM_CMA) := \
-+ vc_sm.o vc_sm_cma_vchi.o
-+
-+obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma.o
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/TODO
-@@ -0,0 +1,2 @@
-+1) Convert to a platform driver.
-+
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -0,0 +1,838 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * VideoCore Shared Memory driver using CMA.
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ *
-+ * Based on vmcs_sm driver from Broadcom Corporation for some API,
-+ * and taking some code for CMA/dmabuf handling from the Android Ion
-+ * driver (Google/Linaro).
-+ *
-+ * This is cut down version to only support import of dma_bufs from
-+ * other kernel drivers. A more complete implementation of the old
-+ * vmcs_sm functionality can follow later.
-+ *
-+ */
-+
-+/* ---- Include Files ----------------------------------------------------- */
-+#include <linux/cdev.h>
-+#include <linux/device.h>
-+#include <linux/debugfs.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma-buf.h>
-+#include <linux/errno.h>
-+#include <linux/fs.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/miscdevice.h>
-+#include <linux/module.h>
-+#include <linux/mm.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/proc_fs.h>
-+#include <linux/slab.h>
-+#include <linux/seq_file.h>
-+#include <linux/syscalls.h>
-+#include <linux/types.h>
-+
-+#include "vchiq_connected.h"
-+#include "vc_sm_cma_vchi.h"
-+
-+#include "vc_sm.h"
-+#include "vc_sm_knl.h"
-+
-+/* ---- Private Constants and Types --------------------------------------- */
-+
-+#define DEVICE_NAME "vcsm-cma"
-+#define DEVICE_MINOR 0
-+
-+#define VC_SM_RESOURCE_NAME_DEFAULT "sm-host-resource"
-+
-+#define VC_SM_DIR_ROOT_NAME "vcsm-cma"
-+#define VC_SM_STATE "state"
-+
-+/* Private file data associated with each opened device. */
-+struct vc_sm_privdata_t {
-+ pid_t pid; /* PID of creator. */
-+
-+ int restart_sys; /* Tracks restart on interrupt. */
-+ enum vc_sm_msg_type int_action; /* Interrupted action. */
-+ u32 int_trans_id; /* Interrupted transaction. */
-+};
-+
-+typedef int (*VC_SM_SHOW) (struct seq_file *s, void *v);
-+struct sm_pde_t {
-+ VC_SM_SHOW show; /* Debug fs function hookup. */
-+ struct dentry *dir_entry; /* Debug fs directory entry. */
-+ void *priv_data; /* Private data */
-+};
-+
-+/* Global state information. */
-+struct sm_state_t {
-+ struct platform_device *pdev;
-+
-+ struct miscdevice dev;
-+ struct sm_instance *sm_handle; /* Handle for videocore service. */
-+
-+ struct mutex map_lock; /* Global map lock. */
-+ struct list_head buffer_list; /* List of buffer. */
-+
-+ struct vc_sm_privdata_t *data_knl; /* Kernel internal data tracking. */
-+ struct dentry *dir_root; /* Debug fs entries root. */
-+ struct sm_pde_t dir_state; /* Debug fs entries state sub-tree. */
-+
-+ bool require_released_callback; /* VPU will send a released msg when it
-+ * has finished with a resource.
-+ */
-+ u32 int_trans_id; /* Interrupted transaction. */
-+};
-+
-+/* ---- Private Variables ----------------------------------------------- */
-+
-+static struct sm_state_t *sm_state;
-+static int sm_inited;
-+
-+/* ---- Private Function Prototypes -------------------------------------- */
-+
-+/* ---- Private Functions ------------------------------------------------ */
-+
-+static int vc_sm_cma_seq_file_show(struct seq_file *s, void *v)
-+{
-+ struct sm_pde_t *sm_pde;
-+
-+ sm_pde = (struct sm_pde_t *)(s->private);
-+
-+ if (sm_pde && sm_pde->show)
-+ sm_pde->show(s, v);
-+
-+ return 0;
-+}
-+
-+static int vc_sm_cma_single_open(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, vc_sm_cma_seq_file_show, inode->i_private);
-+}
-+
-+static const struct file_operations vc_sm_cma_debug_fs_fops = {
-+ .open = vc_sm_cma_single_open,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+};
-+
-+static int vc_sm_cma_global_state_show(struct seq_file *s, void *v)
-+{
-+ struct vc_sm_buffer *resource = NULL;
-+ int resource_count = 0;
-+
-+ if (!sm_state)
-+ return 0;
-+
-+ seq_printf(s, "\nVC-ServiceHandle 0x%x\n",
-+ (unsigned int)sm_state->sm_handle);
-+
-+ /* Log all applicable mapping(s). */
-+
-+ mutex_lock(&sm_state->map_lock);
-+ seq_puts(s, "\nResources\n");
-+ if (!list_empty(&sm_state->buffer_list)) {
-+ list_for_each_entry(resource, &sm_state->buffer_list,
-+ global_buffer_list) {
-+ resource_count++;
-+
-+ seq_printf(s, "\nResource %p\n",
-+ resource);
-+ seq_printf(s, " NAME %s\n",
-+ resource->name);
-+ seq_printf(s, " SIZE %d\n",
-+ resource->size);
-+ seq_printf(s, " DMABUF %p\n",
-+ resource->dma_buf);
-+ seq_printf(s, " ATTACH %p\n",
-+ resource->attach);
-+ seq_printf(s, " SG_TABLE %p\n",
-+ resource->sg_table);
-+ seq_printf(s, " SGT %p\n",
-+ resource->sgt);
-+ seq_printf(s, " DMA_ADDR %pad\n",
-+ &resource->dma_addr);
-+ seq_printf(s, " VC_HANDLE %08x\n",
-+ resource->vc_handle);
-+ seq_printf(s, " VC_MAPPING %d\n",
-+ resource->vpu_state);
-+ }
-+ }
-+ seq_printf(s, "\n\nTotal resource count: %d\n\n", resource_count);
-+
-+ mutex_unlock(&sm_state->map_lock);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Adds a buffer to the private data list which tracks all the allocated
-+ * data.
-+ */
-+static void vc_sm_add_resource(struct vc_sm_privdata_t *privdata,
-+ struct vc_sm_buffer *buffer)
-+{
-+ mutex_lock(&sm_state->map_lock);
-+ list_add(&buffer->global_buffer_list, &sm_state->buffer_list);
-+ mutex_unlock(&sm_state->map_lock);
-+
-+ pr_debug("[%s]: added buffer %p (name %s, size %d)\n",
-+ __func__, buffer, buffer->name, buffer->size);
-+}
-+
-+/*
-+ * Release an allocation.
-+ * All refcounting is done via the dma buf object.
-+ */
-+static void vc_sm_release_resource(struct vc_sm_buffer *buffer, int force)
-+{
-+ mutex_lock(&sm_state->map_lock);
-+ mutex_lock(&buffer->lock);
-+
-+ pr_debug("[%s]: buffer %p (name %s, size %d)\n",
-+ __func__, buffer, buffer->name, buffer->size);
-+
-+ if (buffer->vc_handle && buffer->vpu_state == VPU_MAPPED) {
-+ struct vc_sm_free_t free = { buffer->vc_handle, 0 };
-+ int status = vc_sm_cma_vchi_free(sm_state->sm_handle, &free,
-+ &sm_state->int_trans_id);
-+ if (status != 0 && status != -EINTR) {
-+ pr_err("[%s]: failed to free memory on videocore (status: %u, trans_id: %u)\n",
-+ __func__, status, sm_state->int_trans_id);
-+ }
-+
-+ if (sm_state->require_released_callback) {
-+ /* Need to wait for the VPU to confirm the free */
-+
-+ /* Retain a reference on this until the VPU has
-+ * released it
-+ */
-+ buffer->vpu_state = VPU_UNMAPPING;
-+ goto defer;
-+ }
-+ buffer->vpu_state = VPU_NOT_MAPPED;
-+ buffer->vc_handle = 0;
-+ }
-+ if (buffer->vc_handle) {
-+ /* We've sent the unmap request but not had the response. */
-+ pr_err("[%s]: Waiting for VPU unmap response on %p\n",
-+ __func__, buffer);
-+ goto defer;
-+ }
-+ if (buffer->in_use) {
-+ /* Don't release dmabuf here - we await the release */
-+ pr_err("[%s]: buffer %p is still in use\n",
-+ __func__, buffer);
-+ goto defer;
-+ }
-+
-+ /* Handle cleaning up imported dmabufs */
-+ if (buffer->sgt) {
-+ dma_buf_unmap_attachment(buffer->attach, buffer->sgt,
-+ DMA_BIDIRECTIONAL);
-+ buffer->sgt = NULL;
-+ }
-+ if (buffer->attach) {
-+ dma_buf_detach(buffer->dma_buf, buffer->attach);
-+ buffer->attach = NULL;
-+ }
-+
-+ /* Release the dma_buf (whether ours or imported) */
-+ if (buffer->import_dma_buf) {
-+ dma_buf_put(buffer->import_dma_buf);
-+ buffer->import_dma_buf = NULL;
-+ buffer->dma_buf = NULL;
-+ } else if (buffer->dma_buf) {
-+ dma_buf_put(buffer->dma_buf);
-+ buffer->dma_buf = NULL;
-+ }
-+
-+ if (buffer->sg_table && !buffer->import_dma_buf) {
-+ /* Our own allocation that we need to dma_unmap_sg */
-+ dma_unmap_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
-+ buffer->sg_table->nents, DMA_BIDIRECTIONAL);
-+ }
-+
-+ /* Free the local resource. Start by removing it from the list */
-+ buffer->private = NULL;
-+ list_del(&buffer->global_buffer_list);
-+
-+ mutex_unlock(&buffer->lock);
-+ mutex_unlock(&sm_state->map_lock);
-+
-+ mutex_destroy(&buffer->lock);
-+
-+ kfree(buffer);
-+ return;
-+
-+defer:
-+ mutex_unlock(&buffer->lock);
-+ mutex_unlock(&sm_state->map_lock);
-+}
-+
-+/* Create support for private data tracking. */
-+static struct vc_sm_privdata_t *vc_sm_cma_create_priv_data(pid_t id)
-+{
-+ char alloc_name[32];
-+ struct vc_sm_privdata_t *file_data = NULL;
-+
-+ /* Allocate private structure. */
-+ file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
-+
-+ if (!file_data)
-+ return NULL;
-+
-+ snprintf(alloc_name, sizeof(alloc_name), "%d", id);
-+
-+ file_data->pid = id;
-+
-+ return file_data;
-+}
-+
-+/* Dma_buf operations for chaining through to an imported dma_buf */
-+static
-+int vc_sm_import_dma_buf_attach(struct dma_buf *dmabuf,
-+ struct dma_buf_attachment *attachment)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return -EINVAL;
-+ return res->import_dma_buf->ops->attach(res->import_dma_buf,
-+ attachment);
-+}
-+
-+static
-+void vc_sm_import_dma_buf_detatch(struct dma_buf *dmabuf,
-+ struct dma_buf_attachment *attachment)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return;
-+ res->import_dma_buf->ops->detach(res->import_dma_buf, attachment);
-+}
-+
-+static
-+struct sg_table *vc_sm_import_map_dma_buf(struct dma_buf_attachment *attachment,
-+ enum dma_data_direction direction)
-+{
-+ struct vc_sm_buffer *res = attachment->dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return NULL;
-+ return res->import_dma_buf->ops->map_dma_buf(attachment, direction);
-+}
-+
-+static
-+void vc_sm_import_unmap_dma_buf(struct dma_buf_attachment *attachment,
-+ struct sg_table *table,
-+ enum dma_data_direction direction)
-+{
-+ struct vc_sm_buffer *res = attachment->dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return;
-+ res->import_dma_buf->ops->unmap_dma_buf(attachment, table, direction);
-+}
-+
-+static
-+int vc_sm_import_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ pr_debug("%s: mmap dma_buf %p, res %p, imported db %p\n", __func__,
-+ dmabuf, res, res->import_dma_buf);
-+ if (!res->import_dma_buf) {
-+ pr_err("%s: mmap dma_buf %p- not an imported buffer\n",
-+ __func__, dmabuf);
-+ return -EINVAL;
-+ }
-+ return res->import_dma_buf->ops->mmap(res->import_dma_buf, vma);
-+}
-+
-+static
-+void vc_sm_import_dma_buf_release(struct dma_buf *dmabuf)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ pr_debug("%s: Relasing dma_buf %p\n", __func__, dmabuf);
-+ if (!res->import_dma_buf)
-+ return;
-+
-+ res->in_use = 0;
-+
-+ vc_sm_release_resource(res, 0);
-+}
-+
-+static
-+void *vc_sm_import_dma_buf_kmap(struct dma_buf *dmabuf,
-+ unsigned long offset)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return NULL;
-+ return res->import_dma_buf->ops->map(res->import_dma_buf,
-+ offset);
-+}
-+
-+static
-+void vc_sm_import_dma_buf_kunmap(struct dma_buf *dmabuf,
-+ unsigned long offset, void *ptr)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return;
-+ res->import_dma_buf->ops->unmap(res->import_dma_buf,
-+ offset, ptr);
-+}
-+
-+static
-+int vc_sm_import_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
-+ enum dma_data_direction direction)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return -EINVAL;
-+ return res->import_dma_buf->ops->begin_cpu_access(res->import_dma_buf,
-+ direction);
-+}
-+
-+static
-+int vc_sm_import_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
-+ enum dma_data_direction direction)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return -EINVAL;
-+ return res->import_dma_buf->ops->end_cpu_access(res->import_dma_buf,
-+ direction);
-+}
-+
-+static const struct dma_buf_ops dma_buf_import_ops = {
-+ .map_dma_buf = vc_sm_import_map_dma_buf,
-+ .unmap_dma_buf = vc_sm_import_unmap_dma_buf,
-+ .mmap = vc_sm_import_dmabuf_mmap,
-+ .release = vc_sm_import_dma_buf_release,
-+ .attach = vc_sm_import_dma_buf_attach,
-+ .detach = vc_sm_import_dma_buf_detatch,
-+ .begin_cpu_access = vc_sm_import_dma_buf_begin_cpu_access,
-+ .end_cpu_access = vc_sm_import_dma_buf_end_cpu_access,
-+ .map = vc_sm_import_dma_buf_kmap,
-+ .unmap = vc_sm_import_dma_buf_kunmap,
-+};
-+
-+/* Import a dma_buf to be shared with VC. */
-+int
-+vc_sm_cma_import_dmabuf_internal(struct vc_sm_privdata_t *private,
-+ struct dma_buf *dma_buf,
-+ struct dma_buf **imported_buf)
-+{
-+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
-+ struct vc_sm_buffer *buffer = NULL;
-+ struct vc_sm_import import = { };
-+ struct vc_sm_import_result result = { };
-+ struct dma_buf_attachment *attach = NULL;
-+ struct sg_table *sgt = NULL;
-+ int ret = 0;
-+ int status;
-+
-+ /* Setup our allocation parameters */
-+ pr_debug("%s: importing dma_buf %p\n", __func__, dma_buf);
-+
-+ get_dma_buf(dma_buf);
-+ dma_buf = dma_buf;
-+
-+ attach = dma_buf_attach(dma_buf, &sm_state->pdev->dev);
-+ if (IS_ERR(attach)) {
-+ ret = PTR_ERR(attach);
-+ goto error;
-+ }
-+
-+ sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
-+ if (IS_ERR(sgt)) {
-+ ret = PTR_ERR(sgt);
-+ goto error;
-+ }
-+
-+ /* Verify that the address block is contiguous */
-+ if (sgt->nents != 1) {
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ /* Allocate local buffer to track this allocation. */
-+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
-+ if (!buffer) {
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ import.type = VC_SM_ALLOC_NON_CACHED;
-+ import.addr = (uint32_t)sg_dma_address(sgt->sgl);
-+ if ((import.addr & 0xC0000000) != 0xC0000000) {
-+ pr_err("%s: Expecting an uncached alias for dma_addr %08x\n",
-+ __func__, import.addr);
-+ import.addr |= 0xC0000000;
-+ }
-+ import.size = sg_dma_len(sgt->sgl);
-+ import.allocator = current->tgid;
-+ import.kernel_id = (uint32_t)buffer; //FIXME: 64 bit support needed.
-+
-+ memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT,
-+ sizeof(VC_SM_RESOURCE_NAME_DEFAULT));
-+
-+ pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %p, size %u\n",
-+ __func__, import.name, import.type, (void *)import.addr,
-+ import.size);
-+
-+ /* Allocate the videocore buffer. */
-+ status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result,
-+ &sm_state->int_trans_id);
-+ if (status == -EINTR) {
-+ pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n",
-+ __func__, sm_state->int_trans_id);
-+ ret = -ERESTARTSYS;
-+ private->restart_sys = -EINTR;
-+ private->int_action = VC_SM_MSG_TYPE_IMPORT;
-+ goto error;
-+ } else if (status || !result.res_handle) {
-+ pr_debug("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n",
-+ __func__, status, sm_state->int_trans_id);
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ mutex_init(&buffer->lock);
-+ INIT_LIST_HEAD(&buffer->attachments);
-+ memcpy(buffer->name, import.name,
-+ min(sizeof(buffer->name), sizeof(import.name) - 1));
-+
-+ /* Keep track of the buffer we created. */
-+ buffer->private = private;
-+ buffer->vc_handle = result.res_handle;
-+ buffer->size = import.size;
-+ buffer->vpu_state = VPU_MAPPED;
-+
-+ buffer->import_dma_buf = dma_buf;
-+
-+ buffer->attach = attach;
-+ buffer->sgt = sgt;
-+ buffer->dma_addr = sg_dma_address(sgt->sgl);
-+ buffer->in_use = 1;
-+
-+ /*
-+ * We're done - we need to export a new dmabuf chaining through most
-+ * functions, but enabling us to release our own internal references
-+ * here.
-+ */
-+ exp_info.ops = &dma_buf_import_ops;
-+ exp_info.size = import.size;
-+ exp_info.flags = O_RDWR;
-+ exp_info.priv = buffer;
-+
-+ buffer->dma_buf = dma_buf_export(&exp_info);
-+ if (IS_ERR(buffer->dma_buf)) {
-+ ret = PTR_ERR(buffer->dma_buf);
-+ goto error;
-+ }
-+
-+ vc_sm_add_resource(private, buffer);
-+
-+ *imported_buf = buffer->dma_buf;
-+
-+ return 0;
-+
-+error:
-+ if (result.res_handle) {
-+ struct vc_sm_free_t free = { result.res_handle, 0 };
-+
-+ vc_sm_cma_vchi_free(sm_state->sm_handle, &free,
-+ &sm_state->int_trans_id);
-+ }
-+ kfree(buffer);
-+ if (sgt)
-+ dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
-+ if (attach)
-+ dma_buf_detach(dma_buf, attach);
-+ dma_buf_put(dma_buf);
-+ return ret;
-+}
-+
-+/* FIXME: Pass a function pointer to this into vc_vchi_sm.c */
-+void
-+vc_sm_vpu_event(struct sm_instance *instance, struct vc_sm_result_t *reply,
-+ int reply_len)
-+{
-+ switch (reply->trans_id & ~0x80000000) {
-+ case VC_SM_MSG_TYPE_CLIENT_VERSION:
-+ {
-+ /* Acknowledge that the firmware supports the version command */
-+ pr_debug("%s: firmware acked version msg. Require release cb\n",
-+ __func__);
-+ sm_state->require_released_callback = true;
-+ }
-+ break;
-+ case VC_SM_MSG_TYPE_RELEASED:
-+ {
-+ struct vc_sm_released *release = (struct vc_sm_released *)reply;
-+ struct vc_sm_buffer *buffer =
-+ (struct vc_sm_buffer *)release->kernel_id;
-+
-+ /*
-+ * FIXME: Need to check buffer is still valid and allocated
-+ * before continuing
-+ */
-+ pr_debug("%s: Released addr %08x, size %u, id %08x, mem_handle %08x\n",
-+ __func__, release->addr, release->size,
-+ release->kernel_id, release->vc_handle);
-+ mutex_lock(&buffer->lock);
-+ buffer->vc_handle = 0;
-+ buffer->vpu_state = VPU_NOT_MAPPED;
-+ mutex_unlock(&buffer->lock);
-+
-+ vc_sm_release_resource(buffer, 0);
-+ }
-+ break;
-+ default:
-+ pr_err("%s: Unknown vpu cmd %x\n", __func__, reply->trans_id);
-+ break;
-+ }
-+}
-+
-+/* Videocore connected. */
-+static void vc_sm_connected_init(void)
-+{
-+ int ret;
-+ VCHI_INSTANCE_T vchi_instance;
-+ struct vc_sm_version version;
-+ struct vc_sm_result_t version_result;
-+
-+ pr_info("[%s]: start\n", __func__);
-+
-+ /*
-+ * Initialize and create a VCHI connection for the shared memory service
-+ * running on videocore.
-+ */
-+ ret = vchi_initialise(&vchi_instance);
-+ if (ret) {
-+ pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
-+ __func__, ret);
-+
-+ ret = -EIO;
-+ goto err_free_mem;
-+ }
-+
-+ ret = vchi_connect(vchi_instance);
-+ if (ret) {
-+ pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
-+ __func__, ret);
-+
-+ ret = -EIO;
-+ goto err_free_mem;
-+ }
-+
-+ /* Initialize an instance of the shared memory service. */
-+ sm_state->sm_handle = vc_sm_cma_vchi_init(vchi_instance, 1,
-+ vc_sm_vpu_event);
-+ if (!sm_state->sm_handle) {
-+ pr_err("[%s]: failed to initialize shared memory service\n",
-+ __func__);
-+
-+ ret = -EPERM;
-+ goto err_free_mem;
-+ }
-+
-+ /* Create a debug fs directory entry (root). */
-+ sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL);
-+ if (!sm_state->dir_root) {
-+ pr_err("[%s]: failed to create \'%s\' directory entry\n",
-+ __func__, VC_SM_DIR_ROOT_NAME);
-+
-+ ret = -EPERM;
-+ goto err_stop_sm_service;
-+ }
-+
-+ sm_state->dir_state.show = &vc_sm_cma_global_state_show;
-+ sm_state->dir_state.dir_entry =
-+ debugfs_create_file(VC_SM_STATE, 0444, sm_state->dir_root,
-+ &sm_state->dir_state,
-+ &vc_sm_cma_debug_fs_fops);
-+
-+ INIT_LIST_HEAD(&sm_state->buffer_list);
-+
-+ sm_state->data_knl = vc_sm_cma_create_priv_data(0);
-+ if (!sm_state->data_knl) {
-+ pr_err("[%s]: failed to create kernel private data tracker\n",
-+ __func__);
-+ goto err_remove_shared_memory;
-+ }
-+
-+ version.version = 1;
-+ ret = vc_sm_cma_vchi_client_version(sm_state->sm_handle, &version,
-+ &version_result,
-+ &sm_state->int_trans_id);
-+ if (ret) {
-+ pr_err("[%s]: Failed to send version request %d\n", __func__,
-+ ret);
-+ }
-+
-+ /* Done! */
-+ sm_inited = 1;
-+ pr_info("[%s]: installed successfully\n", __func__);
-+ return;
-+
-+err_remove_shared_memory:
-+ debugfs_remove_recursive(sm_state->dir_root);
-+err_stop_sm_service:
-+ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
-+err_free_mem:
-+ kfree(sm_state);
-+ pr_info("[%s]: failed, ret %d\n", __func__, ret);
-+}
-+
-+/* Driver loading. */
-+static int bcm2835_vc_sm_cma_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ int err;
-+
-+ pr_info("%s: Videocore shared memory driver\n", __func__);
-+
-+ sm_state = kzalloc(sizeof(*sm_state), GFP_KERNEL);
-+ if (!sm_state)
-+ return -ENOMEM;
-+ sm_state->pdev = pdev;
-+ mutex_init(&sm_state->map_lock);
-+
-+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
-+ dev->dma_mask = &dev->coherent_dma_mask;
-+ err = of_dma_configure(dev, NULL, true);
-+ if (err) {
-+ dev_err(dev, "Unable to setup DMA: %d\n", err);
-+ return err;
-+ }
-+
-+ vchiq_add_connected_callback(vc_sm_connected_init);
-+ return 0;
-+}
-+
-+/* Driver unloading. */
-+static int bcm2835_vc_sm_cma_remove(struct platform_device *pdev)
-+{
-+ pr_debug("[%s]: start\n", __func__);
-+ if (sm_inited) {
-+ /* Remove shared memory device. */
-+ misc_deregister(&sm_state->dev);
-+
-+ /* Remove all proc entries. */
-+ //debugfs_remove_recursive(sm_state->dir_root);
-+
-+ /* Stop the videocore shared memory service. */
-+ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
-+
-+ /* Free the memory for the state structure. */
-+ mutex_destroy(&sm_state->map_lock);
-+ kfree(sm_state);
-+ }
-+
-+ pr_debug("[%s]: end\n", __func__);
-+ return 0;
-+}
-+
-+/* Get an internal resource handle mapped from the external one. */
-+int vc_sm_cma_int_handle(int handle)
-+{
-+ struct dma_buf *dma_buf = (struct dma_buf *)handle;
-+ struct vc_sm_buffer *res;
-+
-+ /* Validate we can work with this device. */
-+ if (!sm_state || !handle) {
-+ pr_err("[%s]: invalid input\n", __func__);
-+ return 0;
-+ }
-+
-+ res = (struct vc_sm_buffer *)dma_buf->priv;
-+ return res->vc_handle;
-+}
-+EXPORT_SYMBOL_GPL(vc_sm_cma_int_handle);
-+
-+/* Free a previously allocated shared memory handle and block. */
-+int vc_sm_cma_free(int handle)
-+{
-+ struct dma_buf *dma_buf = (struct dma_buf *)handle;
-+
-+ /* Validate we can work with this device. */
-+ if (!sm_state || !handle) {
-+ pr_err("[%s]: invalid input\n", __func__);
-+ return -EPERM;
-+ }
-+
-+ pr_debug("%s: handle %08x/dmabuf %p\n", __func__, handle, dma_buf);
-+
-+ dma_buf_put(dma_buf);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(vc_sm_cma_free);
-+
-+/* Import a dmabuf to be shared with VC. */
-+int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, int *handle)
-+{
-+ struct dma_buf *new_dma_buf;
-+ struct vc_sm_buffer *res;
-+ int ret;
-+
-+ /* Validate we can work with this device. */
-+ if (!sm_state || !src_dmabuf || !handle) {
-+ pr_err("[%s]: invalid input\n", __func__);
-+ return -EPERM;
-+ }
-+
-+ ret = vc_sm_cma_import_dmabuf_internal(sm_state->data_knl, src_dmabuf,
-+ &new_dma_buf);
-+
-+ if (!ret) {
-+ pr_debug("%s: imported to ptr %p\n", __func__, new_dma_buf);
-+ res = (struct vc_sm_buffer *)new_dma_buf->priv;
-+
-+ /* Assign valid handle at this time.*/
-+ *handle = (int)new_dma_buf;
-+ } else {
-+ /*
-+ * succeeded in importing the dma_buf, but then
-+ * failed to look it up again. How?
-+ * Release the fd again.
-+ */
-+ pr_err("%s: imported vc_sm_cma_get_buffer failed %d\n",
-+ __func__, ret);
-+ }
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vc_sm_cma_import_dmabuf);
-+
-+static struct platform_driver bcm2835_vcsm_cma_driver = {
-+ .probe = bcm2835_vc_sm_cma_probe,
-+ .remove = bcm2835_vc_sm_cma_remove,
-+ .driver = {
-+ .name = DEVICE_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+module_platform_driver(bcm2835_vcsm_cma_driver);
-+
-+MODULE_AUTHOR("Dave Stevenson");
-+MODULE_DESCRIPTION("VideoCore CMA Shared Memory Driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:vcsm-cma");
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
-@@ -0,0 +1,59 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/*
-+ * VideoCore Shared Memory driver using CMA.
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ *
-+ */
-+
-+#ifndef VC_SM_H
-+#define VC_SM_H
-+
-+#include <linux/device.h>
-+#include <linux/dma-direction.h>
-+#include <linux/kref.h>
-+#include <linux/mm_types.h>
-+#include <linux/mutex.h>
-+#include <linux/rbtree.h>
-+#include <linux/sched.h>
-+#include <linux/shrinker.h>
-+#include <linux/types.h>
-+#include <linux/miscdevice.h>
-+
-+#define VC_SM_MAX_NAME_LEN 32
-+
-+enum vc_sm_vpu_mapping_state {
-+ VPU_NOT_MAPPED,
-+ VPU_MAPPED,
-+ VPU_UNMAPPING
-+};
-+
-+struct vc_sm_buffer {
-+ struct list_head global_buffer_list; /* Global list of buffers. */
-+
-+ size_t size;
-+
-+ /* Lock over all the following state for this buffer */
-+ struct mutex lock;
-+ struct sg_table *sg_table;
-+ struct list_head attachments;
-+
-+ char name[VC_SM_MAX_NAME_LEN];
-+
-+ int in_use:1; /* Kernel is still using this resource */
-+
-+ enum vc_sm_vpu_mapping_state vpu_state;
-+ u32 vc_handle; /* VideoCore handle for this buffer */
-+
-+ /* DMABUF related fields */
-+ struct dma_buf *import_dma_buf;
-+ struct dma_buf *dma_buf;
-+ struct dma_buf_attachment *attach;
-+ struct sg_table *sgt;
-+ dma_addr_t dma_addr;
-+
-+ struct vc_sm_privdata_t *private;
-+};
-+
-+#endif
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
-@@ -0,0 +1,498 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * VideoCore Shared Memory CMA allocator
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ * Copyright 2011-2012 Broadcom Corporation. All rights reserved.
-+ *
-+ * Based on vmcs_sm driver from Broadcom Corporation.
-+ *
-+ */
-+
-+/* ---- Include Files ----------------------------------------------------- */
-+#include <linux/completion.h>
-+#include <linux/kernel.h>
-+#include <linux/kthread.h>
-+#include <linux/list.h>
-+#include <linux/mutex.h>
-+#include <linux/semaphore.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+
-+#include "vc_sm_cma_vchi.h"
-+
-+#define VC_SM_VER 1
-+#define VC_SM_MIN_VER 0
-+
-+/* ---- Private Constants and Types -------------------------------------- */
-+
-+/* Command blocks come from a pool */
-+#define SM_MAX_NUM_CMD_RSP_BLKS 32
-+
-+struct sm_cmd_rsp_blk {
-+ struct list_head head; /* To create lists */
-+ /* To be signaled when the response is there */
-+ struct completion cmplt;
-+
-+ u16 id;
-+ u16 length;
-+
-+ u8 msg[VC_SM_MAX_MSG_LEN];
-+
-+ uint32_t wait:1;
-+ uint32_t sent:1;
-+ uint32_t alloc:1;
-+
-+};
-+
-+struct sm_instance {
-+ u32 num_connections;
-+ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
-+ struct task_struct *io_thread;
-+ struct completion io_cmplt;
-+
-+ vpu_event_cb vpu_event;
-+
-+ /* Mutex over the following lists */
-+ struct mutex lock;
-+ u32 trans_id;
-+ struct list_head cmd_list;
-+ struct list_head rsp_list;
-+ struct list_head dead_list;
-+
-+ struct sm_cmd_rsp_blk free_blk[SM_MAX_NUM_CMD_RSP_BLKS];
-+
-+ /* Mutex over the free_list */
-+ struct mutex free_lock;
-+ struct list_head free_list;
-+
-+ struct semaphore free_sema;
-+
-+};
-+
-+/* ---- Private Variables ------------------------------------------------ */
-+
-+/* ---- Private Function Prototypes -------------------------------------- */
-+
-+/* ---- Private Functions ------------------------------------------------ */
-+static int
-+bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
-+ void *data,
-+ unsigned int size)
-+{
-+ return vchi_queue_kernel_message(handle,
-+ data,
-+ size);
-+}
-+
-+static struct
-+sm_cmd_rsp_blk *vc_vchi_cmd_create(struct sm_instance *instance,
-+ enum vc_sm_msg_type id, void *msg,
-+ u32 size, int wait)
-+{
-+ struct sm_cmd_rsp_blk *blk;
-+ struct vc_sm_msg_hdr_t *hdr;
-+
-+ if (down_interruptible(&instance->free_sema)) {
-+ blk = kmalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return NULL;
-+
-+ blk->alloc = 1;
-+ init_completion(&blk->cmplt);
-+ } else {
-+ mutex_lock(&instance->free_lock);
-+ blk =
-+ list_first_entry(&instance->free_list,
-+ struct sm_cmd_rsp_blk, head);
-+ list_del(&blk->head);
-+ mutex_unlock(&instance->free_lock);
-+ }
-+
-+ blk->sent = 0;
-+ blk->wait = wait;
-+ blk->length = sizeof(*hdr) + size;
-+
-+ hdr = (struct vc_sm_msg_hdr_t *)blk->msg;
-+ hdr->type = id;
-+ mutex_lock(&instance->lock);
-+ instance->trans_id++;
-+ /*
-+ * Retain the top bit for identifying asynchronous events, or VPU cmds.
-+ */
-+ instance->trans_id &= ~0x80000000;
-+ hdr->trans_id = instance->trans_id;
-+ blk->id = instance->trans_id;
-+ mutex_unlock(&instance->lock);
-+
-+ if (size)
-+ memcpy(hdr->body, msg, size);
-+
-+ return blk;
-+}
-+
-+static void
-+vc_vchi_cmd_delete(struct sm_instance *instance, struct sm_cmd_rsp_blk *blk)
-+{
-+ if (blk->alloc) {
-+ kfree(blk);
-+ return;
-+ }
-+
-+ mutex_lock(&instance->free_lock);
-+ list_add(&blk->head, &instance->free_list);
-+ mutex_unlock(&instance->free_lock);
-+ up(&instance->free_sema);
-+}
-+
-+static void vc_sm_cma_vchi_rx_ack(struct sm_instance *instance,
-+ struct sm_cmd_rsp_blk *cmd,
-+ struct vc_sm_result_t *reply,
-+ u32 reply_len)
-+{
-+ mutex_lock(&instance->lock);
-+ list_for_each_entry(cmd,
-+ &instance->rsp_list,
-+ head) {
-+ if (cmd->id == reply->trans_id)
-+ break;
-+ }
-+ mutex_unlock(&instance->lock);
-+
-+ if (&cmd->head == &instance->rsp_list) {
-+ //pr_debug("%s: received response %u, throw away...",
-+ pr_err("%s: received response %u, throw away...",
-+ __func__,
-+ reply->trans_id);
-+ } else if (reply_len > sizeof(cmd->msg)) {
-+ pr_err("%s: reply too big (%u) %u, throw away...",
-+ __func__, reply_len,
-+ reply->trans_id);
-+ } else {
-+ memcpy(cmd->msg, reply,
-+ reply_len);
-+ complete(&cmd->cmplt);
-+ }
-+}
-+
-+static int vc_sm_cma_vchi_videocore_io(void *arg)
-+{
-+ struct sm_instance *instance = arg;
-+ struct sm_cmd_rsp_blk *cmd = NULL, *cmd_tmp;
-+ struct vc_sm_result_t *reply;
-+ u32 reply_len;
-+ s32 status;
-+ int svc_use = 1;
-+
-+ while (1) {
-+ if (svc_use)
-+ vchi_service_release(instance->vchi_handle[0]);
-+ svc_use = 0;
-+ if (!wait_for_completion_interruptible(&instance->io_cmplt)) {
-+ vchi_service_use(instance->vchi_handle[0]);
-+ svc_use = 1;
-+
-+ do {
-+ /*
-+ * Get new command and move it to response list
-+ */
-+ mutex_lock(&instance->lock);
-+ if (list_empty(&instance->cmd_list)) {
-+ /* no more commands to process */
-+ mutex_unlock(&instance->lock);
-+ break;
-+ }
-+ cmd =
-+ list_first_entry(&instance->cmd_list,
-+ struct sm_cmd_rsp_blk,
-+ head);
-+ list_move(&cmd->head, &instance->rsp_list);
-+ cmd->sent = 1;
-+ mutex_unlock(&instance->lock);
-+
-+ /* Send the command */
-+ status = bcm2835_vchi_msg_queue(
-+ instance->vchi_handle[0],
-+ cmd->msg, cmd->length);
-+ if (status) {
-+ pr_err("%s: failed to queue message (%d)",
-+ __func__, status);
-+ }
-+
-+ /* If no reply is needed then we're done */
-+ if (!cmd->wait) {
-+ mutex_lock(&instance->lock);
-+ list_del(&cmd->head);
-+ mutex_unlock(&instance->lock);
-+ vc_vchi_cmd_delete(instance, cmd);
-+ continue;
-+ }
-+
-+ if (status) {
-+ complete(&cmd->cmplt);
-+ continue;
-+ }
-+
-+ } while (1);
-+
-+ while (!vchi_msg_peek(instance->vchi_handle[0],
-+ (void **)&reply, &reply_len,
-+ VCHI_FLAGS_NONE)) {
-+ if (reply->trans_id & 0x80000000) {
-+ /* Async event or cmd from the VPU */
-+ if (instance->vpu_event)
-+ instance->vpu_event(
-+ instance, reply,
-+ reply_len);
-+ } else {
-+ vc_sm_cma_vchi_rx_ack(instance, cmd,
-+ reply, reply_len);
-+ }
-+
-+ vchi_msg_remove(instance->vchi_handle[0]);
-+ }
-+
-+ /* Go through the dead list and free them */
-+ mutex_lock(&instance->lock);
-+ list_for_each_entry_safe(cmd, cmd_tmp,
-+ &instance->dead_list, head) {
-+ list_del(&cmd->head);
-+ vc_vchi_cmd_delete(instance, cmd);
-+ }
-+ mutex_unlock(&instance->lock);
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static void vc_sm_cma_vchi_callback(void *param,
-+ const VCHI_CALLBACK_REASON_T reason,
-+ void *msg_handle)
-+{
-+ struct sm_instance *instance = param;
-+
-+ (void)msg_handle;
-+
-+ switch (reason) {
-+ case VCHI_CALLBACK_MSG_AVAILABLE:
-+ complete(&instance->io_cmplt);
-+ break;
-+
-+ case VCHI_CALLBACK_SERVICE_CLOSED:
-+ pr_info("%s: service CLOSED!!", __func__);
-+ default:
-+ break;
-+ }
-+}
-+
-+struct sm_instance *vc_sm_cma_vchi_init(VCHI_INSTANCE_T vchi_instance,
-+ unsigned int num_connections,
-+ vpu_event_cb vpu_event)
-+{
-+ u32 i;
-+ struct sm_instance *instance;
-+ int status;
-+
-+ pr_debug("%s: start", __func__);
-+
-+ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
-+ pr_err("%s: unsupported number of connections %u (max=%u)",
-+ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
-+
-+ goto err_null;
-+ }
-+ /* Allocate memory for this instance */
-+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
-+
-+ /* Misc initialisations */
-+ mutex_init(&instance->lock);
-+ init_completion(&instance->io_cmplt);
-+ INIT_LIST_HEAD(&instance->cmd_list);
-+ INIT_LIST_HEAD(&instance->rsp_list);
-+ INIT_LIST_HEAD(&instance->dead_list);
-+ INIT_LIST_HEAD(&instance->free_list);
-+ sema_init(&instance->free_sema, SM_MAX_NUM_CMD_RSP_BLKS);
-+ mutex_init(&instance->free_lock);
-+ for (i = 0; i < SM_MAX_NUM_CMD_RSP_BLKS; i++) {
-+ init_completion(&instance->free_blk[i].cmplt);
-+ list_add(&instance->free_blk[i].head, &instance->free_list);
-+ }
-+
-+ /* Open the VCHI service connections */
-+ instance->num_connections = num_connections;
-+ for (i = 0; i < num_connections; i++) {
-+ SERVICE_CREATION_T params = {
-+ .version = VCHI_VERSION_EX(VC_SM_VER, VC_SM_MIN_VER),
-+ .service_id = VC_SM_SERVER_NAME,
-+ .callback = vc_sm_cma_vchi_callback,
-+ .callback_param = instance,
-+ };
-+
-+ status = vchi_service_open(vchi_instance,
-+ ¶ms, &instance->vchi_handle[i]);
-+ if (status) {
-+ pr_err("%s: failed to open VCHI service (%d)",
-+ __func__, status);
-+
-+ goto err_close_services;
-+ }
-+ }
-+
-+ /* Create the thread which takes care of all io to/from videoocore. */
-+ instance->io_thread = kthread_create(&vc_sm_cma_vchi_videocore_io,
-+ (void *)instance, "SMIO");
-+ if (!instance->io_thread) {
-+ pr_err("%s: failed to create SMIO thread", __func__);
-+
-+ goto err_close_services;
-+ }
-+ instance->vpu_event = vpu_event;
-+ set_user_nice(instance->io_thread, -10);
-+ wake_up_process(instance->io_thread);
-+
-+ pr_debug("%s: success - instance 0x%x", __func__,
-+ (unsigned int)instance);
-+ return instance;
-+
-+err_close_services:
-+ for (i = 0; i < instance->num_connections; i++) {
-+ if (instance->vchi_handle[i])
-+ vchi_service_close(instance->vchi_handle[i]);
-+ }
-+ kfree(instance);
-+err_null:
-+ pr_debug("%s: FAILED", __func__);
-+ return NULL;
-+}
-+
-+int vc_sm_cma_vchi_stop(struct sm_instance **handle)
-+{
-+ struct sm_instance *instance;
-+ u32 i;
-+
-+ if (!handle) {
-+ pr_err("%s: invalid pointer to handle %p", __func__, handle);
-+ goto lock;
-+ }
-+
-+ if (!*handle) {
-+ pr_err("%s: invalid handle %p", __func__, *handle);
-+ goto lock;
-+ }
-+
-+ instance = *handle;
-+
-+ /* Close all VCHI service connections */
-+ for (i = 0; i < instance->num_connections; i++) {
-+ s32 success;
-+
-+ vchi_service_use(instance->vchi_handle[i]);
-+
-+ success = vchi_service_close(instance->vchi_handle[i]);
-+ }
-+
-+ kfree(instance);
-+
-+ *handle = NULL;
-+ return 0;
-+
-+lock:
-+ return -EINVAL;
-+}
-+
-+static int vc_sm_cma_vchi_send_msg(struct sm_instance *handle,
-+ enum vc_sm_msg_type msg_id, void *msg,
-+ u32 msg_size, void *result, u32 result_size,
-+ u32 *cur_trans_id, u8 wait_reply)
-+{
-+ int status = 0;
-+ struct sm_instance *instance = handle;
-+ struct sm_cmd_rsp_blk *cmd_blk;
-+
-+ if (!handle) {
-+ pr_err("%s: invalid handle", __func__);
-+ return -EINVAL;
-+ }
-+ if (!msg) {
-+ pr_err("%s: invalid msg pointer", __func__);
-+ return -EINVAL;
-+ }
-+
-+ cmd_blk =
-+ vc_vchi_cmd_create(instance, msg_id, msg, msg_size, wait_reply);
-+ if (!cmd_blk) {
-+ pr_err("[%s]: failed to allocate global tracking resource",
-+ __func__);
-+ return -ENOMEM;
-+ }
-+
-+ if (cur_trans_id)
-+ *cur_trans_id = cmd_blk->id;
-+
-+ mutex_lock(&instance->lock);
-+ list_add_tail(&cmd_blk->head, &instance->cmd_list);
-+ mutex_unlock(&instance->lock);
-+ complete(&instance->io_cmplt);
-+
-+ if (!wait_reply)
-+ /* We're done */
-+ return 0;
-+
-+ /* Wait for the response */
-+ if (wait_for_completion_interruptible(&cmd_blk->cmplt)) {
-+ mutex_lock(&instance->lock);
-+ if (!cmd_blk->sent) {
-+ list_del(&cmd_blk->head);
-+ mutex_unlock(&instance->lock);
-+ vc_vchi_cmd_delete(instance, cmd_blk);
-+ return -ENXIO;
-+ }
-+
-+ list_move(&cmd_blk->head, &instance->dead_list);
-+ mutex_unlock(&instance->lock);
-+ complete(&instance->io_cmplt);
-+ return -EINTR; /* We're done */
-+ }
-+
-+ if (result && result_size) {
-+ memcpy(result, cmd_blk->msg, result_size);
-+ } else {
-+ struct vc_sm_result_t *res =
-+ (struct vc_sm_result_t *)cmd_blk->msg;
-+ status = (res->success == 0) ? 0 : -ENXIO;
-+ }
-+
-+ mutex_lock(&instance->lock);
-+ list_del(&cmd_blk->head);
-+ mutex_unlock(&instance->lock);
-+ vc_vchi_cmd_delete(instance, cmd_blk);
-+ return status;
-+}
-+
-+int vc_sm_cma_vchi_free(struct sm_instance *handle, struct vc_sm_free_t *msg,
-+ u32 *cur_trans_id)
-+{
-+ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_FREE,
-+ msg, sizeof(*msg), 0, 0, cur_trans_id, 0);
-+}
-+
-+int vc_sm_cma_vchi_import(struct sm_instance *handle, struct vc_sm_import *msg,
-+ struct vc_sm_import_result *result, u32 *cur_trans_id)
-+{
-+ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_IMPORT,
-+ msg, sizeof(*msg), result, sizeof(*result),
-+ cur_trans_id, 1);
-+}
-+
-+int vc_sm_cma_vchi_client_version(struct sm_instance *handle,
-+ struct vc_sm_version *msg,
-+ struct vc_sm_result_t *result,
-+ u32 *cur_trans_id)
-+{
-+ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_CLIENT_VERSION,
-+ //msg, sizeof(*msg), result, sizeof(*result),
-+ //cur_trans_id, 1);
-+ msg, sizeof(*msg), NULL, 0,
-+ cur_trans_id, 0);
-+}
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h
-@@ -0,0 +1,59 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/*
-+ * VideoCore Shared Memory CMA allocator
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ * Copyright 2011-2012 Broadcom Corporation. All rights reserved.
-+ *
-+ * Based on vmcs_sm driver from Broadcom Corporation.
-+ *
-+ */
-+
-+#ifndef __VC_SM_CMA_VCHI_H__INCLUDED__
-+#define __VC_SM_CMA_VCHI_H__INCLUDED__
-+
-+#include "interface/vchi/vchi.h"
-+
-+#include "vc_sm_defs.h"
-+
-+/*
-+ * Forward declare.
-+ */
-+struct sm_instance;
-+
-+typedef void (*vpu_event_cb)(struct sm_instance *instance,
-+ struct vc_sm_result_t *reply, int reply_len);
-+
-+/*
-+ * Initialize the shared memory service, opens up vchi connection to talk to it.
-+ */
-+struct sm_instance *vc_sm_cma_vchi_init(VCHI_INSTANCE_T vchi_instance,
-+ unsigned int num_connections,
-+ vpu_event_cb vpu_event);
-+
-+/*
-+ * Terminates the shared memory service.
-+ */
-+int vc_sm_cma_vchi_stop(struct sm_instance **handle);
-+
-+/*
-+ * Ask the shared memory service to free up some memory that was previously
-+ * allocated by the vc_sm_cma_vchi_alloc function call.
-+ */
-+int vc_sm_cma_vchi_free(struct sm_instance *handle, struct vc_sm_free_t *msg,
-+ u32 *cur_trans_id);
-+
-+/*
-+ * Import a contiguous block of memory and wrap it in a GPU MEM_HANDLE_T.
-+ */
-+int vc_sm_cma_vchi_import(struct sm_instance *handle, struct vc_sm_import *msg,
-+ struct vc_sm_import_result *result,
-+ u32 *cur_trans_id);
-+
-+int vc_sm_cma_vchi_client_version(struct sm_instance *handle,
-+ struct vc_sm_version *msg,
-+ struct vc_sm_result_t *result,
-+ u32 *cur_trans_id);
-+
-+#endif /* __VC_SM_CMA_VCHI_H__INCLUDED__ */
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h
-@@ -0,0 +1,298 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/*
-+ * VideoCore Shared Memory CMA allocator
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ *
-+ * Based on vc_sm_defs.h from the vmcs_sm driver Copyright Broadcom Corporation.
-+ * All IPC messages are copied across to this file, even if the vc-sm-cma
-+ * driver is not currently using them.
-+ *
-+ ****************************************************************************
-+ */
-+
-+#ifndef __VC_SM_DEFS_H__INCLUDED__
-+#define __VC_SM_DEFS_H__INCLUDED__
-+
-+/* FourCC code used for VCHI connection */
-+#define VC_SM_SERVER_NAME MAKE_FOURCC("SMEM")
-+
-+/* Maximum message length */
-+#define VC_SM_MAX_MSG_LEN (sizeof(union vc_sm_msg_union_t) + \
-+ sizeof(struct vc_sm_msg_hdr_t))
-+#define VC_SM_MAX_RSP_LEN (sizeof(union vc_sm_msg_union_t))
-+
-+/* Resource name maximum size */
-+#define VC_SM_RESOURCE_NAME 32
-+
-+/*
-+ * Version to be reported to the VPU
-+ * VPU assumes 0 (aka 1) which does not require the released callback, nor
-+ * expect the client to handle VC_MEM_REQUESTS.
-+ * Version 2 requires the released callback, and must support VC_MEM_REQUESTS.
-+ */
-+#define VC_SM_PROTOCOL_VERSION 2
-+
-+enum vc_sm_msg_type {
-+ /* Message types supported for HOST->VC direction */
-+
-+ /* Allocate shared memory block */
-+ VC_SM_MSG_TYPE_ALLOC,
-+ /* Lock allocated shared memory block */
-+ VC_SM_MSG_TYPE_LOCK,
-+ /* Unlock allocated shared memory block */
-+ VC_SM_MSG_TYPE_UNLOCK,
-+ /* Unlock allocated shared memory block, do not answer command */
-+ VC_SM_MSG_TYPE_UNLOCK_NOANS,
-+ /* Free shared memory block */
-+ VC_SM_MSG_TYPE_FREE,
-+ /* Resize a shared memory block */
-+ VC_SM_MSG_TYPE_RESIZE,
-+ /* Walk the allocated shared memory block(s) */
-+ VC_SM_MSG_TYPE_WALK_ALLOC,
-+
-+ /* A previously applied action will need to be reverted */
-+ VC_SM_MSG_TYPE_ACTION_CLEAN,
-+
-+ /*
-+ * Import a physical address and wrap into a MEM_HANDLE_T.
-+ * Release with VC_SM_MSG_TYPE_FREE.
-+ */
-+ VC_SM_MSG_TYPE_IMPORT,
-+ /*
-+ *Tells VC the protocol version supported by this client.
-+ * 2 supports the async/cmd messages from the VPU for final release
-+ * of memory, and for VC allocations.
-+ */
-+ VC_SM_MSG_TYPE_CLIENT_VERSION,
-+ /* Response to VC request for memory */
-+ VC_SM_MSG_TYPE_VC_MEM_REQUEST_REPLY,
-+
-+ /*
-+ * Asynchronous/cmd messages supported for VC->HOST direction.
-+ * Signalled by setting the top bit in vc_sm_result_t trans_id.
-+ */
-+
-+ /*
-+ * VC has finished with an imported memory allocation.
-+ * Release any Linux reference counts on the underlying block.
-+ */
-+ VC_SM_MSG_TYPE_RELEASED,
-+ /* VC request for memory */
-+ VC_SM_MSG_TYPE_VC_MEM_REQUEST,
-+
-+ VC_SM_MSG_TYPE_MAX
-+};
-+
-+/* Type of memory to be allocated */
-+enum vc_sm_alloc_type_t {
-+ VC_SM_ALLOC_CACHED,
-+ VC_SM_ALLOC_NON_CACHED,
-+};
-+
-+/* Message header for all messages in HOST->VC direction */
-+struct vc_sm_msg_hdr_t {
-+ u32 type;
-+ u32 trans_id;
-+ u8 body[0];
-+
-+};
-+
-+/* Request to allocate memory (HOST->VC) */
-+struct vc_sm_alloc_t {
-+ /* type of memory to allocate */
-+ enum vc_sm_alloc_type_t type;
-+ /* byte amount of data to allocate per unit */
-+ u32 base_unit;
-+ /* number of unit to allocate */
-+ u32 num_unit;
-+ /* alignment to be applied on allocation */
-+ u32 alignment;
-+ /* identity of who allocated this block */
-+ u32 allocator;
-+ /* resource name (for easier tracking on vc side) */
-+ char name[VC_SM_RESOURCE_NAME];
-+
-+};
-+
-+/* Result of a requested memory allocation (VC->HOST) */
-+struct vc_sm_alloc_result_t {
-+ /* Transaction identifier */
-+ u32 trans_id;
-+
-+ /* Resource handle */
-+ u32 res_handle;
-+ /* Pointer to resource buffer */
-+ u32 res_mem;
-+ /* Resource base size (bytes) */
-+ u32 res_base_size;
-+ /* Resource number */
-+ u32 res_num;
-+
-+};
-+
-+/* Request to free a previously allocated memory (HOST->VC) */
-+struct vc_sm_free_t {
-+ /* Resource handle (returned from alloc) */
-+ u32 res_handle;
-+ /* Resource buffer (returned from alloc) */
-+ u32 res_mem;
-+
-+};
-+
-+/* Request to lock a previously allocated memory (HOST->VC) */
-+struct vc_sm_lock_unlock_t {
-+ /* Resource handle (returned from alloc) */
-+ u32 res_handle;
-+ /* Resource buffer (returned from alloc) */
-+ u32 res_mem;
-+
-+};
-+
-+/* Request to resize a previously allocated memory (HOST->VC) */
-+struct vc_sm_resize_t {
-+ /* Resource handle (returned from alloc) */
-+ u32 res_handle;
-+ /* Resource buffer (returned from alloc) */
-+ u32 res_mem;
-+ /* Resource *new* size requested (bytes) */
-+ u32 res_new_size;
-+
-+};
-+
-+/* Result of a requested memory lock (VC->HOST) */
-+struct vc_sm_lock_result_t {
-+ /* Transaction identifier */
-+ u32 trans_id;
-+
-+ /* Resource handle */
-+ u32 res_handle;
-+ /* Pointer to resource buffer */
-+ u32 res_mem;
-+ /*
-+ * Pointer to former resource buffer if the memory
-+ * was reallocated
-+ */
-+ u32 res_old_mem;
-+
-+};
-+
-+/* Generic result for a request (VC->HOST) */
-+struct vc_sm_result_t {
-+ /* Transaction identifier */
-+ u32 trans_id;
-+
-+ s32 success;
-+
-+};
-+
-+/* Request to revert a previously applied action (HOST->VC) */
-+struct vc_sm_action_clean_t {
-+ /* Action of interest */
-+ enum vc_sm_msg_type res_action;
-+ /* Transaction identifier for the action of interest */
-+ u32 action_trans_id;
-+
-+};
-+
-+/* Request to remove all data associated with a given allocator (HOST->VC) */
-+struct vc_sm_free_all_t {
-+ /* Allocator identifier */
-+ u32 allocator;
-+};
-+
-+/* Request to import memory (HOST->VC) */
-+struct vc_sm_import {
-+ /* type of memory to allocate */
-+ enum vc_sm_alloc_type_t type;
-+ /* pointer to the VC (ie physical) address of the allocated memory */
-+ u32 addr;
-+ /* size of buffer */
-+ u32 size;
-+ /* opaque handle returned in RELEASED messages */
-+ u32 kernel_id;
-+ /* Allocator identifier */
-+ u32 allocator;
-+ /* resource name (for easier tracking on vc side) */
-+ char name[VC_SM_RESOURCE_NAME];
-+};
-+
-+/* Result of a requested memory import (VC->HOST) */
-+struct vc_sm_import_result {
-+ /* Transaction identifier */
-+ u32 trans_id;
-+
-+ /* Resource handle */
-+ u32 res_handle;
-+};
-+
-+/* Notification that VC has finished with an allocation (VC->HOST) */
-+struct vc_sm_released {
-+ /* cmd type / trans_id */
-+ u32 cmd;
-+
-+ /* pointer to the VC (ie physical) address of the allocated memory */
-+ u32 addr;
-+ /* size of buffer */
-+ u32 size;
-+ /* opaque handle returned in RELEASED messages */
-+ u32 kernel_id;
-+ u32 vc_handle;
-+};
-+
-+/*
-+ * Client informing VC as to the protocol version it supports.
-+ * >=2 requires the released callback, and supports VC asking for memory.
-+ * Failure means that the firmware doesn't support this call, and therefore the
-+ * client should either fail, or NOT rely on getting the released callback.
-+ */
-+struct vc_sm_version {
-+ u32 version;
-+};
-+
-+/* Request FROM VideoCore for some memory */
-+struct vc_sm_vc_mem_request {
-+ /* cmd type */
-+ u32 cmd;
-+
-+ /* trans_id (from VPU) */
-+ u32 trans_id;
-+ /* size of buffer */
-+ u32 size;
-+ /* alignment of buffer */
-+ u32 align;
-+ /* resource name (for easier tracking) */
-+ char name[VC_SM_RESOURCE_NAME];
-+};
-+
-+/* Response from the kernel to provide the VPU with some memory */
-+struct vc_sm_vc_mem_request_result {
-+ /* Transaction identifier for the VPU */
-+ u32 trans_id;
-+ /* pointer to the physical address of the allocated memory */
-+ u32 addr;
-+ /* opaque handle returned in RELEASED messages */
-+ u32 kernel_id;
-+};
-+
-+/* Union of ALL messages */
-+union vc_sm_msg_union_t {
-+ struct vc_sm_alloc_t alloc;
-+ struct vc_sm_alloc_result_t alloc_result;
-+ struct vc_sm_free_t free;
-+ struct vc_sm_lock_unlock_t lock_unlock;
-+ struct vc_sm_action_clean_t action_clean;
-+ struct vc_sm_resize_t resize;
-+ struct vc_sm_lock_result_t lock_result;
-+ struct vc_sm_result_t result;
-+ struct vc_sm_free_all_t free_all;
-+ struct vc_sm_import import;
-+ struct vc_sm_import_result import_result;
-+ struct vc_sm_version version;
-+ struct vc_sm_released released;
-+ struct vc_sm_vc_mem_request vc_request;
-+ struct vc_sm_vc_mem_request_result vc_request_result;
-+};
-+
-+#endif /* __VC_SM_DEFS_H__INCLUDED__ */
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h
-@@ -0,0 +1,28 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/*
-+ * VideoCore Shared Memory CMA allocator
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ *
-+ * Based on vc_sm_defs.h from the vmcs_sm driver Copyright Broadcom Corporation.
-+ *
-+ */
-+
-+#ifndef __VC_SM_KNL_H__INCLUDED__
-+#define __VC_SM_KNL_H__INCLUDED__
-+
-+#if !defined(__KERNEL__)
-+#error "This interface is for kernel use only..."
-+#endif
-+
-+/* Free a previously allocated or imported shared memory handle and block. */
-+int vc_sm_cma_free(int handle);
-+
-+/* Get an internal resource handle mapped from the external one. */
-+int vc_sm_cma_int_handle(int handle);
-+
-+/* Import a block of memory into the GPU space. */
-+int vc_sm_cma_import_dmabuf(struct dma_buf *dmabuf, int *handle);
-+
-+#endif /* __VC_SM_KNL_H__INCLUDED__ */
--- /dev/null
+From bcb0dccc1f02ed3dd01834ca0e35c4043df8988e Mon Sep 17 00:00:00 2001
+Date: Tue, 25 Sep 2018 16:07:55 +0100
+Subject: [PATCH] staging: vc04_services: Use vc-sm-cma to support zero
+ copy
+
+With the vc-sm-cma driver we can support zero copy of buffers between
+the kernel and VPU. Add this support to vchiq-mmal.
+
+---
+ .../staging/vc04_services/vchiq-mmal/Kconfig | 1 +
+ .../vc04_services/vchiq-mmal/mmal-common.h | 4 ++
+ .../vc04_services/vchiq-mmal/mmal-vchiq.c | 66 ++++++++++++++++++-
+ .../vc04_services/vchiq-mmal/mmal-vchiq.h | 1 +
+ 4 files changed, 70 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/Kconfig
++++ b/drivers/staging/vc04_services/vchiq-mmal/Kconfig
+@@ -2,6 +2,7 @@ config BCM2835_VCHIQ_MMAL
+ tristate "BCM2835 MMAL VCHIQ service"
+ depends on (ARCH_BCM2835 || COMPILE_TEST)
+ select BCM2835_VCHIQ
++ select BCM_VC_SM_CMA
+ help
+ Enables the MMAL API over VCHIQ as used for the
+ majority of the multimedia services on VideoCore.
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
+@@ -51,6 +51,10 @@ struct mmal_buffer {
+
+ struct mmal_msg_context *msg_context;
+
++ struct dma_buf *dma_buf;/* Exported dmabuf fd from videobuf2 */
++ int vcsm_handle; /* VCSM handle having imported the dmabuf */
++ u32 vc_handle; /* VC handle to that dmabuf */
++
+ u32 cmd; /* MMAL command. 0=data. */
+ unsigned long length;
+ u32 mmal_flags;
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -27,9 +27,12 @@
+ #include <media/videobuf2-vmalloc.h>
+
+ #include "mmal-common.h"
++#include "mmal-parameters.h"
+ #include "mmal-vchiq.h"
+ #include "mmal-msg.h"
+
++#include "vc-sm-cma/vc_sm_knl.h"
++
+ #define USE_VCHIQ_ARM
+ #include "interface/vchi/vchi.h"
+
+@@ -425,8 +428,13 @@ buffer_from_host(struct vchiq_mmal_insta
+
+ /* buffer header */
+ m.u.buffer_from_host.buffer_header.cmd = 0;
+- m.u.buffer_from_host.buffer_header.data =
+- (u32)(unsigned long)buf->buffer;
++ if (port->zero_copy) {
++ m.u.buffer_from_host.buffer_header.data = buf->vc_handle;
++ } else {
++ m.u.buffer_from_host.buffer_header.data =
++ (u32)(unsigned long)buf->buffer;
++ }
++
+ m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
+ if (port->type == MMAL_PORT_TYPE_OUTPUT) {
+ m.u.buffer_from_host.buffer_header.length = 0;
+@@ -591,6 +599,22 @@ static void buffer_to_host_cb(struct vch
+
+ msg_context->u.bulk.status = msg->h.status;
+
++ } else if (msg->u.buffer_from_host.is_zero_copy) {
++ /*
++ * Zero copy buffer, so nothing to do.
++ * Copy buffer info and make callback.
++ */
++ msg_context->u.bulk.buffer_used =
++ msg->u.buffer_from_host.buffer_header.length;
++ msg_context->u.bulk.mmal_flags =
++ msg->u.buffer_from_host.buffer_header.flags;
++ msg_context->u.bulk.dts =
++ msg->u.buffer_from_host.buffer_header.dts;
++ msg_context->u.bulk.pts =
++ msg->u.buffer_from_host.buffer_header.pts;
++ msg_context->u.bulk.cmd =
++ msg->u.buffer_from_host.buffer_header.cmd;
++
+ } else if (msg->u.buffer_from_host.buffer_header.length == 0) {
+ /* empty buffer */
+ if (msg->u.buffer_from_host.buffer_header.flags &
+@@ -1538,6 +1562,9 @@ int vchiq_mmal_port_parameter_set(struct
+
+ mutex_unlock(&instance->vchiq_mutex);
+
++ if (parameter == MMAL_PARAMETER_ZERO_COPY && !ret)
++ port->zero_copy = !!(*(bool *)value);
++
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_set);
+@@ -1706,6 +1733,31 @@ int vchiq_mmal_submit_buffer(struct vchi
+ unsigned long flags = 0;
+ int ret;
+
++ /*
++ * We really want to do this in mmal_vchi_buffer_init but can't as
++ * videobuf2 won't let us have the dmabuf there.
++ */
++ if (port->zero_copy && buffer->dma_buf && !buffer->vcsm_handle) {
++ pr_debug("%s: import dmabuf %p\n", __func__, buffer->dma_buf);
++ ret = vc_sm_cma_import_dmabuf(buffer->dma_buf,
++ &buffer->vcsm_handle);
++ if (ret) {
++ pr_err("%s: vc_sm_import_dmabuf_fd failed, ret %d\n",
++ __func__, ret);
++ return ret;
++ }
++
++ buffer->vc_handle = vc_sm_cma_int_handle(buffer->vcsm_handle);
++ if (!buffer->vc_handle) {
++ pr_err("%s: vc_sm_int_handle failed %d\n",
++ __func__, ret);
++ vc_sm_cma_free(buffer->vcsm_handle);
++ return ret;
++ }
++ pr_debug("%s: import dmabuf %p - got vc handle %08X\n",
++ __func__, buffer->dma_buf, buffer->vc_handle);
++ }
++
+ ret = buffer_from_host(instance, port, buffer);
+ if (ret == -EINVAL) {
+ /* Port is disabled. Queue for when it is enabled. */
+@@ -1739,6 +1791,16 @@ int mmal_vchi_buffer_cleanup(struct mmal
+ release_msg_context(msg_context);
+ buf->msg_context = NULL;
+
++ if (buf->vcsm_handle) {
++ int ret;
++
++ pr_debug("%s: vc_sm_cma_free on handle %08X\n", __func__,
++ buf->vcsm_handle);
++ ret = vc_sm_cma_free(buf->vcsm_handle);
++ if (ret)
++ pr_err("%s: vcsm_free failed, ret %d\n", __func__, ret);
++ buf->vcsm_handle = 0;
++ }
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup);
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
+@@ -49,6 +49,7 @@ typedef void (*vchiq_mmal_buffer_cb)(
+
+ struct vchiq_mmal_port {
+ u32 enabled:1;
++ u32 zero_copy:1;
+ u32 handle;
+ u32 type; /* port type, cached to use on port info set */
+ u32 index; /* port index, cached to use on port info set */
--- /dev/null
+From 0b2a62596d0e6efe17bb87a3a5ebd91cee60c64b Mon Sep 17 00:00:00 2001
+Date: Mon, 29 Oct 2018 17:57:45 +0000
+Subject: [PATCH] media: videobuf2: Allow exporting of a struct dmabuf
+
+videobuf2 only allowed exporting a dmabuf as a file descriptor,
+but there are instances where having the struct dma_buf is
+useful within the kernel.
+
+Split the current implementation into two, one step which
+exports a struct dma_buf, and the second which converts that
+into an fd.
+
+---
+ .../media/common/videobuf2/videobuf2-core.c | 21 ++++++++++++++++---
+ include/media/videobuf2-core.h | 15 +++++++++++++
+ 2 files changed, 33 insertions(+), 3 deletions(-)
+
+--- a/drivers/media/common/videobuf2/videobuf2-core.c
++++ b/drivers/media/common/videobuf2/videobuf2-core.c
+@@ -1851,12 +1851,12 @@ static int __find_plane_by_offset(struct
+ return -EINVAL;
+ }
+
+-int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
+- unsigned int index, unsigned int plane, unsigned int flags)
++int vb2_core_expbuf_dmabuf(struct vb2_queue *q, unsigned int type,
++ unsigned int index, unsigned int plane,
++ unsigned int flags, struct dma_buf **dmabuf)
+ {
+ struct vb2_buffer *vb = NULL;
+ struct vb2_plane *vb_plane;
+- int ret;
+ struct dma_buf *dbuf;
+
+ if (q->memory != VB2_MEMORY_MMAP) {
+@@ -1906,6 +1906,21 @@ int vb2_core_expbuf(struct vb2_queue *q,
+ return -EINVAL;
+ }
+
++ *dmabuf = dbuf;
++ return 0;
++}
++EXPORT_SYMBOL_GPL(vb2_core_expbuf_dmabuf);
++
++int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
++ unsigned int index, unsigned int plane, unsigned int flags)
++{
++ struct dma_buf *dbuf;
++ int ret;
++
++ ret = vb2_core_expbuf_dmabuf(q, type, index, plane, flags, &dbuf);
++ if (ret)
++ return ret;
++
+ ret = dma_buf_fd(dbuf, flags & ~O_ACCMODE);
+ if (ret < 0) {
+ dprintk(3, "buffer %d, plane %d failed to export (%d)\n",
+--- a/include/media/videobuf2-core.h
++++ b/include/media/videobuf2-core.h
+@@ -825,6 +825,21 @@ int vb2_core_streamon(struct vb2_queue *
+ int vb2_core_streamoff(struct vb2_queue *q, unsigned int type);
+
+ /**
++ * vb2_core_expbuf_dmabuf() - Export a buffer as a dma_buf structure
++ * @q: videobuf2 queue
++ * @type: buffer type
++ * @index: id number of the buffer
++ * @plane: index of the plane to be exported, 0 for single plane queues
++ * @flags: flags for newly created file, currently only O_CLOEXEC is
++ * supported, refer to manual of open syscall for more details
++ * @dmabuf: Returns the dmabuf pointer
++ *
++ */
++int vb2_core_expbuf_dmabuf(struct vb2_queue *q, unsigned int type,
++ unsigned int index, unsigned int plane,
++ unsigned int flags, struct dma_buf **dmabuf);
++
++/**
+ * vb2_core_expbuf() - Export a buffer as a file descriptor.
+ * @q: pointer to &struct vb2_queue with videobuf2 queue.
+ * @fd: pointer to the file descriptor associated with DMABUF
+++ /dev/null
-From 9eb40722f3ef0d338ed97667a7391f3d74812332 Mon Sep 17 00:00:00 2001
-Date: Tue, 30 Oct 2018 11:42:48 +0000
-Subject: [PATCH] staging: vc-sm-cma: Fixup driver for older VCHI APIs
-
-Original patch was based off staging which included some cleanups
-of the VCHI APIs. Those aren't present here, so switch back to
-the older API.
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 2 +-
- drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 5 +++++
- 2 files changed, 6 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -632,7 +632,7 @@ static void vc_sm_connected_init(void)
- goto err_free_mem;
- }
-
-- ret = vchi_connect(vchi_instance);
-+ ret = vchi_connect(NULL, 0, vchi_instance);
- if (ret) {
- pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
- __func__, ret);
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
-@@ -325,8 +325,13 @@ struct sm_instance *vc_sm_cma_vchi_init(
- SERVICE_CREATION_T params = {
- .version = VCHI_VERSION_EX(VC_SM_VER, VC_SM_MIN_VER),
- .service_id = VC_SM_SERVER_NAME,
-+ .rx_fifo_size = 0,
-+ .tx_fifo_size = 0,
- .callback = vc_sm_cma_vchi_callback,
- .callback_param = instance,
-+ .want_unaligned_bulk_rx = 0,
-+ .want_unaligned_bulk_tx = 0,
-+ .want_crc = 0
- };
-
- status = vchi_service_open(vchi_instance,
--- /dev/null
+From 2758fab4321519446fe5444769b6257dd18e794b Mon Sep 17 00:00:00 2001
+Date: Tue, 25 Sep 2018 14:53:49 +0100
+Subject: [PATCH] staging: vc04_services: Add a V4L2 M2M codec driver
+
+This adds a V4L2 memory to memory device that wraps the MMAL
+video decode and video_encode components for H264 and MJPEG encode
+and decode, MPEG4, H263, and VP8 decode (and MPEG2 decode
+if the appropriate licence has been purchased).
+
+---
+ drivers/staging/vc04_services/Kconfig | 1 +
+ drivers/staging/vc04_services/Makefile | 9 +-
+ .../vc04_services/bcm2835-codec/Kconfig | 11 +
+ .../vc04_services/bcm2835-codec/Makefile | 8 +
+ .../staging/vc04_services/bcm2835-codec/TODO | 24 +
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 2359 +++++++++++++++++
+ 6 files changed, 2408 insertions(+), 4 deletions(-)
+ create mode 100644 drivers/staging/vc04_services/bcm2835-codec/Kconfig
+ create mode 100644 drivers/staging/vc04_services/bcm2835-codec/Makefile
+ create mode 100644 drivers/staging/vc04_services/bcm2835-codec/TODO
+ create mode 100644 drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+
+--- a/drivers/staging/vc04_services/Kconfig
++++ b/drivers/staging/vc04_services/Kconfig
+@@ -23,6 +23,7 @@ source "drivers/staging/vc04_services/bc
+ source "drivers/staging/vc04_services/bcm2835-camera/Kconfig"
+ source "drivers/staging/vc04_services/vchiq-mmal/Kconfig"
+ source "drivers/staging/vc04_services/vc-sm-cma/Kconfig"
++source "drivers/staging/vc04_services/bcm2835-codec/Kconfig"
+
+ endif
+
+--- a/drivers/staging/vc04_services/Makefile
++++ b/drivers/staging/vc04_services/Makefile
+@@ -10,10 +10,11 @@ vchiq-objs := \
+ interface/vchiq_arm/vchiq_util.o \
+ interface/vchiq_arm/vchiq_connected.o \
+
+-obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
+-obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
+-obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
+-obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/
++obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
++obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
++obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
++obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/
++obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec/
+
+ ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000
+
+--- /dev/null
++++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig
+@@ -0,0 +1,11 @@
++config VIDEO_CODEC_BCM2835
++ tristate "BCM2835 Video codec support"
++ depends on MEDIA_SUPPORT
++ depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST)
++ select BCM2835_VCHIQ_MMAL
++ select VIDEOBUF2_DMA_CONTIG
++ select V4L2_MEM2MEM_DEV
++ help
++ Say Y here to enable the V4L2 video codecs for
++ Broadcom BCM2835 SoC. This operates over the VCHIQ interface
++ to a service running on VideoCore.
+--- /dev/null
++++ b/drivers/staging/vc04_services/bcm2835-codec/Makefile
+@@ -0,0 +1,8 @@
++# SPDX-License-Identifier: GPL-2.0
++bcm2835-codec-objs := bcm2835-v4l2-codec.o
++
++obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec.o
++
++ccflags-y += \
++ -Idrivers/staging/vc04_services \
++ -D__VCCOREVER__=0x04000000
+--- /dev/null
++++ b/drivers/staging/vc04_services/bcm2835-codec/TODO
+@@ -0,0 +1,24 @@
++1) Convert to be a platform driver.
++
++Right now when the module probes, it tries to initialize VCHI and
++errors out if it wasn't ready yet. If bcm2835-v4l2 was built in, then
++VCHI generally isn't ready because it depends on both the firmware and
++mailbox drivers having already loaded.
++
++We should have VCHI create a platform device once it's initialized,
++and have this driver bind to it, so that we automatically load the
++v4l2 module after VCHI loads.
++
++2) Support SELECTION API to define crop region on the image for encode.
++
++Particularly for resolutions that aren't a multiple of the macroblock
++size, the codec will report a resolution that is a multiple of the macroblock
++size (it has to have the memory to decode into), and then a different crop
++region within that buffer.
++The most common example is 1080P, where the buffer will be 1920x1088 with a
++crop region of 1920x1080.
++
++3) Refactor so that the component creation is only on queue_setup, not open.
++
++Fixes v4l2-compliance failure on trying to open 100 instances of the
++device.
+\ No newline at end of file
+--- /dev/null
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -0,0 +1,2359 @@
++// SPDX-License-Identifier: GPL-2.0
++
++/*
++ * A v4l2-mem2mem device that wraps the video codec MMAL component.
++ *
++ * Copyright 2018 Raspberry Pi (Trading) Ltd.
++ *
++ * Loosely based on the vim2m virtual driver by Pawel Osciak
++ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
++ *
++ * Whilst this driver uses the v4l2_mem2mem framework, it does not need the
++ * scheduling aspects, so will always take the buffers, pass them to the VPU,
++ * and then signal the job as complete.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the
++ * License, or (at your option) any later version
++ */
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/fs.h>
++#include <linux/timer.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++#include <linux/syscalls.h>
++
++#include <media/v4l2-mem2mem.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-ioctl.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-event.h>
++#include <media/videobuf2-dma-contig.h>
++
++#include "vchiq-mmal/mmal-encodings.h"
++#include "vchiq-mmal/mmal-msg.h"
++#include "vchiq-mmal/mmal-parameters.h"
++#include "vchiq-mmal/mmal-vchiq.h"
++
++/*
++ * Default /dev/videoN node numbers for decode and encode.
++ * Deliberately avoid the very low numbers as these are often taken by webcams
++ * etc, and simple apps tend to only go for /dev/video0.
++ */
++static int decode_video_nr = 10;
++module_param(decode_video_nr, int, 0644);
++MODULE_PARM_DESC(decode_video_nr, "decoder video device number");
++
++static int encode_video_nr = 11;
++module_param(encode_video_nr, int, 0644);
++MODULE_PARM_DESC(encode_video_nr, "encoder video device number");
++
++static unsigned int debug;
++module_param(debug, uint, 0644);
++MODULE_PARM_DESC(debug, "activates debug info (0-3)");
++
++#define MIN_W 32
++#define MIN_H 32
++#define MAX_W 1920
++#define MAX_H 1088
++#define BPL_ALIGN 32
++#define DEFAULT_WIDTH 640
++#define DEFAULT_HEIGHT 480
++/*
++ * The unanswered question - what is the maximum size of a compressed frame?
++ * V4L2 mandates that the encoded frame must fit in a single buffer. Sizing
++ * that buffer is a compromise between wasting memory and risking not fitting.
++ * The 1080P version of Big Buck Bunny has some frames that exceed 512kB.
++ * Adopt a moderately arbitrary split at 720P for switching between 512 and
++ * 768kB buffers.
++ */
++#define DEF_COMP_BUF_SIZE_GREATER_720P (768 << 10)
++#define DEF_COMP_BUF_SIZE_720P_OR_LESS (512 << 10)
++
++/* Flags that indicate a format can be used for capture/output */
++#define MEM2MEM_CAPTURE BIT(0)
++#define MEM2MEM_OUTPUT BIT(1)
++
++#define MEM2MEM_NAME "bcm2835-codec"
++
++struct bcm2835_codec_fmt {
++ u32 fourcc;
++ int depth;
++ int bytesperline_align;
++ u32 flags;
++ u32 mmal_fmt;
++ bool decode_only;
++ bool encode_only;
++ int size_multiplier_x2;
++};
++
++/* Supported raw pixel formats. Those supported for both encode and decode
++ * must come first, with those only supported for decode coming after (there
++ * are no formats supported for encode only).
++ */
++static struct bcm2835_codec_fmt raw_formats[] = {
++ {
++ .fourcc = V4L2_PIX_FMT_YUV420,
++ .depth = 8,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_I420,
++ .size_multiplier_x2 = 3,
++ }, {
++ .fourcc = V4L2_PIX_FMT_YVU420,
++ .depth = 8,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_YV12,
++ .size_multiplier_x2 = 3,
++ }, {
++ .fourcc = V4L2_PIX_FMT_NV12,
++ .depth = 8,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_NV12,
++ .size_multiplier_x2 = 3,
++ }, {
++ .fourcc = V4L2_PIX_FMT_NV21,
++ .depth = 8,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_NV21,
++ .size_multiplier_x2 = 3,
++ }, {
++ .fourcc = V4L2_PIX_FMT_RGB565,
++ .depth = 16,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_RGB16,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_YUYV,
++ .depth = 16,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_YUYV,
++ .encode_only = true,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_UYVY,
++ .depth = 16,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_UYVY,
++ .encode_only = true,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_YVYU,
++ .depth = 16,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_YVYU,
++ .encode_only = true,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_VYUY,
++ .depth = 16,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_VYUY,
++ .encode_only = true,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_RGB24,
++ .depth = 24,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_RGB24,
++ .encode_only = true,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_BGR24,
++ .depth = 24,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BGR24,
++ .encode_only = true,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_BGR32,
++ .depth = 32,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BGRA,
++ .encode_only = true,
++ .size_multiplier_x2 = 2,
++ },
++};
++
++/* Supported encoded formats. Those supported for both encode and decode
++ * must come first, with those only supported for decode coming after (there
++ * are no formats supported for encode only).
++ */
++static struct bcm2835_codec_fmt encoded_formats[] = {
++ {
++ .fourcc = V4L2_PIX_FMT_H264,
++ .depth = 0,
++ .flags = V4L2_FMT_FLAG_COMPRESSED,
++ .mmal_fmt = MMAL_ENCODING_H264,
++ }, {
++ .fourcc = V4L2_PIX_FMT_MJPEG,
++ .depth = 0,
++ .flags = V4L2_FMT_FLAG_COMPRESSED,
++ .mmal_fmt = MMAL_ENCODING_MJPEG,
++ }, {
++ .fourcc = V4L2_PIX_FMT_MPEG4,
++ .depth = 0,
++ .flags = V4L2_FMT_FLAG_COMPRESSED,
++ .mmal_fmt = MMAL_ENCODING_MP4V,
++ .decode_only = true,
++ }, {
++ .fourcc = V4L2_PIX_FMT_H263,
++ .depth = 0,
++ .flags = V4L2_FMT_FLAG_COMPRESSED,
++ .mmal_fmt = MMAL_ENCODING_H263,
++ .decode_only = true,
++ }, {
++ .fourcc = V4L2_PIX_FMT_MPEG2,
++ .depth = 0,
++ .flags = V4L2_FMT_FLAG_COMPRESSED,
++ .mmal_fmt = MMAL_ENCODING_MP2V,
++ .decode_only = true,
++ }, {
++ .fourcc = V4L2_PIX_FMT_VP8,
++ .depth = 0,
++ .flags = V4L2_FMT_FLAG_COMPRESSED,
++ .mmal_fmt = MMAL_ENCODING_VP8,
++ .decode_only = true,
++ },
++ /*
++ * This list couold include VP6 and Theorafor decode, but V4L2 doesn't
++ * support them.
++ */
++};
++
++struct bcm2835_codec_fmt_list {
++ struct bcm2835_codec_fmt *list;
++ unsigned int num_entries;
++};
++
++#define RAW_LIST 0
++#define ENCODED_LIST 1
++
++struct bcm2835_codec_fmt_list formats[] = {
++ {
++ .list = raw_formats,
++ .num_entries = ARRAY_SIZE(raw_formats),
++ }, {
++ .list = encoded_formats,
++ .num_entries = ARRAY_SIZE(encoded_formats),
++ },
++};
++
++struct m2m_mmal_buffer {
++ struct v4l2_m2m_buffer m2m;
++ struct mmal_buffer mmal;
++};
++
++/* Per-queue, driver-specific private data */
++struct bcm2835_codec_q_data {
++ /*
++ * These parameters should be treated as gospel, with everything else
++ * being determined from them.
++ */
++ /* Buffer width/height */
++ unsigned int bytesperline;
++ unsigned int height;
++ /* Crop size used for selection handling */
++ unsigned int crop_width;
++ unsigned int crop_height;
++ bool selection_set;
++
++ unsigned int sizeimage;
++ unsigned int sequence;
++ struct bcm2835_codec_fmt *fmt;
++
++ /* One extra buffer header so we can send an EOS. */
++ struct m2m_mmal_buffer eos_buffer;
++ bool eos_buffer_in_use; /* debug only */
++};
++
++enum {
++ V4L2_M2M_SRC = 0,
++ V4L2_M2M_DST = 1,
++};
++
++static inline struct bcm2835_codec_fmt_list *get_format_list(bool decode,
++ bool capture)
++{
++ return decode ^ capture ? &formats[ENCODED_LIST] : &formats[RAW_LIST];
++}
++
++static struct bcm2835_codec_fmt *get_default_format(bool decode, bool capture)
++{
++ return &get_format_list(decode, capture)->list[0];
++}
++
++static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, bool decode,
++ bool capture)
++{
++ struct bcm2835_codec_fmt *fmt;
++ unsigned int k;
++ struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
++
++ for (k = 0; k < fmts->num_entries; k++) {
++ fmt = &fmts->list[k];
++ if (fmt->fourcc == f->fmt.pix.pixelformat)
++ break;
++ }
++
++ /*
++ * Some compressed formats are only supported for decoding, not
++ * encoding.
++ */
++ if (!decode && fmts->list[k].decode_only)
++ return NULL;
++
++ /* Some pixel formats are only supported for encoding, not decoding. */
++ if (decode && fmts->list[k].encode_only)
++ return NULL;
++
++ if (k == fmts->num_entries)
++ return NULL;
++
++ return &fmts->list[k];
++}
++
++struct bcm2835_codec_dev {
++ struct platform_device *pdev;
++
++ /* v4l2 devices */
++ struct v4l2_device v4l2_dev;
++ struct video_device vfd;
++ /* mutex for the v4l2 device */
++ struct mutex dev_mutex;
++ atomic_t num_inst;
++
++ /* allocated mmal instance and components */
++ bool decode; /* Is this instance a decoder? */
++ struct vchiq_mmal_instance *instance;
++
++ struct v4l2_m2m_dev *m2m_dev;
++};
++
++struct bcm2835_codec_ctx {
++ struct v4l2_fh fh;
++ struct bcm2835_codec_dev *dev;
++
++ struct v4l2_ctrl_handler hdl;
++
++ struct vchiq_mmal_component *component;
++ bool component_enabled;
++
++ enum v4l2_colorspace colorspace;
++ enum v4l2_ycbcr_encoding ycbcr_enc;
++ enum v4l2_xfer_func xfer_func;
++ enum v4l2_quantization quant;
++
++ /* Source and destination queue data */
++ struct bcm2835_codec_q_data q_data[2];
++ s32 bitrate;
++
++ bool aborting;
++ int num_ip_buffers;
++ int num_op_buffers;
++ struct completion frame_cmplt;
++};
++
++struct bcm2835_codec_driver {
++ struct bcm2835_codec_dev *encode;
++ struct bcm2835_codec_dev *decode;
++};
++
++static inline struct bcm2835_codec_ctx *file2ctx(struct file *file)
++{
++ return container_of(file->private_data, struct bcm2835_codec_ctx, fh);
++}
++
++static struct bcm2835_codec_q_data *get_q_data(struct bcm2835_codec_ctx *ctx,
++ enum v4l2_buf_type type)
++{
++ switch (type) {
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
++ return &ctx->q_data[V4L2_M2M_SRC];
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ return &ctx->q_data[V4L2_M2M_DST];
++ default:
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
++ __func__, type);
++ break;
++ }
++ return NULL;
++}
++
++static struct vchiq_mmal_port *get_port_data(struct bcm2835_codec_ctx *ctx,
++ enum v4l2_buf_type type)
++{
++ if (!ctx->component)
++ return NULL;
++
++ switch (type) {
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
++ return &ctx->component->input[0];
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ return &ctx->component->output[0];
++ default:
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
++ __func__, type);
++ break;
++ }
++ return NULL;
++}
++
++/*
++ * mem2mem callbacks
++ */
++
++/**
++ * job_ready() - check whether an instance is ready to be scheduled to run
++ */
++static int job_ready(void *priv)
++{
++ struct bcm2835_codec_ctx *ctx = priv;
++
++ if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
++ !v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx))
++ return 0;
++
++ return 1;
++}
++
++static void job_abort(void *priv)
++{
++ struct bcm2835_codec_ctx *ctx = priv;
++
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s\n", __func__);
++ /* Will cancel the transaction in the next interrupt handler */
++ ctx->aborting = 1;
++}
++
++static inline unsigned int get_sizeimage(int bpl, int height,
++ struct bcm2835_codec_fmt *fmt)
++{
++ return (bpl * height * fmt->size_multiplier_x2) >> 1;
++}
++
++static inline unsigned int get_bytesperline(int width,
++ struct bcm2835_codec_fmt *fmt)
++{
++ return ALIGN((width * fmt->depth) >> 3, fmt->bytesperline_align);
++}
++
++static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx,
++ bool decode,
++ struct bcm2835_codec_q_data *q_data,
++ struct vchiq_mmal_port *port)
++{
++ port->format.encoding = q_data->fmt->mmal_fmt;
++
++ if (!(q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) {
++ /* Raw image format - set width/height */
++ port->es.video.width = q_data->bytesperline /
++ (q_data->fmt->depth >> 3);
++ port->es.video.height = q_data->height;
++ port->es.video.crop.width = q_data->crop_width;
++ port->es.video.crop.height = q_data->crop_height;
++ port->es.video.frame_rate.num = 0;
++ port->es.video.frame_rate.den = 1;
++ } else {
++ /* Compressed format - leave resolution as 0 for decode */
++ if (decode) {
++ port->es.video.width = 0;
++ port->es.video.height = 0;
++ port->es.video.crop.width = 0;
++ port->es.video.crop.height = 0;
++ } else {
++ port->es.video.width = q_data->crop_width;
++ port->es.video.height = q_data->height;
++ port->es.video.crop.width = q_data->crop_width;
++ port->es.video.crop.height = q_data->crop_height;
++ port->format.bitrate = ctx->bitrate;
++ }
++ port->es.video.frame_rate.num = 0;
++ port->es.video.frame_rate.den = 1;
++ }
++ port->es.video.crop.x = 0;
++ port->es.video.crop.y = 0;
++
++ port->current_buffer.size = q_data->sizeimage;
++};
++
++static void ip_buffer_cb(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port, int status,
++ struct mmal_buffer *mmal_buf)
++{
++ struct bcm2835_codec_ctx *ctx = port->cb_ctx/*, *curr_ctx*/;
++ struct m2m_mmal_buffer *buf =
++ container_of(mmal_buf, struct m2m_mmal_buffer, mmal);
++
++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: port %p buf %p length %lu, flags %x\n",
++ __func__, port, mmal_buf, mmal_buf->length,
++ mmal_buf->mmal_flags);
++
++ if (buf == &ctx->q_data[V4L2_M2M_SRC].eos_buffer) {
++ /* Do we need to add lcoking to prevent multiple submission of
++ * the EOS, and therefore handle mutliple return here?
++ */
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: eos buffer returned.\n",
++ __func__);
++ ctx->q_data[V4L2_M2M_SRC].eos_buffer_in_use = false;
++ return;
++ }
++
++ if (status) {
++ /* error in transfer */
++ if (buf)
++ /* there was a buffer with the error so return it */
++ vb2_buffer_done(&buf->m2m.vb.vb2_buf,
++ VB2_BUF_STATE_ERROR);
++ return;
++ }
++ if (mmal_buf->cmd) {
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Not expecting cmd msgs on ip callback - %08x\n",
++ __func__, mmal_buf->cmd);
++ /*
++ * CHECKME: Should we return here. The buffer shouldn't have a
++ * message context or vb2 buf associated.
++ */
++ }
++
++ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: no error. Return buffer %p\n",
++ __func__, &buf->m2m.vb.vb2_buf);
++ vb2_buffer_done(&buf->m2m.vb.vb2_buf, VB2_BUF_STATE_DONE);
++
++ ctx->num_ip_buffers++;
++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: done %d input buffers\n",
++ __func__, ctx->num_ip_buffers);
++
++ if (!port->enabled)
++ complete(&ctx->frame_cmplt);
++}
++
++static void queue_res_chg_event(struct bcm2835_codec_ctx *ctx)
++{
++ static const struct v4l2_event ev_src_ch = {
++ .type = V4L2_EVENT_SOURCE_CHANGE,
++ .u.src_change.changes =
++ V4L2_EVENT_SRC_CH_RESOLUTION,
++ };
++
++ v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
++}
++
++static void send_eos_event(struct bcm2835_codec_ctx *ctx)
++{
++ static const struct v4l2_event ev = {
++ .type = V4L2_EVENT_EOS,
++ };
++
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Sending EOS event\n");
++
++ v4l2_event_queue_fh(&ctx->fh, &ev);
++}
++
++static void color_mmal2v4l(struct bcm2835_codec_ctx *ctx, u32 mmal_color_space)
++{
++ switch (mmal_color_space) {
++ case MMAL_COLOR_SPACE_ITUR_BT601:
++ ctx->colorspace = V4L2_COLORSPACE_REC709;
++ ctx->xfer_func = V4L2_XFER_FUNC_709;
++ ctx->ycbcr_enc = V4L2_YCBCR_ENC_601;
++ ctx->quant = V4L2_QUANTIZATION_LIM_RANGE;
++ break;
++
++ case MMAL_COLOR_SPACE_ITUR_BT709:
++ ctx->colorspace = V4L2_COLORSPACE_REC709;
++ ctx->xfer_func = V4L2_XFER_FUNC_709;
++ ctx->ycbcr_enc = V4L2_YCBCR_ENC_709;
++ ctx->quant = V4L2_QUANTIZATION_LIM_RANGE;
++ break;
++ }
++}
++
++static void handle_fmt_changed(struct bcm2835_codec_ctx *ctx,
++ struct mmal_buffer *mmal_buf)
++{
++ struct bcm2835_codec_q_data *q_data;
++ struct mmal_msg_event_format_changed *format =
++ (struct mmal_msg_event_format_changed *)mmal_buf->buffer;
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed: buff size min %u, rec %u, buff num min %u, rec %u\n",
++ __func__,
++ format->buffer_size_min,
++ format->buffer_size_recommended,
++ format->buffer_num_min,
++ format->buffer_num_recommended
++ );
++ if (format->format.type != MMAL_ES_TYPE_VIDEO) {
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed but not video %u\n",
++ __func__, format->format.type);
++ return;
++ }
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed to %ux%u, crop %ux%u, colourspace %08X\n",
++ __func__, format->es.video.width, format->es.video.height,
++ format->es.video.crop.width, format->es.video.crop.height,
++ format->es.video.color_space);
++
++ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
++ q_data->crop_width = format->es.video.crop.width;
++ q_data->crop_height = format->es.video.crop.height;
++ q_data->bytesperline = format->es.video.crop.width;
++ q_data->height = format->es.video.height;
++ q_data->sizeimage = format->buffer_size_min;
++ if (format->es.video.color_space)
++ color_mmal2v4l(ctx, format->es.video.color_space);
++
++ queue_res_chg_event(ctx);
++}
++
++static void op_buffer_cb(struct vchiq_mmal_instance *instance,
++ struct vchiq_mmal_port *port, int status,
++ struct mmal_buffer *mmal_buf)
++{
++ struct bcm2835_codec_ctx *ctx = port->cb_ctx;
++ struct m2m_mmal_buffer *buf;
++ struct vb2_v4l2_buffer *vb2;
++
++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev,
++ "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
++ __func__, status, mmal_buf, mmal_buf->length,
++ mmal_buf->mmal_flags, mmal_buf->pts);
++
++ if (status) {
++ /* error in transfer */
++ if (vb2) {
++ /* there was a buffer with the error so return it */
++ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_ERROR);
++ }
++ return;
++ }
++
++ if (mmal_buf->cmd) {
++ switch (mmal_buf->cmd) {
++ case MMAL_EVENT_FORMAT_CHANGED:
++ {
++ handle_fmt_changed(ctx, mmal_buf);
++ break;
++ }
++ default:
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Unexpected event on output callback - %08x\n",
++ __func__, mmal_buf->cmd);
++ break;
++ }
++ return;
++ }
++
++ buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal);
++ vb2 = &buf->m2m.vb;
++
++ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: length %lu, flags %x, idx %u\n",
++ __func__, mmal_buf->length, mmal_buf->mmal_flags,
++ vb2->vb2_buf.index);
++
++ if (mmal_buf->length == 0) {
++ /* stream ended, or buffer being returned during disable. */
++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: Empty buffer - flags %04x",
++ __func__, mmal_buf->mmal_flags);
++ if (!mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS) {
++ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_ERROR);
++ if (!port->enabled)
++ complete(&ctx->frame_cmplt);
++ return;
++ }
++ }
++ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS) {
++ /* EOS packet from the VPU */
++ send_eos_event(ctx);
++ vb2->flags |= V4L2_BUF_FLAG_LAST;
++ }
++
++ vb2->vb2_buf.timestamp = mmal_buf->pts;
++
++ vb2_set_plane_payload(&vb2->vb2_buf, 0, mmal_buf->length);
++ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
++ vb2->flags |= V4L2_BUF_FLAG_KEYFRAME;
++
++ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_DONE);
++ ctx->num_op_buffers++;
++
++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: done %d output buffers\n",
++ __func__, ctx->num_op_buffers);
++
++ if (!port->enabled)
++ complete(&ctx->frame_cmplt);
++}
++
++/* vb2_to_mmal_buffer() - converts vb2 buffer header to MMAL
++ *
++ * Copies all the required fields from a VB2 buffer to the MMAL buffer header,
++ * ready for sending to the VPU.
++ */
++static void vb2_to_mmal_buffer(struct m2m_mmal_buffer *buf,
++ struct vb2_v4l2_buffer *vb2)
++{
++ buf->mmal.mmal_flags = 0;
++ if (vb2->flags & V4L2_BUF_FLAG_KEYFRAME)
++ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME;
++
++ /*
++ * Adding this means that the data must be framed correctly as one frame
++ * per buffer. The underlying decoder has no such requirement, but it
++ * will reduce latency as the bistream parser will be kicked immediately
++ * to parse the frame, rather than relying on its own heuristics for
++ * when to wake up.
++ */
++ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END;
++
++ buf->mmal.length = vb2->vb2_buf.planes[0].bytesused;
++ /*
++ * Minor ambiguity in the V4L2 spec as to whether passing in a 0 length
++ * buffer, or one with V4L2_BUF_FLAG_LAST set denotes end of stream.
++ * Handle either.
++ */
++ if (!buf->mmal.length || vb2->flags & V4L2_BUF_FLAG_LAST)
++ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_EOS;
++
++ buf->mmal.pts = vb2->vb2_buf.timestamp;
++ buf->mmal.dts = MMAL_TIME_UNKNOWN;
++}
++
++/* device_run() - prepares and starts the device
++ *
++ * This simulates all the immediate preparations required before starting
++ * a device. This will be called by the framework when it decides to schedule
++ * a particular instance.
++ */
++static void device_run(void *priv)
++{
++ struct bcm2835_codec_ctx *ctx = priv;
++ struct bcm2835_codec_dev *dev = ctx->dev;
++ struct vb2_v4l2_buffer *src_buf, *dst_buf;
++ struct m2m_mmal_buffer *src_m2m_buf, *dst_m2m_buf;
++ struct v4l2_m2m_buffer *m2m;
++ int ret;
++
++ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: off we go\n", __func__);
++
++ src_buf = v4l2_m2m_buf_remove(&ctx->fh.m2m_ctx->out_q_ctx);
++ if (src_buf) {
++ m2m = container_of(src_buf, struct v4l2_m2m_buffer, vb);
++ src_m2m_buf = container_of(m2m, struct m2m_mmal_buffer, m2m);
++ vb2_to_mmal_buffer(src_m2m_buf, src_buf);
++
++ ret = vchiq_mmal_submit_buffer(dev->instance,
++ &ctx->component->input[0],
++ &src_m2m_buf->mmal);
++ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: Submitted ip buffer len %lu, pts %llu, flags %04x\n",
++ __func__, src_m2m_buf->mmal.length,
++ src_m2m_buf->mmal.pts, src_m2m_buf->mmal.mmal_flags);
++ if (ret)
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed submitting ip buffer\n",
++ __func__);
++ }
++
++ dst_buf = v4l2_m2m_buf_remove(&ctx->fh.m2m_ctx->cap_q_ctx);
++ if (dst_buf) {
++ m2m = container_of(dst_buf, struct v4l2_m2m_buffer, vb);
++ dst_m2m_buf = container_of(m2m, struct m2m_mmal_buffer, m2m);
++ vb2_to_mmal_buffer(dst_m2m_buf, dst_buf);
++
++ ret = vchiq_mmal_submit_buffer(dev->instance,
++ &ctx->component->output[0],
++ &dst_m2m_buf->mmal);
++ if (ret)
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed submitting op buffer\n",
++ __func__);
++ }
++
++ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: Submitted src %p, dst %p\n",
++ __func__, src_m2m_buf, dst_m2m_buf);
++
++ /* Complete the job here. */
++ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
++}
++
++/*
++ * video ioctls
++ */
++static int vidioc_querycap(struct file *file, void *priv,
++ struct v4l2_capability *cap)
++{
++ strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
++ strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
++ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
++ MEM2MEM_NAME);
++ cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
++ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
++ return 0;
++}
++
++static int enum_fmt(struct v4l2_fmtdesc *f, bool decode, bool capture)
++{
++ struct bcm2835_codec_fmt *fmt;
++ struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
++
++ if (f->index < fmts->num_entries) {
++ /* Format found */
++ /* Check format isn't a decode only format when encoding */
++ if (!decode &&
++ fmts->list[f->index].decode_only)
++ return -EINVAL;
++ /* Check format isn't a decode only format when encoding */
++ if (decode &&
++ fmts->list[f->index].encode_only)
++ return -EINVAL;
++
++ fmt = &fmts->list[f->index];
++ f->pixelformat = fmt->fourcc;
++ f->flags = fmt->flags;
++ return 0;
++ }
++
++ /* Format not found */
++ return -EINVAL;
++}
++
++static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_fmtdesc *f)
++{
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++
++ return enum_fmt(f, ctx->dev->decode, true);
++}
++
++static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
++ struct v4l2_fmtdesc *f)
++{
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++
++ return enum_fmt(f, ctx->dev->decode, false);
++}
++
++static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f)
++{
++ struct vb2_queue *vq;
++ struct bcm2835_codec_q_data *q_data;
++
++ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
++ if (!vq)
++ return -EINVAL;
++
++ q_data = get_q_data(ctx, f->type);
++
++ f->fmt.pix.width = q_data->crop_width;
++ f->fmt.pix.height = q_data->height;
++ f->fmt.pix.field = V4L2_FIELD_NONE;
++ f->fmt.pix.pixelformat = q_data->fmt->fourcc;
++ f->fmt.pix.bytesperline = q_data->bytesperline;
++ f->fmt.pix.sizeimage = q_data->sizeimage;
++ f->fmt.pix.colorspace = ctx->colorspace;
++ f->fmt.pix.xfer_func = ctx->xfer_func;
++ f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
++ f->fmt.pix.quantization = ctx->quant;
++
++ return 0;
++}
++
++static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ return vidioc_g_fmt(file2ctx(file), f);
++}
++
++static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ return vidioc_g_fmt(file2ctx(file), f);
++}
++
++static int vidioc_try_fmt(struct v4l2_format *f, struct bcm2835_codec_fmt *fmt)
++{
++ /*
++ * The V4L2 specification requires the driver to correct the format
++ * struct if any of the dimensions is unsupported
++ */
++ if (f->fmt.pix.width > MAX_W)
++ f->fmt.pix.width = MAX_W;
++ if (f->fmt.pix.height > MAX_H)
++ f->fmt.pix.height = MAX_H;
++
++ if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
++ /* Only clip min w/h on capture. Treat 0x0 as unknown. */
++ if (f->fmt.pix.width < MIN_W)
++ f->fmt.pix.width = MIN_W;
++ if (f->fmt.pix.height < MIN_H)
++ f->fmt.pix.height = MIN_H;
++
++ /*
++ * Buffer must have a vertical alignment of 16 lines.
++ * The selection will reflect any cropping rectangle when only
++ * some of the pixels are active.
++ */
++ f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
++
++ f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
++ fmt);
++ f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
++ f->fmt.pix.height,
++ fmt);
++ } else {
++ u32 min_size = f->fmt.pix.width > 1280 ||
++ f->fmt.pix.height > 720 ?
++ DEF_COMP_BUF_SIZE_GREATER_720P :
++ DEF_COMP_BUF_SIZE_720P_OR_LESS;
++
++ f->fmt.pix.bytesperline = 0;
++ if (f->fmt.pix.sizeimage < min_size)
++ f->fmt.pix.sizeimage = min_size;
++ }
++
++ f->fmt.pix.field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct bcm2835_codec_fmt *fmt;
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++
++ fmt = find_format(f, ctx->dev->decode, true);
++ if (!fmt) {
++ f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
++ true)->fourcc;
++ fmt = find_format(f, ctx->dev->decode, true);
++ }
++
++ return vidioc_try_fmt(f, fmt);
++}
++
++static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ struct bcm2835_codec_fmt *fmt;
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++
++ fmt = find_format(f, ctx->dev->decode, false);
++ if (!fmt) {
++ f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
++ false)->fourcc;
++ fmt = find_format(f, ctx->dev->decode, false);
++ }
++
++ if (!f->fmt.pix.colorspace)
++ f->fmt.pix.colorspace = ctx->colorspace;
++
++ return vidioc_try_fmt(f, fmt);
++}
++
++static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
++ unsigned int requested_height)
++{
++ struct bcm2835_codec_q_data *q_data;
++ struct vb2_queue *vq;
++ struct vchiq_mmal_port *port;
++ bool update_capture_port = false;
++ int ret;
++
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
++ f->type, f->fmt.pix.width, f->fmt.pix.height,
++ f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
++
++ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
++ if (!vq)
++ return -EINVAL;
++
++ q_data = get_q_data(ctx, f->type);
++ if (!q_data)
++ return -EINVAL;
++
++ if (vb2_is_busy(vq)) {
++ v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
++ return -EBUSY;
++ }
++
++ q_data->fmt = find_format(f, ctx->dev->decode,
++ f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
++ q_data->crop_width = f->fmt.pix.width;
++ q_data->height = f->fmt.pix.height;
++ if (!q_data->selection_set)
++ q_data->crop_height = requested_height;
++
++ /*
++ * Copying the behaviour of vicodec which retains a single set of
++ * colorspace parameters for both input and output.
++ */
++ ctx->colorspace = f->fmt.pix.colorspace;
++ ctx->xfer_func = f->fmt.pix.xfer_func;
++ ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
++ ctx->quant = f->fmt.pix.quantization;
++
++ /* All parameters should have been set correctly by try_fmt */
++ q_data->bytesperline = f->fmt.pix.bytesperline;
++ q_data->sizeimage = f->fmt.pix.sizeimage;
++
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n",
++ q_data->bytesperline, q_data->sizeimage);
++
++ if (ctx->dev->decode && q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
++ f->fmt.pix.width && f->fmt.pix.height) {
++ /*
++ * On the decoder, if provided with a resolution on the input
++ * side, then replicate that to the output side.
++ * GStreamer appears not to support V4L2_EVENT_SOURCE_CHANGE,
++ * nor set up a resolution on the output side, therefore
++ * we can't decode anything at a resolution other than the
++ * default one.
++ */
++ struct bcm2835_codec_q_data *q_data_dst =
++ &ctx->q_data[V4L2_M2M_DST];
++
++ q_data_dst->crop_width = q_data->crop_width;
++ q_data_dst->crop_height = q_data->crop_height;
++ q_data_dst->height = ALIGN(q_data->crop_height, 16);
++
++ q_data_dst->bytesperline =
++ get_bytesperline(f->fmt.pix.width, q_data_dst->fmt);
++ q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline,
++ q_data_dst->height,
++ q_data_dst->fmt);
++ update_capture_port = true;
++ }
++
++ /* If we have a component then setup the port as well */
++ port = get_port_data(ctx, vq->type);
++ if (!port)
++ return 0;
++
++ setup_mmal_port_format(ctx, ctx->dev->decode, q_data, port);
++ ret = vchiq_mmal_port_set_format(ctx->dev->instance, port);
++ if (ret) {
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n",
++ __func__, ret);
++ ret = -EINVAL;
++ }
++
++ if (q_data->sizeimage < port->minimum_buffer.size) {
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Current buffer size of %u < min buf size %u - driver mismatch to MMAL\n",
++ __func__, q_data->sizeimage,
++ port->minimum_buffer.size);
++ }
++
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Set format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
++ f->type, q_data->crop_width, q_data->height,
++ q_data->fmt->fourcc, q_data->sizeimage);
++
++ if (update_capture_port) {
++ struct vchiq_mmal_port *port_dst = &ctx->component->output[0];
++ struct bcm2835_codec_q_data *q_data_dst =
++ &ctx->q_data[V4L2_M2M_DST];
++
++ setup_mmal_port_format(ctx, ctx->dev->decode, q_data_dst,
++ port_dst);
++ ret = vchiq_mmal_port_set_format(ctx->dev->instance, port_dst);
++ if (ret) {
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on output port, ret %d\n",
++ __func__, ret);
++ ret = -EINVAL;
++ }
++ }
++ return ret;
++}
++
++static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ unsigned int height = f->fmt.pix.height;
++ int ret;
++
++ ret = vidioc_try_fmt_vid_cap(file, priv, f);
++ if (ret)
++ return ret;
++
++ return vidioc_s_fmt(file2ctx(file), f, height);
++}
++
++static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
++ struct v4l2_format *f)
++{
++ unsigned int height = f->fmt.pix.height;
++ int ret;
++
++ ret = vidioc_try_fmt_vid_out(file, priv, f);
++ if (ret)
++ return ret;
++
++ ret = vidioc_s_fmt(file2ctx(file), f, height);
++ return ret;
++}
++
++static int vidioc_g_selection(struct file *file, void *priv,
++ struct v4l2_selection *s)
++{
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++ struct bcm2835_codec_q_data *q_data;
++ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
++ true : false;
++
++ if (capture_queue ^ ctx->dev->decode)
++ /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
++ return -EINVAL;
++
++ q_data = get_q_data(ctx, s->type);
++ if (!q_data)
++ return -EINVAL;
++
++ if (ctx->dev->decode) {
++ switch (s->target) {
++ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
++ case V4L2_SEL_TGT_COMPOSE:
++ s->r.left = 0;
++ s->r.top = 0;
++ s->r.width = q_data->crop_width;
++ s->r.height = q_data->crop_height;
++ break;
++ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
++ s->r.left = 0;
++ s->r.top = 0;
++ s->r.width = q_data->crop_width;
++ s->r.height = q_data->crop_height;
++ break;
++ default:
++ return -EINVAL;
++ }
++ } else {
++ switch (s->target) {
++ case V4L2_SEL_TGT_CROP_DEFAULT:
++ case V4L2_SEL_TGT_CROP_BOUNDS:
++ s->r.top = 0;
++ s->r.left = 0;
++ s->r.width = q_data->bytesperline;
++ s->r.height = q_data->height;
++ break;
++ case V4L2_SEL_TGT_CROP:
++ s->r.top = 0;
++ s->r.left = 0;
++ s->r.width = q_data->crop_width;
++ s->r.height = q_data->crop_height;
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++
++ return 0;
++}
++
++static int vidioc_s_selection(struct file *file, void *priv,
++ struct v4l2_selection *s)
++{
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++ struct bcm2835_codec_q_data *q_data = NULL;
++ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
++ true : false;
++
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
++ __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top,
++ s->r.width, s->r.height);
++
++ if (capture_queue ^ ctx->dev->decode)
++ /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
++ return -EINVAL;
++
++ q_data = get_q_data(ctx, s->type);
++ if (!q_data)
++ return -EINVAL;
++
++ if (ctx->dev->decode) {
++ switch (s->target) {
++ case V4L2_SEL_TGT_COMPOSE:
++ /* Accept cropped image */
++ s->r.left = 0;
++ s->r.top = 0;
++ s->r.width = min(s->r.width, q_data->crop_width);
++ s->r.height = min(s->r.height, q_data->height);
++ q_data->crop_width = s->r.width;
++ q_data->crop_height = s->r.height;
++ q_data->selection_set = true;
++ break;
++ default:
++ return -EINVAL;
++ }
++ } else {
++ switch (s->target) {
++ case V4L2_SEL_TGT_CROP:
++ /* Only support crop from (0,0) */
++ s->r.top = 0;
++ s->r.left = 0;
++ s->r.width = min(s->r.width, q_data->crop_width);
++ s->r.height = min(s->r.height, q_data->crop_height);
++ q_data->crop_width = s->r.width;
++ q_data->crop_height = s->r.height;
++ q_data->selection_set = true;
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++
++ return 0;
++}
++
++static int vidioc_subscribe_evt(struct v4l2_fh *fh,
++ const struct v4l2_event_subscription *sub)
++{
++ switch (sub->type) {
++ case V4L2_EVENT_EOS:
++ return v4l2_event_subscribe(fh, sub, 2, NULL);
++ case V4L2_EVENT_SOURCE_CHANGE:
++ return v4l2_src_change_event_subscribe(fh, sub);
++ default:
++ return v4l2_ctrl_subscribe_event(fh, sub);
++ }
++}
++
++static int bcm2835_codec_set_level_profile(struct bcm2835_codec_ctx *ctx,
++ struct v4l2_ctrl *ctrl)
++{
++ struct mmal_parameter_video_profile param;
++ int param_size = sizeof(param);
++ int ret;
++
++ /*
++ * Level and Profile are set via the same MMAL parameter.
++ * Retrieve the current settings and amend the one that has changed.
++ */
++ ret = vchiq_mmal_port_parameter_get(ctx->dev->instance,
++ &ctx->component->output[0],
++ MMAL_PARAMETER_PROFILE,
++ ¶m,
++ ¶m_size);
++ if (ret)
++ return ret;
++
++ switch (ctrl->id) {
++ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
++ switch (ctrl->val) {
++ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
++ param.profile = MMAL_VIDEO_PROFILE_H264_BASELINE;
++ break;
++ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
++ param.profile =
++ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE;
++ break;
++ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
++ param.profile = MMAL_VIDEO_PROFILE_H264_MAIN;
++ break;
++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
++ param.profile = MMAL_VIDEO_PROFILE_H264_HIGH;
++ break;
++ default:
++ /* Should never get here */
++ break;
++ }
++ break;
++
++ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
++ switch (ctrl->val) {
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
++ param.level = MMAL_VIDEO_LEVEL_H264_1;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
++ param.level = MMAL_VIDEO_LEVEL_H264_1b;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
++ param.level = MMAL_VIDEO_LEVEL_H264_11;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
++ param.level = MMAL_VIDEO_LEVEL_H264_12;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
++ param.level = MMAL_VIDEO_LEVEL_H264_13;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
++ param.level = MMAL_VIDEO_LEVEL_H264_2;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
++ param.level = MMAL_VIDEO_LEVEL_H264_21;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
++ param.level = MMAL_VIDEO_LEVEL_H264_22;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
++ param.level = MMAL_VIDEO_LEVEL_H264_3;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
++ param.level = MMAL_VIDEO_LEVEL_H264_31;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
++ param.level = MMAL_VIDEO_LEVEL_H264_32;
++ break;
++ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
++ param.level = MMAL_VIDEO_LEVEL_H264_4;
++ break;
++ default:
++ /* Should never get here */
++ break;
++ }
++ }
++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
++ &ctx->component->output[0],
++ MMAL_PARAMETER_PROFILE,
++ ¶m,
++ param_size);
++
++ return ret;
++}
++
++static int bcm2835_codec_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct bcm2835_codec_ctx *ctx =
++ container_of(ctrl->handler, struct bcm2835_codec_ctx, hdl);
++ int ret = 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_MPEG_VIDEO_BITRATE:
++ ctx->bitrate = ctrl->val;
++ if (!ctx->component)
++ break;
++
++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
++ &ctx->component->output[0],
++ MMAL_PARAMETER_VIDEO_BIT_RATE,
++ &ctrl->val,
++ sizeof(ctrl->val));
++ break;
++
++ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: {
++ u32 bitrate_mode;
++
++ if (!ctx->component)
++ break;
++
++ switch (ctrl->val) {
++ default:
++ case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
++ bitrate_mode = MMAL_VIDEO_RATECONTROL_VARIABLE;
++ break;
++ case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
++ bitrate_mode = MMAL_VIDEO_RATECONTROL_CONSTANT;
++ break;
++ }
++
++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
++ &ctx->component->output[0],
++ MMAL_PARAMETER_RATECONTROL,
++ &bitrate_mode,
++ sizeof(bitrate_mode));
++ break;
++ }
++ case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER:
++ if (!ctx->component)
++ break;
++
++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
++ &ctx->component->output[0],
++ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
++ &ctrl->val,
++ sizeof(ctrl->val));
++ break;
++
++ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
++ if (!ctx->component)
++ break;
++
++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
++ &ctx->component->output[0],
++ MMAL_PARAMETER_INTRAPERIOD,
++ &ctrl->val,
++ sizeof(ctrl->val));
++ break;
++
++ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
++ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
++ if (!ctx->component)
++ break;
++
++ ret = bcm2835_codec_set_level_profile(ctx, ctrl);
++ break;
++
++ default:
++ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
++ return -EINVAL;
++ }
++
++ if (ret)
++ v4l2_err(&ctx->dev->v4l2_dev, "Failed setting ctrl %08x, ret %d\n",
++ ctrl->id, ret);
++ return ret ? -EINVAL : 0;
++}
++
++static const struct v4l2_ctrl_ops bcm2835_codec_ctrl_ops = {
++ .s_ctrl = bcm2835_codec_s_ctrl,
++};
++
++static int vidioc_try_decoder_cmd(struct file *file, void *priv,
++ struct v4l2_decoder_cmd *cmd)
++{
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++
++ if (!ctx->dev->decode)
++ return -EINVAL;
++
++ switch (cmd->cmd) {
++ case V4L2_DEC_CMD_STOP:
++ if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK) {
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: DEC cmd->flags=%u stop to black not supported",
++ __func__, cmd->flags);
++ return -EINVAL;
++ }
++ break;
++ case V4L2_DEC_CMD_START:
++ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int vidioc_decoder_cmd(struct file *file, void *priv,
++ struct v4l2_decoder_cmd *cmd)
++{
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++ struct bcm2835_codec_q_data *q_data = &ctx->q_data[V4L2_M2M_SRC];
++ int ret;
++
++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s, cmd %u", __func__,
++ cmd->cmd);
++ ret = vidioc_try_decoder_cmd(file, priv, cmd);
++ if (ret)
++ return ret;
++
++ switch (cmd->cmd) {
++ case V4L2_DEC_CMD_STOP:
++ if (q_data->eos_buffer_in_use)
++ v4l2_err(&ctx->dev->v4l2_dev, "EOS buffers already in use\n");
++ q_data->eos_buffer_in_use = true;
++
++ q_data->eos_buffer.mmal.buffer_size = 0;
++ q_data->eos_buffer.mmal.length = 0;
++ q_data->eos_buffer.mmal.mmal_flags =
++ MMAL_BUFFER_HEADER_FLAG_EOS;
++ q_data->eos_buffer.mmal.pts = 0;
++ q_data->eos_buffer.mmal.dts = 0;
++
++ if (!ctx->component)
++ break;
++
++ ret = vchiq_mmal_submit_buffer(ctx->dev->instance,
++ &ctx->component->input[0],
++ &q_data->eos_buffer.mmal);
++ if (ret)
++ v4l2_err(&ctx->dev->v4l2_dev,
++ "%s: EOS buffer submit failed %d\n",
++ __func__, ret);
++
++ break;
++
++ case V4L2_DEC_CMD_START:
++ /* Do we need to do anything here? */
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int vidioc_try_encoder_cmd(struct file *file, void *priv,
++ struct v4l2_encoder_cmd *cmd)
++{
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++
++ if (ctx->dev->decode)
++ return -EINVAL;
++
++ switch (cmd->cmd) {
++ case V4L2_ENC_CMD_STOP:
++ break;
++
++ case V4L2_ENC_CMD_START:
++ /* Do we need to do anything here? */
++ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int vidioc_encoder_cmd(struct file *file, void *priv,
++ struct v4l2_encoder_cmd *cmd)
++{
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++ struct bcm2835_codec_q_data *q_data = &ctx->q_data[V4L2_M2M_SRC];
++ int ret;
++
++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s, cmd %u", __func__,
++ cmd->cmd);
++ ret = vidioc_try_encoder_cmd(file, priv, cmd);
++ if (ret)
++ return ret;
++
++ switch (cmd->cmd) {
++ case V4L2_ENC_CMD_STOP:
++ if (q_data->eos_buffer_in_use)
++ v4l2_err(&ctx->dev->v4l2_dev, "EOS buffers already in use\n");
++ q_data->eos_buffer_in_use = true;
++
++ q_data->eos_buffer.mmal.buffer_size = 0;
++ q_data->eos_buffer.mmal.length = 0;
++ q_data->eos_buffer.mmal.mmal_flags =
++ MMAL_BUFFER_HEADER_FLAG_EOS;
++ q_data->eos_buffer.mmal.pts = 0;
++ q_data->eos_buffer.mmal.dts = 0;
++
++ if (!ctx->component)
++ break;
++
++ ret = vchiq_mmal_submit_buffer(ctx->dev->instance,
++ &ctx->component->input[0],
++ &q_data->eos_buffer.mmal);
++ if (ret)
++ v4l2_err(&ctx->dev->v4l2_dev,
++ "%s: EOS buffer submit failed %d\n",
++ __func__, ret);
++
++ break;
++ case V4L2_ENC_CMD_START:
++ /* Do we need to do anything here? */
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = {
++ .vidioc_querycap = vidioc_querycap,
++
++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
++ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
++ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
++
++ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
++ .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
++ .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
++ .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
++
++ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
++ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
++ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
++ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
++ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
++ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
++ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
++
++ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
++ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
++
++ .vidioc_g_selection = vidioc_g_selection,
++ .vidioc_s_selection = vidioc_s_selection,
++
++ .vidioc_subscribe_event = vidioc_subscribe_evt,
++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
++
++ .vidioc_decoder_cmd = vidioc_decoder_cmd,
++ .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd,
++ .vidioc_encoder_cmd = vidioc_encoder_cmd,
++ .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd,
++};
++
++static int bcm2835_codec_set_ctrls(struct bcm2835_codec_ctx *ctx)
++{
++ /*
++ * Query the control handler for the value of the various controls and
++ * set them.
++ */
++ const u32 control_ids[] = {
++ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
++ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER,
++ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
++ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
++ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
++ };
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(control_ids); i++) {
++ struct v4l2_ctrl *ctrl;
++
++ ctrl = v4l2_ctrl_find(&ctx->hdl, control_ids[i]);
++ if (ctrl)
++ bcm2835_codec_s_ctrl(ctrl);
++ }
++
++ return 0;
++}
++
++static int bcm2835_codec_create_component(struct bcm2835_codec_ctx *ctx)
++{
++ struct bcm2835_codec_dev *dev = ctx->dev;
++ unsigned int enable = 1;
++ int ret;
++
++ ret = vchiq_mmal_component_init(dev->instance, dev->decode ?
++ "ril.video_decode" : "ril.video_encode",
++ &ctx->component);
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev, "%s: failed to create component for %s\n",
++ __func__, dev->decode ? "decode" : "encode");
++ return -ENOMEM;
++ }
++
++ vchiq_mmal_port_parameter_set(dev->instance, &ctx->component->input[0],
++ MMAL_PARAMETER_ZERO_COPY, &enable,
++ sizeof(enable));
++ vchiq_mmal_port_parameter_set(dev->instance, &ctx->component->output[0],
++ MMAL_PARAMETER_ZERO_COPY, &enable,
++ sizeof(enable));
++
++ setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_SRC],
++ &ctx->component->input[0]);
++
++ setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_DST],
++ &ctx->component->output[0]);
++
++ ret = vchiq_mmal_port_set_format(dev->instance,
++ &ctx->component->input[0]);
++ if (ret < 0)
++ goto destroy_component;
++
++ ret = vchiq_mmal_port_set_format(dev->instance,
++ &ctx->component->output[0]);
++ if (ret < 0)
++ goto destroy_component;
++
++ if (dev->decode) {
++ if (ctx->q_data[V4L2_M2M_DST].sizeimage <
++ ctx->component->output[0].minimum_buffer.size)
++ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
++ ctx->q_data[V4L2_M2M_DST].sizeimage,
++ ctx->component->output[0].minimum_buffer.size);
++ } else {
++ if (ctx->q_data[V4L2_M2M_SRC].sizeimage <
++ ctx->component->output[0].minimum_buffer.size)
++ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
++ ctx->q_data[V4L2_M2M_SRC].sizeimage,
++ ctx->component->output[0].minimum_buffer.size);
++
++ /* Now we have a component we can set all the ctrls */
++ bcm2835_codec_set_ctrls(ctx);
++ }
++
++ return 0;
++
++destroy_component:
++ vchiq_mmal_component_finalise(ctx->dev->instance, ctx->component);
++
++ return ret;
++}
++
++/*
++ * Queue operations
++ */
++
++static int bcm2835_codec_queue_setup(struct vb2_queue *vq,
++ unsigned int *nbuffers,
++ unsigned int *nplanes,
++ unsigned int sizes[],
++ struct device *alloc_devs[])
++{
++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vq);
++ struct bcm2835_codec_q_data *q_data;
++ struct vchiq_mmal_port *port;
++ unsigned int size;
++
++ q_data = get_q_data(ctx, vq->type);
++ if (!q_data)
++ return -EINVAL;
++
++ if (!ctx->component)
++ if (bcm2835_codec_create_component(ctx))
++ return -EINVAL;
++
++ port = get_port_data(ctx, vq->type);
++
++ size = q_data->sizeimage;
++
++ if (*nplanes)
++ return sizes[0] < size ? -EINVAL : 0;
++
++ *nplanes = 1;
++
++ sizes[0] = size;
++ port->current_buffer.size = size;
++
++ if (*nbuffers < port->minimum_buffer.num)
++ *nbuffers = port->minimum_buffer.num;
++ /* Add one buffer to take an EOS */
++ port->current_buffer.num = *nbuffers + 1;
++
++ return 0;
++}
++
++static int bcm2835_codec_buf_init(struct vb2_buffer *vb)
++{
++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
++ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
++ struct v4l2_m2m_buffer *m2m = container_of(vb2, struct v4l2_m2m_buffer,
++ vb);
++ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer,
++ m2m);
++
++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n",
++ __func__, ctx, vb);
++ buf->mmal.buffer = vb2_plane_vaddr(&buf->m2m.vb.vb2_buf, 0);
++ buf->mmal.buffer_size = vb2_plane_size(&buf->m2m.vb.vb2_buf, 0);
++
++ mmal_vchi_buffer_init(ctx->dev->instance, &buf->mmal);
++
++ return 0;
++}
++
++static int bcm2835_codec_buf_prepare(struct vb2_buffer *vb)
++{
++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
++ struct bcm2835_codec_q_data *q_data;
++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
++ struct v4l2_m2m_buffer *m2m = container_of(vbuf, struct v4l2_m2m_buffer,
++ vb);
++ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer,
++ m2m);
++ int ret;
++
++ v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p\n",
++ __func__, vb->vb2_queue->type, vb);
++
++ q_data = get_q_data(ctx, vb->vb2_queue->type);
++ if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
++ if (vbuf->field == V4L2_FIELD_ANY)
++ vbuf->field = V4L2_FIELD_NONE;
++ if (vbuf->field != V4L2_FIELD_NONE) {
++ v4l2_err(&ctx->dev->v4l2_dev, "%s field isn't supported\n",
++ __func__);
++ return -EINVAL;
++ }
++ }
++
++ if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
++ v4l2_err(&ctx->dev->v4l2_dev, "%s data will not fit into plane (%lu < %lu)\n",
++ __func__, vb2_plane_size(vb, 0),
++ (long)q_data->sizeimage);
++ return -EINVAL;
++ }
++
++ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type))
++ vb2_set_plane_payload(vb, 0, q_data->sizeimage);
++
++ /*
++ * We want to do this at init, but vb2_core_expbuf checks that the
++ * index < q->num_buffers, and q->num_buffers only gets updated once
++ * all the buffers are allocated.
++ */
++ if (!buf->mmal.dma_buf) {
++ ret = vb2_core_expbuf_dmabuf(vb->vb2_queue,
++ vb->vb2_queue->type, vb->index, 0,
++ O_CLOEXEC, &buf->mmal.dma_buf);
++ if (ret)
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed to expbuf idx %d, ret %d\n",
++ __func__, vb->index, ret);
++ } else {
++ ret = 0;
++ }
++
++ return ret;
++}
++
++static void bcm2835_codec_buf_queue(struct vb2_buffer *vb)
++{
++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
++
++ v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p vbuf->flags %u, seq %u, bytesused %u\n",
++ __func__, vb->vb2_queue->type, vb, vbuf->flags, vbuf->sequence,
++ vb->planes[0].bytesused);
++ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
++}
++
++static void bcm2835_codec_buffer_cleanup(struct vb2_buffer *vb)
++{
++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
++ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
++ struct v4l2_m2m_buffer *m2m = container_of(vb2, struct v4l2_m2m_buffer,
++ vb);
++ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer,
++ m2m);
++
++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n",
++ __func__, ctx, vb);
++
++ mmal_vchi_buffer_cleanup(&buf->mmal);
++
++ if (buf->mmal.dma_buf) {
++ dma_buf_put(buf->mmal.dma_buf);
++ buf->mmal.dma_buf = NULL;
++ }
++}
++
++static int bcm2835_codec_start_streaming(struct vb2_queue *q,
++ unsigned int count)
++{
++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(q);
++ struct bcm2835_codec_dev *dev = ctx->dev;
++ struct bcm2835_codec_q_data *q_data = get_q_data(ctx, q->type);
++ int ret;
++
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: type: %d count %d\n",
++ __func__, q->type, count);
++ q_data->sequence = 0;
++
++ if (!ctx->component_enabled) {
++ ret = vchiq_mmal_component_enable(dev->instance,
++ ctx->component);
++ if (ret)
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling component, ret %d\n",
++ __func__, ret);
++ ctx->component_enabled = true;
++ }
++
++ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++ /*
++ * Create the EOS buffer.
++ * We only need the MMAL part, and want to NOT attach a memory
++ * buffer to it as it should only take flags.
++ */
++ memset(&q_data->eos_buffer, 0, sizeof(q_data->eos_buffer));
++ mmal_vchi_buffer_init(dev->instance,
++ &q_data->eos_buffer.mmal);
++ q_data->eos_buffer_in_use = false;
++
++ ctx->component->input[0].cb_ctx = ctx;
++ ret = vchiq_mmal_port_enable(dev->instance,
++ &ctx->component->input[0],
++ ip_buffer_cb);
++ if (ret)
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling i/p port, ret %d\n",
++ __func__, ret);
++ } else {
++ ctx->component->output[0].cb_ctx = ctx;
++ ret = vchiq_mmal_port_enable(dev->instance,
++ &ctx->component->output[0],
++ op_buffer_cb);
++ if (ret)
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
++ __func__, ret);
++ }
++ return ret;
++}
++
++static void bcm2835_codec_stop_streaming(struct vb2_queue *q)
++{
++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(q);
++ struct bcm2835_codec_dev *dev = ctx->dev;
++ struct bcm2835_codec_q_data *q_data = get_q_data(ctx, q->type);
++ struct vchiq_mmal_port *port = get_port_data(ctx, q->type);
++ struct vb2_v4l2_buffer *vbuf;
++ struct vb2_v4l2_buffer *vb2;
++ struct v4l2_m2m_buffer *m2m;
++ struct m2m_mmal_buffer *buf;
++ int ret, i;
++
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: type: %d - return buffers\n",
++ __func__, q->type);
++
++ init_completion(&ctx->frame_cmplt);
++
++ /* Clear out all buffers held by m2m framework */
++ for (;;) {
++ if (V4L2_TYPE_IS_OUTPUT(q->type))
++ vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
++ else
++ vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
++ if (!vbuf)
++ break;
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: return buffer %p\n",
++ __func__, vbuf);
++
++ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
++ }
++
++ /* Disable MMAL port - this will flush buffers back */
++ ret = vchiq_mmal_port_disable(dev->instance, port);
++ if (ret)
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed disabling %s port, ret %d\n",
++ __func__, V4L2_TYPE_IS_OUTPUT(q->type) ? "i/p" : "o/p",
++ ret);
++
++ while (atomic_read(&port->buffers_with_vpu)) {
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Waiting for buffers to be returned - %d outstanding\n",
++ __func__, atomic_read(&port->buffers_with_vpu));
++ ret = wait_for_completion_timeout(&ctx->frame_cmplt, HZ);
++ if (ret <= 0) {
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
++ __func__,
++ atomic_read(&port->buffers_with_vpu));
++ break;
++ }
++ }
++
++ /*
++ * Release the VCSM handle here as otherwise REQBUFS(0) aborts because
++ * someone is using the dmabuf before giving the driver a chance to do
++ * anything about it.
++ */
++ for (i = 0; i < q->num_buffers; i++) {
++ vb2 = to_vb2_v4l2_buffer(q->bufs[i]);
++ m2m = container_of(vb2, struct v4l2_m2m_buffer, vb);
++ buf = container_of(m2m, struct m2m_mmal_buffer, m2m);
++
++ mmal_vchi_buffer_cleanup(&buf->mmal);
++ if (buf->mmal.dma_buf) {
++ dma_buf_put(buf->mmal.dma_buf);
++ buf->mmal.dma_buf = NULL;
++ }
++ }
++
++ /* If both ports disabled, then disable the component */
++ if (!ctx->component->input[0].enabled &&
++ !ctx->component->output[0].enabled) {
++ ret = vchiq_mmal_component_disable(dev->instance,
++ ctx->component);
++ if (ret)
++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling component, ret %d\n",
++ __func__, ret);
++ }
++
++ if (V4L2_TYPE_IS_OUTPUT(q->type))
++ mmal_vchi_buffer_cleanup(&q_data->eos_buffer.mmal);
++
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: done\n", __func__);
++}
++
++static const struct vb2_ops bcm2835_codec_qops = {
++ .queue_setup = bcm2835_codec_queue_setup,
++ .buf_init = bcm2835_codec_buf_init,
++ .buf_prepare = bcm2835_codec_buf_prepare,
++ .buf_queue = bcm2835_codec_buf_queue,
++ .buf_cleanup = bcm2835_codec_buffer_cleanup,
++ .start_streaming = bcm2835_codec_start_streaming,
++ .stop_streaming = bcm2835_codec_stop_streaming,
++ .wait_prepare = vb2_ops_wait_prepare,
++ .wait_finish = vb2_ops_wait_finish,
++};
++
++static int queue_init(void *priv, struct vb2_queue *src_vq,
++ struct vb2_queue *dst_vq)
++{
++ struct bcm2835_codec_ctx *ctx = priv;
++ int ret;
++
++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
++ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
++ src_vq->drv_priv = ctx;
++ src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
++ src_vq->ops = &bcm2835_codec_qops;
++ src_vq->mem_ops = &vb2_dma_contig_memops;
++ src_vq->dev = &ctx->dev->pdev->dev;
++ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
++ src_vq->lock = &ctx->dev->dev_mutex;
++
++ ret = vb2_queue_init(src_vq);
++ if (ret)
++ return ret;
++
++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
++ dst_vq->drv_priv = ctx;
++ dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
++ dst_vq->ops = &bcm2835_codec_qops;
++ dst_vq->mem_ops = &vb2_dma_contig_memops;
++ dst_vq->dev = &ctx->dev->pdev->dev;
++ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
++ dst_vq->lock = &ctx->dev->dev_mutex;
++
++ return vb2_queue_init(dst_vq);
++}
++
++/*
++ * File operations
++ */
++static int bcm2835_codec_open(struct file *file)
++{
++ struct bcm2835_codec_dev *dev = video_drvdata(file);
++ struct bcm2835_codec_ctx *ctx = NULL;
++ struct v4l2_ctrl_handler *hdl;
++ int rc = 0;
++
++ v4l2_dbg(1, debug, &dev->v4l2_dev, "Creating instance for %s\n",
++ dev->decode ? "decode" : "encode");
++ if (mutex_lock_interruptible(&dev->dev_mutex)) {
++ v4l2_err(&dev->v4l2_dev, "Mutex fail\n");
++ return -ERESTARTSYS;
++ }
++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
++ if (!ctx) {
++ rc = -ENOMEM;
++ goto open_unlock;
++ }
++
++ ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev->decode, false);
++ ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev->decode, true);
++ if (dev->decode) {
++ /*
++ * Input width and height are irrelevant as they will be defined
++ * by the bitstream not the format. Required by V4L2 though.
++ */
++ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
++ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
++ ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT;
++ ctx->q_data[V4L2_M2M_SRC].bytesperline = 0;
++ ctx->q_data[V4L2_M2M_SRC].sizeimage =
++ DEF_COMP_BUF_SIZE_720P_OR_LESS;
++
++ ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
++ ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
++ 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].sizeimage =
++ get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline,
++ ctx->q_data[V4L2_M2M_DST].height,
++ ctx->q_data[V4L2_M2M_DST].fmt);
++ } else {
++ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
++ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
++ 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].sizeimage =
++ get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline,
++ ctx->q_data[V4L2_M2M_SRC].height,
++ ctx->q_data[V4L2_M2M_SRC].fmt);
++
++ ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
++ ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
++ ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
++ ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT;
++ ctx->q_data[V4L2_M2M_DST].sizeimage =
++ DEF_COMP_BUF_SIZE_720P_OR_LESS;
++ }
++
++ ctx->colorspace = V4L2_COLORSPACE_REC709;
++ ctx->bitrate = 10 * 1000 * 1000;
++
++ /* Initialise V4L2 contexts */
++ v4l2_fh_init(&ctx->fh, video_devdata(file));
++ file->private_data = &ctx->fh;
++ ctx->dev = dev;
++ hdl = &ctx->hdl;
++ if (!dev->decode) {
++ /* Encode controls */
++ v4l2_ctrl_handler_init(hdl, 6);
++
++ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
++ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
++ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
++ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
++ V4L2_CID_MPEG_VIDEO_BITRATE,
++ 25 * 1000, 25 * 1000 * 1000,
++ 25 * 1000, 10 * 1000 * 1000);
++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
++ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER,
++ 0, 1,
++ 1, 0);
++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
++ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
++ 0, 0x7FFFFFFF,
++ 1, 60);
++ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
++ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
++ V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
++ ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2)),
++ V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
++ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
++ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
++ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
++ ~(BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
++ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
++ if (hdl->error) {
++ rc = hdl->error;
++ goto free_ctrl_handler;
++ }
++ ctx->fh.ctrl_handler = hdl;
++ v4l2_ctrl_handler_setup(hdl);
++ }
++
++ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
++
++ if (IS_ERR(ctx->fh.m2m_ctx)) {
++ rc = PTR_ERR(ctx->fh.m2m_ctx);
++
++ goto free_ctrl_handler;
++ }
++
++ /* Set both queues as buffered as we have buffering in the VPU. That
++ * means that we will be scheduled whenever either an input or output
++ * buffer is available (otherwise one of each are required).
++ */
++ v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
++ v4l2_m2m_set_dst_buffered(ctx->fh.m2m_ctx, true);
++
++ v4l2_fh_add(&ctx->fh);
++ atomic_inc(&dev->num_inst);
++
++ mutex_unlock(&dev->dev_mutex);
++ return 0;
++
++free_ctrl_handler:
++ v4l2_ctrl_handler_free(hdl);
++ kfree(ctx);
++open_unlock:
++ mutex_unlock(&dev->dev_mutex);
++ return rc;
++}
++
++static int bcm2835_codec_release(struct file *file)
++{
++ struct bcm2835_codec_dev *dev = video_drvdata(file);
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++
++ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: Releasing instance %p\n",
++ __func__, ctx);
++
++ v4l2_fh_del(&ctx->fh);
++ v4l2_fh_exit(&ctx->fh);
++ v4l2_ctrl_handler_free(&ctx->hdl);
++ mutex_lock(&dev->dev_mutex);
++ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
++
++ if (ctx->component)
++ vchiq_mmal_component_finalise(dev->instance, ctx->component);
++
++ mutex_unlock(&dev->dev_mutex);
++ kfree(ctx);
++
++ atomic_dec(&dev->num_inst);
++
++ return 0;
++}
++
++static const struct v4l2_file_operations bcm2835_codec_fops = {
++ .owner = THIS_MODULE,
++ .open = bcm2835_codec_open,
++ .release = bcm2835_codec_release,
++ .poll = v4l2_m2m_fop_poll,
++ .unlocked_ioctl = video_ioctl2,
++ .mmap = v4l2_m2m_fop_mmap,
++};
++
++static const struct video_device bcm2835_codec_videodev = {
++ .name = MEM2MEM_NAME,
++ .vfl_dir = VFL_DIR_M2M,
++ .fops = &bcm2835_codec_fops,
++ .ioctl_ops = &bcm2835_codec_ioctl_ops,
++ .minor = -1,
++ .release = video_device_release_empty,
++};
++
++static const struct v4l2_m2m_ops m2m_ops = {
++ .device_run = device_run,
++ .job_ready = job_ready,
++ .job_abort = job_abort,
++};
++
++static int bcm2835_codec_create(struct platform_device *pdev,
++ struct bcm2835_codec_dev **new_dev,
++ bool decode)
++{
++ struct bcm2835_codec_dev *dev;
++ struct video_device *vfd;
++ struct vchiq_mmal_instance *instance = NULL;
++ int video_nr;
++ int ret;
++
++ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++
++ dev->pdev = pdev;
++
++ dev->decode = decode;
++
++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
++ if (ret)
++ return ret;
++
++ atomic_set(&dev->num_inst, 0);
++ mutex_init(&dev->dev_mutex);
++
++ dev->vfd = bcm2835_codec_videodev;
++ vfd = &dev->vfd;
++ vfd->lock = &dev->dev_mutex;
++ vfd->v4l2_dev = &dev->v4l2_dev;
++
++ if (dev->decode) {
++ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
++ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
++ video_nr = decode_video_nr;
++ } else {
++ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
++ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
++ video_nr = encode_video_nr;
++ }
++
++ ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
++ if (ret) {
++ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
++ goto unreg_dev;
++ }
++
++ video_set_drvdata(vfd, dev);
++ snprintf(vfd->name, sizeof(vfd->name), "%s",
++ bcm2835_codec_videodev.name);
++ v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n",
++ vfd->num);
++
++ *new_dev = dev;
++
++ dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
++ if (IS_ERR(dev->m2m_dev)) {
++ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
++ ret = PTR_ERR(dev->m2m_dev);
++ goto err_m2m;
++ }
++
++ ret = vchiq_mmal_init(&instance);
++ if (ret < 0)
++ goto err_m2m;
++ dev->instance = instance;
++
++ v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s codec\n",
++ dev->decode ? "decode" : "encode");
++ return 0;
++
++err_m2m:
++ v4l2_m2m_release(dev->m2m_dev);
++ video_unregister_device(&dev->vfd);
++unreg_dev:
++ v4l2_device_unregister(&dev->v4l2_dev);
++
++ return ret;
++}
++
++static int bcm2835_codec_destroy(struct bcm2835_codec_dev *dev)
++{
++ if (!dev)
++ return -ENODEV;
++
++ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
++ v4l2_m2m_release(dev->m2m_dev);
++ video_unregister_device(&dev->vfd);
++ v4l2_device_unregister(&dev->v4l2_dev);
++
++ return 0;
++}
++
++static int bcm2835_codec_probe(struct platform_device *pdev)
++{
++ struct bcm2835_codec_driver *drv;
++ int ret = 0;
++
++ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
++ if (!drv)
++ return -ENOMEM;
++
++ ret = bcm2835_codec_create(pdev, &drv->encode, false);
++ if (ret)
++ goto out;
++
++ ret = bcm2835_codec_create(pdev, &drv->decode, true);
++ if (ret)
++ goto out;
++
++ platform_set_drvdata(pdev, drv);
++
++ return 0;
++
++out:
++ if (drv->encode) {
++ bcm2835_codec_destroy(drv->encode);
++ drv->encode = NULL;
++ }
++ return ret;
++}
++
++static int bcm2835_codec_remove(struct platform_device *pdev)
++{
++ struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev);
++
++ bcm2835_codec_destroy(drv->encode);
++
++ bcm2835_codec_destroy(drv->decode);
++
++ return 0;
++}
++
++static struct platform_driver bcm2835_v4l2_codec_driver = {
++ .probe = bcm2835_codec_probe,
++ .remove = bcm2835_codec_remove,
++ .driver = {
++ .name = "bcm2835-codec",
++ .owner = THIS_MODULE,
++ },
++};
++
++module_platform_driver(bcm2835_v4l2_codec_driver);
++
++MODULE_DESCRIPTION("BCM2835 codec V4L2 driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION("0.0.1");
++MODULE_ALIAS("platform:bcm2835-codec");
+++ /dev/null
-From bcb0dccc1f02ed3dd01834ca0e35c4043df8988e Mon Sep 17 00:00:00 2001
-Date: Tue, 25 Sep 2018 16:07:55 +0100
-Subject: [PATCH] staging: vc04_services: Use vc-sm-cma to support zero
- copy
-
-With the vc-sm-cma driver we can support zero copy of buffers between
-the kernel and VPU. Add this support to vchiq-mmal.
-
----
- .../staging/vc04_services/vchiq-mmal/Kconfig | 1 +
- .../vc04_services/vchiq-mmal/mmal-common.h | 4 ++
- .../vc04_services/vchiq-mmal/mmal-vchiq.c | 66 ++++++++++++++++++-
- .../vc04_services/vchiq-mmal/mmal-vchiq.h | 1 +
- 4 files changed, 70 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/Kconfig
-+++ b/drivers/staging/vc04_services/vchiq-mmal/Kconfig
-@@ -2,6 +2,7 @@ config BCM2835_VCHIQ_MMAL
- tristate "BCM2835 MMAL VCHIQ service"
- depends on (ARCH_BCM2835 || COMPILE_TEST)
- select BCM2835_VCHIQ
-+ select BCM_VC_SM_CMA
- help
- Enables the MMAL API over VCHIQ as used for the
- majority of the multimedia services on VideoCore.
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
-@@ -51,6 +51,10 @@ struct mmal_buffer {
-
- struct mmal_msg_context *msg_context;
-
-+ struct dma_buf *dma_buf;/* Exported dmabuf fd from videobuf2 */
-+ int vcsm_handle; /* VCSM handle having imported the dmabuf */
-+ u32 vc_handle; /* VC handle to that dmabuf */
-+
- u32 cmd; /* MMAL command. 0=data. */
- unsigned long length;
- u32 mmal_flags;
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -27,9 +27,12 @@
- #include <media/videobuf2-vmalloc.h>
-
- #include "mmal-common.h"
-+#include "mmal-parameters.h"
- #include "mmal-vchiq.h"
- #include "mmal-msg.h"
-
-+#include "vc-sm-cma/vc_sm_knl.h"
-+
- #define USE_VCHIQ_ARM
- #include "interface/vchi/vchi.h"
-
-@@ -425,8 +428,13 @@ buffer_from_host(struct vchiq_mmal_insta
-
- /* buffer header */
- m.u.buffer_from_host.buffer_header.cmd = 0;
-- m.u.buffer_from_host.buffer_header.data =
-- (u32)(unsigned long)buf->buffer;
-+ if (port->zero_copy) {
-+ m.u.buffer_from_host.buffer_header.data = buf->vc_handle;
-+ } else {
-+ m.u.buffer_from_host.buffer_header.data =
-+ (u32)(unsigned long)buf->buffer;
-+ }
-+
- m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
- if (port->type == MMAL_PORT_TYPE_OUTPUT) {
- m.u.buffer_from_host.buffer_header.length = 0;
-@@ -591,6 +599,22 @@ static void buffer_to_host_cb(struct vch
-
- msg_context->u.bulk.status = msg->h.status;
-
-+ } else if (msg->u.buffer_from_host.is_zero_copy) {
-+ /*
-+ * Zero copy buffer, so nothing to do.
-+ * Copy buffer info and make callback.
-+ */
-+ msg_context->u.bulk.buffer_used =
-+ msg->u.buffer_from_host.buffer_header.length;
-+ msg_context->u.bulk.mmal_flags =
-+ msg->u.buffer_from_host.buffer_header.flags;
-+ msg_context->u.bulk.dts =
-+ msg->u.buffer_from_host.buffer_header.dts;
-+ msg_context->u.bulk.pts =
-+ msg->u.buffer_from_host.buffer_header.pts;
-+ msg_context->u.bulk.cmd =
-+ msg->u.buffer_from_host.buffer_header.cmd;
-+
- } else if (msg->u.buffer_from_host.buffer_header.length == 0) {
- /* empty buffer */
- if (msg->u.buffer_from_host.buffer_header.flags &
-@@ -1538,6 +1562,9 @@ int vchiq_mmal_port_parameter_set(struct
-
- mutex_unlock(&instance->vchiq_mutex);
-
-+ if (parameter == MMAL_PARAMETER_ZERO_COPY && !ret)
-+ port->zero_copy = !!(*(bool *)value);
-+
- return ret;
- }
- EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_set);
-@@ -1706,6 +1733,31 @@ int vchiq_mmal_submit_buffer(struct vchi
- unsigned long flags = 0;
- int ret;
-
-+ /*
-+ * We really want to do this in mmal_vchi_buffer_init but can't as
-+ * videobuf2 won't let us have the dmabuf there.
-+ */
-+ if (port->zero_copy && buffer->dma_buf && !buffer->vcsm_handle) {
-+ pr_debug("%s: import dmabuf %p\n", __func__, buffer->dma_buf);
-+ ret = vc_sm_cma_import_dmabuf(buffer->dma_buf,
-+ &buffer->vcsm_handle);
-+ if (ret) {
-+ pr_err("%s: vc_sm_import_dmabuf_fd failed, ret %d\n",
-+ __func__, ret);
-+ return ret;
-+ }
-+
-+ buffer->vc_handle = vc_sm_cma_int_handle(buffer->vcsm_handle);
-+ if (!buffer->vc_handle) {
-+ pr_err("%s: vc_sm_int_handle failed %d\n",
-+ __func__, ret);
-+ vc_sm_cma_free(buffer->vcsm_handle);
-+ return ret;
-+ }
-+ pr_debug("%s: import dmabuf %p - got vc handle %08X\n",
-+ __func__, buffer->dma_buf, buffer->vc_handle);
-+ }
-+
- ret = buffer_from_host(instance, port, buffer);
- if (ret == -EINVAL) {
- /* Port is disabled. Queue for when it is enabled. */
-@@ -1739,6 +1791,16 @@ int mmal_vchi_buffer_cleanup(struct mmal
- release_msg_context(msg_context);
- buf->msg_context = NULL;
-
-+ if (buf->vcsm_handle) {
-+ int ret;
-+
-+ pr_debug("%s: vc_sm_cma_free on handle %08X\n", __func__,
-+ buf->vcsm_handle);
-+ ret = vc_sm_cma_free(buf->vcsm_handle);
-+ if (ret)
-+ pr_err("%s: vcsm_free failed, ret %d\n", __func__, ret);
-+ buf->vcsm_handle = 0;
-+ }
- return 0;
- }
- EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup);
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-@@ -49,6 +49,7 @@ typedef void (*vchiq_mmal_buffer_cb)(
-
- struct vchiq_mmal_port {
- u32 enabled:1;
-+ u32 zero_copy:1;
- u32 handle;
- u32 type; /* port type, cached to use on port info set */
- u32 index; /* port index, cached to use on port info set */
+++ /dev/null
-From 0b2a62596d0e6efe17bb87a3a5ebd91cee60c64b Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Oct 2018 17:57:45 +0000
-Subject: [PATCH] media: videobuf2: Allow exporting of a struct dmabuf
-
-videobuf2 only allowed exporting a dmabuf as a file descriptor,
-but there are instances where having the struct dma_buf is
-useful within the kernel.
-
-Split the current implementation into two, one step which
-exports a struct dma_buf, and the second which converts that
-into an fd.
-
----
- .../media/common/videobuf2/videobuf2-core.c | 21 ++++++++++++++++---
- include/media/videobuf2-core.h | 15 +++++++++++++
- 2 files changed, 33 insertions(+), 3 deletions(-)
-
---- a/drivers/media/common/videobuf2/videobuf2-core.c
-+++ b/drivers/media/common/videobuf2/videobuf2-core.c
-@@ -1851,12 +1851,12 @@ static int __find_plane_by_offset(struct
- return -EINVAL;
- }
-
--int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
-- unsigned int index, unsigned int plane, unsigned int flags)
-+int vb2_core_expbuf_dmabuf(struct vb2_queue *q, unsigned int type,
-+ unsigned int index, unsigned int plane,
-+ unsigned int flags, struct dma_buf **dmabuf)
- {
- struct vb2_buffer *vb = NULL;
- struct vb2_plane *vb_plane;
-- int ret;
- struct dma_buf *dbuf;
-
- if (q->memory != VB2_MEMORY_MMAP) {
-@@ -1906,6 +1906,21 @@ int vb2_core_expbuf(struct vb2_queue *q,
- return -EINVAL;
- }
-
-+ *dmabuf = dbuf;
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(vb2_core_expbuf_dmabuf);
-+
-+int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
-+ unsigned int index, unsigned int plane, unsigned int flags)
-+{
-+ struct dma_buf *dbuf;
-+ int ret;
-+
-+ ret = vb2_core_expbuf_dmabuf(q, type, index, plane, flags, &dbuf);
-+ if (ret)
-+ return ret;
-+
- ret = dma_buf_fd(dbuf, flags & ~O_ACCMODE);
- if (ret < 0) {
- dprintk(3, "buffer %d, plane %d failed to export (%d)\n",
---- a/include/media/videobuf2-core.h
-+++ b/include/media/videobuf2-core.h
-@@ -825,6 +825,21 @@ int vb2_core_streamon(struct vb2_queue *
- int vb2_core_streamoff(struct vb2_queue *q, unsigned int type);
-
- /**
-+ * vb2_core_expbuf_dmabuf() - Export a buffer as a dma_buf structure
-+ * @q: videobuf2 queue
-+ * @type: buffer type
-+ * @index: id number of the buffer
-+ * @plane: index of the plane to be exported, 0 for single plane queues
-+ * @flags: flags for newly created file, currently only O_CLOEXEC is
-+ * supported, refer to manual of open syscall for more details
-+ * @dmabuf: Returns the dmabuf pointer
-+ *
-+ */
-+int vb2_core_expbuf_dmabuf(struct vb2_queue *q, unsigned int type,
-+ unsigned int index, unsigned int plane,
-+ unsigned int flags, struct dma_buf **dmabuf);
-+
-+/**
- * vb2_core_expbuf() - Export a buffer as a file descriptor.
- * @q: pointer to &struct vb2_queue with videobuf2 queue.
- * @fd: pointer to the file descriptor associated with DMABUF
--- /dev/null
+From b28dac3003b4c756b72201bb1d83647e33e2f4f1 Mon Sep 17 00:00:00 2001
+Date: Fri, 26 Oct 2018 15:14:16 +0100
+Subject: [PATCH] staging: vchiq_arm: Register bcm2835-codec as a
+ platform driver
+
+Following the same pattern as bcm2835-camera and bcm2835-audio,
+register the V4L2 codec driver as a platform driver
+
+---
+ drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -170,6 +170,7 @@ static struct class *vchiq_class;
+ static struct device *vchiq_dev;
+ static DEFINE_SPINLOCK(msg_queue_spinlock);
+ static struct platform_device *bcm2835_camera;
++static struct platform_device *bcm2835_codec;
+
+ static const char *const ioctl_names[] = {
+ "CONNECT",
+@@ -3656,6 +3657,9 @@ static int vchiq_probe(struct platform_d
+ bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
+ if (IS_ERR(bcm2835_camera))
+ bcm2835_camera = NULL;
++ bcm2835_codec = vchiq_register_child(pdev, "bcm2835-codec");
++ if (IS_ERR(bcm2835_codec))
++ bcm2835_codec = NULL;
+
+ return 0;
+
+++ /dev/null
-From 2758fab4321519446fe5444769b6257dd18e794b Mon Sep 17 00:00:00 2001
-Date: Tue, 25 Sep 2018 14:53:49 +0100
-Subject: [PATCH] staging: vc04_services: Add a V4L2 M2M codec driver
-
-This adds a V4L2 memory to memory device that wraps the MMAL
-video decode and video_encode components for H264 and MJPEG encode
-and decode, MPEG4, H263, and VP8 decode (and MPEG2 decode
-if the appropriate licence has been purchased).
-
----
- drivers/staging/vc04_services/Kconfig | 1 +
- drivers/staging/vc04_services/Makefile | 9 +-
- .../vc04_services/bcm2835-codec/Kconfig | 11 +
- .../vc04_services/bcm2835-codec/Makefile | 8 +
- .../staging/vc04_services/bcm2835-codec/TODO | 24 +
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 2359 +++++++++++++++++
- 6 files changed, 2408 insertions(+), 4 deletions(-)
- create mode 100644 drivers/staging/vc04_services/bcm2835-codec/Kconfig
- create mode 100644 drivers/staging/vc04_services/bcm2835-codec/Makefile
- create mode 100644 drivers/staging/vc04_services/bcm2835-codec/TODO
- create mode 100644 drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-
---- a/drivers/staging/vc04_services/Kconfig
-+++ b/drivers/staging/vc04_services/Kconfig
-@@ -23,6 +23,7 @@ source "drivers/staging/vc04_services/bc
- source "drivers/staging/vc04_services/bcm2835-camera/Kconfig"
- source "drivers/staging/vc04_services/vchiq-mmal/Kconfig"
- source "drivers/staging/vc04_services/vc-sm-cma/Kconfig"
-+source "drivers/staging/vc04_services/bcm2835-codec/Kconfig"
-
- endif
-
---- a/drivers/staging/vc04_services/Makefile
-+++ b/drivers/staging/vc04_services/Makefile
-@@ -10,10 +10,11 @@ vchiq-objs := \
- interface/vchiq_arm/vchiq_util.o \
- interface/vchiq_arm/vchiq_connected.o \
-
--obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
--obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
--obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
--obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/
-+obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
-+obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
-+obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
-+obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/
-+obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec/
-
- ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000
-
---- /dev/null
-+++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig
-@@ -0,0 +1,11 @@
-+config VIDEO_CODEC_BCM2835
-+ tristate "BCM2835 Video codec support"
-+ depends on MEDIA_SUPPORT
-+ depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST)
-+ select BCM2835_VCHIQ_MMAL
-+ select VIDEOBUF2_DMA_CONTIG
-+ select V4L2_MEM2MEM_DEV
-+ help
-+ Say Y here to enable the V4L2 video codecs for
-+ Broadcom BCM2835 SoC. This operates over the VCHIQ interface
-+ to a service running on VideoCore.
---- /dev/null
-+++ b/drivers/staging/vc04_services/bcm2835-codec/Makefile
-@@ -0,0 +1,8 @@
-+# SPDX-License-Identifier: GPL-2.0
-+bcm2835-codec-objs := bcm2835-v4l2-codec.o
-+
-+obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec.o
-+
-+ccflags-y += \
-+ -Idrivers/staging/vc04_services \
-+ -D__VCCOREVER__=0x04000000
---- /dev/null
-+++ b/drivers/staging/vc04_services/bcm2835-codec/TODO
-@@ -0,0 +1,24 @@
-+1) Convert to be a platform driver.
-+
-+Right now when the module probes, it tries to initialize VCHI and
-+errors out if it wasn't ready yet. If bcm2835-v4l2 was built in, then
-+VCHI generally isn't ready because it depends on both the firmware and
-+mailbox drivers having already loaded.
-+
-+We should have VCHI create a platform device once it's initialized,
-+and have this driver bind to it, so that we automatically load the
-+v4l2 module after VCHI loads.
-+
-+2) Support SELECTION API to define crop region on the image for encode.
-+
-+Particularly for resolutions that aren't a multiple of the macroblock
-+size, the codec will report a resolution that is a multiple of the macroblock
-+size (it has to have the memory to decode into), and then a different crop
-+region within that buffer.
-+The most common example is 1080P, where the buffer will be 1920x1088 with a
-+crop region of 1920x1080.
-+
-+3) Refactor so that the component creation is only on queue_setup, not open.
-+
-+Fixes v4l2-compliance failure on trying to open 100 instances of the
-+device.
-\ No newline at end of file
---- /dev/null
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -0,0 +1,2359 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/*
-+ * A v4l2-mem2mem device that wraps the video codec MMAL component.
-+ *
-+ * Copyright 2018 Raspberry Pi (Trading) Ltd.
-+ *
-+ * Loosely based on the vim2m virtual driver by Pawel Osciak
-+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
-+ *
-+ * Whilst this driver uses the v4l2_mem2mem framework, it does not need the
-+ * scheduling aspects, so will always take the buffers, pass them to the VPU,
-+ * and then signal the job as complete.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the
-+ * License, or (at your option) any later version
-+ */
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/fs.h>
-+#include <linux/timer.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/platform_device.h>
-+#include <linux/syscalls.h>
-+
-+#include <media/v4l2-mem2mem.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-ioctl.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-event.h>
-+#include <media/videobuf2-dma-contig.h>
-+
-+#include "vchiq-mmal/mmal-encodings.h"
-+#include "vchiq-mmal/mmal-msg.h"
-+#include "vchiq-mmal/mmal-parameters.h"
-+#include "vchiq-mmal/mmal-vchiq.h"
-+
-+/*
-+ * Default /dev/videoN node numbers for decode and encode.
-+ * Deliberately avoid the very low numbers as these are often taken by webcams
-+ * etc, and simple apps tend to only go for /dev/video0.
-+ */
-+static int decode_video_nr = 10;
-+module_param(decode_video_nr, int, 0644);
-+MODULE_PARM_DESC(decode_video_nr, "decoder video device number");
-+
-+static int encode_video_nr = 11;
-+module_param(encode_video_nr, int, 0644);
-+MODULE_PARM_DESC(encode_video_nr, "encoder video device number");
-+
-+static unsigned int debug;
-+module_param(debug, uint, 0644);
-+MODULE_PARM_DESC(debug, "activates debug info (0-3)");
-+
-+#define MIN_W 32
-+#define MIN_H 32
-+#define MAX_W 1920
-+#define MAX_H 1088
-+#define BPL_ALIGN 32
-+#define DEFAULT_WIDTH 640
-+#define DEFAULT_HEIGHT 480
-+/*
-+ * The unanswered question - what is the maximum size of a compressed frame?
-+ * V4L2 mandates that the encoded frame must fit in a single buffer. Sizing
-+ * that buffer is a compromise between wasting memory and risking not fitting.
-+ * The 1080P version of Big Buck Bunny has some frames that exceed 512kB.
-+ * Adopt a moderately arbitrary split at 720P for switching between 512 and
-+ * 768kB buffers.
-+ */
-+#define DEF_COMP_BUF_SIZE_GREATER_720P (768 << 10)
-+#define DEF_COMP_BUF_SIZE_720P_OR_LESS (512 << 10)
-+
-+/* Flags that indicate a format can be used for capture/output */
-+#define MEM2MEM_CAPTURE BIT(0)
-+#define MEM2MEM_OUTPUT BIT(1)
-+
-+#define MEM2MEM_NAME "bcm2835-codec"
-+
-+struct bcm2835_codec_fmt {
-+ u32 fourcc;
-+ int depth;
-+ int bytesperline_align;
-+ u32 flags;
-+ u32 mmal_fmt;
-+ bool decode_only;
-+ bool encode_only;
-+ int size_multiplier_x2;
-+};
-+
-+/* Supported raw pixel formats. Those supported for both encode and decode
-+ * must come first, with those only supported for decode coming after (there
-+ * are no formats supported for encode only).
-+ */
-+static struct bcm2835_codec_fmt raw_formats[] = {
-+ {
-+ .fourcc = V4L2_PIX_FMT_YUV420,
-+ .depth = 8,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_I420,
-+ .size_multiplier_x2 = 3,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_YVU420,
-+ .depth = 8,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_YV12,
-+ .size_multiplier_x2 = 3,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_NV12,
-+ .depth = 8,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_NV12,
-+ .size_multiplier_x2 = 3,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_NV21,
-+ .depth = 8,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_NV21,
-+ .size_multiplier_x2 = 3,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_RGB565,
-+ .depth = 16,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_RGB16,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_YUYV,
-+ .depth = 16,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_YUYV,
-+ .encode_only = true,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_UYVY,
-+ .depth = 16,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_UYVY,
-+ .encode_only = true,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_YVYU,
-+ .depth = 16,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_YVYU,
-+ .encode_only = true,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_VYUY,
-+ .depth = 16,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_VYUY,
-+ .encode_only = true,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_RGB24,
-+ .depth = 24,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_RGB24,
-+ .encode_only = true,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_BGR24,
-+ .depth = 24,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BGR24,
-+ .encode_only = true,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_BGR32,
-+ .depth = 32,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BGRA,
-+ .encode_only = true,
-+ .size_multiplier_x2 = 2,
-+ },
-+};
-+
-+/* Supported encoded formats. Those supported for both encode and decode
-+ * must come first, with those only supported for decode coming after (there
-+ * are no formats supported for encode only).
-+ */
-+static struct bcm2835_codec_fmt encoded_formats[] = {
-+ {
-+ .fourcc = V4L2_PIX_FMT_H264,
-+ .depth = 0,
-+ .flags = V4L2_FMT_FLAG_COMPRESSED,
-+ .mmal_fmt = MMAL_ENCODING_H264,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_MJPEG,
-+ .depth = 0,
-+ .flags = V4L2_FMT_FLAG_COMPRESSED,
-+ .mmal_fmt = MMAL_ENCODING_MJPEG,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_MPEG4,
-+ .depth = 0,
-+ .flags = V4L2_FMT_FLAG_COMPRESSED,
-+ .mmal_fmt = MMAL_ENCODING_MP4V,
-+ .decode_only = true,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_H263,
-+ .depth = 0,
-+ .flags = V4L2_FMT_FLAG_COMPRESSED,
-+ .mmal_fmt = MMAL_ENCODING_H263,
-+ .decode_only = true,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_MPEG2,
-+ .depth = 0,
-+ .flags = V4L2_FMT_FLAG_COMPRESSED,
-+ .mmal_fmt = MMAL_ENCODING_MP2V,
-+ .decode_only = true,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_VP8,
-+ .depth = 0,
-+ .flags = V4L2_FMT_FLAG_COMPRESSED,
-+ .mmal_fmt = MMAL_ENCODING_VP8,
-+ .decode_only = true,
-+ },
-+ /*
-+ * This list couold include VP6 and Theorafor decode, but V4L2 doesn't
-+ * support them.
-+ */
-+};
-+
-+struct bcm2835_codec_fmt_list {
-+ struct bcm2835_codec_fmt *list;
-+ unsigned int num_entries;
-+};
-+
-+#define RAW_LIST 0
-+#define ENCODED_LIST 1
-+
-+struct bcm2835_codec_fmt_list formats[] = {
-+ {
-+ .list = raw_formats,
-+ .num_entries = ARRAY_SIZE(raw_formats),
-+ }, {
-+ .list = encoded_formats,
-+ .num_entries = ARRAY_SIZE(encoded_formats),
-+ },
-+};
-+
-+struct m2m_mmal_buffer {
-+ struct v4l2_m2m_buffer m2m;
-+ struct mmal_buffer mmal;
-+};
-+
-+/* Per-queue, driver-specific private data */
-+struct bcm2835_codec_q_data {
-+ /*
-+ * These parameters should be treated as gospel, with everything else
-+ * being determined from them.
-+ */
-+ /* Buffer width/height */
-+ unsigned int bytesperline;
-+ unsigned int height;
-+ /* Crop size used for selection handling */
-+ unsigned int crop_width;
-+ unsigned int crop_height;
-+ bool selection_set;
-+
-+ unsigned int sizeimage;
-+ unsigned int sequence;
-+ struct bcm2835_codec_fmt *fmt;
-+
-+ /* One extra buffer header so we can send an EOS. */
-+ struct m2m_mmal_buffer eos_buffer;
-+ bool eos_buffer_in_use; /* debug only */
-+};
-+
-+enum {
-+ V4L2_M2M_SRC = 0,
-+ V4L2_M2M_DST = 1,
-+};
-+
-+static inline struct bcm2835_codec_fmt_list *get_format_list(bool decode,
-+ bool capture)
-+{
-+ return decode ^ capture ? &formats[ENCODED_LIST] : &formats[RAW_LIST];
-+}
-+
-+static struct bcm2835_codec_fmt *get_default_format(bool decode, bool capture)
-+{
-+ return &get_format_list(decode, capture)->list[0];
-+}
-+
-+static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, bool decode,
-+ bool capture)
-+{
-+ struct bcm2835_codec_fmt *fmt;
-+ unsigned int k;
-+ struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
-+
-+ for (k = 0; k < fmts->num_entries; k++) {
-+ fmt = &fmts->list[k];
-+ if (fmt->fourcc == f->fmt.pix.pixelformat)
-+ break;
-+ }
-+
-+ /*
-+ * Some compressed formats are only supported for decoding, not
-+ * encoding.
-+ */
-+ if (!decode && fmts->list[k].decode_only)
-+ return NULL;
-+
-+ /* Some pixel formats are only supported for encoding, not decoding. */
-+ if (decode && fmts->list[k].encode_only)
-+ return NULL;
-+
-+ if (k == fmts->num_entries)
-+ return NULL;
-+
-+ return &fmts->list[k];
-+}
-+
-+struct bcm2835_codec_dev {
-+ struct platform_device *pdev;
-+
-+ /* v4l2 devices */
-+ struct v4l2_device v4l2_dev;
-+ struct video_device vfd;
-+ /* mutex for the v4l2 device */
-+ struct mutex dev_mutex;
-+ atomic_t num_inst;
-+
-+ /* allocated mmal instance and components */
-+ bool decode; /* Is this instance a decoder? */
-+ struct vchiq_mmal_instance *instance;
-+
-+ struct v4l2_m2m_dev *m2m_dev;
-+};
-+
-+struct bcm2835_codec_ctx {
-+ struct v4l2_fh fh;
-+ struct bcm2835_codec_dev *dev;
-+
-+ struct v4l2_ctrl_handler hdl;
-+
-+ struct vchiq_mmal_component *component;
-+ bool component_enabled;
-+
-+ enum v4l2_colorspace colorspace;
-+ enum v4l2_ycbcr_encoding ycbcr_enc;
-+ enum v4l2_xfer_func xfer_func;
-+ enum v4l2_quantization quant;
-+
-+ /* Source and destination queue data */
-+ struct bcm2835_codec_q_data q_data[2];
-+ s32 bitrate;
-+
-+ bool aborting;
-+ int num_ip_buffers;
-+ int num_op_buffers;
-+ struct completion frame_cmplt;
-+};
-+
-+struct bcm2835_codec_driver {
-+ struct bcm2835_codec_dev *encode;
-+ struct bcm2835_codec_dev *decode;
-+};
-+
-+static inline struct bcm2835_codec_ctx *file2ctx(struct file *file)
-+{
-+ return container_of(file->private_data, struct bcm2835_codec_ctx, fh);
-+}
-+
-+static struct bcm2835_codec_q_data *get_q_data(struct bcm2835_codec_ctx *ctx,
-+ enum v4l2_buf_type type)
-+{
-+ switch (type) {
-+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-+ return &ctx->q_data[V4L2_M2M_SRC];
-+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+ return &ctx->q_data[V4L2_M2M_DST];
-+ default:
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
-+ __func__, type);
-+ break;
-+ }
-+ return NULL;
-+}
-+
-+static struct vchiq_mmal_port *get_port_data(struct bcm2835_codec_ctx *ctx,
-+ enum v4l2_buf_type type)
-+{
-+ if (!ctx->component)
-+ return NULL;
-+
-+ switch (type) {
-+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-+ return &ctx->component->input[0];
-+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+ return &ctx->component->output[0];
-+ default:
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
-+ __func__, type);
-+ break;
-+ }
-+ return NULL;
-+}
-+
-+/*
-+ * mem2mem callbacks
-+ */
-+
-+/**
-+ * job_ready() - check whether an instance is ready to be scheduled to run
-+ */
-+static int job_ready(void *priv)
-+{
-+ struct bcm2835_codec_ctx *ctx = priv;
-+
-+ if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
-+ !v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx))
-+ return 0;
-+
-+ return 1;
-+}
-+
-+static void job_abort(void *priv)
-+{
-+ struct bcm2835_codec_ctx *ctx = priv;
-+
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s\n", __func__);
-+ /* Will cancel the transaction in the next interrupt handler */
-+ ctx->aborting = 1;
-+}
-+
-+static inline unsigned int get_sizeimage(int bpl, int height,
-+ struct bcm2835_codec_fmt *fmt)
-+{
-+ return (bpl * height * fmt->size_multiplier_x2) >> 1;
-+}
-+
-+static inline unsigned int get_bytesperline(int width,
-+ struct bcm2835_codec_fmt *fmt)
-+{
-+ return ALIGN((width * fmt->depth) >> 3, fmt->bytesperline_align);
-+}
-+
-+static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx,
-+ bool decode,
-+ struct bcm2835_codec_q_data *q_data,
-+ struct vchiq_mmal_port *port)
-+{
-+ port->format.encoding = q_data->fmt->mmal_fmt;
-+
-+ if (!(q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) {
-+ /* Raw image format - set width/height */
-+ port->es.video.width = q_data->bytesperline /
-+ (q_data->fmt->depth >> 3);
-+ port->es.video.height = q_data->height;
-+ port->es.video.crop.width = q_data->crop_width;
-+ port->es.video.crop.height = q_data->crop_height;
-+ port->es.video.frame_rate.num = 0;
-+ port->es.video.frame_rate.den = 1;
-+ } else {
-+ /* Compressed format - leave resolution as 0 for decode */
-+ if (decode) {
-+ port->es.video.width = 0;
-+ port->es.video.height = 0;
-+ port->es.video.crop.width = 0;
-+ port->es.video.crop.height = 0;
-+ } else {
-+ port->es.video.width = q_data->crop_width;
-+ port->es.video.height = q_data->height;
-+ port->es.video.crop.width = q_data->crop_width;
-+ port->es.video.crop.height = q_data->crop_height;
-+ port->format.bitrate = ctx->bitrate;
-+ }
-+ port->es.video.frame_rate.num = 0;
-+ port->es.video.frame_rate.den = 1;
-+ }
-+ port->es.video.crop.x = 0;
-+ port->es.video.crop.y = 0;
-+
-+ port->current_buffer.size = q_data->sizeimage;
-+};
-+
-+static void ip_buffer_cb(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port, int status,
-+ struct mmal_buffer *mmal_buf)
-+{
-+ struct bcm2835_codec_ctx *ctx = port->cb_ctx/*, *curr_ctx*/;
-+ struct m2m_mmal_buffer *buf =
-+ container_of(mmal_buf, struct m2m_mmal_buffer, mmal);
-+
-+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: port %p buf %p length %lu, flags %x\n",
-+ __func__, port, mmal_buf, mmal_buf->length,
-+ mmal_buf->mmal_flags);
-+
-+ if (buf == &ctx->q_data[V4L2_M2M_SRC].eos_buffer) {
-+ /* Do we need to add lcoking to prevent multiple submission of
-+ * the EOS, and therefore handle mutliple return here?
-+ */
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: eos buffer returned.\n",
-+ __func__);
-+ ctx->q_data[V4L2_M2M_SRC].eos_buffer_in_use = false;
-+ return;
-+ }
-+
-+ if (status) {
-+ /* error in transfer */
-+ if (buf)
-+ /* there was a buffer with the error so return it */
-+ vb2_buffer_done(&buf->m2m.vb.vb2_buf,
-+ VB2_BUF_STATE_ERROR);
-+ return;
-+ }
-+ if (mmal_buf->cmd) {
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Not expecting cmd msgs on ip callback - %08x\n",
-+ __func__, mmal_buf->cmd);
-+ /*
-+ * CHECKME: Should we return here. The buffer shouldn't have a
-+ * message context or vb2 buf associated.
-+ */
-+ }
-+
-+ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: no error. Return buffer %p\n",
-+ __func__, &buf->m2m.vb.vb2_buf);
-+ vb2_buffer_done(&buf->m2m.vb.vb2_buf, VB2_BUF_STATE_DONE);
-+
-+ ctx->num_ip_buffers++;
-+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: done %d input buffers\n",
-+ __func__, ctx->num_ip_buffers);
-+
-+ if (!port->enabled)
-+ complete(&ctx->frame_cmplt);
-+}
-+
-+static void queue_res_chg_event(struct bcm2835_codec_ctx *ctx)
-+{
-+ static const struct v4l2_event ev_src_ch = {
-+ .type = V4L2_EVENT_SOURCE_CHANGE,
-+ .u.src_change.changes =
-+ V4L2_EVENT_SRC_CH_RESOLUTION,
-+ };
-+
-+ v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
-+}
-+
-+static void send_eos_event(struct bcm2835_codec_ctx *ctx)
-+{
-+ static const struct v4l2_event ev = {
-+ .type = V4L2_EVENT_EOS,
-+ };
-+
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Sending EOS event\n");
-+
-+ v4l2_event_queue_fh(&ctx->fh, &ev);
-+}
-+
-+static void color_mmal2v4l(struct bcm2835_codec_ctx *ctx, u32 mmal_color_space)
-+{
-+ switch (mmal_color_space) {
-+ case MMAL_COLOR_SPACE_ITUR_BT601:
-+ ctx->colorspace = V4L2_COLORSPACE_REC709;
-+ ctx->xfer_func = V4L2_XFER_FUNC_709;
-+ ctx->ycbcr_enc = V4L2_YCBCR_ENC_601;
-+ ctx->quant = V4L2_QUANTIZATION_LIM_RANGE;
-+ break;
-+
-+ case MMAL_COLOR_SPACE_ITUR_BT709:
-+ ctx->colorspace = V4L2_COLORSPACE_REC709;
-+ ctx->xfer_func = V4L2_XFER_FUNC_709;
-+ ctx->ycbcr_enc = V4L2_YCBCR_ENC_709;
-+ ctx->quant = V4L2_QUANTIZATION_LIM_RANGE;
-+ break;
-+ }
-+}
-+
-+static void handle_fmt_changed(struct bcm2835_codec_ctx *ctx,
-+ struct mmal_buffer *mmal_buf)
-+{
-+ struct bcm2835_codec_q_data *q_data;
-+ struct mmal_msg_event_format_changed *format =
-+ (struct mmal_msg_event_format_changed *)mmal_buf->buffer;
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed: buff size min %u, rec %u, buff num min %u, rec %u\n",
-+ __func__,
-+ format->buffer_size_min,
-+ format->buffer_size_recommended,
-+ format->buffer_num_min,
-+ format->buffer_num_recommended
-+ );
-+ if (format->format.type != MMAL_ES_TYPE_VIDEO) {
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed but not video %u\n",
-+ __func__, format->format.type);
-+ return;
-+ }
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed to %ux%u, crop %ux%u, colourspace %08X\n",
-+ __func__, format->es.video.width, format->es.video.height,
-+ format->es.video.crop.width, format->es.video.crop.height,
-+ format->es.video.color_space);
-+
-+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-+ q_data->crop_width = format->es.video.crop.width;
-+ q_data->crop_height = format->es.video.crop.height;
-+ q_data->bytesperline = format->es.video.crop.width;
-+ q_data->height = format->es.video.height;
-+ q_data->sizeimage = format->buffer_size_min;
-+ if (format->es.video.color_space)
-+ color_mmal2v4l(ctx, format->es.video.color_space);
-+
-+ queue_res_chg_event(ctx);
-+}
-+
-+static void op_buffer_cb(struct vchiq_mmal_instance *instance,
-+ struct vchiq_mmal_port *port, int status,
-+ struct mmal_buffer *mmal_buf)
-+{
-+ struct bcm2835_codec_ctx *ctx = port->cb_ctx;
-+ struct m2m_mmal_buffer *buf;
-+ struct vb2_v4l2_buffer *vb2;
-+
-+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev,
-+ "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
-+ __func__, status, mmal_buf, mmal_buf->length,
-+ mmal_buf->mmal_flags, mmal_buf->pts);
-+
-+ if (status) {
-+ /* error in transfer */
-+ if (vb2) {
-+ /* there was a buffer with the error so return it */
-+ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_ERROR);
-+ }
-+ return;
-+ }
-+
-+ if (mmal_buf->cmd) {
-+ switch (mmal_buf->cmd) {
-+ case MMAL_EVENT_FORMAT_CHANGED:
-+ {
-+ handle_fmt_changed(ctx, mmal_buf);
-+ break;
-+ }
-+ default:
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Unexpected event on output callback - %08x\n",
-+ __func__, mmal_buf->cmd);
-+ break;
-+ }
-+ return;
-+ }
-+
-+ buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal);
-+ vb2 = &buf->m2m.vb;
-+
-+ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: length %lu, flags %x, idx %u\n",
-+ __func__, mmal_buf->length, mmal_buf->mmal_flags,
-+ vb2->vb2_buf.index);
-+
-+ if (mmal_buf->length == 0) {
-+ /* stream ended, or buffer being returned during disable. */
-+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: Empty buffer - flags %04x",
-+ __func__, mmal_buf->mmal_flags);
-+ if (!mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS) {
-+ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_ERROR);
-+ if (!port->enabled)
-+ complete(&ctx->frame_cmplt);
-+ return;
-+ }
-+ }
-+ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS) {
-+ /* EOS packet from the VPU */
-+ send_eos_event(ctx);
-+ vb2->flags |= V4L2_BUF_FLAG_LAST;
-+ }
-+
-+ vb2->vb2_buf.timestamp = mmal_buf->pts;
-+
-+ vb2_set_plane_payload(&vb2->vb2_buf, 0, mmal_buf->length);
-+ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
-+ vb2->flags |= V4L2_BUF_FLAG_KEYFRAME;
-+
-+ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_DONE);
-+ ctx->num_op_buffers++;
-+
-+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: done %d output buffers\n",
-+ __func__, ctx->num_op_buffers);
-+
-+ if (!port->enabled)
-+ complete(&ctx->frame_cmplt);
-+}
-+
-+/* vb2_to_mmal_buffer() - converts vb2 buffer header to MMAL
-+ *
-+ * Copies all the required fields from a VB2 buffer to the MMAL buffer header,
-+ * ready for sending to the VPU.
-+ */
-+static void vb2_to_mmal_buffer(struct m2m_mmal_buffer *buf,
-+ struct vb2_v4l2_buffer *vb2)
-+{
-+ buf->mmal.mmal_flags = 0;
-+ if (vb2->flags & V4L2_BUF_FLAG_KEYFRAME)
-+ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME;
-+
-+ /*
-+ * Adding this means that the data must be framed correctly as one frame
-+ * per buffer. The underlying decoder has no such requirement, but it
-+ * will reduce latency as the bistream parser will be kicked immediately
-+ * to parse the frame, rather than relying on its own heuristics for
-+ * when to wake up.
-+ */
-+ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END;
-+
-+ buf->mmal.length = vb2->vb2_buf.planes[0].bytesused;
-+ /*
-+ * Minor ambiguity in the V4L2 spec as to whether passing in a 0 length
-+ * buffer, or one with V4L2_BUF_FLAG_LAST set denotes end of stream.
-+ * Handle either.
-+ */
-+ if (!buf->mmal.length || vb2->flags & V4L2_BUF_FLAG_LAST)
-+ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_EOS;
-+
-+ buf->mmal.pts = vb2->vb2_buf.timestamp;
-+ buf->mmal.dts = MMAL_TIME_UNKNOWN;
-+}
-+
-+/* device_run() - prepares and starts the device
-+ *
-+ * This simulates all the immediate preparations required before starting
-+ * a device. This will be called by the framework when it decides to schedule
-+ * a particular instance.
-+ */
-+static void device_run(void *priv)
-+{
-+ struct bcm2835_codec_ctx *ctx = priv;
-+ struct bcm2835_codec_dev *dev = ctx->dev;
-+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
-+ struct m2m_mmal_buffer *src_m2m_buf, *dst_m2m_buf;
-+ struct v4l2_m2m_buffer *m2m;
-+ int ret;
-+
-+ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: off we go\n", __func__);
-+
-+ src_buf = v4l2_m2m_buf_remove(&ctx->fh.m2m_ctx->out_q_ctx);
-+ if (src_buf) {
-+ m2m = container_of(src_buf, struct v4l2_m2m_buffer, vb);
-+ src_m2m_buf = container_of(m2m, struct m2m_mmal_buffer, m2m);
-+ vb2_to_mmal_buffer(src_m2m_buf, src_buf);
-+
-+ ret = vchiq_mmal_submit_buffer(dev->instance,
-+ &ctx->component->input[0],
-+ &src_m2m_buf->mmal);
-+ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: Submitted ip buffer len %lu, pts %llu, flags %04x\n",
-+ __func__, src_m2m_buf->mmal.length,
-+ src_m2m_buf->mmal.pts, src_m2m_buf->mmal.mmal_flags);
-+ if (ret)
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed submitting ip buffer\n",
-+ __func__);
-+ }
-+
-+ dst_buf = v4l2_m2m_buf_remove(&ctx->fh.m2m_ctx->cap_q_ctx);
-+ if (dst_buf) {
-+ m2m = container_of(dst_buf, struct v4l2_m2m_buffer, vb);
-+ dst_m2m_buf = container_of(m2m, struct m2m_mmal_buffer, m2m);
-+ vb2_to_mmal_buffer(dst_m2m_buf, dst_buf);
-+
-+ ret = vchiq_mmal_submit_buffer(dev->instance,
-+ &ctx->component->output[0],
-+ &dst_m2m_buf->mmal);
-+ if (ret)
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed submitting op buffer\n",
-+ __func__);
-+ }
-+
-+ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: Submitted src %p, dst %p\n",
-+ __func__, src_m2m_buf, dst_m2m_buf);
-+
-+ /* Complete the job here. */
-+ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
-+}
-+
-+/*
-+ * video ioctls
-+ */
-+static int vidioc_querycap(struct file *file, void *priv,
-+ struct v4l2_capability *cap)
-+{
-+ strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
-+ strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
-+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
-+ MEM2MEM_NAME);
-+ cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
-+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-+ return 0;
-+}
-+
-+static int enum_fmt(struct v4l2_fmtdesc *f, bool decode, bool capture)
-+{
-+ struct bcm2835_codec_fmt *fmt;
-+ struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
-+
-+ if (f->index < fmts->num_entries) {
-+ /* Format found */
-+ /* Check format isn't a decode only format when encoding */
-+ if (!decode &&
-+ fmts->list[f->index].decode_only)
-+ return -EINVAL;
-+ /* Check format isn't a decode only format when encoding */
-+ if (decode &&
-+ fmts->list[f->index].encode_only)
-+ return -EINVAL;
-+
-+ fmt = &fmts->list[f->index];
-+ f->pixelformat = fmt->fourcc;
-+ f->flags = fmt->flags;
-+ return 0;
-+ }
-+
-+ /* Format not found */
-+ return -EINVAL;
-+}
-+
-+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
-+ struct v4l2_fmtdesc *f)
-+{
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+
-+ return enum_fmt(f, ctx->dev->decode, true);
-+}
-+
-+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
-+ struct v4l2_fmtdesc *f)
-+{
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+
-+ return enum_fmt(f, ctx->dev->decode, false);
-+}
-+
-+static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f)
-+{
-+ struct vb2_queue *vq;
-+ struct bcm2835_codec_q_data *q_data;
-+
-+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
-+ if (!vq)
-+ return -EINVAL;
-+
-+ q_data = get_q_data(ctx, f->type);
-+
-+ f->fmt.pix.width = q_data->crop_width;
-+ f->fmt.pix.height = q_data->height;
-+ f->fmt.pix.field = V4L2_FIELD_NONE;
-+ f->fmt.pix.pixelformat = q_data->fmt->fourcc;
-+ f->fmt.pix.bytesperline = q_data->bytesperline;
-+ f->fmt.pix.sizeimage = q_data->sizeimage;
-+ f->fmt.pix.colorspace = ctx->colorspace;
-+ f->fmt.pix.xfer_func = ctx->xfer_func;
-+ f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
-+ f->fmt.pix.quantization = ctx->quant;
-+
-+ return 0;
-+}
-+
-+static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
-+ struct v4l2_format *f)
-+{
-+ return vidioc_g_fmt(file2ctx(file), f);
-+}
-+
-+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
-+ struct v4l2_format *f)
-+{
-+ return vidioc_g_fmt(file2ctx(file), f);
-+}
-+
-+static int vidioc_try_fmt(struct v4l2_format *f, struct bcm2835_codec_fmt *fmt)
-+{
-+ /*
-+ * The V4L2 specification requires the driver to correct the format
-+ * struct if any of the dimensions is unsupported
-+ */
-+ if (f->fmt.pix.width > MAX_W)
-+ f->fmt.pix.width = MAX_W;
-+ if (f->fmt.pix.height > MAX_H)
-+ f->fmt.pix.height = MAX_H;
-+
-+ if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
-+ /* Only clip min w/h on capture. Treat 0x0 as unknown. */
-+ if (f->fmt.pix.width < MIN_W)
-+ f->fmt.pix.width = MIN_W;
-+ if (f->fmt.pix.height < MIN_H)
-+ f->fmt.pix.height = MIN_H;
-+
-+ /*
-+ * Buffer must have a vertical alignment of 16 lines.
-+ * The selection will reflect any cropping rectangle when only
-+ * some of the pixels are active.
-+ */
-+ f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
-+
-+ f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
-+ fmt);
-+ f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
-+ f->fmt.pix.height,
-+ fmt);
-+ } else {
-+ u32 min_size = f->fmt.pix.width > 1280 ||
-+ f->fmt.pix.height > 720 ?
-+ DEF_COMP_BUF_SIZE_GREATER_720P :
-+ DEF_COMP_BUF_SIZE_720P_OR_LESS;
-+
-+ f->fmt.pix.bytesperline = 0;
-+ if (f->fmt.pix.sizeimage < min_size)
-+ f->fmt.pix.sizeimage = min_size;
-+ }
-+
-+ f->fmt.pix.field = V4L2_FIELD_NONE;
-+
-+ return 0;
-+}
-+
-+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
-+ struct v4l2_format *f)
-+{
-+ struct bcm2835_codec_fmt *fmt;
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+
-+ fmt = find_format(f, ctx->dev->decode, true);
-+ if (!fmt) {
-+ f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
-+ true)->fourcc;
-+ fmt = find_format(f, ctx->dev->decode, true);
-+ }
-+
-+ return vidioc_try_fmt(f, fmt);
-+}
-+
-+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
-+ struct v4l2_format *f)
-+{
-+ struct bcm2835_codec_fmt *fmt;
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+
-+ fmt = find_format(f, ctx->dev->decode, false);
-+ if (!fmt) {
-+ f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
-+ false)->fourcc;
-+ fmt = find_format(f, ctx->dev->decode, false);
-+ }
-+
-+ if (!f->fmt.pix.colorspace)
-+ f->fmt.pix.colorspace = ctx->colorspace;
-+
-+ return vidioc_try_fmt(f, fmt);
-+}
-+
-+static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
-+ unsigned int requested_height)
-+{
-+ struct bcm2835_codec_q_data *q_data;
-+ struct vb2_queue *vq;
-+ struct vchiq_mmal_port *port;
-+ bool update_capture_port = false;
-+ int ret;
-+
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
-+ f->type, f->fmt.pix.width, f->fmt.pix.height,
-+ f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
-+
-+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
-+ if (!vq)
-+ return -EINVAL;
-+
-+ q_data = get_q_data(ctx, f->type);
-+ if (!q_data)
-+ return -EINVAL;
-+
-+ if (vb2_is_busy(vq)) {
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
-+ return -EBUSY;
-+ }
-+
-+ q_data->fmt = find_format(f, ctx->dev->decode,
-+ f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
-+ q_data->crop_width = f->fmt.pix.width;
-+ q_data->height = f->fmt.pix.height;
-+ if (!q_data->selection_set)
-+ q_data->crop_height = requested_height;
-+
-+ /*
-+ * Copying the behaviour of vicodec which retains a single set of
-+ * colorspace parameters for both input and output.
-+ */
-+ ctx->colorspace = f->fmt.pix.colorspace;
-+ ctx->xfer_func = f->fmt.pix.xfer_func;
-+ ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
-+ ctx->quant = f->fmt.pix.quantization;
-+
-+ /* All parameters should have been set correctly by try_fmt */
-+ q_data->bytesperline = f->fmt.pix.bytesperline;
-+ q_data->sizeimage = f->fmt.pix.sizeimage;
-+
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n",
-+ q_data->bytesperline, q_data->sizeimage);
-+
-+ if (ctx->dev->decode && q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
-+ f->fmt.pix.width && f->fmt.pix.height) {
-+ /*
-+ * On the decoder, if provided with a resolution on the input
-+ * side, then replicate that to the output side.
-+ * GStreamer appears not to support V4L2_EVENT_SOURCE_CHANGE,
-+ * nor set up a resolution on the output side, therefore
-+ * we can't decode anything at a resolution other than the
-+ * default one.
-+ */
-+ struct bcm2835_codec_q_data *q_data_dst =
-+ &ctx->q_data[V4L2_M2M_DST];
-+
-+ q_data_dst->crop_width = q_data->crop_width;
-+ q_data_dst->crop_height = q_data->crop_height;
-+ q_data_dst->height = ALIGN(q_data->crop_height, 16);
-+
-+ q_data_dst->bytesperline =
-+ get_bytesperline(f->fmt.pix.width, q_data_dst->fmt);
-+ q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline,
-+ q_data_dst->height,
-+ q_data_dst->fmt);
-+ update_capture_port = true;
-+ }
-+
-+ /* If we have a component then setup the port as well */
-+ port = get_port_data(ctx, vq->type);
-+ if (!port)
-+ return 0;
-+
-+ setup_mmal_port_format(ctx, ctx->dev->decode, q_data, port);
-+ ret = vchiq_mmal_port_set_format(ctx->dev->instance, port);
-+ if (ret) {
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n",
-+ __func__, ret);
-+ ret = -EINVAL;
-+ }
-+
-+ if (q_data->sizeimage < port->minimum_buffer.size) {
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Current buffer size of %u < min buf size %u - driver mismatch to MMAL\n",
-+ __func__, q_data->sizeimage,
-+ port->minimum_buffer.size);
-+ }
-+
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Set format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
-+ f->type, q_data->crop_width, q_data->height,
-+ q_data->fmt->fourcc, q_data->sizeimage);
-+
-+ if (update_capture_port) {
-+ struct vchiq_mmal_port *port_dst = &ctx->component->output[0];
-+ struct bcm2835_codec_q_data *q_data_dst =
-+ &ctx->q_data[V4L2_M2M_DST];
-+
-+ setup_mmal_port_format(ctx, ctx->dev->decode, q_data_dst,
-+ port_dst);
-+ ret = vchiq_mmal_port_set_format(ctx->dev->instance, port_dst);
-+ if (ret) {
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on output port, ret %d\n",
-+ __func__, ret);
-+ ret = -EINVAL;
-+ }
-+ }
-+ return ret;
-+}
-+
-+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-+ struct v4l2_format *f)
-+{
-+ unsigned int height = f->fmt.pix.height;
-+ int ret;
-+
-+ ret = vidioc_try_fmt_vid_cap(file, priv, f);
-+ if (ret)
-+ return ret;
-+
-+ return vidioc_s_fmt(file2ctx(file), f, height);
-+}
-+
-+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
-+ struct v4l2_format *f)
-+{
-+ unsigned int height = f->fmt.pix.height;
-+ int ret;
-+
-+ ret = vidioc_try_fmt_vid_out(file, priv, f);
-+ if (ret)
-+ return ret;
-+
-+ ret = vidioc_s_fmt(file2ctx(file), f, height);
-+ return ret;
-+}
-+
-+static int vidioc_g_selection(struct file *file, void *priv,
-+ struct v4l2_selection *s)
-+{
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+ struct bcm2835_codec_q_data *q_data;
-+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
-+ true : false;
-+
-+ if (capture_queue ^ ctx->dev->decode)
-+ /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
-+ return -EINVAL;
-+
-+ q_data = get_q_data(ctx, s->type);
-+ if (!q_data)
-+ return -EINVAL;
-+
-+ if (ctx->dev->decode) {
-+ switch (s->target) {
-+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
-+ case V4L2_SEL_TGT_COMPOSE:
-+ s->r.left = 0;
-+ s->r.top = 0;
-+ s->r.width = q_data->crop_width;
-+ s->r.height = q_data->crop_height;
-+ break;
-+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
-+ s->r.left = 0;
-+ s->r.top = 0;
-+ s->r.width = q_data->crop_width;
-+ s->r.height = q_data->crop_height;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ } else {
-+ switch (s->target) {
-+ case V4L2_SEL_TGT_CROP_DEFAULT:
-+ case V4L2_SEL_TGT_CROP_BOUNDS:
-+ s->r.top = 0;
-+ s->r.left = 0;
-+ s->r.width = q_data->bytesperline;
-+ s->r.height = q_data->height;
-+ break;
-+ case V4L2_SEL_TGT_CROP:
-+ s->r.top = 0;
-+ s->r.left = 0;
-+ s->r.width = q_data->crop_width;
-+ s->r.height = q_data->crop_height;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int vidioc_s_selection(struct file *file, void *priv,
-+ struct v4l2_selection *s)
-+{
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+ struct bcm2835_codec_q_data *q_data = NULL;
-+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
-+ true : false;
-+
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
-+ __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top,
-+ s->r.width, s->r.height);
-+
-+ if (capture_queue ^ ctx->dev->decode)
-+ /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
-+ return -EINVAL;
-+
-+ q_data = get_q_data(ctx, s->type);
-+ if (!q_data)
-+ return -EINVAL;
-+
-+ if (ctx->dev->decode) {
-+ switch (s->target) {
-+ case V4L2_SEL_TGT_COMPOSE:
-+ /* Accept cropped image */
-+ s->r.left = 0;
-+ s->r.top = 0;
-+ s->r.width = min(s->r.width, q_data->crop_width);
-+ s->r.height = min(s->r.height, q_data->height);
-+ q_data->crop_width = s->r.width;
-+ q_data->crop_height = s->r.height;
-+ q_data->selection_set = true;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ } else {
-+ switch (s->target) {
-+ case V4L2_SEL_TGT_CROP:
-+ /* Only support crop from (0,0) */
-+ s->r.top = 0;
-+ s->r.left = 0;
-+ s->r.width = min(s->r.width, q_data->crop_width);
-+ s->r.height = min(s->r.height, q_data->crop_height);
-+ q_data->crop_width = s->r.width;
-+ q_data->crop_height = s->r.height;
-+ q_data->selection_set = true;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int vidioc_subscribe_evt(struct v4l2_fh *fh,
-+ const struct v4l2_event_subscription *sub)
-+{
-+ switch (sub->type) {
-+ case V4L2_EVENT_EOS:
-+ return v4l2_event_subscribe(fh, sub, 2, NULL);
-+ case V4L2_EVENT_SOURCE_CHANGE:
-+ return v4l2_src_change_event_subscribe(fh, sub);
-+ default:
-+ return v4l2_ctrl_subscribe_event(fh, sub);
-+ }
-+}
-+
-+static int bcm2835_codec_set_level_profile(struct bcm2835_codec_ctx *ctx,
-+ struct v4l2_ctrl *ctrl)
-+{
-+ struct mmal_parameter_video_profile param;
-+ int param_size = sizeof(param);
-+ int ret;
-+
-+ /*
-+ * Level and Profile are set via the same MMAL parameter.
-+ * Retrieve the current settings and amend the one that has changed.
-+ */
-+ ret = vchiq_mmal_port_parameter_get(ctx->dev->instance,
-+ &ctx->component->output[0],
-+ MMAL_PARAMETER_PROFILE,
-+ ¶m,
-+ ¶m_size);
-+ if (ret)
-+ return ret;
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
-+ switch (ctrl->val) {
-+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
-+ param.profile = MMAL_VIDEO_PROFILE_H264_BASELINE;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
-+ param.profile =
-+ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
-+ param.profile = MMAL_VIDEO_PROFILE_H264_MAIN;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
-+ param.profile = MMAL_VIDEO_PROFILE_H264_HIGH;
-+ break;
-+ default:
-+ /* Should never get here */
-+ break;
-+ }
-+ break;
-+
-+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
-+ switch (ctrl->val) {
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
-+ param.level = MMAL_VIDEO_LEVEL_H264_1;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
-+ param.level = MMAL_VIDEO_LEVEL_H264_1b;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
-+ param.level = MMAL_VIDEO_LEVEL_H264_11;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
-+ param.level = MMAL_VIDEO_LEVEL_H264_12;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
-+ param.level = MMAL_VIDEO_LEVEL_H264_13;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
-+ param.level = MMAL_VIDEO_LEVEL_H264_2;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
-+ param.level = MMAL_VIDEO_LEVEL_H264_21;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
-+ param.level = MMAL_VIDEO_LEVEL_H264_22;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
-+ param.level = MMAL_VIDEO_LEVEL_H264_3;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
-+ param.level = MMAL_VIDEO_LEVEL_H264_31;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
-+ param.level = MMAL_VIDEO_LEVEL_H264_32;
-+ break;
-+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
-+ param.level = MMAL_VIDEO_LEVEL_H264_4;
-+ break;
-+ default:
-+ /* Should never get here */
-+ break;
-+ }
-+ }
-+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
-+ &ctx->component->output[0],
-+ MMAL_PARAMETER_PROFILE,
-+ ¶m,
-+ param_size);
-+
-+ return ret;
-+}
-+
-+static int bcm2835_codec_s_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct bcm2835_codec_ctx *ctx =
-+ container_of(ctrl->handler, struct bcm2835_codec_ctx, hdl);
-+ int ret = 0;
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_MPEG_VIDEO_BITRATE:
-+ ctx->bitrate = ctrl->val;
-+ if (!ctx->component)
-+ break;
-+
-+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
-+ &ctx->component->output[0],
-+ MMAL_PARAMETER_VIDEO_BIT_RATE,
-+ &ctrl->val,
-+ sizeof(ctrl->val));
-+ break;
-+
-+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: {
-+ u32 bitrate_mode;
-+
-+ if (!ctx->component)
-+ break;
-+
-+ switch (ctrl->val) {
-+ default:
-+ case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
-+ bitrate_mode = MMAL_VIDEO_RATECONTROL_VARIABLE;
-+ break;
-+ case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
-+ bitrate_mode = MMAL_VIDEO_RATECONTROL_CONSTANT;
-+ break;
-+ }
-+
-+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
-+ &ctx->component->output[0],
-+ MMAL_PARAMETER_RATECONTROL,
-+ &bitrate_mode,
-+ sizeof(bitrate_mode));
-+ break;
-+ }
-+ case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER:
-+ if (!ctx->component)
-+ break;
-+
-+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
-+ &ctx->component->output[0],
-+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
-+ &ctrl->val,
-+ sizeof(ctrl->val));
-+ break;
-+
-+ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
-+ if (!ctx->component)
-+ break;
-+
-+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
-+ &ctx->component->output[0],
-+ MMAL_PARAMETER_INTRAPERIOD,
-+ &ctrl->val,
-+ sizeof(ctrl->val));
-+ break;
-+
-+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
-+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
-+ if (!ctx->component)
-+ break;
-+
-+ ret = bcm2835_codec_set_level_profile(ctx, ctrl);
-+ break;
-+
-+ default:
-+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
-+ return -EINVAL;
-+ }
-+
-+ if (ret)
-+ v4l2_err(&ctx->dev->v4l2_dev, "Failed setting ctrl %08x, ret %d\n",
-+ ctrl->id, ret);
-+ return ret ? -EINVAL : 0;
-+}
-+
-+static const struct v4l2_ctrl_ops bcm2835_codec_ctrl_ops = {
-+ .s_ctrl = bcm2835_codec_s_ctrl,
-+};
-+
-+static int vidioc_try_decoder_cmd(struct file *file, void *priv,
-+ struct v4l2_decoder_cmd *cmd)
-+{
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+
-+ if (!ctx->dev->decode)
-+ return -EINVAL;
-+
-+ switch (cmd->cmd) {
-+ case V4L2_DEC_CMD_STOP:
-+ if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK) {
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: DEC cmd->flags=%u stop to black not supported",
-+ __func__, cmd->flags);
-+ return -EINVAL;
-+ }
-+ break;
-+ case V4L2_DEC_CMD_START:
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+static int vidioc_decoder_cmd(struct file *file, void *priv,
-+ struct v4l2_decoder_cmd *cmd)
-+{
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+ struct bcm2835_codec_q_data *q_data = &ctx->q_data[V4L2_M2M_SRC];
-+ int ret;
-+
-+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s, cmd %u", __func__,
-+ cmd->cmd);
-+ ret = vidioc_try_decoder_cmd(file, priv, cmd);
-+ if (ret)
-+ return ret;
-+
-+ switch (cmd->cmd) {
-+ case V4L2_DEC_CMD_STOP:
-+ if (q_data->eos_buffer_in_use)
-+ v4l2_err(&ctx->dev->v4l2_dev, "EOS buffers already in use\n");
-+ q_data->eos_buffer_in_use = true;
-+
-+ q_data->eos_buffer.mmal.buffer_size = 0;
-+ q_data->eos_buffer.mmal.length = 0;
-+ q_data->eos_buffer.mmal.mmal_flags =
-+ MMAL_BUFFER_HEADER_FLAG_EOS;
-+ q_data->eos_buffer.mmal.pts = 0;
-+ q_data->eos_buffer.mmal.dts = 0;
-+
-+ if (!ctx->component)
-+ break;
-+
-+ ret = vchiq_mmal_submit_buffer(ctx->dev->instance,
-+ &ctx->component->input[0],
-+ &q_data->eos_buffer.mmal);
-+ if (ret)
-+ v4l2_err(&ctx->dev->v4l2_dev,
-+ "%s: EOS buffer submit failed %d\n",
-+ __func__, ret);
-+
-+ break;
-+
-+ case V4L2_DEC_CMD_START:
-+ /* Do we need to do anything here? */
-+ break;
-+
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int vidioc_try_encoder_cmd(struct file *file, void *priv,
-+ struct v4l2_encoder_cmd *cmd)
-+{
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+
-+ if (ctx->dev->decode)
-+ return -EINVAL;
-+
-+ switch (cmd->cmd) {
-+ case V4L2_ENC_CMD_STOP:
-+ break;
-+
-+ case V4L2_ENC_CMD_START:
-+ /* Do we need to do anything here? */
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+static int vidioc_encoder_cmd(struct file *file, void *priv,
-+ struct v4l2_encoder_cmd *cmd)
-+{
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+ struct bcm2835_codec_q_data *q_data = &ctx->q_data[V4L2_M2M_SRC];
-+ int ret;
-+
-+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s, cmd %u", __func__,
-+ cmd->cmd);
-+ ret = vidioc_try_encoder_cmd(file, priv, cmd);
-+ if (ret)
-+ return ret;
-+
-+ switch (cmd->cmd) {
-+ case V4L2_ENC_CMD_STOP:
-+ if (q_data->eos_buffer_in_use)
-+ v4l2_err(&ctx->dev->v4l2_dev, "EOS buffers already in use\n");
-+ q_data->eos_buffer_in_use = true;
-+
-+ q_data->eos_buffer.mmal.buffer_size = 0;
-+ q_data->eos_buffer.mmal.length = 0;
-+ q_data->eos_buffer.mmal.mmal_flags =
-+ MMAL_BUFFER_HEADER_FLAG_EOS;
-+ q_data->eos_buffer.mmal.pts = 0;
-+ q_data->eos_buffer.mmal.dts = 0;
-+
-+ if (!ctx->component)
-+ break;
-+
-+ ret = vchiq_mmal_submit_buffer(ctx->dev->instance,
-+ &ctx->component->input[0],
-+ &q_data->eos_buffer.mmal);
-+ if (ret)
-+ v4l2_err(&ctx->dev->v4l2_dev,
-+ "%s: EOS buffer submit failed %d\n",
-+ __func__, ret);
-+
-+ break;
-+ case V4L2_ENC_CMD_START:
-+ /* Do we need to do anything here? */
-+ break;
-+
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = {
-+ .vidioc_querycap = vidioc_querycap,
-+
-+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
-+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-+
-+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
-+ .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
-+ .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
-+ .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
-+
-+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
-+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
-+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
-+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
-+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
-+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
-+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
-+
-+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
-+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
-+
-+ .vidioc_g_selection = vidioc_g_selection,
-+ .vidioc_s_selection = vidioc_s_selection,
-+
-+ .vidioc_subscribe_event = vidioc_subscribe_evt,
-+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-+
-+ .vidioc_decoder_cmd = vidioc_decoder_cmd,
-+ .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd,
-+ .vidioc_encoder_cmd = vidioc_encoder_cmd,
-+ .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd,
-+};
-+
-+static int bcm2835_codec_set_ctrls(struct bcm2835_codec_ctx *ctx)
-+{
-+ /*
-+ * Query the control handler for the value of the various controls and
-+ * set them.
-+ */
-+ const u32 control_ids[] = {
-+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
-+ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER,
-+ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
-+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
-+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
-+ };
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(control_ids); i++) {
-+ struct v4l2_ctrl *ctrl;
-+
-+ ctrl = v4l2_ctrl_find(&ctx->hdl, control_ids[i]);
-+ if (ctrl)
-+ bcm2835_codec_s_ctrl(ctrl);
-+ }
-+
-+ return 0;
-+}
-+
-+static int bcm2835_codec_create_component(struct bcm2835_codec_ctx *ctx)
-+{
-+ struct bcm2835_codec_dev *dev = ctx->dev;
-+ unsigned int enable = 1;
-+ int ret;
-+
-+ ret = vchiq_mmal_component_init(dev->instance, dev->decode ?
-+ "ril.video_decode" : "ril.video_encode",
-+ &ctx->component);
-+ if (ret < 0) {
-+ v4l2_err(&dev->v4l2_dev, "%s: failed to create component for %s\n",
-+ __func__, dev->decode ? "decode" : "encode");
-+ return -ENOMEM;
-+ }
-+
-+ vchiq_mmal_port_parameter_set(dev->instance, &ctx->component->input[0],
-+ MMAL_PARAMETER_ZERO_COPY, &enable,
-+ sizeof(enable));
-+ vchiq_mmal_port_parameter_set(dev->instance, &ctx->component->output[0],
-+ MMAL_PARAMETER_ZERO_COPY, &enable,
-+ sizeof(enable));
-+
-+ setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_SRC],
-+ &ctx->component->input[0]);
-+
-+ setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_DST],
-+ &ctx->component->output[0]);
-+
-+ ret = vchiq_mmal_port_set_format(dev->instance,
-+ &ctx->component->input[0]);
-+ if (ret < 0)
-+ goto destroy_component;
-+
-+ ret = vchiq_mmal_port_set_format(dev->instance,
-+ &ctx->component->output[0]);
-+ if (ret < 0)
-+ goto destroy_component;
-+
-+ if (dev->decode) {
-+ if (ctx->q_data[V4L2_M2M_DST].sizeimage <
-+ ctx->component->output[0].minimum_buffer.size)
-+ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
-+ ctx->q_data[V4L2_M2M_DST].sizeimage,
-+ ctx->component->output[0].minimum_buffer.size);
-+ } else {
-+ if (ctx->q_data[V4L2_M2M_SRC].sizeimage <
-+ ctx->component->output[0].minimum_buffer.size)
-+ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
-+ ctx->q_data[V4L2_M2M_SRC].sizeimage,
-+ ctx->component->output[0].minimum_buffer.size);
-+
-+ /* Now we have a component we can set all the ctrls */
-+ bcm2835_codec_set_ctrls(ctx);
-+ }
-+
-+ return 0;
-+
-+destroy_component:
-+ vchiq_mmal_component_finalise(ctx->dev->instance, ctx->component);
-+
-+ return ret;
-+}
-+
-+/*
-+ * Queue operations
-+ */
-+
-+static int bcm2835_codec_queue_setup(struct vb2_queue *vq,
-+ unsigned int *nbuffers,
-+ unsigned int *nplanes,
-+ unsigned int sizes[],
-+ struct device *alloc_devs[])
-+{
-+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vq);
-+ struct bcm2835_codec_q_data *q_data;
-+ struct vchiq_mmal_port *port;
-+ unsigned int size;
-+
-+ q_data = get_q_data(ctx, vq->type);
-+ if (!q_data)
-+ return -EINVAL;
-+
-+ if (!ctx->component)
-+ if (bcm2835_codec_create_component(ctx))
-+ return -EINVAL;
-+
-+ port = get_port_data(ctx, vq->type);
-+
-+ size = q_data->sizeimage;
-+
-+ if (*nplanes)
-+ return sizes[0] < size ? -EINVAL : 0;
-+
-+ *nplanes = 1;
-+
-+ sizes[0] = size;
-+ port->current_buffer.size = size;
-+
-+ if (*nbuffers < port->minimum_buffer.num)
-+ *nbuffers = port->minimum_buffer.num;
-+ /* Add one buffer to take an EOS */
-+ port->current_buffer.num = *nbuffers + 1;
-+
-+ return 0;
-+}
-+
-+static int bcm2835_codec_buf_init(struct vb2_buffer *vb)
-+{
-+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-+ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
-+ struct v4l2_m2m_buffer *m2m = container_of(vb2, struct v4l2_m2m_buffer,
-+ vb);
-+ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer,
-+ m2m);
-+
-+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n",
-+ __func__, ctx, vb);
-+ buf->mmal.buffer = vb2_plane_vaddr(&buf->m2m.vb.vb2_buf, 0);
-+ buf->mmal.buffer_size = vb2_plane_size(&buf->m2m.vb.vb2_buf, 0);
-+
-+ mmal_vchi_buffer_init(ctx->dev->instance, &buf->mmal);
-+
-+ return 0;
-+}
-+
-+static int bcm2835_codec_buf_prepare(struct vb2_buffer *vb)
-+{
-+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-+ struct bcm2835_codec_q_data *q_data;
-+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-+ struct v4l2_m2m_buffer *m2m = container_of(vbuf, struct v4l2_m2m_buffer,
-+ vb);
-+ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer,
-+ m2m);
-+ int ret;
-+
-+ v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p\n",
-+ __func__, vb->vb2_queue->type, vb);
-+
-+ q_data = get_q_data(ctx, vb->vb2_queue->type);
-+ if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
-+ if (vbuf->field == V4L2_FIELD_ANY)
-+ vbuf->field = V4L2_FIELD_NONE;
-+ if (vbuf->field != V4L2_FIELD_NONE) {
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s field isn't supported\n",
-+ __func__);
-+ return -EINVAL;
-+ }
-+ }
-+
-+ if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s data will not fit into plane (%lu < %lu)\n",
-+ __func__, vb2_plane_size(vb, 0),
-+ (long)q_data->sizeimage);
-+ return -EINVAL;
-+ }
-+
-+ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type))
-+ vb2_set_plane_payload(vb, 0, q_data->sizeimage);
-+
-+ /*
-+ * We want to do this at init, but vb2_core_expbuf checks that the
-+ * index < q->num_buffers, and q->num_buffers only gets updated once
-+ * all the buffers are allocated.
-+ */
-+ if (!buf->mmal.dma_buf) {
-+ ret = vb2_core_expbuf_dmabuf(vb->vb2_queue,
-+ vb->vb2_queue->type, vb->index, 0,
-+ O_CLOEXEC, &buf->mmal.dma_buf);
-+ if (ret)
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed to expbuf idx %d, ret %d\n",
-+ __func__, vb->index, ret);
-+ } else {
-+ ret = 0;
-+ }
-+
-+ return ret;
-+}
-+
-+static void bcm2835_codec_buf_queue(struct vb2_buffer *vb)
-+{
-+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-+
-+ v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p vbuf->flags %u, seq %u, bytesused %u\n",
-+ __func__, vb->vb2_queue->type, vb, vbuf->flags, vbuf->sequence,
-+ vb->planes[0].bytesused);
-+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
-+}
-+
-+static void bcm2835_codec_buffer_cleanup(struct vb2_buffer *vb)
-+{
-+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-+ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
-+ struct v4l2_m2m_buffer *m2m = container_of(vb2, struct v4l2_m2m_buffer,
-+ vb);
-+ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer,
-+ m2m);
-+
-+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n",
-+ __func__, ctx, vb);
-+
-+ mmal_vchi_buffer_cleanup(&buf->mmal);
-+
-+ if (buf->mmal.dma_buf) {
-+ dma_buf_put(buf->mmal.dma_buf);
-+ buf->mmal.dma_buf = NULL;
-+ }
-+}
-+
-+static int bcm2835_codec_start_streaming(struct vb2_queue *q,
-+ unsigned int count)
-+{
-+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(q);
-+ struct bcm2835_codec_dev *dev = ctx->dev;
-+ struct bcm2835_codec_q_data *q_data = get_q_data(ctx, q->type);
-+ int ret;
-+
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: type: %d count %d\n",
-+ __func__, q->type, count);
-+ q_data->sequence = 0;
-+
-+ if (!ctx->component_enabled) {
-+ ret = vchiq_mmal_component_enable(dev->instance,
-+ ctx->component);
-+ if (ret)
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling component, ret %d\n",
-+ __func__, ret);
-+ ctx->component_enabled = true;
-+ }
-+
-+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-+ /*
-+ * Create the EOS buffer.
-+ * We only need the MMAL part, and want to NOT attach a memory
-+ * buffer to it as it should only take flags.
-+ */
-+ memset(&q_data->eos_buffer, 0, sizeof(q_data->eos_buffer));
-+ mmal_vchi_buffer_init(dev->instance,
-+ &q_data->eos_buffer.mmal);
-+ q_data->eos_buffer_in_use = false;
-+
-+ ctx->component->input[0].cb_ctx = ctx;
-+ ret = vchiq_mmal_port_enable(dev->instance,
-+ &ctx->component->input[0],
-+ ip_buffer_cb);
-+ if (ret)
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling i/p port, ret %d\n",
-+ __func__, ret);
-+ } else {
-+ ctx->component->output[0].cb_ctx = ctx;
-+ ret = vchiq_mmal_port_enable(dev->instance,
-+ &ctx->component->output[0],
-+ op_buffer_cb);
-+ if (ret)
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
-+ __func__, ret);
-+ }
-+ return ret;
-+}
-+
-+static void bcm2835_codec_stop_streaming(struct vb2_queue *q)
-+{
-+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(q);
-+ struct bcm2835_codec_dev *dev = ctx->dev;
-+ struct bcm2835_codec_q_data *q_data = get_q_data(ctx, q->type);
-+ struct vchiq_mmal_port *port = get_port_data(ctx, q->type);
-+ struct vb2_v4l2_buffer *vbuf;
-+ struct vb2_v4l2_buffer *vb2;
-+ struct v4l2_m2m_buffer *m2m;
-+ struct m2m_mmal_buffer *buf;
-+ int ret, i;
-+
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: type: %d - return buffers\n",
-+ __func__, q->type);
-+
-+ init_completion(&ctx->frame_cmplt);
-+
-+ /* Clear out all buffers held by m2m framework */
-+ for (;;) {
-+ if (V4L2_TYPE_IS_OUTPUT(q->type))
-+ vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
-+ else
-+ vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-+ if (!vbuf)
-+ break;
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: return buffer %p\n",
-+ __func__, vbuf);
-+
-+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
-+ }
-+
-+ /* Disable MMAL port - this will flush buffers back */
-+ ret = vchiq_mmal_port_disable(dev->instance, port);
-+ if (ret)
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed disabling %s port, ret %d\n",
-+ __func__, V4L2_TYPE_IS_OUTPUT(q->type) ? "i/p" : "o/p",
-+ ret);
-+
-+ while (atomic_read(&port->buffers_with_vpu)) {
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Waiting for buffers to be returned - %d outstanding\n",
-+ __func__, atomic_read(&port->buffers_with_vpu));
-+ ret = wait_for_completion_timeout(&ctx->frame_cmplt, HZ);
-+ if (ret <= 0) {
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
-+ __func__,
-+ atomic_read(&port->buffers_with_vpu));
-+ break;
-+ }
-+ }
-+
-+ /*
-+ * Release the VCSM handle here as otherwise REQBUFS(0) aborts because
-+ * someone is using the dmabuf before giving the driver a chance to do
-+ * anything about it.
-+ */
-+ for (i = 0; i < q->num_buffers; i++) {
-+ vb2 = to_vb2_v4l2_buffer(q->bufs[i]);
-+ m2m = container_of(vb2, struct v4l2_m2m_buffer, vb);
-+ buf = container_of(m2m, struct m2m_mmal_buffer, m2m);
-+
-+ mmal_vchi_buffer_cleanup(&buf->mmal);
-+ if (buf->mmal.dma_buf) {
-+ dma_buf_put(buf->mmal.dma_buf);
-+ buf->mmal.dma_buf = NULL;
-+ }
-+ }
-+
-+ /* If both ports disabled, then disable the component */
-+ if (!ctx->component->input[0].enabled &&
-+ !ctx->component->output[0].enabled) {
-+ ret = vchiq_mmal_component_disable(dev->instance,
-+ ctx->component);
-+ if (ret)
-+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling component, ret %d\n",
-+ __func__, ret);
-+ }
-+
-+ if (V4L2_TYPE_IS_OUTPUT(q->type))
-+ mmal_vchi_buffer_cleanup(&q_data->eos_buffer.mmal);
-+
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: done\n", __func__);
-+}
-+
-+static const struct vb2_ops bcm2835_codec_qops = {
-+ .queue_setup = bcm2835_codec_queue_setup,
-+ .buf_init = bcm2835_codec_buf_init,
-+ .buf_prepare = bcm2835_codec_buf_prepare,
-+ .buf_queue = bcm2835_codec_buf_queue,
-+ .buf_cleanup = bcm2835_codec_buffer_cleanup,
-+ .start_streaming = bcm2835_codec_start_streaming,
-+ .stop_streaming = bcm2835_codec_stop_streaming,
-+ .wait_prepare = vb2_ops_wait_prepare,
-+ .wait_finish = vb2_ops_wait_finish,
-+};
-+
-+static int queue_init(void *priv, struct vb2_queue *src_vq,
-+ struct vb2_queue *dst_vq)
-+{
-+ struct bcm2835_codec_ctx *ctx = priv;
-+ int ret;
-+
-+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
-+ src_vq->drv_priv = ctx;
-+ src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
-+ src_vq->ops = &bcm2835_codec_qops;
-+ src_vq->mem_ops = &vb2_dma_contig_memops;
-+ src_vq->dev = &ctx->dev->pdev->dev;
-+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-+ src_vq->lock = &ctx->dev->dev_mutex;
-+
-+ ret = vb2_queue_init(src_vq);
-+ if (ret)
-+ return ret;
-+
-+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
-+ dst_vq->drv_priv = ctx;
-+ dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
-+ dst_vq->ops = &bcm2835_codec_qops;
-+ dst_vq->mem_ops = &vb2_dma_contig_memops;
-+ dst_vq->dev = &ctx->dev->pdev->dev;
-+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-+ dst_vq->lock = &ctx->dev->dev_mutex;
-+
-+ return vb2_queue_init(dst_vq);
-+}
-+
-+/*
-+ * File operations
-+ */
-+static int bcm2835_codec_open(struct file *file)
-+{
-+ struct bcm2835_codec_dev *dev = video_drvdata(file);
-+ struct bcm2835_codec_ctx *ctx = NULL;
-+ struct v4l2_ctrl_handler *hdl;
-+ int rc = 0;
-+
-+ v4l2_dbg(1, debug, &dev->v4l2_dev, "Creating instance for %s\n",
-+ dev->decode ? "decode" : "encode");
-+ if (mutex_lock_interruptible(&dev->dev_mutex)) {
-+ v4l2_err(&dev->v4l2_dev, "Mutex fail\n");
-+ return -ERESTARTSYS;
-+ }
-+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-+ if (!ctx) {
-+ rc = -ENOMEM;
-+ goto open_unlock;
-+ }
-+
-+ ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev->decode, false);
-+ ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev->decode, true);
-+ if (dev->decode) {
-+ /*
-+ * Input width and height are irrelevant as they will be defined
-+ * by the bitstream not the format. Required by V4L2 though.
-+ */
-+ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
-+ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
-+ ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT;
-+ ctx->q_data[V4L2_M2M_SRC].bytesperline = 0;
-+ ctx->q_data[V4L2_M2M_SRC].sizeimage =
-+ DEF_COMP_BUF_SIZE_720P_OR_LESS;
-+
-+ ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
-+ ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
-+ 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].sizeimage =
-+ get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline,
-+ ctx->q_data[V4L2_M2M_DST].height,
-+ ctx->q_data[V4L2_M2M_DST].fmt);
-+ } else {
-+ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
-+ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
-+ 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].sizeimage =
-+ get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline,
-+ ctx->q_data[V4L2_M2M_SRC].height,
-+ ctx->q_data[V4L2_M2M_SRC].fmt);
-+
-+ ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
-+ ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
-+ ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
-+ ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT;
-+ ctx->q_data[V4L2_M2M_DST].sizeimage =
-+ DEF_COMP_BUF_SIZE_720P_OR_LESS;
-+ }
-+
-+ ctx->colorspace = V4L2_COLORSPACE_REC709;
-+ ctx->bitrate = 10 * 1000 * 1000;
-+
-+ /* Initialise V4L2 contexts */
-+ v4l2_fh_init(&ctx->fh, video_devdata(file));
-+ file->private_data = &ctx->fh;
-+ ctx->dev = dev;
-+ hdl = &ctx->hdl;
-+ if (!dev->decode) {
-+ /* Encode controls */
-+ v4l2_ctrl_handler_init(hdl, 6);
-+
-+ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
-+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
-+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
-+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
-+ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
-+ V4L2_CID_MPEG_VIDEO_BITRATE,
-+ 25 * 1000, 25 * 1000 * 1000,
-+ 25 * 1000, 10 * 1000 * 1000);
-+ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
-+ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER,
-+ 0, 1,
-+ 1, 0);
-+ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
-+ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
-+ 0, 0x7FFFFFFF,
-+ 1, 60);
-+ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
-+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
-+ V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
-+ ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
-+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2)),
-+ V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
-+ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
-+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
-+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
-+ ~(BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
-+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
-+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
-+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
-+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
-+ if (hdl->error) {
-+ rc = hdl->error;
-+ goto free_ctrl_handler;
-+ }
-+ ctx->fh.ctrl_handler = hdl;
-+ v4l2_ctrl_handler_setup(hdl);
-+ }
-+
-+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
-+
-+ if (IS_ERR(ctx->fh.m2m_ctx)) {
-+ rc = PTR_ERR(ctx->fh.m2m_ctx);
-+
-+ goto free_ctrl_handler;
-+ }
-+
-+ /* Set both queues as buffered as we have buffering in the VPU. That
-+ * means that we will be scheduled whenever either an input or output
-+ * buffer is available (otherwise one of each are required).
-+ */
-+ v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
-+ v4l2_m2m_set_dst_buffered(ctx->fh.m2m_ctx, true);
-+
-+ v4l2_fh_add(&ctx->fh);
-+ atomic_inc(&dev->num_inst);
-+
-+ mutex_unlock(&dev->dev_mutex);
-+ return 0;
-+
-+free_ctrl_handler:
-+ v4l2_ctrl_handler_free(hdl);
-+ kfree(ctx);
-+open_unlock:
-+ mutex_unlock(&dev->dev_mutex);
-+ return rc;
-+}
-+
-+static int bcm2835_codec_release(struct file *file)
-+{
-+ struct bcm2835_codec_dev *dev = video_drvdata(file);
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+
-+ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: Releasing instance %p\n",
-+ __func__, ctx);
-+
-+ v4l2_fh_del(&ctx->fh);
-+ v4l2_fh_exit(&ctx->fh);
-+ v4l2_ctrl_handler_free(&ctx->hdl);
-+ mutex_lock(&dev->dev_mutex);
-+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
-+
-+ if (ctx->component)
-+ vchiq_mmal_component_finalise(dev->instance, ctx->component);
-+
-+ mutex_unlock(&dev->dev_mutex);
-+ kfree(ctx);
-+
-+ atomic_dec(&dev->num_inst);
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_file_operations bcm2835_codec_fops = {
-+ .owner = THIS_MODULE,
-+ .open = bcm2835_codec_open,
-+ .release = bcm2835_codec_release,
-+ .poll = v4l2_m2m_fop_poll,
-+ .unlocked_ioctl = video_ioctl2,
-+ .mmap = v4l2_m2m_fop_mmap,
-+};
-+
-+static const struct video_device bcm2835_codec_videodev = {
-+ .name = MEM2MEM_NAME,
-+ .vfl_dir = VFL_DIR_M2M,
-+ .fops = &bcm2835_codec_fops,
-+ .ioctl_ops = &bcm2835_codec_ioctl_ops,
-+ .minor = -1,
-+ .release = video_device_release_empty,
-+};
-+
-+static const struct v4l2_m2m_ops m2m_ops = {
-+ .device_run = device_run,
-+ .job_ready = job_ready,
-+ .job_abort = job_abort,
-+};
-+
-+static int bcm2835_codec_create(struct platform_device *pdev,
-+ struct bcm2835_codec_dev **new_dev,
-+ bool decode)
-+{
-+ struct bcm2835_codec_dev *dev;
-+ struct video_device *vfd;
-+ struct vchiq_mmal_instance *instance = NULL;
-+ int video_nr;
-+ int ret;
-+
-+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
-+ if (!dev)
-+ return -ENOMEM;
-+
-+ dev->pdev = pdev;
-+
-+ dev->decode = decode;
-+
-+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-+ if (ret)
-+ return ret;
-+
-+ atomic_set(&dev->num_inst, 0);
-+ mutex_init(&dev->dev_mutex);
-+
-+ dev->vfd = bcm2835_codec_videodev;
-+ vfd = &dev->vfd;
-+ vfd->lock = &dev->dev_mutex;
-+ vfd->v4l2_dev = &dev->v4l2_dev;
-+
-+ if (dev->decode) {
-+ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
-+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
-+ video_nr = decode_video_nr;
-+ } else {
-+ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
-+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
-+ video_nr = encode_video_nr;
-+ }
-+
-+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
-+ if (ret) {
-+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
-+ goto unreg_dev;
-+ }
-+
-+ video_set_drvdata(vfd, dev);
-+ snprintf(vfd->name, sizeof(vfd->name), "%s",
-+ bcm2835_codec_videodev.name);
-+ v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n",
-+ vfd->num);
-+
-+ *new_dev = dev;
-+
-+ dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
-+ if (IS_ERR(dev->m2m_dev)) {
-+ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
-+ ret = PTR_ERR(dev->m2m_dev);
-+ goto err_m2m;
-+ }
-+
-+ ret = vchiq_mmal_init(&instance);
-+ if (ret < 0)
-+ goto err_m2m;
-+ dev->instance = instance;
-+
-+ v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s codec\n",
-+ dev->decode ? "decode" : "encode");
-+ return 0;
-+
-+err_m2m:
-+ v4l2_m2m_release(dev->m2m_dev);
-+ video_unregister_device(&dev->vfd);
-+unreg_dev:
-+ v4l2_device_unregister(&dev->v4l2_dev);
-+
-+ return ret;
-+}
-+
-+static int bcm2835_codec_destroy(struct bcm2835_codec_dev *dev)
-+{
-+ if (!dev)
-+ return -ENODEV;
-+
-+ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
-+ v4l2_m2m_release(dev->m2m_dev);
-+ video_unregister_device(&dev->vfd);
-+ v4l2_device_unregister(&dev->v4l2_dev);
-+
-+ return 0;
-+}
-+
-+static int bcm2835_codec_probe(struct platform_device *pdev)
-+{
-+ struct bcm2835_codec_driver *drv;
-+ int ret = 0;
-+
-+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
-+ if (!drv)
-+ return -ENOMEM;
-+
-+ ret = bcm2835_codec_create(pdev, &drv->encode, false);
-+ if (ret)
-+ goto out;
-+
-+ ret = bcm2835_codec_create(pdev, &drv->decode, true);
-+ if (ret)
-+ goto out;
-+
-+ platform_set_drvdata(pdev, drv);
-+
-+ return 0;
-+
-+out:
-+ if (drv->encode) {
-+ bcm2835_codec_destroy(drv->encode);
-+ drv->encode = NULL;
-+ }
-+ return ret;
-+}
-+
-+static int bcm2835_codec_remove(struct platform_device *pdev)
-+{
-+ struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev);
-+
-+ bcm2835_codec_destroy(drv->encode);
-+
-+ bcm2835_codec_destroy(drv->decode);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver bcm2835_v4l2_codec_driver = {
-+ .probe = bcm2835_codec_probe,
-+ .remove = bcm2835_codec_remove,
-+ .driver = {
-+ .name = "bcm2835-codec",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+module_platform_driver(bcm2835_v4l2_codec_driver);
-+
-+MODULE_DESCRIPTION("BCM2835 codec V4L2 driver");
-+MODULE_LICENSE("GPL");
-+MODULE_VERSION("0.0.1");
-+MODULE_ALIAS("platform:bcm2835-codec");
--- /dev/null
+From 69c5c6d62b457ee88e55c4090dc09c0441b059f2 Mon Sep 17 00:00:00 2001
+Date: Fri, 26 Oct 2018 15:19:40 +0100
+Subject: [PATCH] staging: vchiq_arm: Register vcsm-cma as a platform
+ driver
+
+Following the same pattern as bcm2835-camera and bcm2835-audio,
+register the vcsm-cma driver as a platform driver
+
+---
+ drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -171,6 +171,7 @@ static struct device *vchiq_dev;
+ static DEFINE_SPINLOCK(msg_queue_spinlock);
+ static struct platform_device *bcm2835_camera;
+ static struct platform_device *bcm2835_codec;
++static struct platform_device *vcsm_cma;
+
+ static const char *const ioctl_names[] = {
+ "CONNECT",
+@@ -3654,6 +3655,9 @@ static int vchiq_probe(struct platform_d
+ VCHIQ_VERSION, VCHIQ_VERSION_MIN,
+ MAJOR(vchiq_devid), MINOR(vchiq_devid));
+
++ vcsm_cma = vchiq_register_child(pdev, "vcsm-cma");
++ if (IS_ERR(vcsm_cma))
++ vcsm_cma = NULL;
+ bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
+ if (IS_ERR(bcm2835_camera))
+ bcm2835_camera = NULL;
--- /dev/null
+From 69e42b6209062b9cd3fc9aea8fb53ed703509e51 Mon Sep 17 00:00:00 2001
+Date: Fri, 30 Nov 2018 16:00:54 +0000
+Subject: [PATCH] staging: bcm2835-camera: Fix stride on RGB3/BGR3
+ formats
+
+RGB3/BGR3 end up being 3 bytes per pixel, which meant that
+the alignment code ended up trying to align using bitmasking
+with a mask of 96.
+That doesn't work, so switch to an arithmetic alignment for
+those formats.
+
+---
+ .../bcm2835-camera/bcm2835-camera.c | 26 ++++++++++++++-----
+ 1 file changed, 20 insertions(+), 6 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -1008,13 +1008,27 @@ static int vidioc_try_fmt_vid_cap(struct
+ 1, 0);
+ f->fmt.pix.bytesperline = f->fmt.pix.width * mfmt->ybbp;
+ if (!mfmt->remove_padding) {
+- int align_mask = ((32 * mfmt->depth) >> 3) - 1;
+- /* GPU isn't removing padding, so stride is aligned to 32 */
+- f->fmt.pix.bytesperline =
+- (f->fmt.pix.bytesperline + align_mask) & ~align_mask;
++ if (mfmt->depth == 24) {
++ /*
++ * 24bpp is a pain as we can't use simple masking.
++ * Min stride is width aligned to 16, times 24bpp.
++ */
++ f->fmt.pix.bytesperline =
++ ((f->fmt.pix.width + 15) & ~15) * 3;
++ } else {
++ /*
++ * GPU isn't removing padding, so stride is aligned to
++ * 32
++ */
++ int align_mask = ((32 * mfmt->depth) >> 3) - 1;
++
++ f->fmt.pix.bytesperline =
++ (f->fmt.pix.bytesperline + align_mask) &
++ ~align_mask;
++ }
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+- "Not removing padding, so bytes/line = %d, (align_mask %d)\n",
+- f->fmt.pix.bytesperline, align_mask);
++ "Not removing padding, so bytes/line = %d\n",
++ f->fmt.pix.bytesperline);
+ }
+
+ /* Image buffer has to be padded to allow for alignment, even though
+++ /dev/null
-From b28dac3003b4c756b72201bb1d83647e33e2f4f1 Mon Sep 17 00:00:00 2001
-Date: Fri, 26 Oct 2018 15:14:16 +0100
-Subject: [PATCH] staging: vchiq_arm: Register bcm2835-codec as a
- platform driver
-
-Following the same pattern as bcm2835-camera and bcm2835-audio,
-register the V4L2 codec driver as a platform driver
-
----
- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -170,6 +170,7 @@ static struct class *vchiq_class;
- static struct device *vchiq_dev;
- static DEFINE_SPINLOCK(msg_queue_spinlock);
- static struct platform_device *bcm2835_camera;
-+static struct platform_device *bcm2835_codec;
-
- static const char *const ioctl_names[] = {
- "CONNECT",
-@@ -3656,6 +3657,9 @@ static int vchiq_probe(struct platform_d
- bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
- if (IS_ERR(bcm2835_camera))
- bcm2835_camera = NULL;
-+ bcm2835_codec = vchiq_register_child(pdev, "bcm2835-codec");
-+ if (IS_ERR(bcm2835_codec))
-+ bcm2835_codec = NULL;
-
- return 0;
-
+++ /dev/null
-From 69c5c6d62b457ee88e55c4090dc09c0441b059f2 Mon Sep 17 00:00:00 2001
-Date: Fri, 26 Oct 2018 15:19:40 +0100
-Subject: [PATCH] staging: vchiq_arm: Register vcsm-cma as a platform
- driver
-
-Following the same pattern as bcm2835-camera and bcm2835-audio,
-register the vcsm-cma driver as a platform driver
-
----
- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -171,6 +171,7 @@ static struct device *vchiq_dev;
- static DEFINE_SPINLOCK(msg_queue_spinlock);
- static struct platform_device *bcm2835_camera;
- static struct platform_device *bcm2835_codec;
-+static struct platform_device *vcsm_cma;
-
- static const char *const ioctl_names[] = {
- "CONNECT",
-@@ -3654,6 +3655,9 @@ static int vchiq_probe(struct platform_d
- VCHIQ_VERSION, VCHIQ_VERSION_MIN,
- MAJOR(vchiq_devid), MINOR(vchiq_devid));
-
-+ vcsm_cma = vchiq_register_child(pdev, "vcsm-cma");
-+ if (IS_ERR(vcsm_cma))
-+ vcsm_cma = NULL;
- bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
- if (IS_ERR(bcm2835_camera))
- bcm2835_camera = NULL;
--- /dev/null
+From 38e82adecd1b7ae790a827c29e954d35a2bbee98 Mon Sep 17 00:00:00 2001
+Date: Mon, 3 Sep 2018 21:51:51 +0200
+Subject: [PATCH] tpm: Make SECURITYFS a weak dependency
+
+commit 2f7d8dbb11287cbe9da6380ca14ed5d38c9ed91f upstream.
+
+While having SECURITYFS enabled for the tpm subsystem is beneficial in
+most cases, it is not strictly necessary to have it enabled at all.
+Especially on platforms without any boot firmware integration of the TPM
+(e.g. raspberry pi) it does not add any value for the tpm subsystem,
+as there is no eventlog present.
+
+By turning it from 'select' to 'imply' it still gets selected per
+default, but enables users who want to save some kb of ram by turning
+SECURITYFS off.
+
+---
+ drivers/char/tpm/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/char/tpm/Kconfig
++++ b/drivers/char/tpm/Kconfig
+@@ -5,7 +5,7 @@
+ menuconfig TCG_TPM
+ tristate "TPM Hardware Support"
+ depends on HAS_IOMEM
+- select SECURITYFS
++ imply SECURITYFS
+ select CRYPTO
+ select CRYPTO_HASH_INFO
+ ---help---
--- /dev/null
+From 82298c670f768f392f48526fe7c8a93682e83998 Mon Sep 17 00:00:00 2001
+Date: Thu, 14 Jun 2018 22:51:24 +0200
+Subject: [PATCH] Add overlay for SLB9760 Iridium /LetsTrust TPM
+
+Device Tree overlay for the Infineon SLB9670 Trusted Platform Module add-on
+boards, which can be used as a secure key storage and hwrng.
+available as "Iridium SLB9670" by Infineon and "LetsTrust TPM" by
+pi3g.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 8 ++++
+ .../boot/dts/overlays/tpm-slb9670-overlay.dts | 44 +++++++++++++++++++
+ 3 files changed, 53 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -137,6 +137,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ tc358743.dtbo \
+ tc358743-audio.dtbo \
+ tinylcd35.dtbo \
++ tpm-slb9670.dtbo \
+ uart0.dtbo \
+ uart1.dtbo \
+ upstream.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2012,6 +2012,14 @@ Params: speed Display
+ dtoverlay=tinylcd35,touch,touchgpio=3
+
+
++Name: tpm-slb9670
++Info: Enables support for Infineon SLB9670 Trusted Platform Module add-on
++ boards, which can be used as a secure key storage and hwrng,
++ available as "Iridium SLB9670" by Infineon and "LetsTrust TPM" by pi3g.
++Load: dtoverlay=tpm-slb9670
++Params: <None>
++
++
+ Name: uart0
+ Info: Change the pin usage of uart0
+ Load: dtoverlay=uart0,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts
+@@ -0,0 +1,44 @@
++/*
++ * Device Tree overlay for the Infineon SLB9670 Trusted Platform Module add-on
++ * boards, which can be used as a secure key storage and hwrng.
++ * available as "Iridium SLB9670" by Infineon and "LetsTrust TPM" by pi3g.
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ slb9670: slb9670@1 {
++ compatible = "infineon,slb9670";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <32000000>;
++ status = "okay";
++ };
++
++ };
++ };
++};
+++ /dev/null
-From 69e42b6209062b9cd3fc9aea8fb53ed703509e51 Mon Sep 17 00:00:00 2001
-Date: Fri, 30 Nov 2018 16:00:54 +0000
-Subject: [PATCH] staging: bcm2835-camera: Fix stride on RGB3/BGR3
- formats
-
-RGB3/BGR3 end up being 3 bytes per pixel, which meant that
-the alignment code ended up trying to align using bitmasking
-with a mask of 96.
-That doesn't work, so switch to an arithmetic alignment for
-those formats.
-
----
- .../bcm2835-camera/bcm2835-camera.c | 26 ++++++++++++++-----
- 1 file changed, 20 insertions(+), 6 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -1008,13 +1008,27 @@ static int vidioc_try_fmt_vid_cap(struct
- 1, 0);
- f->fmt.pix.bytesperline = f->fmt.pix.width * mfmt->ybbp;
- if (!mfmt->remove_padding) {
-- int align_mask = ((32 * mfmt->depth) >> 3) - 1;
-- /* GPU isn't removing padding, so stride is aligned to 32 */
-- f->fmt.pix.bytesperline =
-- (f->fmt.pix.bytesperline + align_mask) & ~align_mask;
-+ if (mfmt->depth == 24) {
-+ /*
-+ * 24bpp is a pain as we can't use simple masking.
-+ * Min stride is width aligned to 16, times 24bpp.
-+ */
-+ f->fmt.pix.bytesperline =
-+ ((f->fmt.pix.width + 15) & ~15) * 3;
-+ } else {
-+ /*
-+ * GPU isn't removing padding, so stride is aligned to
-+ * 32
-+ */
-+ int align_mask = ((32 * mfmt->depth) >> 3) - 1;
-+
-+ f->fmt.pix.bytesperline =
-+ (f->fmt.pix.bytesperline + align_mask) &
-+ ~align_mask;
-+ }
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-- "Not removing padding, so bytes/line = %d, (align_mask %d)\n",
-- f->fmt.pix.bytesperline, align_mask);
-+ "Not removing padding, so bytes/line = %d\n",
-+ f->fmt.pix.bytesperline);
- }
-
- /* Image buffer has to be padded to allow for alignment, even though
--- /dev/null
+From e740bd2cc3fcd632fcd6c8881b1fc671bcde5914 Mon Sep 17 00:00:00 2001
+Date: Wed, 5 Dec 2018 10:59:11 +0100
+Subject: [PATCH] ASoC: add driver for 3Dlab Nano soundcard (#2758)
+
+---
+ .../overlays/3dlab-nano-player-overlay.dts | 32 ++
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 +
+ sound/soc/bcm/3dlab-nano-player.c | 370 ++++++++++++++++++
+ sound/soc/bcm/Kconfig | 6 +
+ sound/soc/bcm/Makefile | 2 +
+ 8 files changed, 419 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/3dlab-nano-player-overlay.dts
+ create mode 100644 sound/soc/bcm/3dlab-nano-player.c
+
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/3dlab-nano-player-overlay.dts
+@@ -0,0 +1,32 @@
++// Definitions for 3Dlab Nano Player
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ nano-player@41 {
++ compatible = "3dlab,nano-player";
++ reg = <0x41>;
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++ };
++};
++
++// EOF
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -1,6 +1,7 @@
+ # Overlays for the Raspberry Pi platform
+
+ dtbo-$(CONFIG_ARCH_BCM2835) += \
++ 3dlab-nano-player.dtbo \
+ adau1977-adc.dtbo \
+ adau7002-simple.dtbo \
+ ads1015.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -199,6 +199,12 @@ Params:
+ and the other i2c baudrate parameters.
+
+
++Name: 3dlab-nano-player
++Info: Configures the 3Dlab Nano Player
++Load: dtoverlay=3dlab-nano-player
++Params: <None>
++
++
+ Name: adau1977-adc
+ Info: Overlay for activation of ADAU1977 ADC codec over I2C for control
+ and I2S for data.
+--- /dev/null
++++ b/sound/soc/bcm/3dlab-nano-player.c
+@@ -0,0 +1,370 @@
++/*
++ * 3Dlab Nano Player ALSA SoC Audio driver.
++ *
++ * Copyright (C) 2018 3Dlab.
++ *
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <sound/soc.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/control.h>
++
++#define NANO_ID 0x00
++#define NANO_VER 0x01
++#define NANO_CFG 0x02
++#define NANO_STATUS 0x03
++#define NANO_SPI_ADDR 0x04
++#define NANO_SPI_DATA 0x05
++
++#define NANO_ID_VAL 0x3D
++#define NANO_CFG_OFF 0x00
++#define NANO_CFG_MULT1 0
++#define NANO_CFG_MULT2 1
++#define NANO_CFG_MULT4 2
++#define NANO_CFG_MULT8 3
++#define NANO_CFG_MULT16 4
++#define NANO_CFG_CLK22 0
++#define NANO_CFG_CLK24 BIT(3)
++#define NANO_CFG_DSD BIT(4)
++#define NANO_CFG_ENA BIT(5)
++#define NANO_CFG_BLINK BIT(6)
++#define NANO_STATUS_P1 BIT(0)
++#define NANO_STATUS_P2 BIT(1)
++#define NANO_STATUS_FLG BIT(2)
++#define NANO_STATUS_CLK BIT(3)
++#define NANO_SPI_READ 0
++#define NANO_SPI_WRITE BIT(5)
++
++#define NANO_DAC_CTRL1 0x00
++#define NANO_DAC_CTRL2 0x01
++#define NANO_DAC_CTRL3 0x02
++#define NANO_DAC_LATT 0x03
++#define NANO_DAC_RATT 0x04
++
++#define NANO_CTRL2_VAL 0x22
++
++static int nano_player_spi_write(struct regmap *map,
++ unsigned int reg, unsigned int val)
++{
++ /* indirect register access */
++ regmap_write(map, NANO_SPI_DATA, val);
++ regmap_write(map, NANO_SPI_ADDR, reg | NANO_SPI_WRITE);
++ return 0;
++}
++
++static int nano_player_ctrl_info(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ /* describe control element */
++ if (strstr(kcontrol->id.name, "Volume")) {
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++ uinfo->count = 1;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = 100;
++ } else {
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
++ uinfo->count = 1;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = 1;
++ }
++
++ return 0;
++}
++
++static int nano_player_ctrl_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ /* program control value to hardware */
++ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
++ struct regmap *regmap = snd_soc_card_get_drvdata(card);
++
++ if (strstr(kcontrol->id.name, "Volume")) {
++ unsigned int vol = ucontrol->value.integer.value[0];
++ unsigned int att = 255 - (2 * (100 - vol));
++
++ nano_player_spi_write(regmap, NANO_DAC_LATT, att);
++ nano_player_spi_write(regmap, NANO_DAC_RATT, att);
++ kcontrol->private_value = vol;
++ } else {
++ unsigned int mute = ucontrol->value.integer.value[0];
++ unsigned int reg = NANO_CTRL2_VAL | mute;
++
++ nano_player_spi_write(regmap, NANO_DAC_CTRL2, reg);
++ kcontrol->private_value = mute;
++ }
++ return 0;
++}
++
++static int nano_player_ctrl_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ /* return last programmed value */
++ ucontrol->value.integer.value[0] = kcontrol->private_value;
++ return 0;
++}
++
++#define SOC_NANO_PLAYER_CTRL(xname) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
++ .info = nano_player_ctrl_info, \
++ .put = nano_player_ctrl_put, \
++ .get = nano_player_ctrl_get }
++
++static const struct snd_kcontrol_new nano_player_controls[] = {
++ SOC_NANO_PLAYER_CTRL("Master Playback Volume"),
++ SOC_NANO_PLAYER_CTRL("Master Playback Switch"),
++};
++
++static const unsigned int nano_player_rates[] = {
++ 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000,
++ 705600, 768000 /* only possible with fast clocks */
++};
++
++static struct snd_pcm_hw_constraint_list nano_player_constraint_rates = {
++ .list = nano_player_rates,
++ .count = ARRAY_SIZE(nano_player_rates),
++};
++
++static int nano_player_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_card *card = rtd->card;
++ struct regmap *regmap = snd_soc_card_get_drvdata(card);
++ struct snd_soc_pcm_stream *cpu = &rtd->cpu_dai->driver->playback;
++ struct snd_soc_pcm_stream *codec = &rtd->codec_dai->driver->playback;
++ unsigned int sample_bits = 32;
++ unsigned int val;
++
++ /* configure cpu dai */
++ cpu->formats |= SNDRV_PCM_FMTBIT_DSD_U32_LE;
++ cpu->rate_max = 768000;
++
++ /* configure dummy codec dai */
++ codec->rate_min = 44100;
++ codec->rates = SNDRV_PCM_RATE_KNOT;
++ codec->formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_DSD_U32_LE;
++
++ /* configure max supported rate */
++ regmap_read(regmap, NANO_STATUS, &val);
++ if (val & NANO_STATUS_CLK) {
++ dev_notice(card->dev, "Board with fast clocks installed\n");
++ codec->rate_max = 768000;
++ } else {
++ dev_notice(card->dev, "Board with normal clocks installed\n");
++ codec->rate_max = 384000;
++ }
++
++ /* frame length enforced by hardware */
++ return snd_soc_dai_set_bclk_ratio(rtd->cpu_dai, sample_bits * 2);
++}
++
++static int nano_player_startup(struct snd_pcm_substream *substream)
++{
++ return snd_pcm_hw_constraint_list(substream->runtime, 0,
++ SNDRV_PCM_HW_PARAM_RATE,
++ &nano_player_constraint_rates);
++}
++
++static int nano_player_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_card *card = rtd->card;
++ struct regmap *regmap = snd_soc_card_get_drvdata(card);
++ unsigned int config = NANO_CFG_ENA;
++ struct snd_mask *fmt;
++
++ /* configure PCM or DSD */
++ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
++ if (snd_mask_test(fmt, SNDRV_PCM_FORMAT_DSD_U32_LE)) {
++ /* embed DSD in PCM data */
++ snd_mask_none(fmt);
++ snd_mask_set(fmt, SNDRV_PCM_FORMAT_S32_LE);
++ /* enable DSD mode */
++ config |= NANO_CFG_DSD;
++ }
++
++ /* configure clocks */
++ switch (params_rate(params)) {
++ case 44100:
++ config |= NANO_CFG_MULT1 | NANO_CFG_CLK22;
++ break;
++ case 88200:
++ config |= NANO_CFG_MULT2 | NANO_CFG_CLK22;
++ break;
++ case 176400:
++ config |= NANO_CFG_MULT4 | NANO_CFG_CLK22;
++ break;
++ case 352800:
++ config |= NANO_CFG_MULT8 | NANO_CFG_CLK22;
++ break;
++ case 705600:
++ config |= NANO_CFG_MULT16 | NANO_CFG_CLK22;
++ break;
++ case 48000:
++ config |= NANO_CFG_MULT1 | NANO_CFG_CLK24;
++ break;
++ case 96000:
++ config |= NANO_CFG_MULT2 | NANO_CFG_CLK24;
++ break;
++ case 192000:
++ config |= NANO_CFG_MULT4 | NANO_CFG_CLK24;
++ break;
++ case 384000:
++ config |= NANO_CFG_MULT8 | NANO_CFG_CLK24;
++ break;
++ case 768000:
++ config |= NANO_CFG_MULT16 | NANO_CFG_CLK24;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ dev_dbg(card->dev, "Send CFG register 0x%02X\n", config);
++ return regmap_write(regmap, NANO_CFG, config);
++}
++
++static struct snd_soc_ops nano_player_ops = {
++ .startup = nano_player_startup,
++ .hw_params = nano_player_hw_params,
++};
++
++static struct snd_soc_dai_link nano_player_link = {
++ .name = "3Dlab Nano Player",
++ .stream_name = "3Dlab Nano Player HiFi",
++ .platform_name = "bcm2708-i2s.0",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_name = "snd-soc-dummy",
++ .codec_dai_name = "snd-soc-dummy-dai",
++ .dai_fmt = SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_CONT |
++ SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM,
++ .init = nano_player_init,
++ .ops = &nano_player_ops,
++};
++
++static const struct regmap_config nano_player_regmap = {
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = 128,
++ .cache_type = REGCACHE_RBTREE,
++};
++
++static int nano_player_card_probe(struct snd_soc_card *card)
++{
++ struct regmap *regmap = snd_soc_card_get_drvdata(card);
++ unsigned int val;
++
++ /* check hardware integrity */
++ regmap_read(regmap, NANO_ID, &val);
++ if (val != NANO_ID_VAL) {
++ dev_err(card->dev, "Invalid ID register 0x%02X\n", val);
++ return -ENODEV;
++ }
++
++ /* report version to the user */
++ regmap_read(regmap, NANO_VER, &val);
++ dev_notice(card->dev, "Started 3Dlab Nano Player driver (v%d)\n", val);
++
++ /* enable internal audio bus and blink status LED */
++ return regmap_write(regmap, NANO_CFG, NANO_CFG_ENA | NANO_CFG_BLINK);
++}
++
++static int nano_player_card_remove(struct snd_soc_card *card)
++{
++ /* disable internal audio bus */
++ struct regmap *regmap = snd_soc_card_get_drvdata(card);
++
++ return regmap_write(regmap, NANO_CFG, NANO_CFG_OFF);
++}
++
++static struct snd_soc_card nano_player_card = {
++ .name = "3Dlab_Nano_Player",
++ .owner = THIS_MODULE,
++ .dai_link = &nano_player_link,
++ .num_links = 1,
++ .controls = nano_player_controls,
++ .num_controls = ARRAY_SIZE(nano_player_controls),
++ .probe = nano_player_card_probe,
++ .remove = nano_player_card_remove,
++};
++
++static int nano_player_i2c_probe(struct i2c_client *i2c,
++ const struct i2c_device_id *id)
++{
++ struct regmap *regmap;
++ int ret;
++
++ regmap = devm_regmap_init_i2c(i2c, &nano_player_regmap);
++ if (IS_ERR(regmap)) {
++ ret = PTR_ERR(regmap);
++ dev_err(&i2c->dev, "Failed to init regmap %d\n", ret);
++ return ret;
++ }
++
++ if (i2c->dev.of_node) {
++ struct snd_soc_dai_link *dai = &nano_player_link;
++ struct device_node *node;
++
++ /* cpu handle configured by device tree */
++ node = of_parse_phandle(i2c->dev.of_node, "i2s-controller", 0);
++ if (node) {
++ dai->platform_name = NULL;
++ dai->platform_of_node = node;
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = node;
++ }
++ }
++
++ nano_player_card.dev = &i2c->dev;
++ snd_soc_card_set_drvdata(&nano_player_card, regmap);
++ ret = devm_snd_soc_register_card(&i2c->dev, &nano_player_card);
++
++ if (ret && ret != -EPROBE_DEFER)
++ dev_err(&i2c->dev, "Failed to register card %d\n", ret);
++
++ return ret;
++}
++
++static const struct of_device_id nano_player_of_match[] = {
++ { .compatible = "3dlab,nano-player", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, nano_player_of_match);
++
++static const struct i2c_device_id nano_player_i2c_id[] = {
++ { "nano-player", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, nano_player_i2c_id);
++
++static struct i2c_driver nano_player_i2c_driver = {
++ .probe = nano_player_i2c_probe,
++ .id_table = nano_player_i2c_id,
++ .driver = {
++ .name = "nano-player",
++ .owner = THIS_MODULE,
++ .of_match_table = nano_player_of_match,
++ },
++};
++
++module_i2c_driver(nano_player_i2c_driver);
++
++MODULE_DESCRIPTION("ASoC 3Dlab Nano Player driver");
++MODULE_LICENSE("GPL v2");
++
++/* EOF */
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -17,6 +17,12 @@ config SND_SOC_CYGNUS
+
+ If you don't know what to do here, say N.
+
++config SND_BCM2708_SOC_3DLAB_NANO_PLAYER
++ tristate "Support for 3Dlab Nano Player"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ help
++ Say Y or M if you want to add support for 3Dlab Nano Player.
++
+ config SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD
+ tristate "Support for Google voiceHAT soundcard"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-
+ snd-soc-googlevoicehat-codec-objs := googlevoicehat-codec.o
+
+ # BCM2708 Machine Support
++snd-soc-3dlab-nano-player-objs := 3dlab-nano-player.o
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
+ snd-soc-justboom-dac-objs := justboom-dac.o
+ snd-soc-rpi-cirrus-objs := rpi-cirrus.o
+@@ -31,6 +32,7 @@ snd-soc-fe-pi-audio-objs := fe-pi-audio.
+ snd-soc-rpi-simple-soundcard-objs := rpi-simple-soundcard.o
+ snd-soc-rpi-wm8804-soundcard-objs := rpi-wm8804-soundcard.o
+
++obj-$(CONFIG_SND_BCM2708_SOC_3DLAB_NANO_PLAYER) += snd-soc-3dlab-nano-player.o
+ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
+++ /dev/null
-From 38e82adecd1b7ae790a827c29e954d35a2bbee98 Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Sep 2018 21:51:51 +0200
-Subject: [PATCH] tpm: Make SECURITYFS a weak dependency
-
-commit 2f7d8dbb11287cbe9da6380ca14ed5d38c9ed91f upstream.
-
-While having SECURITYFS enabled for the tpm subsystem is beneficial in
-most cases, it is not strictly necessary to have it enabled at all.
-Especially on platforms without any boot firmware integration of the TPM
-(e.g. raspberry pi) it does not add any value for the tpm subsystem,
-as there is no eventlog present.
-
-By turning it from 'select' to 'imply' it still gets selected per
-default, but enables users who want to save some kb of ram by turning
-SECURITYFS off.
-
----
- drivers/char/tpm/Kconfig | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/char/tpm/Kconfig
-+++ b/drivers/char/tpm/Kconfig
-@@ -5,7 +5,7 @@
- menuconfig TCG_TPM
- tristate "TPM Hardware Support"
- depends on HAS_IOMEM
-- select SECURITYFS
-+ imply SECURITYFS
- select CRYPTO
- select CRYPTO_HASH_INFO
- ---help---
+++ /dev/null
-From 82298c670f768f392f48526fe7c8a93682e83998 Mon Sep 17 00:00:00 2001
-Date: Thu, 14 Jun 2018 22:51:24 +0200
-Subject: [PATCH] Add overlay for SLB9760 Iridium /LetsTrust TPM
-
-Device Tree overlay for the Infineon SLB9670 Trusted Platform Module add-on
-boards, which can be used as a secure key storage and hwrng.
-available as "Iridium SLB9670" by Infineon and "LetsTrust TPM" by
-pi3g.
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 8 ++++
- .../boot/dts/overlays/tpm-slb9670-overlay.dts | 44 +++++++++++++++++++
- 3 files changed, 53 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -137,6 +137,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- tc358743.dtbo \
- tc358743-audio.dtbo \
- tinylcd35.dtbo \
-+ tpm-slb9670.dtbo \
- uart0.dtbo \
- uart1.dtbo \
- upstream.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -2012,6 +2012,14 @@ Params: speed Display
- dtoverlay=tinylcd35,touch,touchgpio=3
-
-
-+Name: tpm-slb9670
-+Info: Enables support for Infineon SLB9670 Trusted Platform Module add-on
-+ boards, which can be used as a secure key storage and hwrng,
-+ available as "Iridium SLB9670" by Infineon and "LetsTrust TPM" by pi3g.
-+Load: dtoverlay=tpm-slb9670
-+Params: <None>
-+
-+
- Name: uart0
- Info: Change the pin usage of uart0
- Load: dtoverlay=uart0,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts
-@@ -0,0 +1,44 @@
-+/*
-+ * Device Tree overlay for the Infineon SLB9670 Trusted Platform Module add-on
-+ * boards, which can be used as a secure key storage and hwrng.
-+ * available as "Iridium SLB9670" by Infineon and "LetsTrust TPM" by pi3g.
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spidev1>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ slb9670: slb9670@1 {
-+ compatible = "infineon,slb9670";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <32000000>;
-+ status = "okay";
-+ };
-+
-+ };
-+ };
-+};
--- /dev/null
+From f2c24ce7e03d059fa9f674d8ebf6286e8f0c38b6 Mon Sep 17 00:00:00 2001
+Date: Wed, 5 Dec 2018 11:56:40 +0000
+Subject: [PATCH] overlays: Update README with removal of lirc-rpi
+
+---
+ arch/arm/boot/dts/overlays/README | 57 ++++++++++++-------------------
+ 1 file changed, 21 insertions(+), 36 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -56,23 +56,29 @@ have its contents deleted (or commented
+ Using Overlays
+ ==============
+
+-Overlays are loaded using the "dtoverlay" directive. As an example, consider
+-the popular lirc-rpi module, the Linux Infrared Remote Control driver. In the
+-pre-DT world this would be loaded from /etc/modules, with an explicit
+-"modprobe lirc-rpi" command, or programmatically by lircd. With DT enabled,
+-this becomes a line in config.txt:
+-
+- dtoverlay=lirc-rpi
+-
+-This causes the file /boot/overlays/lirc-rpi.dtbo to be loaded. By
+-default it will use GPIOs 17 (out) and 18 (in), but this can be modified using
+-DT parameters:
+-
+- dtoverlay=lirc-rpi,gpio_out_pin=17,gpio_in_pin=13
+-
+-Parameters always have default values, although in some cases (e.g. "w1-gpio")
+-it is necessary to provided multiple overlays in order to get the desired
+-behaviour. See the list of overlays below for a description of the parameters
++Overlays are loaded using the "dtoverlay" config.txt setting. As an example,
++consider I2C Real Time Clock drivers. In the pre-DT world these would be loaded
++by writing a magic string comprising a device identifier and an I2C address to
++a special file in /sys/class/i2c-adapter, having first loaded the driver for
++the I2C interface and the RTC device - something like this:
++
++ modprobe i2c-bcm2835
++ modprobe rtc-ds1307
++ echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
++
++With DT enabled, this becomes a line in config.txt:
++
++ dtoverlay=i2c-rtc,ds1307
++
++This causes the file /boot/overlays/i2c-rtc.dtbo to be loaded and a "node"
++describing the DS1307 I2C device to be added to the Device Tree for the Pi. By
++default it usees address 0x68, but this can be modified with an additional DT
++parameter:
++
++ dtoverlay=i2c-rtc,ds1307,addr=0x68
++
++Parameters usually have default values, although certain parameters are
++mandatory. See the list of overlays below for a description of the parameters
+ and their defaults.
+
+ The Overlay and Parameter Reference
+@@ -1135,29 +1141,8 @@ Params: <None>
+
+
+ Name: lirc-rpi
+-Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi)
+- Consult the module documentation for more details.
+-Load: dtoverlay=lirc-rpi,<param>=<val>
+-Params: gpio_out_pin GPIO for output (default "17")
+-
+- gpio_in_pin GPIO for input (default "18")
+-
+- gpio_in_pull Pull up/down/off on the input pin
+- (default "down")
+-
+- sense Override the IR receive auto-detection logic:
+- "0" = force active-high
+- "1" = force active-low
+- "-1" = use auto-detection
+- (default "-1")
+-
+- softcarrier Turn the software carrier "on" or "off"
+- (default "on")
+-
+- invert "on" = invert the output pin (default "off")
+-
+- debug "on" = enable additional debug messages
+- (default "off")
++Info: This overlay has been deprecated and removed - see gpio-ir
++Load: <Deprecated>
+
+
+ Name: ltc294x
+++ /dev/null
-From e740bd2cc3fcd632fcd6c8881b1fc671bcde5914 Mon Sep 17 00:00:00 2001
-Date: Wed, 5 Dec 2018 10:59:11 +0100
-Subject: [PATCH] ASoC: add driver for 3Dlab Nano soundcard (#2758)
-
----
- .../overlays/3dlab-nano-player-overlay.dts | 32 ++
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 6 +
- sound/soc/bcm/3dlab-nano-player.c | 370 ++++++++++++++++++
- sound/soc/bcm/Kconfig | 6 +
- sound/soc/bcm/Makefile | 2 +
- 8 files changed, 419 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/3dlab-nano-player-overlay.dts
- create mode 100644 sound/soc/bcm/3dlab-nano-player.c
-
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/3dlab-nano-player-overlay.dts
-@@ -0,0 +1,32 @@
-+// Definitions for 3Dlab Nano Player
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2c>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ nano-player@41 {
-+ compatible = "3dlab,nano-player";
-+ reg = <0x41>;
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
-+
-+// EOF
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -1,6 +1,7 @@
- # Overlays for the Raspberry Pi platform
-
- dtbo-$(CONFIG_ARCH_BCM2835) += \
-+ 3dlab-nano-player.dtbo \
- adau1977-adc.dtbo \
- adau7002-simple.dtbo \
- ads1015.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -199,6 +199,12 @@ Params:
- and the other i2c baudrate parameters.
-
-
-+Name: 3dlab-nano-player
-+Info: Configures the 3Dlab Nano Player
-+Load: dtoverlay=3dlab-nano-player
-+Params: <None>
-+
-+
- Name: adau1977-adc
- Info: Overlay for activation of ADAU1977 ADC codec over I2C for control
- and I2S for data.
---- /dev/null
-+++ b/sound/soc/bcm/3dlab-nano-player.c
-@@ -0,0 +1,370 @@
-+/*
-+ * 3Dlab Nano Player ALSA SoC Audio driver.
-+ *
-+ * Copyright (C) 2018 3Dlab.
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/i2c.h>
-+#include <sound/soc.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/control.h>
-+
-+#define NANO_ID 0x00
-+#define NANO_VER 0x01
-+#define NANO_CFG 0x02
-+#define NANO_STATUS 0x03
-+#define NANO_SPI_ADDR 0x04
-+#define NANO_SPI_DATA 0x05
-+
-+#define NANO_ID_VAL 0x3D
-+#define NANO_CFG_OFF 0x00
-+#define NANO_CFG_MULT1 0
-+#define NANO_CFG_MULT2 1
-+#define NANO_CFG_MULT4 2
-+#define NANO_CFG_MULT8 3
-+#define NANO_CFG_MULT16 4
-+#define NANO_CFG_CLK22 0
-+#define NANO_CFG_CLK24 BIT(3)
-+#define NANO_CFG_DSD BIT(4)
-+#define NANO_CFG_ENA BIT(5)
-+#define NANO_CFG_BLINK BIT(6)
-+#define NANO_STATUS_P1 BIT(0)
-+#define NANO_STATUS_P2 BIT(1)
-+#define NANO_STATUS_FLG BIT(2)
-+#define NANO_STATUS_CLK BIT(3)
-+#define NANO_SPI_READ 0
-+#define NANO_SPI_WRITE BIT(5)
-+
-+#define NANO_DAC_CTRL1 0x00
-+#define NANO_DAC_CTRL2 0x01
-+#define NANO_DAC_CTRL3 0x02
-+#define NANO_DAC_LATT 0x03
-+#define NANO_DAC_RATT 0x04
-+
-+#define NANO_CTRL2_VAL 0x22
-+
-+static int nano_player_spi_write(struct regmap *map,
-+ unsigned int reg, unsigned int val)
-+{
-+ /* indirect register access */
-+ regmap_write(map, NANO_SPI_DATA, val);
-+ regmap_write(map, NANO_SPI_ADDR, reg | NANO_SPI_WRITE);
-+ return 0;
-+}
-+
-+static int nano_player_ctrl_info(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_info *uinfo)
-+{
-+ /* describe control element */
-+ if (strstr(kcontrol->id.name, "Volume")) {
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-+ uinfo->count = 1;
-+ uinfo->value.integer.min = 0;
-+ uinfo->value.integer.max = 100;
-+ } else {
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-+ uinfo->count = 1;
-+ uinfo->value.integer.min = 0;
-+ uinfo->value.integer.max = 1;
-+ }
-+
-+ return 0;
-+}
-+
-+static int nano_player_ctrl_put(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ /* program control value to hardware */
-+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
-+ struct regmap *regmap = snd_soc_card_get_drvdata(card);
-+
-+ if (strstr(kcontrol->id.name, "Volume")) {
-+ unsigned int vol = ucontrol->value.integer.value[0];
-+ unsigned int att = 255 - (2 * (100 - vol));
-+
-+ nano_player_spi_write(regmap, NANO_DAC_LATT, att);
-+ nano_player_spi_write(regmap, NANO_DAC_RATT, att);
-+ kcontrol->private_value = vol;
-+ } else {
-+ unsigned int mute = ucontrol->value.integer.value[0];
-+ unsigned int reg = NANO_CTRL2_VAL | mute;
-+
-+ nano_player_spi_write(regmap, NANO_DAC_CTRL2, reg);
-+ kcontrol->private_value = mute;
-+ }
-+ return 0;
-+}
-+
-+static int nano_player_ctrl_get(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ /* return last programmed value */
-+ ucontrol->value.integer.value[0] = kcontrol->private_value;
-+ return 0;
-+}
-+
-+#define SOC_NANO_PLAYER_CTRL(xname) \
-+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
-+ .info = nano_player_ctrl_info, \
-+ .put = nano_player_ctrl_put, \
-+ .get = nano_player_ctrl_get }
-+
-+static const struct snd_kcontrol_new nano_player_controls[] = {
-+ SOC_NANO_PLAYER_CTRL("Master Playback Volume"),
-+ SOC_NANO_PLAYER_CTRL("Master Playback Switch"),
-+};
-+
-+static const unsigned int nano_player_rates[] = {
-+ 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000,
-+ 705600, 768000 /* only possible with fast clocks */
-+};
-+
-+static struct snd_pcm_hw_constraint_list nano_player_constraint_rates = {
-+ .list = nano_player_rates,
-+ .count = ARRAY_SIZE(nano_player_rates),
-+};
-+
-+static int nano_player_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ struct snd_soc_card *card = rtd->card;
-+ struct regmap *regmap = snd_soc_card_get_drvdata(card);
-+ struct snd_soc_pcm_stream *cpu = &rtd->cpu_dai->driver->playback;
-+ struct snd_soc_pcm_stream *codec = &rtd->codec_dai->driver->playback;
-+ unsigned int sample_bits = 32;
-+ unsigned int val;
-+
-+ /* configure cpu dai */
-+ cpu->formats |= SNDRV_PCM_FMTBIT_DSD_U32_LE;
-+ cpu->rate_max = 768000;
-+
-+ /* configure dummy codec dai */
-+ codec->rate_min = 44100;
-+ codec->rates = SNDRV_PCM_RATE_KNOT;
-+ codec->formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_DSD_U32_LE;
-+
-+ /* configure max supported rate */
-+ regmap_read(regmap, NANO_STATUS, &val);
-+ if (val & NANO_STATUS_CLK) {
-+ dev_notice(card->dev, "Board with fast clocks installed\n");
-+ codec->rate_max = 768000;
-+ } else {
-+ dev_notice(card->dev, "Board with normal clocks installed\n");
-+ codec->rate_max = 384000;
-+ }
-+
-+ /* frame length enforced by hardware */
-+ return snd_soc_dai_set_bclk_ratio(rtd->cpu_dai, sample_bits * 2);
-+}
-+
-+static int nano_player_startup(struct snd_pcm_substream *substream)
-+{
-+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
-+ SNDRV_PCM_HW_PARAM_RATE,
-+ &nano_player_constraint_rates);
-+}
-+
-+static int nano_player_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_card *card = rtd->card;
-+ struct regmap *regmap = snd_soc_card_get_drvdata(card);
-+ unsigned int config = NANO_CFG_ENA;
-+ struct snd_mask *fmt;
-+
-+ /* configure PCM or DSD */
-+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-+ if (snd_mask_test(fmt, SNDRV_PCM_FORMAT_DSD_U32_LE)) {
-+ /* embed DSD in PCM data */
-+ snd_mask_none(fmt);
-+ snd_mask_set(fmt, SNDRV_PCM_FORMAT_S32_LE);
-+ /* enable DSD mode */
-+ config |= NANO_CFG_DSD;
-+ }
-+
-+ /* configure clocks */
-+ switch (params_rate(params)) {
-+ case 44100:
-+ config |= NANO_CFG_MULT1 | NANO_CFG_CLK22;
-+ break;
-+ case 88200:
-+ config |= NANO_CFG_MULT2 | NANO_CFG_CLK22;
-+ break;
-+ case 176400:
-+ config |= NANO_CFG_MULT4 | NANO_CFG_CLK22;
-+ break;
-+ case 352800:
-+ config |= NANO_CFG_MULT8 | NANO_CFG_CLK22;
-+ break;
-+ case 705600:
-+ config |= NANO_CFG_MULT16 | NANO_CFG_CLK22;
-+ break;
-+ case 48000:
-+ config |= NANO_CFG_MULT1 | NANO_CFG_CLK24;
-+ break;
-+ case 96000:
-+ config |= NANO_CFG_MULT2 | NANO_CFG_CLK24;
-+ break;
-+ case 192000:
-+ config |= NANO_CFG_MULT4 | NANO_CFG_CLK24;
-+ break;
-+ case 384000:
-+ config |= NANO_CFG_MULT8 | NANO_CFG_CLK24;
-+ break;
-+ case 768000:
-+ config |= NANO_CFG_MULT16 | NANO_CFG_CLK24;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ dev_dbg(card->dev, "Send CFG register 0x%02X\n", config);
-+ return regmap_write(regmap, NANO_CFG, config);
-+}
-+
-+static struct snd_soc_ops nano_player_ops = {
-+ .startup = nano_player_startup,
-+ .hw_params = nano_player_hw_params,
-+};
-+
-+static struct snd_soc_dai_link nano_player_link = {
-+ .name = "3Dlab Nano Player",
-+ .stream_name = "3Dlab Nano Player HiFi",
-+ .platform_name = "bcm2708-i2s.0",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .codec_name = "snd-soc-dummy",
-+ .codec_dai_name = "snd-soc-dummy-dai",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S |
-+ SND_SOC_DAIFMT_CONT |
-+ SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBM_CFM,
-+ .init = nano_player_init,
-+ .ops = &nano_player_ops,
-+};
-+
-+static const struct regmap_config nano_player_regmap = {
-+ .reg_bits = 8,
-+ .val_bits = 8,
-+ .max_register = 128,
-+ .cache_type = REGCACHE_RBTREE,
-+};
-+
-+static int nano_player_card_probe(struct snd_soc_card *card)
-+{
-+ struct regmap *regmap = snd_soc_card_get_drvdata(card);
-+ unsigned int val;
-+
-+ /* check hardware integrity */
-+ regmap_read(regmap, NANO_ID, &val);
-+ if (val != NANO_ID_VAL) {
-+ dev_err(card->dev, "Invalid ID register 0x%02X\n", val);
-+ return -ENODEV;
-+ }
-+
-+ /* report version to the user */
-+ regmap_read(regmap, NANO_VER, &val);
-+ dev_notice(card->dev, "Started 3Dlab Nano Player driver (v%d)\n", val);
-+
-+ /* enable internal audio bus and blink status LED */
-+ return regmap_write(regmap, NANO_CFG, NANO_CFG_ENA | NANO_CFG_BLINK);
-+}
-+
-+static int nano_player_card_remove(struct snd_soc_card *card)
-+{
-+ /* disable internal audio bus */
-+ struct regmap *regmap = snd_soc_card_get_drvdata(card);
-+
-+ return regmap_write(regmap, NANO_CFG, NANO_CFG_OFF);
-+}
-+
-+static struct snd_soc_card nano_player_card = {
-+ .name = "3Dlab_Nano_Player",
-+ .owner = THIS_MODULE,
-+ .dai_link = &nano_player_link,
-+ .num_links = 1,
-+ .controls = nano_player_controls,
-+ .num_controls = ARRAY_SIZE(nano_player_controls),
-+ .probe = nano_player_card_probe,
-+ .remove = nano_player_card_remove,
-+};
-+
-+static int nano_player_i2c_probe(struct i2c_client *i2c,
-+ const struct i2c_device_id *id)
-+{
-+ struct regmap *regmap;
-+ int ret;
-+
-+ regmap = devm_regmap_init_i2c(i2c, &nano_player_regmap);
-+ if (IS_ERR(regmap)) {
-+ ret = PTR_ERR(regmap);
-+ dev_err(&i2c->dev, "Failed to init regmap %d\n", ret);
-+ return ret;
-+ }
-+
-+ if (i2c->dev.of_node) {
-+ struct snd_soc_dai_link *dai = &nano_player_link;
-+ struct device_node *node;
-+
-+ /* cpu handle configured by device tree */
-+ node = of_parse_phandle(i2c->dev.of_node, "i2s-controller", 0);
-+ if (node) {
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = node;
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = node;
-+ }
-+ }
-+
-+ nano_player_card.dev = &i2c->dev;
-+ snd_soc_card_set_drvdata(&nano_player_card, regmap);
-+ ret = devm_snd_soc_register_card(&i2c->dev, &nano_player_card);
-+
-+ if (ret && ret != -EPROBE_DEFER)
-+ dev_err(&i2c->dev, "Failed to register card %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static const struct of_device_id nano_player_of_match[] = {
-+ { .compatible = "3dlab,nano-player", },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, nano_player_of_match);
-+
-+static const struct i2c_device_id nano_player_i2c_id[] = {
-+ { "nano-player", 0 },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(i2c, nano_player_i2c_id);
-+
-+static struct i2c_driver nano_player_i2c_driver = {
-+ .probe = nano_player_i2c_probe,
-+ .id_table = nano_player_i2c_id,
-+ .driver = {
-+ .name = "nano-player",
-+ .owner = THIS_MODULE,
-+ .of_match_table = nano_player_of_match,
-+ },
-+};
-+
-+module_i2c_driver(nano_player_i2c_driver);
-+
-+MODULE_DESCRIPTION("ASoC 3Dlab Nano Player driver");
-+MODULE_LICENSE("GPL v2");
-+
-+/* EOF */
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -17,6 +17,12 @@ config SND_SOC_CYGNUS
-
- If you don't know what to do here, say N.
-
-+config SND_BCM2708_SOC_3DLAB_NANO_PLAYER
-+ tristate "Support for 3Dlab Nano Player"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ help
-+ Say Y or M if you want to add support for 3Dlab Nano Player.
-+
- config SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD
- tristate "Support for Google voiceHAT soundcard"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -12,6 +12,7 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-
- snd-soc-googlevoicehat-codec-objs := googlevoicehat-codec.o
-
- # BCM2708 Machine Support
-+snd-soc-3dlab-nano-player-objs := 3dlab-nano-player.o
- snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
- snd-soc-justboom-dac-objs := justboom-dac.o
- snd-soc-rpi-cirrus-objs := rpi-cirrus.o
-@@ -31,6 +32,7 @@ snd-soc-fe-pi-audio-objs := fe-pi-audio.
- snd-soc-rpi-simple-soundcard-objs := rpi-simple-soundcard.o
- snd-soc-rpi-wm8804-soundcard-objs := rpi-wm8804-soundcard.o
-
-+obj-$(CONFIG_SND_BCM2708_SOC_3DLAB_NANO_PLAYER) += snd-soc-3dlab-nano-player.o
- obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
- obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
--- /dev/null
+From 81f6d4e84fd127cf0b31c9822a2beb9b298aa7bb Mon Sep 17 00:00:00 2001
+Date: Tue, 11 Dec 2018 15:18:02 +0000
+Subject: [PATCH] staging: bcm2835-camera: Check the error for
+ REPEAT_SEQ_HEADER (#2782)
+
+When handling for V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER was added
+the firmware would reject the setting if H264 hadn't already been
+selected. This was fixed in the firmware at that point, but to
+enable backwards compatibility the returned error was ignored.
+
+That was Dec 2013, so the chances of having a firmware that still
+has that issue is so close to zero that the workaround can be
+removed.
+
+---
+ drivers/staging/vc04_services/bcm2835-camera/controls.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -1100,7 +1100,7 @@ static const struct bm2835_mmal_v4l2_ctr
+ 0, 1, NULL,
+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
+ &ctrl_set_video_encode_param_output,
+- true /* Errors ignored as requires latest firmware to work */
++ false
+ },
+ {
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
--- /dev/null
+From d1cf5fb57ee5ee4512a93614d67d15af9c8070b2 Mon Sep 17 00:00:00 2001
+Date: Wed, 9 Jan 2019 14:51:01 +0100
+Subject: [PATCH] gpio-ir: change default pull configuration to up
+
+IR receivers like the TSOP series from Vishay and compatible ones
+have active-low open collector outputs with an internal pull up of
+about 30k (according to the TSOP datasheets).
+
+Activating a pull-down resistor on the GPIO will make it work against
+the pull-up in the IR receiver and brings the idle input voltage down
+to about 1.9V (measured on a RPi3B+ with a TSOP4438). While that's
+usually enough to make the RPi see a high signal it's certainly not
+optimal and may even fail when using an IR receiver with a weaker pull-up.
+
+Switching the default GPIO pull to "up" results in an input voltage
+level of about 3.3V and ensures that an idle state (high signal) will
+be detected if no IR receiver is attached.
+
+---
+ arch/arm/boot/dts/overlays/README | 2 +-
+ arch/arm/boot/dts/overlays/gpio-ir-overlay.dts | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -611,7 +611,7 @@ Load: dtoverlay=gpio-ir,<param>=<val>
+ Params: gpio_pin Input pin number. Default is 18.
+
+ gpio_pull Desired pull-up/down state (off, down, up)
+- Default is "down".
++ Default is "up".
+
+ rc-map-name Default rc keymap (can also be changed by
+ ir-keytable), defaults to "rc-rc6-mce"
+--- a/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
+@@ -30,7 +30,7 @@
+ gpio_ir_pins: gpio_ir_pins@12 {
+ brcm,pins = <18>; // pin 18
+ brcm,function = <0>; // in
+- brcm,pull = <1>; // down
++ brcm,pull = <2>; // up
+ };
+ };
+ };
+++ /dev/null
-From f2c24ce7e03d059fa9f674d8ebf6286e8f0c38b6 Mon Sep 17 00:00:00 2001
-Date: Wed, 5 Dec 2018 11:56:40 +0000
-Subject: [PATCH] overlays: Update README with removal of lirc-rpi
-
----
- arch/arm/boot/dts/overlays/README | 57 ++++++++++++-------------------
- 1 file changed, 21 insertions(+), 36 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -56,23 +56,29 @@ have its contents deleted (or commented
- Using Overlays
- ==============
-
--Overlays are loaded using the "dtoverlay" directive. As an example, consider
--the popular lirc-rpi module, the Linux Infrared Remote Control driver. In the
--pre-DT world this would be loaded from /etc/modules, with an explicit
--"modprobe lirc-rpi" command, or programmatically by lircd. With DT enabled,
--this becomes a line in config.txt:
--
-- dtoverlay=lirc-rpi
--
--This causes the file /boot/overlays/lirc-rpi.dtbo to be loaded. By
--default it will use GPIOs 17 (out) and 18 (in), but this can be modified using
--DT parameters:
--
-- dtoverlay=lirc-rpi,gpio_out_pin=17,gpio_in_pin=13
--
--Parameters always have default values, although in some cases (e.g. "w1-gpio")
--it is necessary to provided multiple overlays in order to get the desired
--behaviour. See the list of overlays below for a description of the parameters
-+Overlays are loaded using the "dtoverlay" config.txt setting. As an example,
-+consider I2C Real Time Clock drivers. In the pre-DT world these would be loaded
-+by writing a magic string comprising a device identifier and an I2C address to
-+a special file in /sys/class/i2c-adapter, having first loaded the driver for
-+the I2C interface and the RTC device - something like this:
-+
-+ modprobe i2c-bcm2835
-+ modprobe rtc-ds1307
-+ echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
-+
-+With DT enabled, this becomes a line in config.txt:
-+
-+ dtoverlay=i2c-rtc,ds1307
-+
-+This causes the file /boot/overlays/i2c-rtc.dtbo to be loaded and a "node"
-+describing the DS1307 I2C device to be added to the Device Tree for the Pi. By
-+default it usees address 0x68, but this can be modified with an additional DT
-+parameter:
-+
-+ dtoverlay=i2c-rtc,ds1307,addr=0x68
-+
-+Parameters usually have default values, although certain parameters are
-+mandatory. See the list of overlays below for a description of the parameters
- and their defaults.
-
- The Overlay and Parameter Reference
-@@ -1135,29 +1141,8 @@ Params: <None>
-
-
- Name: lirc-rpi
--Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi)
-- Consult the module documentation for more details.
--Load: dtoverlay=lirc-rpi,<param>=<val>
--Params: gpio_out_pin GPIO for output (default "17")
--
-- gpio_in_pin GPIO for input (default "18")
--
-- gpio_in_pull Pull up/down/off on the input pin
-- (default "down")
--
-- sense Override the IR receive auto-detection logic:
-- "0" = force active-high
-- "1" = force active-low
-- "-1" = use auto-detection
-- (default "-1")
--
-- softcarrier Turn the software carrier "on" or "off"
-- (default "on")
--
-- invert "on" = invert the output pin (default "off")
--
-- debug "on" = enable additional debug messages
-- (default "off")
-+Info: This overlay has been deprecated and removed - see gpio-ir
-+Load: <Deprecated>
-
-
- Name: ltc294x
--- /dev/null
+From dfd66230d2d538e7f290436d2952124d6eadeb3d Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Jan 2019 17:58:06 +0000
+Subject: [PATCH] firmware: raspberrypi: Report the fw variant during
+ probe
+
+The driver already reported the firmware build date during probe.
+The mailbox calls have been extended to also report the variant
+ 1 = standard start.elf
+ 2 = start_x.elf (includes camera stack)
+ 3 = start_db.elf (includes assert logging)
+ 4 = start_cd.elf (cutdown version for smallest memory footprint).
+Log the variant during probe.
+
+---
+ drivers/firmware/raspberrypi.c | 32 +++++++++++++++++-----
+ include/soc/bcm2835/raspberrypi-firmware.h | 1 +
+ 2 files changed, 26 insertions(+), 7 deletions(-)
+
+--- a/drivers/firmware/raspberrypi.c
++++ b/drivers/firmware/raspberrypi.c
+@@ -227,21 +227,39 @@ static const struct attribute_group rpi_
+ static void
+ rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
+ {
++ static const char * const variant_strs[] = {
++ "unknown",
++ "start",
++ "start_x",
++ "start_db",
++ "start_cd",
++ };
++ const char *variant_str = "cmd unsupported";
+ u32 packet;
++ u32 variant;
++ struct tm tm;
+ int ret = rpi_firmware_property(fw,
+ RPI_FIRMWARE_GET_FIRMWARE_REVISION,
+ &packet, sizeof(packet));
+
+- if (ret == 0) {
+- struct tm tm;
++ if (ret)
++ return;
+
+- time64_to_tm(packet, 0, &tm);
++ ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_FIRMWARE_VARIANT,
++ &variant, sizeof(variant));
+
+- dev_info(fw->cl.dev,
+- "Attached to firmware from %04ld-%02d-%02d %02d:%02d\n",
+- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+- tm.tm_hour, tm.tm_min);
++ if (!ret) {
++ if (variant >= ARRAY_SIZE(variant_strs))
++ variant = 0;
++ variant_str = variant_strs[variant];
+ }
++
++ time64_to_tm(packet, 0, &tm);
++
++ dev_info(fw->cl.dev,
++ "Attached to firmware from %04ld-%02d-%02d %02d:%02d, variant %s\n",
++ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
++ tm.tm_min, variant_str);
+ }
+
+ static void
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -41,6 +41,7 @@ struct rpi_firmware_property_tag_header
+ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_PROPERTY_END = 0,
+ RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001,
++ RPI_FIRMWARE_GET_FIRMWARE_VARIANT = 0x00000002,
+
+ RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010,
+ RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011,
+++ /dev/null
-From 81f6d4e84fd127cf0b31c9822a2beb9b298aa7bb Mon Sep 17 00:00:00 2001
-Date: Tue, 11 Dec 2018 15:18:02 +0000
-Subject: [PATCH] staging: bcm2835-camera: Check the error for
- REPEAT_SEQ_HEADER (#2782)
-
-When handling for V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER was added
-the firmware would reject the setting if H264 hadn't already been
-selected. This was fixed in the firmware at that point, but to
-enable backwards compatibility the returned error was ignored.
-
-That was Dec 2013, so the chances of having a firmware that still
-has that issue is so close to zero that the workaround can be
-removed.
-
----
- drivers/staging/vc04_services/bcm2835-camera/controls.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -1100,7 +1100,7 @@ static const struct bm2835_mmal_v4l2_ctr
- 0, 1, NULL,
- MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
- &ctrl_set_video_encode_param_output,
-- true /* Errors ignored as requires latest firmware to work */
-+ false
- },
- {
- V4L2_CID_MPEG_VIDEO_H264_PROFILE,
--- /dev/null
+From 9abde0ff52268580501b3120629f3c92f0e5d589 Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Jan 2019 18:48:54 +0000
+Subject: [PATCH] firmware: raspberrypi: Report the fw git hash during
+ probe
+
+The firmware can now report the git hash from which it was built
+via the mailbox, so report it during probe.
+
+---
+ drivers/firmware/raspberrypi.c | 17 +++++++++++++++++
+ include/soc/bcm2835/raspberrypi-firmware.h | 1 +
+ 2 files changed, 18 insertions(+)
+
+--- a/drivers/firmware/raspberrypi.c
++++ b/drivers/firmware/raspberrypi.c
+@@ -263,6 +263,22 @@ rpi_firmware_print_firmware_revision(str
+ }
+
+ static void
++rpi_firmware_print_firmware_hash(struct rpi_firmware *fw)
++{
++ u32 hash[5];
++ int ret = rpi_firmware_property(fw,
++ RPI_FIRMWARE_GET_FIRMWARE_HASH,
++ hash, sizeof(hash));
++
++ if (ret)
++ return;
++
++ dev_info(fw->cl.dev,
++ "Firmware hash is %08x%08x%08x%08x%08x\n",
++ hash[0], hash[1], hash[2], hash[3], hash[4]);
++}
++
++static void
+ rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw)
+ {
+ u32 packet;
+@@ -308,6 +324,7 @@ static int rpi_firmware_probe(struct pla
+ g_pdev = pdev;
+
+ rpi_firmware_print_firmware_revision(fw);
++ rpi_firmware_print_firmware_hash(fw);
+ rpi_register_hwmon_driver(dev, fw);
+
+ return 0;
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -42,6 +42,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_PROPERTY_END = 0,
+ RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001,
+ RPI_FIRMWARE_GET_FIRMWARE_VARIANT = 0x00000002,
++ RPI_FIRMWARE_GET_FIRMWARE_HASH = 0x00000003,
+
+ RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010,
+ RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011,
+++ /dev/null
-From d1cf5fb57ee5ee4512a93614d67d15af9c8070b2 Mon Sep 17 00:00:00 2001
-Date: Wed, 9 Jan 2019 14:51:01 +0100
-Subject: [PATCH] gpio-ir: change default pull configuration to up
-
-IR receivers like the TSOP series from Vishay and compatible ones
-have active-low open collector outputs with an internal pull up of
-about 30k (according to the TSOP datasheets).
-
-Activating a pull-down resistor on the GPIO will make it work against
-the pull-up in the IR receiver and brings the idle input voltage down
-to about 1.9V (measured on a RPi3B+ with a TSOP4438). While that's
-usually enough to make the RPi see a high signal it's certainly not
-optimal and may even fail when using an IR receiver with a weaker pull-up.
-
-Switching the default GPIO pull to "up" results in an input voltage
-level of about 3.3V and ensures that an idle state (high signal) will
-be detected if no IR receiver is attached.
-
----
- arch/arm/boot/dts/overlays/README | 2 +-
- arch/arm/boot/dts/overlays/gpio-ir-overlay.dts | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -611,7 +611,7 @@ Load: dtoverlay=gpio-ir,<param>=<val>
- Params: gpio_pin Input pin number. Default is 18.
-
- gpio_pull Desired pull-up/down state (off, down, up)
-- Default is "down".
-+ Default is "up".
-
- rc-map-name Default rc keymap (can also be changed by
- ir-keytable), defaults to "rc-rc6-mce"
---- a/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
-@@ -30,7 +30,7 @@
- gpio_ir_pins: gpio_ir_pins@12 {
- brcm,pins = <18>; // pin 18
- brcm,function = <0>; // in
-- brcm,pull = <1>; // down
-+ brcm,pull = <2>; // up
- };
- };
- };
--- /dev/null
+From bb8f38337d08dc1ac78ab251aa0b515eea45a79e Mon Sep 17 00:00:00 2001
+Date: Tue, 15 Jan 2019 09:56:41 +0000
+Subject: [PATCH] arm64: dts: broadcom: Enable fixups for overlays
+
+See: https://github.com/raspberrypi/linux/pull/2733
+
+---
+ arch/arm64/boot/dts/broadcom/Makefile | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/arch/arm64/boot/dts/broadcom/Makefile
++++ b/arch/arm64/boot/dts/broadcom/Makefile
+@@ -9,3 +9,8 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rp
+
+ subdir-y += northstar2
+ subdir-y += stingray
++
++# Enable fixups to support overlays on BCM2835 platforms
++ifeq ($(CONFIG_ARCH_BCM2835),y)
++ DTC_FLAGS ?= -@
++endif
+++ /dev/null
-From dfd66230d2d538e7f290436d2952124d6eadeb3d Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Jan 2019 17:58:06 +0000
-Subject: [PATCH] firmware: raspberrypi: Report the fw variant during
- probe
-
-The driver already reported the firmware build date during probe.
-The mailbox calls have been extended to also report the variant
- 1 = standard start.elf
- 2 = start_x.elf (includes camera stack)
- 3 = start_db.elf (includes assert logging)
- 4 = start_cd.elf (cutdown version for smallest memory footprint).
-Log the variant during probe.
-
----
- drivers/firmware/raspberrypi.c | 32 +++++++++++++++++-----
- include/soc/bcm2835/raspberrypi-firmware.h | 1 +
- 2 files changed, 26 insertions(+), 7 deletions(-)
-
---- a/drivers/firmware/raspberrypi.c
-+++ b/drivers/firmware/raspberrypi.c
-@@ -227,21 +227,39 @@ static const struct attribute_group rpi_
- static void
- rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
- {
-+ static const char * const variant_strs[] = {
-+ "unknown",
-+ "start",
-+ "start_x",
-+ "start_db",
-+ "start_cd",
-+ };
-+ const char *variant_str = "cmd unsupported";
- u32 packet;
-+ u32 variant;
-+ struct tm tm;
- int ret = rpi_firmware_property(fw,
- RPI_FIRMWARE_GET_FIRMWARE_REVISION,
- &packet, sizeof(packet));
-
-- if (ret == 0) {
-- struct tm tm;
-+ if (ret)
-+ return;
-
-- time64_to_tm(packet, 0, &tm);
-+ ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_FIRMWARE_VARIANT,
-+ &variant, sizeof(variant));
-
-- dev_info(fw->cl.dev,
-- "Attached to firmware from %04ld-%02d-%02d %02d:%02d\n",
-- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
-- tm.tm_hour, tm.tm_min);
-+ if (!ret) {
-+ if (variant >= ARRAY_SIZE(variant_strs))
-+ variant = 0;
-+ variant_str = variant_strs[variant];
- }
-+
-+ time64_to_tm(packet, 0, &tm);
-+
-+ dev_info(fw->cl.dev,
-+ "Attached to firmware from %04ld-%02d-%02d %02d:%02d, variant %s\n",
-+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
-+ tm.tm_min, variant_str);
- }
-
- static void
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -41,6 +41,7 @@ struct rpi_firmware_property_tag_header
- enum rpi_firmware_property_tag {
- RPI_FIRMWARE_PROPERTY_END = 0,
- RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001,
-+ RPI_FIRMWARE_GET_FIRMWARE_VARIANT = 0x00000002,
-
- RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010,
- RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011,
--- /dev/null
+From 1d26e4d72f2d0563cc6455e682a5d4c491de178c Mon Sep 17 00:00:00 2001
+Date: Sun, 9 Dec 2018 16:46:00 -0500
+Subject: [PATCH] dtoverlays: fe-pi-audio: fix sgtl5000 compatible
+ string
+
+The compatible string was set to "fepi,sgtl5000", which worked for some
+reason in 4.14, but does not work in 4.19, presumably due to some
+change in the kernel matching logic. The correct string is
+"fsl,sgtl5000".
+
+---
+ arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts
+@@ -39,7 +39,7 @@
+
+ sgtl5000@0a {
+ #sound-dai-cells = <0>;
+- compatible = "fepi,sgtl5000";
++ compatible = "fsl,sgtl5000";
+ reg = <0x0a>;
+ clocks = <&sgtl5000_mclk>;
+ micbias-resistor-k-ohms = <2>;
+++ /dev/null
-From 9abde0ff52268580501b3120629f3c92f0e5d589 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Jan 2019 18:48:54 +0000
-Subject: [PATCH] firmware: raspberrypi: Report the fw git hash during
- probe
-
-The firmware can now report the git hash from which it was built
-via the mailbox, so report it during probe.
-
----
- drivers/firmware/raspberrypi.c | 17 +++++++++++++++++
- include/soc/bcm2835/raspberrypi-firmware.h | 1 +
- 2 files changed, 18 insertions(+)
-
---- a/drivers/firmware/raspberrypi.c
-+++ b/drivers/firmware/raspberrypi.c
-@@ -263,6 +263,22 @@ rpi_firmware_print_firmware_revision(str
- }
-
- static void
-+rpi_firmware_print_firmware_hash(struct rpi_firmware *fw)
-+{
-+ u32 hash[5];
-+ int ret = rpi_firmware_property(fw,
-+ RPI_FIRMWARE_GET_FIRMWARE_HASH,
-+ hash, sizeof(hash));
-+
-+ if (ret)
-+ return;
-+
-+ dev_info(fw->cl.dev,
-+ "Firmware hash is %08x%08x%08x%08x%08x\n",
-+ hash[0], hash[1], hash[2], hash[3], hash[4]);
-+}
-+
-+static void
- rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw)
- {
- u32 packet;
-@@ -308,6 +324,7 @@ static int rpi_firmware_probe(struct pla
- g_pdev = pdev;
-
- rpi_firmware_print_firmware_revision(fw);
-+ rpi_firmware_print_firmware_hash(fw);
- rpi_register_hwmon_driver(dev, fw);
-
- return 0;
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -42,6 +42,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_PROPERTY_END = 0,
- RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001,
- RPI_FIRMWARE_GET_FIRMWARE_VARIANT = 0x00000002,
-+ RPI_FIRMWARE_GET_FIRMWARE_HASH = 0x00000003,
-
- RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010,
- RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011,
+++ /dev/null
-From bb8f38337d08dc1ac78ab251aa0b515eea45a79e Mon Sep 17 00:00:00 2001
-Date: Tue, 15 Jan 2019 09:56:41 +0000
-Subject: [PATCH] arm64: dts: broadcom: Enable fixups for overlays
-
-See: https://github.com/raspberrypi/linux/pull/2733
-
----
- arch/arm64/boot/dts/broadcom/Makefile | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/arch/arm64/boot/dts/broadcom/Makefile
-+++ b/arch/arm64/boot/dts/broadcom/Makefile
-@@ -9,3 +9,8 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rp
-
- subdir-y += northstar2
- subdir-y += stingray
-+
-+# Enable fixups to support overlays on BCM2835 platforms
-+ifeq ($(CONFIG_ARCH_BCM2835),y)
-+ DTC_FLAGS ?= -@
-+endif
--- /dev/null
+From e5111d81c8efc17d8d585510980d3fe49c998741 Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Dec 2018 19:11:13 +0000
+Subject: [PATCH] bcm2835_smi: re-add dereference to fix DMA transfers
+
+---
+ drivers/misc/bcm2835_smi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/misc/bcm2835_smi.c
++++ b/drivers/misc/bcm2835_smi.c
+@@ -879,7 +879,7 @@ static int bcm2835_smi_probe(struct plat
+ goto err;
+ }
+ addr = of_get_address(node, 0, NULL, NULL);
+- inst->smi_regs_busaddr = be32_to_cpu(addr);
++ inst->smi_regs_busaddr = be32_to_cpu(*addr);
+
+ err = bcm2835_smi_dma_setup(inst);
+ if (err)
+++ /dev/null
-From 1d26e4d72f2d0563cc6455e682a5d4c491de178c Mon Sep 17 00:00:00 2001
-Date: Sun, 9 Dec 2018 16:46:00 -0500
-Subject: [PATCH] dtoverlays: fe-pi-audio: fix sgtl5000 compatible
- string
-
-The compatible string was set to "fepi,sgtl5000", which worked for some
-reason in 4.14, but does not work in 4.19, presumably due to some
-change in the kernel matching logic. The correct string is
-"fsl,sgtl5000".
-
----
- arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts
-@@ -39,7 +39,7 @@
-
- sgtl5000@0a {
- #sound-dai-cells = <0>;
-- compatible = "fepi,sgtl5000";
-+ compatible = "fsl,sgtl5000";
- reg = <0x0a>;
- clocks = <&sgtl5000_mclk>;
- micbias-resistor-k-ohms = <2>;
--- /dev/null
+From 020ee4d0d438b830ee40da8d9d3414de156a11e7 Mon Sep 17 00:00:00 2001
+Date: Wed, 7 Nov 2018 16:07:40 -0800
+Subject: [PATCH] lan78xx: Debounce link events to minimize poll storm
+
+The bInterval is set to 4 (i.e. 8 microframes => 1ms) and the only bit
+that the driver pays attention to is "link was reset". If there's a
+flapping status bit in that endpoint data, (such as if PHY negotiation
+needs a few tries to get a stable link) then polling at a slower rate
+would act as a de-bounce.
+
+See: https://github.com/raspberrypi/linux/issues/2447
+---
+ drivers/net/usb/lan78xx.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/usb/lan78xx.c
++++ b/drivers/net/usb/lan78xx.c
+@@ -449,6 +449,11 @@ static bool enable_tso;
+ module_param(enable_tso, bool, 0644);
+ MODULE_PARM_DESC(enable_tso, "Enables TCP segmentation offload");
+
++#define INT_URB_MICROFRAMES_PER_MS 8
++static int int_urb_interval_ms = 8;
++module_param(int_urb_interval_ms, int, 0);
++MODULE_PARM_DESC(int_urb_interval_ms, "Override usb interrupt urb interval");
++
+ static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
+ {
+ u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL);
+@@ -3838,7 +3843,12 @@ static int lan78xx_probe(struct usb_inte
+ dev->pipe_intr = usb_rcvintpipe(dev->udev,
+ dev->ep_intr->desc.bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK);
+- period = dev->ep_intr->desc.bInterval;
++ if (int_urb_interval_ms <= 0)
++ period = dev->ep_intr->desc.bInterval;
++ else
++ period = int_urb_interval_ms * INT_URB_MICROFRAMES_PER_MS;
++
++ netif_notice(dev, probe, netdev, "int urb period %d\n", period);
+
+ maxp = usb_maxpacket(dev->udev, dev->pipe_intr, 0);
+ buf = kmalloc(maxp, GFP_KERNEL);
--- /dev/null
+From 5705594ae56861cb63e7a3de1854e29ad1e830fd Mon Sep 17 00:00:00 2001
+Date: Thu, 3 Jan 2019 00:01:08 +0530
+Subject: [PATCH] ASoC: Add support for AudioSense-Pi add-on soundcard
+
+AudioSense-Pi is a RPi HAT based on a TI's TLV320AIC32x4 stereo codec
+
+This hardware provides multiple audio I/O capabilities to the RPi.
+The codec connects to the RPi's SoC through the I2S Bus.
+
+The following devices can be connected through a 3.5mm jack
+ 1. Line-In: Plain old audio in from mobile phones, PCs, etc.,
+ 2. Mic-In: Connect a microphone
+ 3. Line-Out: Connect the output to a speaker
+ 4. Headphones: Connect a Headphone w or w/o microphones
+
+Multiple Inputs:
+ It supports the following combinations
+ 1. Two stereo Line-Inputs and a microphone
+ 2. One stereo Line-Input and two microphones
+ 3. Two stereo Line-Inputs, a microphone and
+ one mono line-input (with h/w hack)
+ 4. One stereo Line-Input, two microphones and
+ one mono line-input (with h/w hack)
+
+Multiple Outputs:
+ Audio output can be routed to the headphones or
+ speakers (with additional hardware)
+
+---
+ sound/soc/bcm/Kconfig | 7 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/audiosense-pi.c | 246 ++++++++++++++++++++++++++++++++++
+ 3 files changed, 255 insertions(+)
+ create mode 100644 sound/soc/bcm/audiosense-pi.c
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -137,6 +137,13 @@ config SND_AUDIOINJECTOR_OCTO_SOUNDCARD
+ help
+ Say Y or M if you want to add support for audioinjector.net octo add on
+
++config SND_AUDIOSENSE_PI
++ tristate "Support for AudioSense Add-On Soundcard"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_TLV320AIC32X4_I2C
++ help
++ Say Y or M if you want to add support for tlv320aic32x4 add-on
++
+ config SND_DIGIDAC1_SOUNDCARD
+ tristate "Support for Red Rocks Audio DigiDAC1"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -20,6 +20,7 @@ snd-soc-rpi-proto-objs := rpi-proto.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
+ snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
+ snd-soc-audioinjector-octo-soundcard-objs := audioinjector-octo-soundcard.o
++snd-soc-audiosense-pi-objs := audiosense-pi.o
+ snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o
+ snd-soc-dionaudio-loco-objs := dionaudio_loco.o
+ snd-soc-dionaudio-loco-v2-objs := dionaudio_loco-v2.o
+@@ -41,6 +42,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO)
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
+ obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o
+ obj-$(CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD) += snd-soc-audioinjector-octo-soundcard.o
++obj-$(CONFIG_SND_AUDIOSENSE_PI) += snd-soc-audiosense-pi.o
+ obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o
+ obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o
+ obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2) += snd-soc-dionaudio-loco-v2.o
+--- /dev/null
++++ b/sound/soc/bcm/audiosense-pi.c
+@@ -0,0 +1,246 @@
++/*
++ * ASoC Driver for AudioSense add on soundcard
++ * Author:
++ * Copyright 2017
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/i2c.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++#include <sound/control.h>
++
++#include <sound/tlv320aic32x4.h>
++#include "../codecs/tlv320aic32x4.h"
++
++#define AIC32X4_SYSCLK_XTAL 0x00
++
++/*
++ * Setup Codec Sample Rates and Channels
++ * Supported Rates:
++ * 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000,
++ */
++static const unsigned int audiosense_pi_rate[] = {
++ 48000,
++};
++
++static struct snd_pcm_hw_constraint_list audiosense_constraints_rates = {
++ .list = audiosense_pi_rate,
++ .count = ARRAY_SIZE(audiosense_pi_rate),
++};
++
++static const unsigned int audiosense_pi_channels[] = {
++ 2,
++};
++
++static struct snd_pcm_hw_constraint_list audiosense_constraints_ch = {
++ .count = ARRAY_SIZE(audiosense_pi_channels),
++ .list = audiosense_pi_channels,
++ .mask = 0,
++};
++
++/* Setup DAPM widgets and paths */
++static const struct snd_soc_dapm_widget audiosense_pi_dapm_widgets[] = {
++ SND_SOC_DAPM_HP("Headphone Jack", NULL),
++ SND_SOC_DAPM_LINE("Line Out", NULL),
++ SND_SOC_DAPM_LINE("Line In", NULL),
++ SND_SOC_DAPM_INPUT("CM_L"),
++ SND_SOC_DAPM_INPUT("CM_R"),
++};
++
++static const struct snd_soc_dapm_route audiosense_pi_audio_map[] = {
++ /* Line Inputs are connected to
++ * (IN1_L | IN1_R)
++ * (IN2_L | IN2_R)
++ * (IN3_L | IN3_R)
++ */
++ {"IN1_L", NULL, "Line In"},
++ {"IN1_R", NULL, "Line In"},
++ {"IN2_L", NULL, "Line In"},
++ {"IN2_R", NULL, "Line In"},
++ {"IN3_L", NULL, "Line In"},
++ {"IN3_R", NULL, "Line In"},
++
++ /* Mic is connected to IN2_L and IN2_R */
++ {"Left ADC", NULL, "Mic Bias"},
++ {"Right ADC", NULL, "Mic Bias"},
++
++ /* Headphone connected to HPL, HPR */
++ {"Headphone Jack", NULL, "HPL"},
++ {"Headphone Jack", NULL, "HPR"},
++
++ /* Speakers connected to LOL and LOR */
++ {"Line Out", NULL, "LOL"},
++ {"Line Out", NULL, "LOR"},
++};
++
++static int audiosense_pi_card_init(struct snd_soc_pcm_runtime *rtd)
++{
++ /* TODO: init of the codec specific dapm data, ignore suspend/resume */
++ struct snd_soc_component *component = rtd->codec_dai->component;
++
++ snd_soc_component_update_bits(component, AIC32X4_MICBIAS, 0x78,
++ AIC32X4_MICBIAS_LDOIN |
++ AIC32X4_MICBIAS_2075V);
++ snd_soc_component_update_bits(component, AIC32X4_PWRCFG, 0x08,
++ AIC32X4_AVDDWEAKDISABLE);
++ snd_soc_component_update_bits(component, AIC32X4_LDOCTL, 0x01,
++ AIC32X4_LDOCTLEN);
++
++ return 0;
++}
++
++static int audiosense_pi_card_hw_params(
++ struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ int ret = 0;
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++
++ /* Set the codec system clock, there is a 12 MHz XTAL on the board */
++ ret = snd_soc_dai_set_sysclk(codec_dai, AIC32X4_SYSCLK_XTAL,
++ 12000000, SND_SOC_CLOCK_IN);
++ if (ret) {
++ dev_err(rtd->card->dev,
++ "could not set codec driver clock params\n");
++ return ret;
++ }
++ return 0;
++}
++
++static int audiosense_pi_card_startup(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++
++ /*
++ * Set codec to 48Khz Sampling, Stereo I/O and 16 bit audio
++ */
++ runtime->hw.channels_max = 2;
++ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
++ &audiosense_constraints_ch);
++
++ runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
++ snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
++
++
++ snd_pcm_hw_constraint_list(substream->runtime, 0,
++ SNDRV_PCM_HW_PARAM_RATE,
++ &audiosense_constraints_rates);
++ return 0;
++}
++
++static struct snd_soc_ops audiosense_pi_card_ops = {
++ .startup = audiosense_pi_card_startup,
++ .hw_params = audiosense_pi_card_hw_params,
++};
++
++static struct snd_soc_dai_link audiosense_pi_card_dai[] = {
++ {
++ .name = "TLV320AIC3204 Audio",
++ .stream_name = "TLV320AIC3204 Hifi Audio",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "tlv320aic32x4-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "tlv320aic32x4.1-0018",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM,
++ .ops = &audiosense_pi_card_ops,
++ .init = audiosense_pi_card_init,
++ },
++};
++
++static struct snd_soc_card audiosense_pi_card = {
++ .name = "audiosense-pi",
++ .driver_name = "audiosense-pi",
++ .dai_link = audiosense_pi_card_dai,
++ .owner = THIS_MODULE,
++ .num_links = ARRAY_SIZE(audiosense_pi_card_dai),
++ .dapm_widgets = audiosense_pi_dapm_widgets,
++ .num_dapm_widgets = ARRAY_SIZE(audiosense_pi_dapm_widgets),
++ .dapm_routes = audiosense_pi_audio_map,
++ .num_dapm_routes = ARRAY_SIZE(audiosense_pi_audio_map),
++};
++
++static int audiosense_pi_card_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ struct snd_soc_card *card = &audiosense_pi_card;
++ struct snd_soc_dai_link *dai = &audiosense_pi_card_dai[0];
++ struct device_node *i2s_node = pdev->dev.of_node;
++
++ card->dev = &pdev->dev;
++
++ if (!dai) {
++ dev_err(&pdev->dev, "DAI not found. Missing or Invalid\n");
++ return -EINVAL;
++ }
++
++ i2s_node = of_parse_phandle(pdev->dev.of_node, "i2s-controller", 0);
++ if (!i2s_node) {
++ dev_err(&pdev->dev,
++ "Property 'i2s-controller' missing or invalid\n");
++ return -EINVAL;
++ }
++
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++
++ of_node_put(i2s_node);
++
++ ret = snd_soc_register_card(card);
++ if (ret && ret != -EPROBE_DEFER)
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static int audiosense_pi_card_remove(struct platform_device *pdev)
++{
++ struct snd_soc_card *card = platform_get_drvdata(pdev);
++
++ return snd_soc_unregister_card(card);
++
++}
++
++static const struct of_device_id audiosense_pi_card_of_match[] = {
++ { .compatible = "as,audiosense-pi", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, audiosense_pi_card_of_match);
++
++static struct platform_driver audiosense_pi_card_driver = {
++ .driver = {
++ .name = "audiosense-snd-card",
++ .owner = THIS_MODULE,
++ .of_match_table = audiosense_pi_card_of_match,
++ },
++ .probe = audiosense_pi_card_probe,
++ .remove = audiosense_pi_card_remove,
++};
++
++module_platform_driver(audiosense_pi_card_driver);
++
++MODULE_DESCRIPTION("ASoC Driver for TLV320AIC3204 Audio");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:audiosense-pi");
++
+++ /dev/null
-From e5111d81c8efc17d8d585510980d3fe49c998741 Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Dec 2018 19:11:13 +0000
-Subject: [PATCH] bcm2835_smi: re-add dereference to fix DMA transfers
-
----
- drivers/misc/bcm2835_smi.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/misc/bcm2835_smi.c
-+++ b/drivers/misc/bcm2835_smi.c
-@@ -879,7 +879,7 @@ static int bcm2835_smi_probe(struct plat
- goto err;
- }
- addr = of_get_address(node, 0, NULL, NULL);
-- inst->smi_regs_busaddr = be32_to_cpu(addr);
-+ inst->smi_regs_busaddr = be32_to_cpu(*addr);
-
- err = bcm2835_smi_dma_setup(inst);
- if (err)
--- /dev/null
+From 0d2a0f4f4c00c958fb6e7a2673adbe51c2a932f2 Mon Sep 17 00:00:00 2001
+Date: Thu, 3 Jan 2019 00:29:14 +0530
+Subject: [PATCH] BCM270X: Adding device tree support for AudioSense-Pi
+ add-on soundcard
+
+Device tree overlay for AudioSense-Pi card.
+
+To enable support for the hardware add the following
+line to the RPi /boot/config.txt:
+
+ dtoverlay=audiosense-pi
+
+More documentation @ arch/arm/boot/dts/overlays/README
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 8 ++
+ .../dts/overlays/audiosense-pi-overlay.dts | 82 +++++++++++++++++++
+ 3 files changed, 91 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -20,6 +20,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ audioinjector-addons.dtbo \
+ audioinjector-ultra.dtbo \
+ audioinjector-wm8731-audio.dtbo \
++ audiosense-pi.dtbo \
+ audremap.dtbo \
+ balena-fin.dtbo \
+ bmp085_i2c-sensor.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -453,6 +453,14 @@ Load: dtoverlay=audioinjector-wm8731-a
+ Params: <None>
+
+
++Name: audiosense-pi
++Info: Configures the audiosense-pi add on soundcard
++ For more information refer to
++ https://gitlab.com/kakar0t/audiosense-pi
++Load: dtoverlay=audiosense-pi
++Params: <None>
++
++
+ Name: audremap
+ Info: Switches PWM sound output to pins 12 (Right) & 13 (Left)
+ Load: dtoverlay=audremap,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts
+@@ -0,0 +1,82 @@
++// Definitions for audiosense add on soundcard
++/dts-v1/;
++/plugin/;
++#include <dt-bindings/pinctrl/bcm2835.h>
++#include <dt-bindings/gpio/gpio.h>
++
++/ {
++ compatible = "brcm,bcm2837", "brcm,bcm2836", "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target-path = "/";
++ __overlay__ {
++ codec_reg_1v8: codec-reg-1v8 {
++ compatible = "regulator-fixed";
++ regulator-name = "tlv320aic3204_1v8";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-always-on;
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&gpio>;
++ __overlay__ {
++ codec_rst: codec-rst {
++ brcm,pins = <26>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ /* audio external oscillator */
++ codec_osc: codec_osc {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <12000000>; /* 12 MHz */
++ };
++
++ codec: tlv320aic32x4@18 {
++ #sound-dai-cells = <0>;
++ compatible = "ti,tlv320aic32x4";
++ reg = <0x18>;
++
++ clocks = <&codec_osc>;
++ clock-names = "mclk";
++
++ iov-supply = <&vdd_3v3_reg>;
++ ldoin-supply = <&vdd_3v3_reg>;
++
++ gpio-controller;
++ #gpio-cells = <2>;
++ reset-gpios = <&gpio 26 GPIO_ACTIVE_HIGH>;
++
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "as,audiosense-pi";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++};
+++ /dev/null
-From 020ee4d0d438b830ee40da8d9d3414de156a11e7 Mon Sep 17 00:00:00 2001
-Date: Wed, 7 Nov 2018 16:07:40 -0800
-Subject: [PATCH] lan78xx: Debounce link events to minimize poll storm
-
-The bInterval is set to 4 (i.e. 8 microframes => 1ms) and the only bit
-that the driver pays attention to is "link was reset". If there's a
-flapping status bit in that endpoint data, (such as if PHY negotiation
-needs a few tries to get a stable link) then polling at a slower rate
-would act as a de-bounce.
-
-See: https://github.com/raspberrypi/linux/issues/2447
----
- drivers/net/usb/lan78xx.c | 12 +++++++++++-
- 1 file changed, 11 insertions(+), 1 deletion(-)
-
---- a/drivers/net/usb/lan78xx.c
-+++ b/drivers/net/usb/lan78xx.c
-@@ -449,6 +449,11 @@ static bool enable_tso;
- module_param(enable_tso, bool, 0644);
- MODULE_PARM_DESC(enable_tso, "Enables TCP segmentation offload");
-
-+#define INT_URB_MICROFRAMES_PER_MS 8
-+static int int_urb_interval_ms = 8;
-+module_param(int_urb_interval_ms, int, 0);
-+MODULE_PARM_DESC(int_urb_interval_ms, "Override usb interrupt urb interval");
-+
- static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
- {
- u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL);
-@@ -3838,7 +3843,12 @@ static int lan78xx_probe(struct usb_inte
- dev->pipe_intr = usb_rcvintpipe(dev->udev,
- dev->ep_intr->desc.bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK);
-- period = dev->ep_intr->desc.bInterval;
-+ if (int_urb_interval_ms <= 0)
-+ period = dev->ep_intr->desc.bInterval;
-+ else
-+ period = int_urb_interval_ms * INT_URB_MICROFRAMES_PER_MS;
-+
-+ netif_notice(dev, probe, netdev, "int urb period %d\n", period);
-
- maxp = usb_maxpacket(dev->udev, dev->pipe_intr, 0);
- buf = kmalloc(maxp, GFP_KERNEL);
+++ /dev/null
-From 5705594ae56861cb63e7a3de1854e29ad1e830fd Mon Sep 17 00:00:00 2001
-Date: Thu, 3 Jan 2019 00:01:08 +0530
-Subject: [PATCH] ASoC: Add support for AudioSense-Pi add-on soundcard
-
-AudioSense-Pi is a RPi HAT based on a TI's TLV320AIC32x4 stereo codec
-
-This hardware provides multiple audio I/O capabilities to the RPi.
-The codec connects to the RPi's SoC through the I2S Bus.
-
-The following devices can be connected through a 3.5mm jack
- 1. Line-In: Plain old audio in from mobile phones, PCs, etc.,
- 2. Mic-In: Connect a microphone
- 3. Line-Out: Connect the output to a speaker
- 4. Headphones: Connect a Headphone w or w/o microphones
-
-Multiple Inputs:
- It supports the following combinations
- 1. Two stereo Line-Inputs and a microphone
- 2. One stereo Line-Input and two microphones
- 3. Two stereo Line-Inputs, a microphone and
- one mono line-input (with h/w hack)
- 4. One stereo Line-Input, two microphones and
- one mono line-input (with h/w hack)
-
-Multiple Outputs:
- Audio output can be routed to the headphones or
- speakers (with additional hardware)
-
----
- sound/soc/bcm/Kconfig | 7 +
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/audiosense-pi.c | 246 ++++++++++++++++++++++++++++++++++
- 3 files changed, 255 insertions(+)
- create mode 100644 sound/soc/bcm/audiosense-pi.c
-
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -137,6 +137,13 @@ config SND_AUDIOINJECTOR_OCTO_SOUNDCARD
- help
- Say Y or M if you want to add support for audioinjector.net octo add on
-
-+config SND_AUDIOSENSE_PI
-+ tristate "Support for AudioSense Add-On Soundcard"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_TLV320AIC32X4_I2C
-+ help
-+ Say Y or M if you want to add support for tlv320aic32x4 add-on
-+
- config SND_DIGIDAC1_SOUNDCARD
- tristate "Support for Red Rocks Audio DigiDAC1"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -20,6 +20,7 @@ snd-soc-rpi-proto-objs := rpi-proto.o
- snd-soc-iqaudio-dac-objs := iqaudio-dac.o
- snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
- snd-soc-audioinjector-octo-soundcard-objs := audioinjector-octo-soundcard.o
-+snd-soc-audiosense-pi-objs := audiosense-pi.o
- snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o
- snd-soc-dionaudio-loco-objs := dionaudio_loco.o
- snd-soc-dionaudio-loco-v2-objs := dionaudio_loco-v2.o
-@@ -41,6 +42,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO)
- obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
- obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o
- obj-$(CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD) += snd-soc-audioinjector-octo-soundcard.o
-+obj-$(CONFIG_SND_AUDIOSENSE_PI) += snd-soc-audiosense-pi.o
- obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o
- obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o
- obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2) += snd-soc-dionaudio-loco-v2.o
---- /dev/null
-+++ b/sound/soc/bcm/audiosense-pi.c
-@@ -0,0 +1,246 @@
-+/*
-+ * ASoC Driver for AudioSense add on soundcard
-+ * Author:
-+ * Copyright 2017
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/clk.h>
-+#include <linux/i2c.h>
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+#include <sound/control.h>
-+
-+#include <sound/tlv320aic32x4.h>
-+#include "../codecs/tlv320aic32x4.h"
-+
-+#define AIC32X4_SYSCLK_XTAL 0x00
-+
-+/*
-+ * Setup Codec Sample Rates and Channels
-+ * Supported Rates:
-+ * 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000,
-+ */
-+static const unsigned int audiosense_pi_rate[] = {
-+ 48000,
-+};
-+
-+static struct snd_pcm_hw_constraint_list audiosense_constraints_rates = {
-+ .list = audiosense_pi_rate,
-+ .count = ARRAY_SIZE(audiosense_pi_rate),
-+};
-+
-+static const unsigned int audiosense_pi_channels[] = {
-+ 2,
-+};
-+
-+static struct snd_pcm_hw_constraint_list audiosense_constraints_ch = {
-+ .count = ARRAY_SIZE(audiosense_pi_channels),
-+ .list = audiosense_pi_channels,
-+ .mask = 0,
-+};
-+
-+/* Setup DAPM widgets and paths */
-+static const struct snd_soc_dapm_widget audiosense_pi_dapm_widgets[] = {
-+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
-+ SND_SOC_DAPM_LINE("Line Out", NULL),
-+ SND_SOC_DAPM_LINE("Line In", NULL),
-+ SND_SOC_DAPM_INPUT("CM_L"),
-+ SND_SOC_DAPM_INPUT("CM_R"),
-+};
-+
-+static const struct snd_soc_dapm_route audiosense_pi_audio_map[] = {
-+ /* Line Inputs are connected to
-+ * (IN1_L | IN1_R)
-+ * (IN2_L | IN2_R)
-+ * (IN3_L | IN3_R)
-+ */
-+ {"IN1_L", NULL, "Line In"},
-+ {"IN1_R", NULL, "Line In"},
-+ {"IN2_L", NULL, "Line In"},
-+ {"IN2_R", NULL, "Line In"},
-+ {"IN3_L", NULL, "Line In"},
-+ {"IN3_R", NULL, "Line In"},
-+
-+ /* Mic is connected to IN2_L and IN2_R */
-+ {"Left ADC", NULL, "Mic Bias"},
-+ {"Right ADC", NULL, "Mic Bias"},
-+
-+ /* Headphone connected to HPL, HPR */
-+ {"Headphone Jack", NULL, "HPL"},
-+ {"Headphone Jack", NULL, "HPR"},
-+
-+ /* Speakers connected to LOL and LOR */
-+ {"Line Out", NULL, "LOL"},
-+ {"Line Out", NULL, "LOR"},
-+};
-+
-+static int audiosense_pi_card_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ /* TODO: init of the codec specific dapm data, ignore suspend/resume */
-+ struct snd_soc_component *component = rtd->codec_dai->component;
-+
-+ snd_soc_component_update_bits(component, AIC32X4_MICBIAS, 0x78,
-+ AIC32X4_MICBIAS_LDOIN |
-+ AIC32X4_MICBIAS_2075V);
-+ snd_soc_component_update_bits(component, AIC32X4_PWRCFG, 0x08,
-+ AIC32X4_AVDDWEAKDISABLE);
-+ snd_soc_component_update_bits(component, AIC32X4_LDOCTL, 0x01,
-+ AIC32X4_LDOCTLEN);
-+
-+ return 0;
-+}
-+
-+static int audiosense_pi_card_hw_params(
-+ struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ int ret = 0;
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
-+
-+ /* Set the codec system clock, there is a 12 MHz XTAL on the board */
-+ ret = snd_soc_dai_set_sysclk(codec_dai, AIC32X4_SYSCLK_XTAL,
-+ 12000000, SND_SOC_CLOCK_IN);
-+ if (ret) {
-+ dev_err(rtd->card->dev,
-+ "could not set codec driver clock params\n");
-+ return ret;
-+ }
-+ return 0;
-+}
-+
-+static int audiosense_pi_card_startup(struct snd_pcm_substream *substream)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+
-+ /*
-+ * Set codec to 48Khz Sampling, Stereo I/O and 16 bit audio
-+ */
-+ runtime->hw.channels_max = 2;
-+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-+ &audiosense_constraints_ch);
-+
-+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
-+ snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
-+
-+
-+ snd_pcm_hw_constraint_list(substream->runtime, 0,
-+ SNDRV_PCM_HW_PARAM_RATE,
-+ &audiosense_constraints_rates);
-+ return 0;
-+}
-+
-+static struct snd_soc_ops audiosense_pi_card_ops = {
-+ .startup = audiosense_pi_card_startup,
-+ .hw_params = audiosense_pi_card_hw_params,
-+};
-+
-+static struct snd_soc_dai_link audiosense_pi_card_dai[] = {
-+ {
-+ .name = "TLV320AIC3204 Audio",
-+ .stream_name = "TLV320AIC3204 Hifi Audio",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .codec_dai_name = "tlv320aic32x4-hifi",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codec_name = "tlv320aic32x4.1-0018",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBM_CFM,
-+ .ops = &audiosense_pi_card_ops,
-+ .init = audiosense_pi_card_init,
-+ },
-+};
-+
-+static struct snd_soc_card audiosense_pi_card = {
-+ .name = "audiosense-pi",
-+ .driver_name = "audiosense-pi",
-+ .dai_link = audiosense_pi_card_dai,
-+ .owner = THIS_MODULE,
-+ .num_links = ARRAY_SIZE(audiosense_pi_card_dai),
-+ .dapm_widgets = audiosense_pi_dapm_widgets,
-+ .num_dapm_widgets = ARRAY_SIZE(audiosense_pi_dapm_widgets),
-+ .dapm_routes = audiosense_pi_audio_map,
-+ .num_dapm_routes = ARRAY_SIZE(audiosense_pi_audio_map),
-+};
-+
-+static int audiosense_pi_card_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+ struct snd_soc_card *card = &audiosense_pi_card;
-+ struct snd_soc_dai_link *dai = &audiosense_pi_card_dai[0];
-+ struct device_node *i2s_node = pdev->dev.of_node;
-+
-+ card->dev = &pdev->dev;
-+
-+ if (!dai) {
-+ dev_err(&pdev->dev, "DAI not found. Missing or Invalid\n");
-+ return -EINVAL;
-+ }
-+
-+ i2s_node = of_parse_phandle(pdev->dev.of_node, "i2s-controller", 0);
-+ if (!i2s_node) {
-+ dev_err(&pdev->dev,
-+ "Property 'i2s-controller' missing or invalid\n");
-+ return -EINVAL;
-+ }
-+
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+
-+ of_node_put(i2s_node);
-+
-+ ret = snd_soc_register_card(card);
-+ if (ret && ret != -EPROBE_DEFER)
-+ dev_err(&pdev->dev,
-+ "snd_soc_register_card() failed: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static int audiosense_pi_card_remove(struct platform_device *pdev)
-+{
-+ struct snd_soc_card *card = platform_get_drvdata(pdev);
-+
-+ return snd_soc_unregister_card(card);
-+
-+}
-+
-+static const struct of_device_id audiosense_pi_card_of_match[] = {
-+ { .compatible = "as,audiosense-pi", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, audiosense_pi_card_of_match);
-+
-+static struct platform_driver audiosense_pi_card_driver = {
-+ .driver = {
-+ .name = "audiosense-snd-card",
-+ .owner = THIS_MODULE,
-+ .of_match_table = audiosense_pi_card_of_match,
-+ },
-+ .probe = audiosense_pi_card_probe,
-+ .remove = audiosense_pi_card_remove,
-+};
-+
-+module_platform_driver(audiosense_pi_card_driver);
-+
-+MODULE_DESCRIPTION("ASoC Driver for TLV320AIC3204 Audio");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:audiosense-pi");
-+
--- /dev/null
+From 788109b357ddb30a95be72ce46dc22e2335131af Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Jan 2019 15:27:56 +0000
+Subject: [PATCH] overlays: sdio: Add enhanced 1-bit support
+
+"dtoverlay=sdio,bus_width=1,gpios_22_25" is equivalent to the sdio-1bit
+overlay, which is now deprecated.
+
+"dtoverlay=sdio,bus_width=1,gpios_34_37" enables 1-bit mode on GPIOs 34-37.
+
+---
+ arch/arm/boot/dts/overlays/README | 24 +++++++++++----------
+ arch/arm/boot/dts/overlays/sdio-overlay.dts | 20 ++++++++++++++++-
+ 2 files changed, 32 insertions(+), 12 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -479,8 +479,7 @@ Params: <None>
+
+ Name: bmp085_i2c-sensor
+ Info: This overlay is now deprecated - see i2c-sensor
+-Load: dtoverlay=bmp085_i2c-sensor
+-Params: <None>
++Load: <Deprecated>
+
+
+ Name: dht11
+@@ -1737,7 +1736,8 @@ Params: overclock_50 Clock (i
+
+ Name: sdio
+ Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock,
+- and enables SDIO via GPIOs 22-27.
++ and enables SDIO via GPIOs 22-27. An example of use in 1-bit mode is
++ "dtoverlay=sdio,bus_width=1,gpios_22_25"
+ Load: dtoverlay=sdio,<param>=<val>
+ Params: sdio_overclock SDIO Clock (in MHz) to use when the MMC
+ framework requests 50MHz
+@@ -1747,16 +1747,18 @@ Params: sdio_overclock SDIO Clo
+
+ bus_width Set the SDIO host bus width (default 4 bits)
+
++ gpios_22_25 Select GPIOs 22-25 for 1-bit mode. Must be used
++ with bus_width=1. This replaces the sdio-1bit
++ overlay, which is now deprecated.
+
+-Name: sdio-1bit
+-Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock,
+- and enables 1-bit SDIO via GPIOs 22-25.
+-Load: dtoverlay=sdio-1bit,<param>=<val>
+-Params: sdio_overclock SDIO Clock (in MHz) to use when the MMC
+- framework requests 50MHz
++ gpios_34_37 Select GPIOs 34-37 for 1-bit mode. Must be used
++ with bus_width=1.
+
+- poll_once Disable SDIO-device polling every second
+- (default on: polling once at boot-time)
++
++Name: sdio-1bit
++Info: This overlay is now deprecated. Use
++ "dtoverlay=sdio,bus_width=1,gpios_22_25" instead.
++Load: <Deprecated>
+
+
+ Name: sdtweak
+--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
+@@ -32,7 +32,7 @@
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdio_ovl_pins>;
+ non-removable;
+- bus-width = <1>;
++ bus-width = <4>;
+ };
+ };
+ };
+@@ -49,6 +49,22 @@
+ };
+
+ fragment@3 {
++ target = <&sdio_ovl_pins>;
++ __dormant__ {
++ brcm,pins = <22 23 24 25>;
++ brcm,pull = <0 2 2 2>;
++ };
++ };
++
++ fragment@4 {
++ target = <&sdio_ovl_pins>;
++ __dormant__ {
++ brcm,pins = <34 35 36 37>;
++ brcm,pull = <0 2 2 2>;
++ };
++ };
++
++ fragment@6 {
+ target-path = "/aliases";
+ __overlay__ {
+ mmc1 = "/soc/sdio@7e300000";
+@@ -59,5 +75,7 @@
+ poll_once = <&sdio_ovl>,"non-removable?";
+ bus_width = <&sdio_ovl>,"bus-width:0";
+ sdio_overclock = <&sdio_ovl>,"brcm,overclock-50:0";
++ gpios_22_25 = <0>,"=3";
++ gpios_34_37 = <0>,"=4";
+ };
+ };
+++ /dev/null
-From 0d2a0f4f4c00c958fb6e7a2673adbe51c2a932f2 Mon Sep 17 00:00:00 2001
-Date: Thu, 3 Jan 2019 00:29:14 +0530
-Subject: [PATCH] BCM270X: Adding device tree support for AudioSense-Pi
- add-on soundcard
-
-Device tree overlay for AudioSense-Pi card.
-
-To enable support for the hardware add the following
-line to the RPi /boot/config.txt:
-
- dtoverlay=audiosense-pi
-
-More documentation @ arch/arm/boot/dts/overlays/README
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 8 ++
- .../dts/overlays/audiosense-pi-overlay.dts | 82 +++++++++++++++++++
- 3 files changed, 91 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -20,6 +20,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- audioinjector-addons.dtbo \
- audioinjector-ultra.dtbo \
- audioinjector-wm8731-audio.dtbo \
-+ audiosense-pi.dtbo \
- audremap.dtbo \
- balena-fin.dtbo \
- bmp085_i2c-sensor.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -453,6 +453,14 @@ Load: dtoverlay=audioinjector-wm8731-a
- Params: <None>
-
-
-+Name: audiosense-pi
-+Info: Configures the audiosense-pi add on soundcard
-+ For more information refer to
-+ https://gitlab.com/kakar0t/audiosense-pi
-+Load: dtoverlay=audiosense-pi
-+Params: <None>
-+
-+
- Name: audremap
- Info: Switches PWM sound output to pins 12 (Right) & 13 (Left)
- Load: dtoverlay=audremap,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts
-@@ -0,0 +1,82 @@
-+// Definitions for audiosense add on soundcard
-+/dts-v1/;
-+/plugin/;
-+#include <dt-bindings/pinctrl/bcm2835.h>
-+#include <dt-bindings/gpio/gpio.h>
-+
-+/ {
-+ compatible = "brcm,bcm2837", "brcm,bcm2836", "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target-path = "/";
-+ __overlay__ {
-+ codec_reg_1v8: codec-reg-1v8 {
-+ compatible = "regulator-fixed";
-+ regulator-name = "tlv320aic3204_1v8";
-+ regulator-min-microvolt = <1800000>;
-+ regulator-max-microvolt = <1800000>;
-+ regulator-always-on;
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ codec_rst: codec-rst {
-+ brcm,pins = <26>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ /* audio external oscillator */
-+ codec_osc: codec_osc {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <12000000>; /* 12 MHz */
-+ };
-+
-+ codec: tlv320aic32x4@18 {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,tlv320aic32x4";
-+ reg = <0x18>;
-+
-+ clocks = <&codec_osc>;
-+ clock-names = "mclk";
-+
-+ iov-supply = <&vdd_3v3_reg>;
-+ ldoin-supply = <&vdd_3v3_reg>;
-+
-+ gpio-controller;
-+ #gpio-cells = <2>;
-+ reset-gpios = <&gpio 26 GPIO_ACTIVE_HIGH>;
-+
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "as,audiosense-pi";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+};
--- /dev/null
+From 6e56da00afdf11416045213552514d10bab845cc Mon Sep 17 00:00:00 2001
+Date: Wed, 16 Jan 2019 10:17:52 +0000
+Subject: [PATCH] dwc_otg: fix bug with port_addr assignment for
+ single-TT hubs
+
+See https://github.com/raspberrypi/linux/issues/2734
+
+The "Hub Port" field in the split transaction packet was always set
+to 1 for single-TT hubs. The majority of single-TT hub products
+apparently ignore this field and broadcast to all downstream enabled
+ports, which masked the issue. A subset of hub devices apparently
+need the port number to be exact or split transactions will fail.
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
+@@ -232,7 +232,7 @@ static int _hub_info(dwc_otg_hcd_t * hcd
+ else
+ *hub_addr = urb->dev->tt->hub->devnum;
+ }
+- *port_addr = urb->dev->tt->multi ? urb->dev->ttport : 1;
++ *port_addr = urb->dev->ttport;
+ } else {
+ *hub_addr = 0;
+ *port_addr = urb->dev->ttport;
--- /dev/null
+From dde0ec6b9fd5755de3a8962489cde9c0ce5e5005 Mon Sep 17 00:00:00 2001
+Date: Mon, 8 Oct 2018 18:10:12 +0200
+Subject: [PATCH] Added driver for the HiFiBerry DAC+ ADC (#2694)
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 21 +
+ .../overlays/hifiberry-dacplusadc-overlay.dts | 71 +++
+ sound/soc/bcm/Kconfig | 8 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/hifiberry_dacplusadc.c | 407 ++++++++++++++++++
+ 8 files changed, 512 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
+ create mode 100644 sound/soc/bcm/hifiberry_dacplusadc.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -49,6 +49,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ hifiberry-amp.dtbo \
+ hifiberry-dac.dtbo \
+ hifiberry-dacplus.dtbo \
++ hifiberry-dacplusadc.dtbo \
+ hifiberry-digi.dtbo \
+ hifiberry-digi-pro.dtbo \
+ hy28a.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -779,6 +779,27 @@ Params: 24db_digital_gain Allow ga
+ master for bit clock and frame clock.
+
+
++Name: hifiberry-dacplusadc
++Info: Configures the HifiBerry DAC+ADC audio card
++Load: dtoverlay=hifiberry-dacplusadc,<param>=<val>
++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
++ Digital volume control. Enable with
++ "dtoverlay=hifiberry-dacplus,24db_digital_gain"
++ (The default behaviour is that the Digital
++ volume control is limited to a maximum of
++ 0dB. ie. it can attenuate but not provide
++ gain. For most users, this will be desired
++ as it will prevent clipping. By appending
++ the 24dB_digital_gain parameter, the Digital
++ volume control will allow up to 24dB of
++ gain. If this parameter is enabled, it is the
++ responsibility of the user to ensure that
++ the Digital volume control is set to a value
++ that does not result in clipping/distortion!)
++ slave Force DAC+ Pro into slave mode, using Pi as
++ master for bit clock and frame clock.
++
++
+ Name: hifiberry-digi
+ Info: Configures the HifiBerry Digi and Digi+ audio card
+ Load: dtoverlay=hifiberry-digi
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
+@@ -0,0 +1,71 @@
++// Definitions for HiFiBerry DAC+ADC
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target-path = "/clocks";
++ __overlay__ {
++ dacpro_osc: dacpro_osc {
++ compatible = "hifiberry,dacpro-clk";
++ #clock-cells = <0>;
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm_codec: pcm5122@4d {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm5122";
++ reg = <0x4d>;
++ clocks = <&dacpro_osc>;
++ AVDD-supply = <&vdd_3v3_reg>;
++ DVDD-supply = <&vdd_3v3_reg>;
++ CPVDD-supply = <&vdd_3v3_reg>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@3 {
++ target-path = "/";
++ __overlay__ {
++ dmic {
++ #sound-dai-cells = <0>;
++ compatible = "dmic-codec";
++ num-channels = <2>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&sound>;
++ hifiberry_dacplusadc: __overlay__ {
++ compatible = "hifiberry,hifiberry-dacplusadc";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ 24db_digital_gain =
++ <&hifiberry_dacplusadc>,"hifiberry,24db_digital_gain?";
++ slave = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,slave?";
++ };
++};
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -46,6 +46,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
+ help
+ Say Y or M if you want to add support for HifiBerry DAC+.
+
++config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC
++ tristate "Support for HifiBerry DAC+ADC"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_PCM512x_I2C
++ select SND_SOC_DMIC
++ help
++ Say Y or M if you want to add support for HifiBerry DAC+ADC.
++
+ config SND_BCM2708_SOC_HIFIBERRY_DIGI
+ tristate "Support for HifiBerry Digi"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -14,6 +14,7 @@ snd-soc-googlevoicehat-codec-objs := goo
+ # BCM2708 Machine Support
+ snd-soc-3dlab-nano-player-objs := 3dlab-nano-player.o
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
++snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
+ snd-soc-justboom-dac-objs := justboom-dac.o
+ snd-soc-rpi-cirrus-objs := rpi-cirrus.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+@@ -36,6 +37,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi
+ obj-$(CONFIG_SND_BCM2708_SOC_3DLAB_NANO_PLAYER) += snd-soc-3dlab-nano-player.o
+ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
+ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+--- /dev/null
++++ b/sound/soc/bcm/hifiberry_dacplusadc.c
+@@ -0,0 +1,407 @@
++/*
++ * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC
++ *
++ * Copyright 2014-2015
++ * Copyright 2018
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/kernel.h>
++#include <linux/clk.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++#include "../codecs/pcm512x.h"
++
++#define HIFIBERRY_DACPRO_NOCLOCK 0
++#define HIFIBERRY_DACPRO_CLK44EN 1
++#define HIFIBERRY_DACPRO_CLK48EN 2
++
++struct platform_device *dmic_codec_dev;
++
++struct pcm512x_priv {
++ struct regmap *regmap;
++ struct clk *sclk;
++};
++
++/* Clock rate of CLK44EN attached to GPIO6 pin */
++#define CLK_44EN_RATE 22579200UL
++/* Clock rate of CLK48EN attached to GPIO3 pin */
++#define CLK_48EN_RATE 24576000UL
++
++static bool slave;
++static bool snd_rpi_hifiberry_is_dacpro;
++static bool digital_gain_0db_limit = true;
++
++static void snd_rpi_hifiberry_dacplusadc_select_clk(struct snd_soc_component *component,
++ int clk_id)
++{
++ switch (clk_id) {
++ case HIFIBERRY_DACPRO_NOCLOCK:
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
++ break;
++ case HIFIBERRY_DACPRO_CLK44EN:
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
++ break;
++ case HIFIBERRY_DACPRO_CLK48EN:
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
++ break;
++ }
++}
++
++static void snd_rpi_hifiberry_dacplusadc_clk_gpio(struct snd_soc_component *component)
++{
++ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24);
++ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
++ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
++}
++
++static bool snd_rpi_hifiberry_dacplusadc_is_sclk(struct snd_soc_component *component)
++{
++ unsigned int sck;
++
++ snd_soc_component_read(component, PCM512x_RATE_DET_4, &sck);
++ return (!(sck & 0x40));
++}
++
++static bool snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(
++ struct snd_soc_component *component)
++{
++ msleep(2);
++ return snd_rpi_hifiberry_dacplusadc_is_sclk(component);
++}
++
++static bool snd_rpi_hifiberry_dacplusadc_is_pro_card(struct snd_soc_component *component)
++{
++ bool isClk44EN, isClk48En, isNoClk;
++
++ snd_rpi_hifiberry_dacplusadc_clk_gpio(component);
++
++ snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_CLK44EN);
++ isClk44EN = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component);
++
++ snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK);
++ isNoClk = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component);
++
++ snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_CLK48EN);
++ isClk48En = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component);
++
++ return (isClk44EN && isClk48En && !isNoClk);
++}
++
++static int snd_rpi_hifiberry_dacplusadc_clk_for_rate(int sample_rate)
++{
++ int type;
++
++ switch (sample_rate) {
++ case 11025:
++ case 22050:
++ case 44100:
++ case 88200:
++ case 176400:
++ case 352800:
++ type = HIFIBERRY_DACPRO_CLK44EN;
++ break;
++ default:
++ type = HIFIBERRY_DACPRO_CLK48EN;
++ break;
++ }
++ return type;
++}
++
++static void snd_rpi_hifiberry_dacplusadc_set_sclk(struct snd_soc_component *component,
++ int sample_rate)
++{
++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
++
++ if (!IS_ERR(pcm512x->sclk)) {
++ int ctype;
++
++ ctype = snd_rpi_hifiberry_dacplusadc_clk_for_rate(sample_rate);
++ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN)
++ ? CLK_44EN_RATE : CLK_48EN_RATE);
++ snd_rpi_hifiberry_dacplusadc_select_clk(component, ctype);
++ }
++}
++
++static int snd_rpi_hifiberry_dacplusadc_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_component *component = rtd->codec_dai->component;
++ struct pcm512x_priv *priv;
++
++ if (slave)
++ snd_rpi_hifiberry_is_dacpro = false;
++ else
++ snd_rpi_hifiberry_is_dacpro =
++ snd_rpi_hifiberry_dacplusadc_is_pro_card(component);
++
++ if (snd_rpi_hifiberry_is_dacpro) {
++ struct snd_soc_dai_link *dai = rtd->dai_link;
++
++ dai->name = "HiFiBerry ADCDAC+ Pro";
++ dai->stream_name = "HiFiBerry ADCDAC+ Pro HiFi";
++ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBM_CFM;
++
++ snd_soc_component_update_bits(component, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
++ snd_soc_component_update_bits(component, PCM512x_MASTER_MODE, 0x03, 0x03);
++ snd_soc_component_update_bits(component, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
++ } else {
++ priv = snd_soc_component_get_drvdata(component);
++ priv->sclk = ERR_PTR(-ENOENT);
++ }
++
++ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
++ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++
++ if (digital_gain_0db_limit) {
++ int ret;
++ struct snd_soc_card *card = rtd->card;
++
++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
++ }
++
++ return 0;
++}
++
++static int snd_rpi_hifiberry_dacplusadc_update_rate_den(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *component = rtd->codec_dai->component;
++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
++ struct snd_ratnum *rats_no_pll;
++ unsigned int num = 0, den = 0;
++ int err;
++
++ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
++ if (!rats_no_pll)
++ return -ENOMEM;
++
++ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
++ rats_no_pll->den_min = 1;
++ rats_no_pll->den_max = 128;
++ rats_no_pll->den_step = 1;
++
++ err = snd_interval_ratnum(hw_param_interval(params,
++ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
++ if (err >= 0 && den) {
++ params->rate_num = num;
++ params->rate_den = den;
++ }
++
++ devm_kfree(rtd->dev, rats_no_pll);
++ return 0;
++}
++
++static int snd_rpi_hifiberry_dacplusadc_hw_params(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ int ret = 0;
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ int channels = params_channels(params);
++ int width = 32;
++
++ if (snd_rpi_hifiberry_is_dacpro) {
++ struct snd_soc_component *component = rtd->codec_dai->component;
++
++ width = snd_pcm_format_physical_width(params_format(params));
++
++ snd_rpi_hifiberry_dacplusadc_set_sclk(component,
++ params_rate(params));
++
++ ret = snd_rpi_hifiberry_dacplusadc_update_rate_den(
++ substream, params);
++ }
++
++ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x03, 0x03,
++ channels, width);
++ if (ret)
++ return ret;
++ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, 0x03, 0x03,
++ channels, width);
++ return ret;
++}
++
++static int hifiberry_dacplusadc_LED_cnt;
++
++static int snd_rpi_hifiberry_dacplusadc_startup(
++ struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *component = rtd->codec_dai->component;
++
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1,
++ 0x08, 0x08);
++ hifiberry_dacplusadc_LED_cnt++;
++ return 0;
++}
++
++static void snd_rpi_hifiberry_dacplusadc_shutdown(
++ struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *component = rtd->codec_dai->component;
++
++ hifiberry_dacplusadc_LED_cnt--;
++ if (!hifiberry_dacplusadc_LED_cnt)
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1,
++ 0x08, 0x00);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_hifiberry_dacplusadc_ops = {
++ .hw_params = snd_rpi_hifiberry_dacplusadc_hw_params,
++ .startup = snd_rpi_hifiberry_dacplusadc_startup,
++ .shutdown = snd_rpi_hifiberry_dacplusadc_shutdown,
++};
++
++static struct snd_soc_dai_link_component snd_rpi_hifiberry_dacplusadc_codecs[] = {
++ {
++ .name = "pcm512x.1-004d",
++ .dai_name = "pcm512x-hifi",
++ },
++ {
++ .name = "dmic-codec",
++ .dai_name = "dmic-hifi",
++ },
++};
++
++static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadc_dai[] = {
++{
++ .name = "HiFiBerry DAC+ADC",
++ .stream_name = "HiFiBerry DAC+ADC HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .platform_name = "bcm2708-i2s.0",
++ .codecs = snd_rpi_hifiberry_dacplusadc_codecs,
++ .num_codecs = 2,
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_hifiberry_dacplusadc_ops,
++ .init = snd_rpi_hifiberry_dacplusadc_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_hifiberry_dacplusadc = {
++ .name = "snd_rpi_hifiberry_dacplusadc",
++ .driver_name = "HifiberryDacpAdc",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_hifiberry_dacplusadc_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplusadc_dai),
++};
++
++
++static int snd_rpi_hifiberry_dacplusadc_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_hifiberry_dacplusadc.dev = &pdev->dev;
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai;
++
++ dai = &snd_rpi_hifiberry_dacplusadc_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++ if (i2s_node) {
++ dai->cpu_of_node = i2s_node;
++ dai->platform_of_node = i2s_node;
++ dai->cpu_dai_name = NULL;
++ dai->platform_name = NULL;
++ }
++ dai = &snd_rpi_hifiberry_dacplusadc_dai[1];
++ i2s_node = of_parse_phandle(pdev->dev.of_node, "dmic", 0);
++ if (i2s_node) {
++ dai->cpu_of_node = i2s_node;
++ dai->platform_of_node = i2s_node;
++ }
++
++ }
++ digital_gain_0db_limit = !of_property_read_bool(
++ pdev->dev.of_node, "hifiberry,24db_digital_gain");
++ slave = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplusadc,slave");
++
++ ret = devm_snd_soc_register_card(&pdev->dev,
++ &snd_rpi_hifiberry_dacplusadc);
++ if (ret && ret != -EPROBE_DEFER)
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static const struct of_device_id snd_rpi_hifiberry_dacplusadc_of_match[] = {
++ { .compatible = "hifiberry,hifiberry-dacplusadc", },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplusadc_of_match);
++
++static struct platform_driver snd_rpi_hifiberry_dacplusadc_driver = {
++ .driver = {
++ .name = "snd-rpi-hifiberry-dacplusadc",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_hifiberry_dacplusadc_of_match,
++ },
++ .probe = snd_rpi_hifiberry_dacplusadc_probe,
++};
++
++static int __init hifiberry_dacplusadc_init(void)
++{
++ int ret;
++
++ dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL,
++ 0);
++ if (IS_ERR(dmic_codec_dev)) {
++ pr_err("%s: dmic-codec device registration failed\n", __func__);
++ return PTR_ERR(dmic_codec_dev);
++ }
++
++ ret = platform_driver_register(&snd_rpi_hifiberry_dacplusadc_driver);
++ if (ret) {
++ pr_err("%s: platform driver registration failed\n", __func__);
++ platform_device_unregister(dmic_codec_dev);
++ }
++
++ return ret;
++}
++module_init(hifiberry_dacplusadc_init);
++
++static void __exit hifiberry_dacplusadc_exit(void)
++{
++ platform_driver_unregister(&snd_rpi_hifiberry_dacplusadc_driver);
++ platform_device_unregister(dmic_codec_dev);
++}
++module_exit(hifiberry_dacplusadc_exit);
++
++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ADC");
++MODULE_LICENSE("GPL v2");
+++ /dev/null
-From 788109b357ddb30a95be72ce46dc22e2335131af Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Jan 2019 15:27:56 +0000
-Subject: [PATCH] overlays: sdio: Add enhanced 1-bit support
-
-"dtoverlay=sdio,bus_width=1,gpios_22_25" is equivalent to the sdio-1bit
-overlay, which is now deprecated.
-
-"dtoverlay=sdio,bus_width=1,gpios_34_37" enables 1-bit mode on GPIOs 34-37.
-
----
- arch/arm/boot/dts/overlays/README | 24 +++++++++++----------
- arch/arm/boot/dts/overlays/sdio-overlay.dts | 20 ++++++++++++++++-
- 2 files changed, 32 insertions(+), 12 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -479,8 +479,7 @@ Params: <None>
-
- Name: bmp085_i2c-sensor
- Info: This overlay is now deprecated - see i2c-sensor
--Load: dtoverlay=bmp085_i2c-sensor
--Params: <None>
-+Load: <Deprecated>
-
-
- Name: dht11
-@@ -1737,7 +1736,8 @@ Params: overclock_50 Clock (i
-
- Name: sdio
- Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock,
-- and enables SDIO via GPIOs 22-27.
-+ and enables SDIO via GPIOs 22-27. An example of use in 1-bit mode is
-+ "dtoverlay=sdio,bus_width=1,gpios_22_25"
- Load: dtoverlay=sdio,<param>=<val>
- Params: sdio_overclock SDIO Clock (in MHz) to use when the MMC
- framework requests 50MHz
-@@ -1747,16 +1747,18 @@ Params: sdio_overclock SDIO Clo
-
- bus_width Set the SDIO host bus width (default 4 bits)
-
-+ gpios_22_25 Select GPIOs 22-25 for 1-bit mode. Must be used
-+ with bus_width=1. This replaces the sdio-1bit
-+ overlay, which is now deprecated.
-
--Name: sdio-1bit
--Info: Selects the bcm2835-sdhost SD/MMC driver, optionally with overclock,
-- and enables 1-bit SDIO via GPIOs 22-25.
--Load: dtoverlay=sdio-1bit,<param>=<val>
--Params: sdio_overclock SDIO Clock (in MHz) to use when the MMC
-- framework requests 50MHz
-+ gpios_34_37 Select GPIOs 34-37 for 1-bit mode. Must be used
-+ with bus_width=1.
-
-- poll_once Disable SDIO-device polling every second
-- (default on: polling once at boot-time)
-+
-+Name: sdio-1bit
-+Info: This overlay is now deprecated. Use
-+ "dtoverlay=sdio,bus_width=1,gpios_22_25" instead.
-+Load: <Deprecated>
-
-
- Name: sdtweak
---- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
-@@ -32,7 +32,7 @@
- pinctrl-names = "default";
- pinctrl-0 = <&sdio_ovl_pins>;
- non-removable;
-- bus-width = <1>;
-+ bus-width = <4>;
- };
- };
- };
-@@ -49,6 +49,22 @@
- };
-
- fragment@3 {
-+ target = <&sdio_ovl_pins>;
-+ __dormant__ {
-+ brcm,pins = <22 23 24 25>;
-+ brcm,pull = <0 2 2 2>;
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&sdio_ovl_pins>;
-+ __dormant__ {
-+ brcm,pins = <34 35 36 37>;
-+ brcm,pull = <0 2 2 2>;
-+ };
-+ };
-+
-+ fragment@6 {
- target-path = "/aliases";
- __overlay__ {
- mmc1 = "/soc/sdio@7e300000";
-@@ -59,5 +75,7 @@
- poll_once = <&sdio_ovl>,"non-removable?";
- bus_width = <&sdio_ovl>,"bus-width:0";
- sdio_overclock = <&sdio_ovl>,"brcm,overclock-50:0";
-+ gpios_22_25 = <0>,"=3";
-+ gpios_34_37 = <0>,"=4";
- };
- };
+++ /dev/null
-From 6e56da00afdf11416045213552514d10bab845cc Mon Sep 17 00:00:00 2001
-Date: Wed, 16 Jan 2019 10:17:52 +0000
-Subject: [PATCH] dwc_otg: fix bug with port_addr assignment for
- single-TT hubs
-
-See https://github.com/raspberrypi/linux/issues/2734
-
-The "Hub Port" field in the split transaction packet was always set
-to 1 for single-TT hubs. The majority of single-TT hub products
-apparently ignore this field and broadcast to all downstream enabled
-ports, which masked the issue. A subset of hub devices apparently
-need the port number to be exact or split transactions will fail.
----
- drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-@@ -232,7 +232,7 @@ static int _hub_info(dwc_otg_hcd_t * hcd
- else
- *hub_addr = urb->dev->tt->hub->devnum;
- }
-- *port_addr = urb->dev->tt->multi ? urb->dev->ttport : 1;
-+ *port_addr = urb->dev->ttport;
- } else {
- *hub_addr = 0;
- *port_addr = urb->dev->ttport;
--- /dev/null
+From 20a5b38305df30e25b4429e0e34e35235dd57228 Mon Sep 17 00:00:00 2001
+Date: Mon, 1 Oct 2018 15:23:57 +0200
+Subject: [PATCH] pwm: Send a uevent on the pwmchip device upon channel
+ sysfs (un)export
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 552c02e3e7cfe2744b59de285aaea70021ae95c9 upstream.
+
+This patch sends a uevent (KOBJ_CHANGE) on the pwmchipN device,
+everytime a pwmX channel has been exported/unexported via sysfs. This
+allows udev to implement rules on such events, like:
+
+SUBSYSTEM=="pwm*", PROGRAM="/bin/sh -c '\
+ chown -R root:gpio /sys/class/pwm && chmod -R 770 /sys/class/pwm;\
+ chown -R root:gpio
+/sys/devices/platform/soc/*.pwm/pwm/pwmchip* && chmod -R 770
+/sys/devices/platform/soc/*.pwm/pwm/pwmchip*\
+'"
+
+This is a replacement patch for commit 7e5d1fd75c3d ("pwm: Set class for
+exported channels in sysfs"), see [1].
+
+basic testing:
+$ udevadm monitor --environment &
+$ echo 0 > /sys/class/pwm/pwmchip0/export
+KERNEL[197.321736] change /devices/.../pwm/pwmchip0 (pwm)
+ACTION=change
+DEVPATH=/devices/.../pwm/pwmchip0
+EXPORT=pwm0
+SEQNUM=2045
+SUBSYSTEM=pwm
+
+[1] https://lkml.org/lkml/2018/9/25/713
+
+---
+ drivers/pwm/sysfs.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/drivers/pwm/sysfs.c
++++ b/drivers/pwm/sysfs.c
+@@ -249,6 +249,7 @@ static void pwm_export_release(struct de
+ static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
+ {
+ struct pwm_export *export;
++ char *pwm_prop[2];
+ int ret;
+
+ if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags))
+@@ -276,6 +277,10 @@ static int pwm_export_child(struct devic
+ export = NULL;
+ return ret;
+ }
++ pwm_prop[0] = kasprintf(GFP_KERNEL, "EXPORT=pwm%u", pwm->hwpwm);
++ pwm_prop[1] = NULL;
++ kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop);
++ kfree(pwm_prop[0]);
+
+ return 0;
+ }
+@@ -288,6 +293,7 @@ static int pwm_unexport_match(struct dev
+ static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
+ {
+ struct device *child;
++ char *pwm_prop[2];
+
+ if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags))
+ return -ENODEV;
+@@ -296,6 +302,11 @@ static int pwm_unexport_child(struct dev
+ if (!child)
+ return -ENODEV;
+
++ pwm_prop[0] = kasprintf(GFP_KERNEL, "UNEXPORT=pwm%u", pwm->hwpwm);
++ pwm_prop[1] = NULL;
++ kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop);
++ kfree(pwm_prop[0]);
++
+ /* for device_find_child() */
+ put_device(child);
+ device_unregister(child);
+++ /dev/null
-From dde0ec6b9fd5755de3a8962489cde9c0ce5e5005 Mon Sep 17 00:00:00 2001
-Date: Mon, 8 Oct 2018 18:10:12 +0200
-Subject: [PATCH] Added driver for the HiFiBerry DAC+ ADC (#2694)
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 21 +
- .../overlays/hifiberry-dacplusadc-overlay.dts | 71 +++
- sound/soc/bcm/Kconfig | 8 +
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/hifiberry_dacplusadc.c | 407 ++++++++++++++++++
- 8 files changed, 512 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
- create mode 100644 sound/soc/bcm/hifiberry_dacplusadc.c
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -49,6 +49,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- hifiberry-amp.dtbo \
- hifiberry-dac.dtbo \
- hifiberry-dacplus.dtbo \
-+ hifiberry-dacplusadc.dtbo \
- hifiberry-digi.dtbo \
- hifiberry-digi-pro.dtbo \
- hy28a.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -779,6 +779,27 @@ Params: 24db_digital_gain Allow ga
- master for bit clock and frame clock.
-
-
-+Name: hifiberry-dacplusadc
-+Info: Configures the HifiBerry DAC+ADC audio card
-+Load: dtoverlay=hifiberry-dacplusadc,<param>=<val>
-+Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
-+ Digital volume control. Enable with
-+ "dtoverlay=hifiberry-dacplus,24db_digital_gain"
-+ (The default behaviour is that the Digital
-+ volume control is limited to a maximum of
-+ 0dB. ie. it can attenuate but not provide
-+ gain. For most users, this will be desired
-+ as it will prevent clipping. By appending
-+ the 24dB_digital_gain parameter, the Digital
-+ volume control will allow up to 24dB of
-+ gain. If this parameter is enabled, it is the
-+ responsibility of the user to ensure that
-+ the Digital volume control is set to a value
-+ that does not result in clipping/distortion!)
-+ slave Force DAC+ Pro into slave mode, using Pi as
-+ master for bit clock and frame clock.
-+
-+
- Name: hifiberry-digi
- Info: Configures the HifiBerry Digi and Digi+ audio card
- Load: dtoverlay=hifiberry-digi
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
-@@ -0,0 +1,71 @@
-+// Definitions for HiFiBerry DAC+ADC
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target-path = "/clocks";
-+ __overlay__ {
-+ dacpro_osc: dacpro_osc {
-+ compatible = "hifiberry,dacpro-clk";
-+ #clock-cells = <0>;
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ pcm_codec: pcm5122@4d {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,pcm5122";
-+ reg = <0x4d>;
-+ clocks = <&dacpro_osc>;
-+ AVDD-supply = <&vdd_3v3_reg>;
-+ DVDD-supply = <&vdd_3v3_reg>;
-+ CPVDD-supply = <&vdd_3v3_reg>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target-path = "/";
-+ __overlay__ {
-+ dmic {
-+ #sound-dai-cells = <0>;
-+ compatible = "dmic-codec";
-+ num-channels = <2>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&sound>;
-+ hifiberry_dacplusadc: __overlay__ {
-+ compatible = "hifiberry,hifiberry-dacplusadc";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ 24db_digital_gain =
-+ <&hifiberry_dacplusadc>,"hifiberry,24db_digital_gain?";
-+ slave = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,slave?";
-+ };
-+};
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -46,6 +46,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
- help
- Say Y or M if you want to add support for HifiBerry DAC+.
-
-+config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC
-+ tristate "Support for HifiBerry DAC+ADC"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_PCM512x_I2C
-+ select SND_SOC_DMIC
-+ help
-+ Say Y or M if you want to add support for HifiBerry DAC+ADC.
-+
- config SND_BCM2708_SOC_HIFIBERRY_DIGI
- tristate "Support for HifiBerry Digi"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -14,6 +14,7 @@ snd-soc-googlevoicehat-codec-objs := goo
- # BCM2708 Machine Support
- snd-soc-3dlab-nano-player-objs := 3dlab-nano-player.o
- snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
-+snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
- snd-soc-justboom-dac-objs := justboom-dac.o
- snd-soc-rpi-cirrus-objs := rpi-cirrus.o
- snd-soc-rpi-proto-objs := rpi-proto.o
-@@ -36,6 +37,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi
- obj-$(CONFIG_SND_BCM2708_SOC_3DLAB_NANO_PLAYER) += snd-soc-3dlab-nano-player.o
- obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
-+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
- obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
---- /dev/null
-+++ b/sound/soc/bcm/hifiberry_dacplusadc.c
-@@ -0,0 +1,407 @@
-+/*
-+ * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC
-+ *
-+ * Copyright 2014-2015
-+ * Copyright 2018
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/kernel.h>
-+#include <linux/clk.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+
-+#include "../codecs/pcm512x.h"
-+
-+#define HIFIBERRY_DACPRO_NOCLOCK 0
-+#define HIFIBERRY_DACPRO_CLK44EN 1
-+#define HIFIBERRY_DACPRO_CLK48EN 2
-+
-+struct platform_device *dmic_codec_dev;
-+
-+struct pcm512x_priv {
-+ struct regmap *regmap;
-+ struct clk *sclk;
-+};
-+
-+/* Clock rate of CLK44EN attached to GPIO6 pin */
-+#define CLK_44EN_RATE 22579200UL
-+/* Clock rate of CLK48EN attached to GPIO3 pin */
-+#define CLK_48EN_RATE 24576000UL
-+
-+static bool slave;
-+static bool snd_rpi_hifiberry_is_dacpro;
-+static bool digital_gain_0db_limit = true;
-+
-+static void snd_rpi_hifiberry_dacplusadc_select_clk(struct snd_soc_component *component,
-+ int clk_id)
-+{
-+ switch (clk_id) {
-+ case HIFIBERRY_DACPRO_NOCLOCK:
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
-+ break;
-+ case HIFIBERRY_DACPRO_CLK44EN:
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
-+ break;
-+ case HIFIBERRY_DACPRO_CLK48EN:
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
-+ break;
-+ }
-+}
-+
-+static void snd_rpi_hifiberry_dacplusadc_clk_gpio(struct snd_soc_component *component)
-+{
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24);
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
-+}
-+
-+static bool snd_rpi_hifiberry_dacplusadc_is_sclk(struct snd_soc_component *component)
-+{
-+ unsigned int sck;
-+
-+ snd_soc_component_read(component, PCM512x_RATE_DET_4, &sck);
-+ return (!(sck & 0x40));
-+}
-+
-+static bool snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(
-+ struct snd_soc_component *component)
-+{
-+ msleep(2);
-+ return snd_rpi_hifiberry_dacplusadc_is_sclk(component);
-+}
-+
-+static bool snd_rpi_hifiberry_dacplusadc_is_pro_card(struct snd_soc_component *component)
-+{
-+ bool isClk44EN, isClk48En, isNoClk;
-+
-+ snd_rpi_hifiberry_dacplusadc_clk_gpio(component);
-+
-+ snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_CLK44EN);
-+ isClk44EN = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component);
-+
-+ snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK);
-+ isNoClk = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component);
-+
-+ snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_CLK48EN);
-+ isClk48En = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component);
-+
-+ return (isClk44EN && isClk48En && !isNoClk);
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadc_clk_for_rate(int sample_rate)
-+{
-+ int type;
-+
-+ switch (sample_rate) {
-+ case 11025:
-+ case 22050:
-+ case 44100:
-+ case 88200:
-+ case 176400:
-+ case 352800:
-+ type = HIFIBERRY_DACPRO_CLK44EN;
-+ break;
-+ default:
-+ type = HIFIBERRY_DACPRO_CLK48EN;
-+ break;
-+ }
-+ return type;
-+}
-+
-+static void snd_rpi_hifiberry_dacplusadc_set_sclk(struct snd_soc_component *component,
-+ int sample_rate)
-+{
-+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
-+
-+ if (!IS_ERR(pcm512x->sclk)) {
-+ int ctype;
-+
-+ ctype = snd_rpi_hifiberry_dacplusadc_clk_for_rate(sample_rate);
-+ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN)
-+ ? CLK_44EN_RATE : CLK_48EN_RATE);
-+ snd_rpi_hifiberry_dacplusadc_select_clk(component, ctype);
-+ }
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadc_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ struct snd_soc_component *component = rtd->codec_dai->component;
-+ struct pcm512x_priv *priv;
-+
-+ if (slave)
-+ snd_rpi_hifiberry_is_dacpro = false;
-+ else
-+ snd_rpi_hifiberry_is_dacpro =
-+ snd_rpi_hifiberry_dacplusadc_is_pro_card(component);
-+
-+ if (snd_rpi_hifiberry_is_dacpro) {
-+ struct snd_soc_dai_link *dai = rtd->dai_link;
-+
-+ dai->name = "HiFiBerry ADCDAC+ Pro";
-+ dai->stream_name = "HiFiBerry ADCDAC+ Pro HiFi";
-+ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-+ | SND_SOC_DAIFMT_CBM_CFM;
-+
-+ snd_soc_component_update_bits(component, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
-+ snd_soc_component_update_bits(component, PCM512x_MASTER_MODE, 0x03, 0x03);
-+ snd_soc_component_update_bits(component, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
-+ } else {
-+ priv = snd_soc_component_get_drvdata(component);
-+ priv->sclk = ERR_PTR(-ENOENT);
-+ }
-+
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+
-+ if (digital_gain_0db_limit) {
-+ int ret;
-+ struct snd_soc_card *card = rtd->card;
-+
-+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
-+ if (ret < 0)
-+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
-+ }
-+
-+ return 0;
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadc_update_rate_den(
-+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *component = rtd->codec_dai->component;
-+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
-+ struct snd_ratnum *rats_no_pll;
-+ unsigned int num = 0, den = 0;
-+ int err;
-+
-+ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
-+ if (!rats_no_pll)
-+ return -ENOMEM;
-+
-+ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
-+ rats_no_pll->den_min = 1;
-+ rats_no_pll->den_max = 128;
-+ rats_no_pll->den_step = 1;
-+
-+ err = snd_interval_ratnum(hw_param_interval(params,
-+ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
-+ if (err >= 0 && den) {
-+ params->rate_num = num;
-+ params->rate_den = den;
-+ }
-+
-+ devm_kfree(rtd->dev, rats_no_pll);
-+ return 0;
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadc_hw_params(
-+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
-+{
-+ int ret = 0;
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ int channels = params_channels(params);
-+ int width = 32;
-+
-+ if (snd_rpi_hifiberry_is_dacpro) {
-+ struct snd_soc_component *component = rtd->codec_dai->component;
-+
-+ width = snd_pcm_format_physical_width(params_format(params));
-+
-+ snd_rpi_hifiberry_dacplusadc_set_sclk(component,
-+ params_rate(params));
-+
-+ ret = snd_rpi_hifiberry_dacplusadc_update_rate_den(
-+ substream, params);
-+ }
-+
-+ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x03, 0x03,
-+ channels, width);
-+ if (ret)
-+ return ret;
-+ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, 0x03, 0x03,
-+ channels, width);
-+ return ret;
-+}
-+
-+static int hifiberry_dacplusadc_LED_cnt;
-+
-+static int snd_rpi_hifiberry_dacplusadc_startup(
-+ struct snd_pcm_substream *substream)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *component = rtd->codec_dai->component;
-+
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1,
-+ 0x08, 0x08);
-+ hifiberry_dacplusadc_LED_cnt++;
-+ return 0;
-+}
-+
-+static void snd_rpi_hifiberry_dacplusadc_shutdown(
-+ struct snd_pcm_substream *substream)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *component = rtd->codec_dai->component;
-+
-+ hifiberry_dacplusadc_LED_cnt--;
-+ if (!hifiberry_dacplusadc_LED_cnt)
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1,
-+ 0x08, 0x00);
-+}
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_hifiberry_dacplusadc_ops = {
-+ .hw_params = snd_rpi_hifiberry_dacplusadc_hw_params,
-+ .startup = snd_rpi_hifiberry_dacplusadc_startup,
-+ .shutdown = snd_rpi_hifiberry_dacplusadc_shutdown,
-+};
-+
-+static struct snd_soc_dai_link_component snd_rpi_hifiberry_dacplusadc_codecs[] = {
-+ {
-+ .name = "pcm512x.1-004d",
-+ .dai_name = "pcm512x-hifi",
-+ },
-+ {
-+ .name = "dmic-codec",
-+ .dai_name = "dmic-hifi",
-+ },
-+};
-+
-+static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadc_dai[] = {
-+{
-+ .name = "HiFiBerry DAC+ADC",
-+ .stream_name = "HiFiBerry DAC+ADC HiFi",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codecs = snd_rpi_hifiberry_dacplusadc_codecs,
-+ .num_codecs = 2,
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBS_CFS,
-+ .ops = &snd_rpi_hifiberry_dacplusadc_ops,
-+ .init = snd_rpi_hifiberry_dacplusadc_init,
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_hifiberry_dacplusadc = {
-+ .name = "snd_rpi_hifiberry_dacplusadc",
-+ .driver_name = "HifiberryDacpAdc",
-+ .owner = THIS_MODULE,
-+ .dai_link = snd_rpi_hifiberry_dacplusadc_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplusadc_dai),
-+};
-+
-+
-+static int snd_rpi_hifiberry_dacplusadc_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ snd_rpi_hifiberry_dacplusadc.dev = &pdev->dev;
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai;
-+
-+ dai = &snd_rpi_hifiberry_dacplusadc_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+ if (i2s_node) {
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_of_node = i2s_node;
-+ dai->cpu_dai_name = NULL;
-+ dai->platform_name = NULL;
-+ }
-+ dai = &snd_rpi_hifiberry_dacplusadc_dai[1];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node, "dmic", 0);
-+ if (i2s_node) {
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_of_node = i2s_node;
-+ }
-+
-+ }
-+ digital_gain_0db_limit = !of_property_read_bool(
-+ pdev->dev.of_node, "hifiberry,24db_digital_gain");
-+ slave = of_property_read_bool(pdev->dev.of_node,
-+ "hifiberry-dacplusadc,slave");
-+
-+ ret = devm_snd_soc_register_card(&pdev->dev,
-+ &snd_rpi_hifiberry_dacplusadc);
-+ if (ret && ret != -EPROBE_DEFER)
-+ dev_err(&pdev->dev,
-+ "snd_soc_register_card() failed: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static const struct of_device_id snd_rpi_hifiberry_dacplusadc_of_match[] = {
-+ { .compatible = "hifiberry,hifiberry-dacplusadc", },
-+ {},
-+};
-+
-+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplusadc_of_match);
-+
-+static struct platform_driver snd_rpi_hifiberry_dacplusadc_driver = {
-+ .driver = {
-+ .name = "snd-rpi-hifiberry-dacplusadc",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_hifiberry_dacplusadc_of_match,
-+ },
-+ .probe = snd_rpi_hifiberry_dacplusadc_probe,
-+};
-+
-+static int __init hifiberry_dacplusadc_init(void)
-+{
-+ int ret;
-+
-+ dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL,
-+ 0);
-+ if (IS_ERR(dmic_codec_dev)) {
-+ pr_err("%s: dmic-codec device registration failed\n", __func__);
-+ return PTR_ERR(dmic_codec_dev);
-+ }
-+
-+ ret = platform_driver_register(&snd_rpi_hifiberry_dacplusadc_driver);
-+ if (ret) {
-+ pr_err("%s: platform driver registration failed\n", __func__);
-+ platform_device_unregister(dmic_codec_dev);
-+ }
-+
-+ return ret;
-+}
-+module_init(hifiberry_dacplusadc_init);
-+
-+static void __exit hifiberry_dacplusadc_exit(void)
-+{
-+ platform_driver_unregister(&snd_rpi_hifiberry_dacplusadc_driver);
-+ platform_device_unregister(dmic_codec_dev);
-+}
-+module_exit(hifiberry_dacplusadc_exit);
-+
-+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ADC");
-+MODULE_LICENSE("GPL v2");
--- /dev/null
+From d8eac0d3e4f6c6f9e5f789c8e2288699b2afebcb Mon Sep 17 00:00:00 2001
+Date: Mon, 21 Jan 2019 21:17:27 +0000
+Subject: [PATCH] overlays: Add ssd1306 overlay for OLED display
+
+See: https://github.com/raspberrypi/firmware/issues/1098
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 31 ++++++++++++++++
+ .../arm/boot/dts/overlays/ssd1306-overlay.dts | 36 +++++++++++++++++++
+ 3 files changed, 68 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/ssd1306-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -135,6 +135,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ spi2-1cs.dtbo \
+ spi2-2cs.dtbo \
+ spi2-3cs.dtbo \
++ ssd1306.dtbo \
+ superaudioboard.dtbo \
+ sx150x.dtbo \
+ tc358743.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1950,6 +1950,37 @@ Params: cs0_pin GPIO pin
+ is 'okay' or enabled).
+
+
++Name: ssd1306
++Info: Overlay for activation of SSD1306 over I2C OLED display framebuffer.
++Load: dtoverlay=ssd1306,<param>=<val>
++Params: address Location in display memory of first character.
++ (default=0)
++ width Width of display. (default=128)
++ height Height of display. (default=64)
++ offset virtual channel a. (default=0)
++ normal Has no effect on displays tested. (default=not
++ set)
++ sequential Set this if every other scan line is missing.
++ (default=not set)
++ remapped Set this if display is garbled. (default=not
++ set)
++ inverted Set this if display is inverted and mirrored.
++ (default=not set)
++
++ Examples:
++ Typical usage for 128x64 display: dtoverlay=ssd1306,inverted
++
++ Typical usage for 128x32 display: dtoverlay=ssd1306,inverted,sequential
++
++ i2c_baudrate=400000 will speed up the display.
++
++ i2c_baudrate=1000000 seems to work even though it's not officially
++ supported by the hardware, and is faster still.
++
++ For more information refer to the device datasheet at:
++ https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
++
++
+ Name: superaudioboard
+ Info: Configures the SuperAudioBoard sound card
+ Load: dtoverlay=superaudioboard,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/ssd1306-overlay.dts
+@@ -0,0 +1,36 @@
++// Overlay for SSD1306 128x64 and 128x32 OLED displays
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2718";
++
++ fragment@0 {
++ target = <&i2c1>;
++ __overlay__ {
++ status = "okay";
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ ssd1306: oled@3c{
++ compatible = "solomon,ssd1306fb-i2c";
++ reg = <0x3c>;
++ solomon,width = <128>;
++ solomon,height = <64>;
++ solomon,page-offset = <0>;
++ };
++ };
++ };
++
++ __overrides__ {
++ address = <&ssd1306>,"reg:0";
++ width = <&ssd1306>,"solomon,width:0";
++ height = <&ssd1306>,"solomon,height:0";
++ offset = <&ssd1306>,"solomon,page-offset:0";
++ normal = <&ssd1306>,"solomon,segment-no-remap?";
++ sequential = <&ssd1306>,"solomon,com-seq?";
++ remapped = <&ssd1306>,"solomon,com-lrremap?";
++ inverted = <&ssd1306>,"solomon,com-invdir?";
++ };
++};
--- /dev/null
+From c85a1ccbc6b1cab51a5fe5b916bcaf40bcd9096c Mon Sep 17 00:00:00 2001
+Date: Mon, 21 Jan 2019 12:19:57 +0000
+Subject: [PATCH] overlays: mcp23017: Support the MCP23008
+
+Add an 'mcp23008' parameter to enable support for the MCP23008 device.
+
+See: https://github.com/raspberrypi/linux/issues/2818
+
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 10 +++++++++-
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1212,6 +1212,8 @@ Params: gpiopin Gpio pin
+
+ addr I2C address of the MCP23017 (default: 0x20)
+
++ mcp23008 Configure an MCP23008 instead.
++
+
+ Name: mcp23s17
+ Info: Configures the MCP23S08/17 SPI GPIO expanders.
+--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
+@@ -44,11 +44,19 @@
+ };
+ };
+ };
+-
++
++ fragment@3 {
++ target = <&mcp23017>;
++ __dormant__ {
++ compatible = "microchip,mcp23008";
++ };
++ };
++
+ __overrides__ {
+ gpiopin = <&mcp23017_pins>,"brcm,pins:0",
+ <&mcp23017>,"interrupts:0";
+ addr = <&mcp23017>,"reg:0";
++ mcp23008 = <0>,"=3";
+ };
+ };
+
+++ /dev/null
-From 20a5b38305df30e25b4429e0e34e35235dd57228 Mon Sep 17 00:00:00 2001
-Date: Mon, 1 Oct 2018 15:23:57 +0200
-Subject: [PATCH] pwm: Send a uevent on the pwmchip device upon channel
- sysfs (un)export
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-commit 552c02e3e7cfe2744b59de285aaea70021ae95c9 upstream.
-
-This patch sends a uevent (KOBJ_CHANGE) on the pwmchipN device,
-everytime a pwmX channel has been exported/unexported via sysfs. This
-allows udev to implement rules on such events, like:
-
-SUBSYSTEM=="pwm*", PROGRAM="/bin/sh -c '\
- chown -R root:gpio /sys/class/pwm && chmod -R 770 /sys/class/pwm;\
- chown -R root:gpio
-/sys/devices/platform/soc/*.pwm/pwm/pwmchip* && chmod -R 770
-/sys/devices/platform/soc/*.pwm/pwm/pwmchip*\
-'"
-
-This is a replacement patch for commit 7e5d1fd75c3d ("pwm: Set class for
-exported channels in sysfs"), see [1].
-
-basic testing:
-$ udevadm monitor --environment &
-$ echo 0 > /sys/class/pwm/pwmchip0/export
-KERNEL[197.321736] change /devices/.../pwm/pwmchip0 (pwm)
-ACTION=change
-DEVPATH=/devices/.../pwm/pwmchip0
-EXPORT=pwm0
-SEQNUM=2045
-SUBSYSTEM=pwm
-
-[1] https://lkml.org/lkml/2018/9/25/713
-
----
- drivers/pwm/sysfs.c | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
---- a/drivers/pwm/sysfs.c
-+++ b/drivers/pwm/sysfs.c
-@@ -249,6 +249,7 @@ static void pwm_export_release(struct de
- static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
- {
- struct pwm_export *export;
-+ char *pwm_prop[2];
- int ret;
-
- if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags))
-@@ -276,6 +277,10 @@ static int pwm_export_child(struct devic
- export = NULL;
- return ret;
- }
-+ pwm_prop[0] = kasprintf(GFP_KERNEL, "EXPORT=pwm%u", pwm->hwpwm);
-+ pwm_prop[1] = NULL;
-+ kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop);
-+ kfree(pwm_prop[0]);
-
- return 0;
- }
-@@ -288,6 +293,7 @@ static int pwm_unexport_match(struct dev
- static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
- {
- struct device *child;
-+ char *pwm_prop[2];
-
- if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags))
- return -ENODEV;
-@@ -296,6 +302,11 @@ static int pwm_unexport_child(struct dev
- if (!child)
- return -ENODEV;
-
-+ pwm_prop[0] = kasprintf(GFP_KERNEL, "UNEXPORT=pwm%u", pwm->hwpwm);
-+ pwm_prop[1] = NULL;
-+ kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop);
-+ kfree(pwm_prop[0]);
-+
- /* for device_find_child() */
- put_device(child);
- device_unregister(child);
--- /dev/null
+From b71f1fd962c66ba3fa46483f193cc2263146c5bf Mon Sep 17 00:00:00 2001
+Date: Mon, 21 Jan 2019 12:23:55 +0000
+Subject: [PATCH] overlays: Add mcp342x overlay
+
+Support the MCP342x family of ADCs from Microchip.
+
+See: https://github.com/raspberrypi/linux/issues/2819
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 16 ++++
+ .../arm/boot/dts/overlays/mcp342x-overlay.dts | 93 +++++++++++++++++++
+ 3 files changed, 110 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/mcp342x-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -79,6 +79,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ mcp2515-can1.dtbo \
+ mcp3008.dtbo \
+ mcp3202.dtbo \
++ mcp342x.dtbo \
+ media-center.dtbo \
+ midi-uart0.dtbo \
+ midi-uart1.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1277,6 +1277,22 @@ Params: spi<n>-<m>-present boolean,
+ spi<n>-<m>-speed integer, set the spi bus speed for this device
+
+
++Name: mcp342x
++Info: Overlay for activation of Microchip MCP3421-3428 ADCs over I2C
++Load: dtoverlay=mcp342x,<param>=<val>
++Params: addr I2C bus address of device, for devices with
++ addresses that are configurable, e.g. by
++ hardware links (default=0x68)
++ mcp3421 The device is an MCP3421
++ mcp3422 The device is an MCP3422
++ mcp3423 The device is an MCP3423
++ mcp3424 The device is an MCP3424
++ mcp3425 The device is an MCP3425
++ mcp3426 The device is an MCP3426
++ mcp3427 The device is an MCP3427
++ mcp3428 The device is an MCP3428
++
++
+ Name: media-center
+ Info: Media Center HAT - 2.83" Touch Display + extras by Pi Supply
+ Load: dtoverlay=media-center,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
+@@ -0,0 +1,93 @@
++// Overlay for MCP3421-8 ADCs from Microchip Semiconductor
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ fragment@0 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp342x: mcp@68 {
++ reg = <0x68>;
++
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&mcp342x>;
++ __dormant__ {
++ compatible = "microchip,mcp3421";
++ };
++ };
++
++ fragment@2 {
++ target = <&mcp342x>;
++ __dormant__ {
++ compatible = "microchip,mcp3422";
++ };
++ };
++
++ fragment@3 {
++ target = <&mcp342x>;
++ __dormant__ {
++ compatible = "microchip,mcp3423";
++ };
++ };
++
++ fragment@4 {
++ target = <&mcp342x>;
++ __dormant__ {
++ compatible = "microchip,mcp3424";
++ };
++ };
++
++ fragment@5 {
++ target = <&mcp342x>;
++ __dormant__ {
++ compatible = "microchip,mcp3425";
++ };
++ };
++
++ fragment@6 {
++ target = <&mcp342x>;
++ __dormant__ {
++ compatible = "microchip,mcp3426";
++ };
++ };
++
++ fragment@7 {
++ target = <&mcp342x>;
++ __dormant__ {
++ compatible = "microchip,mcp3427";
++ };
++ };
++
++ fragment@8 {
++ target = <&mcp342x>;
++ __dormant__ {
++ compatible = "microchip,mcp3428";
++ };
++ };
++
++ __overrides__ {
++ addr = <&mcp342x>,"reg:0";
++ mcp3421 = <0>,"=1";
++ mcp3422 = <0>,"=2";
++ mcp3423 = <0>,"=3";
++ mcp3424 = <0>,"=4";
++ mcp3425 = <0>,"=5";
++ mcp3426 = <0>,"=6";
++ mcp3427 = <0>,"=7";
++ mcp3428 = <0>,"=8";
++ };
++};
++
+++ /dev/null
-From d8eac0d3e4f6c6f9e5f789c8e2288699b2afebcb Mon Sep 17 00:00:00 2001
-Date: Mon, 21 Jan 2019 21:17:27 +0000
-Subject: [PATCH] overlays: Add ssd1306 overlay for OLED display
-
-See: https://github.com/raspberrypi/firmware/issues/1098
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 31 ++++++++++++++++
- .../arm/boot/dts/overlays/ssd1306-overlay.dts | 36 +++++++++++++++++++
- 3 files changed, 68 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/ssd1306-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -135,6 +135,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- spi2-1cs.dtbo \
- spi2-2cs.dtbo \
- spi2-3cs.dtbo \
-+ ssd1306.dtbo \
- superaudioboard.dtbo \
- sx150x.dtbo \
- tc358743.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1950,6 +1950,37 @@ Params: cs0_pin GPIO pin
- is 'okay' or enabled).
-
-
-+Name: ssd1306
-+Info: Overlay for activation of SSD1306 over I2C OLED display framebuffer.
-+Load: dtoverlay=ssd1306,<param>=<val>
-+Params: address Location in display memory of first character.
-+ (default=0)
-+ width Width of display. (default=128)
-+ height Height of display. (default=64)
-+ offset virtual channel a. (default=0)
-+ normal Has no effect on displays tested. (default=not
-+ set)
-+ sequential Set this if every other scan line is missing.
-+ (default=not set)
-+ remapped Set this if display is garbled. (default=not
-+ set)
-+ inverted Set this if display is inverted and mirrored.
-+ (default=not set)
-+
-+ Examples:
-+ Typical usage for 128x64 display: dtoverlay=ssd1306,inverted
-+
-+ Typical usage for 128x32 display: dtoverlay=ssd1306,inverted,sequential
-+
-+ i2c_baudrate=400000 will speed up the display.
-+
-+ i2c_baudrate=1000000 seems to work even though it's not officially
-+ supported by the hardware, and is faster still.
-+
-+ For more information refer to the device datasheet at:
-+ https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
-+
-+
- Name: superaudioboard
- Info: Configures the SuperAudioBoard sound card
- Load: dtoverlay=superaudioboard,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/ssd1306-overlay.dts
-@@ -0,0 +1,36 @@
-+// Overlay for SSD1306 128x64 and 128x32 OLED displays
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2718";
-+
-+ fragment@0 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ ssd1306: oled@3c{
-+ compatible = "solomon,ssd1306fb-i2c";
-+ reg = <0x3c>;
-+ solomon,width = <128>;
-+ solomon,height = <64>;
-+ solomon,page-offset = <0>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ address = <&ssd1306>,"reg:0";
-+ width = <&ssd1306>,"solomon,width:0";
-+ height = <&ssd1306>,"solomon,height:0";
-+ offset = <&ssd1306>,"solomon,page-offset:0";
-+ normal = <&ssd1306>,"solomon,segment-no-remap?";
-+ sequential = <&ssd1306>,"solomon,com-seq?";
-+ remapped = <&ssd1306>,"solomon,com-lrremap?";
-+ inverted = <&ssd1306>,"solomon,com-invdir?";
-+ };
-+};
--- /dev/null
+From 70194b474d22974cd46356e5b3d3b0582abd02da Mon Sep 17 00:00:00 2001
+Date: Thu, 24 Jan 2019 13:56:30 +0000
+Subject: [PATCH] char: vcio: Add compat ioctl handling
+
+There was no compat ioctl handler, so 32 bit userspace on a
+64 bit kernel failed as IOCTL_MBOX_PROPERTY used the size
+of char*.
+
+---
+ drivers/char/broadcom/vcio.c | 22 +++++++++++++++++++++-
+ 1 file changed, 21 insertions(+), 1 deletion(-)
+
+--- a/drivers/char/broadcom/vcio.c
++++ b/drivers/char/broadcom/vcio.c
+@@ -24,6 +24,9 @@
+
+ #define VCIO_IOC_MAGIC 100
+ #define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
++#ifdef CONFIG_COMPAT
++#define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
++#endif
+
+ static struct {
+ dev_t devt;
+@@ -87,13 +90,30 @@ static long vcio_device_ioctl(struct fil
+ case IOCTL_MBOX_PROPERTY:
+ return vcio_user_property_list((void *)ioctl_param);
+ default:
+- pr_err("unknown ioctl: %d\n", ioctl_num);
++ pr_err("unknown ioctl: %x\n", ioctl_num);
+ return -EINVAL;
+ }
+ }
+
++#ifdef CONFIG_COMPAT
++static long vcio_device_compat_ioctl(struct file *file, unsigned int ioctl_num,
++ unsigned long ioctl_param)
++{
++ switch (ioctl_num) {
++ case IOCTL_MBOX_PROPERTY32:
++ return vcio_user_property_list(compat_ptr(ioctl_param));
++ default:
++ pr_err("unknown ioctl: %x\n", ioctl_num);
++ return -EINVAL;
++ }
++}
++#endif
++
+ const struct file_operations vcio_fops = {
+ .unlocked_ioctl = vcio_device_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = vcio_device_compat_ioctl,
++#endif
+ .open = vcio_device_open,
+ .release = vcio_device_release,
+ };
+++ /dev/null
-From c85a1ccbc6b1cab51a5fe5b916bcaf40bcd9096c Mon Sep 17 00:00:00 2001
-Date: Mon, 21 Jan 2019 12:19:57 +0000
-Subject: [PATCH] overlays: mcp23017: Support the MCP23008
-
-Add an 'mcp23008' parameter to enable support for the MCP23008 device.
-
-See: https://github.com/raspberrypi/linux/issues/2818
-
----
- arch/arm/boot/dts/overlays/README | 2 ++
- arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 10 +++++++++-
- 2 files changed, 11 insertions(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1212,6 +1212,8 @@ Params: gpiopin Gpio pin
-
- addr I2C address of the MCP23017 (default: 0x20)
-
-+ mcp23008 Configure an MCP23008 instead.
-+
-
- Name: mcp23s17
- Info: Configures the MCP23S08/17 SPI GPIO expanders.
---- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
-@@ -44,11 +44,19 @@
- };
- };
- };
--
-+
-+ fragment@3 {
-+ target = <&mcp23017>;
-+ __dormant__ {
-+ compatible = "microchip,mcp23008";
-+ };
-+ };
-+
- __overrides__ {
- gpiopin = <&mcp23017_pins>,"brcm,pins:0",
- <&mcp23017>,"interrupts:0";
- addr = <&mcp23017>,"reg:0";
-+ mcp23008 = <0>,"=3";
- };
- };
-
--- /dev/null
+From 6880e5c73b75be683299debf391eba4f521cc20f Mon Sep 17 00:00:00 2001
+Date: Thu, 24 Jan 2019 14:03:28 +0000
+Subject: [PATCH] char: vcio: Fail probe if rpi_firmware is not found.
+
+Device Tree is now the only supported config mechanism, therefore
+uncomment the block of code that fails the probe if the
+firmware node can't be found.
+
+---
+ drivers/char/broadcom/vcio.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/char/broadcom/vcio.c
++++ b/drivers/char/broadcom/vcio.c
+@@ -126,10 +126,9 @@ static int __init vcio_init(void)
+
+ np = of_find_compatible_node(NULL, NULL,
+ "raspberrypi,bcm2835-firmware");
+-/* Uncomment this when we only boot with Device Tree
+ if (!of_device_is_available(np))
+ return -ENODEV;
+-*/
++
+ vcio.fw = rpi_firmware_get(np);
+ if (!vcio.fw)
+ return -ENODEV;
+++ /dev/null
-From b71f1fd962c66ba3fa46483f193cc2263146c5bf Mon Sep 17 00:00:00 2001
-Date: Mon, 21 Jan 2019 12:23:55 +0000
-Subject: [PATCH] overlays: Add mcp342x overlay
-
-Support the MCP342x family of ADCs from Microchip.
-
-See: https://github.com/raspberrypi/linux/issues/2819
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 16 ++++
- .../arm/boot/dts/overlays/mcp342x-overlay.dts | 93 +++++++++++++++++++
- 3 files changed, 110 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/mcp342x-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -79,6 +79,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- mcp2515-can1.dtbo \
- mcp3008.dtbo \
- mcp3202.dtbo \
-+ mcp342x.dtbo \
- media-center.dtbo \
- midi-uart0.dtbo \
- midi-uart1.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1277,6 +1277,22 @@ Params: spi<n>-<m>-present boolean,
- spi<n>-<m>-speed integer, set the spi bus speed for this device
-
-
-+Name: mcp342x
-+Info: Overlay for activation of Microchip MCP3421-3428 ADCs over I2C
-+Load: dtoverlay=mcp342x,<param>=<val>
-+Params: addr I2C bus address of device, for devices with
-+ addresses that are configurable, e.g. by
-+ hardware links (default=0x68)
-+ mcp3421 The device is an MCP3421
-+ mcp3422 The device is an MCP3422
-+ mcp3423 The device is an MCP3423
-+ mcp3424 The device is an MCP3424
-+ mcp3425 The device is an MCP3425
-+ mcp3426 The device is an MCP3426
-+ mcp3427 The device is an MCP3427
-+ mcp3428 The device is an MCP3428
-+
-+
- Name: media-center
- Info: Media Center HAT - 2.83" Touch Display + extras by Pi Supply
- Load: dtoverlay=media-center,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
-@@ -0,0 +1,93 @@
-+// Overlay for MCP3421-8 ADCs from Microchip Semiconductor
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ fragment@0 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp342x: mcp@68 {
-+ reg = <0x68>;
-+
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&mcp342x>;
-+ __dormant__ {
-+ compatible = "microchip,mcp3421";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&mcp342x>;
-+ __dormant__ {
-+ compatible = "microchip,mcp3422";
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&mcp342x>;
-+ __dormant__ {
-+ compatible = "microchip,mcp3423";
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&mcp342x>;
-+ __dormant__ {
-+ compatible = "microchip,mcp3424";
-+ };
-+ };
-+
-+ fragment@5 {
-+ target = <&mcp342x>;
-+ __dormant__ {
-+ compatible = "microchip,mcp3425";
-+ };
-+ };
-+
-+ fragment@6 {
-+ target = <&mcp342x>;
-+ __dormant__ {
-+ compatible = "microchip,mcp3426";
-+ };
-+ };
-+
-+ fragment@7 {
-+ target = <&mcp342x>;
-+ __dormant__ {
-+ compatible = "microchip,mcp3427";
-+ };
-+ };
-+
-+ fragment@8 {
-+ target = <&mcp342x>;
-+ __dormant__ {
-+ compatible = "microchip,mcp3428";
-+ };
-+ };
-+
-+ __overrides__ {
-+ addr = <&mcp342x>,"reg:0";
-+ mcp3421 = <0>,"=1";
-+ mcp3422 = <0>,"=2";
-+ mcp3423 = <0>,"=3";
-+ mcp3424 = <0>,"=4";
-+ mcp3425 = <0>,"=5";
-+ mcp3426 = <0>,"=6";
-+ mcp3427 = <0>,"=7";
-+ mcp3428 = <0>,"=8";
-+ };
-+};
-+
+++ /dev/null
-From 70194b474d22974cd46356e5b3d3b0582abd02da Mon Sep 17 00:00:00 2001
-Date: Thu, 24 Jan 2019 13:56:30 +0000
-Subject: [PATCH] char: vcio: Add compat ioctl handling
-
-There was no compat ioctl handler, so 32 bit userspace on a
-64 bit kernel failed as IOCTL_MBOX_PROPERTY used the size
-of char*.
-
----
- drivers/char/broadcom/vcio.c | 22 +++++++++++++++++++++-
- 1 file changed, 21 insertions(+), 1 deletion(-)
-
---- a/drivers/char/broadcom/vcio.c
-+++ b/drivers/char/broadcom/vcio.c
-@@ -24,6 +24,9 @@
-
- #define VCIO_IOC_MAGIC 100
- #define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
-+#ifdef CONFIG_COMPAT
-+#define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
-+#endif
-
- static struct {
- dev_t devt;
-@@ -87,13 +90,30 @@ static long vcio_device_ioctl(struct fil
- case IOCTL_MBOX_PROPERTY:
- return vcio_user_property_list((void *)ioctl_param);
- default:
-- pr_err("unknown ioctl: %d\n", ioctl_num);
-+ pr_err("unknown ioctl: %x\n", ioctl_num);
- return -EINVAL;
- }
- }
-
-+#ifdef CONFIG_COMPAT
-+static long vcio_device_compat_ioctl(struct file *file, unsigned int ioctl_num,
-+ unsigned long ioctl_param)
-+{
-+ switch (ioctl_num) {
-+ case IOCTL_MBOX_PROPERTY32:
-+ return vcio_user_property_list(compat_ptr(ioctl_param));
-+ default:
-+ pr_err("unknown ioctl: %x\n", ioctl_num);
-+ return -EINVAL;
-+ }
-+}
-+#endif
-+
- const struct file_operations vcio_fops = {
- .unlocked_ioctl = vcio_device_ioctl,
-+#ifdef CONFIG_COMPAT
-+ .compat_ioctl = vcio_device_compat_ioctl,
-+#endif
- .open = vcio_device_open,
- .release = vcio_device_release,
- };
--- /dev/null
+From 18511b66fee5967ed5631e7cbe2c263f07e956f9 Mon Sep 17 00:00:00 2001
+Date: Tue, 22 Jan 2019 12:04:09 +0000
+Subject: [PATCH] staging: mmal-vchiq: Fix client_component for 64 bit
+ kernel
+
+The MMAL client_component field is used with the event
+mechanism to allow the client to identify the component for
+which the event is generated.
+The field is only 32bits in size, therefore we can't use a
+pointer to the component in a 64 bit kernel.
+
+Component handles are already held in an array per VCHI
+instance, so use the array index as the client_component handle
+to avoid having to create a new IDR for this purpose.
+
+---
+ .../staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 12 +++++++++---
+ .../staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 1 +
+ 2 files changed, 10 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -473,9 +473,9 @@ buffer_from_host(struct vchiq_mmal_insta
+ static void event_to_host_cb(struct vchiq_mmal_instance *instance,
+ struct mmal_msg *msg, u32 msg_len)
+ {
+- /* FIXME: Not going to work on 64 bit */
++ int comp_idx = msg->u.event_to_host.client_component;
+ struct vchiq_mmal_component *component =
+- (struct vchiq_mmal_component *)msg->u.event_to_host.client_component;
++ &instance->component[comp_idx];
+ struct vchiq_mmal_port *port = NULL;
+ struct mmal_msg_context *msg_context;
+ u32 port_num = msg->u.event_to_host.port_num;
+@@ -1074,7 +1074,7 @@ static int create_component(struct vchiq
+
+ /* build component create message */
+ m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE;
+- m.u.component_create.client_component = (u32)(unsigned long)component;
++ m.u.component_create.client_component = component->client_component;
+ strncpy(m.u.component_create.name, name,
+ sizeof(m.u.component_create.name));
+
+@@ -1869,6 +1869,12 @@ int vchiq_mmal_component_init(struct vch
+ goto unlock;
+ }
+
++ /* We need a handle to reference back to our component structure.
++ * Use the array index in instance->component rather than rolling
++ * another IDR.
++ */
++ component->client_component = idx;
++
+ ret = create_component(instance, component, name);
+ if (ret < 0) {
+ pr_err("%s: failed to create component %d (Not enough GPU mem?)\n",
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
+@@ -97,6 +97,7 @@ struct vchiq_mmal_component {
+ struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */
+ struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */
+ struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */
++ u32 client_component; /* Used to ref back to client struct */
+ };
+
+ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance);
+++ /dev/null
-From 6880e5c73b75be683299debf391eba4f521cc20f Mon Sep 17 00:00:00 2001
-Date: Thu, 24 Jan 2019 14:03:28 +0000
-Subject: [PATCH] char: vcio: Fail probe if rpi_firmware is not found.
-
-Device Tree is now the only supported config mechanism, therefore
-uncomment the block of code that fails the probe if the
-firmware node can't be found.
-
----
- drivers/char/broadcom/vcio.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/char/broadcom/vcio.c
-+++ b/drivers/char/broadcom/vcio.c
-@@ -126,10 +126,9 @@ static int __init vcio_init(void)
-
- np = of_find_compatible_node(NULL, NULL,
- "raspberrypi,bcm2835-firmware");
--/* Uncomment this when we only boot with Device Tree
- if (!of_device_is_available(np))
- return -ENODEV;
--*/
-+
- vcio.fw = rpi_firmware_get(np);
- if (!vcio.fw)
- return -ENODEV;
--- /dev/null
+From 6b3fde1207785584dbd1fdf65110cf60bd29b409 Mon Sep 17 00:00:00 2001
+Date: Tue, 15 Jan 2019 15:35:24 +0000
+Subject: [PATCH] staging: bcm2835-camera: Add sanity checks for
+ queue_setup/CREATE_BUFS
+
+Fixes a v4l2-compliance failure when passed a buffer that is
+too small.
+queue_setup wasn't handling the case where !(*nplanes), as
+used from CREATE_BUFS and requiring the driver to sanity
+check the provided buffer parameters. It was assuming that
+it was always being used in the REQBUFS case where it provides
+the buffer properties.
+
+---
+ .../bcm2835-camera/bcm2835-camera.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -242,6 +242,22 @@ static int queue_setup(struct vb2_queue
+ return -EINVAL;
+ }
+
++ /* Handle CREATE_BUFS situation - *nplanes != 0 */
++ if (*nplanes) {
++ if (*nplanes != 1 ||
++ sizes[0] < dev->capture.port->current_buffer.size) {
++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
++ "%s: dev:%p Invalid buffer request from CREATE_BUFS, size %u < %u, nplanes %u != 1\n",
++ __func__, dev, sizes[0],
++ dev->capture.port->current_buffer.size,
++ *nplanes);
++ return -EINVAL;
++ } else {
++ return 0;
++ }
++ }
++
++ /* Handle REQBUFS situation */
+ size = dev->capture.port->current_buffer.size;
+ if (size == 0) {
+ v4l2_err(&dev->v4l2_dev,
--- /dev/null
+From 7f67e8ed8ae17ddca0748975de0c0efad6a5e6bb Mon Sep 17 00:00:00 2001
+Date: Tue, 15 Jan 2019 16:32:33 +0000
+Subject: [PATCH] staging: bcm2835-camera: Set the field value within
+ each buffer
+
+Fixes a v4l2-compliance failure
+v4l2-test-buffers.cpp(415): g_field() == V4L2_FIELD_ANY
+
+The driver only ever produces progresive frames, so field should
+always be set to V4L2_FIELD_NONE.
+
+---
+ drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+@@ -443,6 +443,7 @@ static void buffer_cb(struct vchiq_mmal_
+ }
+ dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
+ buf->vb.sequence = dev->capture.sequence++;
++ buf->vb.field = V4L2_FIELD_NONE;
+
+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, mmal_buf->length);
+ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+++ /dev/null
-From 18511b66fee5967ed5631e7cbe2c263f07e956f9 Mon Sep 17 00:00:00 2001
-Date: Tue, 22 Jan 2019 12:04:09 +0000
-Subject: [PATCH] staging: mmal-vchiq: Fix client_component for 64 bit
- kernel
-
-The MMAL client_component field is used with the event
-mechanism to allow the client to identify the component for
-which the event is generated.
-The field is only 32bits in size, therefore we can't use a
-pointer to the component in a 64 bit kernel.
-
-Component handles are already held in an array per VCHI
-instance, so use the array index as the client_component handle
-to avoid having to create a new IDR for this purpose.
-
----
- .../staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 12 +++++++++---
- .../staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 1 +
- 2 files changed, 10 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -473,9 +473,9 @@ buffer_from_host(struct vchiq_mmal_insta
- static void event_to_host_cb(struct vchiq_mmal_instance *instance,
- struct mmal_msg *msg, u32 msg_len)
- {
-- /* FIXME: Not going to work on 64 bit */
-+ int comp_idx = msg->u.event_to_host.client_component;
- struct vchiq_mmal_component *component =
-- (struct vchiq_mmal_component *)msg->u.event_to_host.client_component;
-+ &instance->component[comp_idx];
- struct vchiq_mmal_port *port = NULL;
- struct mmal_msg_context *msg_context;
- u32 port_num = msg->u.event_to_host.port_num;
-@@ -1074,7 +1074,7 @@ static int create_component(struct vchiq
-
- /* build component create message */
- m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE;
-- m.u.component_create.client_component = (u32)(unsigned long)component;
-+ m.u.component_create.client_component = component->client_component;
- strncpy(m.u.component_create.name, name,
- sizeof(m.u.component_create.name));
-
-@@ -1869,6 +1869,12 @@ int vchiq_mmal_component_init(struct vch
- goto unlock;
- }
-
-+ /* We need a handle to reference back to our component structure.
-+ * Use the array index in instance->component rather than rolling
-+ * another IDR.
-+ */
-+ component->client_component = idx;
-+
- ret = create_component(instance, component, name);
- if (ret < 0) {
- pr_err("%s: failed to create component %d (Not enough GPU mem?)\n",
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-@@ -97,6 +97,7 @@ struct vchiq_mmal_component {
- struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */
- struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */
- struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */
-+ u32 client_component; /* Used to ref back to client struct */
- };
-
- int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance);
--- /dev/null
+From 966ff2b4c758eb8c8c04f26422cd183e6aa8eda5 Mon Sep 17 00:00:00 2001
+Date: Wed, 23 Jan 2019 18:25:50 +0000
+Subject: [PATCH] char: vc_mem: Fix up compat ioctls for 64bit kernel
+
+compat_ioctl wasn't defined, so 32bit user/64bit kernel
+always failed.
+VC_MEM_IOC_MEM_PHYS_ADDR was defined with parameter size
+unsigned long, so the ioctl cmd changes between sizes.
+
+---
+ drivers/char/broadcom/vc_mem.c | 40 +++++++++++++++++++++++++++++----
+ include/linux/broadcom/vc_mem.h | 4 ++++
+ 2 files changed, 40 insertions(+), 4 deletions(-)
+
+--- a/drivers/char/broadcom/vc_mem.c
++++ b/drivers/char/broadcom/vc_mem.c
+@@ -148,7 +148,7 @@ vc_mem_ioctl(struct file *file, unsigned
+ (void) cmd;
+ (void) arg;
+
+- pr_debug("%s: called file = 0x%p\n", __func__, file);
++ pr_debug("%s: called file = 0x%p, cmd %08x\n", __func__, file, cmd);
+
+ switch (cmd) {
+ case VC_MEM_IOC_MEM_PHYS_ADDR:
+@@ -167,7 +167,7 @@ vc_mem_ioctl(struct file *file, unsigned
+ // Get the videocore memory size first
+ vc_mem_get_size();
+
+- pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%u\n", __func__,
++ pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%x\n", __func__,
+ mm_vc_mem_size);
+
+ if (copy_to_user((void *) arg, &mm_vc_mem_size,
+@@ -181,7 +181,7 @@ vc_mem_ioctl(struct file *file, unsigned
+ // Get the videocore memory base
+ vc_mem_get_base();
+
+- pr_debug("%s: VC_MEM_IOC_MEM_BASE=%u\n", __func__,
++ pr_debug("%s: VC_MEM_IOC_MEM_BASE=%x\n", __func__,
+ mm_vc_mem_base);
+
+ if (copy_to_user((void *) arg, &mm_vc_mem_base,
+@@ -195,7 +195,7 @@ vc_mem_ioctl(struct file *file, unsigned
+ // Get the videocore memory base
+ vc_mem_get_base();
+
+- pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%u\n", __func__,
++ pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%x\n", __func__,
+ mm_vc_mem_base);
+
+ if (copy_to_user((void *) arg, &mm_vc_mem_base,
+@@ -214,6 +214,35 @@ vc_mem_ioctl(struct file *file, unsigned
+ return rc;
+ }
+
++#ifdef CONFIG_COMPAT
++static long
++vc_mem_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ int rc = 0;
++
++ switch (cmd) {
++ case VC_MEM_IOC_MEM_PHYS_ADDR32:
++ pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR32=0x%p\n",
++ __func__, (void *)mm_vc_mem_phys_addr);
++
++ /* This isn't correct, but will cover us for now as
++ * VideoCore is 32bit only.
++ */
++ if (copy_to_user((void *)arg, &mm_vc_mem_phys_addr,
++ sizeof(compat_ulong_t)))
++ rc = -EFAULT;
++
++ break;
++
++ default:
++ rc = vc_mem_ioctl(file, cmd, arg);
++ break;
++ }
++
++ return rc;
++}
++#endif
++
+ /****************************************************************************
+ *
+ * vc_mem_mmap
+@@ -259,6 +288,9 @@ static const struct file_operations vc_m
+ .open = vc_mem_open,
+ .release = vc_mem_release,
+ .unlocked_ioctl = vc_mem_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = vc_mem_compat_ioctl,
++#endif
+ .mmap = vc_mem_mmap,
+ };
+
+--- a/include/linux/broadcom/vc_mem.h
++++ b/include/linux/broadcom/vc_mem.h
+@@ -32,4 +32,8 @@ extern unsigned int mm_vc_mem_size;
+ extern int vc_mem_get_current_size( void );
+ #endif
+
++#ifdef CONFIG_COMPAT
++#define VC_MEM_IOC_MEM_PHYS_ADDR32 _IOR(VC_MEM_IOC_MAGIC, 0, compat_ulong_t)
++#endif
++
+ #endif /* _VC_MEM_H */
+++ /dev/null
-From 6b3fde1207785584dbd1fdf65110cf60bd29b409 Mon Sep 17 00:00:00 2001
-Date: Tue, 15 Jan 2019 15:35:24 +0000
-Subject: [PATCH] staging: bcm2835-camera: Add sanity checks for
- queue_setup/CREATE_BUFS
-
-Fixes a v4l2-compliance failure when passed a buffer that is
-too small.
-queue_setup wasn't handling the case where !(*nplanes), as
-used from CREATE_BUFS and requiring the driver to sanity
-check the provided buffer parameters. It was assuming that
-it was always being used in the REQBUFS case where it provides
-the buffer properties.
-
----
- .../bcm2835-camera/bcm2835-camera.c | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -242,6 +242,22 @@ static int queue_setup(struct vb2_queue
- return -EINVAL;
- }
-
-+ /* Handle CREATE_BUFS situation - *nplanes != 0 */
-+ if (*nplanes) {
-+ if (*nplanes != 1 ||
-+ sizes[0] < dev->capture.port->current_buffer.size) {
-+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
-+ "%s: dev:%p Invalid buffer request from CREATE_BUFS, size %u < %u, nplanes %u != 1\n",
-+ __func__, dev, sizes[0],
-+ dev->capture.port->current_buffer.size,
-+ *nplanes);
-+ return -EINVAL;
-+ } else {
-+ return 0;
-+ }
-+ }
-+
-+ /* Handle REQBUFS situation */
- size = dev->capture.port->current_buffer.size;
- if (size == 0) {
- v4l2_err(&dev->v4l2_dev,
--- /dev/null
+From 8d64f178c3568d212f3ddf05ea1ad7f103beeb86 Mon Sep 17 00:00:00 2001
+Date: Wed, 23 Jan 2019 18:37:29 +0000
+Subject: [PATCH] char: vc_mem: Fix all coding style issues.
+
+Cleans up all checkpatch errors in vc_mem.c and vc_mem.h
+No functional change to the code.
+
+---
+ drivers/char/broadcom/vc_mem.c | 177 +++++++++++---------------------
+ include/linux/broadcom/vc_mem.h | 38 +++----
+ 2 files changed, 77 insertions(+), 138 deletions(-)
+
+--- a/drivers/char/broadcom/vc_mem.c
++++ b/drivers/char/broadcom/vc_mem.c
+@@ -1,16 +1,16 @@
+-/*****************************************************************************
+-* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
+-*
+-* Unless you and Broadcom execute a separate written software license
+-* agreement governing use of this software, this software is licensed to you
+-* under the terms of the GNU General Public License version 2, available at
+-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+-*
+-* Notwithstanding the above, under no circumstances may you combine this
+-* software in any way with any other Broadcom software provided under a
+-* license other than the GPL, without Broadcom's express prior written
+-* consent.
+-*****************************************************************************/
++/*
++ * Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
++ *
++ * Unless you and Broadcom execute a separate written software license
++ * agreement governing use of this software, this software is licensed to you
++ * under the terms of the GNU General Public License version 2, available at
++ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++ *
++ * Notwithstanding the above, under no circumstances may you combine this
++ * software in any way with any other Broadcom software provided under a
++ * license other than the GPL, without Broadcom's express prior written
++ * consent.
++ */
+
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+@@ -26,11 +26,11 @@
+
+ #define DRIVER_NAME "vc-mem"
+
+-// Device (/dev) related variables
+-static dev_t vc_mem_devnum = 0;
+-static struct class *vc_mem_class = NULL;
++/* Device (/dev) related variables */
++static dev_t vc_mem_devnum;
++static struct class *vc_mem_class;
+ static struct cdev vc_mem_cdev;
+-static int vc_mem_inited = 0;
++static int vc_mem_inited;
+
+ #ifdef CONFIG_DEBUG_FS
+ static struct dentry *vc_mem_debugfs_entry;
+@@ -50,96 +50,55 @@ static struct dentry *vc_mem_debugfs_ent
+ * bootloader (and/or kernel). When that happens, the values of these variables
+ * would be calculated and assigned in the init function.
+ */
+-// in the 2835 VC in mapped above ARM, but ARM has full access to VC space
+-unsigned long mm_vc_mem_phys_addr = 0x00000000;
+-unsigned int mm_vc_mem_size = 0;
+-unsigned int mm_vc_mem_base = 0;
+-
++/* In the 2835 VC in mapped above ARM, but ARM has full access to VC space */
++unsigned long mm_vc_mem_phys_addr;
+ EXPORT_SYMBOL(mm_vc_mem_phys_addr);
++unsigned int mm_vc_mem_size;
+ EXPORT_SYMBOL(mm_vc_mem_size);
++unsigned int mm_vc_mem_base;
+ EXPORT_SYMBOL(mm_vc_mem_base);
+
+-static uint phys_addr = 0;
+-static uint mem_size = 0;
+-static uint mem_base = 0;
+-
+-
+-/****************************************************************************
+-*
+-* vc_mem_open
+-*
+-***************************************************************************/
++static uint phys_addr;
++static uint mem_size;
++static uint mem_base;
+
+ static int
+ vc_mem_open(struct inode *inode, struct file *file)
+ {
+- (void) inode;
+- (void) file;
++ (void)inode;
+
+ pr_debug("%s: called file = 0x%p\n", __func__, file);
+
+ return 0;
+ }
+
+-/****************************************************************************
+-*
+-* vc_mem_release
+-*
+-***************************************************************************/
+-
+ static int
+ vc_mem_release(struct inode *inode, struct file *file)
+ {
+- (void) inode;
+- (void) file;
++ (void)inode;
+
+ pr_debug("%s: called file = 0x%p\n", __func__, file);
+
+ return 0;
+ }
+
+-/****************************************************************************
+-*
+-* vc_mem_get_size
+-*
+-***************************************************************************/
+-
+ static void
+ vc_mem_get_size(void)
+ {
+ }
+
+-/****************************************************************************
+-*
+-* vc_mem_get_base
+-*
+-***************************************************************************/
+-
+ static void
+ vc_mem_get_base(void)
+ {
+ }
+
+-/****************************************************************************
+-*
+-* vc_mem_get_current_size
+-*
+-***************************************************************************/
+-
+ int
+ vc_mem_get_current_size(void)
+ {
+ return mm_vc_mem_size;
+ }
+-
+ EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
+
+-/****************************************************************************
+-*
+-* vc_mem_ioctl
+-*
+-***************************************************************************/
+-
+ static long
+ vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+@@ -154,52 +113,52 @@ vc_mem_ioctl(struct file *file, unsigned
+ case VC_MEM_IOC_MEM_PHYS_ADDR:
+ {
+ pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p\n",
+- __func__, (void *) mm_vc_mem_phys_addr);
++ __func__, (void *)mm_vc_mem_phys_addr);
+
+- if (copy_to_user((void *) arg, &mm_vc_mem_phys_addr,
+- sizeof (mm_vc_mem_phys_addr)) != 0) {
++ if (copy_to_user((void *)arg, &mm_vc_mem_phys_addr,
++ sizeof(mm_vc_mem_phys_addr))) {
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case VC_MEM_IOC_MEM_SIZE:
+ {
+- // Get the videocore memory size first
++ /* Get the videocore memory size first */
+ vc_mem_get_size();
+
+ pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%x\n", __func__,
+- mm_vc_mem_size);
++ mm_vc_mem_size);
+
+- if (copy_to_user((void *) arg, &mm_vc_mem_size,
+- sizeof (mm_vc_mem_size)) != 0) {
++ if (copy_to_user((void *)arg, &mm_vc_mem_size,
++ sizeof(mm_vc_mem_size))) {
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case VC_MEM_IOC_MEM_BASE:
+ {
+- // Get the videocore memory base
++ /* Get the videocore memory base */
+ vc_mem_get_base();
+
+ pr_debug("%s: VC_MEM_IOC_MEM_BASE=%x\n", __func__,
+- mm_vc_mem_base);
++ mm_vc_mem_base);
+
+- if (copy_to_user((void *) arg, &mm_vc_mem_base,
+- sizeof (mm_vc_mem_base)) != 0) {
++ if (copy_to_user((void *)arg, &mm_vc_mem_base,
++ sizeof(mm_vc_mem_base))) {
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case VC_MEM_IOC_MEM_LOAD:
+ {
+- // Get the videocore memory base
++ /* Get the videocore memory base */
+ vc_mem_get_base();
+
+ pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%x\n", __func__,
+ mm_vc_mem_base);
+
+- if (copy_to_user((void *) arg, &mm_vc_mem_base,
+- sizeof (mm_vc_mem_base)) != 0) {
++ if (copy_to_user((void *)arg, &mm_vc_mem_base,
++ sizeof(mm_vc_mem_base))) {
+ rc = -EFAULT;
+ }
+ break;
+@@ -243,12 +202,6 @@ vc_mem_compat_ioctl(struct file *file, u
+ }
+ #endif
+
+-/****************************************************************************
+-*
+-* vc_mem_mmap
+-*
+-***************************************************************************/
+-
+ static int
+ vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
+ {
+@@ -257,32 +210,26 @@ vc_mem_mmap(struct file *filp, struct vm
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ pr_debug("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx\n",
+- __func__, (long) vma->vm_start, (long) vma->vm_end,
+- (long) vma->vm_pgoff);
++ __func__, (long)vma->vm_start, (long)vma->vm_end,
++ (long)vma->vm_pgoff);
+
+ if (offset + length > mm_vc_mem_size) {
+ pr_err("%s: length %ld is too big\n", __func__, length);
+ return -EINVAL;
+ }
+- // Do not cache the memory map
++ /* Do not cache the memory map */
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ rc = remap_pfn_range(vma, vma->vm_start,
+ (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
+ vma->vm_pgoff, length, vma->vm_page_prot);
+- if (rc != 0) {
++ if (rc)
+ pr_err("%s: remap_pfn_range failed (rc=%d)\n", __func__, rc);
+- }
+
+ return rc;
+ }
+
+-/****************************************************************************
+-*
+-* File Operations for the driver.
+-*
+-***************************************************************************/
+-
++/* File Operations for the driver. */
+ static const struct file_operations vc_mem_fops = {
+ .owner = THIS_MODULE,
+ .open = vc_mem_open,
+@@ -316,7 +263,7 @@ static int vc_mem_debugfs_init(
+ vc_mem_debugfs_entry,
+ (u32 *)&mm_vc_mem_phys_addr)) {
+ dev_warn(dev, "%s:could not create vc_mem_phys entry\n",
+- __func__);
++ __func__);
+ goto fail;
+ }
+
+@@ -325,7 +272,7 @@ static int vc_mem_debugfs_init(
+ vc_mem_debugfs_entry,
+ (u32 *)&mm_vc_mem_size)) {
+ dev_warn(dev, "%s:could not create vc_mem_size entry\n",
+- __func__);
++ __func__);
+ goto fail;
+ }
+
+@@ -347,12 +294,7 @@ fail:
+
+ #endif /* CONFIG_DEBUG_FS */
+
+-
+-/****************************************************************************
+-*
+-* vc_mem_init
+-*
+-***************************************************************************/
++/* Module load/unload functions */
+
+ static int __init
+ vc_mem_init(void)
+@@ -369,16 +311,19 @@ vc_mem_init(void)
+ vc_mem_get_size();
+
+ pr_info("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
+- mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size, mm_vc_mem_size / (1024 * 1024));
++ mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size,
++ mm_vc_mem_size / (1024 * 1024));
+
+- if ((rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME)) < 0) {
++ rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME);
++ if (rc < 0) {
+ pr_err("%s: alloc_chrdev_region failed (rc=%d)\n",
+ __func__, rc);
+ goto out_err;
+ }
+
+ cdev_init(&vc_mem_cdev, &vc_mem_fops);
+- if ((rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1)) != 0) {
++ rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1);
++ if (rc) {
+ pr_err("%s: cdev_add failed (rc=%d)\n", __func__, rc);
+ goto out_unregister;
+ }
+@@ -408,26 +353,20 @@ vc_mem_init(void)
+
+ device_destroy(vc_mem_class, vc_mem_devnum);
+
+- out_class_destroy:
++out_class_destroy:
+ class_destroy(vc_mem_class);
+ vc_mem_class = NULL;
+
+- out_cdev_del:
++out_cdev_del:
+ cdev_del(&vc_mem_cdev);
+
+- out_unregister:
++out_unregister:
+ unregister_chrdev_region(vc_mem_devnum, 1);
+
+- out_err:
++out_err:
+ return -1;
+ }
+
+-/****************************************************************************
+-*
+-* vc_mem_exit
+-*
+-***************************************************************************/
+-
+ static void __exit
+ vc_mem_exit(void)
+ {
+--- a/include/linux/broadcom/vc_mem.h
++++ b/include/linux/broadcom/vc_mem.h
+@@ -1,16 +1,16 @@
+-/*****************************************************************************
+-* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
+-*
+-* Unless you and Broadcom execute a separate written software license
+-* agreement governing use of this software, this software is licensed to you
+-* under the terms of the GNU General Public License version 2, available at
+-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+-*
+-* Notwithstanding the above, under no circumstances may you combine this
+-* software in any way with any other Broadcom software provided under a
+-* license other than the GPL, without Broadcom's express prior written
+-* consent.
+-*****************************************************************************/
++/*
++ * Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
++ *
++ * Unless you and Broadcom execute a separate written software license
++ * agreement governing use of this software, this software is licensed to you
++ * under the terms of the GNU General Public License version 2, available at
++ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++ *
++ * Notwithstanding the above, under no circumstances may you combine this
++ * software in any way with any other Broadcom software provided under a
++ * license other than the GPL, without Broadcom's express prior written
++ * consent.
++ */
+
+ #ifndef _VC_MEM_H
+ #define _VC_MEM_H
+@@ -19,17 +19,17 @@
+
+ #define VC_MEM_IOC_MAGIC 'v'
+
+-#define VC_MEM_IOC_MEM_PHYS_ADDR _IOR( VC_MEM_IOC_MAGIC, 0, unsigned long )
+-#define VC_MEM_IOC_MEM_SIZE _IOR( VC_MEM_IOC_MAGIC, 1, unsigned int )
+-#define VC_MEM_IOC_MEM_BASE _IOR( VC_MEM_IOC_MAGIC, 2, unsigned int )
+-#define VC_MEM_IOC_MEM_LOAD _IOR( VC_MEM_IOC_MAGIC, 3, unsigned int )
++#define VC_MEM_IOC_MEM_PHYS_ADDR _IOR(VC_MEM_IOC_MAGIC, 0, unsigned long)
++#define VC_MEM_IOC_MEM_SIZE _IOR(VC_MEM_IOC_MAGIC, 1, unsigned int)
++#define VC_MEM_IOC_MEM_BASE _IOR(VC_MEM_IOC_MAGIC, 2, unsigned int)
++#define VC_MEM_IOC_MEM_LOAD _IOR(VC_MEM_IOC_MAGIC, 3, unsigned int)
+
+-#if defined( __KERNEL__ )
++#ifdef __KERNEL__
+ #define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
+
+ extern unsigned long mm_vc_mem_phys_addr;
+ extern unsigned int mm_vc_mem_size;
+-extern int vc_mem_get_current_size( void );
++extern int vc_mem_get_current_size(void);
+ #endif
+
+ #ifdef CONFIG_COMPAT
+++ /dev/null
-From 7f67e8ed8ae17ddca0748975de0c0efad6a5e6bb Mon Sep 17 00:00:00 2001
-Date: Tue, 15 Jan 2019 16:32:33 +0000
-Subject: [PATCH] staging: bcm2835-camera: Set the field value within
- each buffer
-
-Fixes a v4l2-compliance failure
-v4l2-test-buffers.cpp(415): g_field() == V4L2_FIELD_ANY
-
-The driver only ever produces progresive frames, so field should
-always be set to V4L2_FIELD_NONE.
-
----
- drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
-@@ -443,6 +443,7 @@ static void buffer_cb(struct vchiq_mmal_
- }
- dev->capture.last_timestamp = buf->vb.vb2_buf.timestamp;
- buf->vb.sequence = dev->capture.sequence++;
-+ buf->vb.field = V4L2_FIELD_NONE;
-
- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, mmal_buf->length);
- if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+++ /dev/null
-From 966ff2b4c758eb8c8c04f26422cd183e6aa8eda5 Mon Sep 17 00:00:00 2001
-Date: Wed, 23 Jan 2019 18:25:50 +0000
-Subject: [PATCH] char: vc_mem: Fix up compat ioctls for 64bit kernel
-
-compat_ioctl wasn't defined, so 32bit user/64bit kernel
-always failed.
-VC_MEM_IOC_MEM_PHYS_ADDR was defined with parameter size
-unsigned long, so the ioctl cmd changes between sizes.
-
----
- drivers/char/broadcom/vc_mem.c | 40 +++++++++++++++++++++++++++++----
- include/linux/broadcom/vc_mem.h | 4 ++++
- 2 files changed, 40 insertions(+), 4 deletions(-)
-
---- a/drivers/char/broadcom/vc_mem.c
-+++ b/drivers/char/broadcom/vc_mem.c
-@@ -148,7 +148,7 @@ vc_mem_ioctl(struct file *file, unsigned
- (void) cmd;
- (void) arg;
-
-- pr_debug("%s: called file = 0x%p\n", __func__, file);
-+ pr_debug("%s: called file = 0x%p, cmd %08x\n", __func__, file, cmd);
-
- switch (cmd) {
- case VC_MEM_IOC_MEM_PHYS_ADDR:
-@@ -167,7 +167,7 @@ vc_mem_ioctl(struct file *file, unsigned
- // Get the videocore memory size first
- vc_mem_get_size();
-
-- pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%u\n", __func__,
-+ pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%x\n", __func__,
- mm_vc_mem_size);
-
- if (copy_to_user((void *) arg, &mm_vc_mem_size,
-@@ -181,7 +181,7 @@ vc_mem_ioctl(struct file *file, unsigned
- // Get the videocore memory base
- vc_mem_get_base();
-
-- pr_debug("%s: VC_MEM_IOC_MEM_BASE=%u\n", __func__,
-+ pr_debug("%s: VC_MEM_IOC_MEM_BASE=%x\n", __func__,
- mm_vc_mem_base);
-
- if (copy_to_user((void *) arg, &mm_vc_mem_base,
-@@ -195,7 +195,7 @@ vc_mem_ioctl(struct file *file, unsigned
- // Get the videocore memory base
- vc_mem_get_base();
-
-- pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%u\n", __func__,
-+ pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%x\n", __func__,
- mm_vc_mem_base);
-
- if (copy_to_user((void *) arg, &mm_vc_mem_base,
-@@ -214,6 +214,35 @@ vc_mem_ioctl(struct file *file, unsigned
- return rc;
- }
-
-+#ifdef CONFIG_COMPAT
-+static long
-+vc_mem_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ int rc = 0;
-+
-+ switch (cmd) {
-+ case VC_MEM_IOC_MEM_PHYS_ADDR32:
-+ pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR32=0x%p\n",
-+ __func__, (void *)mm_vc_mem_phys_addr);
-+
-+ /* This isn't correct, but will cover us for now as
-+ * VideoCore is 32bit only.
-+ */
-+ if (copy_to_user((void *)arg, &mm_vc_mem_phys_addr,
-+ sizeof(compat_ulong_t)))
-+ rc = -EFAULT;
-+
-+ break;
-+
-+ default:
-+ rc = vc_mem_ioctl(file, cmd, arg);
-+ break;
-+ }
-+
-+ return rc;
-+}
-+#endif
-+
- /****************************************************************************
- *
- * vc_mem_mmap
-@@ -259,6 +288,9 @@ static const struct file_operations vc_m
- .open = vc_mem_open,
- .release = vc_mem_release,
- .unlocked_ioctl = vc_mem_ioctl,
-+#ifdef CONFIG_COMPAT
-+ .compat_ioctl = vc_mem_compat_ioctl,
-+#endif
- .mmap = vc_mem_mmap,
- };
-
---- a/include/linux/broadcom/vc_mem.h
-+++ b/include/linux/broadcom/vc_mem.h
-@@ -32,4 +32,8 @@ extern unsigned int mm_vc_mem_size;
- extern int vc_mem_get_current_size( void );
- #endif
-
-+#ifdef CONFIG_COMPAT
-+#define VC_MEM_IOC_MEM_PHYS_ADDR32 _IOR(VC_MEM_IOC_MAGIC, 0, compat_ulong_t)
-+#endif
-+
- #endif /* _VC_MEM_H */
--- /dev/null
+From 83a7175c91133a3e7a746693847b447bf6297094 Mon Sep 17 00:00:00 2001
+Date: Thu, 24 Jan 2019 15:09:28 +0000
+Subject: [PATCH] clk: clk-bcm2835: Use %zd when printing size_t
+
+The debug text for how many clocks have been registered
+uses "%d" with a size_t. Correct it to "%zd".
+
+---
+ drivers/clk/bcm/clk-bcm2835.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -2271,7 +2271,7 @@ static int bcm2835_clk_probe(struct plat
+ return ret;
+
+ /* note that we have registered all the clocks */
+- dev_dbg(dev, "registered %d clocks\n", asize);
++ dev_dbg(dev, "registered %zd clocks\n", asize);
+
+ return 0;
+ }
+++ /dev/null
-From 8d64f178c3568d212f3ddf05ea1ad7f103beeb86 Mon Sep 17 00:00:00 2001
-Date: Wed, 23 Jan 2019 18:37:29 +0000
-Subject: [PATCH] char: vc_mem: Fix all coding style issues.
-
-Cleans up all checkpatch errors in vc_mem.c and vc_mem.h
-No functional change to the code.
-
----
- drivers/char/broadcom/vc_mem.c | 177 +++++++++++---------------------
- include/linux/broadcom/vc_mem.h | 38 +++----
- 2 files changed, 77 insertions(+), 138 deletions(-)
-
---- a/drivers/char/broadcom/vc_mem.c
-+++ b/drivers/char/broadcom/vc_mem.c
-@@ -1,16 +1,16 @@
--/*****************************************************************************
--* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
--*
--* Unless you and Broadcom execute a separate written software license
--* agreement governing use of this software, this software is licensed to you
--* under the terms of the GNU General Public License version 2, available at
--* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
--*
--* Notwithstanding the above, under no circumstances may you combine this
--* software in any way with any other Broadcom software provided under a
--* license other than the GPL, without Broadcom's express prior written
--* consent.
--*****************************************************************************/
-+/*
-+ * Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
-+ *
-+ * Unless you and Broadcom execute a separate written software license
-+ * agreement governing use of this software, this software is licensed to you
-+ * under the terms of the GNU General Public License version 2, available at
-+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+ *
-+ * Notwithstanding the above, under no circumstances may you combine this
-+ * software in any way with any other Broadcom software provided under a
-+ * license other than the GPL, without Broadcom's express prior written
-+ * consent.
-+ */
-
- #include <linux/kernel.h>
- #include <linux/module.h>
-@@ -26,11 +26,11 @@
-
- #define DRIVER_NAME "vc-mem"
-
--// Device (/dev) related variables
--static dev_t vc_mem_devnum = 0;
--static struct class *vc_mem_class = NULL;
-+/* Device (/dev) related variables */
-+static dev_t vc_mem_devnum;
-+static struct class *vc_mem_class;
- static struct cdev vc_mem_cdev;
--static int vc_mem_inited = 0;
-+static int vc_mem_inited;
-
- #ifdef CONFIG_DEBUG_FS
- static struct dentry *vc_mem_debugfs_entry;
-@@ -50,96 +50,55 @@ static struct dentry *vc_mem_debugfs_ent
- * bootloader (and/or kernel). When that happens, the values of these variables
- * would be calculated and assigned in the init function.
- */
--// in the 2835 VC in mapped above ARM, but ARM has full access to VC space
--unsigned long mm_vc_mem_phys_addr = 0x00000000;
--unsigned int mm_vc_mem_size = 0;
--unsigned int mm_vc_mem_base = 0;
--
-+/* In the 2835 VC in mapped above ARM, but ARM has full access to VC space */
-+unsigned long mm_vc_mem_phys_addr;
- EXPORT_SYMBOL(mm_vc_mem_phys_addr);
-+unsigned int mm_vc_mem_size;
- EXPORT_SYMBOL(mm_vc_mem_size);
-+unsigned int mm_vc_mem_base;
- EXPORT_SYMBOL(mm_vc_mem_base);
-
--static uint phys_addr = 0;
--static uint mem_size = 0;
--static uint mem_base = 0;
--
--
--/****************************************************************************
--*
--* vc_mem_open
--*
--***************************************************************************/
-+static uint phys_addr;
-+static uint mem_size;
-+static uint mem_base;
-
- static int
- vc_mem_open(struct inode *inode, struct file *file)
- {
-- (void) inode;
-- (void) file;
-+ (void)inode;
-
- pr_debug("%s: called file = 0x%p\n", __func__, file);
-
- return 0;
- }
-
--/****************************************************************************
--*
--* vc_mem_release
--*
--***************************************************************************/
--
- static int
- vc_mem_release(struct inode *inode, struct file *file)
- {
-- (void) inode;
-- (void) file;
-+ (void)inode;
-
- pr_debug("%s: called file = 0x%p\n", __func__, file);
-
- return 0;
- }
-
--/****************************************************************************
--*
--* vc_mem_get_size
--*
--***************************************************************************/
--
- static void
- vc_mem_get_size(void)
- {
- }
-
--/****************************************************************************
--*
--* vc_mem_get_base
--*
--***************************************************************************/
--
- static void
- vc_mem_get_base(void)
- {
- }
-
--/****************************************************************************
--*
--* vc_mem_get_current_size
--*
--***************************************************************************/
--
- int
- vc_mem_get_current_size(void)
- {
- return mm_vc_mem_size;
- }
--
- EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
-
--/****************************************************************************
--*
--* vc_mem_ioctl
--*
--***************************************************************************/
--
- static long
- vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- {
-@@ -154,52 +113,52 @@ vc_mem_ioctl(struct file *file, unsigned
- case VC_MEM_IOC_MEM_PHYS_ADDR:
- {
- pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p\n",
-- __func__, (void *) mm_vc_mem_phys_addr);
-+ __func__, (void *)mm_vc_mem_phys_addr);
-
-- if (copy_to_user((void *) arg, &mm_vc_mem_phys_addr,
-- sizeof (mm_vc_mem_phys_addr)) != 0) {
-+ if (copy_to_user((void *)arg, &mm_vc_mem_phys_addr,
-+ sizeof(mm_vc_mem_phys_addr))) {
- rc = -EFAULT;
- }
- break;
- }
- case VC_MEM_IOC_MEM_SIZE:
- {
-- // Get the videocore memory size first
-+ /* Get the videocore memory size first */
- vc_mem_get_size();
-
- pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%x\n", __func__,
-- mm_vc_mem_size);
-+ mm_vc_mem_size);
-
-- if (copy_to_user((void *) arg, &mm_vc_mem_size,
-- sizeof (mm_vc_mem_size)) != 0) {
-+ if (copy_to_user((void *)arg, &mm_vc_mem_size,
-+ sizeof(mm_vc_mem_size))) {
- rc = -EFAULT;
- }
- break;
- }
- case VC_MEM_IOC_MEM_BASE:
- {
-- // Get the videocore memory base
-+ /* Get the videocore memory base */
- vc_mem_get_base();
-
- pr_debug("%s: VC_MEM_IOC_MEM_BASE=%x\n", __func__,
-- mm_vc_mem_base);
-+ mm_vc_mem_base);
-
-- if (copy_to_user((void *) arg, &mm_vc_mem_base,
-- sizeof (mm_vc_mem_base)) != 0) {
-+ if (copy_to_user((void *)arg, &mm_vc_mem_base,
-+ sizeof(mm_vc_mem_base))) {
- rc = -EFAULT;
- }
- break;
- }
- case VC_MEM_IOC_MEM_LOAD:
- {
-- // Get the videocore memory base
-+ /* Get the videocore memory base */
- vc_mem_get_base();
-
- pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%x\n", __func__,
- mm_vc_mem_base);
-
-- if (copy_to_user((void *) arg, &mm_vc_mem_base,
-- sizeof (mm_vc_mem_base)) != 0) {
-+ if (copy_to_user((void *)arg, &mm_vc_mem_base,
-+ sizeof(mm_vc_mem_base))) {
- rc = -EFAULT;
- }
- break;
-@@ -243,12 +202,6 @@ vc_mem_compat_ioctl(struct file *file, u
- }
- #endif
-
--/****************************************************************************
--*
--* vc_mem_mmap
--*
--***************************************************************************/
--
- static int
- vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
- {
-@@ -257,32 +210,26 @@ vc_mem_mmap(struct file *filp, struct vm
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-
- pr_debug("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx\n",
-- __func__, (long) vma->vm_start, (long) vma->vm_end,
-- (long) vma->vm_pgoff);
-+ __func__, (long)vma->vm_start, (long)vma->vm_end,
-+ (long)vma->vm_pgoff);
-
- if (offset + length > mm_vc_mem_size) {
- pr_err("%s: length %ld is too big\n", __func__, length);
- return -EINVAL;
- }
-- // Do not cache the memory map
-+ /* Do not cache the memory map */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- rc = remap_pfn_range(vma, vma->vm_start,
- (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
- vma->vm_pgoff, length, vma->vm_page_prot);
-- if (rc != 0) {
-+ if (rc)
- pr_err("%s: remap_pfn_range failed (rc=%d)\n", __func__, rc);
-- }
-
- return rc;
- }
-
--/****************************************************************************
--*
--* File Operations for the driver.
--*
--***************************************************************************/
--
-+/* File Operations for the driver. */
- static const struct file_operations vc_mem_fops = {
- .owner = THIS_MODULE,
- .open = vc_mem_open,
-@@ -316,7 +263,7 @@ static int vc_mem_debugfs_init(
- vc_mem_debugfs_entry,
- (u32 *)&mm_vc_mem_phys_addr)) {
- dev_warn(dev, "%s:could not create vc_mem_phys entry\n",
-- __func__);
-+ __func__);
- goto fail;
- }
-
-@@ -325,7 +272,7 @@ static int vc_mem_debugfs_init(
- vc_mem_debugfs_entry,
- (u32 *)&mm_vc_mem_size)) {
- dev_warn(dev, "%s:could not create vc_mem_size entry\n",
-- __func__);
-+ __func__);
- goto fail;
- }
-
-@@ -347,12 +294,7 @@ fail:
-
- #endif /* CONFIG_DEBUG_FS */
-
--
--/****************************************************************************
--*
--* vc_mem_init
--*
--***************************************************************************/
-+/* Module load/unload functions */
-
- static int __init
- vc_mem_init(void)
-@@ -369,16 +311,19 @@ vc_mem_init(void)
- vc_mem_get_size();
-
- pr_info("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
-- mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size, mm_vc_mem_size / (1024 * 1024));
-+ mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size,
-+ mm_vc_mem_size / (1024 * 1024));
-
-- if ((rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME)) < 0) {
-+ rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME);
-+ if (rc < 0) {
- pr_err("%s: alloc_chrdev_region failed (rc=%d)\n",
- __func__, rc);
- goto out_err;
- }
-
- cdev_init(&vc_mem_cdev, &vc_mem_fops);
-- if ((rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1)) != 0) {
-+ rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1);
-+ if (rc) {
- pr_err("%s: cdev_add failed (rc=%d)\n", __func__, rc);
- goto out_unregister;
- }
-@@ -408,26 +353,20 @@ vc_mem_init(void)
-
- device_destroy(vc_mem_class, vc_mem_devnum);
-
-- out_class_destroy:
-+out_class_destroy:
- class_destroy(vc_mem_class);
- vc_mem_class = NULL;
-
-- out_cdev_del:
-+out_cdev_del:
- cdev_del(&vc_mem_cdev);
-
-- out_unregister:
-+out_unregister:
- unregister_chrdev_region(vc_mem_devnum, 1);
-
-- out_err:
-+out_err:
- return -1;
- }
-
--/****************************************************************************
--*
--* vc_mem_exit
--*
--***************************************************************************/
--
- static void __exit
- vc_mem_exit(void)
- {
---- a/include/linux/broadcom/vc_mem.h
-+++ b/include/linux/broadcom/vc_mem.h
-@@ -1,16 +1,16 @@
--/*****************************************************************************
--* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
--*
--* Unless you and Broadcom execute a separate written software license
--* agreement governing use of this software, this software is licensed to you
--* under the terms of the GNU General Public License version 2, available at
--* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
--*
--* Notwithstanding the above, under no circumstances may you combine this
--* software in any way with any other Broadcom software provided under a
--* license other than the GPL, without Broadcom's express prior written
--* consent.
--*****************************************************************************/
-+/*
-+ * Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
-+ *
-+ * Unless you and Broadcom execute a separate written software license
-+ * agreement governing use of this software, this software is licensed to you
-+ * under the terms of the GNU General Public License version 2, available at
-+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+ *
-+ * Notwithstanding the above, under no circumstances may you combine this
-+ * software in any way with any other Broadcom software provided under a
-+ * license other than the GPL, without Broadcom's express prior written
-+ * consent.
-+ */
-
- #ifndef _VC_MEM_H
- #define _VC_MEM_H
-@@ -19,17 +19,17 @@
-
- #define VC_MEM_IOC_MAGIC 'v'
-
--#define VC_MEM_IOC_MEM_PHYS_ADDR _IOR( VC_MEM_IOC_MAGIC, 0, unsigned long )
--#define VC_MEM_IOC_MEM_SIZE _IOR( VC_MEM_IOC_MAGIC, 1, unsigned int )
--#define VC_MEM_IOC_MEM_BASE _IOR( VC_MEM_IOC_MAGIC, 2, unsigned int )
--#define VC_MEM_IOC_MEM_LOAD _IOR( VC_MEM_IOC_MAGIC, 3, unsigned int )
-+#define VC_MEM_IOC_MEM_PHYS_ADDR _IOR(VC_MEM_IOC_MAGIC, 0, unsigned long)
-+#define VC_MEM_IOC_MEM_SIZE _IOR(VC_MEM_IOC_MAGIC, 1, unsigned int)
-+#define VC_MEM_IOC_MEM_BASE _IOR(VC_MEM_IOC_MAGIC, 2, unsigned int)
-+#define VC_MEM_IOC_MEM_LOAD _IOR(VC_MEM_IOC_MAGIC, 3, unsigned int)
-
--#if defined( __KERNEL__ )
-+#ifdef __KERNEL__
- #define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
-
- extern unsigned long mm_vc_mem_phys_addr;
- extern unsigned int mm_vc_mem_size;
--extern int vc_mem_get_current_size( void );
-+extern int vc_mem_get_current_size(void);
- #endif
-
- #ifdef CONFIG_COMPAT
--- /dev/null
+From 3e1371cc80a8153885cf87b06053ab2a2f1a1e66 Mon Sep 17 00:00:00 2001
+Date: Tue, 29 Jan 2019 12:05:49 +0000
+Subject: [PATCH] mfd: Add rpi_sense_core of compatible string
+
+---
+ drivers/mfd/rpisense-core.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/mfd/rpisense-core.c
++++ b/drivers/mfd/rpisense-core.c
+@@ -138,6 +138,14 @@ static const struct i2c_device_id rpisen
+ };
+ MODULE_DEVICE_TABLE(i2c, rpisense_i2c_id);
+
++#ifdef CONFIG_OF
++static const struct of_device_id rpisense_core_id[] = {
++ { .compatible = "rpi,rpi-sense" },
++ { },
++};
++MODULE_DEVICE_TABLE(of, rpisense_core_id);
++#endif
++
+
+ static struct i2c_driver rpisense_driver = {
+ .driver = {
+++ /dev/null
-From 83a7175c91133a3e7a746693847b447bf6297094 Mon Sep 17 00:00:00 2001
-Date: Thu, 24 Jan 2019 15:09:28 +0000
-Subject: [PATCH] clk: clk-bcm2835: Use %zd when printing size_t
-
-The debug text for how many clocks have been registered
-uses "%d" with a size_t. Correct it to "%zd".
-
----
- drivers/clk/bcm/clk-bcm2835.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -2271,7 +2271,7 @@ static int bcm2835_clk_probe(struct plat
- return ret;
-
- /* note that we have registered all the clocks */
-- dev_dbg(dev, "registered %d clocks\n", asize);
-+ dev_dbg(dev, "registered %zd clocks\n", asize);
-
- return 0;
- }
--- /dev/null
+From 32e0a9e2549c43d9abc03427ba6f3b7b8c2e1407 Mon Sep 17 00:00:00 2001
+Date: Mon, 28 Jan 2019 14:40:16 +0000
+Subject: [PATCH] gpu: vc4_firmware_kms: Fix up 64 bit compile
+ warnings.
+
+Resolve two build warnings with regard using incorrectly
+sized parameters in logging messages on 64 bit builds.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -160,14 +160,14 @@ static void vc4_primary_plane_atomic_upd
+ WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]);
+ }
+
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%08x/%d\n",
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n",
+ plane->base.id, plane->name,
+ state->crtc_w,
+ state->crtc_h,
+ bpp,
+ state->crtc_x,
+ state->crtc_y,
+- bo->paddr + fb->offsets[0],
++ &fbinfo->base,
+ fb->pitches[0]);
+
+ ret = rpi_firmware_transaction(vc4->firmware,
+@@ -197,6 +197,7 @@ static void vc4_cursor_plane_atomic_upda
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
++ dma_addr_t addr = bo->paddr + fb->offsets[0];
+ int ret;
+ u32 packet_state[] = {
+ state->crtc->state->active,
+@@ -206,13 +207,13 @@ static void vc4_cursor_plane_atomic_upda
+ };
+ WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4);
+
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%08x/%d)",
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%pad/%d)",
+ plane->base.id, plane->name,
+ state->crtc_w,
+ state->crtc_h,
+ state->crtc_x,
+ state->crtc_y,
+- bo->paddr + fb->offsets[0],
++ &addr,
+ fb->pitches[0]);
+
+ /* add on the top/left offsets when overscan is active */
+@@ -238,7 +239,7 @@ static void vc4_cursor_plane_atomic_upda
+ fb != old_state->fb) {
+ u32 packet_info[] = { state->crtc_w, state->crtc_h,
+ 0, /* unused */
+- bo->paddr + fb->offsets[0],
++ addr,
+ 0, 0, /* hotx, hoty */};
+
+ ret = rpi_firmware_property(vc4->firmware,
--- /dev/null
+From 61ce13e4ab846aa035037217c5eec6aff229e539 Mon Sep 17 00:00:00 2001
+Date: Mon, 28 Jan 2019 14:42:34 +0000
+Subject: [PATCH] input: rpi-ft5406: Clear build warning on 64 bit
+ builds.
+
+Resolve 64 bit build warning over using %x with a dma_addr_t.
+
+---
+ drivers/input/touchscreen/rpi-ft5406.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/input/touchscreen/rpi-ft5406.c
++++ b/drivers/input/touchscreen/rpi-ft5406.c
+@@ -218,8 +218,8 @@ static int ft5406_probe(struct platform_
+
+ if (!ts->ts_base) {
+ dev_warn(dev,
+- "set failed, trying get (err:%d touchbuf:%x virt:%p bus:%x)\n",
+- err, touchbuf, ts->ts_base, ts->bus_addr);
++ "set failed, trying get (err:%d touchbuf:%x virt:%p bus:%pad)\n",
++ err, touchbuf, ts->ts_base, &ts->bus_addr);
+
+ err = rpi_firmware_property(
+ fw,
+++ /dev/null
-From 3e1371cc80a8153885cf87b06053ab2a2f1a1e66 Mon Sep 17 00:00:00 2001
-Date: Tue, 29 Jan 2019 12:05:49 +0000
-Subject: [PATCH] mfd: Add rpi_sense_core of compatible string
-
----
- drivers/mfd/rpisense-core.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/drivers/mfd/rpisense-core.c
-+++ b/drivers/mfd/rpisense-core.c
-@@ -138,6 +138,14 @@ static const struct i2c_device_id rpisen
- };
- MODULE_DEVICE_TABLE(i2c, rpisense_i2c_id);
-
-+#ifdef CONFIG_OF
-+static const struct of_device_id rpisense_core_id[] = {
-+ { .compatible = "rpi,rpi-sense" },
-+ { },
-+};
-+MODULE_DEVICE_TABLE(of, rpisense_core_id);
-+#endif
-+
-
- static struct i2c_driver rpisense_driver = {
- .driver = {
--- /dev/null
+From 5c0dfdba54fdaeb813d8535283aa8f75080e1055 Mon Sep 17 00:00:00 2001
+Date: Tue, 18 Sep 2018 10:47:38 +0100
+Subject: [PATCH] dtoverlays: Correct DT handling camera GPIOs
+
+The firmware has support for updating overrides with the correct
+GPIO settings for the camera GPIOs, but the wrong device tree
+setup ended up being merged.
+Correct the DT configuration so that the firmware does set it
+up correctly.
+
+---
+ arch/arm/boot/dts/bcm270x.dtsi | 7 +++++++
+ arch/arm/boot/dts/overlays/README | 10 +---------
+ arch/arm/boot/dts/overlays/ov5647-overlay.dts | 14 +++++++++++---
+ 3 files changed, 19 insertions(+), 12 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm270x.dtsi
++++ b/arch/arm/boot/dts/bcm270x.dtsi
+@@ -152,6 +152,13 @@
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
++
++ __overrides__ {
++ cam0-pwdn-ctrl;
++ cam0-pwdn;
++ cam0-led-ctrl;
++ cam0-led;
++ };
+ };
+
+ &vc4 {
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1366,15 +1366,7 @@ Info: Omnivision OV5647 camera module.
+ Uses Unicam 1, which is the standard camera connector on most Pi
+ variants.
+ Load: dtoverlay=ov5647,<param>=<val>
+-Params: cam0-pwdn GPIO used to control the sensor powerdown line.
+-
+- cam0-led GPIO used to control the sensor led
+- Both these fields should be automatically filled
+- in by the firmware to reflect the default GPIO
+- configuration of the particular Pi variant in
+- use.
+-
+- i2c_pins_0_1 Use pins 0&1 for the I2C instead of 44&45.
++Params: i2c_pins_0_1 Use pins 0&1 for the I2C instead of 44&45.
+ Useful on Compute Modules.
+
+ i2c_pins_28_29 Use pins 28&29 for the I2C instead of 44&45.
+--- a/arch/arm/boot/dts/overlays/ov5647-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts
+@@ -14,7 +14,7 @@
+ status = "okay";
+
+ ov5647: ov5647@36 {
+- compatible = "ov5647";
++ compatible = "ovti,ov5647";
+ reg = <0x36>;
+ status = "okay";
+
+@@ -82,10 +82,18 @@
+ };
+ };
+
++ fragment@6 {
++ target-path="/__overrides__";
++ __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";
++ };
++ };
++
+ __overrides__ {
+ i2c_pins_0_1 = <0>,"-2-3+4";
+ i2c_pins_28_29 = <0>,"+2-3-4";
+- cam0-pwdn = <&ov5647>,"pwdn-gpios:4";
+- cam0-led = <&ov5647>,"pwdn-gpios:16";
+ };
+ };
+++ /dev/null
-From 32e0a9e2549c43d9abc03427ba6f3b7b8c2e1407 Mon Sep 17 00:00:00 2001
-Date: Mon, 28 Jan 2019 14:40:16 +0000
-Subject: [PATCH] gpu: vc4_firmware_kms: Fix up 64 bit compile
- warnings.
-
-Resolve two build warnings with regard using incorrectly
-sized parameters in logging messages on 64 bit builds.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 11 ++++++-----
- 1 file changed, 6 insertions(+), 5 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -160,14 +160,14 @@ static void vc4_primary_plane_atomic_upd
- WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]);
- }
-
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%08x/%d\n",
-+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n",
- plane->base.id, plane->name,
- state->crtc_w,
- state->crtc_h,
- bpp,
- state->crtc_x,
- state->crtc_y,
-- bo->paddr + fb->offsets[0],
-+ &fbinfo->base,
- fb->pitches[0]);
-
- ret = rpi_firmware_transaction(vc4->firmware,
-@@ -197,6 +197,7 @@ static void vc4_cursor_plane_atomic_upda
- struct drm_plane_state *state = plane->state;
- struct drm_framebuffer *fb = state->fb;
- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
-+ dma_addr_t addr = bo->paddr + fb->offsets[0];
- int ret;
- u32 packet_state[] = {
- state->crtc->state->active,
-@@ -206,13 +207,13 @@ static void vc4_cursor_plane_atomic_upda
- };
- WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4);
-
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%08x/%d)",
-+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%pad/%d)",
- plane->base.id, plane->name,
- state->crtc_w,
- state->crtc_h,
- state->crtc_x,
- state->crtc_y,
-- bo->paddr + fb->offsets[0],
-+ &addr,
- fb->pitches[0]);
-
- /* add on the top/left offsets when overscan is active */
-@@ -238,7 +239,7 @@ static void vc4_cursor_plane_atomic_upda
- fb != old_state->fb) {
- u32 packet_info[] = { state->crtc_w, state->crtc_h,
- 0, /* unused */
-- bo->paddr + fb->offsets[0],
-+ addr,
- 0, 0, /* hotx, hoty */};
-
- ret = rpi_firmware_property(vc4->firmware,
+++ /dev/null
-From 61ce13e4ab846aa035037217c5eec6aff229e539 Mon Sep 17 00:00:00 2001
-Date: Mon, 28 Jan 2019 14:42:34 +0000
-Subject: [PATCH] input: rpi-ft5406: Clear build warning on 64 bit
- builds.
-
-Resolve 64 bit build warning over using %x with a dma_addr_t.
-
----
- drivers/input/touchscreen/rpi-ft5406.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/input/touchscreen/rpi-ft5406.c
-+++ b/drivers/input/touchscreen/rpi-ft5406.c
-@@ -218,8 +218,8 @@ static int ft5406_probe(struct platform_
-
- if (!ts->ts_base) {
- dev_warn(dev,
-- "set failed, trying get (err:%d touchbuf:%x virt:%p bus:%x)\n",
-- err, touchbuf, ts->ts_base, ts->bus_addr);
-+ "set failed, trying get (err:%d touchbuf:%x virt:%p bus:%pad)\n",
-+ err, touchbuf, ts->ts_base, &ts->bus_addr);
-
- err = rpi_firmware_property(
- fw,
--- /dev/null
+From 3be30ee1b3aafd7c6cc45bcea77f25c9613732f4 Mon Sep 17 00:00:00 2001
+Date: Tue, 18 Sep 2018 11:08:51 +0100
+Subject: [PATCH] media: ov5647: Use gpiod_set_value_cansleep
+
+All calls to the gpio library are in contexts that can sleep,
+therefore there is no issue with having those GPIOs controlled
+by controllers which require sleeping (eg I2C GPIO expanders).
+
+Switch to using gpiod_set_value_cansleep instead of gpiod_set_value
+to avoid triggering the warning in gpiolib should the GPIO
+controller need to sleep.
+
+---
+ drivers/media/i2c/ov5647.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -373,7 +373,7 @@ static int ov5647_sensor_power(struct v4
+ dev_dbg(&client->dev, "OV5647 power on\n");
+
+ if (ov5647->pwdn) {
+- gpiod_set_value(ov5647->pwdn, 0);
++ gpiod_set_value_cansleep(ov5647->pwdn, 0);
+ msleep(PWDN_ACTIVE_DELAY_MS);
+ }
+
+@@ -415,7 +415,7 @@ static int ov5647_sensor_power(struct v4
+
+ clk_disable_unprepare(ov5647->xclk);
+
+- gpiod_set_value(ov5647->pwdn, 1);
++ gpiod_set_value_cansleep(ov5647->pwdn, 1);
+ }
+
+ /* Update the power count. */
+@@ -649,13 +649,13 @@ static int ov5647_probe(struct i2c_clien
+ goto mutex_remove;
+
+ if (sensor->pwdn) {
+- gpiod_set_value(sensor->pwdn, 0);
++ gpiod_set_value_cansleep(sensor->pwdn, 0);
+ msleep(PWDN_ACTIVE_DELAY_MS);
+ }
+
+ ret = ov5647_detect(sd);
+
+- gpiod_set_value(sensor->pwdn, 1);
++ gpiod_set_value_cansleep(sensor->pwdn, 1);
+
+ if (ret < 0)
+ goto error;
+++ /dev/null
-From 5c0dfdba54fdaeb813d8535283aa8f75080e1055 Mon Sep 17 00:00:00 2001
-Date: Tue, 18 Sep 2018 10:47:38 +0100
-Subject: [PATCH] dtoverlays: Correct DT handling camera GPIOs
-
-The firmware has support for updating overrides with the correct
-GPIO settings for the camera GPIOs, but the wrong device tree
-setup ended up being merged.
-Correct the DT configuration so that the firmware does set it
-up correctly.
-
----
- arch/arm/boot/dts/bcm270x.dtsi | 7 +++++++
- arch/arm/boot/dts/overlays/README | 10 +---------
- arch/arm/boot/dts/overlays/ov5647-overlay.dts | 14 +++++++++++---
- 3 files changed, 19 insertions(+), 12 deletions(-)
-
---- a/arch/arm/boot/dts/bcm270x.dtsi
-+++ b/arch/arm/boot/dts/bcm270x.dtsi
-@@ -152,6 +152,13 @@
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- };
-+
-+ __overrides__ {
-+ cam0-pwdn-ctrl;
-+ cam0-pwdn;
-+ cam0-led-ctrl;
-+ cam0-led;
-+ };
- };
-
- &vc4 {
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1366,15 +1366,7 @@ Info: Omnivision OV5647 camera module.
- Uses Unicam 1, which is the standard camera connector on most Pi
- variants.
- Load: dtoverlay=ov5647,<param>=<val>
--Params: cam0-pwdn GPIO used to control the sensor powerdown line.
--
-- cam0-led GPIO used to control the sensor led
-- Both these fields should be automatically filled
-- in by the firmware to reflect the default GPIO
-- configuration of the particular Pi variant in
-- use.
--
-- i2c_pins_0_1 Use pins 0&1 for the I2C instead of 44&45.
-+Params: i2c_pins_0_1 Use pins 0&1 for the I2C instead of 44&45.
- Useful on Compute Modules.
-
- i2c_pins_28_29 Use pins 28&29 for the I2C instead of 44&45.
---- a/arch/arm/boot/dts/overlays/ov5647-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts
-@@ -14,7 +14,7 @@
- status = "okay";
-
- ov5647: ov5647@36 {
-- compatible = "ov5647";
-+ compatible = "ovti,ov5647";
- reg = <0x36>;
- status = "okay";
-
-@@ -82,10 +82,18 @@
- };
- };
-
-+ fragment@6 {
-+ target-path="/__overrides__";
-+ __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";
-+ };
-+ };
-+
- __overrides__ {
- i2c_pins_0_1 = <0>,"-2-3+4";
- i2c_pins_28_29 = <0>,"+2-3-4";
-- cam0-pwdn = <&ov5647>,"pwdn-gpios:4";
-- cam0-led = <&ov5647>,"pwdn-gpios:16";
- };
- };
--- /dev/null
+From bf1805e0c8c4fc05e2a13b0a03b510ff4e523418 Mon Sep 17 00:00:00 2001
+Date: Tue, 29 Jan 2019 15:56:10 +0000
+Subject: [PATCH] media:bcm2835-unicam: Power on subdev on
+ open/release, not streaming
+
+The driver was powering on the source subdevice as part of STREAMON,
+and powering it off in STREAMOFF. This isn't so great if there is a
+significant amount of setup required for your device.
+
+Copy the approach taken in the Atmel ISC driver where s_power(1) is called
+on first file handle open, and s_power(0) is called on the last release.
+
+See https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=232437
+
+---
+ .../media/platform/bcm2835/bcm2835-unicam.c | 68 +++++++++++++++----
+ 1 file changed, 54 insertions(+), 14 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
+@@ -1237,11 +1237,6 @@ static int unicam_start_streaming(struct
+ unicam_err(dev, "Failed to enable CSI clock: %d\n", ret);
+ goto err_pm_put;
+ }
+- ret = v4l2_subdev_call(dev->sensor, core, s_power, 1);
+- if (ret < 0 && ret != -ENOIOCTLCMD) {
+- unicam_err(dev, "power on failed in subdev\n");
+- goto err_clock_unprepare;
+- }
+ dev->streaming = 1;
+
+ unicam_start_rx(dev, addr);
+@@ -1256,8 +1251,6 @@ static int unicam_start_streaming(struct
+
+ err_disable_unicam:
+ unicam_disable(dev);
+- v4l2_subdev_call(dev->sensor, core, s_power, 0);
+-err_clock_unprepare:
+ clk_disable_unprepare(dev->clock);
+ err_pm_put:
+ unicam_runtime_put(dev);
+@@ -1306,11 +1299,6 @@ static void unicam_stop_streaming(struct
+ dev->next_frm = NULL;
+ spin_unlock_irqrestore(&dev->dma_queue_lock, flags);
+
+- if (v4l2_subdev_has_op(dev->sensor, core, s_power)) {
+- if (v4l2_subdev_call(dev->sensor, core, s_power, 0) < 0)
+- unicam_err(dev, "power off failed in subdev\n");
+- }
+-
+ clk_disable_unprepare(dev->clock);
+ unicam_runtime_put(dev);
+ }
+@@ -1543,11 +1531,63 @@ static const struct vb2_ops unicam_video
+ .stop_streaming = unicam_stop_streaming,
+ };
+
++/*
++ * unicam_open : This function is based on the v4l2_fh_open helper function.
++ * It has been augmented to handle sensor subdevice power management,
++ */
++static int unicam_open(struct file *file)
++{
++ struct unicam_device *dev = video_drvdata(file);
++ int ret;
++
++ mutex_lock(&dev->lock);
++
++ ret = v4l2_fh_open(file);
++ if (ret) {
++ unicam_err(dev, "v4l2_fh_open failed\n");
++ goto unlock;
++ }
++
++ if (!v4l2_fh_is_singular_file(file))
++ goto unlock;
++
++ ret = v4l2_subdev_call(dev->sensor, core, s_power, 1);
++ if (ret < 0 && ret != -ENOIOCTLCMD) {
++ v4l2_fh_release(file);
++ goto unlock;
++ }
++
++unlock:
++ mutex_unlock(&dev->lock);
++ return ret;
++}
++
++static int unicam_release(struct file *file)
++{
++ struct unicam_device *dev = video_drvdata(file);
++ struct v4l2_subdev *sd = dev->sensor;
++ bool fh_singular;
++ int ret;
++
++ mutex_lock(&dev->lock);
++
++ fh_singular = v4l2_fh_is_singular_file(file);
++
++ ret = _vb2_fop_release(file, NULL);
++
++ if (fh_singular)
++ v4l2_subdev_call(sd, core, s_power, 0);
++
++ mutex_unlock(&dev->lock);
++
++ return ret;
++}
++
+ /* unicam capture driver file operations */
+ static const struct v4l2_file_operations unicam_fops = {
+ .owner = THIS_MODULE,
+- .open = v4l2_fh_open,
+- .release = vb2_fop_release,
++ .open = unicam_open,
++ .release = unicam_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
--- /dev/null
+From 0e69aceab4e7615cf631a8c7bdb25093cbba240a Mon Sep 17 00:00:00 2001
+Date: Tue, 29 Jan 2019 14:56:03 +1100
+Subject: [PATCH] audioinjector-octo: revert to dummy supplies
+
+The Audio Injector Octo has had a lot of reports of not coming up on power cycles. By reverting to dummy supplies, the card comes up reliably.
+---
+ arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
++++ b/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
+@@ -25,10 +25,6 @@
+ reg = <0x48>;
+ clocks = <&cs42448_mclk>;
+ clock-names = "mclk";
+- VA-supply = <&vdd_5v0_reg>;
+- VD-supply = <&vdd_3v3_reg>;
+- VLS-supply = <&vdd_3v3_reg>;
+- VLC-supply = <&vdd_3v3_reg>;
+ status = "okay";
+ };
+
+++ /dev/null
-From 3be30ee1b3aafd7c6cc45bcea77f25c9613732f4 Mon Sep 17 00:00:00 2001
-Date: Tue, 18 Sep 2018 11:08:51 +0100
-Subject: [PATCH] media: ov5647: Use gpiod_set_value_cansleep
-
-All calls to the gpio library are in contexts that can sleep,
-therefore there is no issue with having those GPIOs controlled
-by controllers which require sleeping (eg I2C GPIO expanders).
-
-Switch to using gpiod_set_value_cansleep instead of gpiod_set_value
-to avoid triggering the warning in gpiolib should the GPIO
-controller need to sleep.
-
----
- drivers/media/i2c/ov5647.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
---- a/drivers/media/i2c/ov5647.c
-+++ b/drivers/media/i2c/ov5647.c
-@@ -373,7 +373,7 @@ static int ov5647_sensor_power(struct v4
- dev_dbg(&client->dev, "OV5647 power on\n");
-
- if (ov5647->pwdn) {
-- gpiod_set_value(ov5647->pwdn, 0);
-+ gpiod_set_value_cansleep(ov5647->pwdn, 0);
- msleep(PWDN_ACTIVE_DELAY_MS);
- }
-
-@@ -415,7 +415,7 @@ static int ov5647_sensor_power(struct v4
-
- clk_disable_unprepare(ov5647->xclk);
-
-- gpiod_set_value(ov5647->pwdn, 1);
-+ gpiod_set_value_cansleep(ov5647->pwdn, 1);
- }
-
- /* Update the power count. */
-@@ -649,13 +649,13 @@ static int ov5647_probe(struct i2c_clien
- goto mutex_remove;
-
- if (sensor->pwdn) {
-- gpiod_set_value(sensor->pwdn, 0);
-+ gpiod_set_value_cansleep(sensor->pwdn, 0);
- msleep(PWDN_ACTIVE_DELAY_MS);
- }
-
- ret = ov5647_detect(sd);
-
-- gpiod_set_value(sensor->pwdn, 1);
-+ gpiod_set_value_cansleep(sensor->pwdn, 1);
-
- if (ret < 0)
- goto error;
+++ /dev/null
-From bf1805e0c8c4fc05e2a13b0a03b510ff4e523418 Mon Sep 17 00:00:00 2001
-Date: Tue, 29 Jan 2019 15:56:10 +0000
-Subject: [PATCH] media:bcm2835-unicam: Power on subdev on
- open/release, not streaming
-
-The driver was powering on the source subdevice as part of STREAMON,
-and powering it off in STREAMOFF. This isn't so great if there is a
-significant amount of setup required for your device.
-
-Copy the approach taken in the Atmel ISC driver where s_power(1) is called
-on first file handle open, and s_power(0) is called on the last release.
-
-See https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=232437
-
----
- .../media/platform/bcm2835/bcm2835-unicam.c | 68 +++++++++++++++----
- 1 file changed, 54 insertions(+), 14 deletions(-)
-
---- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
-@@ -1237,11 +1237,6 @@ static int unicam_start_streaming(struct
- unicam_err(dev, "Failed to enable CSI clock: %d\n", ret);
- goto err_pm_put;
- }
-- ret = v4l2_subdev_call(dev->sensor, core, s_power, 1);
-- if (ret < 0 && ret != -ENOIOCTLCMD) {
-- unicam_err(dev, "power on failed in subdev\n");
-- goto err_clock_unprepare;
-- }
- dev->streaming = 1;
-
- unicam_start_rx(dev, addr);
-@@ -1256,8 +1251,6 @@ static int unicam_start_streaming(struct
-
- err_disable_unicam:
- unicam_disable(dev);
-- v4l2_subdev_call(dev->sensor, core, s_power, 0);
--err_clock_unprepare:
- clk_disable_unprepare(dev->clock);
- err_pm_put:
- unicam_runtime_put(dev);
-@@ -1306,11 +1299,6 @@ static void unicam_stop_streaming(struct
- dev->next_frm = NULL;
- spin_unlock_irqrestore(&dev->dma_queue_lock, flags);
-
-- if (v4l2_subdev_has_op(dev->sensor, core, s_power)) {
-- if (v4l2_subdev_call(dev->sensor, core, s_power, 0) < 0)
-- unicam_err(dev, "power off failed in subdev\n");
-- }
--
- clk_disable_unprepare(dev->clock);
- unicam_runtime_put(dev);
- }
-@@ -1543,11 +1531,63 @@ static const struct vb2_ops unicam_video
- .stop_streaming = unicam_stop_streaming,
- };
-
-+/*
-+ * unicam_open : This function is based on the v4l2_fh_open helper function.
-+ * It has been augmented to handle sensor subdevice power management,
-+ */
-+static int unicam_open(struct file *file)
-+{
-+ struct unicam_device *dev = video_drvdata(file);
-+ int ret;
-+
-+ mutex_lock(&dev->lock);
-+
-+ ret = v4l2_fh_open(file);
-+ if (ret) {
-+ unicam_err(dev, "v4l2_fh_open failed\n");
-+ goto unlock;
-+ }
-+
-+ if (!v4l2_fh_is_singular_file(file))
-+ goto unlock;
-+
-+ ret = v4l2_subdev_call(dev->sensor, core, s_power, 1);
-+ if (ret < 0 && ret != -ENOIOCTLCMD) {
-+ v4l2_fh_release(file);
-+ goto unlock;
-+ }
-+
-+unlock:
-+ mutex_unlock(&dev->lock);
-+ return ret;
-+}
-+
-+static int unicam_release(struct file *file)
-+{
-+ struct unicam_device *dev = video_drvdata(file);
-+ struct v4l2_subdev *sd = dev->sensor;
-+ bool fh_singular;
-+ int ret;
-+
-+ mutex_lock(&dev->lock);
-+
-+ fh_singular = v4l2_fh_is_singular_file(file);
-+
-+ ret = _vb2_fop_release(file, NULL);
-+
-+ if (fh_singular)
-+ v4l2_subdev_call(sd, core, s_power, 0);
-+
-+ mutex_unlock(&dev->lock);
-+
-+ return ret;
-+}
-+
- /* unicam capture driver file operations */
- static const struct v4l2_file_operations unicam_fops = {
- .owner = THIS_MODULE,
-- .open = v4l2_fh_open,
-- .release = vb2_fop_release,
-+ .open = unicam_open,
-+ .release = unicam_release,
- .read = vb2_fop_read,
- .poll = vb2_fop_poll,
- .unlocked_ioctl = video_ioctl2,
--- /dev/null
+From 8c420772ef0f15ebbc3f13ebcc340d34bbdfad71 Mon Sep 17 00:00:00 2001
+Date: Thu, 24 Jan 2019 16:20:38 +0000
+Subject: [PATCH] staging: bcm2835-camera: Correct ctrl
+ min/max/step/def to 64bit
+
+The V4L2 control API was expanded to take 64 bit values in commit
+0ba2aeb6dab (Apr 16 2014), but as this driver wasn't in the mainline
+kernel at that point this was overlooked.
+
+Update to use 64 bit values. This also fixes a couple of warnings
+in 64 bit builds.
+
+---
+ .../vc04_services/bcm2835-camera/controls.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -78,10 +78,10 @@ struct bm2835_mmal_v4l2_ctrl {
+ /* control minimum value or
+ * mask for MMAL_CONTROL_TYPE_STD_MENU
+ */
+- s32 min;
+- s32 max; /* maximum value of control */
+- s32 def; /* default value of control */
+- s32 step; /* step size of the control */
++ s64 min;
++ s64 max; /* maximum value of control */
++ s64 def; /* default value of control */
++ u64 step; /* step size of the control */
+ const s64 *imenu; /* integer menu array */
+ u32 mmal_id; /* mmal parameter id */
+ bm2835_mmal_v4l2_ctrl_cb *setter;
+@@ -1244,7 +1244,7 @@ int bm2835_mmal_init_controls(struct bm2
+
+ case MMAL_CONTROL_TYPE_STD_MENU:
+ {
+- int mask = ctrl->min;
++ u64 mask = ctrl->min;
+
+ if (ctrl->id == V4L2_CID_SCENE_MODE) {
+ /* Special handling to work out the mask
+@@ -1254,11 +1254,11 @@ int bm2835_mmal_init_controls(struct bm2
+ */
+ int i;
+
+- mask = 1 << V4L2_SCENE_MODE_NONE;
++ mask = BIT(V4L2_SCENE_MODE_NONE);
+ for (i = 0;
+ i < ARRAY_SIZE(scene_configs);
+ i++) {
+- mask |= 1 << scene_configs[i].v4l2_scene;
++ mask |= BIT(scene_configs[i].v4l2_scene);
+ }
+ mask = ~mask;
+ }
+++ /dev/null
-From 0e69aceab4e7615cf631a8c7bdb25093cbba240a Mon Sep 17 00:00:00 2001
-Date: Tue, 29 Jan 2019 14:56:03 +1100
-Subject: [PATCH] audioinjector-octo: revert to dummy supplies
-
-The Audio Injector Octo has had a lot of reports of not coming up on power cycles. By reverting to dummy supplies, the card comes up reliably.
----
- arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts | 4 ----
- 1 file changed, 4 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
-@@ -25,10 +25,6 @@
- reg = <0x48>;
- clocks = <&cs42448_mclk>;
- clock-names = "mclk";
-- VA-supply = <&vdd_5v0_reg>;
-- VD-supply = <&vdd_3v3_reg>;
-- VLS-supply = <&vdd_3v3_reg>;
-- VLC-supply = <&vdd_3v3_reg>;
- status = "okay";
- };
-
--- /dev/null
+From 8920ce80058cfa3d18dc8bc7535119e9986dbad7 Mon Sep 17 00:00:00 2001
+Date: Thu, 24 Jan 2019 16:40:01 +0000
+Subject: [PATCH] staging: bcm2835-codec: variable vb2 may be used
+ uninitialised
+
+In op_buffer_cb, the failure path checked whether there was
+an associated vb2 buffer before the variable vb2 had been
+assigned.
+
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -634,6 +634,9 @@ static void op_buffer_cb(struct vchiq_mm
+ __func__, status, mmal_buf, mmal_buf->length,
+ mmal_buf->mmal_flags, mmal_buf->pts);
+
++ buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal);
++ vb2 = &buf->m2m.vb;
++
+ if (status) {
+ /* error in transfer */
+ if (vb2) {
+@@ -658,9 +661,6 @@ static void op_buffer_cb(struct vchiq_mm
+ return;
+ }
+
+- buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal);
+- vb2 = &buf->m2m.vb;
+-
+ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: length %lu, flags %x, idx %u\n",
+ __func__, mmal_buf->length, mmal_buf->mmal_flags,
+ vb2->vb2_buf.index);
+++ /dev/null
-From 8c420772ef0f15ebbc3f13ebcc340d34bbdfad71 Mon Sep 17 00:00:00 2001
-Date: Thu, 24 Jan 2019 16:20:38 +0000
-Subject: [PATCH] staging: bcm2835-camera: Correct ctrl
- min/max/step/def to 64bit
-
-The V4L2 control API was expanded to take 64 bit values in commit
-0ba2aeb6dab (Apr 16 2014), but as this driver wasn't in the mainline
-kernel at that point this was overlooked.
-
-Update to use 64 bit values. This also fixes a couple of warnings
-in 64 bit builds.
-
----
- .../vc04_services/bcm2835-camera/controls.c | 14 +++++++-------
- 1 file changed, 7 insertions(+), 7 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -78,10 +78,10 @@ struct bm2835_mmal_v4l2_ctrl {
- /* control minimum value or
- * mask for MMAL_CONTROL_TYPE_STD_MENU
- */
-- s32 min;
-- s32 max; /* maximum value of control */
-- s32 def; /* default value of control */
-- s32 step; /* step size of the control */
-+ s64 min;
-+ s64 max; /* maximum value of control */
-+ s64 def; /* default value of control */
-+ u64 step; /* step size of the control */
- const s64 *imenu; /* integer menu array */
- u32 mmal_id; /* mmal parameter id */
- bm2835_mmal_v4l2_ctrl_cb *setter;
-@@ -1244,7 +1244,7 @@ int bm2835_mmal_init_controls(struct bm2
-
- case MMAL_CONTROL_TYPE_STD_MENU:
- {
-- int mask = ctrl->min;
-+ u64 mask = ctrl->min;
-
- if (ctrl->id == V4L2_CID_SCENE_MODE) {
- /* Special handling to work out the mask
-@@ -1254,11 +1254,11 @@ int bm2835_mmal_init_controls(struct bm2
- */
- int i;
-
-- mask = 1 << V4L2_SCENE_MODE_NONE;
-+ mask = BIT(V4L2_SCENE_MODE_NONE);
- for (i = 0;
- i < ARRAY_SIZE(scene_configs);
- i++) {
-- mask |= 1 << scene_configs[i].v4l2_scene;
-+ mask |= BIT(scene_configs[i].v4l2_scene);
- }
- mask = ~mask;
- }
--- /dev/null
+From 7e3cada9dae5d030256605a28df9537b26e776a8 Mon Sep 17 00:00:00 2001
+Date: Thu, 24 Jan 2019 16:36:19 +0000
+Subject: [PATCH] staging: bcm2835-codec: Fix potentially uninitialised
+ vars
+
+src_m2m_buf and dst_m2m_buf were printed in log messages
+when there are code paths that don't initialise them.
+
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -743,7 +743,7 @@ static void device_run(void *priv)
+ struct bcm2835_codec_ctx *ctx = priv;
+ struct bcm2835_codec_dev *dev = ctx->dev;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+- struct m2m_mmal_buffer *src_m2m_buf, *dst_m2m_buf;
++ struct m2m_mmal_buffer *src_m2m_buf = NULL, *dst_m2m_buf = NULL;
+ struct v4l2_m2m_buffer *m2m;
+ int ret;
+
+++ /dev/null
-From 8920ce80058cfa3d18dc8bc7535119e9986dbad7 Mon Sep 17 00:00:00 2001
-Date: Thu, 24 Jan 2019 16:40:01 +0000
-Subject: [PATCH] staging: bcm2835-codec: variable vb2 may be used
- uninitialised
-
-In op_buffer_cb, the failure path checked whether there was
-an associated vb2 buffer before the variable vb2 had been
-assigned.
-
----
- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -634,6 +634,9 @@ static void op_buffer_cb(struct vchiq_mm
- __func__, status, mmal_buf, mmal_buf->length,
- mmal_buf->mmal_flags, mmal_buf->pts);
-
-+ buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal);
-+ vb2 = &buf->m2m.vb;
-+
- if (status) {
- /* error in transfer */
- if (vb2) {
-@@ -658,9 +661,6 @@ static void op_buffer_cb(struct vchiq_mm
- return;
- }
-
-- buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal);
-- vb2 = &buf->m2m.vb;
--
- v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: length %lu, flags %x, idx %u\n",
- __func__, mmal_buf->length, mmal_buf->mmal_flags,
- vb2->vb2_buf.index);
--- /dev/null
+From b5bd7b621f6ab2f29e9f18ec2a2720d702b9727c Mon Sep 17 00:00:00 2001
+Date: Fri, 25 Jan 2019 17:12:54 +0000
+Subject: [PATCH] video: bcm2708_fb: Add compat_ioctl support.
+
+When using a 64 bit kernel with 32 bit userspace we need
+compat ioctl handling for FBIODMACOPY as one of the
+parameters is a pointer.
+
+---
+ drivers/video/fbdev/bcm2708_fb.c | 87 ++++++++++++++++++++++++--------
+ 1 file changed, 66 insertions(+), 21 deletions(-)
+
+--- a/drivers/video/fbdev/bcm2708_fb.c
++++ b/drivers/video/fbdev/bcm2708_fb.c
+@@ -482,9 +482,8 @@ static void dma_memcpy(struct bcm2708_fb
+ /* cache coherent but non-allocating in L1 and L2 */
+ #define INTALIAS_L1L2_NONALLOCATING(x) (((x)&~0xc0000000)|0x80000000)
+
+-static long vc_mem_copy(struct bcm2708_fb *fb, unsigned long arg)
++static long vc_mem_copy(struct bcm2708_fb *fb, struct fb_dmacopy *ioparam)
+ {
+- struct fb_dmacopy ioparam;
+ size_t size = PAGE_SIZE;
+ u32 *buf = NULL;
+ dma_addr_t bus_addr;
+@@ -497,26 +496,16 @@ static long vc_mem_copy(struct bcm2708_f
+ goto out;
+ }
+
+- /* Get the parameter data.
+- */
+- if (copy_from_user
+- (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
+- pr_err("[%s]: failed to copy-from-user\n",
+- __func__);
+- rc = -EFAULT;
+- goto out;
+- }
+-
+- if (fb->gpu.base == 0 || fb->gpu.length == 0) {
++ if (!fb->gpu.base || !fb->gpu.length) {
+ pr_err("[%s]: Unable to determine gpu memory (%x,%x)\n",
+ __func__, fb->gpu.base, fb->gpu.length);
+ return -EFAULT;
+ }
+
+- if (INTALIAS_NORMAL(ioparam.src) < fb->gpu.base ||
+- INTALIAS_NORMAL(ioparam.src) >= fb->gpu.base + fb->gpu.length) {
++ if (INTALIAS_NORMAL(ioparam->src) < fb->gpu.base ||
++ INTALIAS_NORMAL(ioparam->src) >= fb->gpu.base + fb->gpu.length) {
+ pr_err("[%s]: Invalid memory access %x (%x-%x)", __func__,
+- INTALIAS_NORMAL(ioparam.src), fb->gpu.base,
++ INTALIAS_NORMAL(ioparam->src), fb->gpu.base,
+ fb->gpu.base + fb->gpu.length);
+ return -EFAULT;
+ }
+@@ -530,11 +519,11 @@ static long vc_mem_copy(struct bcm2708_f
+ goto out;
+ }
+
+- for (offset = 0; offset < ioparam.length; offset += size) {
+- size_t remaining = ioparam.length - offset;
++ for (offset = 0; offset < ioparam->length; offset += size) {
++ size_t remaining = ioparam->length - offset;
+ size_t s = min(size, remaining);
+- unsigned char *p = (unsigned char *)ioparam.src + offset;
+- unsigned char *q = (unsigned char *)ioparam.dst + offset;
++ u8 *p = (u8 *)((uintptr_t)ioparam->src + offset);
++ u8 *q = (u8 *)ioparam->dst + offset;
+
+ dma_memcpy(fb, bus_addr,
+ INTALIAS_L1L2_NONALLOCATING((dma_addr_t)p), size);
+@@ -566,8 +555,19 @@ static int bcm2708_ioctl(struct fb_info
+ &dummy, sizeof(dummy));
+ break;
+ case FBIODMACOPY:
+- ret = vc_mem_copy(fb, arg);
++ {
++ struct fb_dmacopy ioparam;
++ /* Get the parameter data.
++ */
++ if (copy_from_user
++ (&ioparam, (void *)arg, sizeof(ioparam))) {
++ pr_err("[%s]: failed to copy-from-user\n", __func__);
++ ret = -EFAULT;
++ break;
++ }
++ ret = vc_mem_copy(fb, &ioparam);
+ break;
++ }
+ default:
+ dev_dbg(info->device, "Unknown ioctl 0x%x\n", cmd);
+ return -ENOTTY;
+@@ -578,6 +578,48 @@ static int bcm2708_ioctl(struct fb_info
+
+ return ret;
+ }
++
++#ifdef CONFIG_COMPAT
++struct fb_dmacopy32 {
++ compat_uptr_t dst;
++ __u32 src;
++ __u32 length;
++};
++
++#define FBIODMACOPY32 _IOW('z', 0x22, struct fb_dmacopy32)
++
++static int bcm2708_compat_ioctl(struct fb_info *info, unsigned int cmd,
++ unsigned long arg)
++{
++ struct bcm2708_fb *fb = to_bcm2708(info);
++ int ret;
++
++ switch (cmd) {
++ case FBIODMACOPY32:
++ {
++ struct fb_dmacopy32 param32;
++ struct fb_dmacopy param;
++ /* Get the parameter data.
++ */
++ if (copy_from_user(¶m32, (void *)arg, sizeof(param32))) {
++ pr_err("[%s]: failed to copy-from-user\n", __func__);
++ ret = -EFAULT;
++ break;
++ }
++ param.dst = compat_ptr(param32.dst);
++ param.src = param32.src;
++ param.length = param32.length;
++ ret = vc_mem_copy(fb, ¶m);
++ break;
++ }
++ default:
++ ret = bcm2708_ioctl(info, cmd, arg);
++ break;
++ }
++ return ret;
++}
++#endif
++
+ static void bcm2708_fb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+ {
+@@ -768,6 +810,9 @@ static struct fb_ops bcm2708_fb_ops = {
+ .fb_imageblit = bcm2708_fb_imageblit,
+ .fb_pan_display = bcm2708_fb_pan_display,
+ .fb_ioctl = bcm2708_ioctl,
++#ifdef CONFIG_COMPAT
++ .fb_compat_ioctl = bcm2708_compat_ioctl,
++#endif
+ };
+
+ static int bcm2708_fb_register(struct bcm2708_fb *fb)
+++ /dev/null
-From 7e3cada9dae5d030256605a28df9537b26e776a8 Mon Sep 17 00:00:00 2001
-Date: Thu, 24 Jan 2019 16:36:19 +0000
-Subject: [PATCH] staging: bcm2835-codec: Fix potentially uninitialised
- vars
-
-src_m2m_buf and dst_m2m_buf were printed in log messages
-when there are code paths that don't initialise them.
-
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -743,7 +743,7 @@ static void device_run(void *priv)
- struct bcm2835_codec_ctx *ctx = priv;
- struct bcm2835_codec_dev *dev = ctx->dev;
- struct vb2_v4l2_buffer *src_buf, *dst_buf;
-- struct m2m_mmal_buffer *src_m2m_buf, *dst_m2m_buf;
-+ struct m2m_mmal_buffer *src_m2m_buf = NULL, *dst_m2m_buf = NULL;
- struct v4l2_m2m_buffer *m2m;
- int ret;
-
--- /dev/null
+From ca128febc6abc040d747ddc0808fd203c135668e Mon Sep 17 00:00:00 2001
+Date: Fri, 25 Jan 2019 17:11:39 +0000
+Subject: [PATCH] video: bcm2708_fb: Fix warnings on 64 bit builds
+
+Fix up logging lines where the wrong format specifiers were
+being used.
+
+---
+ drivers/video/fbdev/bcm2708_fb.c | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+--- a/drivers/video/fbdev/bcm2708_fb.c
++++ b/drivers/video/fbdev/bcm2708_fb.c
+@@ -513,8 +513,8 @@ static long vc_mem_copy(struct bcm2708_f
+ buf = dma_alloc_coherent(fb->fb.device, PAGE_ALIGN(size), &bus_addr,
+ GFP_ATOMIC);
+ if (!buf) {
+- pr_err("[%s]: failed to dma_alloc_coherent(%d)\n",
+- __func__, size);
++ pr_err("[%s]: failed to dma_alloc_coherent(%zd)\n", __func__,
++ size);
+ rc = -ENOMEM;
+ goto out;
+ }
+@@ -910,8 +910,7 @@ static int bcm2708_fb_probe(struct platf
+ goto free_fb;
+ }
+
+- pr_info("BCM2708FB: allocated DMA memory %08x\n",
+- fb->cb_handle);
++ pr_info("BCM2708FB: allocated DMA memory %pad\n", &fb->cb_handle);
+
+ ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK,
+ &fb->dma_chan_base, &fb->dma_irq);
+@@ -929,8 +928,7 @@ static int bcm2708_fb_probe(struct platf
+ }
+
+
+- pr_info("BCM2708FB: allocated DMA channel %d @ %p\n",
+- fb->dma_chan, fb->dma_chan_base);
++ pr_info("BCM2708FB: allocated DMA channel %d\n", fb->dma_chan);
+
+ fb->dev = dev;
+ fb->fb.device = &dev->dev;
+++ /dev/null
-From b5bd7b621f6ab2f29e9f18ec2a2720d702b9727c Mon Sep 17 00:00:00 2001
-Date: Fri, 25 Jan 2019 17:12:54 +0000
-Subject: [PATCH] video: bcm2708_fb: Add compat_ioctl support.
-
-When using a 64 bit kernel with 32 bit userspace we need
-compat ioctl handling for FBIODMACOPY as one of the
-parameters is a pointer.
-
----
- drivers/video/fbdev/bcm2708_fb.c | 87 ++++++++++++++++++++++++--------
- 1 file changed, 66 insertions(+), 21 deletions(-)
-
---- a/drivers/video/fbdev/bcm2708_fb.c
-+++ b/drivers/video/fbdev/bcm2708_fb.c
-@@ -482,9 +482,8 @@ static void dma_memcpy(struct bcm2708_fb
- /* cache coherent but non-allocating in L1 and L2 */
- #define INTALIAS_L1L2_NONALLOCATING(x) (((x)&~0xc0000000)|0x80000000)
-
--static long vc_mem_copy(struct bcm2708_fb *fb, unsigned long arg)
-+static long vc_mem_copy(struct bcm2708_fb *fb, struct fb_dmacopy *ioparam)
- {
-- struct fb_dmacopy ioparam;
- size_t size = PAGE_SIZE;
- u32 *buf = NULL;
- dma_addr_t bus_addr;
-@@ -497,26 +496,16 @@ static long vc_mem_copy(struct bcm2708_f
- goto out;
- }
-
-- /* Get the parameter data.
-- */
-- if (copy_from_user
-- (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
-- pr_err("[%s]: failed to copy-from-user\n",
-- __func__);
-- rc = -EFAULT;
-- goto out;
-- }
--
-- if (fb->gpu.base == 0 || fb->gpu.length == 0) {
-+ if (!fb->gpu.base || !fb->gpu.length) {
- pr_err("[%s]: Unable to determine gpu memory (%x,%x)\n",
- __func__, fb->gpu.base, fb->gpu.length);
- return -EFAULT;
- }
-
-- if (INTALIAS_NORMAL(ioparam.src) < fb->gpu.base ||
-- INTALIAS_NORMAL(ioparam.src) >= fb->gpu.base + fb->gpu.length) {
-+ if (INTALIAS_NORMAL(ioparam->src) < fb->gpu.base ||
-+ INTALIAS_NORMAL(ioparam->src) >= fb->gpu.base + fb->gpu.length) {
- pr_err("[%s]: Invalid memory access %x (%x-%x)", __func__,
-- INTALIAS_NORMAL(ioparam.src), fb->gpu.base,
-+ INTALIAS_NORMAL(ioparam->src), fb->gpu.base,
- fb->gpu.base + fb->gpu.length);
- return -EFAULT;
- }
-@@ -530,11 +519,11 @@ static long vc_mem_copy(struct bcm2708_f
- goto out;
- }
-
-- for (offset = 0; offset < ioparam.length; offset += size) {
-- size_t remaining = ioparam.length - offset;
-+ for (offset = 0; offset < ioparam->length; offset += size) {
-+ size_t remaining = ioparam->length - offset;
- size_t s = min(size, remaining);
-- unsigned char *p = (unsigned char *)ioparam.src + offset;
-- unsigned char *q = (unsigned char *)ioparam.dst + offset;
-+ u8 *p = (u8 *)((uintptr_t)ioparam->src + offset);
-+ u8 *q = (u8 *)ioparam->dst + offset;
-
- dma_memcpy(fb, bus_addr,
- INTALIAS_L1L2_NONALLOCATING((dma_addr_t)p), size);
-@@ -566,8 +555,19 @@ static int bcm2708_ioctl(struct fb_info
- &dummy, sizeof(dummy));
- break;
- case FBIODMACOPY:
-- ret = vc_mem_copy(fb, arg);
-+ {
-+ struct fb_dmacopy ioparam;
-+ /* Get the parameter data.
-+ */
-+ if (copy_from_user
-+ (&ioparam, (void *)arg, sizeof(ioparam))) {
-+ pr_err("[%s]: failed to copy-from-user\n", __func__);
-+ ret = -EFAULT;
-+ break;
-+ }
-+ ret = vc_mem_copy(fb, &ioparam);
- break;
-+ }
- default:
- dev_dbg(info->device, "Unknown ioctl 0x%x\n", cmd);
- return -ENOTTY;
-@@ -578,6 +578,48 @@ static int bcm2708_ioctl(struct fb_info
-
- return ret;
- }
-+
-+#ifdef CONFIG_COMPAT
-+struct fb_dmacopy32 {
-+ compat_uptr_t dst;
-+ __u32 src;
-+ __u32 length;
-+};
-+
-+#define FBIODMACOPY32 _IOW('z', 0x22, struct fb_dmacopy32)
-+
-+static int bcm2708_compat_ioctl(struct fb_info *info, unsigned int cmd,
-+ unsigned long arg)
-+{
-+ struct bcm2708_fb *fb = to_bcm2708(info);
-+ int ret;
-+
-+ switch (cmd) {
-+ case FBIODMACOPY32:
-+ {
-+ struct fb_dmacopy32 param32;
-+ struct fb_dmacopy param;
-+ /* Get the parameter data.
-+ */
-+ if (copy_from_user(¶m32, (void *)arg, sizeof(param32))) {
-+ pr_err("[%s]: failed to copy-from-user\n", __func__);
-+ ret = -EFAULT;
-+ break;
-+ }
-+ param.dst = compat_ptr(param32.dst);
-+ param.src = param32.src;
-+ param.length = param32.length;
-+ ret = vc_mem_copy(fb, ¶m);
-+ break;
-+ }
-+ default:
-+ ret = bcm2708_ioctl(info, cmd, arg);
-+ break;
-+ }
-+ return ret;
-+}
-+#endif
-+
- static void bcm2708_fb_fillrect(struct fb_info *info,
- const struct fb_fillrect *rect)
- {
-@@ -768,6 +810,9 @@ static struct fb_ops bcm2708_fb_ops = {
- .fb_imageblit = bcm2708_fb_imageblit,
- .fb_pan_display = bcm2708_fb_pan_display,
- .fb_ioctl = bcm2708_ioctl,
-+#ifdef CONFIG_COMPAT
-+ .fb_compat_ioctl = bcm2708_compat_ioctl,
-+#endif
- };
-
- static int bcm2708_fb_register(struct bcm2708_fb *fb)
--- /dev/null
+From 47f7687efaf3873fe8c0e47653515e9ada1b86da Mon Sep 17 00:00:00 2001
+Date: Fri, 25 Jan 2019 17:32:54 +0000
+Subject: [PATCH] video: bcm2708_fb: Clean up coding style issues
+
+Now checkpatch clean except for 2 long lines, missing
+SPDX header, and no DT documentation.
+
+---
+ drivers/video/fbdev/bcm2708_fb.c | 96 ++++++++++++++------------------
+ 1 file changed, 42 insertions(+), 54 deletions(-)
+
+--- a/drivers/video/fbdev/bcm2708_fb.c
++++ b/drivers/video/fbdev/bcm2708_fb.c
+@@ -41,7 +41,7 @@
+ #define MODULE_NAME "bcm2708_fb"
+
+ #ifdef BCM2708_FB_DEBUG
+-#define print_debug(fmt, ...) pr_debug("%s:%s:%d: "fmt, \
++#define print_debug(fmt, ...) pr_debug("%s:%s:%d: " fmt, \
+ MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
+ #else
+ #define print_debug(fmt, ...)
+@@ -57,7 +57,7 @@ static int fbheight = 480; /* module par
+ static int fbdepth = 32; /* module parameter */
+ static int fbswap; /* module parameter */
+
+-static u32 dma_busy_wait_threshold = 1<<15;
++static u32 dma_busy_wait_threshold = 1 << 15;
+ module_param(dma_busy_wait_threshold, int, 0644);
+ MODULE_PARM_DESC(dma_busy_wait_threshold, "Busy-wait for DMA completion below this area");
+
+@@ -132,8 +132,8 @@ static int bcm2708_fb_debugfs_init(struc
+ fb->stats.regset.nregs = ARRAY_SIZE(stats_registers);
+ fb->stats.regset.base = &fb->stats;
+
+- if (!debugfs_create_regset32(
+- "stats", 0444, fb->debugfs_dir, &fb->stats.regset)) {
++ if (!debugfs_create_regset32("stats", 0444, fb->debugfs_dir,
++ &fb->stats.regset)) {
+ pr_warn("%s: could not create statistics registers\n",
+ __func__);
+ goto fail;
+@@ -223,25 +223,22 @@ static int bcm2708_fb_check_var(struct f
+ {
+ /* info input, var output */
+ print_debug("%s(%p) %dx%d (%dx%d), %d, %d\n",
+- __func__,
+- info,
+- info->var.xres, info->var.yres, info->var.xres_virtual,
+- info->var.yres_virtual, (int)info->screen_size,
+- info->var.bits_per_pixel);
+- print_debug("%s(%p) %dx%d (%dx%d), %d\n", __func__, var,
+- var->xres, var->yres, var->xres_virtual, var->yres_virtual,
+- var->bits_per_pixel);
++ __func__, info, info->var.xres, info->var.yres,
++ info->var.xres_virtual, info->var.yres_virtual,
++ (int)info->screen_size, info->var.bits_per_pixel);
++ print_debug("%s(%p) %dx%d (%dx%d), %d\n", __func__, var, var->xres,
++ var->yres, var->xres_virtual, var->yres_virtual,
++ var->bits_per_pixel);
+
+ if (!var->bits_per_pixel)
+ var->bits_per_pixel = 16;
+
+ if (bcm2708_fb_set_bitfields(var) != 0) {
+ pr_err("%s: invalid bits_per_pixel %d\n", __func__,
+- var->bits_per_pixel);
++ var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+-
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ /* use highest possible virtual resolution */
+@@ -249,7 +246,7 @@ static int bcm2708_fb_check_var(struct f
+ var->yres_virtual = 480;
+
+ pr_err("%s: virtual resolution set to maximum of %dx%d\n",
+- __func__, var->xres_virtual, var->yres_virtual);
++ __func__, var->xres_virtual, var->yres_virtual);
+ }
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+@@ -294,9 +291,9 @@ static int bcm2708_fb_set_par(struct fb_
+ int ret;
+
+ print_debug("%s(%p) %dx%d (%dx%d), %d, %d\n", __func__, info,
+- info->var.xres, info->var.yres, info->var.xres_virtual,
+- info->var.yres_virtual, (int)info->screen_size,
+- info->var.bits_per_pixel);
++ info->var.xres, info->var.yres, info->var.xres_virtual,
++ info->var.yres_virtual, (int)info->screen_size,
++ info->var.bits_per_pixel);
+
+ ret = rpi_firmware_property_list(fb->fw, &fbinfo, sizeof(fbinfo));
+ if (ret) {
+@@ -328,12 +325,10 @@ static int bcm2708_fb_set_par(struct fb_
+ return -ENOMEM;
+ }
+
+- print_debug(
+- "%s: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d\n",
+- __func__,
+- (void *)fb->fb.screen_base, (void *)fb->fb_bus_address,
+- fbinfo.xres, fbinfo.yres, fbinfo.bpp,
+- fbinfo.pitch, (int)fb->fb.screen_size);
++ print_debug("%s: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d\n",
++ __func__, (void *)fb->fb.screen_base,
++ (void *)fb->fb_bus_address, fbinfo.xres, fbinfo.yres,
++ fbinfo.bpp, fbinfo.pitch, (int)fb->fb.screen_size);
+
+ return 0;
+ }
+@@ -345,7 +340,6 @@ static inline u32 convert_bitfield(int v
+ return (val >> (16 - bf->length) & mask) << bf->offset;
+ }
+
+-
+ static int bcm2708_fb_setcolreg(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
+@@ -379,11 +373,11 @@ static int bcm2708_fb_setcolreg(unsigned
+ packet->offset = 0;
+ packet->length = regno + 1;
+ memcpy(packet->cmap, fb->gpu_cmap,
+- sizeof(packet->cmap));
++ sizeof(packet->cmap));
+ ret = rpi_firmware_property(fb->fw,
+- RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE,
+- packet,
+- (2 + packet->length) * sizeof(u32));
++ RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE,
++ packet,
++ (2 + packet->length) * sizeof(u32));
+ if (ret || packet->offset)
+ dev_err(info->device,
+ "Failed to set palette (%d,%u)\n",
+@@ -392,9 +386,9 @@ static int bcm2708_fb_setcolreg(unsigned
+ }
+ } else if (regno < 16) {
+ fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
+- convert_bitfield(blue, &fb->fb.var.blue) |
+- convert_bitfield(green, &fb->fb.var.green) |
+- convert_bitfield(red, &fb->fb.var.red);
++ convert_bitfield(blue, &fb->fb.var.blue) |
++ convert_bitfield(green, &fb->fb.var.green) |
++ convert_bitfield(red, &fb->fb.var.red);
+ }
+ return regno > 255;
+ }
+@@ -437,8 +431,8 @@ static int bcm2708_fb_pan_display(struct
+ info->var.yoffset = var->yoffset;
+ result = bcm2708_fb_set_par(info);
+ if (result != 0)
+- pr_err("%s(%d,%d) returns=%d\n", __func__,
+- var->xoffset, var->yoffset, result);
++ pr_err("%s(%d,%d) returns=%d\n", __func__, var->xoffset,
++ var->yoffset, result);
+ return result;
+ }
+
+@@ -468,9 +462,8 @@ static void dma_memcpy(struct bcm2708_fb
+ cb->info |= BCM2708_DMA_INT_EN;
+ bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
+ while (bcm_dma_is_busy(dma_chan)) {
+- wait_event_interruptible(
+- fb->dma_waitq,
+- !bcm_dma_is_busy(dma_chan));
++ wait_event_interruptible(fb->dma_waitq,
++ !bcm_dma_is_busy(dma_chan));
+ }
+ fb->stats.dma_irqs++;
+ }
+@@ -478,9 +471,9 @@ static void dma_memcpy(struct bcm2708_fb
+ }
+
+ /* address with no aliases */
+-#define INTALIAS_NORMAL(x) ((x)&~0xc0000000)
++#define INTALIAS_NORMAL(x) ((x) & ~0xc0000000)
+ /* cache coherent but non-allocating in L1 and L2 */
+-#define INTALIAS_L1L2_NONALLOCATING(x) (((x)&~0xc0000000)|0x80000000)
++#define INTALIAS_L1L2_NONALLOCATING(x) (((x) & ~0xc0000000) | 0x80000000)
+
+ static long vc_mem_copy(struct bcm2708_fb *fb, struct fb_dmacopy *ioparam)
+ {
+@@ -498,15 +491,15 @@ static long vc_mem_copy(struct bcm2708_f
+
+ if (!fb->gpu.base || !fb->gpu.length) {
+ pr_err("[%s]: Unable to determine gpu memory (%x,%x)\n",
+- __func__, fb->gpu.base, fb->gpu.length);
++ __func__, fb->gpu.base, fb->gpu.length);
+ return -EFAULT;
+ }
+
+ if (INTALIAS_NORMAL(ioparam->src) < fb->gpu.base ||
+ INTALIAS_NORMAL(ioparam->src) >= fb->gpu.base + fb->gpu.length) {
+ pr_err("[%s]: Invalid memory access %x (%x-%x)", __func__,
+- INTALIAS_NORMAL(ioparam->src), fb->gpu.base,
+- fb->gpu.base + fb->gpu.length);
++ INTALIAS_NORMAL(ioparam->src), fb->gpu.base,
++ fb->gpu.base + fb->gpu.length);
+ return -EFAULT;
+ }
+
+@@ -528,8 +521,7 @@ static long vc_mem_copy(struct bcm2708_f
+ dma_memcpy(fb, bus_addr,
+ INTALIAS_L1L2_NONALLOCATING((dma_addr_t)p), size);
+ if (copy_to_user(q, buf, s) != 0) {
+- pr_err("[%s]: failed to copy-to-user\n",
+- __func__);
++ pr_err("[%s]: failed to copy-to-user\n", __func__);
+ rc = -EFAULT;
+ goto out;
+ }
+@@ -755,7 +747,6 @@ static void bcm2708_fb_copyarea(struct f
+ /* end of dma control blocks chain */
+ cb->next = 0;
+
+-
+ if (pixels < dma_busy_wait_threshold) {
+ bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
+ bcm_dma_wait_idle(fb->dma_chan_base);
+@@ -765,9 +756,8 @@ static void bcm2708_fb_copyarea(struct f
+ cb->info |= BCM2708_DMA_INT_EN;
+ bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
+ while (bcm_dma_is_busy(dma_chan)) {
+- wait_event_interruptible(
+- fb->dma_waitq,
+- !bcm_dma_is_busy(dma_chan));
++ wait_event_interruptible(fb->dma_waitq,
++ !bcm_dma_is_busy(dma_chan));
+ }
+ fb->stats.dma_irqs++;
+ }
+@@ -863,7 +853,7 @@ static int bcm2708_fb_register(struct bc
+ return ret;
+
+ print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n",
+- fbwidth, fbheight, fbdepth, fbswap);
++ fbwidth, fbheight, fbdepth, fbswap);
+
+ ret = register_framebuffer(&fb->fb);
+ print_debug("BCM2708FB: register framebuffer (%d)\n", ret);
+@@ -893,7 +883,7 @@ static int bcm2708_fb_probe(struct platf
+ if (!fw)
+ return -EPROBE_DEFER;
+
+- fb = kzalloc(sizeof(struct bcm2708_fb), GFP_KERNEL);
++ fb = kzalloc(sizeof(*fb), GFP_KERNEL);
+ if (!fb) {
+ ret = -ENOMEM;
+ goto free_region;
+@@ -927,7 +917,6 @@ static int bcm2708_fb_probe(struct platf
+ goto free_dma_chan;
+ }
+
+-
+ pr_info("BCM2708FB: allocated DMA channel %d\n", fb->dma_chan);
+
+ fb->dev = dev;
+@@ -936,9 +925,8 @@ static int bcm2708_fb_probe(struct platf
+ /* failure here isn't fatal, but we'll fail in vc_mem_copy if
+ * fb->gpu is not valid
+ */
+- rpi_firmware_property(fb->fw,
+- RPI_FIRMWARE_GET_VC_MEMORY,
+- &fb->gpu, sizeof(fb->gpu));
++ rpi_firmware_property(fb->fw, RPI_FIRMWARE_GET_VC_MEMORY, &fb->gpu,
++ sizeof(fb->gpu));
+
+ ret = bcm2708_fb_register(fb);
+ if (ret == 0) {
--- /dev/null
+From 4ebec374d97c0bba1e41558071bfa062894b07a0 Mon Sep 17 00:00:00 2001
+Date: Fri, 20 Jul 2018 22:03:41 +0100
+Subject: [PATCH] bcm2835-dma: Add support for per-channel flags
+
+Add the ability to interpret the high bits of the dreq specifier as
+flags to be included in the DMA_CS register. The motivation for this
+change is the ability to set the DISDEBUG flag for SD card transfers
+to avoid corruption when using the VPU debugger.
+
+---
+ drivers/dma/bcm2835-dma.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -146,6 +146,10 @@ struct bcm2835_desc {
+ #define BCM2835_DMA_S_DREQ BIT(10) /* enable SREQ for source */
+ #define BCM2835_DMA_S_IGNORE BIT(11) /* ignore source reads - read 0 */
+ #define BCM2835_DMA_BURST_LENGTH(x) ((x & 15) << 12)
++#define BCM2835_DMA_CS_FLAGS(x) (x & (BCM2835_DMA_PRIORITY(15) | \
++ BCM2835_DMA_PANIC_PRIORITY(15) | \
++ BCM2835_DMA_WAIT_FOR_WRITES | \
++ BCM2835_DMA_DIS_DEBUG))
+ #define BCM2835_DMA_PER_MAP(x) ((x & 31) << 16) /* REQ source */
+ #define BCM2835_DMA_WAIT(x) ((x & 31) << 21) /* add DMA-wait cycles */
+ #define BCM2835_DMA_NO_WIDE_BURSTS BIT(26) /* no 2 beat write bursts */
+@@ -461,7 +465,8 @@ static void bcm2835_dma_start_desc(struc
+ c->desc = d = to_bcm2835_dma_desc(&vd->tx);
+
+ writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
+- writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
++ writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
++ c->chan_base + BCM2835_DMA_CS);
+ }
+
+ static irqreturn_t bcm2835_dma_callback(int irq, void *data)
+@@ -488,7 +493,8 @@ static irqreturn_t bcm2835_dma_callback(
+ * if this IRQ handler is threaded.) If the channel is finished, it
+ * will remain idle despite the ACTIVE flag being set.
+ */
+- writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE,
++ writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE |
++ BCM2835_DMA_CS_FLAGS(c->dreq),
+ c->chan_base + BCM2835_DMA_CS);
+
+ d = c->desc;
+++ /dev/null
-From ca128febc6abc040d747ddc0808fd203c135668e Mon Sep 17 00:00:00 2001
-Date: Fri, 25 Jan 2019 17:11:39 +0000
-Subject: [PATCH] video: bcm2708_fb: Fix warnings on 64 bit builds
-
-Fix up logging lines where the wrong format specifiers were
-being used.
-
----
- drivers/video/fbdev/bcm2708_fb.c | 10 ++++------
- 1 file changed, 4 insertions(+), 6 deletions(-)
-
---- a/drivers/video/fbdev/bcm2708_fb.c
-+++ b/drivers/video/fbdev/bcm2708_fb.c
-@@ -513,8 +513,8 @@ static long vc_mem_copy(struct bcm2708_f
- buf = dma_alloc_coherent(fb->fb.device, PAGE_ALIGN(size), &bus_addr,
- GFP_ATOMIC);
- if (!buf) {
-- pr_err("[%s]: failed to dma_alloc_coherent(%d)\n",
-- __func__, size);
-+ pr_err("[%s]: failed to dma_alloc_coherent(%zd)\n", __func__,
-+ size);
- rc = -ENOMEM;
- goto out;
- }
-@@ -910,8 +910,7 @@ static int bcm2708_fb_probe(struct platf
- goto free_fb;
- }
-
-- pr_info("BCM2708FB: allocated DMA memory %08x\n",
-- fb->cb_handle);
-+ pr_info("BCM2708FB: allocated DMA memory %pad\n", &fb->cb_handle);
-
- ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK,
- &fb->dma_chan_base, &fb->dma_irq);
-@@ -929,8 +928,7 @@ static int bcm2708_fb_probe(struct platf
- }
-
-
-- pr_info("BCM2708FB: allocated DMA channel %d @ %p\n",
-- fb->dma_chan, fb->dma_chan_base);
-+ pr_info("BCM2708FB: allocated DMA channel %d\n", fb->dma_chan);
-
- fb->dev = dev;
- fb->fb.device = &dev->dev;
--- /dev/null
+From 18a739ba2e76a5e2bb3a02d9083faeabdee93777 Mon Sep 17 00:00:00 2001
+Date: Fri, 20 Jul 2018 22:08:05 +0100
+Subject: [PATCH] bcm283x: Set the DISDEBUG flag for SD transfers
+
+---
+ arch/arm/boot/dts/bcm283x.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -400,7 +400,7 @@
+ reg = <0x7e202000 0x100>;
+ interrupts = <2 24>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+- dmas = <&dma 13>;
++ dmas = <&dma (13|(1<<29))>;
+ dma-names = "rx-tx";
+ status = "disabled";
+ };
+++ /dev/null
-From 47f7687efaf3873fe8c0e47653515e9ada1b86da Mon Sep 17 00:00:00 2001
-Date: Fri, 25 Jan 2019 17:32:54 +0000
-Subject: [PATCH] video: bcm2708_fb: Clean up coding style issues
-
-Now checkpatch clean except for 2 long lines, missing
-SPDX header, and no DT documentation.
-
----
- drivers/video/fbdev/bcm2708_fb.c | 96 ++++++++++++++------------------
- 1 file changed, 42 insertions(+), 54 deletions(-)
-
---- a/drivers/video/fbdev/bcm2708_fb.c
-+++ b/drivers/video/fbdev/bcm2708_fb.c
-@@ -41,7 +41,7 @@
- #define MODULE_NAME "bcm2708_fb"
-
- #ifdef BCM2708_FB_DEBUG
--#define print_debug(fmt, ...) pr_debug("%s:%s:%d: "fmt, \
-+#define print_debug(fmt, ...) pr_debug("%s:%s:%d: " fmt, \
- MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
- #else
- #define print_debug(fmt, ...)
-@@ -57,7 +57,7 @@ static int fbheight = 480; /* module par
- static int fbdepth = 32; /* module parameter */
- static int fbswap; /* module parameter */
-
--static u32 dma_busy_wait_threshold = 1<<15;
-+static u32 dma_busy_wait_threshold = 1 << 15;
- module_param(dma_busy_wait_threshold, int, 0644);
- MODULE_PARM_DESC(dma_busy_wait_threshold, "Busy-wait for DMA completion below this area");
-
-@@ -132,8 +132,8 @@ static int bcm2708_fb_debugfs_init(struc
- fb->stats.regset.nregs = ARRAY_SIZE(stats_registers);
- fb->stats.regset.base = &fb->stats;
-
-- if (!debugfs_create_regset32(
-- "stats", 0444, fb->debugfs_dir, &fb->stats.regset)) {
-+ if (!debugfs_create_regset32("stats", 0444, fb->debugfs_dir,
-+ &fb->stats.regset)) {
- pr_warn("%s: could not create statistics registers\n",
- __func__);
- goto fail;
-@@ -223,25 +223,22 @@ static int bcm2708_fb_check_var(struct f
- {
- /* info input, var output */
- print_debug("%s(%p) %dx%d (%dx%d), %d, %d\n",
-- __func__,
-- info,
-- info->var.xres, info->var.yres, info->var.xres_virtual,
-- info->var.yres_virtual, (int)info->screen_size,
-- info->var.bits_per_pixel);
-- print_debug("%s(%p) %dx%d (%dx%d), %d\n", __func__, var,
-- var->xres, var->yres, var->xres_virtual, var->yres_virtual,
-- var->bits_per_pixel);
-+ __func__, info, info->var.xres, info->var.yres,
-+ info->var.xres_virtual, info->var.yres_virtual,
-+ (int)info->screen_size, info->var.bits_per_pixel);
-+ print_debug("%s(%p) %dx%d (%dx%d), %d\n", __func__, var, var->xres,
-+ var->yres, var->xres_virtual, var->yres_virtual,
-+ var->bits_per_pixel);
-
- if (!var->bits_per_pixel)
- var->bits_per_pixel = 16;
-
- if (bcm2708_fb_set_bitfields(var) != 0) {
- pr_err("%s: invalid bits_per_pixel %d\n", __func__,
-- var->bits_per_pixel);
-+ var->bits_per_pixel);
- return -EINVAL;
- }
-
--
- if (var->xres_virtual < var->xres)
- var->xres_virtual = var->xres;
- /* use highest possible virtual resolution */
-@@ -249,7 +246,7 @@ static int bcm2708_fb_check_var(struct f
- var->yres_virtual = 480;
-
- pr_err("%s: virtual resolution set to maximum of %dx%d\n",
-- __func__, var->xres_virtual, var->yres_virtual);
-+ __func__, var->xres_virtual, var->yres_virtual);
- }
- if (var->yres_virtual < var->yres)
- var->yres_virtual = var->yres;
-@@ -294,9 +291,9 @@ static int bcm2708_fb_set_par(struct fb_
- int ret;
-
- print_debug("%s(%p) %dx%d (%dx%d), %d, %d\n", __func__, info,
-- info->var.xres, info->var.yres, info->var.xres_virtual,
-- info->var.yres_virtual, (int)info->screen_size,
-- info->var.bits_per_pixel);
-+ info->var.xres, info->var.yres, info->var.xres_virtual,
-+ info->var.yres_virtual, (int)info->screen_size,
-+ info->var.bits_per_pixel);
-
- ret = rpi_firmware_property_list(fb->fw, &fbinfo, sizeof(fbinfo));
- if (ret) {
-@@ -328,12 +325,10 @@ static int bcm2708_fb_set_par(struct fb_
- return -ENOMEM;
- }
-
-- print_debug(
-- "%s: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d\n",
-- __func__,
-- (void *)fb->fb.screen_base, (void *)fb->fb_bus_address,
-- fbinfo.xres, fbinfo.yres, fbinfo.bpp,
-- fbinfo.pitch, (int)fb->fb.screen_size);
-+ print_debug("%s: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d\n",
-+ __func__, (void *)fb->fb.screen_base,
-+ (void *)fb->fb_bus_address, fbinfo.xres, fbinfo.yres,
-+ fbinfo.bpp, fbinfo.pitch, (int)fb->fb.screen_size);
-
- return 0;
- }
-@@ -345,7 +340,6 @@ static inline u32 convert_bitfield(int v
- return (val >> (16 - bf->length) & mask) << bf->offset;
- }
-
--
- static int bcm2708_fb_setcolreg(unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- unsigned int transp, struct fb_info *info)
-@@ -379,11 +373,11 @@ static int bcm2708_fb_setcolreg(unsigned
- packet->offset = 0;
- packet->length = regno + 1;
- memcpy(packet->cmap, fb->gpu_cmap,
-- sizeof(packet->cmap));
-+ sizeof(packet->cmap));
- ret = rpi_firmware_property(fb->fw,
-- RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE,
-- packet,
-- (2 + packet->length) * sizeof(u32));
-+ RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE,
-+ packet,
-+ (2 + packet->length) * sizeof(u32));
- if (ret || packet->offset)
- dev_err(info->device,
- "Failed to set palette (%d,%u)\n",
-@@ -392,9 +386,9 @@ static int bcm2708_fb_setcolreg(unsigned
- }
- } else if (regno < 16) {
- fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
-- convert_bitfield(blue, &fb->fb.var.blue) |
-- convert_bitfield(green, &fb->fb.var.green) |
-- convert_bitfield(red, &fb->fb.var.red);
-+ convert_bitfield(blue, &fb->fb.var.blue) |
-+ convert_bitfield(green, &fb->fb.var.green) |
-+ convert_bitfield(red, &fb->fb.var.red);
- }
- return regno > 255;
- }
-@@ -437,8 +431,8 @@ static int bcm2708_fb_pan_display(struct
- info->var.yoffset = var->yoffset;
- result = bcm2708_fb_set_par(info);
- if (result != 0)
-- pr_err("%s(%d,%d) returns=%d\n", __func__,
-- var->xoffset, var->yoffset, result);
-+ pr_err("%s(%d,%d) returns=%d\n", __func__, var->xoffset,
-+ var->yoffset, result);
- return result;
- }
-
-@@ -468,9 +462,8 @@ static void dma_memcpy(struct bcm2708_fb
- cb->info |= BCM2708_DMA_INT_EN;
- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
- while (bcm_dma_is_busy(dma_chan)) {
-- wait_event_interruptible(
-- fb->dma_waitq,
-- !bcm_dma_is_busy(dma_chan));
-+ wait_event_interruptible(fb->dma_waitq,
-+ !bcm_dma_is_busy(dma_chan));
- }
- fb->stats.dma_irqs++;
- }
-@@ -478,9 +471,9 @@ static void dma_memcpy(struct bcm2708_fb
- }
-
- /* address with no aliases */
--#define INTALIAS_NORMAL(x) ((x)&~0xc0000000)
-+#define INTALIAS_NORMAL(x) ((x) & ~0xc0000000)
- /* cache coherent but non-allocating in L1 and L2 */
--#define INTALIAS_L1L2_NONALLOCATING(x) (((x)&~0xc0000000)|0x80000000)
-+#define INTALIAS_L1L2_NONALLOCATING(x) (((x) & ~0xc0000000) | 0x80000000)
-
- static long vc_mem_copy(struct bcm2708_fb *fb, struct fb_dmacopy *ioparam)
- {
-@@ -498,15 +491,15 @@ static long vc_mem_copy(struct bcm2708_f
-
- if (!fb->gpu.base || !fb->gpu.length) {
- pr_err("[%s]: Unable to determine gpu memory (%x,%x)\n",
-- __func__, fb->gpu.base, fb->gpu.length);
-+ __func__, fb->gpu.base, fb->gpu.length);
- return -EFAULT;
- }
-
- if (INTALIAS_NORMAL(ioparam->src) < fb->gpu.base ||
- INTALIAS_NORMAL(ioparam->src) >= fb->gpu.base + fb->gpu.length) {
- pr_err("[%s]: Invalid memory access %x (%x-%x)", __func__,
-- INTALIAS_NORMAL(ioparam->src), fb->gpu.base,
-- fb->gpu.base + fb->gpu.length);
-+ INTALIAS_NORMAL(ioparam->src), fb->gpu.base,
-+ fb->gpu.base + fb->gpu.length);
- return -EFAULT;
- }
-
-@@ -528,8 +521,7 @@ static long vc_mem_copy(struct bcm2708_f
- dma_memcpy(fb, bus_addr,
- INTALIAS_L1L2_NONALLOCATING((dma_addr_t)p), size);
- if (copy_to_user(q, buf, s) != 0) {
-- pr_err("[%s]: failed to copy-to-user\n",
-- __func__);
-+ pr_err("[%s]: failed to copy-to-user\n", __func__);
- rc = -EFAULT;
- goto out;
- }
-@@ -755,7 +747,6 @@ static void bcm2708_fb_copyarea(struct f
- /* end of dma control blocks chain */
- cb->next = 0;
-
--
- if (pixels < dma_busy_wait_threshold) {
- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
- bcm_dma_wait_idle(fb->dma_chan_base);
-@@ -765,9 +756,8 @@ static void bcm2708_fb_copyarea(struct f
- cb->info |= BCM2708_DMA_INT_EN;
- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
- while (bcm_dma_is_busy(dma_chan)) {
-- wait_event_interruptible(
-- fb->dma_waitq,
-- !bcm_dma_is_busy(dma_chan));
-+ wait_event_interruptible(fb->dma_waitq,
-+ !bcm_dma_is_busy(dma_chan));
- }
- fb->stats.dma_irqs++;
- }
-@@ -863,7 +853,7 @@ static int bcm2708_fb_register(struct bc
- return ret;
-
- print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n",
-- fbwidth, fbheight, fbdepth, fbswap);
-+ fbwidth, fbheight, fbdepth, fbswap);
-
- ret = register_framebuffer(&fb->fb);
- print_debug("BCM2708FB: register framebuffer (%d)\n", ret);
-@@ -893,7 +883,7 @@ static int bcm2708_fb_probe(struct platf
- if (!fw)
- return -EPROBE_DEFER;
-
-- fb = kzalloc(sizeof(struct bcm2708_fb), GFP_KERNEL);
-+ fb = kzalloc(sizeof(*fb), GFP_KERNEL);
- if (!fb) {
- ret = -ENOMEM;
- goto free_region;
-@@ -927,7 +917,6 @@ static int bcm2708_fb_probe(struct platf
- goto free_dma_chan;
- }
-
--
- pr_info("BCM2708FB: allocated DMA channel %d\n", fb->dma_chan);
-
- fb->dev = dev;
-@@ -936,9 +925,8 @@ static int bcm2708_fb_probe(struct platf
- /* failure here isn't fatal, but we'll fail in vc_mem_copy if
- * fb->gpu is not valid
- */
-- rpi_firmware_property(fb->fw,
-- RPI_FIRMWARE_GET_VC_MEMORY,
-- &fb->gpu, sizeof(fb->gpu));
-+ rpi_firmware_property(fb->fw, RPI_FIRMWARE_GET_VC_MEMORY, &fb->gpu,
-+ sizeof(fb->gpu));
-
- ret = bcm2708_fb_register(fb);
- if (ret == 0) {
--- /dev/null
+From 4a15efde52bb79bf44e63b998cd84f896404d728 Mon Sep 17 00:00:00 2001
+Date: Sat, 24 Nov 2018 22:05:42 +0200
+Subject: [PATCH] ASoC: pcm512x: Implement the digital_mute interface
+
+[ Upstream commit 3500f1c589e92e0b6b1f8d31b4084fbde08d49cb ]
+
+Clicks and pops of various volumes can be produced while the device is
+opened, closed, put into and taken out of standby, or reconfigured.
+Fix this, by implementing the digital_mute interface, so that the
+output is muted during such operations.
+
+---
+ sound/soc/codecs/pcm512x.c | 121 ++++++++++++++++++++++++++++++++++++-
+ sound/soc/codecs/pcm512x.h | 2 +
+ 2 files changed, 121 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/codecs/pcm512x.c
++++ b/sound/soc/codecs/pcm512x.c
+@@ -53,6 +53,8 @@ struct pcm512x_priv {
+ unsigned long overclock_pll;
+ unsigned long overclock_dac;
+ unsigned long overclock_dsp;
++ int mute;
++ struct mutex mutex;
+ int lrclk_div;
+ };
+
+@@ -385,6 +387,61 @@ static const struct soc_enum pcm512x_ved
+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4,
+ pcm512x_ramp_step_text);
+
++static int pcm512x_update_mute(struct pcm512x_priv *pcm512x)
++{
++ return regmap_update_bits(
++ pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR,
++ (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT)
++ | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT));
++}
++
++static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
++
++ mutex_lock(&pcm512x->mutex);
++ ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4);
++ ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2);
++ mutex_unlock(&pcm512x->mutex);
++
++ return 0;
++}
++
++static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
++ int ret, changed = 0;
++
++ mutex_lock(&pcm512x->mutex);
++
++ if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) {
++ pcm512x->mute ^= 0x4;
++ changed = 1;
++ }
++ if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) {
++ pcm512x->mute ^= 0x2;
++ changed = 1;
++ }
++
++ if (changed) {
++ ret = pcm512x_update_mute(pcm512x);
++ if (ret != 0) {
++ dev_err(component->dev,
++ "Failed to update digital mute: %d\n", ret);
++ mutex_unlock(&pcm512x->mutex);
++ return ret;
++ }
++ }
++
++ mutex_unlock(&pcm512x->mutex);
++
++ return changed;
++}
++
+ static const struct snd_kcontrol_new pcm512x_controls[] = {
+ SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
+ PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+@@ -392,8 +449,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume
+ PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
+ SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
+ PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
+-SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
+- PCM512x_RQMR_SHIFT, 1, 1),
++{
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Digital Playback Switch",
++ .index = 0,
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++ .info = snd_ctl_boolean_stereo_info,
++ .get = pcm512x_digital_playback_switch_get,
++ .put = pcm512x_digital_playback_switch_put
++},
+
+ SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
+ SOC_ENUM("DSP Program", pcm512x_dsp_program),
+@@ -1323,6 +1387,56 @@ static int pcm512x_set_fmt(struct snd_so
+ return 0;
+ }
+
++static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
++{
++ struct snd_soc_component *component = dai->component;
++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
++ int ret;
++ unsigned int mute_det;
++
++ mutex_lock(&pcm512x->mutex);
++
++ if (mute) {
++ pcm512x->mute |= 0x1;
++ ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE,
++ PCM512x_RQML | PCM512x_RQMR,
++ PCM512x_RQML | PCM512x_RQMR);
++ if (ret != 0) {
++ dev_err(component->dev,
++ "Failed to set digital mute: %d\n", ret);
++ mutex_unlock(&pcm512x->mutex);
++ return ret;
++ }
++
++ regmap_read_poll_timeout(pcm512x->regmap,
++ PCM512x_ANALOG_MUTE_DET,
++ mute_det, (mute_det & 0x3) == 0,
++ 200, 10000);
++
++ mutex_unlock(&pcm512x->mutex);
++ } else {
++ pcm512x->mute &= ~0x1;
++ ret = pcm512x_update_mute(pcm512x);
++ if (ret != 0) {
++ dev_err(component->dev,
++ "Failed to update digital mute: %d\n", ret);
++ mutex_unlock(&pcm512x->mutex);
++ return ret;
++ }
++
++ regmap_read_poll_timeout(pcm512x->regmap,
++ PCM512x_ANALOG_MUTE_DET,
++ mute_det,
++ (mute_det & 0x3)
++ == ((~pcm512x->mute >> 1) & 0x3),
++ 200, 10000);
++ }
++
++ mutex_unlock(&pcm512x->mutex);
++
++ return 0;
++}
++
+ static int pcm512x_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int width)
+@@ -1348,6 +1462,7 @@ static const struct snd_soc_dai_ops pcm5
+ .startup = pcm512x_dai_startup,
+ .hw_params = pcm512x_hw_params,
+ .set_fmt = pcm512x_set_fmt,
++ .digital_mute = pcm512x_digital_mute,
+ .set_tdm_slot = pcm512x_set_tdm_slot,
+ };
+
+@@ -1414,6 +1529,8 @@ int pcm512x_probe(struct device *dev, st
+ if (!pcm512x)
+ return -ENOMEM;
+
++ mutex_init(&pcm512x->mutex);
++
+ dev_set_drvdata(dev, pcm512x);
+ pcm512x->regmap = regmap;
+
+--- a/sound/soc/codecs/pcm512x.h
++++ b/sound/soc/codecs/pcm512x.h
+@@ -112,7 +112,9 @@
+ #define PCM512x_RQST_SHIFT 4
+
+ /* Page 0, Register 3 - mute */
++#define PCM512x_RQMR (1 << 0)
+ #define PCM512x_RQMR_SHIFT 0
++#define PCM512x_RQML (1 << 4)
+ #define PCM512x_RQML_SHIFT 4
+
+ /* Page 0, Register 4 - PLL */
+++ /dev/null
-From 4ebec374d97c0bba1e41558071bfa062894b07a0 Mon Sep 17 00:00:00 2001
-Date: Fri, 20 Jul 2018 22:03:41 +0100
-Subject: [PATCH] bcm2835-dma: Add support for per-channel flags
-
-Add the ability to interpret the high bits of the dreq specifier as
-flags to be included in the DMA_CS register. The motivation for this
-change is the ability to set the DISDEBUG flag for SD card transfers
-to avoid corruption when using the VPU debugger.
-
----
- drivers/dma/bcm2835-dma.c | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
---- a/drivers/dma/bcm2835-dma.c
-+++ b/drivers/dma/bcm2835-dma.c
-@@ -146,6 +146,10 @@ struct bcm2835_desc {
- #define BCM2835_DMA_S_DREQ BIT(10) /* enable SREQ for source */
- #define BCM2835_DMA_S_IGNORE BIT(11) /* ignore source reads - read 0 */
- #define BCM2835_DMA_BURST_LENGTH(x) ((x & 15) << 12)
-+#define BCM2835_DMA_CS_FLAGS(x) (x & (BCM2835_DMA_PRIORITY(15) | \
-+ BCM2835_DMA_PANIC_PRIORITY(15) | \
-+ BCM2835_DMA_WAIT_FOR_WRITES | \
-+ BCM2835_DMA_DIS_DEBUG))
- #define BCM2835_DMA_PER_MAP(x) ((x & 31) << 16) /* REQ source */
- #define BCM2835_DMA_WAIT(x) ((x & 31) << 21) /* add DMA-wait cycles */
- #define BCM2835_DMA_NO_WIDE_BURSTS BIT(26) /* no 2 beat write bursts */
-@@ -461,7 +465,8 @@ static void bcm2835_dma_start_desc(struc
- c->desc = d = to_bcm2835_dma_desc(&vd->tx);
-
- writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
-- writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
-+ writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
-+ c->chan_base + BCM2835_DMA_CS);
- }
-
- static irqreturn_t bcm2835_dma_callback(int irq, void *data)
-@@ -488,7 +493,8 @@ static irqreturn_t bcm2835_dma_callback(
- * if this IRQ handler is threaded.) If the channel is finished, it
- * will remain idle despite the ACTIVE flag being set.
- */
-- writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE,
-+ writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE |
-+ BCM2835_DMA_CS_FLAGS(c->dreq),
- c->chan_base + BCM2835_DMA_CS);
-
- d = c->desc;
--- /dev/null
+From 26001d54a7f803258b161f25f457ce11523695d7 Mon Sep 17 00:00:00 2001
+Date: Fri, 21 Dec 2018 12:11:20 +0300
+Subject: [PATCH] ASoC: pcm512x: Fix a double unlock in
+ pcm512x_digital_mute()
+
+[ Upstream commit 28b698b7342c7d5300cfe217cd77ff7d2a55e03d ]
+
+We accidentally call mutex_unlock(&pcm512x->mutex); twice in a row.
+
+I re-wrote the error handling to use "goto unlock;" instead of returning
+directly. Hopefully, it makes the code a little simpler.
+
+Fixes: 3500f1c589e9 ("ASoC: pcm512x: Implement the digital_mute interface")
+---
+ sound/soc/codecs/pcm512x.c | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+--- a/sound/soc/codecs/pcm512x.c
++++ b/sound/soc/codecs/pcm512x.c
+@@ -1404,24 +1404,20 @@ static int pcm512x_digital_mute(struct s
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to set digital mute: %d\n", ret);
+- mutex_unlock(&pcm512x->mutex);
+- return ret;
++ goto unlock;
+ }
+
+ regmap_read_poll_timeout(pcm512x->regmap,
+ PCM512x_ANALOG_MUTE_DET,
+ mute_det, (mute_det & 0x3) == 0,
+ 200, 10000);
+-
+- mutex_unlock(&pcm512x->mutex);
+ } else {
+ pcm512x->mute &= ~0x1;
+ ret = pcm512x_update_mute(pcm512x);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to update digital mute: %d\n", ret);
+- mutex_unlock(&pcm512x->mutex);
+- return ret;
++ goto unlock;
+ }
+
+ regmap_read_poll_timeout(pcm512x->regmap,
+@@ -1432,9 +1428,10 @@ static int pcm512x_digital_mute(struct s
+ 200, 10000);
+ }
+
++unlock:
+ mutex_unlock(&pcm512x->mutex);
+
+- return 0;
++ return ret;
+ }
+
+ static int pcm512x_set_tdm_slot(struct snd_soc_dai *dai,
+++ /dev/null
-From 18a739ba2e76a5e2bb3a02d9083faeabdee93777 Mon Sep 17 00:00:00 2001
-Date: Fri, 20 Jul 2018 22:08:05 +0100
-Subject: [PATCH] bcm283x: Set the DISDEBUG flag for SD transfers
-
----
- arch/arm/boot/dts/bcm283x.dtsi | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -400,7 +400,7 @@
- reg = <0x7e202000 0x100>;
- interrupts = <2 24>;
- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- dmas = <&dma 13>;
-+ dmas = <&dma (13|(1<<29))>;
- dma-names = "rx-tx";
- status = "disabled";
- };
+++ /dev/null
-From 4a15efde52bb79bf44e63b998cd84f896404d728 Mon Sep 17 00:00:00 2001
-Date: Sat, 24 Nov 2018 22:05:42 +0200
-Subject: [PATCH] ASoC: pcm512x: Implement the digital_mute interface
-
-[ Upstream commit 3500f1c589e92e0b6b1f8d31b4084fbde08d49cb ]
-
-Clicks and pops of various volumes can be produced while the device is
-opened, closed, put into and taken out of standby, or reconfigured.
-Fix this, by implementing the digital_mute interface, so that the
-output is muted during such operations.
-
----
- sound/soc/codecs/pcm512x.c | 121 ++++++++++++++++++++++++++++++++++++-
- sound/soc/codecs/pcm512x.h | 2 +
- 2 files changed, 121 insertions(+), 2 deletions(-)
-
---- a/sound/soc/codecs/pcm512x.c
-+++ b/sound/soc/codecs/pcm512x.c
-@@ -53,6 +53,8 @@ struct pcm512x_priv {
- unsigned long overclock_pll;
- unsigned long overclock_dac;
- unsigned long overclock_dsp;
-+ int mute;
-+ struct mutex mutex;
- int lrclk_div;
- };
-
-@@ -385,6 +387,61 @@ static const struct soc_enum pcm512x_ved
- SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4,
- pcm512x_ramp_step_text);
-
-+static int pcm512x_update_mute(struct pcm512x_priv *pcm512x)
-+{
-+ return regmap_update_bits(
-+ pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR,
-+ (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT)
-+ | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT));
-+}
-+
-+static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
-+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
-+
-+ mutex_lock(&pcm512x->mutex);
-+ ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4);
-+ ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2);
-+ mutex_unlock(&pcm512x->mutex);
-+
-+ return 0;
-+}
-+
-+static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
-+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
-+ int ret, changed = 0;
-+
-+ mutex_lock(&pcm512x->mutex);
-+
-+ if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) {
-+ pcm512x->mute ^= 0x4;
-+ changed = 1;
-+ }
-+ if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) {
-+ pcm512x->mute ^= 0x2;
-+ changed = 1;
-+ }
-+
-+ if (changed) {
-+ ret = pcm512x_update_mute(pcm512x);
-+ if (ret != 0) {
-+ dev_err(component->dev,
-+ "Failed to update digital mute: %d\n", ret);
-+ mutex_unlock(&pcm512x->mutex);
-+ return ret;
-+ }
-+ }
-+
-+ mutex_unlock(&pcm512x->mutex);
-+
-+ return changed;
-+}
-+
- static const struct snd_kcontrol_new pcm512x_controls[] = {
- SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
- PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
-@@ -392,8 +449,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume
- PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
- SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
- PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
--SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
-- PCM512x_RQMR_SHIFT, 1, 1),
-+{
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .name = "Digital Playback Switch",
-+ .index = 0,
-+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+ .info = snd_ctl_boolean_stereo_info,
-+ .get = pcm512x_digital_playback_switch_get,
-+ .put = pcm512x_digital_playback_switch_put
-+},
-
- SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
- SOC_ENUM("DSP Program", pcm512x_dsp_program),
-@@ -1323,6 +1387,56 @@ static int pcm512x_set_fmt(struct snd_so
- return 0;
- }
-
-+static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
-+{
-+ struct snd_soc_component *component = dai->component;
-+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
-+ int ret;
-+ unsigned int mute_det;
-+
-+ mutex_lock(&pcm512x->mutex);
-+
-+ if (mute) {
-+ pcm512x->mute |= 0x1;
-+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE,
-+ PCM512x_RQML | PCM512x_RQMR,
-+ PCM512x_RQML | PCM512x_RQMR);
-+ if (ret != 0) {
-+ dev_err(component->dev,
-+ "Failed to set digital mute: %d\n", ret);
-+ mutex_unlock(&pcm512x->mutex);
-+ return ret;
-+ }
-+
-+ regmap_read_poll_timeout(pcm512x->regmap,
-+ PCM512x_ANALOG_MUTE_DET,
-+ mute_det, (mute_det & 0x3) == 0,
-+ 200, 10000);
-+
-+ mutex_unlock(&pcm512x->mutex);
-+ } else {
-+ pcm512x->mute &= ~0x1;
-+ ret = pcm512x_update_mute(pcm512x);
-+ if (ret != 0) {
-+ dev_err(component->dev,
-+ "Failed to update digital mute: %d\n", ret);
-+ mutex_unlock(&pcm512x->mutex);
-+ return ret;
-+ }
-+
-+ regmap_read_poll_timeout(pcm512x->regmap,
-+ PCM512x_ANALOG_MUTE_DET,
-+ mute_det,
-+ (mute_det & 0x3)
-+ == ((~pcm512x->mute >> 1) & 0x3),
-+ 200, 10000);
-+ }
-+
-+ mutex_unlock(&pcm512x->mutex);
-+
-+ return 0;
-+}
-+
- static int pcm512x_set_tdm_slot(struct snd_soc_dai *dai,
- unsigned int tx_mask, unsigned int rx_mask,
- int slots, int width)
-@@ -1348,6 +1462,7 @@ static const struct snd_soc_dai_ops pcm5
- .startup = pcm512x_dai_startup,
- .hw_params = pcm512x_hw_params,
- .set_fmt = pcm512x_set_fmt,
-+ .digital_mute = pcm512x_digital_mute,
- .set_tdm_slot = pcm512x_set_tdm_slot,
- };
-
-@@ -1414,6 +1529,8 @@ int pcm512x_probe(struct device *dev, st
- if (!pcm512x)
- return -ENOMEM;
-
-+ mutex_init(&pcm512x->mutex);
-+
- dev_set_drvdata(dev, pcm512x);
- pcm512x->regmap = regmap;
-
---- a/sound/soc/codecs/pcm512x.h
-+++ b/sound/soc/codecs/pcm512x.h
-@@ -112,7 +112,9 @@
- #define PCM512x_RQST_SHIFT 4
-
- /* Page 0, Register 3 - mute */
-+#define PCM512x_RQMR (1 << 0)
- #define PCM512x_RQMR_SHIFT 0
-+#define PCM512x_RQML (1 << 4)
- #define PCM512x_RQML_SHIFT 4
-
- /* Page 0, Register 4 - PLL */
--- /dev/null
+From d2536830d8f1ef06afdc84c5ac6e1a70b3a2bc40 Mon Sep 17 00:00:00 2001
+Date: Fri, 25 Jan 2019 16:03:31 +0000
+Subject: [PATCH] usb: dwc_otg: Clean up build warnings on 64bit
+ kernels
+
+No functional changes. Almost all are changes to logging lines.
+
+---
+ drivers/usb/host/dwc_otg/dwc_otg_driver.c | 3 +--
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 2 +-
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 19 ++++++++++++++-----
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 10 ++++------
+ 4 files changed, 20 insertions(+), 14 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
+@@ -837,8 +837,7 @@ static int dwc_otg_driver_probe(
+ retval = -ENOMEM;
+ goto fail;
+ }
+- dev_info(&_dev->dev, "base=0x%08x\n",
+- (unsigned)dwc_otg_device->os_dep.base);
++ dev_info(&_dev->dev, "base=%p\n", dwc_otg_device->os_dep.base);
+ #endif
+
+ /*
+--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
+@@ -301,7 +301,7 @@ static int notrace fiq_iso_out_advance(s
+ last = 1;
+
+ /* New DMA address - address of bounce buffer referred to in index */
+- hcdma.d32 = (uint32_t) &blob->channel[n].index[i].buf[0];
++ hcdma.d32 = (dma_addr_t) blob->channel[n].index[i].buf;
+ //hcdma.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HC_DMA);
+ //hcdma.d32 += st->channel[n].dma_info.slot_len[i];
+ fiq_print(FIQDBG_INT, st, "LAST: %01d ", last);
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+@@ -1041,8 +1041,8 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd
+ * moderately readable array casts.
+ */
+ hcd->fiq_dmab = DWC_DMA_ALLOC(dev, (sizeof(struct fiq_dma_channel) * num_channels), &hcd->fiq_state->dma_base);
+- DWC_WARN("FIQ DMA bounce buffers: virt = 0x%08x dma = 0x%08x len=%d",
+- (unsigned int)hcd->fiq_dmab, (unsigned int)hcd->fiq_state->dma_base,
++ DWC_WARN("FIQ DMA bounce buffers: virt = %px dma = %pad len=%zu",
++ hcd->fiq_dmab, &hcd->fiq_state->dma_base,
+ sizeof(struct fiq_dma_channel) * num_channels);
+
+ DWC_MEMSET(hcd->fiq_dmab, 0x6b, 9024);
+@@ -1522,9 +1522,12 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
+ /*
+ * Set dma_regs to bounce buffer. FIQ will update the
+ * state depending on transaction progress.
++ * Pointer arithmetic on hcd->fiq_state->dma_base (a dma_addr_t)
++ * to point it to the correct offset in the allocated buffers.
+ */
+ blob = (struct fiq_dma_blob *) hcd->fiq_state->dma_base;
+- st->hcdma_copy.d32 = (uint32_t) &blob->channel[hc->hc_num].index[0].buf[0];
++ st->hcdma_copy.d32 = (dma_addr_t) blob->channel[hc->hc_num].index[0].buf;
++
+ /* Calculate the max number of CSPLITS such that the FIQ can time out
+ * a transaction if it fails.
+ */
+@@ -1571,9 +1574,15 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
+ st->nrpackets = i;
+ }
+ ptr = qtd->urb->buf + frame_desc->offset;
+- /* Point the HC at the DMA address of the bounce buffers */
++ /*
++ * Point the HC at the DMA address of the bounce buffers
++ *
++ * Pointer arithmetic on hcd->fiq_state->dma_base (a
++ * dma_addr_t) to point it to the correct offset in the
++ * allocated buffers.
++ */
+ blob = (struct fiq_dma_blob *) hcd->fiq_state->dma_base;
+- st->hcdma_copy.d32 = (uint32_t) &blob->channel[hc->hc_num].index[0].buf[0];
++ st->hcdma_copy.d32 = (dma_addr_t) blob->channel[hc->hc_num].index[0].buf;
+
+ /* fixup xfersize to the actual packet size */
+ st->hctsiz_copy.b.pid = 0;
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
+@@ -454,11 +454,9 @@ static void hcd_init_fiq(void *cookie)
+ DWC_ERROR("Can't claim FIQ");
+ BUG();
+ }
+- DWC_WARN("FIQ on core %d at 0x%08x",
+- smp_processor_id(),
+- (fiq_fsm_enable ? (int)&dwc_otg_fiq_fsm : (int)&dwc_otg_fiq_nop));
+- DWC_WARN("FIQ ASM at 0x%08x length %d", (int)&_dwc_otg_fiq_stub, (int)(&_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub));
+- set_fiq_handler((void *) &_dwc_otg_fiq_stub, &_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub);
++ DWC_WARN("FIQ on core %d", smp_processor_id());
++ DWC_WARN("FIQ ASM at %px length %d", &_dwc_otg_fiq_stub, (int)(&_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub));
++ set_fiq_handler((void *) &_dwc_otg_fiq_stub, &_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub);
+ memset(®s,0,sizeof(regs));
+
+ regs.ARM_r8 = (long) dwc_otg_hcd->fiq_state;
+@@ -483,7 +481,7 @@ static void hcd_init_fiq(void *cookie)
+ dwc_otg_hcd->fiq_state->mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c;
+ dwc_otg_hcd->fiq_state->mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50;
+ dwc_otg_hcd->fiq_state->dwc_regs_base = otg_dev->os_dep.base;
+- DWC_WARN("MPHI regs_base at 0x%08x", (int)dwc_otg_hcd->fiq_state->mphi_regs.base);
++ DWC_WARN("MPHI regs_base at %px", dwc_otg_hcd->fiq_state->mphi_regs.base);
+ //Enable mphi peripheral
+ writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl);
+ #ifdef DEBUG
+++ /dev/null
-From 26001d54a7f803258b161f25f457ce11523695d7 Mon Sep 17 00:00:00 2001
-Date: Fri, 21 Dec 2018 12:11:20 +0300
-Subject: [PATCH] ASoC: pcm512x: Fix a double unlock in
- pcm512x_digital_mute()
-
-[ Upstream commit 28b698b7342c7d5300cfe217cd77ff7d2a55e03d ]
-
-We accidentally call mutex_unlock(&pcm512x->mutex); twice in a row.
-
-I re-wrote the error handling to use "goto unlock;" instead of returning
-directly. Hopefully, it makes the code a little simpler.
-
-Fixes: 3500f1c589e9 ("ASoC: pcm512x: Implement the digital_mute interface")
----
- sound/soc/codecs/pcm512x.c | 11 ++++-------
- 1 file changed, 4 insertions(+), 7 deletions(-)
-
---- a/sound/soc/codecs/pcm512x.c
-+++ b/sound/soc/codecs/pcm512x.c
-@@ -1404,24 +1404,20 @@ static int pcm512x_digital_mute(struct s
- if (ret != 0) {
- dev_err(component->dev,
- "Failed to set digital mute: %d\n", ret);
-- mutex_unlock(&pcm512x->mutex);
-- return ret;
-+ goto unlock;
- }
-
- regmap_read_poll_timeout(pcm512x->regmap,
- PCM512x_ANALOG_MUTE_DET,
- mute_det, (mute_det & 0x3) == 0,
- 200, 10000);
--
-- mutex_unlock(&pcm512x->mutex);
- } else {
- pcm512x->mute &= ~0x1;
- ret = pcm512x_update_mute(pcm512x);
- if (ret != 0) {
- dev_err(component->dev,
- "Failed to update digital mute: %d\n", ret);
-- mutex_unlock(&pcm512x->mutex);
-- return ret;
-+ goto unlock;
- }
-
- regmap_read_poll_timeout(pcm512x->regmap,
-@@ -1432,9 +1428,10 @@ static int pcm512x_digital_mute(struct s
- 200, 10000);
- }
-
-+unlock:
- mutex_unlock(&pcm512x->mutex);
-
-- return 0;
-+ return ret;
- }
-
- static int pcm512x_set_tdm_slot(struct snd_soc_dai *dai,
--- /dev/null
+From f0d93c5098283f88ea1de3af152a190177da8f36 Mon Sep 17 00:00:00 2001
+Date: Wed, 30 Jan 2019 17:47:51 +0000
+Subject: [PATCH] usb: dwc_otg: Use dma allocation for mphi dummy_send
+ buffer
+
+The FIQ driver used a kzalloc'ed buffer for dummy_send,
+passing a kernel virtual address to the hardware block.
+The buffer is only ever used for a dummy read, so it
+should be harmless, but there is the chance that it will
+cause exceptions.
+
+Use a dma allocation so that we have a genuine bus address,
+and read from that.
+Free the allocation when done for good measure.
+
+---
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 4 ++--
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 1 +
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 5 ++++-
+ 3 files changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
+@@ -1347,7 +1347,7 @@ void notrace dwc_otg_fiq_fsm(struct fiq_
+ /* We got an interrupt, didn't handle it. */
+ if (kick_irq) {
+ state->mphi_int_count++;
+- FIQ_WRITE(state->mphi_regs.outdda, (int) state->dummy_send);
++ FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
+ FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
+
+ }
+@@ -1408,7 +1408,7 @@ void notrace dwc_otg_fiq_nop(struct fiq_
+ FIQ_WRITE(state->dwc_regs_base + GINTMSK, gintmsk.d32);
+ /* Force a clear before another dummy send */
+ FIQ_WRITE(state->mphi_regs.intstat, (1<<29));
+- FIQ_WRITE(state->mphi_regs.outdda, (int) state->dummy_send);
++ FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
+ FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
+
+ }
+--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
+@@ -352,6 +352,7 @@ struct fiq_state {
+ dma_addr_t dma_base;
+ struct fiq_dma_blob *fiq_dmab;
+ void *dummy_send;
++ dma_addr_t dummy_send_dma;
+ gintmsk_data_t gintmsk_saved;
+ haintmsk_data_t haintmsk_saved;
+ int mphi_int_count;
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+@@ -929,6 +929,8 @@ static void dwc_otg_hcd_free(dwc_otg_hcd
+ DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
+ DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
+ DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet);
++ DWC_DMA_FREE(dev, 16, dwc_otg_hcd->fiq_state->dummy_send,
++ dwc_otg_hcd->fiq_state->dummy_send_dma);
+ DWC_FREE(dwc_otg_hcd->fiq_state);
+
+ #ifdef DWC_DEV_SRPCAP
+@@ -1021,7 +1023,8 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd
+ for (i = 0; i < num_channels; i++) {
+ hcd->fiq_state->channel[i].fsm = FIQ_PASSTHROUGH;
+ }
+- hcd->fiq_state->dummy_send = DWC_ALLOC_ATOMIC(16);
++ hcd->fiq_state->dummy_send = DWC_DMA_ALLOC_ATOMIC(dev, 16,
++ &hcd->fiq_state->dummy_send_dma);
+
+ hcd->fiq_stack = DWC_ALLOC(sizeof(struct fiq_stack));
+ if (!hcd->fiq_stack) {
--- /dev/null
+From f03f60a51efdf7fbc1f7d2c5b120a7de93ea6d9e Mon Sep 17 00:00:00 2001
+Date: Tue, 29 Jan 2019 16:13:25 +0000
+Subject: [PATCH] staging: vchiq_arm: Set up dma ranges on child
+ devices
+
+The VCHIQ driver now loads the audio, camera, codec, and vc-sm
+drivers as platform drivers. However they were not being given
+the correct DMA configuration.
+
+Call of_dma_configure with the parent (VCHIQ) parameters to be
+inherited by the child.
+
+---
+ .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -3585,6 +3585,7 @@ static struct platform_device *
+ vchiq_register_child(struct platform_device *pdev, const char *name)
+ {
+ struct platform_device_info pdevinfo;
++ struct platform_device *new_dev;
+
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+
+@@ -3593,7 +3594,17 @@ vchiq_register_child(struct platform_dev
+ pdevinfo.id = PLATFORM_DEVID_NONE;
+ pdevinfo.dma_mask = DMA_BIT_MASK(32);
+
+- return platform_device_register_full(&pdevinfo);
++ new_dev = platform_device_register_full(&pdevinfo);
++ if (!new_dev)
++ return NULL;
++
++ /*
++ * We want the dma-ranges etc to be copied from the parent VCHIQ device
++ * to be passed on to the children too.
++ */
++ of_dma_configure(&new_dev->dev, pdev->dev.of_node, true);
++
++ return new_dev;
+ }
+
+ static int vchiq_probe(struct platform_device *pdev)
+++ /dev/null
-From d2536830d8f1ef06afdc84c5ac6e1a70b3a2bc40 Mon Sep 17 00:00:00 2001
-Date: Fri, 25 Jan 2019 16:03:31 +0000
-Subject: [PATCH] usb: dwc_otg: Clean up build warnings on 64bit
- kernels
-
-No functional changes. Almost all are changes to logging lines.
-
----
- drivers/usb/host/dwc_otg/dwc_otg_driver.c | 3 +--
- drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 2 +-
- drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 19 ++++++++++++++-----
- drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 10 ++++------
- 4 files changed, 20 insertions(+), 14 deletions(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
-@@ -837,8 +837,7 @@ static int dwc_otg_driver_probe(
- retval = -ENOMEM;
- goto fail;
- }
-- dev_info(&_dev->dev, "base=0x%08x\n",
-- (unsigned)dwc_otg_device->os_dep.base);
-+ dev_info(&_dev->dev, "base=%p\n", dwc_otg_device->os_dep.base);
- #endif
-
- /*
---- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
-@@ -301,7 +301,7 @@ static int notrace fiq_iso_out_advance(s
- last = 1;
-
- /* New DMA address - address of bounce buffer referred to in index */
-- hcdma.d32 = (uint32_t) &blob->channel[n].index[i].buf[0];
-+ hcdma.d32 = (dma_addr_t) blob->channel[n].index[i].buf;
- //hcdma.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HC_DMA);
- //hcdma.d32 += st->channel[n].dma_info.slot_len[i];
- fiq_print(FIQDBG_INT, st, "LAST: %01d ", last);
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-@@ -1041,8 +1041,8 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd
- * moderately readable array casts.
- */
- hcd->fiq_dmab = DWC_DMA_ALLOC(dev, (sizeof(struct fiq_dma_channel) * num_channels), &hcd->fiq_state->dma_base);
-- DWC_WARN("FIQ DMA bounce buffers: virt = 0x%08x dma = 0x%08x len=%d",
-- (unsigned int)hcd->fiq_dmab, (unsigned int)hcd->fiq_state->dma_base,
-+ DWC_WARN("FIQ DMA bounce buffers: virt = %px dma = %pad len=%zu",
-+ hcd->fiq_dmab, &hcd->fiq_state->dma_base,
- sizeof(struct fiq_dma_channel) * num_channels);
-
- DWC_MEMSET(hcd->fiq_dmab, 0x6b, 9024);
-@@ -1522,9 +1522,12 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
- /*
- * Set dma_regs to bounce buffer. FIQ will update the
- * state depending on transaction progress.
-+ * Pointer arithmetic on hcd->fiq_state->dma_base (a dma_addr_t)
-+ * to point it to the correct offset in the allocated buffers.
- */
- blob = (struct fiq_dma_blob *) hcd->fiq_state->dma_base;
-- st->hcdma_copy.d32 = (uint32_t) &blob->channel[hc->hc_num].index[0].buf[0];
-+ st->hcdma_copy.d32 = (dma_addr_t) blob->channel[hc->hc_num].index[0].buf;
-+
- /* Calculate the max number of CSPLITS such that the FIQ can time out
- * a transaction if it fails.
- */
-@@ -1571,9 +1574,15 @@ int fiq_fsm_setup_periodic_dma(dwc_otg_h
- st->nrpackets = i;
- }
- ptr = qtd->urb->buf + frame_desc->offset;
-- /* Point the HC at the DMA address of the bounce buffers */
-+ /*
-+ * Point the HC at the DMA address of the bounce buffers
-+ *
-+ * Pointer arithmetic on hcd->fiq_state->dma_base (a
-+ * dma_addr_t) to point it to the correct offset in the
-+ * allocated buffers.
-+ */
- blob = (struct fiq_dma_blob *) hcd->fiq_state->dma_base;
-- st->hcdma_copy.d32 = (uint32_t) &blob->channel[hc->hc_num].index[0].buf[0];
-+ st->hcdma_copy.d32 = (dma_addr_t) blob->channel[hc->hc_num].index[0].buf;
-
- /* fixup xfersize to the actual packet size */
- st->hctsiz_copy.b.pid = 0;
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-@@ -454,11 +454,9 @@ static void hcd_init_fiq(void *cookie)
- DWC_ERROR("Can't claim FIQ");
- BUG();
- }
-- DWC_WARN("FIQ on core %d at 0x%08x",
-- smp_processor_id(),
-- (fiq_fsm_enable ? (int)&dwc_otg_fiq_fsm : (int)&dwc_otg_fiq_nop));
-- DWC_WARN("FIQ ASM at 0x%08x length %d", (int)&_dwc_otg_fiq_stub, (int)(&_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub));
-- set_fiq_handler((void *) &_dwc_otg_fiq_stub, &_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub);
-+ DWC_WARN("FIQ on core %d", smp_processor_id());
-+ DWC_WARN("FIQ ASM at %px length %d", &_dwc_otg_fiq_stub, (int)(&_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub));
-+ set_fiq_handler((void *) &_dwc_otg_fiq_stub, &_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub);
- memset(®s,0,sizeof(regs));
-
- regs.ARM_r8 = (long) dwc_otg_hcd->fiq_state;
-@@ -483,7 +481,7 @@ static void hcd_init_fiq(void *cookie)
- dwc_otg_hcd->fiq_state->mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c;
- dwc_otg_hcd->fiq_state->mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50;
- dwc_otg_hcd->fiq_state->dwc_regs_base = otg_dev->os_dep.base;
-- DWC_WARN("MPHI regs_base at 0x%08x", (int)dwc_otg_hcd->fiq_state->mphi_regs.base);
-+ DWC_WARN("MPHI regs_base at %px", dwc_otg_hcd->fiq_state->mphi_regs.base);
- //Enable mphi peripheral
- writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl);
- #ifdef DEBUG
--- /dev/null
+From ea000a969afa022776bdf8050aaa501b2679e028 Mon Sep 17 00:00:00 2001
+Date: Tue, 29 Jan 2019 16:24:41 +0000
+Subject: [PATCH] staging: vc-sm-cma: Correct DMA configuration.
+
+Now that VCHIQ is setting up the DMA configuration as our
+parent device, don't try to configure it during probe.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 15 +++++----------
+ 1 file changed, 5 insertions(+), 10 deletions(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -703,9 +703,6 @@ err_free_mem:
+ /* Driver loading. */
+ static int bcm2835_vc_sm_cma_probe(struct platform_device *pdev)
+ {
+- struct device *dev = &pdev->dev;
+- int err;
+-
+ pr_info("%s: Videocore shared memory driver\n", __func__);
+
+ sm_state = kzalloc(sizeof(*sm_state), GFP_KERNEL);
+@@ -714,13 +711,11 @@ static int bcm2835_vc_sm_cma_probe(struc
+ sm_state->pdev = pdev;
+ mutex_init(&sm_state->map_lock);
+
+- dev->coherent_dma_mask = DMA_BIT_MASK(32);
+- dev->dma_mask = &dev->coherent_dma_mask;
+- err = of_dma_configure(dev, NULL, true);
+- if (err) {
+- dev_err(dev, "Unable to setup DMA: %d\n", err);
+- return err;
+- }
++ pdev->dev.dma_parms = devm_kzalloc(&pdev->dev,
++ sizeof(*pdev->dev.dma_parms),
++ GFP_KERNEL);
++ /* dma_set_max_seg_size checks if dma_parms is NULL. */
++ dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF);
+
+ vchiq_add_connected_callback(vc_sm_connected_init);
+ return 0;
+++ /dev/null
-From f0d93c5098283f88ea1de3af152a190177da8f36 Mon Sep 17 00:00:00 2001
-Date: Wed, 30 Jan 2019 17:47:51 +0000
-Subject: [PATCH] usb: dwc_otg: Use dma allocation for mphi dummy_send
- buffer
-
-The FIQ driver used a kzalloc'ed buffer for dummy_send,
-passing a kernel virtual address to the hardware block.
-The buffer is only ever used for a dummy read, so it
-should be harmless, but there is the chance that it will
-cause exceptions.
-
-Use a dma allocation so that we have a genuine bus address,
-and read from that.
-Free the allocation when done for good measure.
-
----
- drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 4 ++--
- drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 1 +
- drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 5 ++++-
- 3 files changed, 7 insertions(+), 3 deletions(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
-@@ -1347,7 +1347,7 @@ void notrace dwc_otg_fiq_fsm(struct fiq_
- /* We got an interrupt, didn't handle it. */
- if (kick_irq) {
- state->mphi_int_count++;
-- FIQ_WRITE(state->mphi_regs.outdda, (int) state->dummy_send);
-+ FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
- FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
-
- }
-@@ -1408,7 +1408,7 @@ void notrace dwc_otg_fiq_nop(struct fiq_
- FIQ_WRITE(state->dwc_regs_base + GINTMSK, gintmsk.d32);
- /* Force a clear before another dummy send */
- FIQ_WRITE(state->mphi_regs.intstat, (1<<29));
-- FIQ_WRITE(state->mphi_regs.outdda, (int) state->dummy_send);
-+ FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
- FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
-
- }
---- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
-@@ -352,6 +352,7 @@ struct fiq_state {
- dma_addr_t dma_base;
- struct fiq_dma_blob *fiq_dmab;
- void *dummy_send;
-+ dma_addr_t dummy_send_dma;
- gintmsk_data_t gintmsk_saved;
- haintmsk_data_t haintmsk_saved;
- int mphi_int_count;
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-@@ -929,6 +929,8 @@ static void dwc_otg_hcd_free(dwc_otg_hcd
- DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
- DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
- DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet);
-+ DWC_DMA_FREE(dev, 16, dwc_otg_hcd->fiq_state->dummy_send,
-+ dwc_otg_hcd->fiq_state->dummy_send_dma);
- DWC_FREE(dwc_otg_hcd->fiq_state);
-
- #ifdef DWC_DEV_SRPCAP
-@@ -1021,7 +1023,8 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd
- for (i = 0; i < num_channels; i++) {
- hcd->fiq_state->channel[i].fsm = FIQ_PASSTHROUGH;
- }
-- hcd->fiq_state->dummy_send = DWC_ALLOC_ATOMIC(16);
-+ hcd->fiq_state->dummy_send = DWC_DMA_ALLOC_ATOMIC(dev, 16,
-+ &hcd->fiq_state->dummy_send_dma);
-
- hcd->fiq_stack = DWC_ALLOC(sizeof(struct fiq_stack));
- if (!hcd->fiq_stack) {
--- /dev/null
+From df84621e5bd5cc206d1039ce0880ccd0b325525b Mon Sep 17 00:00:00 2001
+Date: Tue, 29 Jan 2019 16:29:00 +0000
+Subject: [PATCH] staging: vc-sm-cma: Use a void* pointer as the handle
+ within the kernel
+
+The driver was using an unsigned int as the handle to the outside world,
+and doing a nasty cast to the struct dmabuf when handed it back.
+This breaks badly with a 64 bit kernel where the pointer doesn't fit
+in an unsigned int.
+
+Switch to using a void* within the kernel. Reality is that it is
+a struct dma_buf*, but advertising it as such to other drivers seems
+to encourage the use of it as such, and I'm not sure on the implications
+of that.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 10 +++++-----
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h | 6 +++---
+ drivers/staging/vc04_services/vchiq-mmal/mmal-common.h | 2 +-
+ drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 2 +-
+ 4 files changed, 10 insertions(+), 10 deletions(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -745,7 +745,7 @@ static int bcm2835_vc_sm_cma_remove(stru
+ }
+
+ /* Get an internal resource handle mapped from the external one. */
+-int vc_sm_cma_int_handle(int handle)
++int vc_sm_cma_int_handle(void *handle)
+ {
+ struct dma_buf *dma_buf = (struct dma_buf *)handle;
+ struct vc_sm_buffer *res;
+@@ -762,7 +762,7 @@ int vc_sm_cma_int_handle(int handle)
+ EXPORT_SYMBOL_GPL(vc_sm_cma_int_handle);
+
+ /* Free a previously allocated shared memory handle and block. */
+-int vc_sm_cma_free(int handle)
++int vc_sm_cma_free(void *handle)
+ {
+ struct dma_buf *dma_buf = (struct dma_buf *)handle;
+
+@@ -772,7 +772,7 @@ int vc_sm_cma_free(int handle)
+ return -EPERM;
+ }
+
+- pr_debug("%s: handle %08x/dmabuf %p\n", __func__, handle, dma_buf);
++ pr_debug("%s: handle %p/dmabuf %p\n", __func__, handle, dma_buf);
+
+ dma_buf_put(dma_buf);
+
+@@ -781,7 +781,7 @@ int vc_sm_cma_free(int handle)
+ EXPORT_SYMBOL_GPL(vc_sm_cma_free);
+
+ /* Import a dmabuf to be shared with VC. */
+-int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, int *handle)
++int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, void **handle)
+ {
+ struct dma_buf *new_dma_buf;
+ struct vc_sm_buffer *res;
+@@ -801,7 +801,7 @@ int vc_sm_cma_import_dmabuf(struct dma_b
+ res = (struct vc_sm_buffer *)new_dma_buf->priv;
+
+ /* Assign valid handle at this time.*/
+- *handle = (int)new_dma_buf;
++ *handle = new_dma_buf;
+ } else {
+ /*
+ * succeeded in importing the dma_buf, but then
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h
+@@ -17,12 +17,12 @@
+ #endif
+
+ /* Free a previously allocated or imported shared memory handle and block. */
+-int vc_sm_cma_free(int handle);
++int vc_sm_cma_free(void *handle);
+
+ /* Get an internal resource handle mapped from the external one. */
+-int vc_sm_cma_int_handle(int handle);
++int vc_sm_cma_int_handle(void *handle);
+
+ /* Import a block of memory into the GPU space. */
+-int vc_sm_cma_import_dmabuf(struct dma_buf *dmabuf, int *handle);
++int vc_sm_cma_import_dmabuf(struct dma_buf *dmabuf, void **handle);
+
+ #endif /* __VC_SM_KNL_H__INCLUDED__ */
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
+@@ -52,7 +52,7 @@ struct mmal_buffer {
+ struct mmal_msg_context *msg_context;
+
+ struct dma_buf *dma_buf;/* Exported dmabuf fd from videobuf2 */
+- int vcsm_handle; /* VCSM handle having imported the dmabuf */
++ void *vcsm_handle; /* VCSM handle having imported the dmabuf */
+ u32 vc_handle; /* VC handle to that dmabuf */
+
+ u32 cmd; /* MMAL command. 0=data. */
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -1794,7 +1794,7 @@ int mmal_vchi_buffer_cleanup(struct mmal
+ if (buf->vcsm_handle) {
+ int ret;
+
+- pr_debug("%s: vc_sm_cma_free on handle %08X\n", __func__,
++ pr_debug("%s: vc_sm_cma_free on handle %p\n", __func__,
+ buf->vcsm_handle);
+ ret = vc_sm_cma_free(buf->vcsm_handle);
+ if (ret)
+++ /dev/null
-From f03f60a51efdf7fbc1f7d2c5b120a7de93ea6d9e Mon Sep 17 00:00:00 2001
-Date: Tue, 29 Jan 2019 16:13:25 +0000
-Subject: [PATCH] staging: vchiq_arm: Set up dma ranges on child
- devices
-
-The VCHIQ driver now loads the audio, camera, codec, and vc-sm
-drivers as platform drivers. However they were not being given
-the correct DMA configuration.
-
-Call of_dma_configure with the parent (VCHIQ) parameters to be
-inherited by the child.
-
----
- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 13 ++++++++++++-
- 1 file changed, 12 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -3585,6 +3585,7 @@ static struct platform_device *
- vchiq_register_child(struct platform_device *pdev, const char *name)
- {
- struct platform_device_info pdevinfo;
-+ struct platform_device *new_dev;
-
- memset(&pdevinfo, 0, sizeof(pdevinfo));
-
-@@ -3593,7 +3594,17 @@ vchiq_register_child(struct platform_dev
- pdevinfo.id = PLATFORM_DEVID_NONE;
- pdevinfo.dma_mask = DMA_BIT_MASK(32);
-
-- return platform_device_register_full(&pdevinfo);
-+ new_dev = platform_device_register_full(&pdevinfo);
-+ if (!new_dev)
-+ return NULL;
-+
-+ /*
-+ * We want the dma-ranges etc to be copied from the parent VCHIQ device
-+ * to be passed on to the children too.
-+ */
-+ of_dma_configure(&new_dev->dev, pdev->dev.of_node, true);
-+
-+ return new_dev;
- }
-
- static int vchiq_probe(struct platform_device *pdev)
+++ /dev/null
-From ea000a969afa022776bdf8050aaa501b2679e028 Mon Sep 17 00:00:00 2001
-Date: Tue, 29 Jan 2019 16:24:41 +0000
-Subject: [PATCH] staging: vc-sm-cma: Correct DMA configuration.
-
-Now that VCHIQ is setting up the DMA configuration as our
-parent device, don't try to configure it during probe.
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 15 +++++----------
- 1 file changed, 5 insertions(+), 10 deletions(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -703,9 +703,6 @@ err_free_mem:
- /* Driver loading. */
- static int bcm2835_vc_sm_cma_probe(struct platform_device *pdev)
- {
-- struct device *dev = &pdev->dev;
-- int err;
--
- pr_info("%s: Videocore shared memory driver\n", __func__);
-
- sm_state = kzalloc(sizeof(*sm_state), GFP_KERNEL);
-@@ -714,13 +711,11 @@ static int bcm2835_vc_sm_cma_probe(struc
- sm_state->pdev = pdev;
- mutex_init(&sm_state->map_lock);
-
-- dev->coherent_dma_mask = DMA_BIT_MASK(32);
-- dev->dma_mask = &dev->coherent_dma_mask;
-- err = of_dma_configure(dev, NULL, true);
-- if (err) {
-- dev_err(dev, "Unable to setup DMA: %d\n", err);
-- return err;
-- }
-+ pdev->dev.dma_parms = devm_kzalloc(&pdev->dev,
-+ sizeof(*pdev->dev.dma_parms),
-+ GFP_KERNEL);
-+ /* dma_set_max_seg_size checks if dma_parms is NULL. */
-+ dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF);
-
- vchiq_add_connected_callback(vc_sm_connected_init);
- return 0;
--- /dev/null
+From 696aa66a971b20e4f00431cb53747f0e4b92bb03 Mon Sep 17 00:00:00 2001
+Date: Tue, 29 Jan 2019 16:32:57 +0000
+Subject: [PATCH] staging: vc-sm-cma: Fix up for 64bit builds
+
+There were a number of logging lines that were using
+inappropriate formatting under 64bit kernels.
+
+The kernel_id field passed to/from the VPU was being
+abused for storing the struct vc_sm_buffer *.
+This breaks with 64bit kernels, so change to using an IDR.
+
+---
+ .../staging/vc04_services/vc-sm-cma/vc_sm.c | 60 +++++++++++++++----
+ .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 3 +-
+ 2 files changed, 48 insertions(+), 15 deletions(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -75,6 +75,9 @@ struct sm_state_t {
+ struct miscdevice dev;
+ struct sm_instance *sm_handle; /* Handle for videocore service. */
+
++ spinlock_t kernelid_map_lock; /* Spinlock protecting kernelid_map */
++ struct idr kernelid_map;
++
+ struct mutex map_lock; /* Global map lock. */
+ struct list_head buffer_list; /* List of buffer. */
+
+@@ -97,6 +100,29 @@ static int sm_inited;
+
+ /* ---- Private Functions ------------------------------------------------ */
+
++static int get_kernel_id(struct vc_sm_buffer *buffer)
++{
++ int handle;
++
++ spin_lock(&sm_state->kernelid_map_lock);
++ handle = idr_alloc(&sm_state->kernelid_map, buffer, 0, 0, GFP_KERNEL);
++ spin_unlock(&sm_state->kernelid_map_lock);
++
++ return handle;
++}
++
++static struct vc_sm_buffer *lookup_kernel_id(int handle)
++{
++ return idr_find(&sm_state->kernelid_map, handle);
++}
++
++static void free_kernel_id(int handle)
++{
++ spin_lock(&sm_state->kernelid_map_lock);
++ idr_remove(&sm_state->kernelid_map, handle);
++ spin_unlock(&sm_state->kernelid_map_lock);
++}
++
+ static int vc_sm_cma_seq_file_show(struct seq_file *s, void *v)
+ {
+ struct sm_pde_t *sm_pde;
+@@ -129,8 +155,7 @@ static int vc_sm_cma_global_state_show(s
+ if (!sm_state)
+ return 0;
+
+- seq_printf(s, "\nVC-ServiceHandle 0x%x\n",
+- (unsigned int)sm_state->sm_handle);
++ seq_printf(s, "\nVC-ServiceHandle %p\n", sm_state->sm_handle);
+
+ /* Log all applicable mapping(s). */
+
+@@ -145,7 +170,7 @@ static int vc_sm_cma_global_state_show(s
+ resource);
+ seq_printf(s, " NAME %s\n",
+ resource->name);
+- seq_printf(s, " SIZE %d\n",
++ seq_printf(s, " SIZE %zu\n",
+ resource->size);
+ seq_printf(s, " DMABUF %p\n",
+ resource->dma_buf);
+@@ -181,7 +206,7 @@ static void vc_sm_add_resource(struct vc
+ list_add(&buffer->global_buffer_list, &sm_state->buffer_list);
+ mutex_unlock(&sm_state->map_lock);
+
+- pr_debug("[%s]: added buffer %p (name %s, size %d)\n",
++ pr_debug("[%s]: added buffer %p (name %s, size %zu)\n",
+ __func__, buffer, buffer->name, buffer->size);
+ }
+
+@@ -194,7 +219,7 @@ static void vc_sm_release_resource(struc
+ mutex_lock(&sm_state->map_lock);
+ mutex_lock(&buffer->lock);
+
+- pr_debug("[%s]: buffer %p (name %s, size %d)\n",
++ pr_debug("[%s]: buffer %p (name %s, size %zu)\n",
+ __func__, buffer, buffer->name, buffer->size);
+
+ if (buffer->vc_handle && buffer->vpu_state == VPU_MAPPED) {
+@@ -443,6 +468,7 @@ vc_sm_cma_import_dmabuf_internal(struct
+ struct vc_sm_import_result result = { };
+ struct dma_buf_attachment *attach = NULL;
+ struct sg_table *sgt = NULL;
++ dma_addr_t dma_addr;
+ int ret = 0;
+ int status;
+
+@@ -478,21 +504,22 @@ vc_sm_cma_import_dmabuf_internal(struct
+ }
+
+ import.type = VC_SM_ALLOC_NON_CACHED;
+- import.addr = (uint32_t)sg_dma_address(sgt->sgl);
++ dma_addr = sg_dma_address(sgt->sgl);
++ import.addr = (uint32_t)dma_addr;
+ if ((import.addr & 0xC0000000) != 0xC0000000) {
+- pr_err("%s: Expecting an uncached alias for dma_addr %08x\n",
+- __func__, import.addr);
++ pr_err("%s: Expecting an uncached alias for dma_addr %pad\n",
++ __func__, &dma_addr);
+ import.addr |= 0xC0000000;
+ }
+ import.size = sg_dma_len(sgt->sgl);
+ import.allocator = current->tgid;
+- import.kernel_id = (uint32_t)buffer; //FIXME: 64 bit support needed.
++ import.kernel_id = get_kernel_id(buffer);
+
+ memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT,
+ sizeof(VC_SM_RESOURCE_NAME_DEFAULT));
+
+- pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %p, size %u\n",
+- __func__, import.name, import.type, (void *)import.addr,
++ pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %pad, size %u\n",
++ __func__, import.name, import.type, &dma_addr,
+ import.size);
+
+ /* Allocate the videocore buffer. */
+@@ -527,7 +554,7 @@ vc_sm_cma_import_dmabuf_internal(struct
+
+ buffer->attach = attach;
+ buffer->sgt = sgt;
+- buffer->dma_addr = sg_dma_address(sgt->sgl);
++ buffer->dma_addr = dma_addr;
+ buffer->in_use = 1;
+
+ /*
+@@ -559,6 +586,7 @@ error:
+ vc_sm_cma_vchi_free(sm_state->sm_handle, &free,
+ &sm_state->int_trans_id);
+ }
++ free_kernel_id(import.kernel_id);
+ kfree(buffer);
+ if (sgt)
+ dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+@@ -586,7 +614,7 @@ vc_sm_vpu_event(struct sm_instance *inst
+ {
+ struct vc_sm_released *release = (struct vc_sm_released *)reply;
+ struct vc_sm_buffer *buffer =
+- (struct vc_sm_buffer *)release->kernel_id;
++ lookup_kernel_id(release->kernel_id);
+
+ /*
+ * FIXME: Need to check buffer is still valid and allocated
+@@ -599,6 +627,7 @@ vc_sm_vpu_event(struct sm_instance *inst
+ buffer->vc_handle = 0;
+ buffer->vpu_state = VPU_NOT_MAPPED;
+ mutex_unlock(&buffer->lock);
++ free_kernel_id(release->kernel_id);
+
+ vc_sm_release_resource(buffer, 0);
+ }
+@@ -711,6 +740,9 @@ static int bcm2835_vc_sm_cma_probe(struc
+ sm_state->pdev = pdev;
+ mutex_init(&sm_state->map_lock);
+
++ spin_lock_init(&sm_state->kernelid_map_lock);
++ idr_init_base(&sm_state->kernelid_map, 1);
++
+ pdev->dev.dma_parms = devm_kzalloc(&pdev->dev,
+ sizeof(*pdev->dev.dma_parms),
+ GFP_KERNEL);
+@@ -735,6 +767,8 @@ static int bcm2835_vc_sm_cma_remove(stru
+ /* Stop the videocore shared memory service. */
+ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
+
++ idr_destroy(&sm_state->kernelid_map);
++
+ /* Free the memory for the state structure. */
+ mutex_destroy(&sm_state->map_lock);
+ kfree(sm_state);
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
+@@ -356,8 +356,7 @@ struct sm_instance *vc_sm_cma_vchi_init(
+ set_user_nice(instance->io_thread, -10);
+ wake_up_process(instance->io_thread);
+
+- pr_debug("%s: success - instance 0x%x", __func__,
+- (unsigned int)instance);
++ pr_debug("%s: success - instance %p", __func__, instance);
+ return instance;
+
+ err_close_services:
--- /dev/null
+From 3ffbec3df726c6d36ef728d476cb3ff3fcc17c81 Mon Sep 17 00:00:00 2001
+Date: Thu, 7 Feb 2019 18:16:25 +0000
+Subject: [PATCH] configs: Enable the AD193x codecs
+
+See: https://github.com/raspberrypi/linux/issues/2850
+
+---
+ sound/soc/codecs/Kconfig | 4 ++--
+ 4 files changed, 8 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -295,11 +295,11 @@ config SND_SOC_AD193X
+ tristate
+
+ config SND_SOC_AD193X_SPI
+- tristate
++ tristate "Analog Devices AU193X CODEC - SPI"
+ select SND_SOC_AD193X
+
+ config SND_SOC_AD193X_I2C
+- tristate
++ tristate "Analog Devices AU193X CODEC - I2C"
+ select SND_SOC_AD193X
+
+ config SND_SOC_AD1980
+++ /dev/null
-From df84621e5bd5cc206d1039ce0880ccd0b325525b Mon Sep 17 00:00:00 2001
-Date: Tue, 29 Jan 2019 16:29:00 +0000
-Subject: [PATCH] staging: vc-sm-cma: Use a void* pointer as the handle
- within the kernel
-
-The driver was using an unsigned int as the handle to the outside world,
-and doing a nasty cast to the struct dmabuf when handed it back.
-This breaks badly with a 64 bit kernel where the pointer doesn't fit
-in an unsigned int.
-
-Switch to using a void* within the kernel. Reality is that it is
-a struct dma_buf*, but advertising it as such to other drivers seems
-to encourage the use of it as such, and I'm not sure on the implications
-of that.
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 10 +++++-----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h | 6 +++---
- drivers/staging/vc04_services/vchiq-mmal/mmal-common.h | 2 +-
- drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 2 +-
- 4 files changed, 10 insertions(+), 10 deletions(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -745,7 +745,7 @@ static int bcm2835_vc_sm_cma_remove(stru
- }
-
- /* Get an internal resource handle mapped from the external one. */
--int vc_sm_cma_int_handle(int handle)
-+int vc_sm_cma_int_handle(void *handle)
- {
- struct dma_buf *dma_buf = (struct dma_buf *)handle;
- struct vc_sm_buffer *res;
-@@ -762,7 +762,7 @@ int vc_sm_cma_int_handle(int handle)
- EXPORT_SYMBOL_GPL(vc_sm_cma_int_handle);
-
- /* Free a previously allocated shared memory handle and block. */
--int vc_sm_cma_free(int handle)
-+int vc_sm_cma_free(void *handle)
- {
- struct dma_buf *dma_buf = (struct dma_buf *)handle;
-
-@@ -772,7 +772,7 @@ int vc_sm_cma_free(int handle)
- return -EPERM;
- }
-
-- pr_debug("%s: handle %08x/dmabuf %p\n", __func__, handle, dma_buf);
-+ pr_debug("%s: handle %p/dmabuf %p\n", __func__, handle, dma_buf);
-
- dma_buf_put(dma_buf);
-
-@@ -781,7 +781,7 @@ int vc_sm_cma_free(int handle)
- EXPORT_SYMBOL_GPL(vc_sm_cma_free);
-
- /* Import a dmabuf to be shared with VC. */
--int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, int *handle)
-+int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, void **handle)
- {
- struct dma_buf *new_dma_buf;
- struct vc_sm_buffer *res;
-@@ -801,7 +801,7 @@ int vc_sm_cma_import_dmabuf(struct dma_b
- res = (struct vc_sm_buffer *)new_dma_buf->priv;
-
- /* Assign valid handle at this time.*/
-- *handle = (int)new_dma_buf;
-+ *handle = new_dma_buf;
- } else {
- /*
- * succeeded in importing the dma_buf, but then
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h
-@@ -17,12 +17,12 @@
- #endif
-
- /* Free a previously allocated or imported shared memory handle and block. */
--int vc_sm_cma_free(int handle);
-+int vc_sm_cma_free(void *handle);
-
- /* Get an internal resource handle mapped from the external one. */
--int vc_sm_cma_int_handle(int handle);
-+int vc_sm_cma_int_handle(void *handle);
-
- /* Import a block of memory into the GPU space. */
--int vc_sm_cma_import_dmabuf(struct dma_buf *dmabuf, int *handle);
-+int vc_sm_cma_import_dmabuf(struct dma_buf *dmabuf, void **handle);
-
- #endif /* __VC_SM_KNL_H__INCLUDED__ */
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h
-@@ -52,7 +52,7 @@ struct mmal_buffer {
- struct mmal_msg_context *msg_context;
-
- struct dma_buf *dma_buf;/* Exported dmabuf fd from videobuf2 */
-- int vcsm_handle; /* VCSM handle having imported the dmabuf */
-+ void *vcsm_handle; /* VCSM handle having imported the dmabuf */
- u32 vc_handle; /* VC handle to that dmabuf */
-
- u32 cmd; /* MMAL command. 0=data. */
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -1794,7 +1794,7 @@ int mmal_vchi_buffer_cleanup(struct mmal
- if (buf->vcsm_handle) {
- int ret;
-
-- pr_debug("%s: vc_sm_cma_free on handle %08X\n", __func__,
-+ pr_debug("%s: vc_sm_cma_free on handle %p\n", __func__,
- buf->vcsm_handle);
- ret = vc_sm_cma_free(buf->vcsm_handle);
- if (ret)
--- /dev/null
+From 6cafe647492605d21c2418b6261bf3182b9229f2 Mon Sep 17 00:00:00 2001
+Date: Fri, 8 Feb 2019 13:03:38 +0200
+Subject: [PATCH] overlays: balenaFin v1.1.0 carrier board update
+
+A backward compatible update for the balenaFin carrier board for the
+Raspberry Pi Compute Module 3/3+ Lite.
+
+The updated overlay includes:
+ * support for the newly introduced RGB LEDs
+ * i2c-gpio and SDIO improvements
+ * DT based Marvell 88W8887 configuration
+
+---
+ arch/arm/boot/dts/overlays/README | 2 +-
+ .../boot/dts/overlays/balena-fin-overlay.dts | 46 ++++++++++++++++++-
+ 2 files changed, 45 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -472,7 +472,7 @@ Params: swap_lr Reverse
+
+ Name: balena-fin
+ Info: Overlay that enables WiFi, Bluetooth and the GPIO expander on the
+- Balena Fin board.
++ balenaFin carrier board for the Raspberry Pi Compute Module 3/3+ Lite.
+ Load: dtoverlay=balena-fin
+ Params: <None>
+
+--- a/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
++++ b/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
+@@ -11,6 +11,7 @@
+ pinctrl-0 = <&sdio_pins>;
+ bus-width = <4>;
+ brcm,overclock-50 = <35>;
++ non-removable;
+ status = "okay";
+ };
+ };
+@@ -34,7 +35,8 @@
+ fragment@2 {
+ target-path = "/";
+ __overlay__ {
+- // We should investigate how to switch to mmc-pwrseq-sd8787
++ // We should switch to mmc-pwrseq-sd8787 after making it
++ // compatible with sd8887
+ // Currently that module requires two GPIOs to function since it
+ // targets a slightly different chip
+ power_ctrl: power_ctrl {
+@@ -46,10 +48,21 @@
+ i2c_soft: i2c@0 {
+ compatible = "i2c-gpio";
+ gpios = <&gpio 43 0 /* sda */ &gpio 42 0 /* scl */>;
+- i2c-gpio,delay-us = <2>; /* ~100 kHz */
++ i2c-gpio,delay-us = <5>;
++ i2c-gpio,scl-open-drain;
++ i2c-gpio,sda-open-drain;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
++
++ sd8xxx-wlan {
++ drvdbg = <0x6>;
++ drv_mode = <0x1>;
++ cfg80211_wext = <0xf>;
++ sta_name = "wlan";
++ wfd_name = "p2p";
++ cal_data_cfg = "none";
++ };
+ };
+ };
+
+@@ -74,6 +87,35 @@
+ reg = <0x68>;
+ status = "okay";
+ };
++
++ // RGB LEDs (>= v1.1.0)
++ pca9633: pca9633@62 {
++ compatible = "nxp,pca9633";
++ reg = <0x62>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ red@0 {
++ label = "red";
++ reg = <0>;
++ linux,default-trigger = "none";
++ };
++ green@1 {
++ label = "green";
++ reg = <1>;
++ linux,default-trigger = "none";
++ };
++ blue@2 {
++ label = "blue";
++ reg = <2>;
++ linux,default-trigger = "none";
++ };
++ unused@3 {
++ label = "unused";
++ reg = <3>;
++ linux,default-trigger = "none";
++ };
++ };
+ };
+ };
+ };
+++ /dev/null
-From 696aa66a971b20e4f00431cb53747f0e4b92bb03 Mon Sep 17 00:00:00 2001
-Date: Tue, 29 Jan 2019 16:32:57 +0000
-Subject: [PATCH] staging: vc-sm-cma: Fix up for 64bit builds
-
-There were a number of logging lines that were using
-inappropriate formatting under 64bit kernels.
-
-The kernel_id field passed to/from the VPU was being
-abused for storing the struct vc_sm_buffer *.
-This breaks with 64bit kernels, so change to using an IDR.
-
----
- .../staging/vc04_services/vc-sm-cma/vc_sm.c | 60 +++++++++++++++----
- .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 3 +-
- 2 files changed, 48 insertions(+), 15 deletions(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -75,6 +75,9 @@ struct sm_state_t {
- struct miscdevice dev;
- struct sm_instance *sm_handle; /* Handle for videocore service. */
-
-+ spinlock_t kernelid_map_lock; /* Spinlock protecting kernelid_map */
-+ struct idr kernelid_map;
-+
- struct mutex map_lock; /* Global map lock. */
- struct list_head buffer_list; /* List of buffer. */
-
-@@ -97,6 +100,29 @@ static int sm_inited;
-
- /* ---- Private Functions ------------------------------------------------ */
-
-+static int get_kernel_id(struct vc_sm_buffer *buffer)
-+{
-+ int handle;
-+
-+ spin_lock(&sm_state->kernelid_map_lock);
-+ handle = idr_alloc(&sm_state->kernelid_map, buffer, 0, 0, GFP_KERNEL);
-+ spin_unlock(&sm_state->kernelid_map_lock);
-+
-+ return handle;
-+}
-+
-+static struct vc_sm_buffer *lookup_kernel_id(int handle)
-+{
-+ return idr_find(&sm_state->kernelid_map, handle);
-+}
-+
-+static void free_kernel_id(int handle)
-+{
-+ spin_lock(&sm_state->kernelid_map_lock);
-+ idr_remove(&sm_state->kernelid_map, handle);
-+ spin_unlock(&sm_state->kernelid_map_lock);
-+}
-+
- static int vc_sm_cma_seq_file_show(struct seq_file *s, void *v)
- {
- struct sm_pde_t *sm_pde;
-@@ -129,8 +155,7 @@ static int vc_sm_cma_global_state_show(s
- if (!sm_state)
- return 0;
-
-- seq_printf(s, "\nVC-ServiceHandle 0x%x\n",
-- (unsigned int)sm_state->sm_handle);
-+ seq_printf(s, "\nVC-ServiceHandle %p\n", sm_state->sm_handle);
-
- /* Log all applicable mapping(s). */
-
-@@ -145,7 +170,7 @@ static int vc_sm_cma_global_state_show(s
- resource);
- seq_printf(s, " NAME %s\n",
- resource->name);
-- seq_printf(s, " SIZE %d\n",
-+ seq_printf(s, " SIZE %zu\n",
- resource->size);
- seq_printf(s, " DMABUF %p\n",
- resource->dma_buf);
-@@ -181,7 +206,7 @@ static void vc_sm_add_resource(struct vc
- list_add(&buffer->global_buffer_list, &sm_state->buffer_list);
- mutex_unlock(&sm_state->map_lock);
-
-- pr_debug("[%s]: added buffer %p (name %s, size %d)\n",
-+ pr_debug("[%s]: added buffer %p (name %s, size %zu)\n",
- __func__, buffer, buffer->name, buffer->size);
- }
-
-@@ -194,7 +219,7 @@ static void vc_sm_release_resource(struc
- mutex_lock(&sm_state->map_lock);
- mutex_lock(&buffer->lock);
-
-- pr_debug("[%s]: buffer %p (name %s, size %d)\n",
-+ pr_debug("[%s]: buffer %p (name %s, size %zu)\n",
- __func__, buffer, buffer->name, buffer->size);
-
- if (buffer->vc_handle && buffer->vpu_state == VPU_MAPPED) {
-@@ -443,6 +468,7 @@ vc_sm_cma_import_dmabuf_internal(struct
- struct vc_sm_import_result result = { };
- struct dma_buf_attachment *attach = NULL;
- struct sg_table *sgt = NULL;
-+ dma_addr_t dma_addr;
- int ret = 0;
- int status;
-
-@@ -478,21 +504,22 @@ vc_sm_cma_import_dmabuf_internal(struct
- }
-
- import.type = VC_SM_ALLOC_NON_CACHED;
-- import.addr = (uint32_t)sg_dma_address(sgt->sgl);
-+ dma_addr = sg_dma_address(sgt->sgl);
-+ import.addr = (uint32_t)dma_addr;
- if ((import.addr & 0xC0000000) != 0xC0000000) {
-- pr_err("%s: Expecting an uncached alias for dma_addr %08x\n",
-- __func__, import.addr);
-+ pr_err("%s: Expecting an uncached alias for dma_addr %pad\n",
-+ __func__, &dma_addr);
- import.addr |= 0xC0000000;
- }
- import.size = sg_dma_len(sgt->sgl);
- import.allocator = current->tgid;
-- import.kernel_id = (uint32_t)buffer; //FIXME: 64 bit support needed.
-+ import.kernel_id = get_kernel_id(buffer);
-
- memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT,
- sizeof(VC_SM_RESOURCE_NAME_DEFAULT));
-
-- pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %p, size %u\n",
-- __func__, import.name, import.type, (void *)import.addr,
-+ pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %pad, size %u\n",
-+ __func__, import.name, import.type, &dma_addr,
- import.size);
-
- /* Allocate the videocore buffer. */
-@@ -527,7 +554,7 @@ vc_sm_cma_import_dmabuf_internal(struct
-
- buffer->attach = attach;
- buffer->sgt = sgt;
-- buffer->dma_addr = sg_dma_address(sgt->sgl);
-+ buffer->dma_addr = dma_addr;
- buffer->in_use = 1;
-
- /*
-@@ -559,6 +586,7 @@ error:
- vc_sm_cma_vchi_free(sm_state->sm_handle, &free,
- &sm_state->int_trans_id);
- }
-+ free_kernel_id(import.kernel_id);
- kfree(buffer);
- if (sgt)
- dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
-@@ -586,7 +614,7 @@ vc_sm_vpu_event(struct sm_instance *inst
- {
- struct vc_sm_released *release = (struct vc_sm_released *)reply;
- struct vc_sm_buffer *buffer =
-- (struct vc_sm_buffer *)release->kernel_id;
-+ lookup_kernel_id(release->kernel_id);
-
- /*
- * FIXME: Need to check buffer is still valid and allocated
-@@ -599,6 +627,7 @@ vc_sm_vpu_event(struct sm_instance *inst
- buffer->vc_handle = 0;
- buffer->vpu_state = VPU_NOT_MAPPED;
- mutex_unlock(&buffer->lock);
-+ free_kernel_id(release->kernel_id);
-
- vc_sm_release_resource(buffer, 0);
- }
-@@ -711,6 +740,9 @@ static int bcm2835_vc_sm_cma_probe(struc
- sm_state->pdev = pdev;
- mutex_init(&sm_state->map_lock);
-
-+ spin_lock_init(&sm_state->kernelid_map_lock);
-+ idr_init_base(&sm_state->kernelid_map, 1);
-+
- pdev->dev.dma_parms = devm_kzalloc(&pdev->dev,
- sizeof(*pdev->dev.dma_parms),
- GFP_KERNEL);
-@@ -735,6 +767,8 @@ static int bcm2835_vc_sm_cma_remove(stru
- /* Stop the videocore shared memory service. */
- vc_sm_cma_vchi_stop(&sm_state->sm_handle);
-
-+ idr_destroy(&sm_state->kernelid_map);
-+
- /* Free the memory for the state structure. */
- mutex_destroy(&sm_state->map_lock);
- kfree(sm_state);
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
-@@ -356,8 +356,7 @@ struct sm_instance *vc_sm_cma_vchi_init(
- set_user_nice(instance->io_thread, -10);
- wake_up_process(instance->io_thread);
-
-- pr_debug("%s: success - instance 0x%x", __func__,
-- (unsigned int)instance);
-+ pr_debug("%s: success - instance %p", __func__, instance);
- return instance;
-
- err_close_services:
+++ /dev/null
-From 3ffbec3df726c6d36ef728d476cb3ff3fcc17c81 Mon Sep 17 00:00:00 2001
-Date: Thu, 7 Feb 2019 18:16:25 +0000
-Subject: [PATCH] configs: Enable the AD193x codecs
-
-See: https://github.com/raspberrypi/linux/issues/2850
-
----
- sound/soc/codecs/Kconfig | 4 ++--
- 4 files changed, 8 insertions(+), 2 deletions(-)
-
---- a/sound/soc/codecs/Kconfig
-+++ b/sound/soc/codecs/Kconfig
-@@ -295,11 +295,11 @@ config SND_SOC_AD193X
- tristate
-
- config SND_SOC_AD193X_SPI
-- tristate
-+ tristate "Analog Devices AU193X CODEC - SPI"
- select SND_SOC_AD193X
-
- config SND_SOC_AD193X_I2C
-- tristate
-+ tristate "Analog Devices AU193X CODEC - I2C"
- select SND_SOC_AD193X
-
- config SND_SOC_AD1980
--- /dev/null
+From e5285033e0fbfb6750d7d39e7edebf67a16c8434 Mon Sep 17 00:00:00 2001
+Date: Tue, 19 Feb 2019 15:06:31 +0000
+Subject: [PATCH] gpu:vc4-fkms: Update driver to not use plane->crtc.
+
+Following on from
+commit 2f958af7fc248 ("drm/vc4: Stop updating plane->fb/crtc")
+do the same in the firmwarekms driver and look at plane_state->crtc
+instead.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -193,8 +193,8 @@ static void vc4_cursor_plane_atomic_upda
+ struct drm_plane_state *old_state)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+- struct vc4_crtc *vc4_crtc = to_vc4_crtc(plane->crtc);
+ struct drm_plane_state *state = plane->state;
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+ dma_addr_t addr = bo->paddr + fb->offsets[0];
+@@ -682,8 +682,6 @@ static int vc4_fkms_bind(struct device *
+ drm_crtc_init_with_planes(drm, crtc, primary_plane, cursor_plane,
+ &vc4_crtc_funcs, NULL);
+ drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
+- primary_plane->crtc = crtc;
+- cursor_plane->crtc = crtc;
+
+ vc4_encoder = devm_kzalloc(dev, sizeof(*vc4_encoder), GFP_KERNEL);
+ if (!vc4_encoder)
--- /dev/null
+From bb8e85deab20dd38c26d354452e1ac42add37530 Mon Sep 17 00:00:00 2001
+Date: Tue, 19 Feb 2019 15:18:25 +0000
+Subject: [PATCH] drm: vc4: Programming the CTM is conditional on
+ running full KMS
+
+vc4_ctm_commit writes to HVS registers, so this is only applicable
+when in full KMS mode, not in firmware KMS mode. Add this conditional.
+
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -147,7 +147,8 @@ vc4_atomic_complete_commit(struct drm_at
+
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+- vc4_ctm_commit(vc4, state);
++ if (!vc4->firmware_kms)
++ vc4_ctm_commit(vc4, state);
+
+ drm_atomic_helper_commit_planes(dev, state, 0);
+
+++ /dev/null
-From 6cafe647492605d21c2418b6261bf3182b9229f2 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Feb 2019 13:03:38 +0200
-Subject: [PATCH] overlays: balenaFin v1.1.0 carrier board update
-
-A backward compatible update for the balenaFin carrier board for the
-Raspberry Pi Compute Module 3/3+ Lite.
-
-The updated overlay includes:
- * support for the newly introduced RGB LEDs
- * i2c-gpio and SDIO improvements
- * DT based Marvell 88W8887 configuration
-
----
- arch/arm/boot/dts/overlays/README | 2 +-
- .../boot/dts/overlays/balena-fin-overlay.dts | 46 ++++++++++++++++++-
- 2 files changed, 45 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -472,7 +472,7 @@ Params: swap_lr Reverse
-
- Name: balena-fin
- Info: Overlay that enables WiFi, Bluetooth and the GPIO expander on the
-- Balena Fin board.
-+ balenaFin carrier board for the Raspberry Pi Compute Module 3/3+ Lite.
- Load: dtoverlay=balena-fin
- Params: <None>
-
---- a/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
-@@ -11,6 +11,7 @@
- pinctrl-0 = <&sdio_pins>;
- bus-width = <4>;
- brcm,overclock-50 = <35>;
-+ non-removable;
- status = "okay";
- };
- };
-@@ -34,7 +35,8 @@
- fragment@2 {
- target-path = "/";
- __overlay__ {
-- // We should investigate how to switch to mmc-pwrseq-sd8787
-+ // We should switch to mmc-pwrseq-sd8787 after making it
-+ // compatible with sd8887
- // Currently that module requires two GPIOs to function since it
- // targets a slightly different chip
- power_ctrl: power_ctrl {
-@@ -46,10 +48,21 @@
- i2c_soft: i2c@0 {
- compatible = "i2c-gpio";
- gpios = <&gpio 43 0 /* sda */ &gpio 42 0 /* scl */>;
-- i2c-gpio,delay-us = <2>; /* ~100 kHz */
-+ i2c-gpio,delay-us = <5>;
-+ i2c-gpio,scl-open-drain;
-+ i2c-gpio,sda-open-drain;
- #address-cells = <1>;
- #size-cells = <0>;
- };
-+
-+ sd8xxx-wlan {
-+ drvdbg = <0x6>;
-+ drv_mode = <0x1>;
-+ cfg80211_wext = <0xf>;
-+ sta_name = "wlan";
-+ wfd_name = "p2p";
-+ cal_data_cfg = "none";
-+ };
- };
- };
-
-@@ -74,6 +87,35 @@
- reg = <0x68>;
- status = "okay";
- };
-+
-+ // RGB LEDs (>= v1.1.0)
-+ pca9633: pca9633@62 {
-+ compatible = "nxp,pca9633";
-+ reg = <0x62>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ red@0 {
-+ label = "red";
-+ reg = <0>;
-+ linux,default-trigger = "none";
-+ };
-+ green@1 {
-+ label = "green";
-+ reg = <1>;
-+ linux,default-trigger = "none";
-+ };
-+ blue@2 {
-+ label = "blue";
-+ reg = <2>;
-+ linux,default-trigger = "none";
-+ };
-+ unused@3 {
-+ label = "unused";
-+ reg = <3>;
-+ linux,default-trigger = "none";
-+ };
-+ };
- };
- };
- };
+++ /dev/null
-From e5285033e0fbfb6750d7d39e7edebf67a16c8434 Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Feb 2019 15:06:31 +0000
-Subject: [PATCH] gpu:vc4-fkms: Update driver to not use plane->crtc.
-
-Following on from
-commit 2f958af7fc248 ("drm/vc4: Stop updating plane->fb/crtc")
-do the same in the firmwarekms driver and look at plane_state->crtc
-instead.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 +---
- 1 file changed, 1 insertion(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -193,8 +193,8 @@ static void vc4_cursor_plane_atomic_upda
- struct drm_plane_state *old_state)
- {
- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
-- struct vc4_crtc *vc4_crtc = to_vc4_crtc(plane->crtc);
- struct drm_plane_state *state = plane->state;
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
- struct drm_framebuffer *fb = state->fb;
- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
- dma_addr_t addr = bo->paddr + fb->offsets[0];
-@@ -682,8 +682,6 @@ static int vc4_fkms_bind(struct device *
- drm_crtc_init_with_planes(drm, crtc, primary_plane, cursor_plane,
- &vc4_crtc_funcs, NULL);
- drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
-- primary_plane->crtc = crtc;
-- cursor_plane->crtc = crtc;
-
- vc4_encoder = devm_kzalloc(dev, sizeof(*vc4_encoder), GFP_KERNEL);
- if (!vc4_encoder)
--- /dev/null
+From 39c4b77533bee8d88d2f4c9be9463041ec1dd483 Mon Sep 17 00:00:00 2001
+Date: Wed, 13 Feb 2019 12:33:29 +0000
+Subject: [PATCH] staging: mmal_vchiq: Add in the Bayer encoding
+ formats
+
+The list of formats was copied before Bayer support was added.
+The ISP supports Bayer and is being supported by the bcm2835_codec
+driver, so add in the encodings for them.
+
+---
+ .../vc04_services/vchiq-mmal/mmal-encodings.h | 27 +++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h
+@@ -69,6 +69,33 @@
+ */
+ #define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V')
+
++/* Bayer formats
++ * FourCC values copied from V4L2 where defined.
++ */
++/* 8 bit per pixel Bayer formats. */
++#define MMAL_ENCODING_BAYER_SBGGR8 MMAL_FOURCC('B', 'A', '8', '1')
++#define MMAL_ENCODING_BAYER_SGBRG8 MMAL_FOURCC('G', 'B', 'R', 'G')
++#define MMAL_ENCODING_BAYER_SGRBG8 MMAL_FOURCC('G', 'R', 'B', 'G')
++#define MMAL_ENCODING_BAYER_SRGGB8 MMAL_FOURCC('R', 'G', 'G', 'B')
++
++/* 10 bit per pixel packed Bayer formats. */
++#define MMAL_ENCODING_BAYER_SBGGR10P MMAL_FOURCC('p', 'B', 'A', 'A')
++#define MMAL_ENCODING_BAYER_SGRBG10P MMAL_FOURCC('p', 'g', 'A', 'A')
++#define MMAL_ENCODING_BAYER_SGBRG10P MMAL_FOURCC('p', 'G', 'A', 'A')
++#define MMAL_ENCODING_BAYER_SRGGB10P MMAL_FOURCC('p', 'R', 'A', 'A')
++
++/* 12 bit per pixel packed Bayer formats. */
++#define MMAL_ENCODING_BAYER_SBGGR12P MMAL_FOURCC('p', 'B', '1', '2')
++#define MMAL_ENCODING_BAYER_SGRBG12P MMAL_FOURCC('p', 'g', '1', '2')
++#define MMAL_ENCODING_BAYER_SGBRG12P MMAL_FOURCC('p', 'G', '1', '2')
++#define MMAL_ENCODING_BAYER_SRGGB12P MMAL_FOURCC('p', 'R', '1', '2')
++
++/* 16 bit per pixel Bayer formats. */
++#define MMAL_ENCODING_BAYER_SBGGR16 MMAL_FOURCC('B', 'G', '1', '6')
++#define MMAL_ENCODING_BAYER_SGBRG16 MMAL_FOURCC('G', 'B', '1', '6')
++#define MMAL_ENCODING_BAYER_SGRBG16 MMAL_FOURCC('G', 'R', '1', '6')
++#define MMAL_ENCODING_BAYER_SRGGB16 MMAL_FOURCC('R', 'G', '1', '6')
++
+ /** An EGL image handle
+ */
+ #define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I')
+++ /dev/null
-From bb8e85deab20dd38c26d354452e1ac42add37530 Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Feb 2019 15:18:25 +0000
-Subject: [PATCH] drm: vc4: Programming the CTM is conditional on
- running full KMS
-
-vc4_ctm_commit writes to HVS registers, so this is only applicable
-when in full KMS mode, not in firmware KMS mode. Add this conditional.
-
----
- drivers/gpu/drm/vc4/vc4_kms.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -147,7 +147,8 @@ vc4_atomic_complete_commit(struct drm_at
-
- drm_atomic_helper_commit_modeset_disables(dev, state);
-
-- vc4_ctm_commit(vc4, state);
-+ if (!vc4->firmware_kms)
-+ vc4_ctm_commit(vc4, state);
-
- drm_atomic_helper_commit_planes(dev, state, 0);
-
--- /dev/null
+From 0c0e55d9b04868733f30c348df7400fa5e6d30e2 Mon Sep 17 00:00:00 2001
+Date: Wed, 13 Feb 2019 12:36:56 +0000
+Subject: [PATCH] staging: mmal-vchiq: Always return the param size
+ from param_get
+
+mmal-vchiq is a reimplementation of the userland library for MMAL.
+When getting a parameter, the client provides the storage and
+the size of the storage. The VPU then returns the size of the
+parameter that it wished to return, and as much as possible of
+that parameter is returned to the client.
+
+The implementation previously only returned the size provided
+by the VPU should it exceed the buffer size. So for parameters
+such as the supported encodings list the client had no idea
+how much of the provided storage had been populated.
+
+---
+ drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -1413,11 +1413,12 @@ static int port_parameter_get(struct vch
+ */
+ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
+ *value_size);
+- *value_size = rmsg->u.port_parameter_get_reply.size;
+ } else {
+ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
+ rmsg->u.port_parameter_get_reply.size);
+ }
++ /* Always report the size of the returned parameter to the caller */
++ *value_size = rmsg->u.port_parameter_get_reply.size;
+
+ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
+ ret, port->component->handle, port->handle, parameter_id);
--- /dev/null
+From 78c34cf60b9ae8bf8aa797c72d2f1abdc0a0bb9d Mon Sep 17 00:00:00 2001
+Date: Wed, 13 Feb 2019 12:51:03 +0000
+Subject: [PATCH] staging: mmal-vchiq: If the VPU returns an error,
+ don't negate it
+
+There is an enum for the errors that the VPU can return.
+port_parameter_get was negating that value, but also using -EINVAL
+from the Linux error codes.
+Pass the VPU error code as positive values. Should the function
+need to pass a Linux failure, then return that as negative.
+
+---
+ drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -1401,7 +1401,8 @@ static int port_parameter_get(struct vch
+ goto release_msg;
+ }
+
+- ret = -rmsg->u.port_parameter_get_reply.status;
++ ret = rmsg->u.port_parameter_get_reply.status;
++
+ /* port_parameter_get_reply.size includes the header,
+ * whilst *value_size doesn't.
+ */
+++ /dev/null
-From 39c4b77533bee8d88d2f4c9be9463041ec1dd483 Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Feb 2019 12:33:29 +0000
-Subject: [PATCH] staging: mmal_vchiq: Add in the Bayer encoding
- formats
-
-The list of formats was copied before Bayer support was added.
-The ISP supports Bayer and is being supported by the bcm2835_codec
-driver, so add in the encodings for them.
-
----
- .../vc04_services/vchiq-mmal/mmal-encodings.h | 27 +++++++++++++++++++
- 1 file changed, 27 insertions(+)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h
-@@ -69,6 +69,33 @@
- */
- #define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V')
-
-+/* Bayer formats
-+ * FourCC values copied from V4L2 where defined.
-+ */
-+/* 8 bit per pixel Bayer formats. */
-+#define MMAL_ENCODING_BAYER_SBGGR8 MMAL_FOURCC('B', 'A', '8', '1')
-+#define MMAL_ENCODING_BAYER_SGBRG8 MMAL_FOURCC('G', 'B', 'R', 'G')
-+#define MMAL_ENCODING_BAYER_SGRBG8 MMAL_FOURCC('G', 'R', 'B', 'G')
-+#define MMAL_ENCODING_BAYER_SRGGB8 MMAL_FOURCC('R', 'G', 'G', 'B')
-+
-+/* 10 bit per pixel packed Bayer formats. */
-+#define MMAL_ENCODING_BAYER_SBGGR10P MMAL_FOURCC('p', 'B', 'A', 'A')
-+#define MMAL_ENCODING_BAYER_SGRBG10P MMAL_FOURCC('p', 'g', 'A', 'A')
-+#define MMAL_ENCODING_BAYER_SGBRG10P MMAL_FOURCC('p', 'G', 'A', 'A')
-+#define MMAL_ENCODING_BAYER_SRGGB10P MMAL_FOURCC('p', 'R', 'A', 'A')
-+
-+/* 12 bit per pixel packed Bayer formats. */
-+#define MMAL_ENCODING_BAYER_SBGGR12P MMAL_FOURCC('p', 'B', '1', '2')
-+#define MMAL_ENCODING_BAYER_SGRBG12P MMAL_FOURCC('p', 'g', '1', '2')
-+#define MMAL_ENCODING_BAYER_SGBRG12P MMAL_FOURCC('p', 'G', '1', '2')
-+#define MMAL_ENCODING_BAYER_SRGGB12P MMAL_FOURCC('p', 'R', '1', '2')
-+
-+/* 16 bit per pixel Bayer formats. */
-+#define MMAL_ENCODING_BAYER_SBGGR16 MMAL_FOURCC('B', 'G', '1', '6')
-+#define MMAL_ENCODING_BAYER_SGBRG16 MMAL_FOURCC('G', 'B', '1', '6')
-+#define MMAL_ENCODING_BAYER_SGRBG16 MMAL_FOURCC('G', 'R', '1', '6')
-+#define MMAL_ENCODING_BAYER_SRGGB16 MMAL_FOURCC('R', 'G', '1', '6')
-+
- /** An EGL image handle
- */
- #define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I')
--- /dev/null
+From ce8cc7a85839af588b753ce4af0832db9c467f45 Mon Sep 17 00:00:00 2001
+Date: Wed, 13 Feb 2019 13:44:00 +0000
+Subject: [PATCH] staging: bcm2835_codec: Query supported formats from
+ the component
+
+The driver was previously working with hard coded tables of
+which video formats were supported by each component.
+The components advertise this information via a MMAL parameter,
+so retrieve the information from there during probe, and store
+in the state structure for that device.
+
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 455 +++++++++++++-----
+ 1 file changed, 327 insertions(+), 128 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -88,17 +88,12 @@ struct bcm2835_codec_fmt {
+ int bytesperline_align;
+ u32 flags;
+ u32 mmal_fmt;
+- bool decode_only;
+- bool encode_only;
+ int size_multiplier_x2;
+ };
+
+-/* Supported raw pixel formats. Those supported for both encode and decode
+- * must come first, with those only supported for decode coming after (there
+- * are no formats supported for encode only).
+- */
+-static struct bcm2835_codec_fmt raw_formats[] = {
++static const struct bcm2835_codec_fmt supported_formats[] = {
+ {
++ /* YUV formats */
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .depth = 8,
+ .bytesperline_align = 32,
+@@ -139,7 +134,6 @@ static struct bcm2835_codec_fmt raw_form
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_YUYV,
+- .encode_only = true,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+@@ -147,7 +141,6 @@ static struct bcm2835_codec_fmt raw_form
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_UYVY,
+- .encode_only = true,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+@@ -155,7 +148,6 @@ static struct bcm2835_codec_fmt raw_form
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_YVYU,
+- .encode_only = true,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+@@ -163,15 +155,14 @@ static struct bcm2835_codec_fmt raw_form
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_VYUY,
+- .encode_only = true,
+ .size_multiplier_x2 = 2,
+ }, {
++ /* RGB formats */
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .depth = 24,
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_RGB24,
+- .encode_only = true,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_BGR24,
+@@ -179,7 +170,6 @@ static struct bcm2835_codec_fmt raw_form
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BGR24,
+- .encode_only = true,
+ .size_multiplier_x2 = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_BGR32,
+@@ -187,17 +177,126 @@ static struct bcm2835_codec_fmt raw_form
+ .bytesperline_align = 32,
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BGRA,
+- .encode_only = true,
+ .size_multiplier_x2 = 2,
+- },
+-};
+-
+-/* Supported encoded formats. Those supported for both encode and decode
+- * must come first, with those only supported for decode coming after (there
+- * are no formats supported for encode only).
+- */
+-static struct bcm2835_codec_fmt encoded_formats[] = {
+- {
++ }, {
++ /* Bayer formats */
++ /* 8 bit */
++ .fourcc = V4L2_PIX_FMT_SRGGB8,
++ .depth = 8,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SBGGR8,
++ .depth = 8,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SGRBG8,
++ .depth = 8,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SGBRG8,
++ .depth = 8,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8,
++ .size_multiplier_x2 = 2,
++ }, {
++ /* 10 bit */
++ .fourcc = V4L2_PIX_FMT_SRGGB10P,
++ .depth = 10,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SBGGR10P,
++ .depth = 10,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SGRBG10P,
++ .depth = 10,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SGBRG10P,
++ .depth = 10,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P,
++ .size_multiplier_x2 = 2,
++ }, {
++ /* 12 bit */
++ .fourcc = V4L2_PIX_FMT_SRGGB12P,
++ .depth = 12,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SBGGR12P,
++ .depth = 12,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SGRBG12P,
++ .depth = 12,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SGBRG12P,
++ .depth = 12,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P,
++ .size_multiplier_x2 = 2,
++ }, {
++ /* 16 bit */
++ .fourcc = V4L2_PIX_FMT_SRGGB16,
++ .depth = 16,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SBGGR16,
++ .depth = 16,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SGRBG16,
++ .depth = 16,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16,
++ .size_multiplier_x2 = 2,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SGBRG16,
++ .depth = 16,
++ .bytesperline_align = 32,
++ .flags = 0,
++ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16,
++ .size_multiplier_x2 = 2,
++ }, {
++ /* Compressed formats */
+ .fourcc = V4L2_PIX_FMT_H264,
+ .depth = 0,
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+@@ -212,30 +311,22 @@ static struct bcm2835_codec_fmt encoded_
+ .depth = 0,
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+ .mmal_fmt = MMAL_ENCODING_MP4V,
+- .decode_only = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_H263,
+ .depth = 0,
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+ .mmal_fmt = MMAL_ENCODING_H263,
+- .decode_only = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_MPEG2,
+ .depth = 0,
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+ .mmal_fmt = MMAL_ENCODING_MP2V,
+- .decode_only = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_VP8,
+ .depth = 0,
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+ .mmal_fmt = MMAL_ENCODING_VP8,
+- .decode_only = true,
+ },
+- /*
+- * This list couold include VP6 and Theorafor decode, but V4L2 doesn't
+- * support them.
+- */
+ };
+
+ struct bcm2835_codec_fmt_list {
+@@ -243,19 +334,6 @@ struct bcm2835_codec_fmt_list {
+ unsigned int num_entries;
+ };
+
+-#define RAW_LIST 0
+-#define ENCODED_LIST 1
+-
+-struct bcm2835_codec_fmt_list formats[] = {
+- {
+- .list = raw_formats,
+- .num_entries = ARRAY_SIZE(raw_formats),
+- }, {
+- .list = encoded_formats,
+- .num_entries = ARRAY_SIZE(encoded_formats),
+- },
+-};
+-
+ struct m2m_mmal_buffer {
+ struct v4l2_m2m_buffer m2m;
+ struct mmal_buffer mmal;
+@@ -284,52 +362,6 @@ struct bcm2835_codec_q_data {
+ bool eos_buffer_in_use; /* debug only */
+ };
+
+-enum {
+- V4L2_M2M_SRC = 0,
+- V4L2_M2M_DST = 1,
+-};
+-
+-static inline struct bcm2835_codec_fmt_list *get_format_list(bool decode,
+- bool capture)
+-{
+- return decode ^ capture ? &formats[ENCODED_LIST] : &formats[RAW_LIST];
+-}
+-
+-static struct bcm2835_codec_fmt *get_default_format(bool decode, bool capture)
+-{
+- return &get_format_list(decode, capture)->list[0];
+-}
+-
+-static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, bool decode,
+- bool capture)
+-{
+- struct bcm2835_codec_fmt *fmt;
+- unsigned int k;
+- struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
+-
+- for (k = 0; k < fmts->num_entries; k++) {
+- fmt = &fmts->list[k];
+- if (fmt->fourcc == f->fmt.pix.pixelformat)
+- break;
+- }
+-
+- /*
+- * Some compressed formats are only supported for decoding, not
+- * encoding.
+- */
+- if (!decode && fmts->list[k].decode_only)
+- return NULL;
+-
+- /* Some pixel formats are only supported for encoding, not decoding. */
+- if (decode && fmts->list[k].encode_only)
+- return NULL;
+-
+- if (k == fmts->num_entries)
+- return NULL;
+-
+- return &fmts->list[k];
+-}
+-
+ struct bcm2835_codec_dev {
+ struct platform_device *pdev;
+
+@@ -342,6 +374,9 @@ struct bcm2835_codec_dev {
+
+ /* allocated mmal instance and components */
+ bool decode; /* Is this instance a decoder? */
++ /* The list of formats supported on input and output queues. */
++ struct bcm2835_codec_fmt_list supported_fmts[2];
++
+ struct vchiq_mmal_instance *instance;
+
+ struct v4l2_m2m_dev *m2m_dev;
+@@ -374,8 +409,59 @@ struct bcm2835_codec_ctx {
+ struct bcm2835_codec_driver {
+ struct bcm2835_codec_dev *encode;
+ struct bcm2835_codec_dev *decode;
++ struct bcm2835_codec_dev *isp;
++};
++
++enum {
++ V4L2_M2M_SRC = 0,
++ V4L2_M2M_DST = 1,
+ };
+
++static const struct bcm2835_codec_fmt *get_fmt(u32 mmal_fmt)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
++ if (supported_formats[i].mmal_fmt == mmal_fmt)
++ return &supported_formats[i];
++ }
++ return NULL;
++}
++
++static inline
++struct bcm2835_codec_fmt_list *get_format_list(struct bcm2835_codec_dev *dev,
++ bool capture)
++{
++ return &dev->supported_fmts[capture ? 1 : 0];
++}
++
++static
++struct bcm2835_codec_fmt *get_default_format(struct bcm2835_codec_dev *dev,
++ bool capture)
++{
++ return &dev->supported_fmts[capture ? 1 : 0].list[0];
++}
++
++static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
++ struct bcm2835_codec_dev *dev,
++ bool capture)
++{
++ struct bcm2835_codec_fmt *fmt;
++ unsigned int k;
++ struct bcm2835_codec_fmt_list *fmts =
++ &dev->supported_fmts[capture ? 1 : 0];
++
++ for (k = 0; k < fmts->num_entries; k++) {
++ fmt = &fmts->list[k];
++ if (fmt->fourcc == f->fmt.pix.pixelformat)
++ break;
++ }
++ if (k == fmts->num_entries)
++ return NULL;
++
++ return &fmts->list[k];
++}
++
+ static inline struct bcm2835_codec_ctx *file2ctx(struct file *file)
+ {
+ return container_of(file->private_data, struct bcm2835_codec_ctx, fh);
+@@ -456,7 +542,6 @@ static inline unsigned int get_bytesperl
+ }
+
+ static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx,
+- bool decode,
+ struct bcm2835_codec_q_data *q_data,
+ struct vchiq_mmal_port *port)
+ {
+@@ -473,7 +558,7 @@ static void setup_mmal_port_format(struc
+ port->es.video.frame_rate.den = 1;
+ } else {
+ /* Compressed format - leave resolution as 0 for decode */
+- if (decode) {
++ if (ctx->dev->decode) {
+ port->es.video.width = 0;
+ port->es.video.height = 0;
+ port->es.video.crop.width = 0;
+@@ -802,22 +887,15 @@ static int vidioc_querycap(struct file *
+ return 0;
+ }
+
+-static int enum_fmt(struct v4l2_fmtdesc *f, bool decode, bool capture)
++static int enum_fmt(struct v4l2_fmtdesc *f, struct bcm2835_codec_ctx *ctx,
++ bool capture)
+ {
+ struct bcm2835_codec_fmt *fmt;
+- struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
++ struct bcm2835_codec_fmt_list *fmts =
++ get_format_list(ctx->dev, capture);
+
+ if (f->index < fmts->num_entries) {
+ /* Format found */
+- /* Check format isn't a decode only format when encoding */
+- if (!decode &&
+- fmts->list[f->index].decode_only)
+- return -EINVAL;
+- /* Check format isn't a decode only format when encoding */
+- if (decode &&
+- fmts->list[f->index].encode_only)
+- return -EINVAL;
+-
+ fmt = &fmts->list[f->index];
+ f->pixelformat = fmt->fourcc;
+ f->flags = fmt->flags;
+@@ -833,7 +911,7 @@ static int vidioc_enum_fmt_vid_cap(struc
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+
+- return enum_fmt(f, ctx->dev->decode, true);
++ return enum_fmt(f, ctx, true);
+ }
+
+ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+@@ -841,7 +919,7 @@ static int vidioc_enum_fmt_vid_out(struc
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+
+- return enum_fmt(f, ctx->dev->decode, false);
++ return enum_fmt(f, ctx, false);
+ }
+
+ static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f)
+@@ -933,11 +1011,11 @@ static int vidioc_try_fmt_vid_cap(struct
+ struct bcm2835_codec_fmt *fmt;
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+
+- fmt = find_format(f, ctx->dev->decode, true);
++ fmt = find_format(f, ctx->dev, true);
+ if (!fmt) {
+- f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
++ f->fmt.pix.pixelformat = get_default_format(ctx->dev,
+ true)->fourcc;
+- fmt = find_format(f, ctx->dev->decode, true);
++ fmt = find_format(f, ctx->dev, true);
+ }
+
+ return vidioc_try_fmt(f, fmt);
+@@ -949,11 +1027,11 @@ static int vidioc_try_fmt_vid_out(struct
+ struct bcm2835_codec_fmt *fmt;
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+
+- fmt = find_format(f, ctx->dev->decode, false);
++ fmt = find_format(f, ctx->dev, false);
+ if (!fmt) {
+- f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
++ f->fmt.pix.pixelformat = get_default_format(ctx->dev,
+ false)->fourcc;
+- fmt = find_format(f, ctx->dev->decode, false);
++ fmt = find_format(f, ctx->dev, false);
+ }
+
+ if (!f->fmt.pix.colorspace)
+@@ -988,7 +1066,7 @@ static int vidioc_s_fmt(struct bcm2835_c
+ return -EBUSY;
+ }
+
+- q_data->fmt = find_format(f, ctx->dev->decode,
++ q_data->fmt = find_format(f, ctx->dev,
+ f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ q_data->crop_width = f->fmt.pix.width;
+ q_data->height = f->fmt.pix.height;
+@@ -1041,7 +1119,7 @@ static int vidioc_s_fmt(struct bcm2835_c
+ if (!port)
+ return 0;
+
+- setup_mmal_port_format(ctx, ctx->dev->decode, q_data, port);
++ setup_mmal_port_format(ctx, q_data, port);
+ ret = vchiq_mmal_port_set_format(ctx->dev->instance, port);
+ if (ret) {
+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n",
+@@ -1064,8 +1142,7 @@ static int vidioc_s_fmt(struct bcm2835_c
+ struct bcm2835_codec_q_data *q_data_dst =
+ &ctx->q_data[V4L2_M2M_DST];
+
+- setup_mmal_port_format(ctx, ctx->dev->decode, q_data_dst,
+- port_dst);
++ setup_mmal_port_format(ctx, q_data_dst, port_dst);
+ ret = vchiq_mmal_port_set_format(ctx->dev->instance, port_dst);
+ if (ret) {
+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on output port, ret %d\n",
+@@ -1636,10 +1713,10 @@ static int bcm2835_codec_create_componen
+ MMAL_PARAMETER_ZERO_COPY, &enable,
+ sizeof(enable));
+
+- setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_SRC],
++ setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_SRC],
+ &ctx->component->input[0]);
+
+- setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_DST],
++ setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_DST],
+ &ctx->component->output[0]);
+
+ ret = vchiq_mmal_port_set_format(dev->instance,
+@@ -2025,8 +2102,8 @@ static int bcm2835_codec_open(struct fil
+ goto open_unlock;
+ }
+
+- ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev->decode, false);
+- ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev->decode, true);
++ ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false);
++ ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true);
+ if (dev->decode) {
+ /*
+ * Input width and height are irrelevant as they will be defined
+@@ -2209,13 +2286,130 @@ static const struct v4l2_m2m_ops m2m_ops
+ .job_abort = job_abort,
+ };
+
++/* Size of the array to provide to the VPU when asking for the list of supported
++ * formats.
++ * The ISP component currently advertises 33 input formats, so add a small
++ * overhead on that.
++ */
++#define MAX_SUPPORTED_ENCODINGS 40
++
++/* Populate dev->supported_fmts with the formats supported by those ports. */
++static int bcm2835_codec_get_supported_fmts(struct bcm2835_codec_dev *dev)
++{
++ struct bcm2835_codec_fmt *list;
++ struct vchiq_mmal_component *component;
++ u32 fourccs[MAX_SUPPORTED_ENCODINGS];
++ u32 param_size = sizeof(fourccs);
++ unsigned int i, j, num_encodings;
++ int ret;
++
++ ret = vchiq_mmal_component_init(dev->instance,
++ dev->decode ?
++ "ril.video_decode" :
++ "ril.video_encode",
++ &component);
++ if (ret < 0) {
++ v4l2_err(&dev->v4l2_dev, "%s: failed to create component\n",
++ __func__);
++ return -ENOMEM;
++ }
++
++ ret = vchiq_mmal_port_parameter_get(dev->instance,
++ &component->input[0],
++ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
++ &fourccs,
++ ¶m_size);
++
++ if (ret) {
++ if (ret == MMAL_MSG_STATUS_ENOSPC) {
++ v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n",
++ __func__);
++ num_encodings = MAX_SUPPORTED_ENCODINGS;
++ } else {
++ v4l2_err(&dev->v4l2_dev, "%s: get_param ret %u.\n",
++ __func__, ret);
++ ret = -EINVAL;
++ goto destroy_component;
++ }
++ } else {
++ num_encodings = param_size / sizeof(u32);
++ }
++
++ /* Assume at this stage that all encodings will be supported in V4L2.
++ * Any that aren't supported will waste a very small amount of memory.
++ */
++ list = devm_kzalloc(&dev->pdev->dev,
++ sizeof(struct bcm2835_codec_fmt) * num_encodings,
++ GFP_KERNEL);
++ if (!list) {
++ ret = -ENOMEM;
++ goto destroy_component;
++ }
++ dev->supported_fmts[0].list = list;
++
++ for (i = 0, j = 0; i < num_encodings; i++) {
++ const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]);
++
++ if (fmt) {
++ list[j] = *fmt;
++ j++;
++ }
++ }
++ dev->supported_fmts[0].num_entries = j;
++
++ param_size = sizeof(fourccs);
++ ret = vchiq_mmal_port_parameter_get(dev->instance,
++ &component->output[0],
++ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
++ &fourccs,
++ ¶m_size);
++
++ if (ret) {
++ if (ret == MMAL_MSG_STATUS_ENOSPC) {
++ v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n",
++ __func__);
++ num_encodings = MAX_SUPPORTED_ENCODINGS;
++ } else {
++ ret = -EINVAL;
++ goto destroy_component;
++ }
++ } else {
++ num_encodings = param_size / sizeof(u32);
++ }
++ /* Assume at this stage that all encodings will be supported in V4L2. */
++ list = devm_kzalloc(&dev->pdev->dev,
++ sizeof(struct bcm2835_codec_fmt) * num_encodings,
++ GFP_KERNEL);
++ if (!list) {
++ ret = -ENOMEM;
++ goto destroy_component;
++ }
++ dev->supported_fmts[1].list = list;
++
++ for (i = 0, j = 0; i < num_encodings; i++) {
++ const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]);
++
++ if (fmt) {
++ list[j] = *fmt;
++ j++;
++ }
++ }
++ dev->supported_fmts[1].num_entries = j;
++
++ ret = 0;
++
++destroy_component:
++ vchiq_mmal_component_finalise(dev->instance, component);
++
++ return ret;
++}
++
+ static int bcm2835_codec_create(struct platform_device *pdev,
+ struct bcm2835_codec_dev **new_dev,
+ bool decode)
+ {
+ struct bcm2835_codec_dev *dev;
+ struct video_device *vfd;
+- struct vchiq_mmal_instance *instance = NULL;
+ int video_nr;
+ int ret;
+
+@@ -2227,10 +2421,18 @@ static int bcm2835_codec_create(struct p
+
+ dev->decode = decode;
+
+- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
++ ret = vchiq_mmal_init(&dev->instance);
+ if (ret)
+ return ret;
+
++ ret = bcm2835_codec_get_supported_fmts(dev);
++ if (ret)
++ goto vchiq_finalise;
++
++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
++ if (ret)
++ goto vchiq_finalise;
++
+ atomic_set(&dev->num_inst, 0);
+ mutex_init(&dev->dev_mutex);
+
+@@ -2270,12 +2472,7 @@ static int bcm2835_codec_create(struct p
+ goto err_m2m;
+ }
+
+- ret = vchiq_mmal_init(&instance);
+- if (ret < 0)
+- goto err_m2m;
+- dev->instance = instance;
+-
+- v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s codec\n",
++ v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n",
+ dev->decode ? "decode" : "encode");
+ return 0;
+
+@@ -2284,7 +2481,8 @@ err_m2m:
+ video_unregister_device(&dev->vfd);
+ unreg_dev:
+ v4l2_device_unregister(&dev->v4l2_dev);
+-
++vchiq_finalise:
++ vchiq_mmal_finalise(dev->instance);
+ return ret;
+ }
+
+@@ -2297,6 +2495,7 @@ static int bcm2835_codec_destroy(struct
+ v4l2_m2m_release(dev->m2m_dev);
+ video_unregister_device(&dev->vfd);
+ v4l2_device_unregister(&dev->v4l2_dev);
++ vchiq_mmal_finalise(dev->instance);
+
+ return 0;
+ }
+++ /dev/null
-From 0c0e55d9b04868733f30c348df7400fa5e6d30e2 Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Feb 2019 12:36:56 +0000
-Subject: [PATCH] staging: mmal-vchiq: Always return the param size
- from param_get
-
-mmal-vchiq is a reimplementation of the userland library for MMAL.
-When getting a parameter, the client provides the storage and
-the size of the storage. The VPU then returns the size of the
-parameter that it wished to return, and as much as possible of
-that parameter is returned to the client.
-
-The implementation previously only returned the size provided
-by the VPU should it exceed the buffer size. So for parameters
-such as the supported encodings list the client had no idea
-how much of the provided storage had been populated.
-
----
- drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -1413,11 +1413,12 @@ static int port_parameter_get(struct vch
- */
- memcpy(value, &rmsg->u.port_parameter_get_reply.value,
- *value_size);
-- *value_size = rmsg->u.port_parameter_get_reply.size;
- } else {
- memcpy(value, &rmsg->u.port_parameter_get_reply.value,
- rmsg->u.port_parameter_get_reply.size);
- }
-+ /* Always report the size of the returned parameter to the caller */
-+ *value_size = rmsg->u.port_parameter_get_reply.size;
-
- pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
- ret, port->component->handle, port->handle, parameter_id);
--- /dev/null
+From 7afce6566802bcaa468f92b9e06da8b899161128 Mon Sep 17 00:00:00 2001
+Date: Wed, 13 Feb 2019 14:07:52 +0000
+Subject: [PATCH] staging: bcm2835_codec: Add support for the ISP as an
+ M2M device
+
+The MMAL ISP component can also use this same V4L2 wrapper to
+provide a M2M format conversion and resizer.
+Instantiate 3 V4L2 devices now, one for each of decode, encode,
+and isp.
+The ISP currently doesn't expose any controls via V4L2, but this
+can be extended in the future.
+
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 132 ++++++++++++------
+ 1 file changed, 92 insertions(+), 40 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -54,10 +54,26 @@ static int encode_video_nr = 11;
+ module_param(encode_video_nr, int, 0644);
+ MODULE_PARM_DESC(encode_video_nr, "encoder video device number");
+
++static int isp_video_nr = 12;
++module_param(isp_video_nr, int, 0644);
++MODULE_PARM_DESC(isp_video_nr, "isp video device number");
++
+ static unsigned int debug;
+ module_param(debug, uint, 0644);
+ MODULE_PARM_DESC(debug, "activates debug info (0-3)");
+
++enum bcm2835_codec_role {
++ DECODE,
++ ENCODE,
++ ISP,
++};
++
++static const char * const components[] = {
++ "ril.video_decode",
++ "ril.video_encode",
++ "ril.isp",
++};
++
+ #define MIN_W 32
+ #define MIN_H 32
+ #define MAX_W 1920
+@@ -373,7 +389,7 @@ struct bcm2835_codec_dev {
+ atomic_t num_inst;
+
+ /* allocated mmal instance and components */
+- bool decode; /* Is this instance a decoder? */
++ enum bcm2835_codec_role role;
+ /* The list of formats supported on input and output queues. */
+ struct bcm2835_codec_fmt_list supported_fmts[2];
+
+@@ -558,7 +574,7 @@ static void setup_mmal_port_format(struc
+ port->es.video.frame_rate.den = 1;
+ } else {
+ /* Compressed format - leave resolution as 0 for decode */
+- if (ctx->dev->decode) {
++ if (ctx->dev->role == DECODE) {
+ port->es.video.width = 0;
+ port->es.video.height = 0;
+ port->es.video.crop.width = 0;
+@@ -1089,7 +1105,8 @@ static int vidioc_s_fmt(struct bcm2835_c
+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n",
+ q_data->bytesperline, q_data->sizeimage);
+
+- if (ctx->dev->decode && q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
++ if (ctx->dev->role == DECODE &&
++ q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
+ f->fmt.pix.width && f->fmt.pix.height) {
+ /*
+ * On the decoder, if provided with a resolution on the input
+@@ -1188,7 +1205,8 @@ static int vidioc_g_selection(struct fil
+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+ true : false;
+
+- if (capture_queue ^ ctx->dev->decode)
++ if ((ctx->dev->role == DECODE && !capture_queue) ||
++ (ctx->dev->role == ENCODE && capture_queue))
+ /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
+ return -EINVAL;
+
+@@ -1196,7 +1214,8 @@ static int vidioc_g_selection(struct fil
+ if (!q_data)
+ return -EINVAL;
+
+- if (ctx->dev->decode) {
++ switch (ctx->dev->role) {
++ case DECODE:
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE:
+@@ -1214,7 +1233,8 @@ static int vidioc_g_selection(struct fil
+ default:
+ return -EINVAL;
+ }
+- } else {
++ break;
++ case ENCODE:
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+@@ -1232,6 +1252,9 @@ static int vidioc_g_selection(struct fil
+ default:
+ return -EINVAL;
+ }
++ break;
++ case ISP:
++ break;
+ }
+
+ return 0;
+@@ -1249,7 +1272,8 @@ static int vidioc_s_selection(struct fil
+ __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top,
+ s->r.width, s->r.height);
+
+- if (capture_queue ^ ctx->dev->decode)
++ if ((ctx->dev->role == DECODE && !capture_queue) ||
++ (ctx->dev->role == ENCODE && capture_queue))
+ /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
+ return -EINVAL;
+
+@@ -1257,7 +1281,8 @@ static int vidioc_s_selection(struct fil
+ if (!q_data)
+ return -EINVAL;
+
+- if (ctx->dev->decode) {
++ switch (ctx->dev->role) {
++ case DECODE:
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE:
+ /* Accept cropped image */
+@@ -1272,7 +1297,8 @@ static int vidioc_s_selection(struct fil
+ default:
+ return -EINVAL;
+ }
+- } else {
++ break;
++ case ENCODE:
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP:
+ /* Only support crop from (0,0) */
+@@ -1287,6 +1313,9 @@ static int vidioc_s_selection(struct fil
+ default:
+ return -EINVAL;
+ }
++ break;
++ case ISP:
++ break;
+ }
+
+ return 0;
+@@ -1490,7 +1519,7 @@ static int vidioc_try_decoder_cmd(struct
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+
+- if (!ctx->dev->decode)
++ if (ctx->dev->role != DECODE)
+ return -EINVAL;
+
+ switch (cmd->cmd) {
+@@ -1564,7 +1593,7 @@ static int vidioc_try_encoder_cmd(struct
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+
+- if (ctx->dev->decode)
++ if (ctx->dev->role != ENCODE)
+ return -EINVAL;
+
+ switch (cmd->cmd) {
+@@ -1697,12 +1726,11 @@ static int bcm2835_codec_create_componen
+ unsigned int enable = 1;
+ int ret;
+
+- ret = vchiq_mmal_component_init(dev->instance, dev->decode ?
+- "ril.video_decode" : "ril.video_encode",
++ ret = vchiq_mmal_component_init(dev->instance, components[dev->role],
+ &ctx->component);
+ if (ret < 0) {
+- v4l2_err(&dev->v4l2_dev, "%s: failed to create component for %s\n",
+- __func__, dev->decode ? "decode" : "encode");
++ v4l2_err(&dev->v4l2_dev, "%s: failed to create component %s\n",
++ __func__, components[dev->role]);
+ return -ENOMEM;
+ }
+
+@@ -1729,13 +1757,7 @@ static int bcm2835_codec_create_componen
+ if (ret < 0)
+ goto destroy_component;
+
+- if (dev->decode) {
+- if (ctx->q_data[V4L2_M2M_DST].sizeimage <
+- ctx->component->output[0].minimum_buffer.size)
+- v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
+- ctx->q_data[V4L2_M2M_DST].sizeimage,
+- ctx->component->output[0].minimum_buffer.size);
+- } else {
++ if (dev->role == ENCODE) {
+ if (ctx->q_data[V4L2_M2M_SRC].sizeimage <
+ ctx->component->output[0].minimum_buffer.size)
+ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
+@@ -1744,6 +1766,12 @@ static int bcm2835_codec_create_componen
+
+ /* Now we have a component we can set all the ctrls */
+ bcm2835_codec_set_ctrls(ctx);
++ } else {
++ if (ctx->q_data[V4L2_M2M_DST].sizeimage <
++ ctx->component->output[0].minimum_buffer.size)
++ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
++ ctx->q_data[V4L2_M2M_DST].sizeimage,
++ ctx->component->output[0].minimum_buffer.size);
+ }
+
+ return 0;
+@@ -2090,8 +2118,6 @@ static int bcm2835_codec_open(struct fil
+ struct v4l2_ctrl_handler *hdl;
+ int rc = 0;
+
+- v4l2_dbg(1, debug, &dev->v4l2_dev, "Creating instance for %s\n",
+- dev->decode ? "decode" : "encode");
+ if (mutex_lock_interruptible(&dev->dev_mutex)) {
+ v4l2_err(&dev->v4l2_dev, "Mutex fail\n");
+ return -ERESTARTSYS;
+@@ -2104,7 +2130,8 @@ static int bcm2835_codec_open(struct fil
+
+ ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false);
+ ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true);
+- if (dev->decode) {
++ switch (dev->role) {
++ case DECODE:
+ /*
+ * Input width and height are irrelevant as they will be defined
+ * by the bitstream not the format. Required by V4L2 though.
+@@ -2126,7 +2153,8 @@ static int bcm2835_codec_open(struct fil
+ get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline,
+ ctx->q_data[V4L2_M2M_DST].height,
+ ctx->q_data[V4L2_M2M_DST].fmt);
+- } else {
++ break;
++ case ENCODE:
+ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
+ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
+ ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT;
+@@ -2144,6 +2172,9 @@ static int bcm2835_codec_open(struct fil
+ ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT;
+ ctx->q_data[V4L2_M2M_DST].sizeimage =
+ DEF_COMP_BUF_SIZE_720P_OR_LESS;
++ break;
++ case ISP:
++ break;
+ }
+
+ ctx->colorspace = V4L2_COLORSPACE_REC709;
+@@ -2154,7 +2185,7 @@ static int bcm2835_codec_open(struct fil
+ file->private_data = &ctx->fh;
+ ctx->dev = dev;
+ hdl = &ctx->hdl;
+- if (!dev->decode) {
++ if (dev->role == ENCODE) {
+ /* Encode controls */
+ v4l2_ctrl_handler_init(hdl, 6);
+
+@@ -2303,14 +2334,11 @@ static int bcm2835_codec_get_supported_f
+ unsigned int i, j, num_encodings;
+ int ret;
+
+- ret = vchiq_mmal_component_init(dev->instance,
+- dev->decode ?
+- "ril.video_decode" :
+- "ril.video_encode",
++ ret = vchiq_mmal_component_init(dev->instance, components[dev->role],
+ &component);
+ if (ret < 0) {
+- v4l2_err(&dev->v4l2_dev, "%s: failed to create component\n",
+- __func__);
++ v4l2_err(&dev->v4l2_dev, "%s: failed to create component %s\n",
++ __func__, components[dev->role]);
+ return -ENOMEM;
+ }
+
+@@ -2406,12 +2434,13 @@ destroy_component:
+
+ static int bcm2835_codec_create(struct platform_device *pdev,
+ struct bcm2835_codec_dev **new_dev,
+- bool decode)
++ enum bcm2835_codec_role role)
+ {
+ struct bcm2835_codec_dev *dev;
+ struct video_device *vfd;
+ int video_nr;
+ int ret;
++ const static char *roles[] = {"decode", "encode", "isp"};
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+@@ -2419,7 +2448,7 @@ static int bcm2835_codec_create(struct p
+
+ dev->pdev = pdev;
+
+- dev->decode = decode;
++ dev->role = role;
+
+ ret = vchiq_mmal_init(&dev->instance);
+ if (ret)
+@@ -2441,14 +2470,27 @@ static int bcm2835_codec_create(struct p
+ vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+
+- if (dev->decode) {
++ switch (role) {
++ case DECODE:
+ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
+ video_nr = decode_video_nr;
+- } else {
++ break;
++ case ENCODE:
+ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
+ video_nr = encode_video_nr;
++ break;
++ case ISP:
++ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
++ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
++ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
++ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
++ video_nr = isp_video_nr;
++ break;
++ default:
++ ret = -EINVAL;
++ goto unreg_dev;
+ }
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+@@ -2473,7 +2515,7 @@ static int bcm2835_codec_create(struct p
+ }
+
+ v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n",
+- dev->decode ? "decode" : "encode");
++ roles[role]);
+ return 0;
+
+ err_m2m:
+@@ -2509,11 +2551,15 @@ static int bcm2835_codec_probe(struct pl
+ if (!drv)
+ return -ENOMEM;
+
+- ret = bcm2835_codec_create(pdev, &drv->encode, false);
++ ret = bcm2835_codec_create(pdev, &drv->decode, DECODE);
+ if (ret)
+ goto out;
+
+- ret = bcm2835_codec_create(pdev, &drv->decode, true);
++ ret = bcm2835_codec_create(pdev, &drv->encode, ENCODE);
++ if (ret)
++ goto out;
++
++ ret = bcm2835_codec_create(pdev, &drv->isp, ISP);
+ if (ret)
+ goto out;
+
+@@ -2526,6 +2572,10 @@ out:
+ bcm2835_codec_destroy(drv->encode);
+ drv->encode = NULL;
+ }
++ if (drv->decode) {
++ bcm2835_codec_destroy(drv->decode);
++ drv->decode = NULL;
++ }
+ return ret;
+ }
+
+@@ -2533,6 +2583,8 @@ static int bcm2835_codec_remove(struct p
+ {
+ struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev);
+
++ bcm2835_codec_destroy(drv->isp);
++
+ bcm2835_codec_destroy(drv->encode);
+
+ bcm2835_codec_destroy(drv->decode);
+++ /dev/null
-From 78c34cf60b9ae8bf8aa797c72d2f1abdc0a0bb9d Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Feb 2019 12:51:03 +0000
-Subject: [PATCH] staging: mmal-vchiq: If the VPU returns an error,
- don't negate it
-
-There is an enum for the errors that the VPU can return.
-port_parameter_get was negating that value, but also using -EINVAL
-from the Linux error codes.
-Pass the VPU error code as positive values. Should the function
-need to pass a Linux failure, then return that as negative.
-
----
- drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -1401,7 +1401,8 @@ static int port_parameter_get(struct vch
- goto release_msg;
- }
-
-- ret = -rmsg->u.port_parameter_get_reply.status;
-+ ret = rmsg->u.port_parameter_get_reply.status;
-+
- /* port_parameter_get_reply.size includes the header,
- * whilst *value_size doesn't.
- */
--- /dev/null
+From a126fcc4ff38718e2e714fbb78db3ca1c4f8e564 Mon Sep 17 00:00:00 2001
+Date: Fri, 15 Feb 2019 11:36:14 +0000
+Subject: [PATCH] staging: bcm2835_codec: Add an option for ignoring
+ Bayer formats.
+
+This is a workaround for GStreamer currently not identifying Bayer
+as a raw format, therefore any device that supports it does not
+match the criteria for v4l2convert.
+
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 29 ++++++++++++++++++-
+ 1 file changed, 28 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -58,6 +58,15 @@ static int isp_video_nr = 12;
+ module_param(isp_video_nr, int, 0644);
+ MODULE_PARM_DESC(isp_video_nr, "isp video device number");
+
++/*
++ * Workaround for GStreamer v4l2convert component not considering Bayer formats
++ * as raw, and therefore not considering a V4L2 device that supports them as
++ * as a suitable candidate.
++ */
++static bool disable_bayer;
++module_param(disable_bayer, bool, 0644);
++MODULE_PARM_DESC(disable_bayer, "Disable support for Bayer formats");
++
+ static unsigned int debug;
+ module_param(debug, uint, 0644);
+ MODULE_PARM_DESC(debug, "activates debug info (0-3)");
+@@ -105,6 +114,7 @@ struct bcm2835_codec_fmt {
+ u32 flags;
+ u32 mmal_fmt;
+ int size_multiplier_x2;
++ bool is_bayer;
+ };
+
+ static const struct bcm2835_codec_fmt supported_formats[] = {
+@@ -203,6 +213,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .depth = 8,
+@@ -210,6 +221,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .depth = 8,
+@@ -217,6 +229,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .depth = 8,
+@@ -224,6 +237,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ /* 10 bit */
+ .fourcc = V4L2_PIX_FMT_SRGGB10P,
+@@ -232,6 +246,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR10P,
+ .depth = 10,
+@@ -239,6 +254,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG10P,
+ .depth = 10,
+@@ -246,6 +262,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG10P,
+ .depth = 10,
+@@ -253,6 +270,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ /* 12 bit */
+ .fourcc = V4L2_PIX_FMT_SRGGB12P,
+@@ -261,6 +279,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR12P,
+ .depth = 12,
+@@ -268,6 +287,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG12P,
+ .depth = 12,
+@@ -275,6 +295,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG12P,
+ .depth = 12,
+@@ -282,6 +303,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ /* 16 bit */
+ .fourcc = V4L2_PIX_FMT_SRGGB16,
+@@ -290,6 +312,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR16,
+ .depth = 16,
+@@ -297,6 +320,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG16,
+ .depth = 16,
+@@ -304,6 +328,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG16,
+ .depth = 16,
+@@ -311,6 +336,7 @@ static const struct bcm2835_codec_fmt su
+ .flags = 0,
+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16,
+ .size_multiplier_x2 = 2,
++ .is_bayer = true,
+ }, {
+ /* Compressed formats */
+ .fourcc = V4L2_PIX_FMT_H264,
+@@ -438,7 +464,8 @@ static const struct bcm2835_codec_fmt *g
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
+- if (supported_formats[i].mmal_fmt == mmal_fmt)
++ if (supported_formats[i].mmal_fmt == mmal_fmt &&
++ (!disable_bayer || !supported_formats[i].is_bayer))
+ return &supported_formats[i];
+ }
+ return NULL;
+++ /dev/null
-From ce8cc7a85839af588b753ce4af0832db9c467f45 Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Feb 2019 13:44:00 +0000
-Subject: [PATCH] staging: bcm2835_codec: Query supported formats from
- the component
-
-The driver was previously working with hard coded tables of
-which video formats were supported by each component.
-The components advertise this information via a MMAL parameter,
-so retrieve the information from there during probe, and store
-in the state structure for that device.
-
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 455 +++++++++++++-----
- 1 file changed, 327 insertions(+), 128 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -88,17 +88,12 @@ struct bcm2835_codec_fmt {
- int bytesperline_align;
- u32 flags;
- u32 mmal_fmt;
-- bool decode_only;
-- bool encode_only;
- int size_multiplier_x2;
- };
-
--/* Supported raw pixel formats. Those supported for both encode and decode
-- * must come first, with those only supported for decode coming after (there
-- * are no formats supported for encode only).
-- */
--static struct bcm2835_codec_fmt raw_formats[] = {
-+static const struct bcm2835_codec_fmt supported_formats[] = {
- {
-+ /* YUV formats */
- .fourcc = V4L2_PIX_FMT_YUV420,
- .depth = 8,
- .bytesperline_align = 32,
-@@ -139,7 +134,6 @@ static struct bcm2835_codec_fmt raw_form
- .bytesperline_align = 32,
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_YUYV,
-- .encode_only = true,
- .size_multiplier_x2 = 2,
- }, {
- .fourcc = V4L2_PIX_FMT_UYVY,
-@@ -147,7 +141,6 @@ static struct bcm2835_codec_fmt raw_form
- .bytesperline_align = 32,
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_UYVY,
-- .encode_only = true,
- .size_multiplier_x2 = 2,
- }, {
- .fourcc = V4L2_PIX_FMT_YVYU,
-@@ -155,7 +148,6 @@ static struct bcm2835_codec_fmt raw_form
- .bytesperline_align = 32,
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_YVYU,
-- .encode_only = true,
- .size_multiplier_x2 = 2,
- }, {
- .fourcc = V4L2_PIX_FMT_VYUY,
-@@ -163,15 +155,14 @@ static struct bcm2835_codec_fmt raw_form
- .bytesperline_align = 32,
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_VYUY,
-- .encode_only = true,
- .size_multiplier_x2 = 2,
- }, {
-+ /* RGB formats */
- .fourcc = V4L2_PIX_FMT_RGB24,
- .depth = 24,
- .bytesperline_align = 32,
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_RGB24,
-- .encode_only = true,
- .size_multiplier_x2 = 2,
- }, {
- .fourcc = V4L2_PIX_FMT_BGR24,
-@@ -179,7 +170,6 @@ static struct bcm2835_codec_fmt raw_form
- .bytesperline_align = 32,
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BGR24,
-- .encode_only = true,
- .size_multiplier_x2 = 2,
- }, {
- .fourcc = V4L2_PIX_FMT_BGR32,
-@@ -187,17 +177,126 @@ static struct bcm2835_codec_fmt raw_form
- .bytesperline_align = 32,
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BGRA,
-- .encode_only = true,
- .size_multiplier_x2 = 2,
-- },
--};
--
--/* Supported encoded formats. Those supported for both encode and decode
-- * must come first, with those only supported for decode coming after (there
-- * are no formats supported for encode only).
-- */
--static struct bcm2835_codec_fmt encoded_formats[] = {
-- {
-+ }, {
-+ /* Bayer formats */
-+ /* 8 bit */
-+ .fourcc = V4L2_PIX_FMT_SRGGB8,
-+ .depth = 8,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SBGGR8,
-+ .depth = 8,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SGRBG8,
-+ .depth = 8,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SGBRG8,
-+ .depth = 8,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ /* 10 bit */
-+ .fourcc = V4L2_PIX_FMT_SRGGB10P,
-+ .depth = 10,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SBGGR10P,
-+ .depth = 10,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SGRBG10P,
-+ .depth = 10,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SGBRG10P,
-+ .depth = 10,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ /* 12 bit */
-+ .fourcc = V4L2_PIX_FMT_SRGGB12P,
-+ .depth = 12,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SBGGR12P,
-+ .depth = 12,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SGRBG12P,
-+ .depth = 12,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SGBRG12P,
-+ .depth = 12,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ /* 16 bit */
-+ .fourcc = V4L2_PIX_FMT_SRGGB16,
-+ .depth = 16,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SBGGR16,
-+ .depth = 16,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SGRBG16,
-+ .depth = 16,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SGBRG16,
-+ .depth = 16,
-+ .bytesperline_align = 32,
-+ .flags = 0,
-+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16,
-+ .size_multiplier_x2 = 2,
-+ }, {
-+ /* Compressed formats */
- .fourcc = V4L2_PIX_FMT_H264,
- .depth = 0,
- .flags = V4L2_FMT_FLAG_COMPRESSED,
-@@ -212,30 +311,22 @@ static struct bcm2835_codec_fmt encoded_
- .depth = 0,
- .flags = V4L2_FMT_FLAG_COMPRESSED,
- .mmal_fmt = MMAL_ENCODING_MP4V,
-- .decode_only = true,
- }, {
- .fourcc = V4L2_PIX_FMT_H263,
- .depth = 0,
- .flags = V4L2_FMT_FLAG_COMPRESSED,
- .mmal_fmt = MMAL_ENCODING_H263,
-- .decode_only = true,
- }, {
- .fourcc = V4L2_PIX_FMT_MPEG2,
- .depth = 0,
- .flags = V4L2_FMT_FLAG_COMPRESSED,
- .mmal_fmt = MMAL_ENCODING_MP2V,
-- .decode_only = true,
- }, {
- .fourcc = V4L2_PIX_FMT_VP8,
- .depth = 0,
- .flags = V4L2_FMT_FLAG_COMPRESSED,
- .mmal_fmt = MMAL_ENCODING_VP8,
-- .decode_only = true,
- },
-- /*
-- * This list couold include VP6 and Theorafor decode, but V4L2 doesn't
-- * support them.
-- */
- };
-
- struct bcm2835_codec_fmt_list {
-@@ -243,19 +334,6 @@ struct bcm2835_codec_fmt_list {
- unsigned int num_entries;
- };
-
--#define RAW_LIST 0
--#define ENCODED_LIST 1
--
--struct bcm2835_codec_fmt_list formats[] = {
-- {
-- .list = raw_formats,
-- .num_entries = ARRAY_SIZE(raw_formats),
-- }, {
-- .list = encoded_formats,
-- .num_entries = ARRAY_SIZE(encoded_formats),
-- },
--};
--
- struct m2m_mmal_buffer {
- struct v4l2_m2m_buffer m2m;
- struct mmal_buffer mmal;
-@@ -284,52 +362,6 @@ struct bcm2835_codec_q_data {
- bool eos_buffer_in_use; /* debug only */
- };
-
--enum {
-- V4L2_M2M_SRC = 0,
-- V4L2_M2M_DST = 1,
--};
--
--static inline struct bcm2835_codec_fmt_list *get_format_list(bool decode,
-- bool capture)
--{
-- return decode ^ capture ? &formats[ENCODED_LIST] : &formats[RAW_LIST];
--}
--
--static struct bcm2835_codec_fmt *get_default_format(bool decode, bool capture)
--{
-- return &get_format_list(decode, capture)->list[0];
--}
--
--static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, bool decode,
-- bool capture)
--{
-- struct bcm2835_codec_fmt *fmt;
-- unsigned int k;
-- struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
--
-- for (k = 0; k < fmts->num_entries; k++) {
-- fmt = &fmts->list[k];
-- if (fmt->fourcc == f->fmt.pix.pixelformat)
-- break;
-- }
--
-- /*
-- * Some compressed formats are only supported for decoding, not
-- * encoding.
-- */
-- if (!decode && fmts->list[k].decode_only)
-- return NULL;
--
-- /* Some pixel formats are only supported for encoding, not decoding. */
-- if (decode && fmts->list[k].encode_only)
-- return NULL;
--
-- if (k == fmts->num_entries)
-- return NULL;
--
-- return &fmts->list[k];
--}
--
- struct bcm2835_codec_dev {
- struct platform_device *pdev;
-
-@@ -342,6 +374,9 @@ struct bcm2835_codec_dev {
-
- /* allocated mmal instance and components */
- bool decode; /* Is this instance a decoder? */
-+ /* The list of formats supported on input and output queues. */
-+ struct bcm2835_codec_fmt_list supported_fmts[2];
-+
- struct vchiq_mmal_instance *instance;
-
- struct v4l2_m2m_dev *m2m_dev;
-@@ -374,8 +409,59 @@ struct bcm2835_codec_ctx {
- struct bcm2835_codec_driver {
- struct bcm2835_codec_dev *encode;
- struct bcm2835_codec_dev *decode;
-+ struct bcm2835_codec_dev *isp;
-+};
-+
-+enum {
-+ V4L2_M2M_SRC = 0,
-+ V4L2_M2M_DST = 1,
- };
-
-+static const struct bcm2835_codec_fmt *get_fmt(u32 mmal_fmt)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
-+ if (supported_formats[i].mmal_fmt == mmal_fmt)
-+ return &supported_formats[i];
-+ }
-+ return NULL;
-+}
-+
-+static inline
-+struct bcm2835_codec_fmt_list *get_format_list(struct bcm2835_codec_dev *dev,
-+ bool capture)
-+{
-+ return &dev->supported_fmts[capture ? 1 : 0];
-+}
-+
-+static
-+struct bcm2835_codec_fmt *get_default_format(struct bcm2835_codec_dev *dev,
-+ bool capture)
-+{
-+ return &dev->supported_fmts[capture ? 1 : 0].list[0];
-+}
-+
-+static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
-+ struct bcm2835_codec_dev *dev,
-+ bool capture)
-+{
-+ struct bcm2835_codec_fmt *fmt;
-+ unsigned int k;
-+ struct bcm2835_codec_fmt_list *fmts =
-+ &dev->supported_fmts[capture ? 1 : 0];
-+
-+ for (k = 0; k < fmts->num_entries; k++) {
-+ fmt = &fmts->list[k];
-+ if (fmt->fourcc == f->fmt.pix.pixelformat)
-+ break;
-+ }
-+ if (k == fmts->num_entries)
-+ return NULL;
-+
-+ return &fmts->list[k];
-+}
-+
- static inline struct bcm2835_codec_ctx *file2ctx(struct file *file)
- {
- return container_of(file->private_data, struct bcm2835_codec_ctx, fh);
-@@ -456,7 +542,6 @@ static inline unsigned int get_bytesperl
- }
-
- static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx,
-- bool decode,
- struct bcm2835_codec_q_data *q_data,
- struct vchiq_mmal_port *port)
- {
-@@ -473,7 +558,7 @@ static void setup_mmal_port_format(struc
- port->es.video.frame_rate.den = 1;
- } else {
- /* Compressed format - leave resolution as 0 for decode */
-- if (decode) {
-+ if (ctx->dev->decode) {
- port->es.video.width = 0;
- port->es.video.height = 0;
- port->es.video.crop.width = 0;
-@@ -802,22 +887,15 @@ static int vidioc_querycap(struct file *
- return 0;
- }
-
--static int enum_fmt(struct v4l2_fmtdesc *f, bool decode, bool capture)
-+static int enum_fmt(struct v4l2_fmtdesc *f, struct bcm2835_codec_ctx *ctx,
-+ bool capture)
- {
- struct bcm2835_codec_fmt *fmt;
-- struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture);
-+ struct bcm2835_codec_fmt_list *fmts =
-+ get_format_list(ctx->dev, capture);
-
- if (f->index < fmts->num_entries) {
- /* Format found */
-- /* Check format isn't a decode only format when encoding */
-- if (!decode &&
-- fmts->list[f->index].decode_only)
-- return -EINVAL;
-- /* Check format isn't a decode only format when encoding */
-- if (decode &&
-- fmts->list[f->index].encode_only)
-- return -EINVAL;
--
- fmt = &fmts->list[f->index];
- f->pixelformat = fmt->fourcc;
- f->flags = fmt->flags;
-@@ -833,7 +911,7 @@ static int vidioc_enum_fmt_vid_cap(struc
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
-
-- return enum_fmt(f, ctx->dev->decode, true);
-+ return enum_fmt(f, ctx, true);
- }
-
- static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
-@@ -841,7 +919,7 @@ static int vidioc_enum_fmt_vid_out(struc
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
-
-- return enum_fmt(f, ctx->dev->decode, false);
-+ return enum_fmt(f, ctx, false);
- }
-
- static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f)
-@@ -933,11 +1011,11 @@ static int vidioc_try_fmt_vid_cap(struct
- struct bcm2835_codec_fmt *fmt;
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
-
-- fmt = find_format(f, ctx->dev->decode, true);
-+ fmt = find_format(f, ctx->dev, true);
- if (!fmt) {
-- f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
-+ f->fmt.pix.pixelformat = get_default_format(ctx->dev,
- true)->fourcc;
-- fmt = find_format(f, ctx->dev->decode, true);
-+ fmt = find_format(f, ctx->dev, true);
- }
-
- return vidioc_try_fmt(f, fmt);
-@@ -949,11 +1027,11 @@ static int vidioc_try_fmt_vid_out(struct
- struct bcm2835_codec_fmt *fmt;
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
-
-- fmt = find_format(f, ctx->dev->decode, false);
-+ fmt = find_format(f, ctx->dev, false);
- if (!fmt) {
-- f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode,
-+ f->fmt.pix.pixelformat = get_default_format(ctx->dev,
- false)->fourcc;
-- fmt = find_format(f, ctx->dev->decode, false);
-+ fmt = find_format(f, ctx->dev, false);
- }
-
- if (!f->fmt.pix.colorspace)
-@@ -988,7 +1066,7 @@ static int vidioc_s_fmt(struct bcm2835_c
- return -EBUSY;
- }
-
-- q_data->fmt = find_format(f, ctx->dev->decode,
-+ q_data->fmt = find_format(f, ctx->dev,
- f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
- q_data->crop_width = f->fmt.pix.width;
- q_data->height = f->fmt.pix.height;
-@@ -1041,7 +1119,7 @@ static int vidioc_s_fmt(struct bcm2835_c
- if (!port)
- return 0;
-
-- setup_mmal_port_format(ctx, ctx->dev->decode, q_data, port);
-+ setup_mmal_port_format(ctx, q_data, port);
- ret = vchiq_mmal_port_set_format(ctx->dev->instance, port);
- if (ret) {
- v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n",
-@@ -1064,8 +1142,7 @@ static int vidioc_s_fmt(struct bcm2835_c
- struct bcm2835_codec_q_data *q_data_dst =
- &ctx->q_data[V4L2_M2M_DST];
-
-- setup_mmal_port_format(ctx, ctx->dev->decode, q_data_dst,
-- port_dst);
-+ setup_mmal_port_format(ctx, q_data_dst, port_dst);
- ret = vchiq_mmal_port_set_format(ctx->dev->instance, port_dst);
- if (ret) {
- v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on output port, ret %d\n",
-@@ -1636,10 +1713,10 @@ static int bcm2835_codec_create_componen
- MMAL_PARAMETER_ZERO_COPY, &enable,
- sizeof(enable));
-
-- setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_SRC],
-+ setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_SRC],
- &ctx->component->input[0]);
-
-- setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_DST],
-+ setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_DST],
- &ctx->component->output[0]);
-
- ret = vchiq_mmal_port_set_format(dev->instance,
-@@ -2025,8 +2102,8 @@ static int bcm2835_codec_open(struct fil
- goto open_unlock;
- }
-
-- ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev->decode, false);
-- ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev->decode, true);
-+ ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false);
-+ ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true);
- if (dev->decode) {
- /*
- * Input width and height are irrelevant as they will be defined
-@@ -2209,13 +2286,130 @@ static const struct v4l2_m2m_ops m2m_ops
- .job_abort = job_abort,
- };
-
-+/* Size of the array to provide to the VPU when asking for the list of supported
-+ * formats.
-+ * The ISP component currently advertises 33 input formats, so add a small
-+ * overhead on that.
-+ */
-+#define MAX_SUPPORTED_ENCODINGS 40
-+
-+/* Populate dev->supported_fmts with the formats supported by those ports. */
-+static int bcm2835_codec_get_supported_fmts(struct bcm2835_codec_dev *dev)
-+{
-+ struct bcm2835_codec_fmt *list;
-+ struct vchiq_mmal_component *component;
-+ u32 fourccs[MAX_SUPPORTED_ENCODINGS];
-+ u32 param_size = sizeof(fourccs);
-+ unsigned int i, j, num_encodings;
-+ int ret;
-+
-+ ret = vchiq_mmal_component_init(dev->instance,
-+ dev->decode ?
-+ "ril.video_decode" :
-+ "ril.video_encode",
-+ &component);
-+ if (ret < 0) {
-+ v4l2_err(&dev->v4l2_dev, "%s: failed to create component\n",
-+ __func__);
-+ return -ENOMEM;
-+ }
-+
-+ ret = vchiq_mmal_port_parameter_get(dev->instance,
-+ &component->input[0],
-+ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
-+ &fourccs,
-+ ¶m_size);
-+
-+ if (ret) {
-+ if (ret == MMAL_MSG_STATUS_ENOSPC) {
-+ v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n",
-+ __func__);
-+ num_encodings = MAX_SUPPORTED_ENCODINGS;
-+ } else {
-+ v4l2_err(&dev->v4l2_dev, "%s: get_param ret %u.\n",
-+ __func__, ret);
-+ ret = -EINVAL;
-+ goto destroy_component;
-+ }
-+ } else {
-+ num_encodings = param_size / sizeof(u32);
-+ }
-+
-+ /* Assume at this stage that all encodings will be supported in V4L2.
-+ * Any that aren't supported will waste a very small amount of memory.
-+ */
-+ list = devm_kzalloc(&dev->pdev->dev,
-+ sizeof(struct bcm2835_codec_fmt) * num_encodings,
-+ GFP_KERNEL);
-+ if (!list) {
-+ ret = -ENOMEM;
-+ goto destroy_component;
-+ }
-+ dev->supported_fmts[0].list = list;
-+
-+ for (i = 0, j = 0; i < num_encodings; i++) {
-+ const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]);
-+
-+ if (fmt) {
-+ list[j] = *fmt;
-+ j++;
-+ }
-+ }
-+ dev->supported_fmts[0].num_entries = j;
-+
-+ param_size = sizeof(fourccs);
-+ ret = vchiq_mmal_port_parameter_get(dev->instance,
-+ &component->output[0],
-+ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
-+ &fourccs,
-+ ¶m_size);
-+
-+ if (ret) {
-+ if (ret == MMAL_MSG_STATUS_ENOSPC) {
-+ v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n",
-+ __func__);
-+ num_encodings = MAX_SUPPORTED_ENCODINGS;
-+ } else {
-+ ret = -EINVAL;
-+ goto destroy_component;
-+ }
-+ } else {
-+ num_encodings = param_size / sizeof(u32);
-+ }
-+ /* Assume at this stage that all encodings will be supported in V4L2. */
-+ list = devm_kzalloc(&dev->pdev->dev,
-+ sizeof(struct bcm2835_codec_fmt) * num_encodings,
-+ GFP_KERNEL);
-+ if (!list) {
-+ ret = -ENOMEM;
-+ goto destroy_component;
-+ }
-+ dev->supported_fmts[1].list = list;
-+
-+ for (i = 0, j = 0; i < num_encodings; i++) {
-+ const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]);
-+
-+ if (fmt) {
-+ list[j] = *fmt;
-+ j++;
-+ }
-+ }
-+ dev->supported_fmts[1].num_entries = j;
-+
-+ ret = 0;
-+
-+destroy_component:
-+ vchiq_mmal_component_finalise(dev->instance, component);
-+
-+ return ret;
-+}
-+
- static int bcm2835_codec_create(struct platform_device *pdev,
- struct bcm2835_codec_dev **new_dev,
- bool decode)
- {
- struct bcm2835_codec_dev *dev;
- struct video_device *vfd;
-- struct vchiq_mmal_instance *instance = NULL;
- int video_nr;
- int ret;
-
-@@ -2227,10 +2421,18 @@ static int bcm2835_codec_create(struct p
-
- dev->decode = decode;
-
-- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-+ ret = vchiq_mmal_init(&dev->instance);
- if (ret)
- return ret;
-
-+ ret = bcm2835_codec_get_supported_fmts(dev);
-+ if (ret)
-+ goto vchiq_finalise;
-+
-+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-+ if (ret)
-+ goto vchiq_finalise;
-+
- atomic_set(&dev->num_inst, 0);
- mutex_init(&dev->dev_mutex);
-
-@@ -2270,12 +2472,7 @@ static int bcm2835_codec_create(struct p
- goto err_m2m;
- }
-
-- ret = vchiq_mmal_init(&instance);
-- if (ret < 0)
-- goto err_m2m;
-- dev->instance = instance;
--
-- v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s codec\n",
-+ v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n",
- dev->decode ? "decode" : "encode");
- return 0;
-
-@@ -2284,7 +2481,8 @@ err_m2m:
- video_unregister_device(&dev->vfd);
- unreg_dev:
- v4l2_device_unregister(&dev->v4l2_dev);
--
-+vchiq_finalise:
-+ vchiq_mmal_finalise(dev->instance);
- return ret;
- }
-
-@@ -2297,6 +2495,7 @@ static int bcm2835_codec_destroy(struct
- v4l2_m2m_release(dev->m2m_dev);
- video_unregister_device(&dev->vfd);
- v4l2_device_unregister(&dev->v4l2_dev);
-+ vchiq_mmal_finalise(dev->instance);
-
- return 0;
- }
+++ /dev/null
-From 7afce6566802bcaa468f92b9e06da8b899161128 Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Feb 2019 14:07:52 +0000
-Subject: [PATCH] staging: bcm2835_codec: Add support for the ISP as an
- M2M device
-
-The MMAL ISP component can also use this same V4L2 wrapper to
-provide a M2M format conversion and resizer.
-Instantiate 3 V4L2 devices now, one for each of decode, encode,
-and isp.
-The ISP currently doesn't expose any controls via V4L2, but this
-can be extended in the future.
-
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 132 ++++++++++++------
- 1 file changed, 92 insertions(+), 40 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -54,10 +54,26 @@ static int encode_video_nr = 11;
- module_param(encode_video_nr, int, 0644);
- MODULE_PARM_DESC(encode_video_nr, "encoder video device number");
-
-+static int isp_video_nr = 12;
-+module_param(isp_video_nr, int, 0644);
-+MODULE_PARM_DESC(isp_video_nr, "isp video device number");
-+
- static unsigned int debug;
- module_param(debug, uint, 0644);
- MODULE_PARM_DESC(debug, "activates debug info (0-3)");
-
-+enum bcm2835_codec_role {
-+ DECODE,
-+ ENCODE,
-+ ISP,
-+};
-+
-+static const char * const components[] = {
-+ "ril.video_decode",
-+ "ril.video_encode",
-+ "ril.isp",
-+};
-+
- #define MIN_W 32
- #define MIN_H 32
- #define MAX_W 1920
-@@ -373,7 +389,7 @@ struct bcm2835_codec_dev {
- atomic_t num_inst;
-
- /* allocated mmal instance and components */
-- bool decode; /* Is this instance a decoder? */
-+ enum bcm2835_codec_role role;
- /* The list of formats supported on input and output queues. */
- struct bcm2835_codec_fmt_list supported_fmts[2];
-
-@@ -558,7 +574,7 @@ static void setup_mmal_port_format(struc
- port->es.video.frame_rate.den = 1;
- } else {
- /* Compressed format - leave resolution as 0 for decode */
-- if (ctx->dev->decode) {
-+ if (ctx->dev->role == DECODE) {
- port->es.video.width = 0;
- port->es.video.height = 0;
- port->es.video.crop.width = 0;
-@@ -1089,7 +1105,8 @@ static int vidioc_s_fmt(struct bcm2835_c
- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n",
- q_data->bytesperline, q_data->sizeimage);
-
-- if (ctx->dev->decode && q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
-+ if (ctx->dev->role == DECODE &&
-+ q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
- f->fmt.pix.width && f->fmt.pix.height) {
- /*
- * On the decoder, if provided with a resolution on the input
-@@ -1188,7 +1205,8 @@ static int vidioc_g_selection(struct fil
- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
- true : false;
-
-- if (capture_queue ^ ctx->dev->decode)
-+ if ((ctx->dev->role == DECODE && !capture_queue) ||
-+ (ctx->dev->role == ENCODE && capture_queue))
- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
- return -EINVAL;
-
-@@ -1196,7 +1214,8 @@ static int vidioc_g_selection(struct fil
- if (!q_data)
- return -EINVAL;
-
-- if (ctx->dev->decode) {
-+ switch (ctx->dev->role) {
-+ case DECODE:
- switch (s->target) {
- case V4L2_SEL_TGT_COMPOSE_DEFAULT:
- case V4L2_SEL_TGT_COMPOSE:
-@@ -1214,7 +1233,8 @@ static int vidioc_g_selection(struct fil
- default:
- return -EINVAL;
- }
-- } else {
-+ break;
-+ case ENCODE:
- switch (s->target) {
- case V4L2_SEL_TGT_CROP_DEFAULT:
- case V4L2_SEL_TGT_CROP_BOUNDS:
-@@ -1232,6 +1252,9 @@ static int vidioc_g_selection(struct fil
- default:
- return -EINVAL;
- }
-+ break;
-+ case ISP:
-+ break;
- }
-
- return 0;
-@@ -1249,7 +1272,8 @@ static int vidioc_s_selection(struct fil
- __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top,
- s->r.width, s->r.height);
-
-- if (capture_queue ^ ctx->dev->decode)
-+ if ((ctx->dev->role == DECODE && !capture_queue) ||
-+ (ctx->dev->role == ENCODE && capture_queue))
- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
- return -EINVAL;
-
-@@ -1257,7 +1281,8 @@ static int vidioc_s_selection(struct fil
- if (!q_data)
- return -EINVAL;
-
-- if (ctx->dev->decode) {
-+ switch (ctx->dev->role) {
-+ case DECODE:
- switch (s->target) {
- case V4L2_SEL_TGT_COMPOSE:
- /* Accept cropped image */
-@@ -1272,7 +1297,8 @@ static int vidioc_s_selection(struct fil
- default:
- return -EINVAL;
- }
-- } else {
-+ break;
-+ case ENCODE:
- switch (s->target) {
- case V4L2_SEL_TGT_CROP:
- /* Only support crop from (0,0) */
-@@ -1287,6 +1313,9 @@ static int vidioc_s_selection(struct fil
- default:
- return -EINVAL;
- }
-+ break;
-+ case ISP:
-+ break;
- }
-
- return 0;
-@@ -1490,7 +1519,7 @@ static int vidioc_try_decoder_cmd(struct
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
-
-- if (!ctx->dev->decode)
-+ if (ctx->dev->role != DECODE)
- return -EINVAL;
-
- switch (cmd->cmd) {
-@@ -1564,7 +1593,7 @@ static int vidioc_try_encoder_cmd(struct
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
-
-- if (ctx->dev->decode)
-+ if (ctx->dev->role != ENCODE)
- return -EINVAL;
-
- switch (cmd->cmd) {
-@@ -1697,12 +1726,11 @@ static int bcm2835_codec_create_componen
- unsigned int enable = 1;
- int ret;
-
-- ret = vchiq_mmal_component_init(dev->instance, dev->decode ?
-- "ril.video_decode" : "ril.video_encode",
-+ ret = vchiq_mmal_component_init(dev->instance, components[dev->role],
- &ctx->component);
- if (ret < 0) {
-- v4l2_err(&dev->v4l2_dev, "%s: failed to create component for %s\n",
-- __func__, dev->decode ? "decode" : "encode");
-+ v4l2_err(&dev->v4l2_dev, "%s: failed to create component %s\n",
-+ __func__, components[dev->role]);
- return -ENOMEM;
- }
-
-@@ -1729,13 +1757,7 @@ static int bcm2835_codec_create_componen
- if (ret < 0)
- goto destroy_component;
-
-- if (dev->decode) {
-- if (ctx->q_data[V4L2_M2M_DST].sizeimage <
-- ctx->component->output[0].minimum_buffer.size)
-- v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
-- ctx->q_data[V4L2_M2M_DST].sizeimage,
-- ctx->component->output[0].minimum_buffer.size);
-- } else {
-+ if (dev->role == ENCODE) {
- if (ctx->q_data[V4L2_M2M_SRC].sizeimage <
- ctx->component->output[0].minimum_buffer.size)
- v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
-@@ -1744,6 +1766,12 @@ static int bcm2835_codec_create_componen
-
- /* Now we have a component we can set all the ctrls */
- bcm2835_codec_set_ctrls(ctx);
-+ } else {
-+ if (ctx->q_data[V4L2_M2M_DST].sizeimage <
-+ ctx->component->output[0].minimum_buffer.size)
-+ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
-+ ctx->q_data[V4L2_M2M_DST].sizeimage,
-+ ctx->component->output[0].minimum_buffer.size);
- }
-
- return 0;
-@@ -2090,8 +2118,6 @@ static int bcm2835_codec_open(struct fil
- struct v4l2_ctrl_handler *hdl;
- int rc = 0;
-
-- v4l2_dbg(1, debug, &dev->v4l2_dev, "Creating instance for %s\n",
-- dev->decode ? "decode" : "encode");
- if (mutex_lock_interruptible(&dev->dev_mutex)) {
- v4l2_err(&dev->v4l2_dev, "Mutex fail\n");
- return -ERESTARTSYS;
-@@ -2104,7 +2130,8 @@ static int bcm2835_codec_open(struct fil
-
- ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false);
- ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true);
-- if (dev->decode) {
-+ switch (dev->role) {
-+ case DECODE:
- /*
- * Input width and height are irrelevant as they will be defined
- * by the bitstream not the format. Required by V4L2 though.
-@@ -2126,7 +2153,8 @@ static int bcm2835_codec_open(struct fil
- get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline,
- ctx->q_data[V4L2_M2M_DST].height,
- ctx->q_data[V4L2_M2M_DST].fmt);
-- } else {
-+ break;
-+ case ENCODE:
- ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
- ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
- ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT;
-@@ -2144,6 +2172,9 @@ static int bcm2835_codec_open(struct fil
- ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT;
- ctx->q_data[V4L2_M2M_DST].sizeimage =
- DEF_COMP_BUF_SIZE_720P_OR_LESS;
-+ break;
-+ case ISP:
-+ break;
- }
-
- ctx->colorspace = V4L2_COLORSPACE_REC709;
-@@ -2154,7 +2185,7 @@ static int bcm2835_codec_open(struct fil
- file->private_data = &ctx->fh;
- ctx->dev = dev;
- hdl = &ctx->hdl;
-- if (!dev->decode) {
-+ if (dev->role == ENCODE) {
- /* Encode controls */
- v4l2_ctrl_handler_init(hdl, 6);
-
-@@ -2303,14 +2334,11 @@ static int bcm2835_codec_get_supported_f
- unsigned int i, j, num_encodings;
- int ret;
-
-- ret = vchiq_mmal_component_init(dev->instance,
-- dev->decode ?
-- "ril.video_decode" :
-- "ril.video_encode",
-+ ret = vchiq_mmal_component_init(dev->instance, components[dev->role],
- &component);
- if (ret < 0) {
-- v4l2_err(&dev->v4l2_dev, "%s: failed to create component\n",
-- __func__);
-+ v4l2_err(&dev->v4l2_dev, "%s: failed to create component %s\n",
-+ __func__, components[dev->role]);
- return -ENOMEM;
- }
-
-@@ -2406,12 +2434,13 @@ destroy_component:
-
- static int bcm2835_codec_create(struct platform_device *pdev,
- struct bcm2835_codec_dev **new_dev,
-- bool decode)
-+ enum bcm2835_codec_role role)
- {
- struct bcm2835_codec_dev *dev;
- struct video_device *vfd;
- int video_nr;
- int ret;
-+ const static char *roles[] = {"decode", "encode", "isp"};
-
- dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
- if (!dev)
-@@ -2419,7 +2448,7 @@ static int bcm2835_codec_create(struct p
-
- dev->pdev = pdev;
-
-- dev->decode = decode;
-+ dev->role = role;
-
- ret = vchiq_mmal_init(&dev->instance);
- if (ret)
-@@ -2441,14 +2470,27 @@ static int bcm2835_codec_create(struct p
- vfd->lock = &dev->dev_mutex;
- vfd->v4l2_dev = &dev->v4l2_dev;
-
-- if (dev->decode) {
-+ switch (role) {
-+ case DECODE:
- v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
- video_nr = decode_video_nr;
-- } else {
-+ break;
-+ case ENCODE:
- v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
- video_nr = encode_video_nr;
-+ break;
-+ case ISP:
-+ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
-+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
-+ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
-+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
-+ video_nr = isp_video_nr;
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ goto unreg_dev;
- }
-
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
-@@ -2473,7 +2515,7 @@ static int bcm2835_codec_create(struct p
- }
-
- v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n",
-- dev->decode ? "decode" : "encode");
-+ roles[role]);
- return 0;
-
- err_m2m:
-@@ -2509,11 +2551,15 @@ static int bcm2835_codec_probe(struct pl
- if (!drv)
- return -ENOMEM;
-
-- ret = bcm2835_codec_create(pdev, &drv->encode, false);
-+ ret = bcm2835_codec_create(pdev, &drv->decode, DECODE);
- if (ret)
- goto out;
-
-- ret = bcm2835_codec_create(pdev, &drv->decode, true);
-+ ret = bcm2835_codec_create(pdev, &drv->encode, ENCODE);
-+ if (ret)
-+ goto out;
-+
-+ ret = bcm2835_codec_create(pdev, &drv->isp, ISP);
- if (ret)
- goto out;
-
-@@ -2526,6 +2572,10 @@ out:
- bcm2835_codec_destroy(drv->encode);
- drv->encode = NULL;
- }
-+ if (drv->decode) {
-+ bcm2835_codec_destroy(drv->decode);
-+ drv->decode = NULL;
-+ }
- return ret;
- }
-
-@@ -2533,6 +2583,8 @@ static int bcm2835_codec_remove(struct p
- {
- struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev);
-
-+ bcm2835_codec_destroy(drv->isp);
-+
- bcm2835_codec_destroy(drv->encode);
-
- bcm2835_codec_destroy(drv->decode);
--- /dev/null
+From 0df32e2f563123166c20677f022d4a0f825c5df2 Mon Sep 17 00:00:00 2001
+Date: Fri, 15 Feb 2019 11:38:45 +0000
+Subject: [PATCH] staging: bcm2835_codec: Fix handling of
+ VB2_MEMORY_DMABUF buffers
+
+If the queue is configured as VB2_MEMORY_DMABUF then vb2_core_expbuf
+fails as it ensures the queue is defined as VB2_MEMORY_MMAP.
+
+Correct the handling so that we unmap the buffer from vcsm and the
+VPU on cleanup, and then correctly get the dma buf of the new buffer.
+
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 80 +++++++++++++------
+ .../vc04_services/vchiq-mmal/mmal-vchiq.c | 21 +++--
+ .../vc04_services/vchiq-mmal/mmal-vchiq.h | 2 +
+ 3 files changed, 73 insertions(+), 30 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1852,6 +1852,18 @@ static int bcm2835_codec_queue_setup(str
+ return 0;
+ }
+
++static int bcm2835_codec_mmal_buf_cleanup(struct mmal_buffer *mmal_buf)
++{
++ mmal_vchi_buffer_cleanup(mmal_buf);
++
++ if (mmal_buf->dma_buf) {
++ dma_buf_put(mmal_buf->dma_buf);
++ mmal_buf->dma_buf = NULL;
++ }
++
++ return 0;
++}
++
+ static int bcm2835_codec_buf_init(struct vb2_buffer *vb)
+ {
+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+@@ -1880,6 +1892,7 @@ static int bcm2835_codec_buf_prepare(str
+ vb);
+ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer,
+ m2m);
++ struct dma_buf *dma_buf;
+ int ret;
+
+ v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p\n",
+@@ -1906,20 +1919,48 @@ static int bcm2835_codec_buf_prepare(str
+ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type))
+ vb2_set_plane_payload(vb, 0, q_data->sizeimage);
+
+- /*
+- * We want to do this at init, but vb2_core_expbuf checks that the
+- * index < q->num_buffers, and q->num_buffers only gets updated once
+- * all the buffers are allocated.
+- */
+- if (!buf->mmal.dma_buf) {
+- ret = vb2_core_expbuf_dmabuf(vb->vb2_queue,
+- vb->vb2_queue->type, vb->index, 0,
+- O_CLOEXEC, &buf->mmal.dma_buf);
+- if (ret)
+- v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed to expbuf idx %d, ret %d\n",
+- __func__, vb->index, ret);
+- } else {
++ switch (vb->memory) {
++ case VB2_MEMORY_DMABUF:
++ dma_buf = dma_buf_get(vb->planes[0].m.fd);
++
++ if (dma_buf != buf->mmal.dma_buf) {
++ /* dmabuf either hasn't already been mapped, or it has
++ * changed.
++ */
++ if (buf->mmal.dma_buf) {
++ v4l2_err(&ctx->dev->v4l2_dev,
++ "%s Buffer changed - why did the core not call cleanup?\n",
++ __func__);
++ bcm2835_codec_mmal_buf_cleanup(&buf->mmal);
++ }
++
++ buf->mmal.dma_buf = dma_buf;
++ }
+ ret = 0;
++ break;
++ case VB2_MEMORY_MMAP:
++ /*
++ * We want to do this at init, but vb2_core_expbuf checks that
++ * the index < q->num_buffers, and q->num_buffers only gets
++ * updated once all the buffers are allocated.
++ */
++ if (!buf->mmal.dma_buf) {
++ ret = vb2_core_expbuf_dmabuf(vb->vb2_queue,
++ vb->vb2_queue->type,
++ vb->index, 0,
++ O_CLOEXEC,
++ &buf->mmal.dma_buf);
++ if (ret)
++ v4l2_err(&ctx->dev->v4l2_dev,
++ "%s: Failed to expbuf idx %d, ret %d\n",
++ __func__, vb->index, ret);
++ } else {
++ ret = 0;
++ }
++ break;
++ default:
++ ret = -EINVAL;
++ break;
+ }
+
+ return ret;
+@@ -1948,12 +1989,7 @@ static void bcm2835_codec_buffer_cleanup
+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n",
+ __func__, ctx, vb);
+
+- mmal_vchi_buffer_cleanup(&buf->mmal);
+-
+- if (buf->mmal.dma_buf) {
+- dma_buf_put(buf->mmal.dma_buf);
+- buf->mmal.dma_buf = NULL;
+- }
++ bcm2835_codec_mmal_buf_cleanup(&buf->mmal);
+ }
+
+ static int bcm2835_codec_start_streaming(struct vb2_queue *q,
+@@ -2067,11 +2103,7 @@ static void bcm2835_codec_stop_streaming
+ m2m = container_of(vb2, struct v4l2_m2m_buffer, vb);
+ buf = container_of(m2m, struct m2m_mmal_buffer, m2m);
+
+- mmal_vchi_buffer_cleanup(&buf->mmal);
+- if (buf->mmal.dma_buf) {
+- dma_buf_put(buf->mmal.dma_buf);
+- buf->mmal.dma_buf = NULL;
+- }
++ bcm2835_codec_mmal_buf_cleanup(&buf->mmal);
+ }
+
+ /* If both ports disabled, then disable the component */
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -1785,13 +1785,9 @@ int mmal_vchi_buffer_init(struct vchiq_m
+ }
+ EXPORT_SYMBOL_GPL(mmal_vchi_buffer_init);
+
+-int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf)
++int mmal_vchi_buffer_unmap(struct mmal_buffer *buf)
+ {
+- struct mmal_msg_context *msg_context = buf->msg_context;
+-
+- if (msg_context)
+- release_msg_context(msg_context);
+- buf->msg_context = NULL;
++ int ret = 0;
+
+ if (buf->vcsm_handle) {
+ int ret;
+@@ -1803,6 +1799,19 @@ int mmal_vchi_buffer_cleanup(struct mmal
+ pr_err("%s: vcsm_free failed, ret %d\n", __func__, ret);
+ buf->vcsm_handle = 0;
+ }
++ return ret;
++}
++EXPORT_SYMBOL_GPL(mmal_vchi_buffer_unmap);
++
++int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf)
++{
++ struct mmal_msg_context *msg_context = buf->msg_context;
++
++ if (msg_context)
++ release_msg_context(msg_context);
++ buf->msg_context = NULL;
++
++ mmal_vchi_buffer_unmap(buf);
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup);
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
+@@ -167,6 +167,8 @@ int vchiq_mmal_submit_buffer(struct vchi
+ struct vchiq_mmal_port *port,
+ struct mmal_buffer *buf);
+
++int mmal_vchi_buffer_unmap(struct mmal_buffer *buf);
++
+ int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance,
+ struct mmal_buffer *buf);
+ int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf);
+++ /dev/null
-From a126fcc4ff38718e2e714fbb78db3ca1c4f8e564 Mon Sep 17 00:00:00 2001
-Date: Fri, 15 Feb 2019 11:36:14 +0000
-Subject: [PATCH] staging: bcm2835_codec: Add an option for ignoring
- Bayer formats.
-
-This is a workaround for GStreamer currently not identifying Bayer
-as a raw format, therefore any device that supports it does not
-match the criteria for v4l2convert.
-
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 29 ++++++++++++++++++-
- 1 file changed, 28 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -58,6 +58,15 @@ static int isp_video_nr = 12;
- module_param(isp_video_nr, int, 0644);
- MODULE_PARM_DESC(isp_video_nr, "isp video device number");
-
-+/*
-+ * Workaround for GStreamer v4l2convert component not considering Bayer formats
-+ * as raw, and therefore not considering a V4L2 device that supports them as
-+ * as a suitable candidate.
-+ */
-+static bool disable_bayer;
-+module_param(disable_bayer, bool, 0644);
-+MODULE_PARM_DESC(disable_bayer, "Disable support for Bayer formats");
-+
- static unsigned int debug;
- module_param(debug, uint, 0644);
- MODULE_PARM_DESC(debug, "activates debug info (0-3)");
-@@ -105,6 +114,7 @@ struct bcm2835_codec_fmt {
- u32 flags;
- u32 mmal_fmt;
- int size_multiplier_x2;
-+ bool is_bayer;
- };
-
- static const struct bcm2835_codec_fmt supported_formats[] = {
-@@ -203,6 +213,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- .fourcc = V4L2_PIX_FMT_SBGGR8,
- .depth = 8,
-@@ -210,6 +221,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- .fourcc = V4L2_PIX_FMT_SGRBG8,
- .depth = 8,
-@@ -217,6 +229,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- .fourcc = V4L2_PIX_FMT_SGBRG8,
- .depth = 8,
-@@ -224,6 +237,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- /* 10 bit */
- .fourcc = V4L2_PIX_FMT_SRGGB10P,
-@@ -232,6 +246,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- .fourcc = V4L2_PIX_FMT_SBGGR10P,
- .depth = 10,
-@@ -239,6 +254,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- .fourcc = V4L2_PIX_FMT_SGRBG10P,
- .depth = 10,
-@@ -246,6 +262,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- .fourcc = V4L2_PIX_FMT_SGBRG10P,
- .depth = 10,
-@@ -253,6 +270,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- /* 12 bit */
- .fourcc = V4L2_PIX_FMT_SRGGB12P,
-@@ -261,6 +279,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- .fourcc = V4L2_PIX_FMT_SBGGR12P,
- .depth = 12,
-@@ -268,6 +287,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- .fourcc = V4L2_PIX_FMT_SGRBG12P,
- .depth = 12,
-@@ -275,6 +295,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- .fourcc = V4L2_PIX_FMT_SGBRG12P,
- .depth = 12,
-@@ -282,6 +303,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- /* 16 bit */
- .fourcc = V4L2_PIX_FMT_SRGGB16,
-@@ -290,6 +312,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- .fourcc = V4L2_PIX_FMT_SBGGR16,
- .depth = 16,
-@@ -297,6 +320,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- .fourcc = V4L2_PIX_FMT_SGRBG16,
- .depth = 16,
-@@ -304,6 +328,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- .fourcc = V4L2_PIX_FMT_SGBRG16,
- .depth = 16,
-@@ -311,6 +336,7 @@ static const struct bcm2835_codec_fmt su
- .flags = 0,
- .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16,
- .size_multiplier_x2 = 2,
-+ .is_bayer = true,
- }, {
- /* Compressed formats */
- .fourcc = V4L2_PIX_FMT_H264,
-@@ -438,7 +464,8 @@ static const struct bcm2835_codec_fmt *g
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
-- if (supported_formats[i].mmal_fmt == mmal_fmt)
-+ if (supported_formats[i].mmal_fmt == mmal_fmt &&
-+ (!disable_bayer || !supported_formats[i].is_bayer))
- return &supported_formats[i];
- }
- return NULL;
--- /dev/null
+From f51a6ed76f6a59e65fe06d1f2e06e824f38ae604 Mon Sep 17 00:00:00 2001
+Date: Mon, 18 Feb 2019 15:52:29 +0000
+Subject: [PATCH] staging: mmal-vchiq: Update mmal_parameters.h with
+ recently defined params
+
+mmal_parameters.h hasn't been updated to reflect additions made
+over the last few years. Update it to reflect the currently
+supported parameters.
+
+---
+ .../vchiq-mmal/mmal-parameters.h | 32 ++++++++++++++++++-
+ 1 file changed, 31 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
+@@ -580,7 +580,37 @@ enum mmal_parameter_video_type {
+ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG,
+
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+- MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER
++ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
++
++ /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_SEI_ENABLE,
++
++ /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
++ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_VECTORS,
++
++ /**< Take a @ref MMAL_PARAMETER_VIDEO_RENDER_STATS_T. */
++ MMAL_PARAMETER_VIDEO_RENDER_STATS,
++
++ /**< Take a @ref MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T. */
++ MMAL_PARAMETER_VIDEO_INTERLACE_TYPE,
++
++ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_INTERPOLATE_TIMESTAMPS,
++
++ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_SPS_TIMING,
++
++ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS,
++
++ /**< Takes a @ref MMAL_PARAMETER_SOURCE_PATTERN_T */
++ MMAL_PARAMETER_VIDEO_SOURCE_PATTERN,
++
++ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
++ MMAL_PARAMETER_VIDEO_ENCODE_SEPARATE_NAL_BUFS,
++
++ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
++ MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAME_LENGTH,
+ };
+
+ /** Valid mirror modes */
+++ /dev/null
-From 0df32e2f563123166c20677f022d4a0f825c5df2 Mon Sep 17 00:00:00 2001
-Date: Fri, 15 Feb 2019 11:38:45 +0000
-Subject: [PATCH] staging: bcm2835_codec: Fix handling of
- VB2_MEMORY_DMABUF buffers
-
-If the queue is configured as VB2_MEMORY_DMABUF then vb2_core_expbuf
-fails as it ensures the queue is defined as VB2_MEMORY_MMAP.
-
-Correct the handling so that we unmap the buffer from vcsm and the
-VPU on cleanup, and then correctly get the dma buf of the new buffer.
-
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 80 +++++++++++++------
- .../vc04_services/vchiq-mmal/mmal-vchiq.c | 21 +++--
- .../vc04_services/vchiq-mmal/mmal-vchiq.h | 2 +
- 3 files changed, 73 insertions(+), 30 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1852,6 +1852,18 @@ static int bcm2835_codec_queue_setup(str
- return 0;
- }
-
-+static int bcm2835_codec_mmal_buf_cleanup(struct mmal_buffer *mmal_buf)
-+{
-+ mmal_vchi_buffer_cleanup(mmal_buf);
-+
-+ if (mmal_buf->dma_buf) {
-+ dma_buf_put(mmal_buf->dma_buf);
-+ mmal_buf->dma_buf = NULL;
-+ }
-+
-+ return 0;
-+}
-+
- static int bcm2835_codec_buf_init(struct vb2_buffer *vb)
- {
- struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-@@ -1880,6 +1892,7 @@ static int bcm2835_codec_buf_prepare(str
- vb);
- struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer,
- m2m);
-+ struct dma_buf *dma_buf;
- int ret;
-
- v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p\n",
-@@ -1906,20 +1919,48 @@ static int bcm2835_codec_buf_prepare(str
- if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type))
- vb2_set_plane_payload(vb, 0, q_data->sizeimage);
-
-- /*
-- * We want to do this at init, but vb2_core_expbuf checks that the
-- * index < q->num_buffers, and q->num_buffers only gets updated once
-- * all the buffers are allocated.
-- */
-- if (!buf->mmal.dma_buf) {
-- ret = vb2_core_expbuf_dmabuf(vb->vb2_queue,
-- vb->vb2_queue->type, vb->index, 0,
-- O_CLOEXEC, &buf->mmal.dma_buf);
-- if (ret)
-- v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed to expbuf idx %d, ret %d\n",
-- __func__, vb->index, ret);
-- } else {
-+ switch (vb->memory) {
-+ case VB2_MEMORY_DMABUF:
-+ dma_buf = dma_buf_get(vb->planes[0].m.fd);
-+
-+ if (dma_buf != buf->mmal.dma_buf) {
-+ /* dmabuf either hasn't already been mapped, or it has
-+ * changed.
-+ */
-+ if (buf->mmal.dma_buf) {
-+ v4l2_err(&ctx->dev->v4l2_dev,
-+ "%s Buffer changed - why did the core not call cleanup?\n",
-+ __func__);
-+ bcm2835_codec_mmal_buf_cleanup(&buf->mmal);
-+ }
-+
-+ buf->mmal.dma_buf = dma_buf;
-+ }
- ret = 0;
-+ break;
-+ case VB2_MEMORY_MMAP:
-+ /*
-+ * We want to do this at init, but vb2_core_expbuf checks that
-+ * the index < q->num_buffers, and q->num_buffers only gets
-+ * updated once all the buffers are allocated.
-+ */
-+ if (!buf->mmal.dma_buf) {
-+ ret = vb2_core_expbuf_dmabuf(vb->vb2_queue,
-+ vb->vb2_queue->type,
-+ vb->index, 0,
-+ O_CLOEXEC,
-+ &buf->mmal.dma_buf);
-+ if (ret)
-+ v4l2_err(&ctx->dev->v4l2_dev,
-+ "%s: Failed to expbuf idx %d, ret %d\n",
-+ __func__, vb->index, ret);
-+ } else {
-+ ret = 0;
-+ }
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
- }
-
- return ret;
-@@ -1948,12 +1989,7 @@ static void bcm2835_codec_buffer_cleanup
- v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n",
- __func__, ctx, vb);
-
-- mmal_vchi_buffer_cleanup(&buf->mmal);
--
-- if (buf->mmal.dma_buf) {
-- dma_buf_put(buf->mmal.dma_buf);
-- buf->mmal.dma_buf = NULL;
-- }
-+ bcm2835_codec_mmal_buf_cleanup(&buf->mmal);
- }
-
- static int bcm2835_codec_start_streaming(struct vb2_queue *q,
-@@ -2067,11 +2103,7 @@ static void bcm2835_codec_stop_streaming
- m2m = container_of(vb2, struct v4l2_m2m_buffer, vb);
- buf = container_of(m2m, struct m2m_mmal_buffer, m2m);
-
-- mmal_vchi_buffer_cleanup(&buf->mmal);
-- if (buf->mmal.dma_buf) {
-- dma_buf_put(buf->mmal.dma_buf);
-- buf->mmal.dma_buf = NULL;
-- }
-+ bcm2835_codec_mmal_buf_cleanup(&buf->mmal);
- }
-
- /* If both ports disabled, then disable the component */
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -1785,13 +1785,9 @@ int mmal_vchi_buffer_init(struct vchiq_m
- }
- EXPORT_SYMBOL_GPL(mmal_vchi_buffer_init);
-
--int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf)
-+int mmal_vchi_buffer_unmap(struct mmal_buffer *buf)
- {
-- struct mmal_msg_context *msg_context = buf->msg_context;
--
-- if (msg_context)
-- release_msg_context(msg_context);
-- buf->msg_context = NULL;
-+ int ret = 0;
-
- if (buf->vcsm_handle) {
- int ret;
-@@ -1803,6 +1799,19 @@ int mmal_vchi_buffer_cleanup(struct mmal
- pr_err("%s: vcsm_free failed, ret %d\n", __func__, ret);
- buf->vcsm_handle = 0;
- }
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(mmal_vchi_buffer_unmap);
-+
-+int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf)
-+{
-+ struct mmal_msg_context *msg_context = buf->msg_context;
-+
-+ if (msg_context)
-+ release_msg_context(msg_context);
-+ buf->msg_context = NULL;
-+
-+ mmal_vchi_buffer_unmap(buf);
- return 0;
- }
- EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup);
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
-@@ -167,6 +167,8 @@ int vchiq_mmal_submit_buffer(struct vchi
- struct vchiq_mmal_port *port,
- struct mmal_buffer *buf);
-
-+int mmal_vchi_buffer_unmap(struct mmal_buffer *buf);
-+
- int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance,
- struct mmal_buffer *buf);
- int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf);
--- /dev/null
+From 7f9fd2338e3a9d7b46b6904bbd7f97851e9b3f52 Mon Sep 17 00:00:00 2001
+Date: Mon, 18 Feb 2019 15:56:42 +0000
+Subject: [PATCH] staging: bcm2835_codec: Include timing info in SPS
+ headers
+
+Inserting timing information into the VUI block of the SPS is
+optional with the VPU encoder.
+GStreamer appears to require them when using V4L2 M2M, therefore
+set the option to enable them from the encoder.
+
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1785,6 +1785,8 @@ static int bcm2835_codec_create_componen
+ goto destroy_component;
+
+ if (dev->role == ENCODE) {
++ u32 param = 1;
++
+ if (ctx->q_data[V4L2_M2M_SRC].sizeimage <
+ ctx->component->output[0].minimum_buffer.size)
+ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
+@@ -1793,6 +1795,16 @@ static int bcm2835_codec_create_componen
+
+ /* Now we have a component we can set all the ctrls */
+ bcm2835_codec_set_ctrls(ctx);
++
++ /* Enable SPS Timing header so framerate information is encoded
++ * in the H264 header.
++ */
++ vchiq_mmal_port_parameter_set(
++ ctx->dev->instance,
++ &ctx->component->output[0],
++ MMAL_PARAMETER_VIDEO_ENCODE_SPS_TIMING,
++ ¶m, sizeof(param));
++
+ } else {
+ if (ctx->q_data[V4L2_M2M_DST].sizeimage <
+ ctx->component->output[0].minimum_buffer.size)
--- /dev/null
+From dd5fa07672eb01a4d90dfa39a4c54eaa0e086386 Mon Sep 17 00:00:00 2001
+Date: Mon, 5 Feb 2018 18:53:18 +0000
+Subject: [PATCH] drm/vc4: Don't wait for vblank on fkms cursor
+ updates.
+
+We don't use the same async update path between fkms and normal kms,
+and the normal kms workaround ended up making us wait. This became a
+larger problem in rpi-4.14.y, as the USB HID update rate throttling
+got (accidentally?) dropped.
+
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -222,7 +222,8 @@ static int vc4_atomic_commit(struct drm_
+ * drm_atomic_helper_setup_commit() from auto-completing
+ * commit->flip_done.
+ */
+- state->legacy_cursor_update = false;
++ if (!vc4->firmware_kms)
++ state->legacy_cursor_update = false;
+ ret = drm_atomic_helper_setup_commit(state, nonblock);
+ if (ret)
+ return ret;
+++ /dev/null
-From f51a6ed76f6a59e65fe06d1f2e06e824f38ae604 Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Feb 2019 15:52:29 +0000
-Subject: [PATCH] staging: mmal-vchiq: Update mmal_parameters.h with
- recently defined params
-
-mmal_parameters.h hasn't been updated to reflect additions made
-over the last few years. Update it to reflect the currently
-supported parameters.
-
----
- .../vchiq-mmal/mmal-parameters.h | 32 ++++++++++++++++++-
- 1 file changed, 31 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
-@@ -580,7 +580,37 @@ enum mmal_parameter_video_type {
- MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG,
-
- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-- MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER
-+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
-+
-+ /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_SEI_ENABLE,
-+
-+ /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
-+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_VECTORS,
-+
-+ /**< Take a @ref MMAL_PARAMETER_VIDEO_RENDER_STATS_T. */
-+ MMAL_PARAMETER_VIDEO_RENDER_STATS,
-+
-+ /**< Take a @ref MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T. */
-+ MMAL_PARAMETER_VIDEO_INTERLACE_TYPE,
-+
-+ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_INTERPOLATE_TIMESTAMPS,
-+
-+ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_SPS_TIMING,
-+
-+ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS,
-+
-+ /**< Takes a @ref MMAL_PARAMETER_SOURCE_PATTERN_T */
-+ MMAL_PARAMETER_VIDEO_SOURCE_PATTERN,
-+
-+ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
-+ MMAL_PARAMETER_VIDEO_ENCODE_SEPARATE_NAL_BUFS,
-+
-+ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
-+ MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAME_LENGTH,
- };
-
- /** Valid mirror modes */
--- /dev/null
+From c93b0344d24ba63e0e4caeb693a9fcb7320aae3a Mon Sep 17 00:00:00 2001
+Date: Wed, 27 Feb 2019 14:27:28 +0000
+Subject: [PATCH] Fix for Pisound kernel module in Real Time kernel
+ configuration.
+
+When handler of data_available interrupt is fired, queue_work ends up
+getting called and it can block on a spin lock which is not allowed in
+interrupt context. The fix was to run the handler from a thread context
+instead.
+---
+ sound/soc/bcm/pisound.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/sound/soc/bcm/pisound.c
++++ b/sound/soc/bcm/pisound.c
+@@ -1,6 +1,6 @@
+ /*
+ * Pisound Linux kernel module.
+- * Copyright (C) 2016-2017 Vilniaus Blokas UAB, https://blokas.io/pisound
++ * Copyright (C) 2016-2019 Vilniaus Blokas UAB, https://blokas.io/pisound
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -532,10 +532,10 @@ static void pisnd_spi_gpio_uninit(void)
+
+ static int pisnd_spi_gpio_irq_init(struct device *dev)
+ {
+- return request_irq(
+- gpiod_to_irq(data_available),
++ return request_threaded_irq(
++ gpiod_to_irq(data_available), NULL,
+ data_available_interrupt_handler,
+- IRQF_TIMER | IRQF_TRIGGER_RISING,
++ IRQF_TIMER | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "data_available_int",
+ NULL
+ );
+++ /dev/null
-From 7f9fd2338e3a9d7b46b6904bbd7f97851e9b3f52 Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Feb 2019 15:56:42 +0000
-Subject: [PATCH] staging: bcm2835_codec: Include timing info in SPS
- headers
-
-Inserting timing information into the VUI block of the SPS is
-optional with the VPU encoder.
-GStreamer appears to require them when using V4L2 M2M, therefore
-set the option to enable them from the encoder.
-
----
- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1785,6 +1785,8 @@ static int bcm2835_codec_create_componen
- goto destroy_component;
-
- if (dev->role == ENCODE) {
-+ u32 param = 1;
-+
- if (ctx->q_data[V4L2_M2M_SRC].sizeimage <
- ctx->component->output[0].minimum_buffer.size)
- v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n",
-@@ -1793,6 +1795,16 @@ static int bcm2835_codec_create_componen
-
- /* Now we have a component we can set all the ctrls */
- bcm2835_codec_set_ctrls(ctx);
-+
-+ /* Enable SPS Timing header so framerate information is encoded
-+ * in the H264 header.
-+ */
-+ vchiq_mmal_port_parameter_set(
-+ ctx->dev->instance,
-+ &ctx->component->output[0],
-+ MMAL_PARAMETER_VIDEO_ENCODE_SPS_TIMING,
-+ ¶m, sizeof(param));
-+
- } else {
- if (ctx->q_data[V4L2_M2M_DST].sizeimage <
- ctx->component->output[0].minimum_buffer.size)
--- /dev/null
+From 193dc2529db3cfee676aae2b18f059363e151e09 Mon Sep 17 00:00:00 2001
+Date: Thu, 7 Jun 2018 21:22:45 +0530
+Subject: [PATCH] Added mute stream func
+
+---
+ sound/soc/bcm/allo-katana-codec.c | 60 ++++++++++++++++++++++---------
+ 1 file changed, 44 insertions(+), 16 deletions(-)
+
+--- a/sound/soc/bcm/allo-katana-codec.c
++++ b/sound/soc/bcm/allo-katana-codec.c
+@@ -31,21 +31,23 @@
+
+ #define KATANA_CODEC_CHIP_ID 0x30
+ #define KATANA_CODEC_VIRT_BASE 0x100
+-#define KATANA_CODEC_PAGE 0
++#define KATANA_CODEC_PAGE 0
+
+ #define KATANA_CODEC_CHIP_ID_REG (KATANA_CODEC_VIRT_BASE + 0)
+-#define KATANA_CODEC_RESET (KATANA_CODEC_VIRT_BASE + 1)
++#define KATANA_CODEC_RESET (KATANA_CODEC_VIRT_BASE + 1)
+ #define KATANA_CODEC_VOLUME_1 (KATANA_CODEC_VIRT_BASE + 2)
+ #define KATANA_CODEC_VOLUME_2 (KATANA_CODEC_VIRT_BASE + 3)
+-#define KATANA_CODEC_MUTE (KATANA_CODEC_VIRT_BASE + 4)
++#define KATANA_CODEC_MUTE (KATANA_CODEC_VIRT_BASE + 4)
+ #define KATANA_CODEC_DSP_PROGRAM (KATANA_CODEC_VIRT_BASE + 5)
+ #define KATANA_CODEC_DEEMPHASIS (KATANA_CODEC_VIRT_BASE + 6)
+-#define KATANA_CODEC_DOP (KATANA_CODEC_VIRT_BASE + 7)
+-#define KATANA_CODEC_FORMAT (KATANA_CODEC_VIRT_BASE + 8)
++#define KATANA_CODEC_DOP (KATANA_CODEC_VIRT_BASE + 7)
++#define KATANA_CODEC_FORMAT (KATANA_CODEC_VIRT_BASE + 8)
+ #define KATANA_CODEC_COMMAND (KATANA_CODEC_VIRT_BASE + 9)
+-#define KATANA_CODEC_MAX_REGISTER (KATANA_CODEC_VIRT_BASE + 9)
++#define KATANA_CODEC_MUTE_STREAM (KATANA_CODEC_VIRT_BASE + 10)
+
+-#define KATANA_CODEC_FMT 0xff
++#define KATANA_CODEC_MAX_REGISTER (KATANA_CODEC_VIRT_BASE + 10)
++
++#define KATANA_CODEC_FMT 0xff
+ #define KATANA_CODEC_CHAN_MONO 0x00
+ #define KATANA_CODEC_CHAN_STEREO 0x80
+ #define KATANA_CODEC_ALEN_16 0x10
+@@ -135,7 +137,8 @@ static const struct snd_kcontrol_new kat
+ SOC_SINGLE("DoP Playback Switch", KATANA_CODEC_DOP, 0, 1, 1)
+ };
+
+-static bool katana_codec_readable_register(struct device *dev, unsigned int reg)
++static bool katana_codec_readable_register(struct device *dev,
++ unsigned int reg)
+ {
+ switch (reg) {
+ case KATANA_CODEC_CHIP_ID_REG:
+@@ -150,13 +153,15 @@ static int katana_codec_hw_params(struct
+ struct snd_soc_dai *dai)
+ {
+ struct snd_soc_component *component = dai->component;
+- struct katana_codec_priv *katana_codec = snd_soc_component_get_drvdata(component);
++ struct katana_codec_priv *katana_codec =
++ snd_soc_component_get_drvdata(component);
+ int fmt = 0;
+ int ret;
+
+- dev_dbg(component->card->dev, "hw_params %u Hz, %u channels\n",
++ dev_dbg(component->card->dev, "hw_params %u Hz, %u channels, %u bits\n",
+ params_rate(params),
+- params_channels(params));
++ params_channels(params),
++ params_width(params));
+
+ switch (katana_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM: // master
+@@ -212,13 +217,17 @@ static int katana_codec_hw_params(struct
+ return -EINVAL;
+ }
+
+- ret = regmap_write(katana_codec->regmap, KATANA_CODEC_FORMAT, fmt);
++ ret = regmap_write(katana_codec->regmap, KATANA_CODEC_FORMAT,
++ fmt);
+ if (ret != 0) {
+ dev_err(component->card->dev, "Failed to set format: %d\n", ret);
+ return ret;
+ }
+ break;
+
++ case SND_SOC_DAIFMT_CBS_CFS:
++ break;
++
+ default:
+ return -EINVAL;
+ }
+@@ -229,14 +238,33 @@ static int katana_codec_hw_params(struct
+ static int katana_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+ {
+ struct snd_soc_component *component = dai->component;
+- struct katana_codec_priv *katana_codec = snd_soc_component_get_drvdata(component);
++ struct katana_codec_priv *katana_codec =
++ snd_soc_component_get_drvdata(component);
+
+ katana_codec->fmt = fmt;
+
+ return 0;
+ }
+
++int katana_codec_dai_mute_stream(struct snd_soc_dai *dai, int mute,
++ int stream)
++{
++ struct snd_soc_component *component = dai->component;
++ struct katana_codec_priv *katana_codec =
++ snd_soc_component_get_drvdata(component);
++ int ret = 0;
++
++ ret = regmap_write(katana_codec->regmap, KATANA_CODEC_MUTE_STREAM,
++ mute);
++ if (ret != 0) {
++ dev_err(component->card->dev, "Failed to set mute: %d\n", ret);
++ return ret;
++ }
++ return ret;
++}
++
+ static const struct snd_soc_dai_ops katana_codec_dai_ops = {
++ .mute_stream = katana_codec_dai_mute_stream,
+ .hw_params = katana_codec_hw_params,
+ .set_fmt = katana_codec_set_fmt,
+ };
+@@ -300,7 +328,7 @@ static int allo_katana_component_probe(s
+ return PTR_ERR(regmap);
+
+ katana_codec = devm_kzalloc(dev, sizeof(struct katana_codec_priv),
+- GFP_KERNEL);
++ GFP_KERNEL);
+ if (!katana_codec)
+ return -ENOMEM;
+
+@@ -348,8 +376,8 @@ static struct i2c_driver allo_katana_com
+ .remove = allo_katana_component_remove,
+ .id_table = allo_katana_component_id,
+ .driver = {
+- .name = "allo-katana-codec",
+- .of_match_table = allo_katana_codec_of_match,
++ .name = "allo-katana-codec",
++ .of_match_table = allo_katana_codec_of_match,
+ },
+ };
+
+++ /dev/null
-From dd5fa07672eb01a4d90dfa39a4c54eaa0e086386 Mon Sep 17 00:00:00 2001
-Date: Mon, 5 Feb 2018 18:53:18 +0000
-Subject: [PATCH] drm/vc4: Don't wait for vblank on fkms cursor
- updates.
-
-We don't use the same async update path between fkms and normal kms,
-and the normal kms workaround ended up making us wait. This became a
-larger problem in rpi-4.14.y, as the USB HID update rate throttling
-got (accidentally?) dropped.
-
----
- drivers/gpu/drm/vc4/vc4_kms.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -222,7 +222,8 @@ static int vc4_atomic_commit(struct drm_
- * drm_atomic_helper_setup_commit() from auto-completing
- * commit->flip_done.
- */
-- state->legacy_cursor_update = false;
-+ if (!vc4->firmware_kms)
-+ state->legacy_cursor_update = false;
- ret = drm_atomic_helper_setup_commit(state, nonblock);
- if (ret)
- return ret;
+++ /dev/null
-From c93b0344d24ba63e0e4caeb693a9fcb7320aae3a Mon Sep 17 00:00:00 2001
-Date: Wed, 27 Feb 2019 14:27:28 +0000
-Subject: [PATCH] Fix for Pisound kernel module in Real Time kernel
- configuration.
-
-When handler of data_available interrupt is fired, queue_work ends up
-getting called and it can block on a spin lock which is not allowed in
-interrupt context. The fix was to run the handler from a thread context
-instead.
----
- sound/soc/bcm/pisound.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
---- a/sound/soc/bcm/pisound.c
-+++ b/sound/soc/bcm/pisound.c
-@@ -1,6 +1,6 @@
- /*
- * Pisound Linux kernel module.
-- * Copyright (C) 2016-2017 Vilniaus Blokas UAB, https://blokas.io/pisound
-+ * Copyright (C) 2016-2019 Vilniaus Blokas UAB, https://blokas.io/pisound
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
-@@ -532,10 +532,10 @@ static void pisnd_spi_gpio_uninit(void)
-
- static int pisnd_spi_gpio_irq_init(struct device *dev)
- {
-- return request_irq(
-- gpiod_to_irq(data_available),
-+ return request_threaded_irq(
-+ gpiod_to_irq(data_available), NULL,
- data_available_interrupt_handler,
-- IRQF_TIMER | IRQF_TRIGGER_RISING,
-+ IRQF_TIMER | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- "data_available_int",
- NULL
- );
--- /dev/null
+From 5917a0b0e56928aecd1270c85a79fce77a404629 Mon Sep 17 00:00:00 2001
+Date: Tue, 5 Mar 2019 09:51:22 +0000
+Subject: [PATCH] lan78xx: EEE support is now a PHY property
+
+Now that EEE support is a property of the PHY, use the PHY's DT node
+when querying the EEE-related properties.
+
+See: https://github.com/raspberrypi/linux/issues/2882
+
+---
+ drivers/net/usb/lan78xx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/usb/lan78xx.c
++++ b/drivers/net/usb/lan78xx.c
+@@ -2196,7 +2196,7 @@ static int lan78xx_phy_init(struct lan78
+ mii_adv = (u32)mii_advertise_flowctrl(dev->fc_request_control);
+ phydev->advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
+
+- if (of_property_read_bool(dev->udev->dev.of_node,
++ if (of_property_read_bool(phydev->mdio.dev.of_node,
+ "microchip,eee-enabled")) {
+ struct ethtool_eee edata;
+ memset(&edata, 0, sizeof(edata));
+++ /dev/null
-From 193dc2529db3cfee676aae2b18f059363e151e09 Mon Sep 17 00:00:00 2001
-Date: Thu, 7 Jun 2018 21:22:45 +0530
-Subject: [PATCH] Added mute stream func
-
----
- sound/soc/bcm/allo-katana-codec.c | 60 ++++++++++++++++++++++---------
- 1 file changed, 44 insertions(+), 16 deletions(-)
-
---- a/sound/soc/bcm/allo-katana-codec.c
-+++ b/sound/soc/bcm/allo-katana-codec.c
-@@ -31,21 +31,23 @@
-
- #define KATANA_CODEC_CHIP_ID 0x30
- #define KATANA_CODEC_VIRT_BASE 0x100
--#define KATANA_CODEC_PAGE 0
-+#define KATANA_CODEC_PAGE 0
-
- #define KATANA_CODEC_CHIP_ID_REG (KATANA_CODEC_VIRT_BASE + 0)
--#define KATANA_CODEC_RESET (KATANA_CODEC_VIRT_BASE + 1)
-+#define KATANA_CODEC_RESET (KATANA_CODEC_VIRT_BASE + 1)
- #define KATANA_CODEC_VOLUME_1 (KATANA_CODEC_VIRT_BASE + 2)
- #define KATANA_CODEC_VOLUME_2 (KATANA_CODEC_VIRT_BASE + 3)
--#define KATANA_CODEC_MUTE (KATANA_CODEC_VIRT_BASE + 4)
-+#define KATANA_CODEC_MUTE (KATANA_CODEC_VIRT_BASE + 4)
- #define KATANA_CODEC_DSP_PROGRAM (KATANA_CODEC_VIRT_BASE + 5)
- #define KATANA_CODEC_DEEMPHASIS (KATANA_CODEC_VIRT_BASE + 6)
--#define KATANA_CODEC_DOP (KATANA_CODEC_VIRT_BASE + 7)
--#define KATANA_CODEC_FORMAT (KATANA_CODEC_VIRT_BASE + 8)
-+#define KATANA_CODEC_DOP (KATANA_CODEC_VIRT_BASE + 7)
-+#define KATANA_CODEC_FORMAT (KATANA_CODEC_VIRT_BASE + 8)
- #define KATANA_CODEC_COMMAND (KATANA_CODEC_VIRT_BASE + 9)
--#define KATANA_CODEC_MAX_REGISTER (KATANA_CODEC_VIRT_BASE + 9)
-+#define KATANA_CODEC_MUTE_STREAM (KATANA_CODEC_VIRT_BASE + 10)
-
--#define KATANA_CODEC_FMT 0xff
-+#define KATANA_CODEC_MAX_REGISTER (KATANA_CODEC_VIRT_BASE + 10)
-+
-+#define KATANA_CODEC_FMT 0xff
- #define KATANA_CODEC_CHAN_MONO 0x00
- #define KATANA_CODEC_CHAN_STEREO 0x80
- #define KATANA_CODEC_ALEN_16 0x10
-@@ -135,7 +137,8 @@ static const struct snd_kcontrol_new kat
- SOC_SINGLE("DoP Playback Switch", KATANA_CODEC_DOP, 0, 1, 1)
- };
-
--static bool katana_codec_readable_register(struct device *dev, unsigned int reg)
-+static bool katana_codec_readable_register(struct device *dev,
-+ unsigned int reg)
- {
- switch (reg) {
- case KATANA_CODEC_CHIP_ID_REG:
-@@ -150,13 +153,15 @@ static int katana_codec_hw_params(struct
- struct snd_soc_dai *dai)
- {
- struct snd_soc_component *component = dai->component;
-- struct katana_codec_priv *katana_codec = snd_soc_component_get_drvdata(component);
-+ struct katana_codec_priv *katana_codec =
-+ snd_soc_component_get_drvdata(component);
- int fmt = 0;
- int ret;
-
-- dev_dbg(component->card->dev, "hw_params %u Hz, %u channels\n",
-+ dev_dbg(component->card->dev, "hw_params %u Hz, %u channels, %u bits\n",
- params_rate(params),
-- params_channels(params));
-+ params_channels(params),
-+ params_width(params));
-
- switch (katana_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM: // master
-@@ -212,13 +217,17 @@ static int katana_codec_hw_params(struct
- return -EINVAL;
- }
-
-- ret = regmap_write(katana_codec->regmap, KATANA_CODEC_FORMAT, fmt);
-+ ret = regmap_write(katana_codec->regmap, KATANA_CODEC_FORMAT,
-+ fmt);
- if (ret != 0) {
- dev_err(component->card->dev, "Failed to set format: %d\n", ret);
- return ret;
- }
- break;
-
-+ case SND_SOC_DAIFMT_CBS_CFS:
-+ break;
-+
- default:
- return -EINVAL;
- }
-@@ -229,14 +238,33 @@ static int katana_codec_hw_params(struct
- static int katana_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
- {
- struct snd_soc_component *component = dai->component;
-- struct katana_codec_priv *katana_codec = snd_soc_component_get_drvdata(component);
-+ struct katana_codec_priv *katana_codec =
-+ snd_soc_component_get_drvdata(component);
-
- katana_codec->fmt = fmt;
-
- return 0;
- }
-
-+int katana_codec_dai_mute_stream(struct snd_soc_dai *dai, int mute,
-+ int stream)
-+{
-+ struct snd_soc_component *component = dai->component;
-+ struct katana_codec_priv *katana_codec =
-+ snd_soc_component_get_drvdata(component);
-+ int ret = 0;
-+
-+ ret = regmap_write(katana_codec->regmap, KATANA_CODEC_MUTE_STREAM,
-+ mute);
-+ if (ret != 0) {
-+ dev_err(component->card->dev, "Failed to set mute: %d\n", ret);
-+ return ret;
-+ }
-+ return ret;
-+}
-+
- static const struct snd_soc_dai_ops katana_codec_dai_ops = {
-+ .mute_stream = katana_codec_dai_mute_stream,
- .hw_params = katana_codec_hw_params,
- .set_fmt = katana_codec_set_fmt,
- };
-@@ -300,7 +328,7 @@ static int allo_katana_component_probe(s
- return PTR_ERR(regmap);
-
- katana_codec = devm_kzalloc(dev, sizeof(struct katana_codec_priv),
-- GFP_KERNEL);
-+ GFP_KERNEL);
- if (!katana_codec)
- return -ENOMEM;
-
-@@ -348,8 +376,8 @@ static struct i2c_driver allo_katana_com
- .remove = allo_katana_component_remove,
- .id_table = allo_katana_component_id,
- .driver = {
-- .name = "allo-katana-codec",
-- .of_match_table = allo_katana_codec_of_match,
-+ .name = "allo-katana-codec",
-+ .of_match_table = allo_katana_codec_of_match,
- },
- };
-
--- /dev/null
+From 7b2fac96ce48939e399707c4b8bd9905d6274a05 Mon Sep 17 00:00:00 2001
+Date: Fri, 8 Mar 2019 10:38:59 +0000
+Subject: [PATCH] staging: vc_sm_cma: Remove erroneous misc_deregister
+
+Code from the misc /dev node was still present in
+bcm2835_vc_sm_cma_remove, which caused a NULL deref.
+Remove it.
+
+See #2885.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -25,7 +25,6 @@
+ #include <linux/fs.h>
+ #include <linux/kernel.h>
+ #include <linux/list.h>
+-#include <linux/miscdevice.h>
+ #include <linux/module.h>
+ #include <linux/mm.h>
+ #include <linux/of_device.h>
+@@ -72,7 +71,6 @@ struct sm_pde_t {
+ struct sm_state_t {
+ struct platform_device *pdev;
+
+- struct miscdevice dev;
+ struct sm_instance *sm_handle; /* Handle for videocore service. */
+
+ spinlock_t kernelid_map_lock; /* Spinlock protecting kernelid_map */
+@@ -758,9 +756,6 @@ static int bcm2835_vc_sm_cma_remove(stru
+ {
+ pr_debug("[%s]: start\n", __func__);
+ if (sm_inited) {
+- /* Remove shared memory device. */
+- misc_deregister(&sm_state->dev);
+-
+ /* Remove all proc entries. */
+ //debugfs_remove_recursive(sm_state->dir_root);
+
+++ /dev/null
-From 5917a0b0e56928aecd1270c85a79fce77a404629 Mon Sep 17 00:00:00 2001
-Date: Tue, 5 Mar 2019 09:51:22 +0000
-Subject: [PATCH] lan78xx: EEE support is now a PHY property
-
-Now that EEE support is a property of the PHY, use the PHY's DT node
-when querying the EEE-related properties.
-
-See: https://github.com/raspberrypi/linux/issues/2882
-
----
- drivers/net/usb/lan78xx.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/usb/lan78xx.c
-+++ b/drivers/net/usb/lan78xx.c
-@@ -2196,7 +2196,7 @@ static int lan78xx_phy_init(struct lan78
- mii_adv = (u32)mii_advertise_flowctrl(dev->fc_request_control);
- phydev->advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
-
-- if (of_property_read_bool(dev->udev->dev.of_node,
-+ if (of_property_read_bool(phydev->mdio.dev.of_node,
- "microchip,eee-enabled")) {
- struct ethtool_eee edata;
- memset(&edata, 0, sizeof(edata));
--- /dev/null
+From d36a5a94156ebe7e9906574fa8b01b200a15c11d Mon Sep 17 00:00:00 2001
+Date: Mon, 18 Mar 2019 17:14:51 +0000
+Subject: [PATCH] vcsm: Fix makefile include on out-of-tree builds
+
+The vc_sm module tries to include the 'fs' directory from the
+$(srctree). $(srctree) is already provided by the build system, and
+causes the include path to be duplicated.
+
+With -Werror this fails to compile.
+
+Remove the unnecessary variable.
+
+---
+ drivers/char/broadcom/vc_sm/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/char/broadcom/vc_sm/Makefile
++++ b/drivers/char/broadcom/vc_sm/Makefile
+@@ -1,5 +1,5 @@
+ ccflags-$(CONFIG_BCM_VC_SM) += -Werror -Wall -Wstrict-prototypes -Wno-trigraphs -O2
+-ccflags-$(CONFIG_BCM_VC_SM) += -I"drivers/staging/vc04_services" -I"drivers/staging/vc04_services/interface/vchi" -I"drivers/staging/vc04_services/interface/vchiq_arm" -I"$(srctree)/fs/"
++ccflags-$(CONFIG_BCM_VC_SM) += -I"drivers/staging/vc04_services" -I"drivers/staging/vc04_services/interface/vchi" -I"drivers/staging/vc04_services/interface/vchiq_arm" -I"fs"
+ ccflags-$(CONFIG_BCM_VC_SM) += -DOS_ASSERT_FAILURE -D__STDC_VERSION=199901L -D__STDC_VERSION__=199901L -D__VCCOREVER__=0 -D__KERNEL__ -D__linux__
+
+ obj-$(CONFIG_BCM_VC_SM) := vc-sm.o
+++ /dev/null
-From 7b2fac96ce48939e399707c4b8bd9905d6274a05 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Mar 2019 10:38:59 +0000
-Subject: [PATCH] staging: vc_sm_cma: Remove erroneous misc_deregister
-
-Code from the misc /dev node was still present in
-bcm2835_vc_sm_cma_remove, which caused a NULL deref.
-Remove it.
-
-See #2885.
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 5 -----
- 1 file changed, 5 deletions(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -25,7 +25,6 @@
- #include <linux/fs.h>
- #include <linux/kernel.h>
- #include <linux/list.h>
--#include <linux/miscdevice.h>
- #include <linux/module.h>
- #include <linux/mm.h>
- #include <linux/of_device.h>
-@@ -72,7 +71,6 @@ struct sm_pde_t {
- struct sm_state_t {
- struct platform_device *pdev;
-
-- struct miscdevice dev;
- struct sm_instance *sm_handle; /* Handle for videocore service. */
-
- spinlock_t kernelid_map_lock; /* Spinlock protecting kernelid_map */
-@@ -758,9 +756,6 @@ static int bcm2835_vc_sm_cma_remove(stru
- {
- pr_debug("[%s]: start\n", __func__);
- if (sm_inited) {
-- /* Remove shared memory device. */
-- misc_deregister(&sm_state->dev);
--
- /* Remove all proc entries. */
- //debugfs_remove_recursive(sm_state->dir_root);
-
--- /dev/null
+From 5a58b2bb907d57dc2b1cc2619bd5f1d948509e3e Mon Sep 17 00:00:00 2001
+Date: Mon, 18 Mar 2019 17:16:41 +0000
+Subject: [PATCH] vcsm: Remove set but unused variable
+
+The 'success' variable is set by the call to vchi_service_close() but never checked.
+Remove it, keeping the call in place.
+
+---
+ drivers/char/broadcom/vc_sm/vc_vchi_sm.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
++++ b/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
+@@ -361,11 +361,9 @@ int vc_vchi_sm_stop(struct sm_instance *
+
+ /* Close all VCHI service connections */
+ for (i = 0; i < instance->num_connections; i++) {
+- int32_t success;
+-
+ vchi_service_use(instance->vchi_handle[i]);
+
+- success = vchi_service_close(instance->vchi_handle[i]);
++ vchi_service_close(instance->vchi_handle[i]);
+ }
+
+ kfree(instance);
+++ /dev/null
-From d36a5a94156ebe7e9906574fa8b01b200a15c11d Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Mar 2019 17:14:51 +0000
-Subject: [PATCH] vcsm: Fix makefile include on out-of-tree builds
-
-The vc_sm module tries to include the 'fs' directory from the
-$(srctree). $(srctree) is already provided by the build system, and
-causes the include path to be duplicated.
-
-With -Werror this fails to compile.
-
-Remove the unnecessary variable.
-
----
- drivers/char/broadcom/vc_sm/Makefile | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/char/broadcom/vc_sm/Makefile
-+++ b/drivers/char/broadcom/vc_sm/Makefile
-@@ -1,5 +1,5 @@
- ccflags-$(CONFIG_BCM_VC_SM) += -Werror -Wall -Wstrict-prototypes -Wno-trigraphs -O2
--ccflags-$(CONFIG_BCM_VC_SM) += -I"drivers/staging/vc04_services" -I"drivers/staging/vc04_services/interface/vchi" -I"drivers/staging/vc04_services/interface/vchiq_arm" -I"$(srctree)/fs/"
-+ccflags-$(CONFIG_BCM_VC_SM) += -I"drivers/staging/vc04_services" -I"drivers/staging/vc04_services/interface/vchi" -I"drivers/staging/vc04_services/interface/vchiq_arm" -I"fs"
- ccflags-$(CONFIG_BCM_VC_SM) += -DOS_ASSERT_FAILURE -D__STDC_VERSION=199901L -D__STDC_VERSION__=199901L -D__VCCOREVER__=0 -D__KERNEL__ -D__linux__
-
- obj-$(CONFIG_BCM_VC_SM) := vc-sm.o
--- /dev/null
+From 2a1fd1a32b7355c6ae8c5fc1654a96fa42e00586 Mon Sep 17 00:00:00 2001
+Date: Mon, 18 Mar 2019 17:17:40 +0000
+Subject: [PATCH] vcsm: Reduce scope of local functions
+
+The functions:
+
+ vc_vchi_sm_send_msg
+ vc_sm_ioctl_alloc
+ vc_sm_ioctl_alloc_share
+ vc_sm_ioctl_import_dmabuf
+
+Are declared without a prototype. They are not used outside of this
+module, thus - convert them to static functions.
+
+---
+ drivers/char/broadcom/vc_sm/vc_vchi_sm.c | 2 +-
+ drivers/char/broadcom/vc_sm/vmcs_sm.c | 14 +++++++-------
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
++++ b/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
+@@ -375,7 +375,7 @@ lock:
+ return -EINVAL;
+ }
+
+-int vc_vchi_sm_send_msg(struct sm_instance *handle,
++static int vc_vchi_sm_send_msg(struct sm_instance *handle,
+ enum vc_sm_msg_type msg_id,
+ void *msg, uint32_t msg_size,
+ void *result, uint32_t result_size,
+--- a/drivers/char/broadcom/vc_sm/vmcs_sm.c
++++ b/drivers/char/broadcom/vc_sm/vmcs_sm.c
+@@ -1574,8 +1574,8 @@ error:
+ }
+
+ /* Allocate a shared memory handle and block. */
+-int vc_sm_ioctl_alloc(struct sm_priv_data_t *private,
+- struct vmcs_sm_ioctl_alloc *ioparam)
++static int vc_sm_ioctl_alloc(struct sm_priv_data_t *private,
++ struct vmcs_sm_ioctl_alloc *ioparam)
+ {
+ int ret = 0;
+ int status;
+@@ -1685,8 +1685,8 @@ error:
+ }
+
+ /* Share an allocate memory handle and block.*/
+-int vc_sm_ioctl_alloc_share(struct sm_priv_data_t *private,
+- struct vmcs_sm_ioctl_alloc_share *ioparam)
++static int vc_sm_ioctl_alloc_share(struct sm_priv_data_t *private,
++ struct vmcs_sm_ioctl_alloc_share *ioparam)
+ {
+ struct sm_resource_t *resource, *shared_resource;
+ int ret = 0;
+@@ -2200,9 +2200,9 @@ error:
+ }
+
+ /* Import a contiguous block of memory to be shared with VC. */
+-int vc_sm_ioctl_import_dmabuf(struct sm_priv_data_t *private,
+- struct vmcs_sm_ioctl_import_dmabuf *ioparam,
+- struct dma_buf *src_dma_buf)
++static int vc_sm_ioctl_import_dmabuf(struct sm_priv_data_t *private,
++ struct vmcs_sm_ioctl_import_dmabuf *ioparam,
++ struct dma_buf *src_dma_buf)
+ {
+ int ret = 0;
+ int status;
--- /dev/null
+From 140c118a9886b0386d748e6aa7cbd8ba9f9b0ede Mon Sep 17 00:00:00 2001
+Date: Tue, 19 Mar 2019 17:55:09 +0000
+Subject: [PATCH] staging: bcm2835-codec: NULL component handle on
+ queue_setup failure
+
+queue_setup tries creating the relevant MMAL component and configures
+the input and output ports as we're expecting to start streaming.
+If the port configuration failed then it destroyed the component,
+but failed to clear the component handle, therefore release tried
+destroying the component again.
+Adds some logging should the port config fail as well.
+
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1776,13 +1776,21 @@ static int bcm2835_codec_create_componen
+
+ ret = vchiq_mmal_port_set_format(dev->instance,
+ &ctx->component->input[0]);
+- if (ret < 0)
++ if (ret < 0) {
++ v4l2_dbg(1, debug, &dev->v4l2_dev,
++ "%s: vchiq_mmal_port_set_format ip port failed\n",
++ __func__);
+ goto destroy_component;
++ }
+
+ ret = vchiq_mmal_port_set_format(dev->instance,
+ &ctx->component->output[0]);
+- if (ret < 0)
++ if (ret < 0) {
++ v4l2_dbg(1, debug, &dev->v4l2_dev,
++ "%s: vchiq_mmal_port_set_format op port failed\n",
++ __func__);
+ goto destroy_component;
++ }
+
+ if (dev->role == ENCODE) {
+ u32 param = 1;
+@@ -1812,11 +1820,14 @@ static int bcm2835_codec_create_componen
+ ctx->q_data[V4L2_M2M_DST].sizeimage,
+ ctx->component->output[0].minimum_buffer.size);
+ }
++ v4l2_dbg(2, debug, &dev->v4l2_dev, "%s: component created as %s\n",
++ __func__, components[dev->role]);
+
+ return 0;
+
+ destroy_component:
+ vchiq_mmal_component_finalise(ctx->dev->instance, ctx->component);
++ ctx->component = NULL;
+
+ return ret;
+ }
+++ /dev/null
-From 5a58b2bb907d57dc2b1cc2619bd5f1d948509e3e Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Mar 2019 17:16:41 +0000
-Subject: [PATCH] vcsm: Remove set but unused variable
-
-The 'success' variable is set by the call to vchi_service_close() but never checked.
-Remove it, keeping the call in place.
-
----
- drivers/char/broadcom/vc_sm/vc_vchi_sm.c | 4 +---
- 1 file changed, 1 insertion(+), 3 deletions(-)
-
---- a/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
-+++ b/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
-@@ -361,11 +361,9 @@ int vc_vchi_sm_stop(struct sm_instance *
-
- /* Close all VCHI service connections */
- for (i = 0; i < instance->num_connections; i++) {
-- int32_t success;
--
- vchi_service_use(instance->vchi_handle[i]);
-
-- success = vchi_service_close(instance->vchi_handle[i]);
-+ vchi_service_close(instance->vchi_handle[i]);
- }
-
- kfree(instance);
--- /dev/null
+From 4857371a7cc5d371b1e4221fa38848716a779eb1 Mon Sep 17 00:00:00 2001
+Date: Fri, 8 Mar 2019 10:49:17 +0000
+Subject: [PATCH] staging: vc-sm-cma: Remove the debugfs directory on
+ remove
+
+Without removing that, reloading the driver fails.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -757,7 +757,7 @@ static int bcm2835_vc_sm_cma_remove(stru
+ pr_debug("[%s]: start\n", __func__);
+ if (sm_inited) {
+ /* Remove all proc entries. */
+- //debugfs_remove_recursive(sm_state->dir_root);
++ debugfs_remove_recursive(sm_state->dir_root);
+
+ /* Stop the videocore shared memory service. */
+ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
+++ /dev/null
-From 2a1fd1a32b7355c6ae8c5fc1654a96fa42e00586 Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Mar 2019 17:17:40 +0000
-Subject: [PATCH] vcsm: Reduce scope of local functions
-
-The functions:
-
- vc_vchi_sm_send_msg
- vc_sm_ioctl_alloc
- vc_sm_ioctl_alloc_share
- vc_sm_ioctl_import_dmabuf
-
-Are declared without a prototype. They are not used outside of this
-module, thus - convert them to static functions.
-
----
- drivers/char/broadcom/vc_sm/vc_vchi_sm.c | 2 +-
- drivers/char/broadcom/vc_sm/vmcs_sm.c | 14 +++++++-------
- 2 files changed, 8 insertions(+), 8 deletions(-)
-
---- a/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
-+++ b/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
-@@ -375,7 +375,7 @@ lock:
- return -EINVAL;
- }
-
--int vc_vchi_sm_send_msg(struct sm_instance *handle,
-+static int vc_vchi_sm_send_msg(struct sm_instance *handle,
- enum vc_sm_msg_type msg_id,
- void *msg, uint32_t msg_size,
- void *result, uint32_t result_size,
---- a/drivers/char/broadcom/vc_sm/vmcs_sm.c
-+++ b/drivers/char/broadcom/vc_sm/vmcs_sm.c
-@@ -1574,8 +1574,8 @@ error:
- }
-
- /* Allocate a shared memory handle and block. */
--int vc_sm_ioctl_alloc(struct sm_priv_data_t *private,
-- struct vmcs_sm_ioctl_alloc *ioparam)
-+static int vc_sm_ioctl_alloc(struct sm_priv_data_t *private,
-+ struct vmcs_sm_ioctl_alloc *ioparam)
- {
- int ret = 0;
- int status;
-@@ -1685,8 +1685,8 @@ error:
- }
-
- /* Share an allocate memory handle and block.*/
--int vc_sm_ioctl_alloc_share(struct sm_priv_data_t *private,
-- struct vmcs_sm_ioctl_alloc_share *ioparam)
-+static int vc_sm_ioctl_alloc_share(struct sm_priv_data_t *private,
-+ struct vmcs_sm_ioctl_alloc_share *ioparam)
- {
- struct sm_resource_t *resource, *shared_resource;
- int ret = 0;
-@@ -2200,9 +2200,9 @@ error:
- }
-
- /* Import a contiguous block of memory to be shared with VC. */
--int vc_sm_ioctl_import_dmabuf(struct sm_priv_data_t *private,
-- struct vmcs_sm_ioctl_import_dmabuf *ioparam,
-- struct dma_buf *src_dma_buf)
-+static int vc_sm_ioctl_import_dmabuf(struct sm_priv_data_t *private,
-+ struct vmcs_sm_ioctl_import_dmabuf *ioparam,
-+ struct dma_buf *src_dma_buf)
- {
- int ret = 0;
- int status;
+++ /dev/null
-From 140c118a9886b0386d748e6aa7cbd8ba9f9b0ede Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Mar 2019 17:55:09 +0000
-Subject: [PATCH] staging: bcm2835-codec: NULL component handle on
- queue_setup failure
-
-queue_setup tries creating the relevant MMAL component and configures
-the input and output ports as we're expecting to start streaming.
-If the port configuration failed then it destroyed the component,
-but failed to clear the component handle, therefore release tried
-destroying the component again.
-Adds some logging should the port config fail as well.
-
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 15 +++++++++++++--
- 1 file changed, 13 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1776,13 +1776,21 @@ static int bcm2835_codec_create_componen
-
- ret = vchiq_mmal_port_set_format(dev->instance,
- &ctx->component->input[0]);
-- if (ret < 0)
-+ if (ret < 0) {
-+ v4l2_dbg(1, debug, &dev->v4l2_dev,
-+ "%s: vchiq_mmal_port_set_format ip port failed\n",
-+ __func__);
- goto destroy_component;
-+ }
-
- ret = vchiq_mmal_port_set_format(dev->instance,
- &ctx->component->output[0]);
-- if (ret < 0)
-+ if (ret < 0) {
-+ v4l2_dbg(1, debug, &dev->v4l2_dev,
-+ "%s: vchiq_mmal_port_set_format op port failed\n",
-+ __func__);
- goto destroy_component;
-+ }
-
- if (dev->role == ENCODE) {
- u32 param = 1;
-@@ -1812,11 +1820,14 @@ static int bcm2835_codec_create_componen
- ctx->q_data[V4L2_M2M_DST].sizeimage,
- ctx->component->output[0].minimum_buffer.size);
- }
-+ v4l2_dbg(2, debug, &dev->v4l2_dev, "%s: component created as %s\n",
-+ __func__, components[dev->role]);
-
- return 0;
-
- destroy_component:
- vchiq_mmal_component_finalise(ctx->dev->instance, ctx->component);
-+ ctx->component = NULL;
-
- return ret;
- }
--- /dev/null
+From 6214831525192a9eb665c67fe8c93006c17acbad Mon Sep 17 00:00:00 2001
+Date: Fri, 8 Mar 2019 11:06:41 +0000
+Subject: [PATCH] staging: vc-sm-cma: Use devm_ allocs for sm_state.
+
+Use managed allocations for sm_state, removing reliance on
+manual management.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -656,7 +656,7 @@ static void vc_sm_connected_init(void)
+ __func__, ret);
+
+ ret = -EIO;
+- goto err_free_mem;
++ goto err_failed;
+ }
+
+ ret = vchi_connect(NULL, 0, vchi_instance);
+@@ -665,7 +665,7 @@ static void vc_sm_connected_init(void)
+ __func__, ret);
+
+ ret = -EIO;
+- goto err_free_mem;
++ goto err_failed;
+ }
+
+ /* Initialize an instance of the shared memory service. */
+@@ -676,7 +676,7 @@ static void vc_sm_connected_init(void)
+ __func__);
+
+ ret = -EPERM;
+- goto err_free_mem;
++ goto err_failed;
+ }
+
+ /* Create a debug fs directory entry (root). */
+@@ -722,8 +722,7 @@ err_remove_shared_memory:
+ debugfs_remove_recursive(sm_state->dir_root);
+ err_stop_sm_service:
+ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
+-err_free_mem:
+- kfree(sm_state);
++err_failed:
+ pr_info("[%s]: failed, ret %d\n", __func__, ret);
+ }
+
+@@ -732,7 +731,7 @@ static int bcm2835_vc_sm_cma_probe(struc
+ {
+ pr_info("%s: Videocore shared memory driver\n", __func__);
+
+- sm_state = kzalloc(sizeof(*sm_state), GFP_KERNEL);
++ sm_state = devm_kzalloc(&pdev->dev, sizeof(*sm_state), GFP_KERNEL);
+ if (!sm_state)
+ return -ENOMEM;
+ sm_state->pdev = pdev;
+@@ -766,7 +765,6 @@ static int bcm2835_vc_sm_cma_remove(stru
+
+ /* Free the memory for the state structure. */
+ mutex_destroy(&sm_state->map_lock);
+- kfree(sm_state);
+ }
+
+ pr_debug("[%s]: end\n", __func__);
--- /dev/null
+From 13572df6bba85d8fc91a212faa89b5b6147bdf94 Mon Sep 17 00:00:00 2001
+Date: Fri, 8 Mar 2019 11:09:49 +0000
+Subject: [PATCH] staging: vc-sm-cma: Don't fail if debugfs calls fail.
+
+Return codes from debugfs calls should never alter the
+flow of the main code.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 8 --------
+ 1 file changed, 8 deletions(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -681,13 +681,6 @@ static void vc_sm_connected_init(void)
+
+ /* Create a debug fs directory entry (root). */
+ sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL);
+- if (!sm_state->dir_root) {
+- pr_err("[%s]: failed to create \'%s\' directory entry\n",
+- __func__, VC_SM_DIR_ROOT_NAME);
+-
+- ret = -EPERM;
+- goto err_stop_sm_service;
+- }
+
+ sm_state->dir_state.show = &vc_sm_cma_global_state_show;
+ sm_state->dir_state.dir_entry =
+@@ -720,7 +713,6 @@ static void vc_sm_connected_init(void)
+
+ err_remove_shared_memory:
+ debugfs_remove_recursive(sm_state->dir_root);
+-err_stop_sm_service:
+ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
+ err_failed:
+ pr_info("[%s]: failed, ret %d\n", __func__, ret);
+++ /dev/null
-From 4857371a7cc5d371b1e4221fa38848716a779eb1 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Mar 2019 10:49:17 +0000
-Subject: [PATCH] staging: vc-sm-cma: Remove the debugfs directory on
- remove
-
-Without removing that, reloading the driver fails.
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -757,7 +757,7 @@ static int bcm2835_vc_sm_cma_remove(stru
- pr_debug("[%s]: start\n", __func__);
- if (sm_inited) {
- /* Remove all proc entries. */
-- //debugfs_remove_recursive(sm_state->dir_root);
-+ debugfs_remove_recursive(sm_state->dir_root);
-
- /* Stop the videocore shared memory service. */
- vc_sm_cma_vchi_stop(&sm_state->sm_handle);
--- /dev/null
+From 4027b08d96c68919f51c768a23877283ef5aefb9 Mon Sep 17 00:00:00 2001
+Date: Fri, 8 Mar 2019 11:11:46 +0000
+Subject: [PATCH] staging: vc-sm-cma: Ensure mutex and idr are
+ destroyed
+
+map_lock and kernelid_map are created in probe, but not released
+in release should the vcsm service not connect (eg running the
+cutdown firmware).
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -752,7 +752,9 @@ static int bcm2835_vc_sm_cma_remove(stru
+
+ /* Stop the videocore shared memory service. */
+ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
++ }
+
++ if (sm_state) {
+ idr_destroy(&sm_state->kernelid_map);
+
+ /* Free the memory for the state structure. */
+++ /dev/null
-From 6214831525192a9eb665c67fe8c93006c17acbad Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Mar 2019 11:06:41 +0000
-Subject: [PATCH] staging: vc-sm-cma: Use devm_ allocs for sm_state.
-
-Use managed allocations for sm_state, removing reliance on
-manual management.
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 12 +++++-------
- 1 file changed, 5 insertions(+), 7 deletions(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -656,7 +656,7 @@ static void vc_sm_connected_init(void)
- __func__, ret);
-
- ret = -EIO;
-- goto err_free_mem;
-+ goto err_failed;
- }
-
- ret = vchi_connect(NULL, 0, vchi_instance);
-@@ -665,7 +665,7 @@ static void vc_sm_connected_init(void)
- __func__, ret);
-
- ret = -EIO;
-- goto err_free_mem;
-+ goto err_failed;
- }
-
- /* Initialize an instance of the shared memory service. */
-@@ -676,7 +676,7 @@ static void vc_sm_connected_init(void)
- __func__);
-
- ret = -EPERM;
-- goto err_free_mem;
-+ goto err_failed;
- }
-
- /* Create a debug fs directory entry (root). */
-@@ -722,8 +722,7 @@ err_remove_shared_memory:
- debugfs_remove_recursive(sm_state->dir_root);
- err_stop_sm_service:
- vc_sm_cma_vchi_stop(&sm_state->sm_handle);
--err_free_mem:
-- kfree(sm_state);
-+err_failed:
- pr_info("[%s]: failed, ret %d\n", __func__, ret);
- }
-
-@@ -732,7 +731,7 @@ static int bcm2835_vc_sm_cma_probe(struc
- {
- pr_info("%s: Videocore shared memory driver\n", __func__);
-
-- sm_state = kzalloc(sizeof(*sm_state), GFP_KERNEL);
-+ sm_state = devm_kzalloc(&pdev->dev, sizeof(*sm_state), GFP_KERNEL);
- if (!sm_state)
- return -ENOMEM;
- sm_state->pdev = pdev;
-@@ -766,7 +765,6 @@ static int bcm2835_vc_sm_cma_remove(stru
-
- /* Free the memory for the state structure. */
- mutex_destroy(&sm_state->map_lock);
-- kfree(sm_state);
- }
-
- pr_debug("[%s]: end\n", __func__);
--- /dev/null
+From c42ae04bb6ed5be61d3b3e2e2c6004ae252ee34a Mon Sep 17 00:00:00 2001
+Date: Fri, 8 Mar 2019 11:26:00 +0000
+Subject: [PATCH] staging: bcm2835_codec: Clean up logging on unloading
+ the driver
+
+The log line was missing a closing \n, so wasn't added to the
+log immediately.
+Adds the function of the V4L2 device that is being unregistered
+too.
+
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -77,6 +77,12 @@ enum bcm2835_codec_role {
+ ISP,
+ };
+
++const static char *roles[] = {
++ "decode",
++ "encode",
++ "isp"
++};
++
+ static const char * const components[] = {
+ "ril.video_decode",
+ "ril.video_encode",
+@@ -2522,7 +2528,6 @@ static int bcm2835_codec_create(struct p
+ struct video_device *vfd;
+ int video_nr;
+ int ret;
+- const static char *roles[] = {"decode", "encode", "isp"};
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+@@ -2615,7 +2620,8 @@ static int bcm2835_codec_destroy(struct
+ if (!dev)
+ return -ENODEV;
+
+- v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
++ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME ", %s\n",
++ roles[dev->role]);
+ v4l2_m2m_release(dev->m2m_dev);
+ video_unregister_device(&dev->vfd);
+ v4l2_device_unregister(&dev->v4l2_dev);
+++ /dev/null
-From 13572df6bba85d8fc91a212faa89b5b6147bdf94 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Mar 2019 11:09:49 +0000
-Subject: [PATCH] staging: vc-sm-cma: Don't fail if debugfs calls fail.
-
-Return codes from debugfs calls should never alter the
-flow of the main code.
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 8 --------
- 1 file changed, 8 deletions(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -681,13 +681,6 @@ static void vc_sm_connected_init(void)
-
- /* Create a debug fs directory entry (root). */
- sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL);
-- if (!sm_state->dir_root) {
-- pr_err("[%s]: failed to create \'%s\' directory entry\n",
-- __func__, VC_SM_DIR_ROOT_NAME);
--
-- ret = -EPERM;
-- goto err_stop_sm_service;
-- }
-
- sm_state->dir_state.show = &vc_sm_cma_global_state_show;
- sm_state->dir_state.dir_entry =
-@@ -720,7 +713,6 @@ static void vc_sm_connected_init(void)
-
- err_remove_shared_memory:
- debugfs_remove_recursive(sm_state->dir_root);
--err_stop_sm_service:
- vc_sm_cma_vchi_stop(&sm_state->sm_handle);
- err_failed:
- pr_info("[%s]: failed, ret %d\n", __func__, ret);
--- /dev/null
+From 44db7882be675cdf2d89741af5bbeba41b3e25af Mon Sep 17 00:00:00 2001
+Date: Wed, 13 Mar 2019 14:19:11 +0000
+Subject: [PATCH] bcm2835-sdhost: Allow for sg entries that cross pages
+
+The dma_complete handling code calculates a virtual address for a page
+then adds an offset, but if the offset is more than a page and HIGHMEM
+is in use then the summed address could be in an unmapped (or just
+incorrect) page.
+
+The upstream SDHOST driver allows for this possibility - copy the code
+that does so.
+
+---
+ drivers/mmc/host/bcm2835-sdhost.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -543,6 +543,11 @@ static void bcm2835_sdhost_dma_complete(
+ void *page;
+ u32 *buf;
+
++ if (host->drain_offset & PAGE_MASK) {
++ host->drain_page += host->drain_offset >> PAGE_SHIFT;
++ host->drain_offset &= ~PAGE_MASK;
++ }
++
+ page = kmap_atomic(host->drain_page);
+ buf = page + host->drain_offset;
+
+++ /dev/null
-From 4027b08d96c68919f51c768a23877283ef5aefb9 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Mar 2019 11:11:46 +0000
-Subject: [PATCH] staging: vc-sm-cma: Ensure mutex and idr are
- destroyed
-
-map_lock and kernelid_map are created in probe, but not released
-in release should the vcsm service not connect (eg running the
-cutdown firmware).
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -752,7 +752,9 @@ static int bcm2835_vc_sm_cma_remove(stru
-
- /* Stop the videocore shared memory service. */
- vc_sm_cma_vchi_stop(&sm_state->sm_handle);
-+ }
-
-+ if (sm_state) {
- idr_destroy(&sm_state->kernelid_map);
-
- /* Free the memory for the state structure. */
--- /dev/null
+From 7c23c772289fa31960b9e6969499aa93c92d842b Mon Sep 17 00:00:00 2001
+Date: Fri, 22 Mar 2019 11:35:30 +0100
+Subject: [PATCH] overlays: sdio: Added 4-bit support on GPIOs 34-39.
+ (#2903)
+
+---
+ arch/arm/boot/dts/overlays/README | 3 +++
+ arch/arm/boot/dts/overlays/sdio-overlay.dts | 9 +++++++++
+ 2 files changed, 12 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1785,6 +1785,9 @@ Params: sdio_overclock SDIO Clo
+ gpios_34_37 Select GPIOs 34-37 for 1-bit mode. Must be used
+ with bus_width=1.
+
++ gpios_34_39 Select GPIOs 34-39 for 4-bit mode. Must be used
++ with bus_width=4 (the default).
++
+
+ Name: sdio-1bit
+ Info: This overlay is now deprecated. Use
+--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
+@@ -64,6 +64,14 @@
+ };
+ };
+
++ fragment@5 {
++ target = <&sdio_ovl_pins>;
++ __dormant__ {
++ brcm,pins = <34 35 36 37 38 39>;
++ brcm,pull = <0 2 2 2 2 2>;
++ };
++ };
++
+ fragment@6 {
+ target-path = "/aliases";
+ __overlay__ {
+@@ -77,5 +85,6 @@
+ sdio_overclock = <&sdio_ovl>,"brcm,overclock-50:0";
+ gpios_22_25 = <0>,"=3";
+ gpios_34_37 = <0>,"=4";
++ gpios_34_39 = <0>,"=5";
+ };
+ };
+++ /dev/null
-From c42ae04bb6ed5be61d3b3e2e2c6004ae252ee34a Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Mar 2019 11:26:00 +0000
-Subject: [PATCH] staging: bcm2835_codec: Clean up logging on unloading
- the driver
-
-The log line was missing a closing \n, so wasn't added to the
-log immediately.
-Adds the function of the V4L2 device that is being unregistered
-too.
-
----
- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -77,6 +77,12 @@ enum bcm2835_codec_role {
- ISP,
- };
-
-+const static char *roles[] = {
-+ "decode",
-+ "encode",
-+ "isp"
-+};
-+
- static const char * const components[] = {
- "ril.video_decode",
- "ril.video_encode",
-@@ -2522,7 +2528,6 @@ static int bcm2835_codec_create(struct p
- struct video_device *vfd;
- int video_nr;
- int ret;
-- const static char *roles[] = {"decode", "encode", "isp"};
-
- dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
- if (!dev)
-@@ -2615,7 +2620,8 @@ static int bcm2835_codec_destroy(struct
- if (!dev)
- return -ENODEV;
-
-- v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
-+ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME ", %s\n",
-+ roles[dev->role]);
- v4l2_m2m_release(dev->m2m_dev);
- video_unregister_device(&dev->vfd);
- v4l2_device_unregister(&dev->v4l2_dev);
+++ /dev/null
-From 44db7882be675cdf2d89741af5bbeba41b3e25af Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Mar 2019 14:19:11 +0000
-Subject: [PATCH] bcm2835-sdhost: Allow for sg entries that cross pages
-
-The dma_complete handling code calculates a virtual address for a page
-then adds an offset, but if the offset is more than a page and HIGHMEM
-is in use then the summed address could be in an unmapped (or just
-incorrect) page.
-
-The upstream SDHOST driver allows for this possibility - copy the code
-that does so.
-
----
- drivers/mmc/host/bcm2835-sdhost.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/mmc/host/bcm2835-sdhost.c
-+++ b/drivers/mmc/host/bcm2835-sdhost.c
-@@ -543,6 +543,11 @@ static void bcm2835_sdhost_dma_complete(
- void *page;
- u32 *buf;
-
-+ if (host->drain_offset & PAGE_MASK) {
-+ host->drain_page += host->drain_offset >> PAGE_SHIFT;
-+ host->drain_offset &= ~PAGE_MASK;
-+ }
-+
- page = kmap_atomic(host->drain_page);
- buf = page + host->drain_offset;
-
--- /dev/null
+From 649efe5db3900ed3bbfd3c3daa3b96d8fc0b9d68 Mon Sep 17 00:00:00 2001
+Date: Fri, 22 Mar 2019 16:44:47 +0000
+Subject: [PATCH] overlays: Fix multiple-instantiation of sc16is7xx*
+
+The registration of the fixed clocks uses the node name as the clock
+name, causing a clash if two clock nodes have the same name, regardless
+of the path to the node. Fix the issue by overwriting the clock node
+names using the value of the "addr" parameter, providing a crude
+disambiguation. (A bit of string pasting to form "sc16is752_clk_<addr>"
+would have been nice, but that is outside the abilities of the overlay
+parameter mechanism.)
+
+Also give the sc16is750-i2c overlay the xtal parameter for symmetry.
+
+See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=235650
+
+---
+ arch/arm/boot/dts/overlays/README | 1 +
+ arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts | 3 ++-
+ arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts | 2 +-
+ 3 files changed, 4 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1725,6 +1725,7 @@ Info: Overlay for the NXP SC16IS750 UA
+ Load: dtoverlay=sc16is750-i2c,<param>=<val>
+ Params: int_pin GPIO used for IRQ (default 24)
+ addr Address (default 0x48)
++ xtal On-board crystal frequency (default 14745600)
+
+
+ Name: sc16is752-i2c
+--- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
+@@ -31,7 +31,8 @@
+
+ __overrides__ {
+ int_pin = <&sc16is750>,"interrupts:0";
+- addr = <&sc16is750>,"reg:0";
++ addr = <&sc16is750>,"reg:0",<&sc16is750_clk>,"name";
++ xtal = <&sc16is750>,"clock-frequency:0";
+ };
+
+ };
+--- a/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts
+@@ -34,7 +34,7 @@
+
+ __overrides__ {
+ int_pin = <&sc16is752>,"interrupts:0";
+- addr = <&sc16is752>,"reg:0";
++ addr = <&sc16is752>,"reg:0",<&sc16is752_clk>,"name";
+ xtal = <&sc16is752>,"clock-frequency:0";
+ };
+ };
--- /dev/null
+From 7458efc95816cc9d716d94a4894172c2a9d9fba7 Mon Sep 17 00:00:00 2001
+Date: Wed, 16 Jan 2019 12:22:32 +0100
+Subject: [PATCH] bcm2835-mmc: Fix DMA channel leak
+
+The BCM2835 MMC host driver requests a DMA channel on probe but neglects
+to release the channel in the probe error path and on driver unbind.
+
+I'm seeing this happen on every boot of the Compute Module 3: On first
+driver probe, DMA channel 2 is allocated and then leaked with a "could
+not get clk, deferring probe" message. On second driver probe, channel 4
+is allocated.
+
+Fix it.
+
+---
+ drivers/mmc/host/bcm2835-mmc.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/mmc/host/bcm2835-mmc.c
++++ b/drivers/mmc/host/bcm2835-mmc.c
+@@ -1503,6 +1503,8 @@ static int bcm2835_mmc_probe(struct plat
+
+ return 0;
+ err:
++ if (host->dma_chan_rxtx)
++ dma_release_channel(host->dma_chan_rxtx);
+ mmc_free_host(mmc);
+
+ return ret;
+@@ -1548,6 +1550,9 @@ static int bcm2835_mmc_remove(struct pla
+
+ tasklet_kill(&host->finish_tasklet);
+
++ if (host->dma_chan_rxtx)
++ dma_release_channel(host->dma_chan_rxtx);
++
+ mmc_free_host(host->mmc);
+ platform_set_drvdata(pdev, NULL);
+
+++ /dev/null
-From 7c23c772289fa31960b9e6969499aa93c92d842b Mon Sep 17 00:00:00 2001
-Date: Fri, 22 Mar 2019 11:35:30 +0100
-Subject: [PATCH] overlays: sdio: Added 4-bit support on GPIOs 34-39.
- (#2903)
-
----
- arch/arm/boot/dts/overlays/README | 3 +++
- arch/arm/boot/dts/overlays/sdio-overlay.dts | 9 +++++++++
- 2 files changed, 12 insertions(+)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1785,6 +1785,9 @@ Params: sdio_overclock SDIO Clo
- gpios_34_37 Select GPIOs 34-37 for 1-bit mode. Must be used
- with bus_width=1.
-
-+ gpios_34_39 Select GPIOs 34-39 for 4-bit mode. Must be used
-+ with bus_width=4 (the default).
-+
-
- Name: sdio-1bit
- Info: This overlay is now deprecated. Use
---- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
-@@ -64,6 +64,14 @@
- };
- };
-
-+ fragment@5 {
-+ target = <&sdio_ovl_pins>;
-+ __dormant__ {
-+ brcm,pins = <34 35 36 37 38 39>;
-+ brcm,pull = <0 2 2 2 2 2>;
-+ };
-+ };
-+
- fragment@6 {
- target-path = "/aliases";
- __overlay__ {
-@@ -77,5 +85,6 @@
- sdio_overclock = <&sdio_ovl>,"brcm,overclock-50:0";
- gpios_22_25 = <0>,"=3";
- gpios_34_37 = <0>,"=4";
-+ gpios_34_39 = <0>,"=5";
- };
- };
--- /dev/null
+From 82ced13dc5805f6e49e2182269e672b20d8394bc Mon Sep 17 00:00:00 2001
+Date: Sat, 19 Jan 2019 08:06:48 +0100
+Subject: [PATCH] bcm2835-mmc: Fix struct mmc_host leak on probe
+
+The BCM2835 MMC host driver requests the bus address of the host's
+register map on probe. If that fails, the driver leaks the struct
+mmc_host allocated earlier.
+
+Fix it.
+
+---
+ drivers/mmc/host/bcm2835-mmc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/mmc/host/bcm2835-mmc.c
++++ b/drivers/mmc/host/bcm2835-mmc.c
+@@ -1439,7 +1439,8 @@ static int bcm2835_mmc_probe(struct plat
+ addr = of_get_address(node, 0, NULL, NULL);
+ if (!addr) {
+ dev_err(dev, "could not get DMA-register address\n");
+- return -ENODEV;
++ ret = -ENODEV;
++ goto err;
+ }
+ host->bus_addr = be32_to_cpup(addr);
+ pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
+++ /dev/null
-From 649efe5db3900ed3bbfd3c3daa3b96d8fc0b9d68 Mon Sep 17 00:00:00 2001
-Date: Fri, 22 Mar 2019 16:44:47 +0000
-Subject: [PATCH] overlays: Fix multiple-instantiation of sc16is7xx*
-
-The registration of the fixed clocks uses the node name as the clock
-name, causing a clash if two clock nodes have the same name, regardless
-of the path to the node. Fix the issue by overwriting the clock node
-names using the value of the "addr" parameter, providing a crude
-disambiguation. (A bit of string pasting to form "sc16is752_clk_<addr>"
-would have been nice, but that is outside the abilities of the overlay
-parameter mechanism.)
-
-Also give the sc16is750-i2c overlay the xtal parameter for symmetry.
-
-See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=235650
-
----
- arch/arm/boot/dts/overlays/README | 1 +
- arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts | 3 ++-
- arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts | 2 +-
- 3 files changed, 4 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1725,6 +1725,7 @@ Info: Overlay for the NXP SC16IS750 UA
- Load: dtoverlay=sc16is750-i2c,<param>=<val>
- Params: int_pin GPIO used for IRQ (default 24)
- addr Address (default 0x48)
-+ xtal On-board crystal frequency (default 14745600)
-
-
- Name: sc16is752-i2c
---- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
-@@ -31,7 +31,8 @@
-
- __overrides__ {
- int_pin = <&sc16is750>,"interrupts:0";
-- addr = <&sc16is750>,"reg:0";
-+ addr = <&sc16is750>,"reg:0",<&sc16is750_clk>,"name";
-+ xtal = <&sc16is750>,"clock-frequency:0";
- };
-
- };
---- a/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts
-@@ -34,7 +34,7 @@
-
- __overrides__ {
- int_pin = <&sc16is752>,"interrupts:0";
-- addr = <&sc16is752>,"reg:0";
-+ addr = <&sc16is752>,"reg:0",<&sc16is752_clk>,"name";
- xtal = <&sc16is752>,"clock-frequency:0";
- };
- };
+++ /dev/null
-From 7458efc95816cc9d716d94a4894172c2a9d9fba7 Mon Sep 17 00:00:00 2001
-Date: Wed, 16 Jan 2019 12:22:32 +0100
-Subject: [PATCH] bcm2835-mmc: Fix DMA channel leak
-
-The BCM2835 MMC host driver requests a DMA channel on probe but neglects
-to release the channel in the probe error path and on driver unbind.
-
-I'm seeing this happen on every boot of the Compute Module 3: On first
-driver probe, DMA channel 2 is allocated and then leaked with a "could
-not get clk, deferring probe" message. On second driver probe, channel 4
-is allocated.
-
-Fix it.
-
----
- drivers/mmc/host/bcm2835-mmc.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/mmc/host/bcm2835-mmc.c
-+++ b/drivers/mmc/host/bcm2835-mmc.c
-@@ -1503,6 +1503,8 @@ static int bcm2835_mmc_probe(struct plat
-
- return 0;
- err:
-+ if (host->dma_chan_rxtx)
-+ dma_release_channel(host->dma_chan_rxtx);
- mmc_free_host(mmc);
-
- return ret;
-@@ -1548,6 +1550,9 @@ static int bcm2835_mmc_remove(struct pla
-
- tasklet_kill(&host->finish_tasklet);
-
-+ if (host->dma_chan_rxtx)
-+ dma_release_channel(host->dma_chan_rxtx);
-+
- mmc_free_host(host->mmc);
- platform_set_drvdata(pdev, NULL);
-
--- /dev/null
+From 4a15e086fa9531f808c15b8fb8d7ed1fdb411b74 Mon Sep 17 00:00:00 2001
+Date: Sat, 19 Jan 2019 09:00:26 +0100
+Subject: [PATCH] bcm2835-mmc: Fix duplicate free_irq() on remove
+
+The BCM2835 MMC host driver requests its interrupt as a device-managed
+resource, so the interrupt is automatically freed after the driver is
+unbound.
+
+However on driver unbind, bcm2835_mmc_remove() frees the interrupt
+explicitly to avoid invocation of the interrupt handler after driver
+structures have been torn down.
+
+The interrupt is thus freed twice, leading to a WARN splat in
+__free_irq(). Fix by not requesting the interrupt as a device-managed
+resource.
+
+---
+ drivers/mmc/host/bcm2835-mmc.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/mmc/host/bcm2835-mmc.c
++++ b/drivers/mmc/host/bcm2835-mmc.c
+@@ -1389,9 +1389,9 @@ static int bcm2835_mmc_add_host(struct b
+ init_waitqueue_head(&host->buf_ready_int);
+
+ bcm2835_mmc_init(host, 0);
+- ret = devm_request_threaded_irq(dev, host->irq, bcm2835_mmc_irq,
+- bcm2835_mmc_thread_irq, IRQF_SHARED,
+- mmc_hostname(mmc), host);
++ ret = request_threaded_irq(host->irq, bcm2835_mmc_irq,
++ bcm2835_mmc_thread_irq, IRQF_SHARED,
++ mmc_hostname(mmc), host);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ %d: %d\n", host->irq, ret);
+ goto untasklet;
+++ /dev/null
-From 82ced13dc5805f6e49e2182269e672b20d8394bc Mon Sep 17 00:00:00 2001
-Date: Sat, 19 Jan 2019 08:06:48 +0100
-Subject: [PATCH] bcm2835-mmc: Fix struct mmc_host leak on probe
-
-The BCM2835 MMC host driver requests the bus address of the host's
-register map on probe. If that fails, the driver leaks the struct
-mmc_host allocated earlier.
-
-Fix it.
-
----
- drivers/mmc/host/bcm2835-mmc.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/mmc/host/bcm2835-mmc.c
-+++ b/drivers/mmc/host/bcm2835-mmc.c
-@@ -1439,7 +1439,8 @@ static int bcm2835_mmc_probe(struct plat
- addr = of_get_address(node, 0, NULL, NULL);
- if (!addr) {
- dev_err(dev, "could not get DMA-register address\n");
-- return -ENODEV;
-+ ret = -ENODEV;
-+ goto err;
- }
- host->bus_addr = be32_to_cpup(addr);
- pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
--- /dev/null
+From 2e2f57e09e1ace18ae01a87d9fc4378c96c54370 Mon Sep 17 00:00:00 2001
+Date: Tue, 22 Jan 2019 12:29:45 +0100
+Subject: [PATCH] bcm2835-mmc: Handle mmc_add_host() errors
+
+The BCM2835 MMC host driver calls mmc_add_host() but doesn't check its
+return value. Errors occurring in that function are therefore not
+handled. Fix it.
+
+---
+ drivers/mmc/host/bcm2835-mmc.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/mmc/host/bcm2835-mmc.c
++++ b/drivers/mmc/host/bcm2835-mmc.c
+@@ -1398,10 +1398,16 @@ static int bcm2835_mmc_add_host(struct b
+ }
+
+ mmiowb();
+- mmc_add_host(mmc);
++ ret = mmc_add_host(mmc);
++ if (ret) {
++ dev_err(dev, "could not add MMC host\n");
++ goto free_irq;
++ }
+
+ return 0;
+
++free_irq:
++ free_irq(host->irq, host);
+ untasklet:
+ tasklet_kill(&host->finish_tasklet);
+
--- /dev/null
+From 3f6e190df3989e10a9baf591a7bf67d754842533 Mon Sep 17 00:00:00 2001
+Date: Sat, 19 Jan 2019 08:42:40 +0100
+Subject: [PATCH] bcm2835-mmc: Deduplicate reset of driver data on
+ remove
+
+The BCM2835 MMC host driver sets the device's driver data pointer to
+NULL on ->remove() even though the driver core subsequently does the
+same in __device_release_driver(). Drop the duplicate assignment.
+
+---
+ drivers/mmc/host/bcm2835-mmc.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/mmc/host/bcm2835-mmc.c
++++ b/drivers/mmc/host/bcm2835-mmc.c
+@@ -1561,7 +1561,6 @@ static int bcm2835_mmc_remove(struct pla
+ dma_release_channel(host->dma_chan_rxtx);
+
+ mmc_free_host(host->mmc);
+- platform_set_drvdata(pdev, NULL);
+
+ return 0;
+ }
+++ /dev/null
-From 4a15e086fa9531f808c15b8fb8d7ed1fdb411b74 Mon Sep 17 00:00:00 2001
-Date: Sat, 19 Jan 2019 09:00:26 +0100
-Subject: [PATCH] bcm2835-mmc: Fix duplicate free_irq() on remove
-
-The BCM2835 MMC host driver requests its interrupt as a device-managed
-resource, so the interrupt is automatically freed after the driver is
-unbound.
-
-However on driver unbind, bcm2835_mmc_remove() frees the interrupt
-explicitly to avoid invocation of the interrupt handler after driver
-structures have been torn down.
-
-The interrupt is thus freed twice, leading to a WARN splat in
-__free_irq(). Fix by not requesting the interrupt as a device-managed
-resource.
-
----
- drivers/mmc/host/bcm2835-mmc.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/mmc/host/bcm2835-mmc.c
-+++ b/drivers/mmc/host/bcm2835-mmc.c
-@@ -1389,9 +1389,9 @@ static int bcm2835_mmc_add_host(struct b
- init_waitqueue_head(&host->buf_ready_int);
-
- bcm2835_mmc_init(host, 0);
-- ret = devm_request_threaded_irq(dev, host->irq, bcm2835_mmc_irq,
-- bcm2835_mmc_thread_irq, IRQF_SHARED,
-- mmc_hostname(mmc), host);
-+ ret = request_threaded_irq(host->irq, bcm2835_mmc_irq,
-+ bcm2835_mmc_thread_irq, IRQF_SHARED,
-+ mmc_hostname(mmc), host);
- if (ret) {
- dev_err(dev, "Failed to request IRQ %d: %d\n", host->irq, ret);
- goto untasklet;
+++ /dev/null
-From 2e2f57e09e1ace18ae01a87d9fc4378c96c54370 Mon Sep 17 00:00:00 2001
-Date: Tue, 22 Jan 2019 12:29:45 +0100
-Subject: [PATCH] bcm2835-mmc: Handle mmc_add_host() errors
-
-The BCM2835 MMC host driver calls mmc_add_host() but doesn't check its
-return value. Errors occurring in that function are therefore not
-handled. Fix it.
-
----
- drivers/mmc/host/bcm2835-mmc.c | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
---- a/drivers/mmc/host/bcm2835-mmc.c
-+++ b/drivers/mmc/host/bcm2835-mmc.c
-@@ -1398,10 +1398,16 @@ static int bcm2835_mmc_add_host(struct b
- }
-
- mmiowb();
-- mmc_add_host(mmc);
-+ ret = mmc_add_host(mmc);
-+ if (ret) {
-+ dev_err(dev, "could not add MMC host\n");
-+ goto free_irq;
-+ }
-
- return 0;
-
-+free_irq:
-+ free_irq(host->irq, host);
- untasklet:
- tasklet_kill(&host->finish_tasklet);
-
--- /dev/null
+From fe6ccc8df700133615716df211f183c9c27d1e2e Mon Sep 17 00:00:00 2001
+Date: Mon, 25 Mar 2019 18:03:48 +0000
+Subject: [PATCH] overlays: Add max17040 support to i2c-sensor
+
+See: https://github.com/raspberrypi/linux/issues/2906
+
+---
+ arch/arm/boot/dts/overlays/README | 3 +++
+ .../arm/boot/dts/overlays/i2c-sensor-overlay.dts | 16 ++++++++++++++++
+ 2 files changed, 19 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1030,6 +1030,9 @@ Params: addr Set the
+
+ lm75addr Deprecated - use addr parameter instead
+
++ max17040 Select the Maxim Integrated MAX17040 battery
++ monitor
++
+ sht3x Select the Sensiron SHT3x temperature and
+ humidity sensor. Valid addresses 0x44-0x45,
+ default 0x44
+--- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
+@@ -201,6 +201,21 @@
+ };
+ };
+
++ fragment@13 {
++ target = <&i2c_arm>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ max17040: max17040@36 {
++ compatible = "maxim,max17040";
++ reg = <0x36>;
++ status = "okay";
++ };
++ };
++ };
++
+ __overrides__ {
+ addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0",
+ <&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0",
+@@ -219,5 +234,6 @@
+ veml6070 = <0>,"+10";
+ sht3x = <0>,"+11";
+ ds1621 = <0>,"+12";
++ max17040 = <0>,"+13";
+ };
+ };
+++ /dev/null
-From 3f6e190df3989e10a9baf591a7bf67d754842533 Mon Sep 17 00:00:00 2001
-Date: Sat, 19 Jan 2019 08:42:40 +0100
-Subject: [PATCH] bcm2835-mmc: Deduplicate reset of driver data on
- remove
-
-The BCM2835 MMC host driver sets the device's driver data pointer to
-NULL on ->remove() even though the driver core subsequently does the
-same in __device_release_driver(). Drop the duplicate assignment.
-
----
- drivers/mmc/host/bcm2835-mmc.c | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/drivers/mmc/host/bcm2835-mmc.c
-+++ b/drivers/mmc/host/bcm2835-mmc.c
-@@ -1561,7 +1561,6 @@ static int bcm2835_mmc_remove(struct pla
- dma_release_channel(host->dma_chan_rxtx);
-
- mmc_free_host(host->mmc);
-- platform_set_drvdata(pdev, NULL);
-
- return 0;
- }
--- /dev/null
+From 7c876909bc0a6d23124689d5fca89657a4fcb5a5 Mon Sep 17 00:00:00 2001
+Date: Tue, 5 Mar 2019 15:43:27 +0000
+Subject: [PATCH] media: bcm2835-unicam: Add support for enum
+ framesizes and frameintervals
+
+vidioc_enum_framesizes and vidioc_enum_frameintervals weren't implemented,
+therefore clients couldn't enumerate the supported resolutions.
+
+Implement them by forwarding on to the sensor driver.
+
+---
+ .../media/platform/bcm2835/bcm2835-unicam.c | 94 +++++++++++++++++++
+ 1 file changed, 94 insertions(+)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
+@@ -1406,6 +1406,84 @@ static int unicam_g_edid(struct file *fi
+ return v4l2_subdev_call(dev->sensor, pad, get_edid, edid);
+ }
+
++static int unicam_enum_framesizes(struct file *file, void *priv,
++ struct v4l2_frmsizeenum *fsize)
++{
++ struct unicam_device *dev = video_drvdata(file);
++ const struct unicam_fmt *fmt;
++ struct v4l2_subdev_frame_size_enum fse;
++ int ret;
++
++ /* 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;
++ }
++
++ fse.index = fsize->index;
++ fse.pad = 0;
++ fse.code = fmt->code;
++
++ 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;
++
++ return 0;
++}
++
++static int unicam_enum_frameintervals(struct file *file, void *priv,
++ struct v4l2_frmivalenum *fival)
++{
++ struct unicam_device *dev = video_drvdata(file);
++ const struct unicam_fmt *fmt;
++ struct v4l2_subdev_frame_interval_enum fie = {
++ .index = fival->index,
++ .width = fival->width,
++ .height = fival->height,
++ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
++ };
++ 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;
++}
++
++static int unicam_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
++{
++ struct unicam_device *dev = video_drvdata(file);
++
++ return v4l2_g_parm_cap(video_devdata(file), dev->sensor, a);
++}
++
++static int unicam_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
++{
++ struct unicam_device *dev = video_drvdata(file);
++
++ return v4l2_s_parm_cap(video_devdata(file), dev->sensor, a);
++}
++
+ static int unicam_g_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+ {
+@@ -1613,6 +1691,12 @@ static const struct v4l2_ioctl_ops unica
+ .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_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,
+@@ -1850,6 +1934,16 @@ static int unicam_probe_complete(struct
+ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUM_DV_TIMINGS);
+ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_QUERY_DV_TIMINGS);
+ }
++ if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_interval))
++ v4l2_disable_ioctl(&unicam->video_dev,
++ VIDIOC_ENUM_FRAMEINTERVALS);
++ if (!v4l2_subdev_has_op(unicam->sensor, video, g_frame_interval))
++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_PARM);
++ if (!v4l2_subdev_has_op(unicam->sensor, video, s_frame_interval))
++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_PARM);
++
++ if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_size))
++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUM_FRAMESIZES);
+
+ ret = v4l2_device_register_subdev_nodes(&unicam->v4l2_dev);
+ if (ret) {
+++ /dev/null
-From fe6ccc8df700133615716df211f183c9c27d1e2e Mon Sep 17 00:00:00 2001
-Date: Mon, 25 Mar 2019 18:03:48 +0000
-Subject: [PATCH] overlays: Add max17040 support to i2c-sensor
-
-See: https://github.com/raspberrypi/linux/issues/2906
-
----
- arch/arm/boot/dts/overlays/README | 3 +++
- .../arm/boot/dts/overlays/i2c-sensor-overlay.dts | 16 ++++++++++++++++
- 2 files changed, 19 insertions(+)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1030,6 +1030,9 @@ Params: addr Set the
-
- lm75addr Deprecated - use addr parameter instead
-
-+ max17040 Select the Maxim Integrated MAX17040 battery
-+ monitor
-+
- sht3x Select the Sensiron SHT3x temperature and
- humidity sensor. Valid addresses 0x44-0x45,
- default 0x44
---- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
-@@ -201,6 +201,21 @@
- };
- };
-
-+ fragment@13 {
-+ target = <&i2c_arm>;
-+ __dormant__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ max17040: max17040@36 {
-+ compatible = "maxim,max17040";
-+ reg = <0x36>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
- __overrides__ {
- addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0",
- <&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0",
-@@ -219,5 +234,6 @@
- veml6070 = <0>,"+10";
- sht3x = <0>,"+11";
- ds1621 = <0>,"+12";
-+ max17040 = <0>,"+13";
- };
- };
--- /dev/null
+From a97baa799a8069fe965a4d194935c025e21acf8e Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Mar 2019 10:06:51 +0000
+Subject: [PATCH] staging: bcm2835-codec: Refactor default resolution
+ code
+
+The default resolution code was different for each role
+as compressed formats need to pass bytesperline as 0 and
+set up customised buffer sizes.
+This is common setup, therefore amend get_sizeimage and
+get_bytesperline to do the correct thing whether compressed
+or uncompressed.
+
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 103 +++++++-----------
+ 1 file changed, 40 insertions(+), 63 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -578,10 +578,17 @@ static void job_abort(void *priv)
+ ctx->aborting = 1;
+ }
+
+-static inline unsigned int get_sizeimage(int bpl, int height,
++static inline unsigned int get_sizeimage(int bpl, int width, int height,
+ struct bcm2835_codec_fmt *fmt)
+ {
+- return (bpl * height * fmt->size_multiplier_x2) >> 1;
++ if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
++ if (width * height > 1280 * 720)
++ return DEF_COMP_BUF_SIZE_GREATER_720P;
++ else
++ return DEF_COMP_BUF_SIZE_720P_OR_LESS;
++ } else {
++ return (bpl * height * fmt->size_multiplier_x2) >> 1;
++ }
+ }
+
+ static inline unsigned int get_bytesperline(int width,
+@@ -1032,22 +1039,13 @@ static int vidioc_try_fmt(struct v4l2_fo
+ * some of the pixels are active.
+ */
+ f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
+-
+- f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
+- fmt);
+- f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
+- f->fmt.pix.height,
+- fmt);
+- } else {
+- u32 min_size = f->fmt.pix.width > 1280 ||
+- f->fmt.pix.height > 720 ?
+- DEF_COMP_BUF_SIZE_GREATER_720P :
+- DEF_COMP_BUF_SIZE_720P_OR_LESS;
+-
+- f->fmt.pix.bytesperline = 0;
+- if (f->fmt.pix.sizeimage < min_size)
+- f->fmt.pix.sizeimage = min_size;
+ }
++ f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
++ fmt);
++ f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
++ f->fmt.pix.width,
++ f->fmt.pix.height,
++ fmt);
+
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+
+@@ -1159,6 +1157,7 @@ static int vidioc_s_fmt(struct bcm2835_c
+ q_data_dst->bytesperline =
+ get_bytesperline(f->fmt.pix.width, q_data_dst->fmt);
+ q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline,
++ q_data_dst->crop_width,
+ q_data_dst->height,
+ q_data_dst->fmt);
+ update_capture_port = true;
+@@ -2218,52 +2217,30 @@ static int bcm2835_codec_open(struct fil
+
+ ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false);
+ ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true);
+- switch (dev->role) {
+- case DECODE:
+- /*
+- * Input width and height are irrelevant as they will be defined
+- * by the bitstream not the format. Required by V4L2 though.
+- */
+- ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
+- ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
+- ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT;
+- ctx->q_data[V4L2_M2M_SRC].bytesperline = 0;
+- ctx->q_data[V4L2_M2M_SRC].sizeimage =
+- DEF_COMP_BUF_SIZE_720P_OR_LESS;
+-
+- ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
+- ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
+- 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].sizeimage =
+- get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline,
+- ctx->q_data[V4L2_M2M_DST].height,
+- ctx->q_data[V4L2_M2M_DST].fmt);
+- break;
+- case ENCODE:
+- ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
+- ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
+- 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].sizeimage =
+- get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline,
+- ctx->q_data[V4L2_M2M_SRC].height,
+- ctx->q_data[V4L2_M2M_SRC].fmt);
+-
+- ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
+- ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
+- ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
+- ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT;
+- ctx->q_data[V4L2_M2M_DST].sizeimage =
+- DEF_COMP_BUF_SIZE_720P_OR_LESS;
+- break;
+- case ISP:
+- break;
+- }
++
++ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
++ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
++ 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].sizeimage =
++ get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline,
++ ctx->q_data[V4L2_M2M_SRC].crop_width,
++ ctx->q_data[V4L2_M2M_SRC].height,
++ ctx->q_data[V4L2_M2M_SRC].fmt);
++
++ ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
++ ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
++ 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].sizeimage =
++ get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline,
++ ctx->q_data[V4L2_M2M_DST].crop_width,
++ ctx->q_data[V4L2_M2M_DST].height,
++ ctx->q_data[V4L2_M2M_DST].fmt);
+
+ ctx->colorspace = V4L2_COLORSPACE_REC709;
+ ctx->bitrate = 10 * 1000 * 1000;
+++ /dev/null
-From 7c876909bc0a6d23124689d5fca89657a4fcb5a5 Mon Sep 17 00:00:00 2001
-Date: Tue, 5 Mar 2019 15:43:27 +0000
-Subject: [PATCH] media: bcm2835-unicam: Add support for enum
- framesizes and frameintervals
-
-vidioc_enum_framesizes and vidioc_enum_frameintervals weren't implemented,
-therefore clients couldn't enumerate the supported resolutions.
-
-Implement them by forwarding on to the sensor driver.
-
----
- .../media/platform/bcm2835/bcm2835-unicam.c | 94 +++++++++++++++++++
- 1 file changed, 94 insertions(+)
-
---- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
-@@ -1406,6 +1406,84 @@ static int unicam_g_edid(struct file *fi
- return v4l2_subdev_call(dev->sensor, pad, get_edid, edid);
- }
-
-+static int unicam_enum_framesizes(struct file *file, void *priv,
-+ struct v4l2_frmsizeenum *fsize)
-+{
-+ struct unicam_device *dev = video_drvdata(file);
-+ const struct unicam_fmt *fmt;
-+ struct v4l2_subdev_frame_size_enum fse;
-+ int ret;
-+
-+ /* 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;
-+ }
-+
-+ fse.index = fsize->index;
-+ fse.pad = 0;
-+ fse.code = fmt->code;
-+
-+ 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;
-+
-+ return 0;
-+}
-+
-+static int unicam_enum_frameintervals(struct file *file, void *priv,
-+ struct v4l2_frmivalenum *fival)
-+{
-+ struct unicam_device *dev = video_drvdata(file);
-+ const struct unicam_fmt *fmt;
-+ struct v4l2_subdev_frame_interval_enum fie = {
-+ .index = fival->index,
-+ .width = fival->width,
-+ .height = fival->height,
-+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
-+ };
-+ 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;
-+}
-+
-+static int unicam_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
-+{
-+ struct unicam_device *dev = video_drvdata(file);
-+
-+ return v4l2_g_parm_cap(video_devdata(file), dev->sensor, a);
-+}
-+
-+static int unicam_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
-+{
-+ struct unicam_device *dev = video_drvdata(file);
-+
-+ return v4l2_s_parm_cap(video_devdata(file), dev->sensor, a);
-+}
-+
- static int unicam_g_dv_timings(struct file *file, void *priv,
- struct v4l2_dv_timings *timings)
- {
-@@ -1613,6 +1691,12 @@ static const struct v4l2_ioctl_ops unica
- .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_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,
-@@ -1850,6 +1934,16 @@ static int unicam_probe_complete(struct
- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUM_DV_TIMINGS);
- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_QUERY_DV_TIMINGS);
- }
-+ if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_interval))
-+ v4l2_disable_ioctl(&unicam->video_dev,
-+ VIDIOC_ENUM_FRAMEINTERVALS);
-+ if (!v4l2_subdev_has_op(unicam->sensor, video, g_frame_interval))
-+ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_PARM);
-+ if (!v4l2_subdev_has_op(unicam->sensor, video, s_frame_interval))
-+ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_PARM);
-+
-+ if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_size))
-+ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUM_FRAMESIZES);
-
- ret = v4l2_device_register_subdev_nodes(&unicam->v4l2_dev);
- if (ret) {
--- /dev/null
+From c9e76146066660a2884e61216c1ce227cf509bf8 Mon Sep 17 00:00:00 2001
+Date: Fri, 30 Nov 2018 11:53:20 +0000
+Subject: [PATCH] nvmem: add type attribute
+
+commit 16688453661b6d5159be558a1f8c1f54463a420f upstream.
+
+Add a type attribute so userspace is able to know how the data is stored as
+this can help taking the correct decision when selecting which device to
+use. This will also help program display the proper warnings when burning
+fuses for example.
+
+---
+ drivers/nvmem/core.c | 21 +++++++++++++++++++++
+ include/linux/nvmem-provider.h | 16 ++++++++++++++++
+ 2 files changed, 37 insertions(+)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -36,6 +36,7 @@ struct nvmem_device {
+ size_t size;
+ bool read_only;
+ int flags;
++ enum nvmem_type type;
+ struct bin_attribute eeprom;
+ struct device *base_dev;
+ nvmem_reg_read_t reg_read;
+@@ -84,6 +85,21 @@ static int nvmem_reg_write(struct nvmem_
+ return -EINVAL;
+ }
+
++static ssize_t type_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct nvmem_device *nvmem = to_nvmem_device(dev);
++
++ return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]);
++}
++
++static DEVICE_ATTR_RO(type);
++
++static struct attribute *nvmem_attrs[] = {
++ &dev_attr_type.attr,
++ NULL,
++};
++
+ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t pos, size_t count)
+@@ -169,6 +185,7 @@ static struct bin_attribute *nvmem_bin_r
+
+ static const struct attribute_group nvmem_bin_rw_group = {
+ .bin_attrs = nvmem_bin_rw_attributes,
++ .attrs = nvmem_attrs,
+ };
+
+ static const struct attribute_group *nvmem_rw_dev_groups[] = {
+@@ -192,6 +209,7 @@ static struct bin_attribute *nvmem_bin_r
+
+ static const struct attribute_group nvmem_bin_ro_group = {
+ .bin_attrs = nvmem_bin_ro_attributes,
++ .attrs = nvmem_attrs,
+ };
+
+ static const struct attribute_group *nvmem_ro_dev_groups[] = {
+@@ -216,6 +234,7 @@ static struct bin_attribute *nvmem_bin_r
+
+ static const struct attribute_group nvmem_bin_rw_root_group = {
+ .bin_attrs = nvmem_bin_rw_root_attributes,
++ .attrs = nvmem_attrs,
+ };
+
+ static const struct attribute_group *nvmem_rw_root_dev_groups[] = {
+@@ -239,6 +258,7 @@ static struct bin_attribute *nvmem_bin_r
+
+ static const struct attribute_group nvmem_bin_ro_root_group = {
+ .bin_attrs = nvmem_bin_ro_root_attributes,
++ .attrs = nvmem_attrs,
+ };
+
+ static const struct attribute_group *nvmem_ro_root_dev_groups[] = {
+@@ -485,6 +505,7 @@ struct nvmem_device *nvmem_register(cons
+ nvmem->dev.bus = &nvmem_bus_type;
+ nvmem->dev.parent = config->dev;
+ nvmem->priv = config->priv;
++ nvmem->type = config->type;
+ nvmem->reg_read = config->reg_read;
+ nvmem->reg_write = config->reg_write;
+ nvmem->dev.of_node = config->dev->of_node;
+--- a/include/linux/nvmem-provider.h
++++ b/include/linux/nvmem-provider.h
+@@ -22,6 +22,20 @@ typedef int (*nvmem_reg_read_t)(void *pr
+ typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset,
+ void *val, size_t bytes);
+
++enum nvmem_type {
++ NVMEM_TYPE_UNKNOWN = 0,
++ NVMEM_TYPE_EEPROM,
++ NVMEM_TYPE_OTP,
++ NVMEM_TYPE_BATTERY_BACKED,
++};
++
++static const char * const nvmem_type_str[] = {
++ [NVMEM_TYPE_UNKNOWN] = "Unknown",
++ [NVMEM_TYPE_EEPROM] = "EEPROM",
++ [NVMEM_TYPE_OTP] = "OTP",
++ [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed",
++};
++
+ /**
+ * struct nvmem_config - NVMEM device configuration
+ *
+@@ -31,6 +45,7 @@ typedef int (*nvmem_reg_write_t)(void *p
+ * @owner: Pointer to exporter module. Used for refcounting.
+ * @cells: Optional array of pre-defined NVMEM cells.
+ * @ncells: Number of elements in cells.
++ * @type: Type of the nvmem storage
+ * @read_only: Device is read-only.
+ * @root_only: Device is accessibly to root only.
+ * @reg_read: Callback to read data.
+@@ -54,6 +69,7 @@ struct nvmem_config {
+ struct module *owner;
+ const struct nvmem_cell_info *cells;
+ int ncells;
++ enum nvmem_type type;
+ bool read_only;
+ bool root_only;
+ nvmem_reg_read_t reg_read;
--- /dev/null
+From bb0e317bfc453877805a12f975490ad38b6413f1 Mon Sep 17 00:00:00 2001
+Date: Wed, 13 Feb 2019 00:21:36 +0100
+Subject: [PATCH] rtc: rv3028: add new driver
+
+upstream commit e6e7376cfd7b3f9b63de3a22792f64d9bfb2ab53.
+
+Add a driver for the MicroCrystal RV-3028. It is a SMT Real-Time Clock
+Module that incorporates an integrated CMOS circuit together with an XTAL.
+It has an i2c interface.
+
+The driver handles date/time, alarms, trickle charging, timestamping,
+frequency offset correction, EEPROM and NVRAM.
+
+---
+ Documentation/devicetree/bindings/rtc/rtc.txt | 69 ++
+ drivers/rtc/Kconfig | 9 +
+ drivers/rtc/Makefile | 1 +
+ drivers/rtc/rtc-rv3028.c | 733 ++++++++++++++++++
+ 4 files changed, 812 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/rtc/rtc.txt
+ create mode 100644 drivers/rtc/rtc-rv3028.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/rtc/rtc.txt
+@@ -0,0 +1,69 @@
++Generic device tree bindings for Real Time Clock devices
++========================================================
++
++This document describes generic bindings which can be used to describe Real Time
++Clock devices in a device tree.
++
++Required properties
++-------------------
++
++- compatible : name of RTC device following generic names recommended practice.
++
++For other required properties e.g. to describe register sets,
++clocks, etc. check the binding documentation of the specific driver.
++
++Optional properties
++-------------------
++
++- start-year : if provided, the default hardware range supported by the RTC is
++ shifted so the first usable year is the specified one.
++
++The following properties may not be supported by all drivers. However, if a
++driver wants to support one of the below features, it should adapt the bindings
++below.
++- trickle-resistor-ohms : Selected resistor for trickle charger. Should be given
++ if trickle charger should be enabled
++- trickle-diode-disable : Do not use internal trickle charger diode Should be
++ given if internal trickle charger diode should be
++ disabled
++- wakeup-source : Enables wake up of host system on alarm
++- quartz-load-femtofarads : The capacitive load of the quartz(x-tal),
++ expressed in femto Farad (fF).
++ The default value shall be listed (if optional),
++ and likewise all valid values.
++
++Trivial RTCs
++------------
++
++This is a list of trivial RTC devices that have simple device tree
++bindings, consisting only of a compatible field, an address and
++possibly an interrupt line.
++
++
++Compatible Vendor / Chip
++========== =============
++abracon,abb5zes3 AB-RTCMC-32.768kHz-B5ZE-S3: Real Time Clock/Calendar Module with I2C Interface
++dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
++dallas,ds1672 Dallas DS1672 Real-time Clock
++dallas,ds3232 Extremely Accurate I²C RTC with Integrated Crystal and SRAM
++epson,rx8010 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
++epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
++emmicro,em3027 EM Microelectronic EM3027 Real-time Clock
++isil,isl1208 Intersil ISL1208 Low Power RTC with Battery Backed SRAM
++isil,isl1218 Intersil ISL1218 Low Power RTC with Battery Backed SRAM
++isil,isl12022 Intersil ISL12022 Real-time Clock
++microcrystal,rv3028 Real Time Clock Module with I2C-Bus
++microcrystal,rv3029 Real Time Clock Module with I2C-Bus
++microcrystal,rv8523 Real Time Clock
++nxp,pcf2127 Real-time clock
++nxp,pcf2129 Real-time clock
++nxp,pcf8563 Real-time clock/calendar
++pericom,pt7c4338 Real-time Clock Module
++ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
++ricoh,r2221tl I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
++ricoh,rs5c372a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
++ricoh,rs5c372b I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
++ricoh,rv5c386 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
++ricoh,rv5c387a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
++sii,s35390a 2-wire CMOS real-time clock
++whwave,sd3078 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -625,6 +625,15 @@ config RTC_DRV_EM3027
+ This driver can also be built as a module. If so, the module
+ will be called rtc-em3027.
+
++config RTC_DRV_RV3028
++ tristate "Micro Crystal RV3028"
++ help
++ If you say yes here you get support for the Micro Crystal
++ RV3028.
++
++ This driver can also be built as a module. If so, the module
++ will be called rtc-rv3028.
++
+ config RTC_DRV_RV8803
+ tristate "Micro Crystal RV8803, Epson RX8900"
+ help
+--- a/drivers/rtc/Makefile
++++ b/drivers/rtc/Makefile
+@@ -136,6 +136,7 @@ obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5
+ obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
+ obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
+ obj-$(CONFIG_RTC_DRV_RTD119X) += rtc-rtd119x.o
++obj-$(CONFIG_RTC_DRV_RV3028) += rtc-rv3028.o
+ obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
+ obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o
+ obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o
+--- /dev/null
++++ b/drivers/rtc/rtc-rv3028.c
+@@ -0,0 +1,733 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * RTC driver for the Micro Crystal RV3028
++ *
++ * Copyright (C) 2019 Micro Crystal SA
++ *
++ *
++ */
++
++#include <linux/bcd.h>
++#include <linux/bitops.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/log2.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/regmap.h>
++#include <linux/rtc.h>
++#include "rtc-core.h"
++
++#define RV3028_SEC 0x00
++#define RV3028_MIN 0x01
++#define RV3028_HOUR 0x02
++#define RV3028_WDAY 0x03
++#define RV3028_DAY 0x04
++#define RV3028_MONTH 0x05
++#define RV3028_YEAR 0x06
++#define RV3028_ALARM_MIN 0x07
++#define RV3028_ALARM_HOUR 0x08
++#define RV3028_ALARM_DAY 0x09
++#define RV3028_STATUS 0x0E
++#define RV3028_CTRL1 0x0F
++#define RV3028_CTRL2 0x10
++#define RV3028_EVT_CTRL 0x13
++#define RV3028_TS_COUNT 0x14
++#define RV3028_TS_SEC 0x15
++#define RV3028_RAM1 0x1F
++#define RV3028_EEPROM_ADDR 0x25
++#define RV3028_EEPROM_DATA 0x26
++#define RV3028_EEPROM_CMD 0x27
++#define RV3028_CLKOUT 0x35
++#define RV3028_OFFSET 0x36
++#define RV3028_BACKUP 0x37
++
++#define RV3028_STATUS_PORF BIT(0)
++#define RV3028_STATUS_EVF BIT(1)
++#define RV3028_STATUS_AF BIT(2)
++#define RV3028_STATUS_TF BIT(3)
++#define RV3028_STATUS_UF BIT(4)
++#define RV3028_STATUS_BSF BIT(5)
++#define RV3028_STATUS_CLKF BIT(6)
++#define RV3028_STATUS_EEBUSY BIT(7)
++
++#define RV3028_CTRL1_EERD BIT(3)
++#define RV3028_CTRL1_WADA BIT(5)
++
++#define RV3028_CTRL2_RESET BIT(0)
++#define RV3028_CTRL2_12_24 BIT(1)
++#define RV3028_CTRL2_EIE BIT(2)
++#define RV3028_CTRL2_AIE BIT(3)
++#define RV3028_CTRL2_TIE BIT(4)
++#define RV3028_CTRL2_UIE BIT(5)
++#define RV3028_CTRL2_TSE BIT(7)
++
++#define RV3028_EVT_CTRL_TSR BIT(2)
++
++#define RV3028_EEPROM_CMD_WRITE 0x21
++#define RV3028_EEPROM_CMD_READ 0x22
++
++#define RV3028_EEBUSY_POLL 10000
++#define RV3028_EEBUSY_TIMEOUT 100000
++
++#define RV3028_BACKUP_TCE BIT(5)
++#define RV3028_BACKUP_TCR_MASK GENMASK(1,0)
++
++#define OFFSET_STEP_PPT 953674
++
++enum rv3028_type {
++ rv_3028,
++};
++
++struct rv3028_data {
++ struct regmap *regmap;
++ struct rtc_device *rtc;
++ enum rv3028_type type;
++};
++
++static u16 rv3028_trickle_resistors[] = {1000, 3000, 6000, 11000};
++
++static ssize_t timestamp0_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
++
++ regmap_update_bits(rv3028->regmap, RV3028_EVT_CTRL, RV3028_EVT_CTRL_TSR,
++ RV3028_EVT_CTRL_TSR);
++
++ return count;
++};
++
++static ssize_t timestamp0_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
++ struct rtc_time tm;
++ int ret, count;
++ u8 date[6];
++
++ ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
++ if (ret)
++ return ret;
++
++ if (!count)
++ return 0;
++
++ ret = regmap_bulk_read(rv3028->regmap, RV3028_TS_SEC, date,
++ sizeof(date));
++ if (ret)
++ return ret;
++
++ tm.tm_sec = bcd2bin(date[0]);
++ tm.tm_min = bcd2bin(date[1]);
++ tm.tm_hour = bcd2bin(date[2]);
++ tm.tm_mday = bcd2bin(date[3]);
++ tm.tm_mon = bcd2bin(date[4]) - 1;
++ tm.tm_year = bcd2bin(date[5]) + 100;
++
++ ret = rtc_valid_tm(&tm);
++ if (ret)
++ return ret;
++
++ return sprintf(buf, "%llu\n",
++ (unsigned long long)rtc_tm_to_time64(&tm));
++};
++
++static DEVICE_ATTR_RW(timestamp0);
++
++static ssize_t timestamp0_count_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
++ int ret, count;
++
++ ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
++ if (ret)
++ return ret;
++
++ return sprintf(buf, "%u\n", count);
++};
++
++static DEVICE_ATTR_RO(timestamp0_count);
++
++static struct attribute *rv3028_attrs[] = {
++ &dev_attr_timestamp0.attr,
++ &dev_attr_timestamp0_count.attr,
++ NULL
++};
++
++static const struct attribute_group rv3028_attr_group = {
++ .attrs = rv3028_attrs,
++};
++
++static irqreturn_t rv3028_handle_irq(int irq, void *dev_id)
++{
++ struct rv3028_data *rv3028 = dev_id;
++ unsigned long events = 0;
++ u32 status = 0, ctrl = 0;
++
++ if (regmap_read(rv3028->regmap, RV3028_STATUS, &status) < 0 ||
++ status == 0) {
++ return IRQ_NONE;
++ }
++
++ if (status & RV3028_STATUS_PORF)
++ dev_warn(&rv3028->rtc->dev, "Voltage low, data loss detected.\n");
++
++ if (status & RV3028_STATUS_TF) {
++ status |= RV3028_STATUS_TF;
++ ctrl |= RV3028_CTRL2_TIE;
++ events |= RTC_PF;
++ }
++
++ if (status & RV3028_STATUS_AF) {
++ status |= RV3028_STATUS_AF;
++ ctrl |= RV3028_CTRL2_AIE;
++ events |= RTC_AF;
++ }
++
++ if (status & RV3028_STATUS_UF) {
++ status |= RV3028_STATUS_UF;
++ ctrl |= RV3028_CTRL2_UIE;
++ events |= RTC_UF;
++ }
++
++ if (events) {
++ rtc_update_irq(rv3028->rtc, 1, events);
++ regmap_update_bits(rv3028->regmap, RV3028_STATUS, status, 0);
++ regmap_update_bits(rv3028->regmap, RV3028_CTRL2, ctrl, 0);
++ }
++
++ if (status & RV3028_STATUS_EVF) {
++ sysfs_notify(&rv3028->rtc->dev.kobj, NULL,
++ dev_attr_timestamp0.attr.name);
++ dev_warn(&rv3028->rtc->dev, "event detected");
++ }
++
++ return IRQ_HANDLED;
++}
++
++static int rv3028_get_time(struct device *dev, struct rtc_time *tm)
++{
++ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
++ u8 date[7];
++ int ret, status;
++
++ ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
++ if (ret < 0)
++ return ret;
++
++ if (status & RV3028_STATUS_PORF) {
++ dev_warn(dev, "Voltage low, data is invalid.\n");
++ return -EINVAL;
++ }
++
++ ret = regmap_bulk_read(rv3028->regmap, RV3028_SEC, date, sizeof(date));
++ if (ret)
++ return ret;
++
++ tm->tm_sec = bcd2bin(date[RV3028_SEC] & 0x7f);
++ tm->tm_min = bcd2bin(date[RV3028_MIN] & 0x7f);
++ tm->tm_hour = bcd2bin(date[RV3028_HOUR] & 0x3f);
++ tm->tm_wday = ilog2(date[RV3028_WDAY] & 0x7f);
++ tm->tm_mday = bcd2bin(date[RV3028_DAY] & 0x3f);
++ tm->tm_mon = bcd2bin(date[RV3028_MONTH] & 0x1f) - 1;
++ tm->tm_year = bcd2bin(date[RV3028_YEAR]) + 100;
++
++ return 0;
++}
++
++static int rv3028_set_time(struct device *dev, struct rtc_time *tm)
++{
++ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
++ u8 date[7];
++ int ret;
++
++ date[RV3028_SEC] = bin2bcd(tm->tm_sec);
++ date[RV3028_MIN] = bin2bcd(tm->tm_min);
++ date[RV3028_HOUR] = bin2bcd(tm->tm_hour);
++ date[RV3028_WDAY] = 1 << (tm->tm_wday);
++ date[RV3028_DAY] = bin2bcd(tm->tm_mday);
++ date[RV3028_MONTH] = bin2bcd(tm->tm_mon + 1);
++ date[RV3028_YEAR] = bin2bcd(tm->tm_year - 100);
++
++ /*
++ * Writing to the Seconds register has the same effect as setting RESET
++ * bit to 1
++ */
++ ret = regmap_bulk_write(rv3028->regmap, RV3028_SEC, date,
++ sizeof(date));
++ if (ret)
++ return ret;
++
++ ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
++ RV3028_STATUS_PORF, 0);
++
++ return ret;
++}
++
++static int rv3028_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
++{
++ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
++ u8 alarmvals[3];
++ int status, ctrl, ret;
++
++ ret = regmap_bulk_read(rv3028->regmap, RV3028_ALARM_MIN, alarmvals,
++ sizeof(alarmvals));
++ if (ret)
++ return ret;
++
++ ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
++ if (ret < 0)
++ return ret;
++
++ ret = regmap_read(rv3028->regmap, RV3028_CTRL2, &ctrl);
++ if (ret < 0)
++ return ret;
++
++ alrm->time.tm_sec = 0;
++ alrm->time.tm_min = bcd2bin(alarmvals[0] & 0x7f);
++ alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
++ alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f);
++
++ alrm->enabled = !!(ctrl & RV3028_CTRL2_AIE);
++ alrm->pending = (status & RV3028_STATUS_AF) && alrm->enabled;
++
++ return 0;
++}
++
++static int rv3028_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
++{
++ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
++ u8 alarmvals[3];
++ u8 ctrl = 0;
++ int ret;
++
++ /* The alarm has no seconds, round up to nearest minute */
++ if (alrm->time.tm_sec) {
++ time64_t alarm_time = rtc_tm_to_time64(&alrm->time);
++
++ alarm_time += 60 - alrm->time.tm_sec;
++ rtc_time64_to_tm(alarm_time, &alrm->time);
++ }
++
++ ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
++ RV3028_CTRL2_AIE | RV3028_CTRL2_UIE, 0);
++ if (ret)
++ return ret;
++
++ alarmvals[0] = bin2bcd(alrm->time.tm_min);
++ alarmvals[1] = bin2bcd(alrm->time.tm_hour);
++ alarmvals[2] = bin2bcd(alrm->time.tm_mday);
++
++ ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
++ RV3028_STATUS_AF, 0);
++ if (ret)
++ return ret;
++
++ ret = regmap_bulk_write(rv3028->regmap, RV3028_ALARM_MIN, alarmvals,
++ sizeof(alarmvals));
++ if (ret)
++ return ret;
++
++ if (alrm->enabled) {
++ if (rv3028->rtc->uie_rtctimer.enabled)
++ ctrl |= RV3028_CTRL2_UIE;
++ if (rv3028->rtc->aie_timer.enabled)
++ ctrl |= RV3028_CTRL2_AIE;
++ }
++
++ ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
++ RV3028_CTRL2_UIE | RV3028_CTRL2_AIE, ctrl);
++
++ return ret;
++}
++
++static int rv3028_alarm_irq_enable(struct device *dev, unsigned int enabled)
++{
++ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
++ int ctrl = 0, ret;
++
++ if (enabled) {
++ if (rv3028->rtc->uie_rtctimer.enabled)
++ ctrl |= RV3028_CTRL2_UIE;
++ if (rv3028->rtc->aie_timer.enabled)
++ ctrl |= RV3028_CTRL2_AIE;
++ }
++
++ ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
++ RV3028_STATUS_AF | RV3028_STATUS_UF, 0);
++ if (ret)
++ return ret;
++
++ ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
++ RV3028_CTRL2_UIE | RV3028_CTRL2_AIE, ctrl);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static int rv3028_read_offset(struct device *dev, long *offset)
++{
++ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
++ int ret, value, steps;
++
++ ret = regmap_read(rv3028->regmap, RV3028_OFFSET, &value);
++ if (ret < 0)
++ return ret;
++
++ steps = sign_extend32(value << 1, 8);
++
++ ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &value);
++ if (ret < 0)
++ return ret;
++
++ steps += value >> 7;
++
++ *offset = DIV_ROUND_CLOSEST(steps * OFFSET_STEP_PPT, 1000);
++
++ return 0;
++}
++
++static int rv3028_set_offset(struct device *dev, long offset)
++{
++ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
++ int ret;
++
++ offset = clamp(offset, -244141L, 243187L) * 1000;
++ offset = DIV_ROUND_CLOSEST(offset, OFFSET_STEP_PPT);
++
++ ret = regmap_write(rv3028->regmap, RV3028_OFFSET, offset >> 1);
++ if (ret < 0)
++ return ret;
++
++ return regmap_update_bits(rv3028->regmap, RV3028_BACKUP, BIT(7),
++ offset << 7);
++}
++
++static int rv3028_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
++{
++ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
++ int status, ret = 0;
++
++ switch (cmd) {
++ case RTC_VL_READ:
++ ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
++ if (ret < 0)
++ return ret;
++
++ if (status & RV3028_STATUS_PORF)
++ dev_warn(&rv3028->rtc->dev, "Voltage low, data loss detected.\n");
++
++ status &= RV3028_STATUS_PORF;
++
++ if (copy_to_user((void __user *)arg, &status, sizeof(int)))
++ return -EFAULT;
++
++ return 0;
++
++ case RTC_VL_CLR:
++ ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
++ RV3028_STATUS_PORF, 0);
++
++ return ret;
++
++ default:
++ return -ENOIOCTLCMD;
++ }
++}
++
++static int rv3028_nvram_write(void *priv, unsigned int offset, void *val,
++ size_t bytes)
++{
++ return regmap_bulk_write(priv, RV3028_RAM1 + offset, val, bytes);
++}
++
++static int rv3028_nvram_read(void *priv, unsigned int offset, void *val,
++ size_t bytes)
++{
++ return regmap_bulk_read(priv, RV3028_RAM1 + offset, val, bytes);
++}
++
++static int rv3028_eeprom_write(void *priv, unsigned int offset, void *val,
++ size_t bytes)
++{
++ u32 status, ctrl1;
++ int i, ret, err;
++ u8 *buf = val;
++
++ ret = regmap_read(priv, RV3028_CTRL1, &ctrl1);
++ if (ret)
++ return ret;
++
++ if (!(ctrl1 & RV3028_CTRL1_EERD)) {
++ ret = regmap_update_bits(priv, RV3028_CTRL1,
++ RV3028_CTRL1_EERD, RV3028_CTRL1_EERD);
++ if (ret)
++ return ret;
++
++ ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
++ !(status & RV3028_STATUS_EEBUSY),
++ RV3028_EEBUSY_POLL,
++ RV3028_EEBUSY_TIMEOUT);
++ if (ret)
++ goto restore_eerd;
++ }
++
++ for (i = 0; i < bytes; i++) {
++ ret = regmap_write(priv, RV3028_EEPROM_ADDR, offset + i);
++ if (ret)
++ goto restore_eerd;
++
++ ret = regmap_write(priv, RV3028_EEPROM_DATA, buf[i]);
++ if (ret)
++ goto restore_eerd;
++
++ ret = regmap_write(priv, RV3028_EEPROM_CMD, 0x0);
++ if (ret)
++ goto restore_eerd;
++
++ ret = regmap_write(priv, RV3028_EEPROM_CMD,
++ RV3028_EEPROM_CMD_WRITE);
++ if (ret)
++ goto restore_eerd;
++
++ usleep_range(RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT);
++
++ ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
++ !(status & RV3028_STATUS_EEBUSY),
++ RV3028_EEBUSY_POLL,
++ RV3028_EEBUSY_TIMEOUT);
++ if (ret)
++ goto restore_eerd;
++ }
++
++restore_eerd:
++ if (!(ctrl1 & RV3028_CTRL1_EERD))
++ {
++ err = regmap_update_bits(priv, RV3028_CTRL1, RV3028_CTRL1_EERD,
++ 0);
++ if (err && !ret)
++ ret = err;
++ }
++
++ return ret;
++}
++
++static int rv3028_eeprom_read(void *priv, unsigned int offset, void *val,
++ size_t bytes)
++{
++ u32 status, ctrl1, data;
++ int i, ret, err;
++ u8 *buf = val;
++
++ ret = regmap_read(priv, RV3028_CTRL1, &ctrl1);
++ if (ret)
++ return ret;
++
++ if (!(ctrl1 & RV3028_CTRL1_EERD)) {
++ ret = regmap_update_bits(priv, RV3028_CTRL1,
++ RV3028_CTRL1_EERD, RV3028_CTRL1_EERD);
++ if (ret)
++ return ret;
++
++ ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
++ !(status & RV3028_STATUS_EEBUSY),
++ RV3028_EEBUSY_POLL,
++ RV3028_EEBUSY_TIMEOUT);
++ if (ret)
++ goto restore_eerd;
++ }
++
++ for (i = 0; i < bytes; i++) {
++ ret = regmap_write(priv, RV3028_EEPROM_ADDR, offset + i);
++ if (ret)
++ goto restore_eerd;
++
++ ret = regmap_write(priv, RV3028_EEPROM_CMD, 0x0);
++ if (ret)
++ goto restore_eerd;
++
++ ret = regmap_write(priv, RV3028_EEPROM_CMD,
++ RV3028_EEPROM_CMD_READ);
++ if (ret)
++ goto restore_eerd;
++
++ ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
++ !(status & RV3028_STATUS_EEBUSY),
++ RV3028_EEBUSY_POLL,
++ RV3028_EEBUSY_TIMEOUT);
++ if (ret)
++ goto restore_eerd;
++
++ ret = regmap_read(priv, RV3028_EEPROM_DATA, &data);
++ if (ret)
++ goto restore_eerd;
++ buf[i] = data;
++ }
++
++restore_eerd:
++ if (!(ctrl1 & RV3028_CTRL1_EERD))
++ {
++ err = regmap_update_bits(priv, RV3028_CTRL1, RV3028_CTRL1_EERD,
++ 0);
++ if (err && !ret)
++ ret = err;
++ }
++
++ return ret;
++}
++
++static struct rtc_class_ops rv3028_rtc_ops = {
++ .read_time = rv3028_get_time,
++ .set_time = rv3028_set_time,
++ .read_offset = rv3028_read_offset,
++ .set_offset = rv3028_set_offset,
++ .ioctl = rv3028_ioctl,
++};
++
++static const struct regmap_config regmap_config = {
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = 0x37,
++};
++
++static int rv3028_probe(struct i2c_client *client)
++{
++ struct rv3028_data *rv3028;
++ int ret, status;
++ u32 ohms;
++ struct nvmem_config nvmem_cfg = {
++ .name = "rv3028_nvram",
++ .word_size = 1,
++ .stride = 1,
++ .size = 2,
++ .type = NVMEM_TYPE_BATTERY_BACKED,
++ .reg_read = rv3028_nvram_read,
++ .reg_write = rv3028_nvram_write,
++ };
++ struct nvmem_config eeprom_cfg = {
++ .name = "rv3028_eeprom",
++ .word_size = 1,
++ .stride = 1,
++ .size = 43,
++ .type = NVMEM_TYPE_EEPROM,
++ .reg_read = rv3028_eeprom_read,
++ .reg_write = rv3028_eeprom_write,
++ };
++
++ rv3028 = devm_kzalloc(&client->dev, sizeof(struct rv3028_data),
++ GFP_KERNEL);
++ if (!rv3028)
++ return -ENOMEM;
++
++ rv3028->regmap = devm_regmap_init_i2c(client, ®map_config);
++
++ i2c_set_clientdata(client, rv3028);
++
++ ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
++ if (ret < 0)
++ return ret;
++
++ if (status & RV3028_STATUS_PORF)
++ dev_warn(&client->dev, "Voltage low, data loss detected.\n");
++
++ if (status & RV3028_STATUS_AF)
++ dev_warn(&client->dev, "An alarm may have been missed.\n");
++
++ rv3028->rtc = devm_rtc_allocate_device(&client->dev);
++ if (IS_ERR(rv3028->rtc)) {
++ return PTR_ERR(rv3028->rtc);
++ }
++
++ if (client->irq > 0) {
++ ret = devm_request_threaded_irq(&client->dev, client->irq,
++ NULL, rv3028_handle_irq,
++ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
++ "rv3028", rv3028);
++ if (ret) {
++ dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
++ client->irq = 0;
++ } else {
++ rv3028_rtc_ops.read_alarm = rv3028_get_alarm;
++ rv3028_rtc_ops.set_alarm = rv3028_set_alarm;
++ rv3028_rtc_ops.alarm_irq_enable = rv3028_alarm_irq_enable;
++ }
++ }
++
++ ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL1,
++ RV3028_CTRL1_WADA, RV3028_CTRL1_WADA);
++ if (ret)
++ return ret;
++
++ /* setup timestamping */
++ ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
++ RV3028_CTRL2_EIE | RV3028_CTRL2_TSE,
++ RV3028_CTRL2_EIE | RV3028_CTRL2_TSE);
++ if (ret)
++ return ret;
++
++ /* setup trickle charger */
++ if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms",
++ &ohms)) {
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++)
++ if (ohms == rv3028_trickle_resistors[i])
++ break;
++
++ if (i < ARRAY_SIZE(rv3028_trickle_resistors)) {
++ ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP,
++ RV3028_BACKUP_TCE |
++ RV3028_BACKUP_TCR_MASK,
++ RV3028_BACKUP_TCE | i);
++ if (ret)
++ return ret;
++ } else {
++ dev_warn(&client->dev, "invalid trickle resistor value\n");
++ }
++ }
++
++ ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group);
++ if (ret)
++ return ret;
++
++ rv3028->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
++ rv3028->rtc->range_max = RTC_TIMESTAMP_END_2099;
++ rv3028->rtc->ops = &rv3028_rtc_ops;
++ ret = rtc_register_device(rv3028->rtc);
++ if (ret)
++ return ret;
++
++ nvmem_cfg.priv = rv3028->regmap;
++ rtc_nvmem_register(rv3028->rtc, &nvmem_cfg);
++ eeprom_cfg.priv = rv3028->regmap;
++ rtc_nvmem_register(rv3028->rtc, &eeprom_cfg);
++
++ rv3028->rtc->max_user_freq = 1;
++
++ return 0;
++}
++
++static const struct of_device_id rv3028_of_match[] = {
++ { .compatible = "microcrystal,rv3028", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, rv3028_of_match);
++
++static struct i2c_driver rv3028_driver = {
++ .driver = {
++ .name = "rtc-rv3028",
++ .of_match_table = of_match_ptr(rv3028_of_match),
++ },
++ .probe_new = rv3028_probe,
++};
++module_i2c_driver(rv3028_driver);
++
++MODULE_DESCRIPTION("Micro Crystal RV3028 RTC driver");
++MODULE_LICENSE("GPL v2");
+++ /dev/null
-From a97baa799a8069fe965a4d194935c025e21acf8e Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Mar 2019 10:06:51 +0000
-Subject: [PATCH] staging: bcm2835-codec: Refactor default resolution
- code
-
-The default resolution code was different for each role
-as compressed formats need to pass bytesperline as 0 and
-set up customised buffer sizes.
-This is common setup, therefore amend get_sizeimage and
-get_bytesperline to do the correct thing whether compressed
-or uncompressed.
-
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 103 +++++++-----------
- 1 file changed, 40 insertions(+), 63 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -578,10 +578,17 @@ static void job_abort(void *priv)
- ctx->aborting = 1;
- }
-
--static inline unsigned int get_sizeimage(int bpl, int height,
-+static inline unsigned int get_sizeimage(int bpl, int width, int height,
- struct bcm2835_codec_fmt *fmt)
- {
-- return (bpl * height * fmt->size_multiplier_x2) >> 1;
-+ if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
-+ if (width * height > 1280 * 720)
-+ return DEF_COMP_BUF_SIZE_GREATER_720P;
-+ else
-+ return DEF_COMP_BUF_SIZE_720P_OR_LESS;
-+ } else {
-+ return (bpl * height * fmt->size_multiplier_x2) >> 1;
-+ }
- }
-
- static inline unsigned int get_bytesperline(int width,
-@@ -1032,22 +1039,13 @@ static int vidioc_try_fmt(struct v4l2_fo
- * some of the pixels are active.
- */
- f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
--
-- f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
-- fmt);
-- f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
-- f->fmt.pix.height,
-- fmt);
-- } else {
-- u32 min_size = f->fmt.pix.width > 1280 ||
-- f->fmt.pix.height > 720 ?
-- DEF_COMP_BUF_SIZE_GREATER_720P :
-- DEF_COMP_BUF_SIZE_720P_OR_LESS;
--
-- f->fmt.pix.bytesperline = 0;
-- if (f->fmt.pix.sizeimage < min_size)
-- f->fmt.pix.sizeimage = min_size;
- }
-+ f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
-+ fmt);
-+ f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
-+ f->fmt.pix.width,
-+ f->fmt.pix.height,
-+ fmt);
-
- f->fmt.pix.field = V4L2_FIELD_NONE;
-
-@@ -1159,6 +1157,7 @@ static int vidioc_s_fmt(struct bcm2835_c
- q_data_dst->bytesperline =
- get_bytesperline(f->fmt.pix.width, q_data_dst->fmt);
- q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline,
-+ q_data_dst->crop_width,
- q_data_dst->height,
- q_data_dst->fmt);
- update_capture_port = true;
-@@ -2218,52 +2217,30 @@ static int bcm2835_codec_open(struct fil
-
- ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false);
- ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true);
-- switch (dev->role) {
-- case DECODE:
-- /*
-- * Input width and height are irrelevant as they will be defined
-- * by the bitstream not the format. Required by V4L2 though.
-- */
-- ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
-- ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
-- ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT;
-- ctx->q_data[V4L2_M2M_SRC].bytesperline = 0;
-- ctx->q_data[V4L2_M2M_SRC].sizeimage =
-- DEF_COMP_BUF_SIZE_720P_OR_LESS;
--
-- ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
-- ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
-- 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].sizeimage =
-- get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline,
-- ctx->q_data[V4L2_M2M_DST].height,
-- ctx->q_data[V4L2_M2M_DST].fmt);
-- break;
-- case ENCODE:
-- ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
-- ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
-- 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].sizeimage =
-- get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline,
-- ctx->q_data[V4L2_M2M_SRC].height,
-- ctx->q_data[V4L2_M2M_SRC].fmt);
--
-- ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
-- ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
-- ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
-- ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT;
-- ctx->q_data[V4L2_M2M_DST].sizeimage =
-- DEF_COMP_BUF_SIZE_720P_OR_LESS;
-- break;
-- case ISP:
-- break;
-- }
-+
-+ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH;
-+ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT;
-+ 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].sizeimage =
-+ get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline,
-+ ctx->q_data[V4L2_M2M_SRC].crop_width,
-+ ctx->q_data[V4L2_M2M_SRC].height,
-+ ctx->q_data[V4L2_M2M_SRC].fmt);
-+
-+ ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
-+ ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
-+ 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].sizeimage =
-+ get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline,
-+ ctx->q_data[V4L2_M2M_DST].crop_width,
-+ ctx->q_data[V4L2_M2M_DST].height,
-+ ctx->q_data[V4L2_M2M_DST].fmt);
-
- ctx->colorspace = V4L2_COLORSPACE_REC709;
- ctx->bitrate = 10 * 1000 * 1000;
+++ /dev/null
-From c9e76146066660a2884e61216c1ce227cf509bf8 Mon Sep 17 00:00:00 2001
-Date: Fri, 30 Nov 2018 11:53:20 +0000
-Subject: [PATCH] nvmem: add type attribute
-
-commit 16688453661b6d5159be558a1f8c1f54463a420f upstream.
-
-Add a type attribute so userspace is able to know how the data is stored as
-this can help taking the correct decision when selecting which device to
-use. This will also help program display the proper warnings when burning
-fuses for example.
-
----
- drivers/nvmem/core.c | 21 +++++++++++++++++++++
- include/linux/nvmem-provider.h | 16 ++++++++++++++++
- 2 files changed, 37 insertions(+)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -36,6 +36,7 @@ struct nvmem_device {
- size_t size;
- bool read_only;
- int flags;
-+ enum nvmem_type type;
- struct bin_attribute eeprom;
- struct device *base_dev;
- nvmem_reg_read_t reg_read;
-@@ -84,6 +85,21 @@ static int nvmem_reg_write(struct nvmem_
- return -EINVAL;
- }
-
-+static ssize_t type_show(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct nvmem_device *nvmem = to_nvmem_device(dev);
-+
-+ return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]);
-+}
-+
-+static DEVICE_ATTR_RO(type);
-+
-+static struct attribute *nvmem_attrs[] = {
-+ &dev_attr_type.attr,
-+ NULL,
-+};
-+
- static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t pos, size_t count)
-@@ -169,6 +185,7 @@ static struct bin_attribute *nvmem_bin_r
-
- static const struct attribute_group nvmem_bin_rw_group = {
- .bin_attrs = nvmem_bin_rw_attributes,
-+ .attrs = nvmem_attrs,
- };
-
- static const struct attribute_group *nvmem_rw_dev_groups[] = {
-@@ -192,6 +209,7 @@ static struct bin_attribute *nvmem_bin_r
-
- static const struct attribute_group nvmem_bin_ro_group = {
- .bin_attrs = nvmem_bin_ro_attributes,
-+ .attrs = nvmem_attrs,
- };
-
- static const struct attribute_group *nvmem_ro_dev_groups[] = {
-@@ -216,6 +234,7 @@ static struct bin_attribute *nvmem_bin_r
-
- static const struct attribute_group nvmem_bin_rw_root_group = {
- .bin_attrs = nvmem_bin_rw_root_attributes,
-+ .attrs = nvmem_attrs,
- };
-
- static const struct attribute_group *nvmem_rw_root_dev_groups[] = {
-@@ -239,6 +258,7 @@ static struct bin_attribute *nvmem_bin_r
-
- static const struct attribute_group nvmem_bin_ro_root_group = {
- .bin_attrs = nvmem_bin_ro_root_attributes,
-+ .attrs = nvmem_attrs,
- };
-
- static const struct attribute_group *nvmem_ro_root_dev_groups[] = {
-@@ -485,6 +505,7 @@ struct nvmem_device *nvmem_register(cons
- nvmem->dev.bus = &nvmem_bus_type;
- nvmem->dev.parent = config->dev;
- nvmem->priv = config->priv;
-+ nvmem->type = config->type;
- nvmem->reg_read = config->reg_read;
- nvmem->reg_write = config->reg_write;
- nvmem->dev.of_node = config->dev->of_node;
---- a/include/linux/nvmem-provider.h
-+++ b/include/linux/nvmem-provider.h
-@@ -22,6 +22,20 @@ typedef int (*nvmem_reg_read_t)(void *pr
- typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset,
- void *val, size_t bytes);
-
-+enum nvmem_type {
-+ NVMEM_TYPE_UNKNOWN = 0,
-+ NVMEM_TYPE_EEPROM,
-+ NVMEM_TYPE_OTP,
-+ NVMEM_TYPE_BATTERY_BACKED,
-+};
-+
-+static const char * const nvmem_type_str[] = {
-+ [NVMEM_TYPE_UNKNOWN] = "Unknown",
-+ [NVMEM_TYPE_EEPROM] = "EEPROM",
-+ [NVMEM_TYPE_OTP] = "OTP",
-+ [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed",
-+};
-+
- /**
- * struct nvmem_config - NVMEM device configuration
- *
-@@ -31,6 +45,7 @@ typedef int (*nvmem_reg_write_t)(void *p
- * @owner: Pointer to exporter module. Used for refcounting.
- * @cells: Optional array of pre-defined NVMEM cells.
- * @ncells: Number of elements in cells.
-+ * @type: Type of the nvmem storage
- * @read_only: Device is read-only.
- * @root_only: Device is accessibly to root only.
- * @reg_read: Callback to read data.
-@@ -54,6 +69,7 @@ struct nvmem_config {
- struct module *owner;
- const struct nvmem_cell_info *cells;
- int ncells;
-+ enum nvmem_type type;
- bool read_only;
- bool root_only;
- nvmem_reg_read_t reg_read;
--- /dev/null
+From 67dd8e4c8ccf5d331960c7e936e5b03a9f92496d Mon Sep 17 00:00:00 2001
+Date: Thu, 28 Mar 2019 13:26:59 +0000
+Subject: [PATCH] overlays: Add rv3028 to i2c-rtc
+
+See: https://github.com/raspberrypi/linux/issues/2912
+
+---
+ arch/arm/boot/dts/overlays/README | 4 +++-
+ .../arm/boot/dts/overlays/i2c-rtc-overlay.dts | 19 ++++++++++++++++++-
+ 2 files changed, 21 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -939,6 +939,8 @@ Params: abx80x Select o
+
+ pcf8563 Select the PCF8563 device
+
++ rv3028 Select the Micro Crystal RV3028 device
++
+ addr Sets the address for the RTC. Note that the
+ device must be configured to use the specified
+ address.
+@@ -947,7 +949,7 @@ Params: abx80x Select o
+ "schottky" (ABx80x only)
+
+ trickle-resistor-ohms Resistor value for trickle charge (DS1339,
+- ABx80x)
++ ABx80x, RV3028)
+
+ wakeup-source Specify that the RTC can be used as a wakeup
+ source
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+@@ -158,6 +158,21 @@
+ };
+ };
+
++ fragment@10 {
++ target = <&i2c_arm>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ rv3028: rv3028@52 {
++ compatible = "microcrystal,rv3028";
++ reg = <0x52>;
++ status = "okay";
++ };
++ };
++ };
++
+ __overrides__ {
+ abx80x = <0>,"+0";
+ ds1307 = <0>,"+1";
+@@ -169,6 +184,7 @@
+ pcf8523 = <0>,"+7";
+ pcf8563 = <0>,"+8";
+ m41t62 = <0>,"+9";
++ rv3028 = <0>,"+10";
+
+ addr = <&abx80x>, "reg:0",
+ <&ds1307>, "reg:0",
+@@ -182,7 +198,8 @@
+ <&m41t62>, "reg:0";
+ trickle-diode-type = <&abx80x>,"abracon,tc-diode";
+ trickle-resistor-ohms = <&ds1339>,"trickle-resistor-ohms:0",
+- <&abx80x>,"abracon,tc-resistor";
++ <&abx80x>,"abracon,tc-resistor",
++ <&rv3028>,"trickle-resistor-ohms:0";
+ wakeup-source = <&ds1339>,"wakeup-source?",
+ <&ds3231>,"wakeup-source?",
+ <&mcp7940x>,"wakeup-source?",
--- /dev/null
+From 053938f67f73773152f70d89aa32e7893ee19694 Mon Sep 17 00:00:00 2001
+Date: Wed, 9 Jan 2019 22:41:21 +0530
+Subject: [PATCH] ASoC: tlv320aic32x4: SND_SOC_DAPM_MICBIAS is
+ deprecated
+
+commit 04d979d7a7bac2f645cd827ea37e5ffa5b4e1f97 upstream.
+
+SND_SOC_DAPM_MICBIAS is deprecated, replace it with SND_SOC_DAPM_SUPPLY.
+
+MICBIAS voltage wasn't supplied to the microphone with the older
+SND_SOC_DAPM_MICBIAS widget, hence the microphone wouldn't work.
+
+This patch fixes the problem.
+
+---
+ sound/soc/codecs/tlv320aic32x4.c | 30 +++++++++++++++++++++++++++++-
+ sound/soc/codecs/tlv320aic32x4.h | 1 +
+ 2 files changed, 30 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -79,6 +79,32 @@ struct aic32x4_priv {
+ struct device *dev;
+ };
+
++static int mic_bias_event(struct snd_soc_dapm_widget *w,
++ struct snd_kcontrol *kcontrol, int event)
++{
++ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
++
++ switch (event) {
++ case SND_SOC_DAPM_POST_PMU:
++ /* Change Mic Bias Registor */
++ snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
++ AIC32x4_MICBIAS_MASK,
++ AIC32X4_MICBIAS_LDOIN |
++ AIC32X4_MICBIAS_2075V);
++ printk(KERN_DEBUG "%s: Mic Bias will be turned ON\n", __func__);
++ break;
++ case SND_SOC_DAPM_PRE_PMD:
++ snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
++ AIC32x4_MICBIAS_MASK, 0);
++ printk(KERN_DEBUG "%s: Mic Bias will be turned OFF\n",
++ __func__);
++ break;
++ }
++
++ return 0;
++}
++
++
+ static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+@@ -450,7 +476,9 @@ static const struct snd_soc_dapm_widget
+ SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
+ in3r_to_lmixer_controls),
+
+- SND_SOC_DAPM_MICBIAS("Mic Bias", AIC32X4_MICBIAS, 6, 0),
++ SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event,
++ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
++
+
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+--- a/sound/soc/codecs/tlv320aic32x4.h
++++ b/sound/soc/codecs/tlv320aic32x4.h
+@@ -195,6 +195,7 @@ int aic32x4_remove(struct device *dev);
+ /* AIC32X4_MICBIAS */
+ #define AIC32X4_MICBIAS_LDOIN BIT(3)
+ #define AIC32X4_MICBIAS_2075V 0x60
++#define AIC32x4_MICBIAS_MASK GENMASK(6, 3)
+
+ /* AIC32X4_LMICPGANIN */
+ #define AIC32X4_LMICPGANIN_IN2R_10K 0x10
+++ /dev/null
-From bb0e317bfc453877805a12f975490ad38b6413f1 Mon Sep 17 00:00:00 2001
-Date: Wed, 13 Feb 2019 00:21:36 +0100
-Subject: [PATCH] rtc: rv3028: add new driver
-
-upstream commit e6e7376cfd7b3f9b63de3a22792f64d9bfb2ab53.
-
-Add a driver for the MicroCrystal RV-3028. It is a SMT Real-Time Clock
-Module that incorporates an integrated CMOS circuit together with an XTAL.
-It has an i2c interface.
-
-The driver handles date/time, alarms, trickle charging, timestamping,
-frequency offset correction, EEPROM and NVRAM.
-
----
- Documentation/devicetree/bindings/rtc/rtc.txt | 69 ++
- drivers/rtc/Kconfig | 9 +
- drivers/rtc/Makefile | 1 +
- drivers/rtc/rtc-rv3028.c | 733 ++++++++++++++++++
- 4 files changed, 812 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/rtc/rtc.txt
- create mode 100644 drivers/rtc/rtc-rv3028.c
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/rtc/rtc.txt
-@@ -0,0 +1,69 @@
-+Generic device tree bindings for Real Time Clock devices
-+========================================================
-+
-+This document describes generic bindings which can be used to describe Real Time
-+Clock devices in a device tree.
-+
-+Required properties
-+-------------------
-+
-+- compatible : name of RTC device following generic names recommended practice.
-+
-+For other required properties e.g. to describe register sets,
-+clocks, etc. check the binding documentation of the specific driver.
-+
-+Optional properties
-+-------------------
-+
-+- start-year : if provided, the default hardware range supported by the RTC is
-+ shifted so the first usable year is the specified one.
-+
-+The following properties may not be supported by all drivers. However, if a
-+driver wants to support one of the below features, it should adapt the bindings
-+below.
-+- trickle-resistor-ohms : Selected resistor for trickle charger. Should be given
-+ if trickle charger should be enabled
-+- trickle-diode-disable : Do not use internal trickle charger diode Should be
-+ given if internal trickle charger diode should be
-+ disabled
-+- wakeup-source : Enables wake up of host system on alarm
-+- quartz-load-femtofarads : The capacitive load of the quartz(x-tal),
-+ expressed in femto Farad (fF).
-+ The default value shall be listed (if optional),
-+ and likewise all valid values.
-+
-+Trivial RTCs
-+------------
-+
-+This is a list of trivial RTC devices that have simple device tree
-+bindings, consisting only of a compatible field, an address and
-+possibly an interrupt line.
-+
-+
-+Compatible Vendor / Chip
-+========== =============
-+abracon,abb5zes3 AB-RTCMC-32.768kHz-B5ZE-S3: Real Time Clock/Calendar Module with I2C Interface
-+dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
-+dallas,ds1672 Dallas DS1672 Real-time Clock
-+dallas,ds3232 Extremely Accurate I²C RTC with Integrated Crystal and SRAM
-+epson,rx8010 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
-+epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
-+emmicro,em3027 EM Microelectronic EM3027 Real-time Clock
-+isil,isl1208 Intersil ISL1208 Low Power RTC with Battery Backed SRAM
-+isil,isl1218 Intersil ISL1218 Low Power RTC with Battery Backed SRAM
-+isil,isl12022 Intersil ISL12022 Real-time Clock
-+microcrystal,rv3028 Real Time Clock Module with I2C-Bus
-+microcrystal,rv3029 Real Time Clock Module with I2C-Bus
-+microcrystal,rv8523 Real Time Clock
-+nxp,pcf2127 Real-time clock
-+nxp,pcf2129 Real-time clock
-+nxp,pcf8563 Real-time clock/calendar
-+pericom,pt7c4338 Real-time Clock Module
-+ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-+ricoh,r2221tl I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-+ricoh,rs5c372a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-+ricoh,rs5c372b I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-+ricoh,rv5c386 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-+ricoh,rv5c387a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
-+sii,s35390a 2-wire CMOS real-time clock
-+whwave,sd3078 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
---- a/drivers/rtc/Kconfig
-+++ b/drivers/rtc/Kconfig
-@@ -625,6 +625,15 @@ config RTC_DRV_EM3027
- This driver can also be built as a module. If so, the module
- will be called rtc-em3027.
-
-+config RTC_DRV_RV3028
-+ tristate "Micro Crystal RV3028"
-+ help
-+ If you say yes here you get support for the Micro Crystal
-+ RV3028.
-+
-+ This driver can also be built as a module. If so, the module
-+ will be called rtc-rv3028.
-+
- config RTC_DRV_RV8803
- tristate "Micro Crystal RV8803, Epson RX8900"
- help
---- a/drivers/rtc/Makefile
-+++ b/drivers/rtc/Makefile
-@@ -136,6 +136,7 @@ obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5
- obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
- obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
- obj-$(CONFIG_RTC_DRV_RTD119X) += rtc-rtd119x.o
-+obj-$(CONFIG_RTC_DRV_RV3028) += rtc-rv3028.o
- obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
- obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o
- obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o
---- /dev/null
-+++ b/drivers/rtc/rtc-rv3028.c
-@@ -0,0 +1,733 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * RTC driver for the Micro Crystal RV3028
-+ *
-+ * Copyright (C) 2019 Micro Crystal SA
-+ *
-+ *
-+ */
-+
-+#include <linux/bcd.h>
-+#include <linux/bitops.h>
-+#include <linux/i2c.h>
-+#include <linux/interrupt.h>
-+#include <linux/kernel.h>
-+#include <linux/log2.h>
-+#include <linux/module.h>
-+#include <linux/of_device.h>
-+#include <linux/regmap.h>
-+#include <linux/rtc.h>
-+#include "rtc-core.h"
-+
-+#define RV3028_SEC 0x00
-+#define RV3028_MIN 0x01
-+#define RV3028_HOUR 0x02
-+#define RV3028_WDAY 0x03
-+#define RV3028_DAY 0x04
-+#define RV3028_MONTH 0x05
-+#define RV3028_YEAR 0x06
-+#define RV3028_ALARM_MIN 0x07
-+#define RV3028_ALARM_HOUR 0x08
-+#define RV3028_ALARM_DAY 0x09
-+#define RV3028_STATUS 0x0E
-+#define RV3028_CTRL1 0x0F
-+#define RV3028_CTRL2 0x10
-+#define RV3028_EVT_CTRL 0x13
-+#define RV3028_TS_COUNT 0x14
-+#define RV3028_TS_SEC 0x15
-+#define RV3028_RAM1 0x1F
-+#define RV3028_EEPROM_ADDR 0x25
-+#define RV3028_EEPROM_DATA 0x26
-+#define RV3028_EEPROM_CMD 0x27
-+#define RV3028_CLKOUT 0x35
-+#define RV3028_OFFSET 0x36
-+#define RV3028_BACKUP 0x37
-+
-+#define RV3028_STATUS_PORF BIT(0)
-+#define RV3028_STATUS_EVF BIT(1)
-+#define RV3028_STATUS_AF BIT(2)
-+#define RV3028_STATUS_TF BIT(3)
-+#define RV3028_STATUS_UF BIT(4)
-+#define RV3028_STATUS_BSF BIT(5)
-+#define RV3028_STATUS_CLKF BIT(6)
-+#define RV3028_STATUS_EEBUSY BIT(7)
-+
-+#define RV3028_CTRL1_EERD BIT(3)
-+#define RV3028_CTRL1_WADA BIT(5)
-+
-+#define RV3028_CTRL2_RESET BIT(0)
-+#define RV3028_CTRL2_12_24 BIT(1)
-+#define RV3028_CTRL2_EIE BIT(2)
-+#define RV3028_CTRL2_AIE BIT(3)
-+#define RV3028_CTRL2_TIE BIT(4)
-+#define RV3028_CTRL2_UIE BIT(5)
-+#define RV3028_CTRL2_TSE BIT(7)
-+
-+#define RV3028_EVT_CTRL_TSR BIT(2)
-+
-+#define RV3028_EEPROM_CMD_WRITE 0x21
-+#define RV3028_EEPROM_CMD_READ 0x22
-+
-+#define RV3028_EEBUSY_POLL 10000
-+#define RV3028_EEBUSY_TIMEOUT 100000
-+
-+#define RV3028_BACKUP_TCE BIT(5)
-+#define RV3028_BACKUP_TCR_MASK GENMASK(1,0)
-+
-+#define OFFSET_STEP_PPT 953674
-+
-+enum rv3028_type {
-+ rv_3028,
-+};
-+
-+struct rv3028_data {
-+ struct regmap *regmap;
-+ struct rtc_device *rtc;
-+ enum rv3028_type type;
-+};
-+
-+static u16 rv3028_trickle_resistors[] = {1000, 3000, 6000, 11000};
-+
-+static ssize_t timestamp0_store(struct device *dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
-+
-+ regmap_update_bits(rv3028->regmap, RV3028_EVT_CTRL, RV3028_EVT_CTRL_TSR,
-+ RV3028_EVT_CTRL_TSR);
-+
-+ return count;
-+};
-+
-+static ssize_t timestamp0_show(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
-+ struct rtc_time tm;
-+ int ret, count;
-+ u8 date[6];
-+
-+ ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
-+ if (ret)
-+ return ret;
-+
-+ if (!count)
-+ return 0;
-+
-+ ret = regmap_bulk_read(rv3028->regmap, RV3028_TS_SEC, date,
-+ sizeof(date));
-+ if (ret)
-+ return ret;
-+
-+ tm.tm_sec = bcd2bin(date[0]);
-+ tm.tm_min = bcd2bin(date[1]);
-+ tm.tm_hour = bcd2bin(date[2]);
-+ tm.tm_mday = bcd2bin(date[3]);
-+ tm.tm_mon = bcd2bin(date[4]) - 1;
-+ tm.tm_year = bcd2bin(date[5]) + 100;
-+
-+ ret = rtc_valid_tm(&tm);
-+ if (ret)
-+ return ret;
-+
-+ return sprintf(buf, "%llu\n",
-+ (unsigned long long)rtc_tm_to_time64(&tm));
-+};
-+
-+static DEVICE_ATTR_RW(timestamp0);
-+
-+static ssize_t timestamp0_count_show(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
-+ int ret, count;
-+
-+ ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
-+ if (ret)
-+ return ret;
-+
-+ return sprintf(buf, "%u\n", count);
-+};
-+
-+static DEVICE_ATTR_RO(timestamp0_count);
-+
-+static struct attribute *rv3028_attrs[] = {
-+ &dev_attr_timestamp0.attr,
-+ &dev_attr_timestamp0_count.attr,
-+ NULL
-+};
-+
-+static const struct attribute_group rv3028_attr_group = {
-+ .attrs = rv3028_attrs,
-+};
-+
-+static irqreturn_t rv3028_handle_irq(int irq, void *dev_id)
-+{
-+ struct rv3028_data *rv3028 = dev_id;
-+ unsigned long events = 0;
-+ u32 status = 0, ctrl = 0;
-+
-+ if (regmap_read(rv3028->regmap, RV3028_STATUS, &status) < 0 ||
-+ status == 0) {
-+ return IRQ_NONE;
-+ }
-+
-+ if (status & RV3028_STATUS_PORF)
-+ dev_warn(&rv3028->rtc->dev, "Voltage low, data loss detected.\n");
-+
-+ if (status & RV3028_STATUS_TF) {
-+ status |= RV3028_STATUS_TF;
-+ ctrl |= RV3028_CTRL2_TIE;
-+ events |= RTC_PF;
-+ }
-+
-+ if (status & RV3028_STATUS_AF) {
-+ status |= RV3028_STATUS_AF;
-+ ctrl |= RV3028_CTRL2_AIE;
-+ events |= RTC_AF;
-+ }
-+
-+ if (status & RV3028_STATUS_UF) {
-+ status |= RV3028_STATUS_UF;
-+ ctrl |= RV3028_CTRL2_UIE;
-+ events |= RTC_UF;
-+ }
-+
-+ if (events) {
-+ rtc_update_irq(rv3028->rtc, 1, events);
-+ regmap_update_bits(rv3028->regmap, RV3028_STATUS, status, 0);
-+ regmap_update_bits(rv3028->regmap, RV3028_CTRL2, ctrl, 0);
-+ }
-+
-+ if (status & RV3028_STATUS_EVF) {
-+ sysfs_notify(&rv3028->rtc->dev.kobj, NULL,
-+ dev_attr_timestamp0.attr.name);
-+ dev_warn(&rv3028->rtc->dev, "event detected");
-+ }
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int rv3028_get_time(struct device *dev, struct rtc_time *tm)
-+{
-+ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
-+ u8 date[7];
-+ int ret, status;
-+
-+ ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (status & RV3028_STATUS_PORF) {
-+ dev_warn(dev, "Voltage low, data is invalid.\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = regmap_bulk_read(rv3028->regmap, RV3028_SEC, date, sizeof(date));
-+ if (ret)
-+ return ret;
-+
-+ tm->tm_sec = bcd2bin(date[RV3028_SEC] & 0x7f);
-+ tm->tm_min = bcd2bin(date[RV3028_MIN] & 0x7f);
-+ tm->tm_hour = bcd2bin(date[RV3028_HOUR] & 0x3f);
-+ tm->tm_wday = ilog2(date[RV3028_WDAY] & 0x7f);
-+ tm->tm_mday = bcd2bin(date[RV3028_DAY] & 0x3f);
-+ tm->tm_mon = bcd2bin(date[RV3028_MONTH] & 0x1f) - 1;
-+ tm->tm_year = bcd2bin(date[RV3028_YEAR]) + 100;
-+
-+ return 0;
-+}
-+
-+static int rv3028_set_time(struct device *dev, struct rtc_time *tm)
-+{
-+ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
-+ u8 date[7];
-+ int ret;
-+
-+ date[RV3028_SEC] = bin2bcd(tm->tm_sec);
-+ date[RV3028_MIN] = bin2bcd(tm->tm_min);
-+ date[RV3028_HOUR] = bin2bcd(tm->tm_hour);
-+ date[RV3028_WDAY] = 1 << (tm->tm_wday);
-+ date[RV3028_DAY] = bin2bcd(tm->tm_mday);
-+ date[RV3028_MONTH] = bin2bcd(tm->tm_mon + 1);
-+ date[RV3028_YEAR] = bin2bcd(tm->tm_year - 100);
-+
-+ /*
-+ * Writing to the Seconds register has the same effect as setting RESET
-+ * bit to 1
-+ */
-+ ret = regmap_bulk_write(rv3028->regmap, RV3028_SEC, date,
-+ sizeof(date));
-+ if (ret)
-+ return ret;
-+
-+ ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
-+ RV3028_STATUS_PORF, 0);
-+
-+ return ret;
-+}
-+
-+static int rv3028_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
-+{
-+ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
-+ u8 alarmvals[3];
-+ int status, ctrl, ret;
-+
-+ ret = regmap_bulk_read(rv3028->regmap, RV3028_ALARM_MIN, alarmvals,
-+ sizeof(alarmvals));
-+ if (ret)
-+ return ret;
-+
-+ ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = regmap_read(rv3028->regmap, RV3028_CTRL2, &ctrl);
-+ if (ret < 0)
-+ return ret;
-+
-+ alrm->time.tm_sec = 0;
-+ alrm->time.tm_min = bcd2bin(alarmvals[0] & 0x7f);
-+ alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
-+ alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f);
-+
-+ alrm->enabled = !!(ctrl & RV3028_CTRL2_AIE);
-+ alrm->pending = (status & RV3028_STATUS_AF) && alrm->enabled;
-+
-+ return 0;
-+}
-+
-+static int rv3028_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
-+{
-+ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
-+ u8 alarmvals[3];
-+ u8 ctrl = 0;
-+ int ret;
-+
-+ /* The alarm has no seconds, round up to nearest minute */
-+ if (alrm->time.tm_sec) {
-+ time64_t alarm_time = rtc_tm_to_time64(&alrm->time);
-+
-+ alarm_time += 60 - alrm->time.tm_sec;
-+ rtc_time64_to_tm(alarm_time, &alrm->time);
-+ }
-+
-+ ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
-+ RV3028_CTRL2_AIE | RV3028_CTRL2_UIE, 0);
-+ if (ret)
-+ return ret;
-+
-+ alarmvals[0] = bin2bcd(alrm->time.tm_min);
-+ alarmvals[1] = bin2bcd(alrm->time.tm_hour);
-+ alarmvals[2] = bin2bcd(alrm->time.tm_mday);
-+
-+ ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
-+ RV3028_STATUS_AF, 0);
-+ if (ret)
-+ return ret;
-+
-+ ret = regmap_bulk_write(rv3028->regmap, RV3028_ALARM_MIN, alarmvals,
-+ sizeof(alarmvals));
-+ if (ret)
-+ return ret;
-+
-+ if (alrm->enabled) {
-+ if (rv3028->rtc->uie_rtctimer.enabled)
-+ ctrl |= RV3028_CTRL2_UIE;
-+ if (rv3028->rtc->aie_timer.enabled)
-+ ctrl |= RV3028_CTRL2_AIE;
-+ }
-+
-+ ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
-+ RV3028_CTRL2_UIE | RV3028_CTRL2_AIE, ctrl);
-+
-+ return ret;
-+}
-+
-+static int rv3028_alarm_irq_enable(struct device *dev, unsigned int enabled)
-+{
-+ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
-+ int ctrl = 0, ret;
-+
-+ if (enabled) {
-+ if (rv3028->rtc->uie_rtctimer.enabled)
-+ ctrl |= RV3028_CTRL2_UIE;
-+ if (rv3028->rtc->aie_timer.enabled)
-+ ctrl |= RV3028_CTRL2_AIE;
-+ }
-+
-+ ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
-+ RV3028_STATUS_AF | RV3028_STATUS_UF, 0);
-+ if (ret)
-+ return ret;
-+
-+ ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
-+ RV3028_CTRL2_UIE | RV3028_CTRL2_AIE, ctrl);
-+ if (ret)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int rv3028_read_offset(struct device *dev, long *offset)
-+{
-+ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
-+ int ret, value, steps;
-+
-+ ret = regmap_read(rv3028->regmap, RV3028_OFFSET, &value);
-+ if (ret < 0)
-+ return ret;
-+
-+ steps = sign_extend32(value << 1, 8);
-+
-+ ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &value);
-+ if (ret < 0)
-+ return ret;
-+
-+ steps += value >> 7;
-+
-+ *offset = DIV_ROUND_CLOSEST(steps * OFFSET_STEP_PPT, 1000);
-+
-+ return 0;
-+}
-+
-+static int rv3028_set_offset(struct device *dev, long offset)
-+{
-+ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
-+ int ret;
-+
-+ offset = clamp(offset, -244141L, 243187L) * 1000;
-+ offset = DIV_ROUND_CLOSEST(offset, OFFSET_STEP_PPT);
-+
-+ ret = regmap_write(rv3028->regmap, RV3028_OFFSET, offset >> 1);
-+ if (ret < 0)
-+ return ret;
-+
-+ return regmap_update_bits(rv3028->regmap, RV3028_BACKUP, BIT(7),
-+ offset << 7);
-+}
-+
-+static int rv3028_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
-+{
-+ struct rv3028_data *rv3028 = dev_get_drvdata(dev);
-+ int status, ret = 0;
-+
-+ switch (cmd) {
-+ case RTC_VL_READ:
-+ ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (status & RV3028_STATUS_PORF)
-+ dev_warn(&rv3028->rtc->dev, "Voltage low, data loss detected.\n");
-+
-+ status &= RV3028_STATUS_PORF;
-+
-+ if (copy_to_user((void __user *)arg, &status, sizeof(int)))
-+ return -EFAULT;
-+
-+ return 0;
-+
-+ case RTC_VL_CLR:
-+ ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
-+ RV3028_STATUS_PORF, 0);
-+
-+ return ret;
-+
-+ default:
-+ return -ENOIOCTLCMD;
-+ }
-+}
-+
-+static int rv3028_nvram_write(void *priv, unsigned int offset, void *val,
-+ size_t bytes)
-+{
-+ return regmap_bulk_write(priv, RV3028_RAM1 + offset, val, bytes);
-+}
-+
-+static int rv3028_nvram_read(void *priv, unsigned int offset, void *val,
-+ size_t bytes)
-+{
-+ return regmap_bulk_read(priv, RV3028_RAM1 + offset, val, bytes);
-+}
-+
-+static int rv3028_eeprom_write(void *priv, unsigned int offset, void *val,
-+ size_t bytes)
-+{
-+ u32 status, ctrl1;
-+ int i, ret, err;
-+ u8 *buf = val;
-+
-+ ret = regmap_read(priv, RV3028_CTRL1, &ctrl1);
-+ if (ret)
-+ return ret;
-+
-+ if (!(ctrl1 & RV3028_CTRL1_EERD)) {
-+ ret = regmap_update_bits(priv, RV3028_CTRL1,
-+ RV3028_CTRL1_EERD, RV3028_CTRL1_EERD);
-+ if (ret)
-+ return ret;
-+
-+ ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
-+ !(status & RV3028_STATUS_EEBUSY),
-+ RV3028_EEBUSY_POLL,
-+ RV3028_EEBUSY_TIMEOUT);
-+ if (ret)
-+ goto restore_eerd;
-+ }
-+
-+ for (i = 0; i < bytes; i++) {
-+ ret = regmap_write(priv, RV3028_EEPROM_ADDR, offset + i);
-+ if (ret)
-+ goto restore_eerd;
-+
-+ ret = regmap_write(priv, RV3028_EEPROM_DATA, buf[i]);
-+ if (ret)
-+ goto restore_eerd;
-+
-+ ret = regmap_write(priv, RV3028_EEPROM_CMD, 0x0);
-+ if (ret)
-+ goto restore_eerd;
-+
-+ ret = regmap_write(priv, RV3028_EEPROM_CMD,
-+ RV3028_EEPROM_CMD_WRITE);
-+ if (ret)
-+ goto restore_eerd;
-+
-+ usleep_range(RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT);
-+
-+ ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
-+ !(status & RV3028_STATUS_EEBUSY),
-+ RV3028_EEBUSY_POLL,
-+ RV3028_EEBUSY_TIMEOUT);
-+ if (ret)
-+ goto restore_eerd;
-+ }
-+
-+restore_eerd:
-+ if (!(ctrl1 & RV3028_CTRL1_EERD))
-+ {
-+ err = regmap_update_bits(priv, RV3028_CTRL1, RV3028_CTRL1_EERD,
-+ 0);
-+ if (err && !ret)
-+ ret = err;
-+ }
-+
-+ return ret;
-+}
-+
-+static int rv3028_eeprom_read(void *priv, unsigned int offset, void *val,
-+ size_t bytes)
-+{
-+ u32 status, ctrl1, data;
-+ int i, ret, err;
-+ u8 *buf = val;
-+
-+ ret = regmap_read(priv, RV3028_CTRL1, &ctrl1);
-+ if (ret)
-+ return ret;
-+
-+ if (!(ctrl1 & RV3028_CTRL1_EERD)) {
-+ ret = regmap_update_bits(priv, RV3028_CTRL1,
-+ RV3028_CTRL1_EERD, RV3028_CTRL1_EERD);
-+ if (ret)
-+ return ret;
-+
-+ ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
-+ !(status & RV3028_STATUS_EEBUSY),
-+ RV3028_EEBUSY_POLL,
-+ RV3028_EEBUSY_TIMEOUT);
-+ if (ret)
-+ goto restore_eerd;
-+ }
-+
-+ for (i = 0; i < bytes; i++) {
-+ ret = regmap_write(priv, RV3028_EEPROM_ADDR, offset + i);
-+ if (ret)
-+ goto restore_eerd;
-+
-+ ret = regmap_write(priv, RV3028_EEPROM_CMD, 0x0);
-+ if (ret)
-+ goto restore_eerd;
-+
-+ ret = regmap_write(priv, RV3028_EEPROM_CMD,
-+ RV3028_EEPROM_CMD_READ);
-+ if (ret)
-+ goto restore_eerd;
-+
-+ ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
-+ !(status & RV3028_STATUS_EEBUSY),
-+ RV3028_EEBUSY_POLL,
-+ RV3028_EEBUSY_TIMEOUT);
-+ if (ret)
-+ goto restore_eerd;
-+
-+ ret = regmap_read(priv, RV3028_EEPROM_DATA, &data);
-+ if (ret)
-+ goto restore_eerd;
-+ buf[i] = data;
-+ }
-+
-+restore_eerd:
-+ if (!(ctrl1 & RV3028_CTRL1_EERD))
-+ {
-+ err = regmap_update_bits(priv, RV3028_CTRL1, RV3028_CTRL1_EERD,
-+ 0);
-+ if (err && !ret)
-+ ret = err;
-+ }
-+
-+ return ret;
-+}
-+
-+static struct rtc_class_ops rv3028_rtc_ops = {
-+ .read_time = rv3028_get_time,
-+ .set_time = rv3028_set_time,
-+ .read_offset = rv3028_read_offset,
-+ .set_offset = rv3028_set_offset,
-+ .ioctl = rv3028_ioctl,
-+};
-+
-+static const struct regmap_config regmap_config = {
-+ .reg_bits = 8,
-+ .val_bits = 8,
-+ .max_register = 0x37,
-+};
-+
-+static int rv3028_probe(struct i2c_client *client)
-+{
-+ struct rv3028_data *rv3028;
-+ int ret, status;
-+ u32 ohms;
-+ struct nvmem_config nvmem_cfg = {
-+ .name = "rv3028_nvram",
-+ .word_size = 1,
-+ .stride = 1,
-+ .size = 2,
-+ .type = NVMEM_TYPE_BATTERY_BACKED,
-+ .reg_read = rv3028_nvram_read,
-+ .reg_write = rv3028_nvram_write,
-+ };
-+ struct nvmem_config eeprom_cfg = {
-+ .name = "rv3028_eeprom",
-+ .word_size = 1,
-+ .stride = 1,
-+ .size = 43,
-+ .type = NVMEM_TYPE_EEPROM,
-+ .reg_read = rv3028_eeprom_read,
-+ .reg_write = rv3028_eeprom_write,
-+ };
-+
-+ rv3028 = devm_kzalloc(&client->dev, sizeof(struct rv3028_data),
-+ GFP_KERNEL);
-+ if (!rv3028)
-+ return -ENOMEM;
-+
-+ rv3028->regmap = devm_regmap_init_i2c(client, ®map_config);
-+
-+ i2c_set_clientdata(client, rv3028);
-+
-+ ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (status & RV3028_STATUS_PORF)
-+ dev_warn(&client->dev, "Voltage low, data loss detected.\n");
-+
-+ if (status & RV3028_STATUS_AF)
-+ dev_warn(&client->dev, "An alarm may have been missed.\n");
-+
-+ rv3028->rtc = devm_rtc_allocate_device(&client->dev);
-+ if (IS_ERR(rv3028->rtc)) {
-+ return PTR_ERR(rv3028->rtc);
-+ }
-+
-+ if (client->irq > 0) {
-+ ret = devm_request_threaded_irq(&client->dev, client->irq,
-+ NULL, rv3028_handle_irq,
-+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-+ "rv3028", rv3028);
-+ if (ret) {
-+ dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
-+ client->irq = 0;
-+ } else {
-+ rv3028_rtc_ops.read_alarm = rv3028_get_alarm;
-+ rv3028_rtc_ops.set_alarm = rv3028_set_alarm;
-+ rv3028_rtc_ops.alarm_irq_enable = rv3028_alarm_irq_enable;
-+ }
-+ }
-+
-+ ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL1,
-+ RV3028_CTRL1_WADA, RV3028_CTRL1_WADA);
-+ if (ret)
-+ return ret;
-+
-+ /* setup timestamping */
-+ ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
-+ RV3028_CTRL2_EIE | RV3028_CTRL2_TSE,
-+ RV3028_CTRL2_EIE | RV3028_CTRL2_TSE);
-+ if (ret)
-+ return ret;
-+
-+ /* setup trickle charger */
-+ if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms",
-+ &ohms)) {
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++)
-+ if (ohms == rv3028_trickle_resistors[i])
-+ break;
-+
-+ if (i < ARRAY_SIZE(rv3028_trickle_resistors)) {
-+ ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP,
-+ RV3028_BACKUP_TCE |
-+ RV3028_BACKUP_TCR_MASK,
-+ RV3028_BACKUP_TCE | i);
-+ if (ret)
-+ return ret;
-+ } else {
-+ dev_warn(&client->dev, "invalid trickle resistor value\n");
-+ }
-+ }
-+
-+ ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group);
-+ if (ret)
-+ return ret;
-+
-+ rv3028->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
-+ rv3028->rtc->range_max = RTC_TIMESTAMP_END_2099;
-+ rv3028->rtc->ops = &rv3028_rtc_ops;
-+ ret = rtc_register_device(rv3028->rtc);
-+ if (ret)
-+ return ret;
-+
-+ nvmem_cfg.priv = rv3028->regmap;
-+ rtc_nvmem_register(rv3028->rtc, &nvmem_cfg);
-+ eeprom_cfg.priv = rv3028->regmap;
-+ rtc_nvmem_register(rv3028->rtc, &eeprom_cfg);
-+
-+ rv3028->rtc->max_user_freq = 1;
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id rv3028_of_match[] = {
-+ { .compatible = "microcrystal,rv3028", },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, rv3028_of_match);
-+
-+static struct i2c_driver rv3028_driver = {
-+ .driver = {
-+ .name = "rtc-rv3028",
-+ .of_match_table = of_match_ptr(rv3028_of_match),
-+ },
-+ .probe_new = rv3028_probe,
-+};
-+module_i2c_driver(rv3028_driver);
-+
-+MODULE_DESCRIPTION("Micro Crystal RV3028 RTC driver");
-+MODULE_LICENSE("GPL v2");
--- /dev/null
+From 95b3311cbcd29e07af1ee96b6b37c9089567bcff Mon Sep 17 00:00:00 2001
+Date: Mon, 18 Mar 2019 20:37:44 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Break out clock setting into
+ separate function
+
+commit bf31cbfbe25001036e1e096b1c260bf871766ea5 upstream.
+
+Break the clock setting logic out from the main hw_params. It's
+rather large and unweildy and makes for a large function. This
+also better enables some of the following changes to the clock
+tree access in the driver.
+
+---
+ sound/soc/codecs/tlv320aic32x4.c | 26 ++++++++++++++++++--------
+ 1 file changed, 18 insertions(+), 8 deletions(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -698,17 +698,13 @@ static int aic32x4_set_dai_fmt(struct sn
+ return 0;
+ }
+
+-static int aic32x4_hw_params(struct snd_pcm_substream *substream,
+- struct snd_pcm_hw_params *params,
+- struct snd_soc_dai *dai)
++static int aic32x4_setup_clocks(struct snd_soc_component *component,
++ unsigned int sample_rate,
++ unsigned int parent_rate)
+ {
+- struct snd_soc_component *component = dai->component;
+- struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
+- u8 iface1_reg = 0;
+- u8 dacsetup_reg = 0;
+ int i;
+
+- i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params));
++ i = aic32x4_get_divs(parent_rate, sample_rate);
+ if (i < 0) {
+ printk(KERN_ERR "aic32x4: sampling rate not supported\n");
+ return i;
+@@ -765,6 +761,20 @@ static int aic32x4_hw_params(struct snd_
+ snd_soc_component_update_bits(component, AIC32X4_BCLKN,
+ AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
+
++ return 0;
++}
++
++static int aic32x4_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params,
++ struct snd_soc_dai *dai)
++{
++ struct snd_soc_component *component = dai->component;
++ struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
++ u8 iface1_reg = 0;
++ u8 dacsetup_reg = 0;
++
++ aic32x4_setup_clocks(component, params_rate(params), aic32x4->sysclk);
++
+ switch (params_width(params)) {
+ case 16:
+ iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
+++ /dev/null
-From 67dd8e4c8ccf5d331960c7e936e5b03a9f92496d Mon Sep 17 00:00:00 2001
-Date: Thu, 28 Mar 2019 13:26:59 +0000
-Subject: [PATCH] overlays: Add rv3028 to i2c-rtc
-
-See: https://github.com/raspberrypi/linux/issues/2912
-
----
- arch/arm/boot/dts/overlays/README | 4 +++-
- .../arm/boot/dts/overlays/i2c-rtc-overlay.dts | 19 ++++++++++++++++++-
- 2 files changed, 21 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -939,6 +939,8 @@ Params: abx80x Select o
-
- pcf8563 Select the PCF8563 device
-
-+ rv3028 Select the Micro Crystal RV3028 device
-+
- addr Sets the address for the RTC. Note that the
- device must be configured to use the specified
- address.
-@@ -947,7 +949,7 @@ Params: abx80x Select o
- "schottky" (ABx80x only)
-
- trickle-resistor-ohms Resistor value for trickle charge (DS1339,
-- ABx80x)
-+ ABx80x, RV3028)
-
- wakeup-source Specify that the RTC can be used as a wakeup
- source
---- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-@@ -158,6 +158,21 @@
- };
- };
-
-+ fragment@10 {
-+ target = <&i2c_arm>;
-+ __dormant__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ rv3028: rv3028@52 {
-+ compatible = "microcrystal,rv3028";
-+ reg = <0x52>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
- __overrides__ {
- abx80x = <0>,"+0";
- ds1307 = <0>,"+1";
-@@ -169,6 +184,7 @@
- pcf8523 = <0>,"+7";
- pcf8563 = <0>,"+8";
- m41t62 = <0>,"+9";
-+ rv3028 = <0>,"+10";
-
- addr = <&abx80x>, "reg:0",
- <&ds1307>, "reg:0",
-@@ -182,7 +198,8 @@
- <&m41t62>, "reg:0";
- trickle-diode-type = <&abx80x>,"abracon,tc-diode";
- trickle-resistor-ohms = <&ds1339>,"trickle-resistor-ohms:0",
-- <&abx80x>,"abracon,tc-resistor";
-+ <&abx80x>,"abracon,tc-resistor",
-+ <&rv3028>,"trickle-resistor-ohms:0";
- wakeup-source = <&ds1339>,"wakeup-source?",
- <&ds3231>,"wakeup-source?",
- <&mcp7940x>,"wakeup-source?",
--- /dev/null
+From 6cc882cf38b62fce2a07640413b05b43b420c77a Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Mar 2019 19:38:44 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Properly Set Processing Blocks
+
+commit c95e3a4b96293403a427b5185e60fad28af51fdd upstream.
+
+Different processing blocks are required for different sampling
+rates and power parameters. Set the processing blocks based
+on this information.
+
+---
+ sound/soc/codecs/tlv320aic32x4.c | 56 ++++++++++++++++++++------------
+ 1 file changed, 36 insertions(+), 20 deletions(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -59,6 +59,8 @@ struct aic32x4_rate_divs {
+ u8 nadc;
+ u8 madc;
+ u8 blck_N;
++ u8 r_block;
++ u8 p_block;
+ };
+
+ struct aic32x4_priv {
+@@ -307,34 +309,34 @@ static const struct snd_kcontrol_new aic
+
+ static const struct aic32x4_rate_divs aic32x4_divs[] = {
+ /* 8k rate */
+- {12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
+- {24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
+- {25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
++ {12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24, 1, 1},
++ {24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24, 1, 1},
++ {25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24, 1, 1},
+ /* 11.025k rate */
+- {12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
+- {24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
++ {12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16, 1, 1},
++ {24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16, 1, 1},
+ /* 16k rate */
+- {12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
+- {24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
+- {25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
++ {12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12, 1, 1},
++ {24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12, 1, 1},
++ {25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12, 1, 1},
+ /* 22.05k rate */
+- {12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
+- {24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
+- {25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
++ {12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8, 1, 1},
++ {24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8, 1, 1},
++ {25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8, 1, 1},
+ /* 32k rate */
+- {12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
+- {24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
++ {12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6, 1, 1},
++ {24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6, 1, 1},
+ /* 44.1k rate */
+- {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
+- {24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
+- {25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
++ {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4, 1, 1},
++ {24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4, 1, 1},
++ {25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4, 1, 1},
+ /* 48k rate */
+- {12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
+- {24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
+- {25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4},
++ {12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4, 1, 1},
++ {24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4, 1, 1},
++ {25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4, 1, 1},
+
+ /* 96k rate */
+- {25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1},
++ {25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1, 1, 9},
+ };
+
+ static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
+@@ -698,6 +700,18 @@ static int aic32x4_set_dai_fmt(struct sn
+ return 0;
+ }
+
++static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
++ u8 r_block, u8 p_block)
++{
++ if (r_block > 18 || p_block > 25)
++ return -EINVAL;
++
++ snd_soc_component_write(component, AIC32X4_ADCSPB, r_block);
++ snd_soc_component_write(component, AIC32X4_DACSPB, p_block);
++
++ return 0;
++}
++
+ static int aic32x4_setup_clocks(struct snd_soc_component *component,
+ unsigned int sample_rate,
+ unsigned int parent_rate)
+@@ -710,6 +724,8 @@ static int aic32x4_setup_clocks(struct s
+ return i;
+ }
+
++ aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
++
+ /* MCLK as PLL_CLKIN */
+ snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK,
+ AIC32X4_PLL_CLKIN_MCLK << AIC32X4_PLL_CLKIN_SHIFT);
+++ /dev/null
-From 053938f67f73773152f70d89aa32e7893ee19694 Mon Sep 17 00:00:00 2001
-Date: Wed, 9 Jan 2019 22:41:21 +0530
-Subject: [PATCH] ASoC: tlv320aic32x4: SND_SOC_DAPM_MICBIAS is
- deprecated
-
-commit 04d979d7a7bac2f645cd827ea37e5ffa5b4e1f97 upstream.
-
-SND_SOC_DAPM_MICBIAS is deprecated, replace it with SND_SOC_DAPM_SUPPLY.
-
-MICBIAS voltage wasn't supplied to the microphone with the older
-SND_SOC_DAPM_MICBIAS widget, hence the microphone wouldn't work.
-
-This patch fixes the problem.
-
----
- sound/soc/codecs/tlv320aic32x4.c | 30 +++++++++++++++++++++++++++++-
- sound/soc/codecs/tlv320aic32x4.h | 1 +
- 2 files changed, 30 insertions(+), 1 deletion(-)
-
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -79,6 +79,32 @@ struct aic32x4_priv {
- struct device *dev;
- };
-
-+static int mic_bias_event(struct snd_soc_dapm_widget *w,
-+ struct snd_kcontrol *kcontrol, int event)
-+{
-+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-+
-+ switch (event) {
-+ case SND_SOC_DAPM_POST_PMU:
-+ /* Change Mic Bias Registor */
-+ snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
-+ AIC32x4_MICBIAS_MASK,
-+ AIC32X4_MICBIAS_LDOIN |
-+ AIC32X4_MICBIAS_2075V);
-+ printk(KERN_DEBUG "%s: Mic Bias will be turned ON\n", __func__);
-+ break;
-+ case SND_SOC_DAPM_PRE_PMD:
-+ snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
-+ AIC32x4_MICBIAS_MASK, 0);
-+ printk(KERN_DEBUG "%s: Mic Bias will be turned OFF\n",
-+ __func__);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
- static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
-@@ -450,7 +476,9 @@ static const struct snd_soc_dapm_widget
- SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- in3r_to_lmixer_controls),
-
-- SND_SOC_DAPM_MICBIAS("Mic Bias", AIC32X4_MICBIAS, 6, 0),
-+ SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event,
-+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-+
-
- SND_SOC_DAPM_OUTPUT("HPL"),
- SND_SOC_DAPM_OUTPUT("HPR"),
---- a/sound/soc/codecs/tlv320aic32x4.h
-+++ b/sound/soc/codecs/tlv320aic32x4.h
-@@ -195,6 +195,7 @@ int aic32x4_remove(struct device *dev);
- /* AIC32X4_MICBIAS */
- #define AIC32X4_MICBIAS_LDOIN BIT(3)
- #define AIC32X4_MICBIAS_2075V 0x60
-+#define AIC32x4_MICBIAS_MASK GENMASK(6, 3)
-
- /* AIC32X4_LMICPGANIN */
- #define AIC32X4_LMICPGANIN_IN2R_10K 0x10
+++ /dev/null
-From 95b3311cbcd29e07af1ee96b6b37c9089567bcff Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Mar 2019 20:37:44 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Break out clock setting into
- separate function
-
-commit bf31cbfbe25001036e1e096b1c260bf871766ea5 upstream.
-
-Break the clock setting logic out from the main hw_params. It's
-rather large and unweildy and makes for a large function. This
-also better enables some of the following changes to the clock
-tree access in the driver.
-
----
- sound/soc/codecs/tlv320aic32x4.c | 26 ++++++++++++++++++--------
- 1 file changed, 18 insertions(+), 8 deletions(-)
-
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -698,17 +698,13 @@ static int aic32x4_set_dai_fmt(struct sn
- return 0;
- }
-
--static int aic32x4_hw_params(struct snd_pcm_substream *substream,
-- struct snd_pcm_hw_params *params,
-- struct snd_soc_dai *dai)
-+static int aic32x4_setup_clocks(struct snd_soc_component *component,
-+ unsigned int sample_rate,
-+ unsigned int parent_rate)
- {
-- struct snd_soc_component *component = dai->component;
-- struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
-- u8 iface1_reg = 0;
-- u8 dacsetup_reg = 0;
- int i;
-
-- i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params));
-+ i = aic32x4_get_divs(parent_rate, sample_rate);
- if (i < 0) {
- printk(KERN_ERR "aic32x4: sampling rate not supported\n");
- return i;
-@@ -765,6 +761,20 @@ static int aic32x4_hw_params(struct snd_
- snd_soc_component_update_bits(component, AIC32X4_BCLKN,
- AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
-
-+ return 0;
-+}
-+
-+static int aic32x4_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params,
-+ struct snd_soc_dai *dai)
-+{
-+ struct snd_soc_component *component = dai->component;
-+ struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
-+ u8 iface1_reg = 0;
-+ u8 dacsetup_reg = 0;
-+
-+ aic32x4_setup_clocks(component, params_rate(params), aic32x4->sysclk);
-+
- switch (params_width(params)) {
- case 16:
- iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
--- /dev/null
+From 957ccf05060d65da074d019679ec7f486477e412 Mon Sep 17 00:00:00 2001
+Date: Thu, 21 Mar 2019 17:58:45 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Model PLL in CCF
+
+commit 514b044cba667e4b7c383ec79b42b997e624b91d upstream.
+
+Model and manage the on-board PLL as a component in the Core
+Clock Framework. This should allow us to do some more complex
+clock management and power control. Also, some of the
+on-board chip clocks can be exposed to the outside, and this
+change will make those clocks easier to consume by other
+parts of the kernel.
+
+---
+ sound/soc/codecs/Kconfig | 1 +
+ sound/soc/codecs/Makefile | 2 +-
+ sound/soc/codecs/tlv320aic32x4-clk.c | 323 +++++++++++++++++++++++++++
+ sound/soc/codecs/tlv320aic32x4.c | 195 ++++++++--------
+ sound/soc/codecs/tlv320aic32x4.h | 5 +
+ 5 files changed, 431 insertions(+), 95 deletions(-)
+ create mode 100644 sound/soc/codecs/tlv320aic32x4-clk.c
+
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -1025,6 +1025,7 @@ config SND_SOC_TLV320AIC31XX
+
+ config SND_SOC_TLV320AIC32X4
+ tristate
++ depends on COMMON_CLK
+
+ config SND_SOC_TLV320AIC32X4_I2C
+ tristate "Texas Instruments TLV320AIC32x4 audio CODECs - I2C"
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -182,7 +182,7 @@ snd-soc-tlv320aic23-i2c-objs := tlv320ai
+ snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
+ snd-soc-tlv320aic26-objs := tlv320aic26.o
+ snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
+-snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
++snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o tlv320aic32x4-clk.o
+ snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o
+ snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
+ snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+--- /dev/null
++++ b/sound/soc/codecs/tlv320aic32x4-clk.c
+@@ -0,0 +1,323 @@
++/* SPDX-License-Identifier: GPL-2.0
++ *
++ * Clock Tree for the Texas Instruments TLV320AIC32x4
++ *
++ * Copyright 2019 Annaliese McDermond
++ *
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/clkdev.h>
++#include <linux/regmap.h>
++#include <linux/device.h>
++
++#include "tlv320aic32x4.h"
++
++#define to_clk_aic32x4(_hw) container_of(_hw, struct clk_aic32x4, hw)
++struct clk_aic32x4 {
++ struct clk_hw hw;
++ struct device *dev;
++ struct regmap *regmap;
++ unsigned int reg;
++};
++
++/*
++ * struct clk_aic32x4_pll_muldiv - Multiplier/divider settings
++ * @p: Divider
++ * @r: first multiplier
++ * @j: integer part of second multiplier
++ * @d: decimal part of second multiplier
++ */
++struct clk_aic32x4_pll_muldiv {
++ u8 p;
++ u16 r;
++ u8 j;
++ u16 d;
++};
++
++struct aic32x4_clkdesc {
++ const char *name;
++ const char * const *parent_names;
++ unsigned int num_parents;
++ const struct clk_ops *ops;
++ unsigned int reg;
++};
++
++static int clk_aic32x4_pll_prepare(struct clk_hw *hw)
++{
++ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
++
++ return regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
++ AIC32X4_PLLEN, AIC32X4_PLLEN);
++}
++
++static void clk_aic32x4_pll_unprepare(struct clk_hw *hw)
++{
++ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
++
++ regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
++ AIC32X4_PLLEN, 0);
++}
++
++static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw)
++{
++ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
++
++ unsigned int val;
++ int ret;
++
++ ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
++ if (ret < 0)
++ return ret;
++
++ return !!(val & AIC32X4_PLLEN);
++}
++
++static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll,
++ struct clk_aic32x4_pll_muldiv *settings)
++{
++ /* Change to use regmap_bulk_read? */
++ unsigned int val;
++ int ret;
++
++ ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
++ if (ret)
++ return ret;
++ settings->r = val & AIC32X4_PLL_R_MASK;
++ settings->p = (val & AIC32X4_PLL_P_MASK) >> AIC32X4_PLL_P_SHIFT;
++
++ ret = regmap_read(pll->regmap, AIC32X4_PLLJ, &val);
++ if (ret < 0)
++ return ret;
++ settings->j = val;
++
++ ret = regmap_read(pll->regmap, AIC32X4_PLLDMSB, &val);
++ if (ret < 0)
++ return ret;
++ settings->d = val << 8;
++
++ ret = regmap_read(pll->regmap, AIC32X4_PLLDLSB, &val);
++ if (ret < 0)
++ return ret;
++ settings->d |= val;
++
++ return 0;
++}
++
++static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll,
++ struct clk_aic32x4_pll_muldiv *settings)
++{
++ int ret;
++ /* Change to use regmap_bulk_write for some if not all? */
++
++ ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
++ AIC32X4_PLL_R_MASK, settings->r);
++ if (ret < 0)
++ return ret;
++
++ ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
++ AIC32X4_PLL_P_MASK,
++ settings->p << AIC32X4_PLL_P_SHIFT);
++ if (ret < 0)
++ return ret;
++
++ ret = regmap_write(pll->regmap, AIC32X4_PLLJ, settings->j);
++ if (ret < 0)
++ return ret;
++
++ ret = regmap_write(pll->regmap, AIC32X4_PLLDMSB, (settings->d >> 8));
++ if (ret < 0)
++ return ret;
++ ret = regmap_write(pll->regmap, AIC32X4_PLLDLSB, (settings->d & 0xff));
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static unsigned long clk_aic32x4_pll_calc_rate(
++ struct clk_aic32x4_pll_muldiv *settings,
++ unsigned long parent_rate)
++{
++ u64 rate;
++ /*
++ * We scale j by 10000 to account for the decimal part of P and divide
++ * it back out later.
++ */
++ rate = (u64) parent_rate * settings->r *
++ ((settings->j * 10000) + settings->d);
++
++ return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000);
++}
++
++static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
++ unsigned long rate, unsigned long parent_rate)
++{
++ u64 multiplier;
++
++ settings->p = parent_rate / AIC32X4_MAX_PLL_CLKIN + 1;
++ if (settings->p > 8)
++ return -1;
++
++ /*
++ * We scale this figure by 10000 so that we can get the decimal part
++ * of the multiplier. This is because we can't do floating point
++ * math in the kernel.
++ */
++ multiplier = (u64) rate * settings->p * 10000;
++ do_div(multiplier, parent_rate);
++
++ /*
++ * J can't be over 64, so R can scale this.
++ * R can't be greater than 4.
++ */
++ settings->r = ((u32) multiplier / 640000) + 1;
++ if (settings->r > 4)
++ return -1;
++ do_div(multiplier, settings->r);
++
++ /*
++ * J can't be < 1.
++ */
++ if (multiplier < 10000)
++ return -1;
++
++ /* Figure out the integer part, J, and the fractional part, D. */
++ settings->j = (u32) multiplier / 10000;
++ settings->d = (u32) multiplier % 10000;
++
++ return 0;
++}
++
++static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
++ struct clk_aic32x4_pll_muldiv settings;
++ int ret;
++
++ ret = clk_aic32x4_pll_get_muldiv(pll, &settings);
++ if (ret < 0)
++ return 0;
++
++ return clk_aic32x4_pll_calc_rate(&settings, parent_rate);
++}
++
++static long clk_aic32x4_pll_round_rate(struct clk_hw *hw,
++ unsigned long rate,
++ unsigned long *parent_rate)
++{
++ struct clk_aic32x4_pll_muldiv settings;
++ int ret;
++
++ ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, *parent_rate);
++ if (ret < 0)
++ return 0;
++
++ return clk_aic32x4_pll_calc_rate(&settings, *parent_rate);
++}
++
++static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
++ unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
++ struct clk_aic32x4_pll_muldiv settings;
++ int ret;
++
++ ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, parent_rate);
++ if (ret < 0)
++ return -EINVAL;
++
++ return clk_aic32x4_pll_set_muldiv(pll, &settings);
++}
++
++static int clk_aic32x4_pll_set_parent(struct clk_hw *hw, u8 index)
++{
++ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
++
++ return regmap_update_bits(pll->regmap,
++ AIC32X4_CLKMUX,
++ AIC32X4_PLL_CLKIN_MASK,
++ index << AIC32X4_PLL_CLKIN_SHIFT);
++}
++
++static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw)
++{
++ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
++ unsigned int val;
++
++ regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
++
++ return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT;
++}
++
++
++static const struct clk_ops aic32x4_pll_ops = {
++ .prepare = clk_aic32x4_pll_prepare,
++ .unprepare = clk_aic32x4_pll_unprepare,
++ .is_prepared = clk_aic32x4_pll_is_prepared,
++ .recalc_rate = clk_aic32x4_pll_recalc_rate,
++ .round_rate = clk_aic32x4_pll_round_rate,
++ .set_rate = clk_aic32x4_pll_set_rate,
++ .set_parent = clk_aic32x4_pll_set_parent,
++ .get_parent = clk_aic32x4_pll_get_parent,
++};
++
++static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
++ {
++ .name = "pll",
++ .parent_names =
++ (const char* []) { "mclk", "bclk", "gpio", "din" },
++ .num_parents = 4,
++ .ops = &aic32x4_pll_ops,
++ .reg = 0,
++ },
++};
++
++static struct clk *aic32x4_register_clk(struct device *dev,
++ struct aic32x4_clkdesc *desc)
++{
++ struct clk_init_data init;
++ struct clk_aic32x4 *priv;
++ const char *devname = dev_name(dev);
++
++ init.ops = desc->ops;
++ init.name = desc->name;
++ init.parent_names = desc->parent_names;
++ init.num_parents = desc->num_parents;
++ init.flags = 0;
++
++ priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL);
++ if (priv == NULL)
++ return (struct clk *) -ENOMEM;
++
++ priv->dev = dev;
++ priv->hw.init = &init;
++ priv->regmap = dev_get_regmap(dev, NULL);
++ priv->reg = desc->reg;
++
++ clk_hw_register_clkdev(&priv->hw, desc->name, devname);
++ return devm_clk_register(dev, &priv->hw);
++}
++
++int aic32x4_register_clocks(struct device *dev, const char *mclk_name)
++{
++ int i;
++
++ /*
++ * These lines are here to preserve the current functionality of
++ * the driver with regard to the DT. These should eventually be set
++ * by DT nodes so that the connections can be set up in configuration
++ * rather than code.
++ */
++ aic32x4_clkdesc_array[0].parent_names =
++ (const char* []) { mclk_name, "bclk", "gpio", "din" };
++
++ for (i = 0; i < ARRAY_SIZE(aic32x4_clkdesc_array); ++i)
++ aic32x4_register_clk(dev, &aic32x4_clkdesc_array[i]);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(aic32x4_register_clocks);
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -14,7 +14,7 @@
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+@@ -33,6 +33,7 @@
+ #include <linux/cdev.h>
+ #include <linux/slab.h>
+ #include <linux/clk.h>
++#include <linux/of_clk.h>
+ #include <linux/regulator/consumer.h>
+
+ #include <sound/tlv320aic32x4.h>
+@@ -49,9 +50,7 @@
+ struct aic32x4_rate_divs {
+ u32 mclk;
+ u32 rate;
+- u8 p_val;
+- u8 pll_j;
+- u16 pll_d;
++ unsigned long pll_rate;
+ u16 dosr;
+ u8 ndac;
+ u8 mdac;
+@@ -71,6 +70,7 @@ struct aic32x4_priv {
+ bool swapdacs;
+ int rstn_gpio;
+ struct clk *mclk;
++ const char *mclk_name;
+
+ struct regulator *supply_ldo;
+ struct regulator *supply_iov;
+@@ -309,34 +309,34 @@ static const struct snd_kcontrol_new aic
+
+ static const struct aic32x4_rate_divs aic32x4_divs[] = {
+ /* 8k rate */
+- {12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24, 1, 1},
+- {24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24, 1, 1},
+- {25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24, 1, 1},
++ { 12000000, 8000, 57120000, 768, 5, 3, 128, 5, 18, 24, 1, 1 },
++ { 24000000, 8000, 57120000, 768, 15, 1, 64, 45, 4, 24, 1, 1 },
++ { 25000000, 8000, 32620000, 768, 15, 1, 64, 45, 4, 24, 1, 1 },
+ /* 11.025k rate */
+- {12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16, 1, 1},
+- {24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16, 1, 1},
++ { 12000000, 11025, 44217600, 512, 8, 2, 128, 8, 8, 16, 1, 1 },
++ { 24000000, 11025, 44217600, 512, 16, 1, 64, 32, 4, 16, 1, 1 },
+ /* 16k rate */
+- {12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12, 1, 1},
+- {24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12, 1, 1},
+- {25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12, 1, 1},
++ { 12000000, 16000, 57120000, 384, 5, 3, 128, 5, 9, 12, 1, 1 },
++ { 24000000, 16000, 57120000, 384, 15, 1, 64, 18, 5, 12, 1, 1 },
++ { 25000000, 16000, 32620000, 384, 15, 1, 64, 18, 5, 12, 1, 1 },
+ /* 22.05k rate */
+- {12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8, 1, 1},
+- {24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8, 1, 1},
+- {25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8, 1, 1},
++ { 12000000, 22050, 44217600, 256, 4, 4, 128, 4, 8, 8, 1, 1 },
++ { 24000000, 22050, 44217600, 256, 16, 1, 64, 16, 4, 8, 1, 1 },
++ { 25000000, 22050, 19713750, 256, 16, 1, 64, 16, 4, 8, 1, 1 },
+ /* 32k rate */
+- {12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6, 1, 1},
+- {24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6, 1, 1},
++ { 12000000, 32000, 14112000, 192, 2, 7, 64, 2, 21, 6, 1, 1 },
++ { 24000000, 32000, 14112000, 192, 7, 2, 64, 7, 6, 6, 1, 1 },
+ /* 44.1k rate */
+- {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4, 1, 1},
+- {24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4, 1, 1},
+- {25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4, 1, 1},
++ { 12000000, 44100, 44217600, 128, 2, 8, 128, 2, 8, 4, 1, 1 },
++ { 24000000, 44100, 44217600, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
++ { 25000000, 44100, 19713750, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
+ /* 48k rate */
+- {12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4, 1, 1},
+- {24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4, 1, 1},
+- {25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4, 1, 1},
++ { 12000000, 48000, 18432000, 128, 2, 8, 128, 2, 8, 4, 1, 1 },
++ { 24000000, 48000, 18432000, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
++ { 25000000, 48000, 75626250, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
+
+ /* 96k rate */
+- {25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1, 1, 9},
++ { 25000000, 96000, 75626250, 64, 4, 4, 64, 4, 4, 1, 1, 9 },
+ };
+
+ static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
+@@ -393,7 +393,7 @@ static const struct snd_kcontrol_new in3
+ SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum),
+ };
+
+-/* Right mixer pins */
++/* Right mixer pins */
+ static SOC_ENUM_SINGLE_DECL(in1r_rpga_p_enum, AIC32X4_RMICPGAPIN, 6, resistor_text);
+ static SOC_ENUM_SINGLE_DECL(in2r_rpga_p_enum, AIC32X4_RMICPGAPIN, 4, resistor_text);
+ static SOC_ENUM_SINGLE_DECL(in3r_rpga_p_enum, AIC32X4_RMICPGAPIN, 2, resistor_text);
+@@ -597,7 +597,7 @@ static const struct snd_soc_dapm_route a
+ static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
+ {
+ .selector_reg = 0,
+- .selector_mask = 0xff,
++ .selector_mask = 0xff,
+ .window_start = 0,
+ .window_len = 128,
+ .range_min = 0,
+@@ -618,7 +618,7 @@ static inline int aic32x4_get_divs(int m
+
+ for (i = 0; i < ARRAY_SIZE(aic32x4_divs); i++) {
+ if ((aic32x4_divs[i].rate == rate)
+- && (aic32x4_divs[i].mclk == mclk)) {
++ && (aic32x4_divs[i].mclk == mclk)) {
+ return i;
+ }
+ }
+@@ -690,12 +690,12 @@ static int aic32x4_set_dai_fmt(struct sn
+ }
+
+ snd_soc_component_update_bits(component, AIC32X4_IFACE1,
+- AIC32X4_IFACE1_DATATYPE_MASK |
+- AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
++ AIC32X4_IFACE1_DATATYPE_MASK |
++ AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
+ snd_soc_component_update_bits(component, AIC32X4_IFACE2,
+- AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
++ AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
+ snd_soc_component_update_bits(component, AIC32X4_IFACE3,
+- AIC32X4_BCLKINV_MASK, iface_reg_3);
++ AIC32X4_BCLKINV_MASK, iface_reg_3);
+
+ return 0;
+ }
+@@ -717,6 +717,11 @@ static int aic32x4_setup_clocks(struct s
+ unsigned int parent_rate)
+ {
+ int i;
++ int ret;
++
++ struct clk_bulk_data clocks[] = {
++ { .id = "pll" },
++ };
+
+ i = aic32x4_get_divs(parent_rate, sample_rate);
+ if (i < 0) {
+@@ -724,39 +729,29 @@ static int aic32x4_setup_clocks(struct s
+ return i;
+ }
+
++ ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
++ if (ret)
++ return ret;
++
++ clk_set_rate(clocks[0].clk, sample_rate);
++
+ aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
+
+- /* MCLK as PLL_CLKIN */
+- snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK,
+- AIC32X4_PLL_CLKIN_MCLK << AIC32X4_PLL_CLKIN_SHIFT);
+ /* PLL as CODEC_CLKIN */
+- snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_MASK,
+- AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
++ snd_soc_component_update_bits(component, AIC32X4_CLKMUX,
++ AIC32X4_CODEC_CLKIN_MASK,
++ AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
+ /* DAC_MOD_CLK as BDIV_CLKIN */
+ snd_soc_component_update_bits(component, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK,
+- AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
+-
+- /* We will fix R value to 1 and will make P & J=K.D as variable */
+- snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_R_MASK, 0x01);
+-
+- /* PLL P value */
+- snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_P_MASK,
+- aic32x4_divs[i].p_val << AIC32X4_PLL_P_SHIFT);
+-
+- /* PLL J value */
+- snd_soc_component_write(component, AIC32X4_PLLJ, aic32x4_divs[i].pll_j);
+-
+- /* PLL D value */
+- snd_soc_component_write(component, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8));
+- snd_soc_component_write(component, AIC32X4_PLLDLSB, (aic32x4_divs[i].pll_d & 0xff));
++ AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
+
+ /* NDAC divider value */
+ snd_soc_component_update_bits(component, AIC32X4_NDAC,
+- AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
++ AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
+
+ /* MDAC divider value */
+ snd_soc_component_update_bits(component, AIC32X4_MDAC,
+- AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac);
++ AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac);
+
+ /* DOSR MSB & LSB values */
+ snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
+@@ -764,18 +759,18 @@ static int aic32x4_setup_clocks(struct s
+
+ /* NADC divider value */
+ snd_soc_component_update_bits(component, AIC32X4_NADC,
+- AIC32X4_NADC_MASK, aic32x4_divs[i].nadc);
++ AIC32X4_NADC_MASK, aic32x4_divs[i].nadc);
+
+ /* MADC divider value */
+ snd_soc_component_update_bits(component, AIC32X4_MADC,
+- AIC32X4_MADC_MASK, aic32x4_divs[i].madc);
++ AIC32X4_MADC_MASK, aic32x4_divs[i].madc);
+
+ /* AOSR value */
+ snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
+
+ /* BCLK N divider */
+ snd_soc_component_update_bits(component, AIC32X4_BCLKN,
+- AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
++ AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
+
+ return 0;
+ }
+@@ -794,23 +789,23 @@ static int aic32x4_hw_params(struct snd_
+ switch (params_width(params)) {
+ case 16:
+ iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
+- AIC32X4_IFACE1_DATALEN_SHIFT);
++ AIC32X4_IFACE1_DATALEN_SHIFT);
+ break;
+ case 20:
+ iface1_reg |= (AIC32X4_WORD_LEN_20BITS <<
+- AIC32X4_IFACE1_DATALEN_SHIFT);
++ AIC32X4_IFACE1_DATALEN_SHIFT);
+ break;
+ case 24:
+ iface1_reg |= (AIC32X4_WORD_LEN_24BITS <<
+- AIC32X4_IFACE1_DATALEN_SHIFT);
++ AIC32X4_IFACE1_DATALEN_SHIFT);
+ break;
+ case 32:
+ iface1_reg |= (AIC32X4_WORD_LEN_32BITS <<
+- AIC32X4_IFACE1_DATALEN_SHIFT);
++ AIC32X4_IFACE1_DATALEN_SHIFT);
+ break;
+ }
+ snd_soc_component_update_bits(component, AIC32X4_IFACE1,
+- AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
++ AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
+
+ if (params_channels(params) == 1) {
+ dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
+@@ -821,7 +816,7 @@ static int aic32x4_hw_params(struct snd_
+ dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
+ }
+ snd_soc_component_update_bits(component, AIC32X4_DACSETUP,
+- AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
++ AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
+
+ return 0;
+ }
+@@ -831,7 +826,7 @@ static int aic32x4_mute(struct snd_soc_d
+ struct snd_soc_component *component = dai->component;
+
+ snd_soc_component_update_bits(component, AIC32X4_DACMUTE,
+- AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
++ AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
+
+ return 0;
+ }
+@@ -853,27 +848,27 @@ static int aic32x4_set_bias_level(struct
+
+ /* Switch on PLL */
+ snd_soc_component_update_bits(component, AIC32X4_PLLPR,
+- AIC32X4_PLLEN, AIC32X4_PLLEN);
++ AIC32X4_PLLEN, AIC32X4_PLLEN);
+
+ /* Switch on NDAC Divider */
+ snd_soc_component_update_bits(component, AIC32X4_NDAC,
+- AIC32X4_NDACEN, AIC32X4_NDACEN);
++ AIC32X4_NDACEN, AIC32X4_NDACEN);
+
+ /* Switch on MDAC Divider */
+ snd_soc_component_update_bits(component, AIC32X4_MDAC,
+- AIC32X4_MDACEN, AIC32X4_MDACEN);
++ AIC32X4_MDACEN, AIC32X4_MDACEN);
+
+ /* Switch on NADC Divider */
+ snd_soc_component_update_bits(component, AIC32X4_NADC,
+- AIC32X4_NADCEN, AIC32X4_NADCEN);
++ AIC32X4_NADCEN, AIC32X4_NADCEN);
+
+ /* Switch on MADC Divider */
+ snd_soc_component_update_bits(component, AIC32X4_MADC,
+- AIC32X4_MADCEN, AIC32X4_MADCEN);
++ AIC32X4_MADCEN, AIC32X4_MADCEN);
+
+ /* Switch on BCLK_N Divider */
+ snd_soc_component_update_bits(component, AIC32X4_BCLKN,
+- AIC32X4_BCLKEN, AIC32X4_BCLKEN);
++ AIC32X4_BCLKEN, AIC32X4_BCLKEN);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+@@ -884,27 +879,27 @@ static int aic32x4_set_bias_level(struct
+
+ /* Switch off BCLK_N Divider */
+ snd_soc_component_update_bits(component, AIC32X4_BCLKN,
+- AIC32X4_BCLKEN, 0);
++ AIC32X4_BCLKEN, 0);
+
+ /* Switch off MADC Divider */
+ snd_soc_component_update_bits(component, AIC32X4_MADC,
+- AIC32X4_MADCEN, 0);
++ AIC32X4_MADCEN, 0);
+
+ /* Switch off NADC Divider */
+ snd_soc_component_update_bits(component, AIC32X4_NADC,
+- AIC32X4_NADCEN, 0);
++ AIC32X4_NADCEN, 0);
+
+ /* Switch off MDAC Divider */
+ snd_soc_component_update_bits(component, AIC32X4_MDAC,
+- AIC32X4_MDACEN, 0);
++ AIC32X4_MDACEN, 0);
+
+ /* Switch off NDAC Divider */
+ snd_soc_component_update_bits(component, AIC32X4_NDAC,
+- AIC32X4_NDACEN, 0);
++ AIC32X4_NDACEN, 0);
+
+ /* Switch off PLL */
+ snd_soc_component_update_bits(component, AIC32X4_PLLPR,
+- AIC32X4_PLLEN, 0);
++ AIC32X4_PLLEN, 0);
+
+ /* Switch off master clock */
+ clk_disable_unprepare(aic32x4->mclk);
+@@ -916,7 +911,7 @@ static int aic32x4_set_bias_level(struct
+ }
+
+ #define AIC32X4_RATES SNDRV_PCM_RATE_8000_96000
+-#define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
++#define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+ | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+ static const struct snd_soc_dai_ops aic32x4_ops = {
+@@ -929,17 +924,17 @@ static const struct snd_soc_dai_ops aic3
+ static struct snd_soc_dai_driver aic32x4_dai = {
+ .name = "tlv320aic32x4-hifi",
+ .playback = {
+- .stream_name = "Playback",
+- .channels_min = 1,
+- .channels_max = 2,
+- .rates = AIC32X4_RATES,
+- .formats = AIC32X4_FORMATS,},
++ .stream_name = "Playback",
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = AIC32X4_RATES,
++ .formats = AIC32X4_FORMATS,},
+ .capture = {
+- .stream_name = "Capture",
+- .channels_min = 1,
+- .channels_max = 2,
+- .rates = AIC32X4_RATES,
+- .formats = AIC32X4_FORMATS,},
++ .stream_name = "Capture",
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = AIC32X4_RATES,
++ .formats = AIC32X4_FORMATS,},
+ .ops = &aic32x4_ops,
+ .symmetric_rates = 1,
+ };
+@@ -952,7 +947,7 @@ static void aic32x4_setup_gpios(struct s
+ /* MFP1 */
+ if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) {
+ snd_soc_component_write(component, AIC32X4_DINCTL,
+- aic32x4->setup->gpio_func[0]);
++ aic32x4->setup->gpio_func[0]);
+ snd_soc_add_component_controls(component, aic32x4_mfp1,
+ ARRAY_SIZE(aic32x4_mfp1));
+ }
+@@ -960,7 +955,7 @@ static void aic32x4_setup_gpios(struct s
+ /* MFP2 */
+ if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) {
+ snd_soc_component_write(component, AIC32X4_DOUTCTL,
+- aic32x4->setup->gpio_func[1]);
++ aic32x4->setup->gpio_func[1]);
+ snd_soc_add_component_controls(component, aic32x4_mfp2,
+ ARRAY_SIZE(aic32x4_mfp2));
+ }
+@@ -968,7 +963,7 @@ static void aic32x4_setup_gpios(struct s
+ /* MFP3 */
+ if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) {
+ snd_soc_component_write(component, AIC32X4_SCLKCTL,
+- aic32x4->setup->gpio_func[2]);
++ aic32x4->setup->gpio_func[2]);
+ snd_soc_add_component_controls(component, aic32x4_mfp3,
+ ARRAY_SIZE(aic32x4_mfp3));
+ }
+@@ -976,7 +971,7 @@ static void aic32x4_setup_gpios(struct s
+ /* MFP4 */
+ if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) {
+ snd_soc_component_write(component, AIC32X4_MISOCTL,
+- aic32x4->setup->gpio_func[3]);
++ aic32x4->setup->gpio_func[3]);
+ snd_soc_add_component_controls(component, aic32x4_mfp4,
+ ARRAY_SIZE(aic32x4_mfp4));
+ }
+@@ -984,7 +979,7 @@ static void aic32x4_setup_gpios(struct s
+ /* MFP5 */
+ if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) {
+ snd_soc_component_write(component, AIC32X4_GPIOCTL,
+- aic32x4->setup->gpio_func[4]);
++ aic32x4->setup->gpio_func[4]);
+ snd_soc_add_component_controls(component, aic32x4_mfp5,
+ ARRAY_SIZE(aic32x4_mfp5));
+ }
+@@ -1007,8 +1002,8 @@ static int aic32x4_component_probe(struc
+
+ /* Power platform configuration */
+ if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
+- snd_soc_component_write(component, AIC32X4_MICBIAS, AIC32X4_MICBIAS_LDOIN |
+- AIC32X4_MICBIAS_2075V);
++ snd_soc_component_write(component, AIC32X4_MICBIAS,
++ AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V);
+ }
+ if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
+ snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
+@@ -1071,12 +1066,18 @@ static int aic32x4_parse_dt(struct aic32
+ struct device_node *np)
+ {
+ struct aic32x4_setup_data *aic32x4_setup;
++ int ret;
+
+ aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
+ GFP_KERNEL);
+ if (!aic32x4_setup)
+ return -ENOMEM;
+
++ ret = of_property_match_string(np, "clock-names", "mclk");
++ if (ret < 0)
++ return -EINVAL;
++ aic32x4->mclk_name = of_clk_get_parent_name(np, ret);
++
+ aic32x4->swapdacs = false;
+ aic32x4->micpga_routing = 0;
+ aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
+@@ -1198,7 +1199,7 @@ int aic32x4_probe(struct device *dev, st
+ return PTR_ERR(regmap);
+
+ aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv),
+- GFP_KERNEL);
++ GFP_KERNEL);
+ if (aic32x4 == NULL)
+ return -ENOMEM;
+
+@@ -1210,6 +1211,7 @@ int aic32x4_probe(struct device *dev, st
+ aic32x4->swapdacs = pdata->swapdacs;
+ aic32x4->micpga_routing = pdata->micpga_routing;
+ aic32x4->rstn_gpio = pdata->rstn_gpio;
++ aic32x4->mclk_name = "mclk";
+ } else if (np) {
+ ret = aic32x4_parse_dt(aic32x4, np);
+ if (ret) {
+@@ -1221,6 +1223,7 @@ int aic32x4_probe(struct device *dev, st
+ aic32x4->swapdacs = false;
+ aic32x4->micpga_routing = 0;
+ aic32x4->rstn_gpio = -1;
++ aic32x4->mclk_name = "mclk";
+ }
+
+ aic32x4->mclk = devm_clk_get(dev, "mclk");
+@@ -1229,6 +1232,10 @@ int aic32x4_probe(struct device *dev, st
+ return PTR_ERR(aic32x4->mclk);
+ }
+
++ ret = aic32x4_register_clocks(dev, aic32x4->mclk_name);
++ if (ret)
++ return ret;
++
+ if (gpio_is_valid(aic32x4->rstn_gpio)) {
+ ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio,
+ GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
+--- a/sound/soc/codecs/tlv320aic32x4.h
++++ b/sound/soc/codecs/tlv320aic32x4.h
+@@ -16,6 +16,7 @@ struct regmap_config;
+ extern const struct regmap_config aic32x4_regmap_config;
+ int aic32x4_probe(struct device *dev, struct regmap *regmap);
+ int aic32x4_remove(struct device *dev);
++int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
+
+ /* tlv320aic32x4 register space (in decimal to match datasheet) */
+
+@@ -205,4 +206,8 @@ int aic32x4_remove(struct device *dev);
+ #define AIC32X4_RMICPGANIN_IN1L_10K 0x10
+ #define AIC32X4_RMICPGANIN_CM1R_10K 0x40
+
++/* Clock Limits */
++#define AIC32X4_MAX_PLL_CLKIN 20000000
++
++
+ #endif /* _TLV320AIC32X4_H */
--- /dev/null
+From c5f9d78ec34de15732bcbff52bedba7a840e42b2 Mon Sep 17 00:00:00 2001
+Date: Thu, 21 Mar 2019 17:58:46 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Model CODEC_CLKIN in CCF
+
+commit fd2df3aeafa4b4cc468d58e147e0822967034b71 upstream.
+
+Model and manage codec clock input as a component in the Core
+Clock Framework. This should allow us to do some more complex
+clock management and power control. Also, some of the
+on-board chip clocks can be exposed to the outside, and this
+change will make those clocks easier to consume by other
+parts of the kernel.
+
+---
+ sound/soc/codecs/tlv320aic32x4-clk.c | 34 ++++++++++++++++++++++++++++
+ sound/soc/codecs/tlv320aic32x4.c | 18 +++++++++++----
+ 2 files changed, 47 insertions(+), 5 deletions(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4-clk.c
++++ b/sound/soc/codecs/tlv320aic32x4-clk.c
+@@ -265,6 +265,30 @@ static const struct clk_ops aic32x4_pll_
+ .get_parent = clk_aic32x4_pll_get_parent,
+ };
+
++static int clk_aic32x4_codec_clkin_set_parent(struct clk_hw *hw, u8 index)
++{
++ struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
++
++ return regmap_update_bits(mux->regmap,
++ AIC32X4_CLKMUX,
++ AIC32X4_CODEC_CLKIN_MASK, index << AIC32X4_CODEC_CLKIN_SHIFT);
++}
++
++static u8 clk_aic32x4_codec_clkin_get_parent(struct clk_hw *hw)
++{
++ struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
++ unsigned int val;
++
++ regmap_read(mux->regmap, AIC32X4_CLKMUX, &val);
++
++ return (val & AIC32X4_CODEC_CLKIN_MASK) >> AIC32X4_CODEC_CLKIN_SHIFT;
++}
++
++static const struct clk_ops aic32x4_codec_clkin_ops = {
++ .set_parent = clk_aic32x4_codec_clkin_set_parent,
++ .get_parent = clk_aic32x4_codec_clkin_get_parent,
++};
++
+ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
+ {
+ .name = "pll",
+@@ -274,6 +298,14 @@ static struct aic32x4_clkdesc aic32x4_cl
+ .ops = &aic32x4_pll_ops,
+ .reg = 0,
+ },
++ {
++ .name = "codec_clkin",
++ .parent_names =
++ (const char *[]) { "mclk", "bclk", "gpio", "pll" },
++ .num_parents = 4,
++ .ops = &aic32x4_codec_clkin_ops,
++ .reg = 0,
++ },
+ };
+
+ static struct clk *aic32x4_register_clk(struct device *dev,
+@@ -314,6 +346,8 @@ int aic32x4_register_clocks(struct devic
+ */
+ aic32x4_clkdesc_array[0].parent_names =
+ (const char* []) { mclk_name, "bclk", "gpio", "din" };
++ aic32x4_clkdesc_array[1].parent_names =
++ (const char *[]) { mclk_name, "bclk", "gpio", "pll" };
+
+ for (i = 0; i < ARRAY_SIZE(aic32x4_clkdesc_array); ++i)
+ aic32x4_register_clk(dev, &aic32x4_clkdesc_array[i]);
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -737,12 +737,9 @@ static int aic32x4_setup_clocks(struct s
+
+ aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
+
+- /* PLL as CODEC_CLKIN */
+- snd_soc_component_update_bits(component, AIC32X4_CLKMUX,
+- AIC32X4_CODEC_CLKIN_MASK,
+- AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
+ /* DAC_MOD_CLK as BDIV_CLKIN */
+- snd_soc_component_update_bits(component, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK,
++ snd_soc_component_update_bits(component, AIC32X4_IFACE3,
++ AIC32X4_BDIVCLK_MASK,
+ AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
+
+ /* NDAC divider value */
+@@ -989,6 +986,15 @@ static int aic32x4_component_probe(struc
+ {
+ struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
+ u32 tmp_reg;
++ int ret;
++
++ struct clk_bulk_data clocks[] = {
++ { .id = "codec_clkin" },
++ };
++
++ ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
++ if (ret)
++ return ret;
+
+ if (gpio_is_valid(aic32x4->rstn_gpio)) {
+ ndelay(10);
+@@ -1000,6 +1006,8 @@ static int aic32x4_component_probe(struc
+ if (aic32x4->setup)
+ aic32x4_setup_gpios(component);
+
++ clk_set_parent(clocks[0].clk, clocks[1].clk);
++
+ /* Power platform configuration */
+ if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
+ snd_soc_component_write(component, AIC32X4_MICBIAS,
+++ /dev/null
-From 6cc882cf38b62fce2a07640413b05b43b420c77a Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Mar 2019 19:38:44 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Properly Set Processing Blocks
-
-commit c95e3a4b96293403a427b5185e60fad28af51fdd upstream.
-
-Different processing blocks are required for different sampling
-rates and power parameters. Set the processing blocks based
-on this information.
-
----
- sound/soc/codecs/tlv320aic32x4.c | 56 ++++++++++++++++++++------------
- 1 file changed, 36 insertions(+), 20 deletions(-)
-
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -59,6 +59,8 @@ struct aic32x4_rate_divs {
- u8 nadc;
- u8 madc;
- u8 blck_N;
-+ u8 r_block;
-+ u8 p_block;
- };
-
- struct aic32x4_priv {
-@@ -307,34 +309,34 @@ static const struct snd_kcontrol_new aic
-
- static const struct aic32x4_rate_divs aic32x4_divs[] = {
- /* 8k rate */
-- {12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
-- {24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
-- {25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
-+ {12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24, 1, 1},
-+ {24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24, 1, 1},
-+ {25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24, 1, 1},
- /* 11.025k rate */
-- {12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
-- {24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
-+ {12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16, 1, 1},
-+ {24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16, 1, 1},
- /* 16k rate */
-- {12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
-- {24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
-- {25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
-+ {12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12, 1, 1},
-+ {24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12, 1, 1},
-+ {25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12, 1, 1},
- /* 22.05k rate */
-- {12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
-- {24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
-- {25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
-+ {12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8, 1, 1},
-+ {24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8, 1, 1},
-+ {25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8, 1, 1},
- /* 32k rate */
-- {12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
-- {24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
-+ {12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6, 1, 1},
-+ {24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6, 1, 1},
- /* 44.1k rate */
-- {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
-- {24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
-- {25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
-+ {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4, 1, 1},
-+ {24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4, 1, 1},
-+ {25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4, 1, 1},
- /* 48k rate */
-- {12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
-- {24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
-- {25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4},
-+ {12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4, 1, 1},
-+ {24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4, 1, 1},
-+ {25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4, 1, 1},
-
- /* 96k rate */
-- {25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1},
-+ {25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1, 1, 9},
- };
-
- static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
-@@ -698,6 +700,18 @@ static int aic32x4_set_dai_fmt(struct sn
- return 0;
- }
-
-+static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
-+ u8 r_block, u8 p_block)
-+{
-+ if (r_block > 18 || p_block > 25)
-+ return -EINVAL;
-+
-+ snd_soc_component_write(component, AIC32X4_ADCSPB, r_block);
-+ snd_soc_component_write(component, AIC32X4_DACSPB, p_block);
-+
-+ return 0;
-+}
-+
- static int aic32x4_setup_clocks(struct snd_soc_component *component,
- unsigned int sample_rate,
- unsigned int parent_rate)
-@@ -710,6 +724,8 @@ static int aic32x4_setup_clocks(struct s
- return i;
- }
-
-+ aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
-+
- /* MCLK as PLL_CLKIN */
- snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK,
- AIC32X4_PLL_CLKIN_MCLK << AIC32X4_PLL_CLKIN_SHIFT);
--- /dev/null
+From 3bf2e5984ab7acb4469ab0f3dfee8b7392001bbf Mon Sep 17 00:00:00 2001
+Date: Thu, 21 Mar 2019 17:58:47 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Model DAC/ADC dividers in CCF
+
+commit a51b50062091619915c5155085bbe13a7aca6903 upstream.
+
+Model and manage DAC/ADC dividers as components in the Core
+Clock Framework. This should allow us to do some more complex
+clock management and power control. Also, some of the
+on-board chip clocks can be exposed to the outside, and this
+change will make those clocks easier to consume by other
+parts of the kernel.
+
+---
+ sound/soc/codecs/tlv320aic32x4-clk.c | 90 ++++++++++++++++++++++++
+ sound/soc/codecs/tlv320aic32x4.c | 101 +++++++++++++++------------
+ sound/soc/codecs/tlv320aic32x4.h | 4 ++
+ 3 files changed, 151 insertions(+), 44 deletions(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4-clk.c
++++ b/sound/soc/codecs/tlv320aic32x4-clk.c
+@@ -289,6 +289,68 @@ static const struct clk_ops aic32x4_code
+ .get_parent = clk_aic32x4_codec_clkin_get_parent,
+ };
+
++static int clk_aic32x4_div_prepare(struct clk_hw *hw)
++{
++ struct clk_aic32x4 *div = to_clk_aic32x4(hw);
++
++ return regmap_update_bits(div->regmap, div->reg,
++ AIC32X4_DIVEN, AIC32X4_DIVEN);
++}
++
++static void clk_aic32x4_div_unprepare(struct clk_hw *hw)
++{
++ struct clk_aic32x4 *div = to_clk_aic32x4(hw);
++
++ regmap_update_bits(div->regmap, div->reg,
++ AIC32X4_DIVEN, 0);
++}
++
++static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct clk_aic32x4 *div = to_clk_aic32x4(hw);
++ u8 divisor;
++
++ divisor = DIV_ROUND_UP(parent_rate, rate);
++ if (divisor > 128)
++ return -EINVAL;
++
++ return regmap_update_bits(div->regmap, div->reg,
++ AIC32X4_DIV_MASK, divisor);
++}
++
++static long clk_aic32x4_div_round_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long *parent_rate)
++{
++ unsigned long divisor;
++
++ divisor = DIV_ROUND_UP(*parent_rate, rate);
++ if (divisor > 128)
++ return -EINVAL;
++
++ return DIV_ROUND_UP(*parent_rate, divisor);
++}
++
++static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct clk_aic32x4 *div = to_clk_aic32x4(hw);
++
++ unsigned int val;
++
++ regmap_read(div->regmap, div->reg, &val);
++
++ return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK);
++}
++
++static const struct clk_ops aic32x4_div_ops = {
++ .prepare = clk_aic32x4_div_prepare,
++ .unprepare = clk_aic32x4_div_unprepare,
++ .set_rate = clk_aic32x4_div_set_rate,
++ .round_rate = clk_aic32x4_div_round_rate,
++ .recalc_rate = clk_aic32x4_div_recalc_rate,
++};
++
+ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
+ {
+ .name = "pll",
+@@ -306,6 +368,34 @@ static struct aic32x4_clkdesc aic32x4_cl
+ .ops = &aic32x4_codec_clkin_ops,
+ .reg = 0,
+ },
++ {
++ .name = "ndac",
++ .parent_names = (const char * []) { "codec_clkin" },
++ .num_parents = 1,
++ .ops = &aic32x4_div_ops,
++ .reg = AIC32X4_NDAC,
++ },
++ {
++ .name = "mdac",
++ .parent_names = (const char * []) { "ndac" },
++ .num_parents = 1,
++ .ops = &aic32x4_div_ops,
++ .reg = AIC32X4_MDAC,
++ },
++ {
++ .name = "nadc",
++ .parent_names = (const char * []) { "codec_clkin" },
++ .num_parents = 1,
++ .ops = &aic32x4_div_ops,
++ .reg = AIC32X4_NADC,
++ },
++ {
++ .name = "madc",
++ .parent_names = (const char * []) { "nadc" },
++ .num_parents = 1,
++ .ops = &aic32x4_div_ops,
++ .reg = AIC32X4_MADC,
++ },
+ };
+
+ static struct clk *aic32x4_register_clk(struct device *dev,
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -52,11 +52,11 @@ struct aic32x4_rate_divs {
+ u32 rate;
+ unsigned long pll_rate;
+ u16 dosr;
+- u8 ndac;
+- u8 mdac;
++ unsigned long ndac_rate;
++ unsigned long mdac_rate;
+ u8 aosr;
+- u8 nadc;
+- u8 madc;
++ unsigned long nadc_rate;
++ unsigned long madc_rate;
+ u8 blck_N;
+ u8 r_block;
+ u8 p_block;
+@@ -309,34 +309,54 @@ static const struct snd_kcontrol_new aic
+
+ static const struct aic32x4_rate_divs aic32x4_divs[] = {
+ /* 8k rate */
+- { 12000000, 8000, 57120000, 768, 5, 3, 128, 5, 18, 24, 1, 1 },
+- { 24000000, 8000, 57120000, 768, 15, 1, 64, 45, 4, 24, 1, 1 },
+- { 25000000, 8000, 32620000, 768, 15, 1, 64, 45, 4, 24, 1, 1 },
++ { 12000000, 8000, 57120000, 768, 18432000, 6144000, 128, 18432000,
++ 1024000, 24, 1, 1 },
++ { 24000000, 8000, 57120000, 768, 6144000, 6144000, 64, 2048000,
++ 512000, 24, 1, 1 },
++ { 25000000, 8000, 32620000, 768, 6144000, 6144000, 64, 2048000,
++ 512000, 24, 1, 1 },
+ /* 11.025k rate */
+- { 12000000, 11025, 44217600, 512, 8, 2, 128, 8, 8, 16, 1, 1 },
+- { 24000000, 11025, 44217600, 512, 16, 1, 64, 32, 4, 16, 1, 1 },
++ { 12000000, 11025, 44217600, 512, 11289600, 5644800, 128, 11289600,
++ 1411200, 16, 1, 1 },
++ { 24000000, 11025, 44217600, 512, 5644800, 5644800, 64, 2822400,
++ 705600, 16, 1, 1 },
+ /* 16k rate */
+- { 12000000, 16000, 57120000, 384, 5, 3, 128, 5, 9, 12, 1, 1 },
+- { 24000000, 16000, 57120000, 384, 15, 1, 64, 18, 5, 12, 1, 1 },
+- { 25000000, 16000, 32620000, 384, 15, 1, 64, 18, 5, 12, 1, 1 },
++ { 12000000, 16000, 57120000, 384, 18432000, 6144000, 128, 18432000,
++ 2048000, 12, 1, 1 },
++ { 24000000, 16000, 57120000, 384, 6144000, 6144000, 64, 5120000,
++ 1024000, 12, 1, 1 },
++ { 25000000, 16000, 32620000, 384, 6144000, 6144000, 64, 5120000,
++ 1024000, 12, 1, 1 },
+ /* 22.05k rate */
+- { 12000000, 22050, 44217600, 256, 4, 4, 128, 4, 8, 8, 1, 1 },
+- { 24000000, 22050, 44217600, 256, 16, 1, 64, 16, 4, 8, 1, 1 },
+- { 25000000, 22050, 19713750, 256, 16, 1, 64, 16, 4, 8, 1, 1 },
++ { 12000000, 22050, 44217600, 256, 22579200, 5644800, 128, 22579200,
++ 2822400, 8, 1, 1 },
++ { 24000000, 22050, 44217600, 256, 5644800, 5644800, 64, 5644800,
++ 1411200, 8, 1, 1 },
++ { 25000000, 22050, 19713750, 256, 5644800, 5644800, 64, 5644800,
++ 1411200, 8, 1, 1 },
+ /* 32k rate */
+- { 12000000, 32000, 14112000, 192, 2, 7, 64, 2, 21, 6, 1, 1 },
+- { 24000000, 32000, 14112000, 192, 7, 2, 64, 7, 6, 6, 1, 1 },
++ { 12000000, 32000, 14112000, 192, 43008000, 6144000, 64, 43008000,
++ 2048000, 6, 1, 1 },
++ { 24000000, 32000, 14112000, 192, 12288000, 6144000, 64, 12288000,
++ 2048000, 6, 1, 1 },
+ /* 44.1k rate */
+- { 12000000, 44100, 44217600, 128, 2, 8, 128, 2, 8, 4, 1, 1 },
+- { 24000000, 44100, 44217600, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
+- { 25000000, 44100, 19713750, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
++ { 12000000, 44100, 44217600, 128, 45158400, 5644800, 128, 45158400,
++ 5644800, 4, 1, 1 },
++ { 24000000, 44100, 44217600, 128, 11289600, 5644800, 64, 11289600,
++ 2822400, 4, 1, 1 },
++ { 25000000, 44100, 19713750, 128, 11289600, 5644800, 64, 11289600,
++ 2822400, 4, 1, 1 },
+ /* 48k rate */
+- { 12000000, 48000, 18432000, 128, 2, 8, 128, 2, 8, 4, 1, 1 },
+- { 24000000, 48000, 18432000, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
+- { 25000000, 48000, 75626250, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
++ { 12000000, 48000, 18432000, 128, 49152000, 6144000, 128, 49152000,
++ 6144000, 4, 1, 1 },
++ { 24000000, 48000, 18432000, 128, 12288000, 6144000, 64, 12288000,
++ 3072000, 4, 1, 1 },
++ { 25000000, 48000, 75626250, 128, 12288000, 6144000, 64, 12288000,
++ 3072000, 4, 1, 1 },
+
+ /* 96k rate */
+- { 25000000, 96000, 75626250, 64, 4, 4, 64, 4, 4, 1, 1, 9 },
++ { 25000000, 96000, 75626250, 64, 24576000, 6144000, 64, 24576000,
++ 6144000, 1, 1, 9 },
+ };
+
+ static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
+@@ -721,6 +741,10 @@ static int aic32x4_setup_clocks(struct s
+
+ struct clk_bulk_data clocks[] = {
+ { .id = "pll" },
++ { .id = "nadc" },
++ { .id = "madc" },
++ { .id = "ndac" },
++ { .id = "mdac" },
+ };
+
+ i = aic32x4_get_divs(parent_rate, sample_rate);
+@@ -733,7 +757,11 @@ static int aic32x4_setup_clocks(struct s
+ if (ret)
+ return ret;
+
+- clk_set_rate(clocks[0].clk, sample_rate);
++ clk_set_rate(clocks[0].clk, aic32x4_divs[i].pll_rate);
++ clk_set_rate(clocks[1].clk, aic32x4_divs[i].nadc_rate);
++ clk_set_rate(clocks[2].clk, aic32x4_divs[i].madc_rate);
++ clk_set_rate(clocks[3].clk, aic32x4_divs[i].ndac_rate);
++ clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate);
+
+ aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
+
+@@ -742,26 +770,10 @@ static int aic32x4_setup_clocks(struct s
+ AIC32X4_BDIVCLK_MASK,
+ AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
+
+- /* NDAC divider value */
+- snd_soc_component_update_bits(component, AIC32X4_NDAC,
+- AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
+-
+- /* MDAC divider value */
+- snd_soc_component_update_bits(component, AIC32X4_MDAC,
+- AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac);
+-
+ /* DOSR MSB & LSB values */
+ snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
+ snd_soc_component_write(component, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
+
+- /* NADC divider value */
+- snd_soc_component_update_bits(component, AIC32X4_NADC,
+- AIC32X4_NADC_MASK, aic32x4_divs[i].nadc);
+-
+- /* MADC divider value */
+- snd_soc_component_update_bits(component, AIC32X4_MADC,
+- AIC32X4_MADC_MASK, aic32x4_divs[i].madc);
+-
+ /* AOSR value */
+ snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
+
+@@ -773,8 +785,8 @@ static int aic32x4_setup_clocks(struct s
+ }
+
+ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
+- struct snd_pcm_hw_params *params,
+- struct snd_soc_dai *dai)
++ struct snd_pcm_hw_params *params,
++ struct snd_soc_dai *dai)
+ {
+ struct snd_soc_component *component = dai->component;
+ struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
+@@ -989,7 +1001,8 @@ static int aic32x4_component_probe(struc
+ int ret;
+
+ struct clk_bulk_data clocks[] = {
+- { .id = "codec_clkin" },
++ { .id = "codec_clkin" },
++ { .id = "pll" },
+ };
+
+ ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
+--- a/sound/soc/codecs/tlv320aic32x4.h
++++ b/sound/soc/codecs/tlv320aic32x4.h
+@@ -206,6 +206,10 @@ int aic32x4_register_clocks(struct devic
+ #define AIC32X4_RMICPGANIN_IN1L_10K 0x10
+ #define AIC32X4_RMICPGANIN_CM1R_10K 0x40
+
++/* Common mask and enable for all of the dividers */
++#define AIC32X4_DIVEN BIT(7)
++#define AIC32X4_DIV_MASK GENMASK(6, 0)
++
+ /* Clock Limits */
+ #define AIC32X4_MAX_PLL_CLKIN 20000000
+
+++ /dev/null
-From 957ccf05060d65da074d019679ec7f486477e412 Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Mar 2019 17:58:45 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Model PLL in CCF
-
-commit 514b044cba667e4b7c383ec79b42b997e624b91d upstream.
-
-Model and manage the on-board PLL as a component in the Core
-Clock Framework. This should allow us to do some more complex
-clock management and power control. Also, some of the
-on-board chip clocks can be exposed to the outside, and this
-change will make those clocks easier to consume by other
-parts of the kernel.
-
----
- sound/soc/codecs/Kconfig | 1 +
- sound/soc/codecs/Makefile | 2 +-
- sound/soc/codecs/tlv320aic32x4-clk.c | 323 +++++++++++++++++++++++++++
- sound/soc/codecs/tlv320aic32x4.c | 195 ++++++++--------
- sound/soc/codecs/tlv320aic32x4.h | 5 +
- 5 files changed, 431 insertions(+), 95 deletions(-)
- create mode 100644 sound/soc/codecs/tlv320aic32x4-clk.c
-
---- a/sound/soc/codecs/Kconfig
-+++ b/sound/soc/codecs/Kconfig
-@@ -1025,6 +1025,7 @@ config SND_SOC_TLV320AIC31XX
-
- config SND_SOC_TLV320AIC32X4
- tristate
-+ depends on COMMON_CLK
-
- config SND_SOC_TLV320AIC32X4_I2C
- tristate "Texas Instruments TLV320AIC32x4 audio CODECs - I2C"
---- a/sound/soc/codecs/Makefile
-+++ b/sound/soc/codecs/Makefile
-@@ -182,7 +182,7 @@ snd-soc-tlv320aic23-i2c-objs := tlv320ai
- snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
- snd-soc-tlv320aic26-objs := tlv320aic26.o
- snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
--snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
-+snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o tlv320aic32x4-clk.o
- snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o
- snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
- snd-soc-tlv320aic3x-objs := tlv320aic3x.o
---- /dev/null
-+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
-@@ -0,0 +1,323 @@
-+/* SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Clock Tree for the Texas Instruments TLV320AIC32x4
-+ *
-+ * Copyright 2019 Annaliese McDermond
-+ *
-+ */
-+
-+#include <linux/clk-provider.h>
-+#include <linux/clkdev.h>
-+#include <linux/regmap.h>
-+#include <linux/device.h>
-+
-+#include "tlv320aic32x4.h"
-+
-+#define to_clk_aic32x4(_hw) container_of(_hw, struct clk_aic32x4, hw)
-+struct clk_aic32x4 {
-+ struct clk_hw hw;
-+ struct device *dev;
-+ struct regmap *regmap;
-+ unsigned int reg;
-+};
-+
-+/*
-+ * struct clk_aic32x4_pll_muldiv - Multiplier/divider settings
-+ * @p: Divider
-+ * @r: first multiplier
-+ * @j: integer part of second multiplier
-+ * @d: decimal part of second multiplier
-+ */
-+struct clk_aic32x4_pll_muldiv {
-+ u8 p;
-+ u16 r;
-+ u8 j;
-+ u16 d;
-+};
-+
-+struct aic32x4_clkdesc {
-+ const char *name;
-+ const char * const *parent_names;
-+ unsigned int num_parents;
-+ const struct clk_ops *ops;
-+ unsigned int reg;
-+};
-+
-+static int clk_aic32x4_pll_prepare(struct clk_hw *hw)
-+{
-+ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
-+
-+ return regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
-+ AIC32X4_PLLEN, AIC32X4_PLLEN);
-+}
-+
-+static void clk_aic32x4_pll_unprepare(struct clk_hw *hw)
-+{
-+ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
-+
-+ regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
-+ AIC32X4_PLLEN, 0);
-+}
-+
-+static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw)
-+{
-+ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
-+
-+ unsigned int val;
-+ int ret;
-+
-+ ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ return !!(val & AIC32X4_PLLEN);
-+}
-+
-+static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll,
-+ struct clk_aic32x4_pll_muldiv *settings)
-+{
-+ /* Change to use regmap_bulk_read? */
-+ unsigned int val;
-+ int ret;
-+
-+ ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
-+ if (ret)
-+ return ret;
-+ settings->r = val & AIC32X4_PLL_R_MASK;
-+ settings->p = (val & AIC32X4_PLL_P_MASK) >> AIC32X4_PLL_P_SHIFT;
-+
-+ ret = regmap_read(pll->regmap, AIC32X4_PLLJ, &val);
-+ if (ret < 0)
-+ return ret;
-+ settings->j = val;
-+
-+ ret = regmap_read(pll->regmap, AIC32X4_PLLDMSB, &val);
-+ if (ret < 0)
-+ return ret;
-+ settings->d = val << 8;
-+
-+ ret = regmap_read(pll->regmap, AIC32X4_PLLDLSB, &val);
-+ if (ret < 0)
-+ return ret;
-+ settings->d |= val;
-+
-+ return 0;
-+}
-+
-+static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll,
-+ struct clk_aic32x4_pll_muldiv *settings)
-+{
-+ int ret;
-+ /* Change to use regmap_bulk_write for some if not all? */
-+
-+ ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
-+ AIC32X4_PLL_R_MASK, settings->r);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
-+ AIC32X4_PLL_P_MASK,
-+ settings->p << AIC32X4_PLL_P_SHIFT);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = regmap_write(pll->regmap, AIC32X4_PLLJ, settings->j);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = regmap_write(pll->regmap, AIC32X4_PLLDMSB, (settings->d >> 8));
-+ if (ret < 0)
-+ return ret;
-+ ret = regmap_write(pll->regmap, AIC32X4_PLLDLSB, (settings->d & 0xff));
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static unsigned long clk_aic32x4_pll_calc_rate(
-+ struct clk_aic32x4_pll_muldiv *settings,
-+ unsigned long parent_rate)
-+{
-+ u64 rate;
-+ /*
-+ * We scale j by 10000 to account for the decimal part of P and divide
-+ * it back out later.
-+ */
-+ rate = (u64) parent_rate * settings->r *
-+ ((settings->j * 10000) + settings->d);
-+
-+ return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000);
-+}
-+
-+static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
-+ unsigned long rate, unsigned long parent_rate)
-+{
-+ u64 multiplier;
-+
-+ settings->p = parent_rate / AIC32X4_MAX_PLL_CLKIN + 1;
-+ if (settings->p > 8)
-+ return -1;
-+
-+ /*
-+ * We scale this figure by 10000 so that we can get the decimal part
-+ * of the multiplier. This is because we can't do floating point
-+ * math in the kernel.
-+ */
-+ multiplier = (u64) rate * settings->p * 10000;
-+ do_div(multiplier, parent_rate);
-+
-+ /*
-+ * J can't be over 64, so R can scale this.
-+ * R can't be greater than 4.
-+ */
-+ settings->r = ((u32) multiplier / 640000) + 1;
-+ if (settings->r > 4)
-+ return -1;
-+ do_div(multiplier, settings->r);
-+
-+ /*
-+ * J can't be < 1.
-+ */
-+ if (multiplier < 10000)
-+ return -1;
-+
-+ /* Figure out the integer part, J, and the fractional part, D. */
-+ settings->j = (u32) multiplier / 10000;
-+ settings->d = (u32) multiplier % 10000;
-+
-+ return 0;
-+}
-+
-+static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw,
-+ unsigned long parent_rate)
-+{
-+ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
-+ struct clk_aic32x4_pll_muldiv settings;
-+ int ret;
-+
-+ ret = clk_aic32x4_pll_get_muldiv(pll, &settings);
-+ if (ret < 0)
-+ return 0;
-+
-+ return clk_aic32x4_pll_calc_rate(&settings, parent_rate);
-+}
-+
-+static long clk_aic32x4_pll_round_rate(struct clk_hw *hw,
-+ unsigned long rate,
-+ unsigned long *parent_rate)
-+{
-+ struct clk_aic32x4_pll_muldiv settings;
-+ int ret;
-+
-+ ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, *parent_rate);
-+ if (ret < 0)
-+ return 0;
-+
-+ return clk_aic32x4_pll_calc_rate(&settings, *parent_rate);
-+}
-+
-+static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
-+ unsigned long rate,
-+ unsigned long parent_rate)
-+{
-+ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
-+ struct clk_aic32x4_pll_muldiv settings;
-+ int ret;
-+
-+ ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, parent_rate);
-+ if (ret < 0)
-+ return -EINVAL;
-+
-+ return clk_aic32x4_pll_set_muldiv(pll, &settings);
-+}
-+
-+static int clk_aic32x4_pll_set_parent(struct clk_hw *hw, u8 index)
-+{
-+ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
-+
-+ return regmap_update_bits(pll->regmap,
-+ AIC32X4_CLKMUX,
-+ AIC32X4_PLL_CLKIN_MASK,
-+ index << AIC32X4_PLL_CLKIN_SHIFT);
-+}
-+
-+static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw)
-+{
-+ struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
-+ unsigned int val;
-+
-+ regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
-+
-+ return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT;
-+}
-+
-+
-+static const struct clk_ops aic32x4_pll_ops = {
-+ .prepare = clk_aic32x4_pll_prepare,
-+ .unprepare = clk_aic32x4_pll_unprepare,
-+ .is_prepared = clk_aic32x4_pll_is_prepared,
-+ .recalc_rate = clk_aic32x4_pll_recalc_rate,
-+ .round_rate = clk_aic32x4_pll_round_rate,
-+ .set_rate = clk_aic32x4_pll_set_rate,
-+ .set_parent = clk_aic32x4_pll_set_parent,
-+ .get_parent = clk_aic32x4_pll_get_parent,
-+};
-+
-+static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
-+ {
-+ .name = "pll",
-+ .parent_names =
-+ (const char* []) { "mclk", "bclk", "gpio", "din" },
-+ .num_parents = 4,
-+ .ops = &aic32x4_pll_ops,
-+ .reg = 0,
-+ },
-+};
-+
-+static struct clk *aic32x4_register_clk(struct device *dev,
-+ struct aic32x4_clkdesc *desc)
-+{
-+ struct clk_init_data init;
-+ struct clk_aic32x4 *priv;
-+ const char *devname = dev_name(dev);
-+
-+ init.ops = desc->ops;
-+ init.name = desc->name;
-+ init.parent_names = desc->parent_names;
-+ init.num_parents = desc->num_parents;
-+ init.flags = 0;
-+
-+ priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL);
-+ if (priv == NULL)
-+ return (struct clk *) -ENOMEM;
-+
-+ priv->dev = dev;
-+ priv->hw.init = &init;
-+ priv->regmap = dev_get_regmap(dev, NULL);
-+ priv->reg = desc->reg;
-+
-+ clk_hw_register_clkdev(&priv->hw, desc->name, devname);
-+ return devm_clk_register(dev, &priv->hw);
-+}
-+
-+int aic32x4_register_clocks(struct device *dev, const char *mclk_name)
-+{
-+ int i;
-+
-+ /*
-+ * These lines are here to preserve the current functionality of
-+ * the driver with regard to the DT. These should eventually be set
-+ * by DT nodes so that the connections can be set up in configuration
-+ * rather than code.
-+ */
-+ aic32x4_clkdesc_array[0].parent_names =
-+ (const char* []) { mclk_name, "bclk", "gpio", "din" };
-+
-+ for (i = 0; i < ARRAY_SIZE(aic32x4_clkdesc_array); ++i)
-+ aic32x4_register_clk(dev, &aic32x4_clkdesc_array[i]);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(aic32x4_register_clocks);
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -14,7 +14,7 @@
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
-@@ -33,6 +33,7 @@
- #include <linux/cdev.h>
- #include <linux/slab.h>
- #include <linux/clk.h>
-+#include <linux/of_clk.h>
- #include <linux/regulator/consumer.h>
-
- #include <sound/tlv320aic32x4.h>
-@@ -49,9 +50,7 @@
- struct aic32x4_rate_divs {
- u32 mclk;
- u32 rate;
-- u8 p_val;
-- u8 pll_j;
-- u16 pll_d;
-+ unsigned long pll_rate;
- u16 dosr;
- u8 ndac;
- u8 mdac;
-@@ -71,6 +70,7 @@ struct aic32x4_priv {
- bool swapdacs;
- int rstn_gpio;
- struct clk *mclk;
-+ const char *mclk_name;
-
- struct regulator *supply_ldo;
- struct regulator *supply_iov;
-@@ -309,34 +309,34 @@ static const struct snd_kcontrol_new aic
-
- static const struct aic32x4_rate_divs aic32x4_divs[] = {
- /* 8k rate */
-- {12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24, 1, 1},
-- {24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24, 1, 1},
-- {25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24, 1, 1},
-+ { 12000000, 8000, 57120000, 768, 5, 3, 128, 5, 18, 24, 1, 1 },
-+ { 24000000, 8000, 57120000, 768, 15, 1, 64, 45, 4, 24, 1, 1 },
-+ { 25000000, 8000, 32620000, 768, 15, 1, 64, 45, 4, 24, 1, 1 },
- /* 11.025k rate */
-- {12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16, 1, 1},
-- {24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16, 1, 1},
-+ { 12000000, 11025, 44217600, 512, 8, 2, 128, 8, 8, 16, 1, 1 },
-+ { 24000000, 11025, 44217600, 512, 16, 1, 64, 32, 4, 16, 1, 1 },
- /* 16k rate */
-- {12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12, 1, 1},
-- {24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12, 1, 1},
-- {25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12, 1, 1},
-+ { 12000000, 16000, 57120000, 384, 5, 3, 128, 5, 9, 12, 1, 1 },
-+ { 24000000, 16000, 57120000, 384, 15, 1, 64, 18, 5, 12, 1, 1 },
-+ { 25000000, 16000, 32620000, 384, 15, 1, 64, 18, 5, 12, 1, 1 },
- /* 22.05k rate */
-- {12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8, 1, 1},
-- {24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8, 1, 1},
-- {25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8, 1, 1},
-+ { 12000000, 22050, 44217600, 256, 4, 4, 128, 4, 8, 8, 1, 1 },
-+ { 24000000, 22050, 44217600, 256, 16, 1, 64, 16, 4, 8, 1, 1 },
-+ { 25000000, 22050, 19713750, 256, 16, 1, 64, 16, 4, 8, 1, 1 },
- /* 32k rate */
-- {12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6, 1, 1},
-- {24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6, 1, 1},
-+ { 12000000, 32000, 14112000, 192, 2, 7, 64, 2, 21, 6, 1, 1 },
-+ { 24000000, 32000, 14112000, 192, 7, 2, 64, 7, 6, 6, 1, 1 },
- /* 44.1k rate */
-- {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4, 1, 1},
-- {24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4, 1, 1},
-- {25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4, 1, 1},
-+ { 12000000, 44100, 44217600, 128, 2, 8, 128, 2, 8, 4, 1, 1 },
-+ { 24000000, 44100, 44217600, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
-+ { 25000000, 44100, 19713750, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
- /* 48k rate */
-- {12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4, 1, 1},
-- {24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4, 1, 1},
-- {25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4, 1, 1},
-+ { 12000000, 48000, 18432000, 128, 2, 8, 128, 2, 8, 4, 1, 1 },
-+ { 24000000, 48000, 18432000, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
-+ { 25000000, 48000, 75626250, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
-
- /* 96k rate */
-- {25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1, 1, 9},
-+ { 25000000, 96000, 75626250, 64, 4, 4, 64, 4, 4, 1, 1, 9 },
- };
-
- static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
-@@ -393,7 +393,7 @@ static const struct snd_kcontrol_new in3
- SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum),
- };
-
--/* Right mixer pins */
-+/* Right mixer pins */
- static SOC_ENUM_SINGLE_DECL(in1r_rpga_p_enum, AIC32X4_RMICPGAPIN, 6, resistor_text);
- static SOC_ENUM_SINGLE_DECL(in2r_rpga_p_enum, AIC32X4_RMICPGAPIN, 4, resistor_text);
- static SOC_ENUM_SINGLE_DECL(in3r_rpga_p_enum, AIC32X4_RMICPGAPIN, 2, resistor_text);
-@@ -597,7 +597,7 @@ static const struct snd_soc_dapm_route a
- static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
- {
- .selector_reg = 0,
-- .selector_mask = 0xff,
-+ .selector_mask = 0xff,
- .window_start = 0,
- .window_len = 128,
- .range_min = 0,
-@@ -618,7 +618,7 @@ static inline int aic32x4_get_divs(int m
-
- for (i = 0; i < ARRAY_SIZE(aic32x4_divs); i++) {
- if ((aic32x4_divs[i].rate == rate)
-- && (aic32x4_divs[i].mclk == mclk)) {
-+ && (aic32x4_divs[i].mclk == mclk)) {
- return i;
- }
- }
-@@ -690,12 +690,12 @@ static int aic32x4_set_dai_fmt(struct sn
- }
-
- snd_soc_component_update_bits(component, AIC32X4_IFACE1,
-- AIC32X4_IFACE1_DATATYPE_MASK |
-- AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
-+ AIC32X4_IFACE1_DATATYPE_MASK |
-+ AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
- snd_soc_component_update_bits(component, AIC32X4_IFACE2,
-- AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
-+ AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
- snd_soc_component_update_bits(component, AIC32X4_IFACE3,
-- AIC32X4_BCLKINV_MASK, iface_reg_3);
-+ AIC32X4_BCLKINV_MASK, iface_reg_3);
-
- return 0;
- }
-@@ -717,6 +717,11 @@ static int aic32x4_setup_clocks(struct s
- unsigned int parent_rate)
- {
- int i;
-+ int ret;
-+
-+ struct clk_bulk_data clocks[] = {
-+ { .id = "pll" },
-+ };
-
- i = aic32x4_get_divs(parent_rate, sample_rate);
- if (i < 0) {
-@@ -724,39 +729,29 @@ static int aic32x4_setup_clocks(struct s
- return i;
- }
-
-+ ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
-+ if (ret)
-+ return ret;
-+
-+ clk_set_rate(clocks[0].clk, sample_rate);
-+
- aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
-
-- /* MCLK as PLL_CLKIN */
-- snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK,
-- AIC32X4_PLL_CLKIN_MCLK << AIC32X4_PLL_CLKIN_SHIFT);
- /* PLL as CODEC_CLKIN */
-- snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_MASK,
-- AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
-+ snd_soc_component_update_bits(component, AIC32X4_CLKMUX,
-+ AIC32X4_CODEC_CLKIN_MASK,
-+ AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
- /* DAC_MOD_CLK as BDIV_CLKIN */
- snd_soc_component_update_bits(component, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK,
-- AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
--
-- /* We will fix R value to 1 and will make P & J=K.D as variable */
-- snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_R_MASK, 0x01);
--
-- /* PLL P value */
-- snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_P_MASK,
-- aic32x4_divs[i].p_val << AIC32X4_PLL_P_SHIFT);
--
-- /* PLL J value */
-- snd_soc_component_write(component, AIC32X4_PLLJ, aic32x4_divs[i].pll_j);
--
-- /* PLL D value */
-- snd_soc_component_write(component, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8));
-- snd_soc_component_write(component, AIC32X4_PLLDLSB, (aic32x4_divs[i].pll_d & 0xff));
-+ AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
-
- /* NDAC divider value */
- snd_soc_component_update_bits(component, AIC32X4_NDAC,
-- AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
-+ AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
-
- /* MDAC divider value */
- snd_soc_component_update_bits(component, AIC32X4_MDAC,
-- AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac);
-+ AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac);
-
- /* DOSR MSB & LSB values */
- snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
-@@ -764,18 +759,18 @@ static int aic32x4_setup_clocks(struct s
-
- /* NADC divider value */
- snd_soc_component_update_bits(component, AIC32X4_NADC,
-- AIC32X4_NADC_MASK, aic32x4_divs[i].nadc);
-+ AIC32X4_NADC_MASK, aic32x4_divs[i].nadc);
-
- /* MADC divider value */
- snd_soc_component_update_bits(component, AIC32X4_MADC,
-- AIC32X4_MADC_MASK, aic32x4_divs[i].madc);
-+ AIC32X4_MADC_MASK, aic32x4_divs[i].madc);
-
- /* AOSR value */
- snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
-
- /* BCLK N divider */
- snd_soc_component_update_bits(component, AIC32X4_BCLKN,
-- AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
-+ AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
-
- return 0;
- }
-@@ -794,23 +789,23 @@ static int aic32x4_hw_params(struct snd_
- switch (params_width(params)) {
- case 16:
- iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
-- AIC32X4_IFACE1_DATALEN_SHIFT);
-+ AIC32X4_IFACE1_DATALEN_SHIFT);
- break;
- case 20:
- iface1_reg |= (AIC32X4_WORD_LEN_20BITS <<
-- AIC32X4_IFACE1_DATALEN_SHIFT);
-+ AIC32X4_IFACE1_DATALEN_SHIFT);
- break;
- case 24:
- iface1_reg |= (AIC32X4_WORD_LEN_24BITS <<
-- AIC32X4_IFACE1_DATALEN_SHIFT);
-+ AIC32X4_IFACE1_DATALEN_SHIFT);
- break;
- case 32:
- iface1_reg |= (AIC32X4_WORD_LEN_32BITS <<
-- AIC32X4_IFACE1_DATALEN_SHIFT);
-+ AIC32X4_IFACE1_DATALEN_SHIFT);
- break;
- }
- snd_soc_component_update_bits(component, AIC32X4_IFACE1,
-- AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
-+ AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
-
- if (params_channels(params) == 1) {
- dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
-@@ -821,7 +816,7 @@ static int aic32x4_hw_params(struct snd_
- dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
- }
- snd_soc_component_update_bits(component, AIC32X4_DACSETUP,
-- AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
-+ AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
-
- return 0;
- }
-@@ -831,7 +826,7 @@ static int aic32x4_mute(struct snd_soc_d
- struct snd_soc_component *component = dai->component;
-
- snd_soc_component_update_bits(component, AIC32X4_DACMUTE,
-- AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
-+ AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
-
- return 0;
- }
-@@ -853,27 +848,27 @@ static int aic32x4_set_bias_level(struct
-
- /* Switch on PLL */
- snd_soc_component_update_bits(component, AIC32X4_PLLPR,
-- AIC32X4_PLLEN, AIC32X4_PLLEN);
-+ AIC32X4_PLLEN, AIC32X4_PLLEN);
-
- /* Switch on NDAC Divider */
- snd_soc_component_update_bits(component, AIC32X4_NDAC,
-- AIC32X4_NDACEN, AIC32X4_NDACEN);
-+ AIC32X4_NDACEN, AIC32X4_NDACEN);
-
- /* Switch on MDAC Divider */
- snd_soc_component_update_bits(component, AIC32X4_MDAC,
-- AIC32X4_MDACEN, AIC32X4_MDACEN);
-+ AIC32X4_MDACEN, AIC32X4_MDACEN);
-
- /* Switch on NADC Divider */
- snd_soc_component_update_bits(component, AIC32X4_NADC,
-- AIC32X4_NADCEN, AIC32X4_NADCEN);
-+ AIC32X4_NADCEN, AIC32X4_NADCEN);
-
- /* Switch on MADC Divider */
- snd_soc_component_update_bits(component, AIC32X4_MADC,
-- AIC32X4_MADCEN, AIC32X4_MADCEN);
-+ AIC32X4_MADCEN, AIC32X4_MADCEN);
-
- /* Switch on BCLK_N Divider */
- snd_soc_component_update_bits(component, AIC32X4_BCLKN,
-- AIC32X4_BCLKEN, AIC32X4_BCLKEN);
-+ AIC32X4_BCLKEN, AIC32X4_BCLKEN);
- break;
- case SND_SOC_BIAS_PREPARE:
- break;
-@@ -884,27 +879,27 @@ static int aic32x4_set_bias_level(struct
-
- /* Switch off BCLK_N Divider */
- snd_soc_component_update_bits(component, AIC32X4_BCLKN,
-- AIC32X4_BCLKEN, 0);
-+ AIC32X4_BCLKEN, 0);
-
- /* Switch off MADC Divider */
- snd_soc_component_update_bits(component, AIC32X4_MADC,
-- AIC32X4_MADCEN, 0);
-+ AIC32X4_MADCEN, 0);
-
- /* Switch off NADC Divider */
- snd_soc_component_update_bits(component, AIC32X4_NADC,
-- AIC32X4_NADCEN, 0);
-+ AIC32X4_NADCEN, 0);
-
- /* Switch off MDAC Divider */
- snd_soc_component_update_bits(component, AIC32X4_MDAC,
-- AIC32X4_MDACEN, 0);
-+ AIC32X4_MDACEN, 0);
-
- /* Switch off NDAC Divider */
- snd_soc_component_update_bits(component, AIC32X4_NDAC,
-- AIC32X4_NDACEN, 0);
-+ AIC32X4_NDACEN, 0);
-
- /* Switch off PLL */
- snd_soc_component_update_bits(component, AIC32X4_PLLPR,
-- AIC32X4_PLLEN, 0);
-+ AIC32X4_PLLEN, 0);
-
- /* Switch off master clock */
- clk_disable_unprepare(aic32x4->mclk);
-@@ -916,7 +911,7 @@ static int aic32x4_set_bias_level(struct
- }
-
- #define AIC32X4_RATES SNDRV_PCM_RATE_8000_96000
--#define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
-+#define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
- | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
-
- static const struct snd_soc_dai_ops aic32x4_ops = {
-@@ -929,17 +924,17 @@ static const struct snd_soc_dai_ops aic3
- static struct snd_soc_dai_driver aic32x4_dai = {
- .name = "tlv320aic32x4-hifi",
- .playback = {
-- .stream_name = "Playback",
-- .channels_min = 1,
-- .channels_max = 2,
-- .rates = AIC32X4_RATES,
-- .formats = AIC32X4_FORMATS,},
-+ .stream_name = "Playback",
-+ .channels_min = 1,
-+ .channels_max = 2,
-+ .rates = AIC32X4_RATES,
-+ .formats = AIC32X4_FORMATS,},
- .capture = {
-- .stream_name = "Capture",
-- .channels_min = 1,
-- .channels_max = 2,
-- .rates = AIC32X4_RATES,
-- .formats = AIC32X4_FORMATS,},
-+ .stream_name = "Capture",
-+ .channels_min = 1,
-+ .channels_max = 2,
-+ .rates = AIC32X4_RATES,
-+ .formats = AIC32X4_FORMATS,},
- .ops = &aic32x4_ops,
- .symmetric_rates = 1,
- };
-@@ -952,7 +947,7 @@ static void aic32x4_setup_gpios(struct s
- /* MFP1 */
- if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_DINCTL,
-- aic32x4->setup->gpio_func[0]);
-+ aic32x4->setup->gpio_func[0]);
- snd_soc_add_component_controls(component, aic32x4_mfp1,
- ARRAY_SIZE(aic32x4_mfp1));
- }
-@@ -960,7 +955,7 @@ static void aic32x4_setup_gpios(struct s
- /* MFP2 */
- if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_DOUTCTL,
-- aic32x4->setup->gpio_func[1]);
-+ aic32x4->setup->gpio_func[1]);
- snd_soc_add_component_controls(component, aic32x4_mfp2,
- ARRAY_SIZE(aic32x4_mfp2));
- }
-@@ -968,7 +963,7 @@ static void aic32x4_setup_gpios(struct s
- /* MFP3 */
- if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_SCLKCTL,
-- aic32x4->setup->gpio_func[2]);
-+ aic32x4->setup->gpio_func[2]);
- snd_soc_add_component_controls(component, aic32x4_mfp3,
- ARRAY_SIZE(aic32x4_mfp3));
- }
-@@ -976,7 +971,7 @@ static void aic32x4_setup_gpios(struct s
- /* MFP4 */
- if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_MISOCTL,
-- aic32x4->setup->gpio_func[3]);
-+ aic32x4->setup->gpio_func[3]);
- snd_soc_add_component_controls(component, aic32x4_mfp4,
- ARRAY_SIZE(aic32x4_mfp4));
- }
-@@ -984,7 +979,7 @@ static void aic32x4_setup_gpios(struct s
- /* MFP5 */
- if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_GPIOCTL,
-- aic32x4->setup->gpio_func[4]);
-+ aic32x4->setup->gpio_func[4]);
- snd_soc_add_component_controls(component, aic32x4_mfp5,
- ARRAY_SIZE(aic32x4_mfp5));
- }
-@@ -1007,8 +1002,8 @@ static int aic32x4_component_probe(struc
-
- /* Power platform configuration */
- if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
-- snd_soc_component_write(component, AIC32X4_MICBIAS, AIC32X4_MICBIAS_LDOIN |
-- AIC32X4_MICBIAS_2075V);
-+ snd_soc_component_write(component, AIC32X4_MICBIAS,
-+ AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V);
- }
- if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
- snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
-@@ -1071,12 +1066,18 @@ static int aic32x4_parse_dt(struct aic32
- struct device_node *np)
- {
- struct aic32x4_setup_data *aic32x4_setup;
-+ int ret;
-
- aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
- GFP_KERNEL);
- if (!aic32x4_setup)
- return -ENOMEM;
-
-+ ret = of_property_match_string(np, "clock-names", "mclk");
-+ if (ret < 0)
-+ return -EINVAL;
-+ aic32x4->mclk_name = of_clk_get_parent_name(np, ret);
-+
- aic32x4->swapdacs = false;
- aic32x4->micpga_routing = 0;
- aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
-@@ -1198,7 +1199,7 @@ int aic32x4_probe(struct device *dev, st
- return PTR_ERR(regmap);
-
- aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv),
-- GFP_KERNEL);
-+ GFP_KERNEL);
- if (aic32x4 == NULL)
- return -ENOMEM;
-
-@@ -1210,6 +1211,7 @@ int aic32x4_probe(struct device *dev, st
- aic32x4->swapdacs = pdata->swapdacs;
- aic32x4->micpga_routing = pdata->micpga_routing;
- aic32x4->rstn_gpio = pdata->rstn_gpio;
-+ aic32x4->mclk_name = "mclk";
- } else if (np) {
- ret = aic32x4_parse_dt(aic32x4, np);
- if (ret) {
-@@ -1221,6 +1223,7 @@ int aic32x4_probe(struct device *dev, st
- aic32x4->swapdacs = false;
- aic32x4->micpga_routing = 0;
- aic32x4->rstn_gpio = -1;
-+ aic32x4->mclk_name = "mclk";
- }
-
- aic32x4->mclk = devm_clk_get(dev, "mclk");
-@@ -1229,6 +1232,10 @@ int aic32x4_probe(struct device *dev, st
- return PTR_ERR(aic32x4->mclk);
- }
-
-+ ret = aic32x4_register_clocks(dev, aic32x4->mclk_name);
-+ if (ret)
-+ return ret;
-+
- if (gpio_is_valid(aic32x4->rstn_gpio)) {
- ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio,
- GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
---- a/sound/soc/codecs/tlv320aic32x4.h
-+++ b/sound/soc/codecs/tlv320aic32x4.h
-@@ -16,6 +16,7 @@ struct regmap_config;
- extern const struct regmap_config aic32x4_regmap_config;
- int aic32x4_probe(struct device *dev, struct regmap *regmap);
- int aic32x4_remove(struct device *dev);
-+int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
-
- /* tlv320aic32x4 register space (in decimal to match datasheet) */
-
-@@ -205,4 +206,8 @@ int aic32x4_remove(struct device *dev);
- #define AIC32X4_RMICPGANIN_IN1L_10K 0x10
- #define AIC32X4_RMICPGANIN_CM1R_10K 0x40
-
-+/* Clock Limits */
-+#define AIC32X4_MAX_PLL_CLKIN 20000000
-+
-+
- #endif /* _TLV320AIC32X4_H */
--- /dev/null
+From 69f3f8c51077d0f3dc7f46c2c9a94da899d8eb7c Mon Sep 17 00:00:00 2001
+Date: Thu, 21 Mar 2019 17:58:48 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Model BDIV divider in CCF
+
+commit 9b484124ebd906c4d6bc826cc0d417e80cc1105c upstream.
+
+Model and manage BDIV divider as components in the Core
+Clock Framework. This should allow us to do some more complex
+clock management and power control. Also, some of the
+on-board chip clocks can be exposed to the outside, and this
+change will make those clocks easier to consume by other
+parts of the kernel.
+
+---
+ sound/soc/codecs/tlv320aic32x4-clk.c | 36 ++++++++++++++++++
+ sound/soc/codecs/tlv320aic32x4.c | 56 +++++++++++++---------------
+ 2 files changed, 62 insertions(+), 30 deletions(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4-clk.c
++++ b/sound/soc/codecs/tlv320aic32x4-clk.c
+@@ -351,6 +351,34 @@ static const struct clk_ops aic32x4_div_
+ .recalc_rate = clk_aic32x4_div_recalc_rate,
+ };
+
++static int clk_aic32x4_bdiv_set_parent(struct clk_hw *hw, u8 index)
++{
++ struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
++
++ return regmap_update_bits(mux->regmap, AIC32X4_IFACE3,
++ AIC32X4_BDIVCLK_MASK, index);
++}
++
++static u8 clk_aic32x4_bdiv_get_parent(struct clk_hw *hw)
++{
++ struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
++ unsigned int val;
++
++ regmap_read(mux->regmap, AIC32X4_IFACE3, &val);
++
++ return val & AIC32X4_BDIVCLK_MASK;
++}
++
++static const struct clk_ops aic32x4_bdiv_ops = {
++ .prepare = clk_aic32x4_div_prepare,
++ .unprepare = clk_aic32x4_div_unprepare,
++ .set_parent = clk_aic32x4_bdiv_set_parent,
++ .get_parent = clk_aic32x4_bdiv_get_parent,
++ .set_rate = clk_aic32x4_div_set_rate,
++ .round_rate = clk_aic32x4_div_round_rate,
++ .recalc_rate = clk_aic32x4_div_recalc_rate,
++};
++
+ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
+ {
+ .name = "pll",
+@@ -396,6 +424,14 @@ static struct aic32x4_clkdesc aic32x4_cl
+ .ops = &aic32x4_div_ops,
+ .reg = AIC32X4_MADC,
+ },
++ {
++ .name = "bdiv",
++ .parent_names =
++ (const char *[]) { "ndac", "mdac", "nadc", "madc" },
++ .num_parents = 4,
++ .ops = &aic32x4_bdiv_ops,
++ .reg = AIC32X4_BCLKN,
++ },
+ };
+
+ static struct clk *aic32x4_register_clk(struct device *dev,
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -57,7 +57,7 @@ struct aic32x4_rate_divs {
+ u8 aosr;
+ unsigned long nadc_rate;
+ unsigned long madc_rate;
+- u8 blck_N;
++ unsigned long bdiv_rate;
+ u8 r_block;
+ u8 p_block;
+ };
+@@ -310,53 +310,53 @@ static const struct snd_kcontrol_new aic
+ static const struct aic32x4_rate_divs aic32x4_divs[] = {
+ /* 8k rate */
+ { 12000000, 8000, 57120000, 768, 18432000, 6144000, 128, 18432000,
+- 1024000, 24, 1, 1 },
++ 1024000, 256000, 1, 1 },
+ { 24000000, 8000, 57120000, 768, 6144000, 6144000, 64, 2048000,
+- 512000, 24, 1, 1 },
++ 512000, 256000, 1, 1 },
+ { 25000000, 8000, 32620000, 768, 6144000, 6144000, 64, 2048000,
+- 512000, 24, 1, 1 },
++ 512000, 256000, 1, 1 },
+ /* 11.025k rate */
+ { 12000000, 11025, 44217600, 512, 11289600, 5644800, 128, 11289600,
+- 1411200, 16, 1, 1 },
++ 1411200, 352800, 1, 1 },
+ { 24000000, 11025, 44217600, 512, 5644800, 5644800, 64, 2822400,
+- 705600, 16, 1, 1 },
++ 705600, 352800, 1, 1 },
+ /* 16k rate */
+ { 12000000, 16000, 57120000, 384, 18432000, 6144000, 128, 18432000,
+- 2048000, 12, 1, 1 },
++ 2048000, 512000, 1, 1 },
+ { 24000000, 16000, 57120000, 384, 6144000, 6144000, 64, 5120000,
+- 1024000, 12, 1, 1 },
++ 1024000, 512000, 1, 1 },
+ { 25000000, 16000, 32620000, 384, 6144000, 6144000, 64, 5120000,
+- 1024000, 12, 1, 1 },
++ 1024000, 512000, 1, 1 },
+ /* 22.05k rate */
+ { 12000000, 22050, 44217600, 256, 22579200, 5644800, 128, 22579200,
+- 2822400, 8, 1, 1 },
++ 2822400, 705600, 1, 1 },
+ { 24000000, 22050, 44217600, 256, 5644800, 5644800, 64, 5644800,
+- 1411200, 8, 1, 1 },
++ 1411200, 705600, 1, 1 },
+ { 25000000, 22050, 19713750, 256, 5644800, 5644800, 64, 5644800,
+- 1411200, 8, 1, 1 },
++ 1411200, 705600, 1, 1 },
+ /* 32k rate */
+ { 12000000, 32000, 14112000, 192, 43008000, 6144000, 64, 43008000,
+- 2048000, 6, 1, 1 },
++ 2048000, 1024000, 1, 1 },
+ { 24000000, 32000, 14112000, 192, 12288000, 6144000, 64, 12288000,
+- 2048000, 6, 1, 1 },
++ 2048000, 1024000, 1, 1 },
+ /* 44.1k rate */
+ { 12000000, 44100, 44217600, 128, 45158400, 5644800, 128, 45158400,
+- 5644800, 4, 1, 1 },
++ 5644800, 1411200, 1, 1 },
+ { 24000000, 44100, 44217600, 128, 11289600, 5644800, 64, 11289600,
+- 2822400, 4, 1, 1 },
++ 2822400, 1411200, 1, 1 },
+ { 25000000, 44100, 19713750, 128, 11289600, 5644800, 64, 11289600,
+- 2822400, 4, 1, 1 },
++ 2822400, 1411200, 1, 1 },
+ /* 48k rate */
+ { 12000000, 48000, 18432000, 128, 49152000, 6144000, 128, 49152000,
+- 6144000, 4, 1, 1 },
++ 6144000, 1536000, 1, 1 },
+ { 24000000, 48000, 18432000, 128, 12288000, 6144000, 64, 12288000,
+- 3072000, 4, 1, 1 },
++ 3072000, 1536000, 1, 1 },
+ { 25000000, 48000, 75626250, 128, 12288000, 6144000, 64, 12288000,
+- 3072000, 4, 1, 1 },
++ 3072000, 1536000, 1, 1 },
+
+ /* 96k rate */
+ { 25000000, 96000, 75626250, 64, 24576000, 6144000, 64, 24576000,
+- 6144000, 1, 1, 9 },
++ 6144000, 3072000, 1, 9 },
+ };
+
+ static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
+@@ -745,6 +745,7 @@ static int aic32x4_setup_clocks(struct s
+ { .id = "madc" },
+ { .id = "ndac" },
+ { .id = "mdac" },
++ { .id = "bdiv" },
+ };
+
+ i = aic32x4_get_divs(parent_rate, sample_rate);
+@@ -762,14 +763,10 @@ static int aic32x4_setup_clocks(struct s
+ clk_set_rate(clocks[2].clk, aic32x4_divs[i].madc_rate);
+ clk_set_rate(clocks[3].clk, aic32x4_divs[i].ndac_rate);
+ clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate);
++ clk_set_rate(clocks[5].clk, aic32x4_divs[i].bdiv_rate);
+
+ aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
+
+- /* DAC_MOD_CLK as BDIV_CLKIN */
+- snd_soc_component_update_bits(component, AIC32X4_IFACE3,
+- AIC32X4_BDIVCLK_MASK,
+- AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
+-
+ /* DOSR MSB & LSB values */
+ snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
+ snd_soc_component_write(component, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
+@@ -777,10 +774,6 @@ static int aic32x4_setup_clocks(struct s
+ /* AOSR value */
+ snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
+
+- /* BCLK N divider */
+- snd_soc_component_update_bits(component, AIC32X4_BCLKN,
+- AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
+-
+ return 0;
+ }
+
+@@ -1003,6 +996,8 @@ static int aic32x4_component_probe(struc
+ struct clk_bulk_data clocks[] = {
+ { .id = "codec_clkin" },
+ { .id = "pll" },
++ { .id = "bdiv" },
++ { .id = "mdac" },
+ };
+
+ ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
+@@ -1020,6 +1015,7 @@ static int aic32x4_component_probe(struc
+ aic32x4_setup_gpios(component);
+
+ clk_set_parent(clocks[0].clk, clocks[1].clk);
++ clk_set_parent(clocks[2].clk, clocks[3].clk);
+
+ /* Power platform configuration */
+ if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
+++ /dev/null
-From c5f9d78ec34de15732bcbff52bedba7a840e42b2 Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Mar 2019 17:58:46 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Model CODEC_CLKIN in CCF
-
-commit fd2df3aeafa4b4cc468d58e147e0822967034b71 upstream.
-
-Model and manage codec clock input as a component in the Core
-Clock Framework. This should allow us to do some more complex
-clock management and power control. Also, some of the
-on-board chip clocks can be exposed to the outside, and this
-change will make those clocks easier to consume by other
-parts of the kernel.
-
----
- sound/soc/codecs/tlv320aic32x4-clk.c | 34 ++++++++++++++++++++++++++++
- sound/soc/codecs/tlv320aic32x4.c | 18 +++++++++++----
- 2 files changed, 47 insertions(+), 5 deletions(-)
-
---- a/sound/soc/codecs/tlv320aic32x4-clk.c
-+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
-@@ -265,6 +265,30 @@ static const struct clk_ops aic32x4_pll_
- .get_parent = clk_aic32x4_pll_get_parent,
- };
-
-+static int clk_aic32x4_codec_clkin_set_parent(struct clk_hw *hw, u8 index)
-+{
-+ struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
-+
-+ return regmap_update_bits(mux->regmap,
-+ AIC32X4_CLKMUX,
-+ AIC32X4_CODEC_CLKIN_MASK, index << AIC32X4_CODEC_CLKIN_SHIFT);
-+}
-+
-+static u8 clk_aic32x4_codec_clkin_get_parent(struct clk_hw *hw)
-+{
-+ struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
-+ unsigned int val;
-+
-+ regmap_read(mux->regmap, AIC32X4_CLKMUX, &val);
-+
-+ return (val & AIC32X4_CODEC_CLKIN_MASK) >> AIC32X4_CODEC_CLKIN_SHIFT;
-+}
-+
-+static const struct clk_ops aic32x4_codec_clkin_ops = {
-+ .set_parent = clk_aic32x4_codec_clkin_set_parent,
-+ .get_parent = clk_aic32x4_codec_clkin_get_parent,
-+};
-+
- static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
- {
- .name = "pll",
-@@ -274,6 +298,14 @@ static struct aic32x4_clkdesc aic32x4_cl
- .ops = &aic32x4_pll_ops,
- .reg = 0,
- },
-+ {
-+ .name = "codec_clkin",
-+ .parent_names =
-+ (const char *[]) { "mclk", "bclk", "gpio", "pll" },
-+ .num_parents = 4,
-+ .ops = &aic32x4_codec_clkin_ops,
-+ .reg = 0,
-+ },
- };
-
- static struct clk *aic32x4_register_clk(struct device *dev,
-@@ -314,6 +346,8 @@ int aic32x4_register_clocks(struct devic
- */
- aic32x4_clkdesc_array[0].parent_names =
- (const char* []) { mclk_name, "bclk", "gpio", "din" };
-+ aic32x4_clkdesc_array[1].parent_names =
-+ (const char *[]) { mclk_name, "bclk", "gpio", "pll" };
-
- for (i = 0; i < ARRAY_SIZE(aic32x4_clkdesc_array); ++i)
- aic32x4_register_clk(dev, &aic32x4_clkdesc_array[i]);
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -737,12 +737,9 @@ static int aic32x4_setup_clocks(struct s
-
- aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
-
-- /* PLL as CODEC_CLKIN */
-- snd_soc_component_update_bits(component, AIC32X4_CLKMUX,
-- AIC32X4_CODEC_CLKIN_MASK,
-- AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
- /* DAC_MOD_CLK as BDIV_CLKIN */
-- snd_soc_component_update_bits(component, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK,
-+ snd_soc_component_update_bits(component, AIC32X4_IFACE3,
-+ AIC32X4_BDIVCLK_MASK,
- AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
-
- /* NDAC divider value */
-@@ -989,6 +986,15 @@ static int aic32x4_component_probe(struc
- {
- struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
- u32 tmp_reg;
-+ int ret;
-+
-+ struct clk_bulk_data clocks[] = {
-+ { .id = "codec_clkin" },
-+ };
-+
-+ ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
-+ if (ret)
-+ return ret;
-
- if (gpio_is_valid(aic32x4->rstn_gpio)) {
- ndelay(10);
-@@ -1000,6 +1006,8 @@ static int aic32x4_component_probe(struc
- if (aic32x4->setup)
- aic32x4_setup_gpios(component);
-
-+ clk_set_parent(clocks[0].clk, clocks[1].clk);
-+
- /* Power platform configuration */
- if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
- snd_soc_component_write(component, AIC32X4_MICBIAS,
--- /dev/null
+From f844ea32cba0c4030594a0f590725477a5751f32 Mon Sep 17 00:00:00 2001
+Date: Thu, 21 Mar 2019 17:58:49 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Control clock gating with CCF
+
+commit d25970b5fd51e9fcf0afbe190908ea4049454da4 upstream.
+
+Control the clock gating to the various clock components to use
+the CCF. This allows us to prepare_enalbe only 3 clocks and the
+relationships assigned to them will cause upstream clockss to
+enable automatically. Additionally we can do this in a single
+call to the CCF.
+
+---
+ sound/soc/codecs/tlv320aic32x4.c | 67 +++++++-------------------------
+ 1 file changed, 13 insertions(+), 54 deletions(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -836,41 +836,25 @@ static int aic32x4_mute(struct snd_soc_d
+ static int aic32x4_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+ {
+- struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
+ int ret;
+
++ struct clk_bulk_data clocks[] = {
++ { .id = "madc" },
++ { .id = "mdac" },
++ { .id = "bdiv" },
++ };
++
++ ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
++ if (ret)
++ return ret;
++
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+- /* Switch on master clock */
+- ret = clk_prepare_enable(aic32x4->mclk);
++ ret = clk_bulk_prepare_enable(ARRAY_SIZE(clocks), clocks);
+ if (ret) {
+- dev_err(component->dev, "Failed to enable master clock\n");
++ dev_err(component->dev, "Failed to enable clocks\n");
+ return ret;
+ }
+-
+- /* Switch on PLL */
+- snd_soc_component_update_bits(component, AIC32X4_PLLPR,
+- AIC32X4_PLLEN, AIC32X4_PLLEN);
+-
+- /* Switch on NDAC Divider */
+- snd_soc_component_update_bits(component, AIC32X4_NDAC,
+- AIC32X4_NDACEN, AIC32X4_NDACEN);
+-
+- /* Switch on MDAC Divider */
+- snd_soc_component_update_bits(component, AIC32X4_MDAC,
+- AIC32X4_MDACEN, AIC32X4_MDACEN);
+-
+- /* Switch on NADC Divider */
+- snd_soc_component_update_bits(component, AIC32X4_NADC,
+- AIC32X4_NADCEN, AIC32X4_NADCEN);
+-
+- /* Switch on MADC Divider */
+- snd_soc_component_update_bits(component, AIC32X4_MADC,
+- AIC32X4_MADCEN, AIC32X4_MADCEN);
+-
+- /* Switch on BCLK_N Divider */
+- snd_soc_component_update_bits(component, AIC32X4_BCLKN,
+- AIC32X4_BCLKEN, AIC32X4_BCLKEN);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+@@ -879,32 +863,7 @@ static int aic32x4_set_bias_level(struct
+ if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ break;
+
+- /* Switch off BCLK_N Divider */
+- snd_soc_component_update_bits(component, AIC32X4_BCLKN,
+- AIC32X4_BCLKEN, 0);
+-
+- /* Switch off MADC Divider */
+- snd_soc_component_update_bits(component, AIC32X4_MADC,
+- AIC32X4_MADCEN, 0);
+-
+- /* Switch off NADC Divider */
+- snd_soc_component_update_bits(component, AIC32X4_NADC,
+- AIC32X4_NADCEN, 0);
+-
+- /* Switch off MDAC Divider */
+- snd_soc_component_update_bits(component, AIC32X4_MDAC,
+- AIC32X4_MDACEN, 0);
+-
+- /* Switch off NDAC Divider */
+- snd_soc_component_update_bits(component, AIC32X4_NDAC,
+- AIC32X4_NDACEN, 0);
+-
+- /* Switch off PLL */
+- snd_soc_component_update_bits(component, AIC32X4_PLLPR,
+- AIC32X4_PLLEN, 0);
+-
+- /* Switch off master clock */
+- clk_disable_unprepare(aic32x4->mclk);
++ clk_bulk_disable_unprepare(ARRAY_SIZE(clocks), clocks);
+ break;
+ case SND_SOC_BIAS_OFF:
+ break;
+++ /dev/null
-From 3bf2e5984ab7acb4469ab0f3dfee8b7392001bbf Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Mar 2019 17:58:47 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Model DAC/ADC dividers in CCF
-
-commit a51b50062091619915c5155085bbe13a7aca6903 upstream.
-
-Model and manage DAC/ADC dividers as components in the Core
-Clock Framework. This should allow us to do some more complex
-clock management and power control. Also, some of the
-on-board chip clocks can be exposed to the outside, and this
-change will make those clocks easier to consume by other
-parts of the kernel.
-
----
- sound/soc/codecs/tlv320aic32x4-clk.c | 90 ++++++++++++++++++++++++
- sound/soc/codecs/tlv320aic32x4.c | 101 +++++++++++++++------------
- sound/soc/codecs/tlv320aic32x4.h | 4 ++
- 3 files changed, 151 insertions(+), 44 deletions(-)
-
---- a/sound/soc/codecs/tlv320aic32x4-clk.c
-+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
-@@ -289,6 +289,68 @@ static const struct clk_ops aic32x4_code
- .get_parent = clk_aic32x4_codec_clkin_get_parent,
- };
-
-+static int clk_aic32x4_div_prepare(struct clk_hw *hw)
-+{
-+ struct clk_aic32x4 *div = to_clk_aic32x4(hw);
-+
-+ return regmap_update_bits(div->regmap, div->reg,
-+ AIC32X4_DIVEN, AIC32X4_DIVEN);
-+}
-+
-+static void clk_aic32x4_div_unprepare(struct clk_hw *hw)
-+{
-+ struct clk_aic32x4 *div = to_clk_aic32x4(hw);
-+
-+ regmap_update_bits(div->regmap, div->reg,
-+ AIC32X4_DIVEN, 0);
-+}
-+
-+static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long parent_rate)
-+{
-+ struct clk_aic32x4 *div = to_clk_aic32x4(hw);
-+ u8 divisor;
-+
-+ divisor = DIV_ROUND_UP(parent_rate, rate);
-+ if (divisor > 128)
-+ return -EINVAL;
-+
-+ return regmap_update_bits(div->regmap, div->reg,
-+ AIC32X4_DIV_MASK, divisor);
-+}
-+
-+static long clk_aic32x4_div_round_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long *parent_rate)
-+{
-+ unsigned long divisor;
-+
-+ divisor = DIV_ROUND_UP(*parent_rate, rate);
-+ if (divisor > 128)
-+ return -EINVAL;
-+
-+ return DIV_ROUND_UP(*parent_rate, divisor);
-+}
-+
-+static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
-+ unsigned long parent_rate)
-+{
-+ struct clk_aic32x4 *div = to_clk_aic32x4(hw);
-+
-+ unsigned int val;
-+
-+ regmap_read(div->regmap, div->reg, &val);
-+
-+ return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK);
-+}
-+
-+static const struct clk_ops aic32x4_div_ops = {
-+ .prepare = clk_aic32x4_div_prepare,
-+ .unprepare = clk_aic32x4_div_unprepare,
-+ .set_rate = clk_aic32x4_div_set_rate,
-+ .round_rate = clk_aic32x4_div_round_rate,
-+ .recalc_rate = clk_aic32x4_div_recalc_rate,
-+};
-+
- static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
- {
- .name = "pll",
-@@ -306,6 +368,34 @@ static struct aic32x4_clkdesc aic32x4_cl
- .ops = &aic32x4_codec_clkin_ops,
- .reg = 0,
- },
-+ {
-+ .name = "ndac",
-+ .parent_names = (const char * []) { "codec_clkin" },
-+ .num_parents = 1,
-+ .ops = &aic32x4_div_ops,
-+ .reg = AIC32X4_NDAC,
-+ },
-+ {
-+ .name = "mdac",
-+ .parent_names = (const char * []) { "ndac" },
-+ .num_parents = 1,
-+ .ops = &aic32x4_div_ops,
-+ .reg = AIC32X4_MDAC,
-+ },
-+ {
-+ .name = "nadc",
-+ .parent_names = (const char * []) { "codec_clkin" },
-+ .num_parents = 1,
-+ .ops = &aic32x4_div_ops,
-+ .reg = AIC32X4_NADC,
-+ },
-+ {
-+ .name = "madc",
-+ .parent_names = (const char * []) { "nadc" },
-+ .num_parents = 1,
-+ .ops = &aic32x4_div_ops,
-+ .reg = AIC32X4_MADC,
-+ },
- };
-
- static struct clk *aic32x4_register_clk(struct device *dev,
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -52,11 +52,11 @@ struct aic32x4_rate_divs {
- u32 rate;
- unsigned long pll_rate;
- u16 dosr;
-- u8 ndac;
-- u8 mdac;
-+ unsigned long ndac_rate;
-+ unsigned long mdac_rate;
- u8 aosr;
-- u8 nadc;
-- u8 madc;
-+ unsigned long nadc_rate;
-+ unsigned long madc_rate;
- u8 blck_N;
- u8 r_block;
- u8 p_block;
-@@ -309,34 +309,54 @@ static const struct snd_kcontrol_new aic
-
- static const struct aic32x4_rate_divs aic32x4_divs[] = {
- /* 8k rate */
-- { 12000000, 8000, 57120000, 768, 5, 3, 128, 5, 18, 24, 1, 1 },
-- { 24000000, 8000, 57120000, 768, 15, 1, 64, 45, 4, 24, 1, 1 },
-- { 25000000, 8000, 32620000, 768, 15, 1, 64, 45, 4, 24, 1, 1 },
-+ { 12000000, 8000, 57120000, 768, 18432000, 6144000, 128, 18432000,
-+ 1024000, 24, 1, 1 },
-+ { 24000000, 8000, 57120000, 768, 6144000, 6144000, 64, 2048000,
-+ 512000, 24, 1, 1 },
-+ { 25000000, 8000, 32620000, 768, 6144000, 6144000, 64, 2048000,
-+ 512000, 24, 1, 1 },
- /* 11.025k rate */
-- { 12000000, 11025, 44217600, 512, 8, 2, 128, 8, 8, 16, 1, 1 },
-- { 24000000, 11025, 44217600, 512, 16, 1, 64, 32, 4, 16, 1, 1 },
-+ { 12000000, 11025, 44217600, 512, 11289600, 5644800, 128, 11289600,
-+ 1411200, 16, 1, 1 },
-+ { 24000000, 11025, 44217600, 512, 5644800, 5644800, 64, 2822400,
-+ 705600, 16, 1, 1 },
- /* 16k rate */
-- { 12000000, 16000, 57120000, 384, 5, 3, 128, 5, 9, 12, 1, 1 },
-- { 24000000, 16000, 57120000, 384, 15, 1, 64, 18, 5, 12, 1, 1 },
-- { 25000000, 16000, 32620000, 384, 15, 1, 64, 18, 5, 12, 1, 1 },
-+ { 12000000, 16000, 57120000, 384, 18432000, 6144000, 128, 18432000,
-+ 2048000, 12, 1, 1 },
-+ { 24000000, 16000, 57120000, 384, 6144000, 6144000, 64, 5120000,
-+ 1024000, 12, 1, 1 },
-+ { 25000000, 16000, 32620000, 384, 6144000, 6144000, 64, 5120000,
-+ 1024000, 12, 1, 1 },
- /* 22.05k rate */
-- { 12000000, 22050, 44217600, 256, 4, 4, 128, 4, 8, 8, 1, 1 },
-- { 24000000, 22050, 44217600, 256, 16, 1, 64, 16, 4, 8, 1, 1 },
-- { 25000000, 22050, 19713750, 256, 16, 1, 64, 16, 4, 8, 1, 1 },
-+ { 12000000, 22050, 44217600, 256, 22579200, 5644800, 128, 22579200,
-+ 2822400, 8, 1, 1 },
-+ { 24000000, 22050, 44217600, 256, 5644800, 5644800, 64, 5644800,
-+ 1411200, 8, 1, 1 },
-+ { 25000000, 22050, 19713750, 256, 5644800, 5644800, 64, 5644800,
-+ 1411200, 8, 1, 1 },
- /* 32k rate */
-- { 12000000, 32000, 14112000, 192, 2, 7, 64, 2, 21, 6, 1, 1 },
-- { 24000000, 32000, 14112000, 192, 7, 2, 64, 7, 6, 6, 1, 1 },
-+ { 12000000, 32000, 14112000, 192, 43008000, 6144000, 64, 43008000,
-+ 2048000, 6, 1, 1 },
-+ { 24000000, 32000, 14112000, 192, 12288000, 6144000, 64, 12288000,
-+ 2048000, 6, 1, 1 },
- /* 44.1k rate */
-- { 12000000, 44100, 44217600, 128, 2, 8, 128, 2, 8, 4, 1, 1 },
-- { 24000000, 44100, 44217600, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
-- { 25000000, 44100, 19713750, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
-+ { 12000000, 44100, 44217600, 128, 45158400, 5644800, 128, 45158400,
-+ 5644800, 4, 1, 1 },
-+ { 24000000, 44100, 44217600, 128, 11289600, 5644800, 64, 11289600,
-+ 2822400, 4, 1, 1 },
-+ { 25000000, 44100, 19713750, 128, 11289600, 5644800, 64, 11289600,
-+ 2822400, 4, 1, 1 },
- /* 48k rate */
-- { 12000000, 48000, 18432000, 128, 2, 8, 128, 2, 8, 4, 1, 1 },
-- { 24000000, 48000, 18432000, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
-- { 25000000, 48000, 75626250, 128, 8, 2, 64, 8, 4, 4, 1, 1 },
-+ { 12000000, 48000, 18432000, 128, 49152000, 6144000, 128, 49152000,
-+ 6144000, 4, 1, 1 },
-+ { 24000000, 48000, 18432000, 128, 12288000, 6144000, 64, 12288000,
-+ 3072000, 4, 1, 1 },
-+ { 25000000, 48000, 75626250, 128, 12288000, 6144000, 64, 12288000,
-+ 3072000, 4, 1, 1 },
-
- /* 96k rate */
-- { 25000000, 96000, 75626250, 64, 4, 4, 64, 4, 4, 1, 1, 9 },
-+ { 25000000, 96000, 75626250, 64, 24576000, 6144000, 64, 24576000,
-+ 6144000, 1, 1, 9 },
- };
-
- static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
-@@ -721,6 +741,10 @@ static int aic32x4_setup_clocks(struct s
-
- struct clk_bulk_data clocks[] = {
- { .id = "pll" },
-+ { .id = "nadc" },
-+ { .id = "madc" },
-+ { .id = "ndac" },
-+ { .id = "mdac" },
- };
-
- i = aic32x4_get_divs(parent_rate, sample_rate);
-@@ -733,7 +757,11 @@ static int aic32x4_setup_clocks(struct s
- if (ret)
- return ret;
-
-- clk_set_rate(clocks[0].clk, sample_rate);
-+ clk_set_rate(clocks[0].clk, aic32x4_divs[i].pll_rate);
-+ clk_set_rate(clocks[1].clk, aic32x4_divs[i].nadc_rate);
-+ clk_set_rate(clocks[2].clk, aic32x4_divs[i].madc_rate);
-+ clk_set_rate(clocks[3].clk, aic32x4_divs[i].ndac_rate);
-+ clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate);
-
- aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
-
-@@ -742,26 +770,10 @@ static int aic32x4_setup_clocks(struct s
- AIC32X4_BDIVCLK_MASK,
- AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
-
-- /* NDAC divider value */
-- snd_soc_component_update_bits(component, AIC32X4_NDAC,
-- AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
--
-- /* MDAC divider value */
-- snd_soc_component_update_bits(component, AIC32X4_MDAC,
-- AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac);
--
- /* DOSR MSB & LSB values */
- snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
- snd_soc_component_write(component, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
-
-- /* NADC divider value */
-- snd_soc_component_update_bits(component, AIC32X4_NADC,
-- AIC32X4_NADC_MASK, aic32x4_divs[i].nadc);
--
-- /* MADC divider value */
-- snd_soc_component_update_bits(component, AIC32X4_MADC,
-- AIC32X4_MADC_MASK, aic32x4_divs[i].madc);
--
- /* AOSR value */
- snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
-
-@@ -773,8 +785,8 @@ static int aic32x4_setup_clocks(struct s
- }
-
- static int aic32x4_hw_params(struct snd_pcm_substream *substream,
-- struct snd_pcm_hw_params *params,
-- struct snd_soc_dai *dai)
-+ struct snd_pcm_hw_params *params,
-+ struct snd_soc_dai *dai)
- {
- struct snd_soc_component *component = dai->component;
- struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
-@@ -989,7 +1001,8 @@ static int aic32x4_component_probe(struc
- int ret;
-
- struct clk_bulk_data clocks[] = {
-- { .id = "codec_clkin" },
-+ { .id = "codec_clkin" },
-+ { .id = "pll" },
- };
-
- ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
---- a/sound/soc/codecs/tlv320aic32x4.h
-+++ b/sound/soc/codecs/tlv320aic32x4.h
-@@ -206,6 +206,10 @@ int aic32x4_register_clocks(struct devic
- #define AIC32X4_RMICPGANIN_IN1L_10K 0x10
- #define AIC32X4_RMICPGANIN_CM1R_10K 0x40
-
-+/* Common mask and enable for all of the dividers */
-+#define AIC32X4_DIVEN BIT(7)
-+#define AIC32X4_DIV_MASK GENMASK(6, 0)
-+
- /* Clock Limits */
- #define AIC32X4_MAX_PLL_CLKIN 20000000
-
+++ /dev/null
-From 69f3f8c51077d0f3dc7f46c2c9a94da899d8eb7c Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Mar 2019 17:58:48 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Model BDIV divider in CCF
-
-commit 9b484124ebd906c4d6bc826cc0d417e80cc1105c upstream.
-
-Model and manage BDIV divider as components in the Core
-Clock Framework. This should allow us to do some more complex
-clock management and power control. Also, some of the
-on-board chip clocks can be exposed to the outside, and this
-change will make those clocks easier to consume by other
-parts of the kernel.
-
----
- sound/soc/codecs/tlv320aic32x4-clk.c | 36 ++++++++++++++++++
- sound/soc/codecs/tlv320aic32x4.c | 56 +++++++++++++---------------
- 2 files changed, 62 insertions(+), 30 deletions(-)
-
---- a/sound/soc/codecs/tlv320aic32x4-clk.c
-+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
-@@ -351,6 +351,34 @@ static const struct clk_ops aic32x4_div_
- .recalc_rate = clk_aic32x4_div_recalc_rate,
- };
-
-+static int clk_aic32x4_bdiv_set_parent(struct clk_hw *hw, u8 index)
-+{
-+ struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
-+
-+ return regmap_update_bits(mux->regmap, AIC32X4_IFACE3,
-+ AIC32X4_BDIVCLK_MASK, index);
-+}
-+
-+static u8 clk_aic32x4_bdiv_get_parent(struct clk_hw *hw)
-+{
-+ struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
-+ unsigned int val;
-+
-+ regmap_read(mux->regmap, AIC32X4_IFACE3, &val);
-+
-+ return val & AIC32X4_BDIVCLK_MASK;
-+}
-+
-+static const struct clk_ops aic32x4_bdiv_ops = {
-+ .prepare = clk_aic32x4_div_prepare,
-+ .unprepare = clk_aic32x4_div_unprepare,
-+ .set_parent = clk_aic32x4_bdiv_set_parent,
-+ .get_parent = clk_aic32x4_bdiv_get_parent,
-+ .set_rate = clk_aic32x4_div_set_rate,
-+ .round_rate = clk_aic32x4_div_round_rate,
-+ .recalc_rate = clk_aic32x4_div_recalc_rate,
-+};
-+
- static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
- {
- .name = "pll",
-@@ -396,6 +424,14 @@ static struct aic32x4_clkdesc aic32x4_cl
- .ops = &aic32x4_div_ops,
- .reg = AIC32X4_MADC,
- },
-+ {
-+ .name = "bdiv",
-+ .parent_names =
-+ (const char *[]) { "ndac", "mdac", "nadc", "madc" },
-+ .num_parents = 4,
-+ .ops = &aic32x4_bdiv_ops,
-+ .reg = AIC32X4_BCLKN,
-+ },
- };
-
- static struct clk *aic32x4_register_clk(struct device *dev,
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -57,7 +57,7 @@ struct aic32x4_rate_divs {
- u8 aosr;
- unsigned long nadc_rate;
- unsigned long madc_rate;
-- u8 blck_N;
-+ unsigned long bdiv_rate;
- u8 r_block;
- u8 p_block;
- };
-@@ -310,53 +310,53 @@ static const struct snd_kcontrol_new aic
- static const struct aic32x4_rate_divs aic32x4_divs[] = {
- /* 8k rate */
- { 12000000, 8000, 57120000, 768, 18432000, 6144000, 128, 18432000,
-- 1024000, 24, 1, 1 },
-+ 1024000, 256000, 1, 1 },
- { 24000000, 8000, 57120000, 768, 6144000, 6144000, 64, 2048000,
-- 512000, 24, 1, 1 },
-+ 512000, 256000, 1, 1 },
- { 25000000, 8000, 32620000, 768, 6144000, 6144000, 64, 2048000,
-- 512000, 24, 1, 1 },
-+ 512000, 256000, 1, 1 },
- /* 11.025k rate */
- { 12000000, 11025, 44217600, 512, 11289600, 5644800, 128, 11289600,
-- 1411200, 16, 1, 1 },
-+ 1411200, 352800, 1, 1 },
- { 24000000, 11025, 44217600, 512, 5644800, 5644800, 64, 2822400,
-- 705600, 16, 1, 1 },
-+ 705600, 352800, 1, 1 },
- /* 16k rate */
- { 12000000, 16000, 57120000, 384, 18432000, 6144000, 128, 18432000,
-- 2048000, 12, 1, 1 },
-+ 2048000, 512000, 1, 1 },
- { 24000000, 16000, 57120000, 384, 6144000, 6144000, 64, 5120000,
-- 1024000, 12, 1, 1 },
-+ 1024000, 512000, 1, 1 },
- { 25000000, 16000, 32620000, 384, 6144000, 6144000, 64, 5120000,
-- 1024000, 12, 1, 1 },
-+ 1024000, 512000, 1, 1 },
- /* 22.05k rate */
- { 12000000, 22050, 44217600, 256, 22579200, 5644800, 128, 22579200,
-- 2822400, 8, 1, 1 },
-+ 2822400, 705600, 1, 1 },
- { 24000000, 22050, 44217600, 256, 5644800, 5644800, 64, 5644800,
-- 1411200, 8, 1, 1 },
-+ 1411200, 705600, 1, 1 },
- { 25000000, 22050, 19713750, 256, 5644800, 5644800, 64, 5644800,
-- 1411200, 8, 1, 1 },
-+ 1411200, 705600, 1, 1 },
- /* 32k rate */
- { 12000000, 32000, 14112000, 192, 43008000, 6144000, 64, 43008000,
-- 2048000, 6, 1, 1 },
-+ 2048000, 1024000, 1, 1 },
- { 24000000, 32000, 14112000, 192, 12288000, 6144000, 64, 12288000,
-- 2048000, 6, 1, 1 },
-+ 2048000, 1024000, 1, 1 },
- /* 44.1k rate */
- { 12000000, 44100, 44217600, 128, 45158400, 5644800, 128, 45158400,
-- 5644800, 4, 1, 1 },
-+ 5644800, 1411200, 1, 1 },
- { 24000000, 44100, 44217600, 128, 11289600, 5644800, 64, 11289600,
-- 2822400, 4, 1, 1 },
-+ 2822400, 1411200, 1, 1 },
- { 25000000, 44100, 19713750, 128, 11289600, 5644800, 64, 11289600,
-- 2822400, 4, 1, 1 },
-+ 2822400, 1411200, 1, 1 },
- /* 48k rate */
- { 12000000, 48000, 18432000, 128, 49152000, 6144000, 128, 49152000,
-- 6144000, 4, 1, 1 },
-+ 6144000, 1536000, 1, 1 },
- { 24000000, 48000, 18432000, 128, 12288000, 6144000, 64, 12288000,
-- 3072000, 4, 1, 1 },
-+ 3072000, 1536000, 1, 1 },
- { 25000000, 48000, 75626250, 128, 12288000, 6144000, 64, 12288000,
-- 3072000, 4, 1, 1 },
-+ 3072000, 1536000, 1, 1 },
-
- /* 96k rate */
- { 25000000, 96000, 75626250, 64, 24576000, 6144000, 64, 24576000,
-- 6144000, 1, 1, 9 },
-+ 6144000, 3072000, 1, 9 },
- };
-
- static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
-@@ -745,6 +745,7 @@ static int aic32x4_setup_clocks(struct s
- { .id = "madc" },
- { .id = "ndac" },
- { .id = "mdac" },
-+ { .id = "bdiv" },
- };
-
- i = aic32x4_get_divs(parent_rate, sample_rate);
-@@ -762,14 +763,10 @@ static int aic32x4_setup_clocks(struct s
- clk_set_rate(clocks[2].clk, aic32x4_divs[i].madc_rate);
- clk_set_rate(clocks[3].clk, aic32x4_divs[i].ndac_rate);
- clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate);
-+ clk_set_rate(clocks[5].clk, aic32x4_divs[i].bdiv_rate);
-
- aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
-
-- /* DAC_MOD_CLK as BDIV_CLKIN */
-- snd_soc_component_update_bits(component, AIC32X4_IFACE3,
-- AIC32X4_BDIVCLK_MASK,
-- AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
--
- /* DOSR MSB & LSB values */
- snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
- snd_soc_component_write(component, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
-@@ -777,10 +774,6 @@ static int aic32x4_setup_clocks(struct s
- /* AOSR value */
- snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
-
-- /* BCLK N divider */
-- snd_soc_component_update_bits(component, AIC32X4_BCLKN,
-- AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
--
- return 0;
- }
-
-@@ -1003,6 +996,8 @@ static int aic32x4_component_probe(struc
- struct clk_bulk_data clocks[] = {
- { .id = "codec_clkin" },
- { .id = "pll" },
-+ { .id = "bdiv" },
-+ { .id = "mdac" },
- };
-
- ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
-@@ -1020,6 +1015,7 @@ static int aic32x4_component_probe(struc
- aic32x4_setup_gpios(component);
-
- clk_set_parent(clocks[0].clk, clocks[1].clk);
-+ clk_set_parent(clocks[2].clk, clocks[3].clk);
-
- /* Power platform configuration */
- if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
--- /dev/null
+From a2d8d212b986e4a4ae52c748d246e4c28ebaf1bc Mon Sep 17 00:00:00 2001
+Date: Thu, 21 Mar 2019 17:58:50 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Move aosr and dosr setting to
+ separate functions
+
+commit fbafbf6517274a797e6e6508c18dd8dba5920c89 upstream.
+
+Move these to separate helper functions. This looks cleaner and fits
+better with the new clock setting in CCF.
+
+---
+ sound/soc/codecs/tlv320aic32x4.c | 24 +++++++++++++++++-------
+ 1 file changed, 17 insertions(+), 7 deletions(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -720,6 +720,20 @@ static int aic32x4_set_dai_fmt(struct sn
+ return 0;
+ }
+
++static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr)
++{
++ return snd_soc_component_write(component, AIC32X4_AOSR, aosr);
++}
++
++static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr)
++{
++ snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8);
++ snd_soc_component_write(component, AIC32X4_DOSRLSB,
++ (dosr & 0xff));
++
++ return 0;
++}
++
+ static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
+ u8 r_block, u8 p_block)
+ {
+@@ -765,14 +779,10 @@ static int aic32x4_setup_clocks(struct s
+ clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate);
+ clk_set_rate(clocks[5].clk, aic32x4_divs[i].bdiv_rate);
+
+- aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
++ aic32x4_set_aosr(component, aic32x4_divs[i].aosr);
++ aic32x4_set_dosr(component, aic32x4_divs[i].dosr);
+
+- /* DOSR MSB & LSB values */
+- snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
+- snd_soc_component_write(component, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
+-
+- /* AOSR value */
+- snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
++ aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
+
+ return 0;
+ }
+++ /dev/null
-From f844ea32cba0c4030594a0f590725477a5751f32 Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Mar 2019 17:58:49 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Control clock gating with CCF
-
-commit d25970b5fd51e9fcf0afbe190908ea4049454da4 upstream.
-
-Control the clock gating to the various clock components to use
-the CCF. This allows us to prepare_enalbe only 3 clocks and the
-relationships assigned to them will cause upstream clockss to
-enable automatically. Additionally we can do this in a single
-call to the CCF.
-
----
- sound/soc/codecs/tlv320aic32x4.c | 67 +++++++-------------------------
- 1 file changed, 13 insertions(+), 54 deletions(-)
-
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -836,41 +836,25 @@ static int aic32x4_mute(struct snd_soc_d
- static int aic32x4_set_bias_level(struct snd_soc_component *component,
- enum snd_soc_bias_level level)
- {
-- struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
- int ret;
-
-+ struct clk_bulk_data clocks[] = {
-+ { .id = "madc" },
-+ { .id = "mdac" },
-+ { .id = "bdiv" },
-+ };
-+
-+ ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
-+ if (ret)
-+ return ret;
-+
- switch (level) {
- case SND_SOC_BIAS_ON:
-- /* Switch on master clock */
-- ret = clk_prepare_enable(aic32x4->mclk);
-+ ret = clk_bulk_prepare_enable(ARRAY_SIZE(clocks), clocks);
- if (ret) {
-- dev_err(component->dev, "Failed to enable master clock\n");
-+ dev_err(component->dev, "Failed to enable clocks\n");
- return ret;
- }
--
-- /* Switch on PLL */
-- snd_soc_component_update_bits(component, AIC32X4_PLLPR,
-- AIC32X4_PLLEN, AIC32X4_PLLEN);
--
-- /* Switch on NDAC Divider */
-- snd_soc_component_update_bits(component, AIC32X4_NDAC,
-- AIC32X4_NDACEN, AIC32X4_NDACEN);
--
-- /* Switch on MDAC Divider */
-- snd_soc_component_update_bits(component, AIC32X4_MDAC,
-- AIC32X4_MDACEN, AIC32X4_MDACEN);
--
-- /* Switch on NADC Divider */
-- snd_soc_component_update_bits(component, AIC32X4_NADC,
-- AIC32X4_NADCEN, AIC32X4_NADCEN);
--
-- /* Switch on MADC Divider */
-- snd_soc_component_update_bits(component, AIC32X4_MADC,
-- AIC32X4_MADCEN, AIC32X4_MADCEN);
--
-- /* Switch on BCLK_N Divider */
-- snd_soc_component_update_bits(component, AIC32X4_BCLKN,
-- AIC32X4_BCLKEN, AIC32X4_BCLKEN);
- break;
- case SND_SOC_BIAS_PREPARE:
- break;
-@@ -879,32 +863,7 @@ static int aic32x4_set_bias_level(struct
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
- break;
-
-- /* Switch off BCLK_N Divider */
-- snd_soc_component_update_bits(component, AIC32X4_BCLKN,
-- AIC32X4_BCLKEN, 0);
--
-- /* Switch off MADC Divider */
-- snd_soc_component_update_bits(component, AIC32X4_MADC,
-- AIC32X4_MADCEN, 0);
--
-- /* Switch off NADC Divider */
-- snd_soc_component_update_bits(component, AIC32X4_NADC,
-- AIC32X4_NADCEN, 0);
--
-- /* Switch off MDAC Divider */
-- snd_soc_component_update_bits(component, AIC32X4_MDAC,
-- AIC32X4_MDACEN, 0);
--
-- /* Switch off NDAC Divider */
-- snd_soc_component_update_bits(component, AIC32X4_NDAC,
-- AIC32X4_NDACEN, 0);
--
-- /* Switch off PLL */
-- snd_soc_component_update_bits(component, AIC32X4_PLLPR,
-- AIC32X4_PLLEN, 0);
--
-- /* Switch off master clock */
-- clk_disable_unprepare(aic32x4->mclk);
-+ clk_bulk_disable_unprepare(ARRAY_SIZE(clocks), clocks);
- break;
- case SND_SOC_BIAS_OFF:
- break;
--- /dev/null
+From 3e62c56daa1c799bb2a1d954ecfb88e8d37421bb Mon Sep 17 00:00:00 2001
+Date: Thu, 21 Mar 2019 17:58:51 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Dynamically Determine Clocking
+
+commit 96c3bb00239de4fb5f4ddca42c1f90d6d9b3c697 upstream.
+
+The existing code uses a static lookup table to determine the
+settings of the various clock devices on board the chip. This is
+limiting in a couple of ways. First, this doesn't allow for any
+master clock rates other than the three that have been
+precalculated. Additionally, new sample rates are difficult to
+add to the table. Witness that the chip is capable of 192000 Hz
+sampling, but it is not provided by this driver. Last, if the
+driver is clocked by something that isn't a crystal, the
+upstream clock may not be able to achieve exactly the rate
+requested in the driver. This will mean that clocking will be
+slightly off for the sampling clock or that it won't work at all.
+
+This patch determines the settings for all of the clocks at
+runtime considering the real conditions of the clocks in the
+system. The rules for the clocks are in TI's SLAA557 application
+guide on pages 37, 51 and 77.
+
+---
+ sound/soc/codecs/tlv320aic32x4.c | 190 ++++++++++++++-----------------
+ sound/soc/codecs/tlv320aic32x4.h | 4 +-
+ 2 files changed, 90 insertions(+), 104 deletions(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -47,21 +47,6 @@
+
+ #include "tlv320aic32x4.h"
+
+-struct aic32x4_rate_divs {
+- u32 mclk;
+- u32 rate;
+- unsigned long pll_rate;
+- u16 dosr;
+- unsigned long ndac_rate;
+- unsigned long mdac_rate;
+- u8 aosr;
+- unsigned long nadc_rate;
+- unsigned long madc_rate;
+- unsigned long bdiv_rate;
+- u8 r_block;
+- u8 p_block;
+-};
+-
+ struct aic32x4_priv {
+ struct regmap *regmap;
+ u32 sysclk;
+@@ -307,58 +292,6 @@ static const struct snd_kcontrol_new aic
+ 0, 0x0F, 0),
+ };
+
+-static const struct aic32x4_rate_divs aic32x4_divs[] = {
+- /* 8k rate */
+- { 12000000, 8000, 57120000, 768, 18432000, 6144000, 128, 18432000,
+- 1024000, 256000, 1, 1 },
+- { 24000000, 8000, 57120000, 768, 6144000, 6144000, 64, 2048000,
+- 512000, 256000, 1, 1 },
+- { 25000000, 8000, 32620000, 768, 6144000, 6144000, 64, 2048000,
+- 512000, 256000, 1, 1 },
+- /* 11.025k rate */
+- { 12000000, 11025, 44217600, 512, 11289600, 5644800, 128, 11289600,
+- 1411200, 352800, 1, 1 },
+- { 24000000, 11025, 44217600, 512, 5644800, 5644800, 64, 2822400,
+- 705600, 352800, 1, 1 },
+- /* 16k rate */
+- { 12000000, 16000, 57120000, 384, 18432000, 6144000, 128, 18432000,
+- 2048000, 512000, 1, 1 },
+- { 24000000, 16000, 57120000, 384, 6144000, 6144000, 64, 5120000,
+- 1024000, 512000, 1, 1 },
+- { 25000000, 16000, 32620000, 384, 6144000, 6144000, 64, 5120000,
+- 1024000, 512000, 1, 1 },
+- /* 22.05k rate */
+- { 12000000, 22050, 44217600, 256, 22579200, 5644800, 128, 22579200,
+- 2822400, 705600, 1, 1 },
+- { 24000000, 22050, 44217600, 256, 5644800, 5644800, 64, 5644800,
+- 1411200, 705600, 1, 1 },
+- { 25000000, 22050, 19713750, 256, 5644800, 5644800, 64, 5644800,
+- 1411200, 705600, 1, 1 },
+- /* 32k rate */
+- { 12000000, 32000, 14112000, 192, 43008000, 6144000, 64, 43008000,
+- 2048000, 1024000, 1, 1 },
+- { 24000000, 32000, 14112000, 192, 12288000, 6144000, 64, 12288000,
+- 2048000, 1024000, 1, 1 },
+- /* 44.1k rate */
+- { 12000000, 44100, 44217600, 128, 45158400, 5644800, 128, 45158400,
+- 5644800, 1411200, 1, 1 },
+- { 24000000, 44100, 44217600, 128, 11289600, 5644800, 64, 11289600,
+- 2822400, 1411200, 1, 1 },
+- { 25000000, 44100, 19713750, 128, 11289600, 5644800, 64, 11289600,
+- 2822400, 1411200, 1, 1 },
+- /* 48k rate */
+- { 12000000, 48000, 18432000, 128, 49152000, 6144000, 128, 49152000,
+- 6144000, 1536000, 1, 1 },
+- { 24000000, 48000, 18432000, 128, 12288000, 6144000, 64, 12288000,
+- 3072000, 1536000, 1, 1 },
+- { 25000000, 48000, 75626250, 128, 12288000, 6144000, 64, 12288000,
+- 3072000, 1536000, 1, 1 },
+-
+- /* 96k rate */
+- { 25000000, 96000, 75626250, 64, 24576000, 6144000, 64, 24576000,
+- 6144000, 3072000, 1, 9 },
+-};
+-
+ static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
+ SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
+ SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0),
+@@ -632,20 +565,6 @@ const struct regmap_config aic32x4_regma
+ };
+ EXPORT_SYMBOL(aic32x4_regmap_config);
+
+-static inline int aic32x4_get_divs(int mclk, int rate)
+-{
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(aic32x4_divs); i++) {
+- if ((aic32x4_divs[i].rate == rate)
+- && (aic32x4_divs[i].mclk == mclk)) {
+- return i;
+- }
+- }
+- printk(KERN_ERR "aic32x4: master clock and sample rate is not supported\n");
+- return -EINVAL;
+-}
+-
+ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+ {
+@@ -747,11 +666,17 @@ static int aic32x4_set_processing_blocks
+ }
+
+ static int aic32x4_setup_clocks(struct snd_soc_component *component,
+- unsigned int sample_rate,
+- unsigned int parent_rate)
++ unsigned int sample_rate)
+ {
+- int i;
++ u8 aosr;
++ u16 dosr;
++ u8 adc_resource_class, dac_resource_class;
++ u8 madc, nadc, mdac, ndac, max_nadc, min_mdac, max_ndac;
++ u8 dosr_increment;
++ u16 max_dosr, min_dosr;
++ unsigned long mclk_rate, adc_clock_rate, dac_clock_rate;
+ int ret;
++ struct clk *mclk;
+
+ struct clk_bulk_data clocks[] = {
+ { .id = "pll" },
+@@ -761,30 +686,89 @@ static int aic32x4_setup_clocks(struct s
+ { .id = "mdac" },
+ { .id = "bdiv" },
+ };
+-
+- i = aic32x4_get_divs(parent_rate, sample_rate);
+- if (i < 0) {
+- printk(KERN_ERR "aic32x4: sampling rate not supported\n");
+- return i;
+- }
+-
+ ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
+ if (ret)
+ return ret;
+
+- clk_set_rate(clocks[0].clk, aic32x4_divs[i].pll_rate);
+- clk_set_rate(clocks[1].clk, aic32x4_divs[i].nadc_rate);
+- clk_set_rate(clocks[2].clk, aic32x4_divs[i].madc_rate);
+- clk_set_rate(clocks[3].clk, aic32x4_divs[i].ndac_rate);
+- clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate);
+- clk_set_rate(clocks[5].clk, aic32x4_divs[i].bdiv_rate);
++ mclk = clk_get_parent(clocks[1].clk);
++ mclk_rate = clk_get_rate(mclk);
+
+- aic32x4_set_aosr(component, aic32x4_divs[i].aosr);
+- aic32x4_set_dosr(component, aic32x4_divs[i].dosr);
++ if (sample_rate <= 48000) {
++ aosr = 128;
++ adc_resource_class = 6;
++ dac_resource_class = 8;
++ dosr_increment = 8;
++ aic32x4_set_processing_blocks(component, 1, 1);
++ } else if (sample_rate <= 96000) {
++ aosr = 64;
++ adc_resource_class = 6;
++ dac_resource_class = 8;
++ dosr_increment = 4;
++ aic32x4_set_processing_blocks(component, 1, 9);
++ } else if (sample_rate == 192000) {
++ aosr = 32;
++ adc_resource_class = 3;
++ dac_resource_class = 4;
++ dosr_increment = 2;
++ aic32x4_set_processing_blocks(component, 13, 19);
++ } else {
++ dev_err(component->dev, "Sampling rate not supported\n");
++ return -EINVAL;
++ }
+
+- aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
++ madc = DIV_ROUND_UP((32 * adc_resource_class), aosr);
++ max_dosr = (AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment) *
++ dosr_increment;
++ min_dosr = (AIC32X4_MIN_DOSR_FREQ / sample_rate / dosr_increment) *
++ dosr_increment;
++ max_nadc = AIC32X4_MAX_CODEC_CLKIN_FREQ / (madc * aosr * sample_rate);
++
++ for (nadc = max_nadc; nadc > 0; --nadc) {
++ adc_clock_rate = nadc * madc * aosr * sample_rate;
++ for (dosr = max_dosr; dosr >= min_dosr;
++ dosr -= dosr_increment) {
++ min_mdac = DIV_ROUND_UP((32 * dac_resource_class), dosr);
++ max_ndac = AIC32X4_MAX_CODEC_CLKIN_FREQ /
++ (min_mdac * dosr * sample_rate);
++ for (mdac = min_mdac; mdac <= 128; ++mdac) {
++ for (ndac = max_ndac; ndac > 0; --ndac) {
++ dac_clock_rate = ndac * mdac * dosr *
++ sample_rate;
++ if (dac_clock_rate == adc_clock_rate) {
++ if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
++ continue;
++
++ clk_set_rate(clocks[0].clk,
++ dac_clock_rate);
++
++ clk_set_rate(clocks[1].clk,
++ sample_rate * aosr *
++ madc);
++ clk_set_rate(clocks[2].clk,
++ sample_rate * aosr);
++ aic32x4_set_aosr(component,
++ aosr);
++
++ clk_set_rate(clocks[3].clk,
++ sample_rate * dosr *
++ mdac);
++ clk_set_rate(clocks[4].clk,
++ sample_rate * dosr);
++ aic32x4_set_dosr(component,
++ dosr);
++
++ clk_set_rate(clocks[5].clk,
++ sample_rate * 32);
++ return 0;
++ }
++ }
++ }
++ }
++ }
+
+- return 0;
++ dev_err(component->dev,
++ "Could not set clocks to support sample rate.\n");
++ return -EINVAL;
+ }
+
+ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
+@@ -796,7 +780,7 @@ static int aic32x4_hw_params(struct snd_
+ u8 iface1_reg = 0;
+ u8 dacsetup_reg = 0;
+
+- aic32x4_setup_clocks(component, params_rate(params), aic32x4->sysclk);
++ aic32x4_setup_clocks(component, params_rate(params));
+
+ switch (params_width(params)) {
+ case 16:
+--- a/sound/soc/codecs/tlv320aic32x4.h
++++ b/sound/soc/codecs/tlv320aic32x4.h
+@@ -211,7 +211,9 @@ int aic32x4_register_clocks(struct devic
+ #define AIC32X4_DIV_MASK GENMASK(6, 0)
+
+ /* Clock Limits */
++#define AIC32X4_MAX_DOSR_FREQ 6200000
++#define AIC32X4_MIN_DOSR_FREQ 2800000
++#define AIC32X4_MAX_CODEC_CLKIN_FREQ 110000000
+ #define AIC32X4_MAX_PLL_CLKIN 20000000
+
+-
+ #endif /* _TLV320AIC32X4_H */
+++ /dev/null
-From a2d8d212b986e4a4ae52c748d246e4c28ebaf1bc Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Mar 2019 17:58:50 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Move aosr and dosr setting to
- separate functions
-
-commit fbafbf6517274a797e6e6508c18dd8dba5920c89 upstream.
-
-Move these to separate helper functions. This looks cleaner and fits
-better with the new clock setting in CCF.
-
----
- sound/soc/codecs/tlv320aic32x4.c | 24 +++++++++++++++++-------
- 1 file changed, 17 insertions(+), 7 deletions(-)
-
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -720,6 +720,20 @@ static int aic32x4_set_dai_fmt(struct sn
- return 0;
- }
-
-+static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr)
-+{
-+ return snd_soc_component_write(component, AIC32X4_AOSR, aosr);
-+}
-+
-+static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr)
-+{
-+ snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8);
-+ snd_soc_component_write(component, AIC32X4_DOSRLSB,
-+ (dosr & 0xff));
-+
-+ return 0;
-+}
-+
- static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
- u8 r_block, u8 p_block)
- {
-@@ -765,14 +779,10 @@ static int aic32x4_setup_clocks(struct s
- clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate);
- clk_set_rate(clocks[5].clk, aic32x4_divs[i].bdiv_rate);
-
-- aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
-+ aic32x4_set_aosr(component, aic32x4_divs[i].aosr);
-+ aic32x4_set_dosr(component, aic32x4_divs[i].dosr);
-
-- /* DOSR MSB & LSB values */
-- snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
-- snd_soc_component_write(component, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
--
-- /* AOSR value */
-- snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
-+ aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
-
- return 0;
- }
--- /dev/null
+From 5ec6ed3e423878cf975a955c8796c2cdb10b5ca7 Mon Sep 17 00:00:00 2001
+Date: Thu, 21 Mar 2019 17:58:52 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Restructure set_dai_sysclk
+
+commit aa6a60f7be925210d5156f0e8025f3afe1f4f54d upstream.
+
+The sysclk is now managed by the CCF. Change this function
+to merely find the system clock and set it using
+clk_set_rate.
+
+---
+ sound/soc/codecs/tlv320aic32x4.c | 17 ++++++-----------
+ 1 file changed, 6 insertions(+), 11 deletions(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -49,7 +49,6 @@
+
+ struct aic32x4_priv {
+ struct regmap *regmap;
+- u32 sysclk;
+ u32 power_cfg;
+ u32 micpga_routing;
+ bool swapdacs;
+@@ -569,17 +568,13 @@ static int aic32x4_set_dai_sysclk(struct
+ int clk_id, unsigned int freq, int dir)
+ {
+ struct snd_soc_component *component = codec_dai->component;
+- struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
++ struct clk *mclk;
++ struct clk *pll;
+
+- switch (freq) {
+- case 12000000:
+- case 24000000:
+- case 25000000:
+- aic32x4->sysclk = freq;
+- return 0;
+- }
+- printk(KERN_ERR "aic32x4: invalid frequency to set DAI system clock\n");
+- return -EINVAL;
++ pll = devm_clk_get(component->dev, "pll");
++ mclk = clk_get_parent(pll);
++
++ return clk_set_rate(mclk, freq);
+ }
+
+ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+++ /dev/null
-From 3e62c56daa1c799bb2a1d954ecfb88e8d37421bb Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Mar 2019 17:58:51 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Dynamically Determine Clocking
-
-commit 96c3bb00239de4fb5f4ddca42c1f90d6d9b3c697 upstream.
-
-The existing code uses a static lookup table to determine the
-settings of the various clock devices on board the chip. This is
-limiting in a couple of ways. First, this doesn't allow for any
-master clock rates other than the three that have been
-precalculated. Additionally, new sample rates are difficult to
-add to the table. Witness that the chip is capable of 192000 Hz
-sampling, but it is not provided by this driver. Last, if the
-driver is clocked by something that isn't a crystal, the
-upstream clock may not be able to achieve exactly the rate
-requested in the driver. This will mean that clocking will be
-slightly off for the sampling clock or that it won't work at all.
-
-This patch determines the settings for all of the clocks at
-runtime considering the real conditions of the clocks in the
-system. The rules for the clocks are in TI's SLAA557 application
-guide on pages 37, 51 and 77.
-
----
- sound/soc/codecs/tlv320aic32x4.c | 190 ++++++++++++++-----------------
- sound/soc/codecs/tlv320aic32x4.h | 4 +-
- 2 files changed, 90 insertions(+), 104 deletions(-)
-
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -47,21 +47,6 @@
-
- #include "tlv320aic32x4.h"
-
--struct aic32x4_rate_divs {
-- u32 mclk;
-- u32 rate;
-- unsigned long pll_rate;
-- u16 dosr;
-- unsigned long ndac_rate;
-- unsigned long mdac_rate;
-- u8 aosr;
-- unsigned long nadc_rate;
-- unsigned long madc_rate;
-- unsigned long bdiv_rate;
-- u8 r_block;
-- u8 p_block;
--};
--
- struct aic32x4_priv {
- struct regmap *regmap;
- u32 sysclk;
-@@ -307,58 +292,6 @@ static const struct snd_kcontrol_new aic
- 0, 0x0F, 0),
- };
-
--static const struct aic32x4_rate_divs aic32x4_divs[] = {
-- /* 8k rate */
-- { 12000000, 8000, 57120000, 768, 18432000, 6144000, 128, 18432000,
-- 1024000, 256000, 1, 1 },
-- { 24000000, 8000, 57120000, 768, 6144000, 6144000, 64, 2048000,
-- 512000, 256000, 1, 1 },
-- { 25000000, 8000, 32620000, 768, 6144000, 6144000, 64, 2048000,
-- 512000, 256000, 1, 1 },
-- /* 11.025k rate */
-- { 12000000, 11025, 44217600, 512, 11289600, 5644800, 128, 11289600,
-- 1411200, 352800, 1, 1 },
-- { 24000000, 11025, 44217600, 512, 5644800, 5644800, 64, 2822400,
-- 705600, 352800, 1, 1 },
-- /* 16k rate */
-- { 12000000, 16000, 57120000, 384, 18432000, 6144000, 128, 18432000,
-- 2048000, 512000, 1, 1 },
-- { 24000000, 16000, 57120000, 384, 6144000, 6144000, 64, 5120000,
-- 1024000, 512000, 1, 1 },
-- { 25000000, 16000, 32620000, 384, 6144000, 6144000, 64, 5120000,
-- 1024000, 512000, 1, 1 },
-- /* 22.05k rate */
-- { 12000000, 22050, 44217600, 256, 22579200, 5644800, 128, 22579200,
-- 2822400, 705600, 1, 1 },
-- { 24000000, 22050, 44217600, 256, 5644800, 5644800, 64, 5644800,
-- 1411200, 705600, 1, 1 },
-- { 25000000, 22050, 19713750, 256, 5644800, 5644800, 64, 5644800,
-- 1411200, 705600, 1, 1 },
-- /* 32k rate */
-- { 12000000, 32000, 14112000, 192, 43008000, 6144000, 64, 43008000,
-- 2048000, 1024000, 1, 1 },
-- { 24000000, 32000, 14112000, 192, 12288000, 6144000, 64, 12288000,
-- 2048000, 1024000, 1, 1 },
-- /* 44.1k rate */
-- { 12000000, 44100, 44217600, 128, 45158400, 5644800, 128, 45158400,
-- 5644800, 1411200, 1, 1 },
-- { 24000000, 44100, 44217600, 128, 11289600, 5644800, 64, 11289600,
-- 2822400, 1411200, 1, 1 },
-- { 25000000, 44100, 19713750, 128, 11289600, 5644800, 64, 11289600,
-- 2822400, 1411200, 1, 1 },
-- /* 48k rate */
-- { 12000000, 48000, 18432000, 128, 49152000, 6144000, 128, 49152000,
-- 6144000, 1536000, 1, 1 },
-- { 24000000, 48000, 18432000, 128, 12288000, 6144000, 64, 12288000,
-- 3072000, 1536000, 1, 1 },
-- { 25000000, 48000, 75626250, 128, 12288000, 6144000, 64, 12288000,
-- 3072000, 1536000, 1, 1 },
--
-- /* 96k rate */
-- { 25000000, 96000, 75626250, 64, 24576000, 6144000, 64, 24576000,
-- 6144000, 3072000, 1, 9 },
--};
--
- static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
- SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
- SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0),
-@@ -632,20 +565,6 @@ const struct regmap_config aic32x4_regma
- };
- EXPORT_SYMBOL(aic32x4_regmap_config);
-
--static inline int aic32x4_get_divs(int mclk, int rate)
--{
-- int i;
--
-- for (i = 0; i < ARRAY_SIZE(aic32x4_divs); i++) {
-- if ((aic32x4_divs[i].rate == rate)
-- && (aic32x4_divs[i].mclk == mclk)) {
-- return i;
-- }
-- }
-- printk(KERN_ERR "aic32x4: master clock and sample rate is not supported\n");
-- return -EINVAL;
--}
--
- static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
- int clk_id, unsigned int freq, int dir)
- {
-@@ -747,11 +666,17 @@ static int aic32x4_set_processing_blocks
- }
-
- static int aic32x4_setup_clocks(struct snd_soc_component *component,
-- unsigned int sample_rate,
-- unsigned int parent_rate)
-+ unsigned int sample_rate)
- {
-- int i;
-+ u8 aosr;
-+ u16 dosr;
-+ u8 adc_resource_class, dac_resource_class;
-+ u8 madc, nadc, mdac, ndac, max_nadc, min_mdac, max_ndac;
-+ u8 dosr_increment;
-+ u16 max_dosr, min_dosr;
-+ unsigned long mclk_rate, adc_clock_rate, dac_clock_rate;
- int ret;
-+ struct clk *mclk;
-
- struct clk_bulk_data clocks[] = {
- { .id = "pll" },
-@@ -761,30 +686,89 @@ static int aic32x4_setup_clocks(struct s
- { .id = "mdac" },
- { .id = "bdiv" },
- };
--
-- i = aic32x4_get_divs(parent_rate, sample_rate);
-- if (i < 0) {
-- printk(KERN_ERR "aic32x4: sampling rate not supported\n");
-- return i;
-- }
--
- ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
- if (ret)
- return ret;
-
-- clk_set_rate(clocks[0].clk, aic32x4_divs[i].pll_rate);
-- clk_set_rate(clocks[1].clk, aic32x4_divs[i].nadc_rate);
-- clk_set_rate(clocks[2].clk, aic32x4_divs[i].madc_rate);
-- clk_set_rate(clocks[3].clk, aic32x4_divs[i].ndac_rate);
-- clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate);
-- clk_set_rate(clocks[5].clk, aic32x4_divs[i].bdiv_rate);
-+ mclk = clk_get_parent(clocks[1].clk);
-+ mclk_rate = clk_get_rate(mclk);
-
-- aic32x4_set_aosr(component, aic32x4_divs[i].aosr);
-- aic32x4_set_dosr(component, aic32x4_divs[i].dosr);
-+ if (sample_rate <= 48000) {
-+ aosr = 128;
-+ adc_resource_class = 6;
-+ dac_resource_class = 8;
-+ dosr_increment = 8;
-+ aic32x4_set_processing_blocks(component, 1, 1);
-+ } else if (sample_rate <= 96000) {
-+ aosr = 64;
-+ adc_resource_class = 6;
-+ dac_resource_class = 8;
-+ dosr_increment = 4;
-+ aic32x4_set_processing_blocks(component, 1, 9);
-+ } else if (sample_rate == 192000) {
-+ aosr = 32;
-+ adc_resource_class = 3;
-+ dac_resource_class = 4;
-+ dosr_increment = 2;
-+ aic32x4_set_processing_blocks(component, 13, 19);
-+ } else {
-+ dev_err(component->dev, "Sampling rate not supported\n");
-+ return -EINVAL;
-+ }
-
-- aic32x4_set_processing_blocks(component, aic32x4_divs[i].r_block, aic32x4_divs[i].p_block);
-+ madc = DIV_ROUND_UP((32 * adc_resource_class), aosr);
-+ max_dosr = (AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment) *
-+ dosr_increment;
-+ min_dosr = (AIC32X4_MIN_DOSR_FREQ / sample_rate / dosr_increment) *
-+ dosr_increment;
-+ max_nadc = AIC32X4_MAX_CODEC_CLKIN_FREQ / (madc * aosr * sample_rate);
-+
-+ for (nadc = max_nadc; nadc > 0; --nadc) {
-+ adc_clock_rate = nadc * madc * aosr * sample_rate;
-+ for (dosr = max_dosr; dosr >= min_dosr;
-+ dosr -= dosr_increment) {
-+ min_mdac = DIV_ROUND_UP((32 * dac_resource_class), dosr);
-+ max_ndac = AIC32X4_MAX_CODEC_CLKIN_FREQ /
-+ (min_mdac * dosr * sample_rate);
-+ for (mdac = min_mdac; mdac <= 128; ++mdac) {
-+ for (ndac = max_ndac; ndac > 0; --ndac) {
-+ dac_clock_rate = ndac * mdac * dosr *
-+ sample_rate;
-+ if (dac_clock_rate == adc_clock_rate) {
-+ if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
-+ continue;
-+
-+ clk_set_rate(clocks[0].clk,
-+ dac_clock_rate);
-+
-+ clk_set_rate(clocks[1].clk,
-+ sample_rate * aosr *
-+ madc);
-+ clk_set_rate(clocks[2].clk,
-+ sample_rate * aosr);
-+ aic32x4_set_aosr(component,
-+ aosr);
-+
-+ clk_set_rate(clocks[3].clk,
-+ sample_rate * dosr *
-+ mdac);
-+ clk_set_rate(clocks[4].clk,
-+ sample_rate * dosr);
-+ aic32x4_set_dosr(component,
-+ dosr);
-+
-+ clk_set_rate(clocks[5].clk,
-+ sample_rate * 32);
-+ return 0;
-+ }
-+ }
-+ }
-+ }
-+ }
-
-- return 0;
-+ dev_err(component->dev,
-+ "Could not set clocks to support sample rate.\n");
-+ return -EINVAL;
- }
-
- static int aic32x4_hw_params(struct snd_pcm_substream *substream,
-@@ -796,7 +780,7 @@ static int aic32x4_hw_params(struct snd_
- u8 iface1_reg = 0;
- u8 dacsetup_reg = 0;
-
-- aic32x4_setup_clocks(component, params_rate(params), aic32x4->sysclk);
-+ aic32x4_setup_clocks(component, params_rate(params));
-
- switch (params_width(params)) {
- case 16:
---- a/sound/soc/codecs/tlv320aic32x4.h
-+++ b/sound/soc/codecs/tlv320aic32x4.h
-@@ -211,7 +211,9 @@ int aic32x4_register_clocks(struct devic
- #define AIC32X4_DIV_MASK GENMASK(6, 0)
-
- /* Clock Limits */
-+#define AIC32X4_MAX_DOSR_FREQ 6200000
-+#define AIC32X4_MIN_DOSR_FREQ 2800000
-+#define AIC32X4_MAX_CODEC_CLKIN_FREQ 110000000
- #define AIC32X4_MAX_PLL_CLKIN 20000000
-
--
- #endif /* _TLV320AIC32X4_H */
--- /dev/null
+From 3c7bf08e6b6bdc2e6005aaa5e6aa6d12ce40d406 Mon Sep 17 00:00:00 2001
+Date: Thu, 21 Mar 2019 17:58:53 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Remove mclk references
+
+commit 78f2d58a289302e56a7def96a783a7686ebf27e2 upstream.
+
+mclk is not used by anything anymore. Remove support for it.
+All that information now comes from the clock tree.
+
+---
+ sound/soc/codecs/tlv320aic32x4.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -53,7 +53,6 @@ struct aic32x4_priv {
+ u32 micpga_routing;
+ bool swapdacs;
+ int rstn_gpio;
+- struct clk *mclk;
+ const char *mclk_name;
+
+ struct regulator *supply_ldo;
+@@ -1191,12 +1190,6 @@ int aic32x4_probe(struct device *dev, st
+ aic32x4->mclk_name = "mclk";
+ }
+
+- aic32x4->mclk = devm_clk_get(dev, "mclk");
+- if (IS_ERR(aic32x4->mclk)) {
+- dev_err(dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n");
+- return PTR_ERR(aic32x4->mclk);
+- }
+-
+ ret = aic32x4_register_clocks(dev, aic32x4->mclk_name);
+ if (ret)
+ return ret;
--- /dev/null
+From e54269cdeb78beb5131594de702daeecc2b05ec2 Mon Sep 17 00:00:00 2001
+Date: Thu, 21 Mar 2019 17:58:54 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Allow 192000 Sample Rate
+
+commit 6d56ee1550b8a81bc63c80051ff78d8d704b09ba upstream.
+
+The clocking and processing blocks are now properly set up to
+support 192000 sample rates. Allow drivers to ask for that.
+
+---
+ sound/soc/codecs/tlv320aic32x4.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -859,7 +859,7 @@ static int aic32x4_set_bias_level(struct
+ return 0;
+ }
+
+-#define AIC32X4_RATES SNDRV_PCM_RATE_8000_96000
++#define AIC32X4_RATES SNDRV_PCM_RATE_8000_192000
+ #define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+ | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+++ /dev/null
-From 5ec6ed3e423878cf975a955c8796c2cdb10b5ca7 Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Mar 2019 17:58:52 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Restructure set_dai_sysclk
-
-commit aa6a60f7be925210d5156f0e8025f3afe1f4f54d upstream.
-
-The sysclk is now managed by the CCF. Change this function
-to merely find the system clock and set it using
-clk_set_rate.
-
----
- sound/soc/codecs/tlv320aic32x4.c | 17 ++++++-----------
- 1 file changed, 6 insertions(+), 11 deletions(-)
-
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -49,7 +49,6 @@
-
- struct aic32x4_priv {
- struct regmap *regmap;
-- u32 sysclk;
- u32 power_cfg;
- u32 micpga_routing;
- bool swapdacs;
-@@ -569,17 +568,13 @@ static int aic32x4_set_dai_sysclk(struct
- int clk_id, unsigned int freq, int dir)
- {
- struct snd_soc_component *component = codec_dai->component;
-- struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
-+ struct clk *mclk;
-+ struct clk *pll;
-
-- switch (freq) {
-- case 12000000:
-- case 24000000:
-- case 25000000:
-- aic32x4->sysclk = freq;
-- return 0;
-- }
-- printk(KERN_ERR "aic32x4: invalid frequency to set DAI system clock\n");
-- return -EINVAL;
-+ pll = devm_clk_get(component->dev, "pll");
-+ mclk = clk_get_parent(pll);
-+
-+ return clk_set_rate(mclk, freq);
- }
-
- static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
--- /dev/null
+From 0ef20f96802fac1ce888a1e0b56e14b6b3fd4f72 Mon Sep 17 00:00:00 2001
+Date: Tue, 26 Mar 2019 13:10:13 +0000
+Subject: [PATCH] ASoC: tlv320aic32x4: Only enable with common clock
+
+commit 64f01d2b5ccc621c3aa66b82daf9154f5581f36a upstream.
+
+Some architectures do not yet support the common clock API at all but
+the tlv320aic32x4 driver now requires it.
+
+---
+ sound/soc/codecs/Kconfig | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -170,8 +170,8 @@ config SND_SOC_ALL_CODECS
+ select SND_SOC_TAS5713 if I2C
+ select SND_SOC_TLV320AIC26 if SPI_MASTER
+ select SND_SOC_TLV320AIC31XX if I2C
+- select SND_SOC_TLV320AIC32X4_I2C if I2C
+- select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER
++ select SND_SOC_TLV320AIC32X4_I2C if I2C && COMMON_CLK
++ select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER && COMMON_CLK
+ select SND_SOC_TLV320AIC3X if I2C
+ select SND_SOC_TPA6130A2 if I2C
+ select SND_SOC_TLV320DAC33 if I2C
+@@ -1030,11 +1030,13 @@ config SND_SOC_TLV320AIC32X4
+ config SND_SOC_TLV320AIC32X4_I2C
+ tristate "Texas Instruments TLV320AIC32x4 audio CODECs - I2C"
+ depends on I2C
++ depends on COMMON_CLK
+ select SND_SOC_TLV320AIC32X4
+
+ config SND_SOC_TLV320AIC32X4_SPI
+ tristate "Texas Instruments TLV320AIC32x4 audio CODECs - SPI"
+ depends on SPI_MASTER
++ depends on COMMON_CLK
+ select SND_SOC_TLV320AIC32X4
+
+ config SND_SOC_TLV320AIC3X
+++ /dev/null
-From 3c7bf08e6b6bdc2e6005aaa5e6aa6d12ce40d406 Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Mar 2019 17:58:53 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Remove mclk references
-
-commit 78f2d58a289302e56a7def96a783a7686ebf27e2 upstream.
-
-mclk is not used by anything anymore. Remove support for it.
-All that information now comes from the clock tree.
-
----
- sound/soc/codecs/tlv320aic32x4.c | 7 -------
- 1 file changed, 7 deletions(-)
-
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -53,7 +53,6 @@ struct aic32x4_priv {
- u32 micpga_routing;
- bool swapdacs;
- int rstn_gpio;
-- struct clk *mclk;
- const char *mclk_name;
-
- struct regulator *supply_ldo;
-@@ -1191,12 +1190,6 @@ int aic32x4_probe(struct device *dev, st
- aic32x4->mclk_name = "mclk";
- }
-
-- aic32x4->mclk = devm_clk_get(dev, "mclk");
-- if (IS_ERR(aic32x4->mclk)) {
-- dev_err(dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n");
-- return PTR_ERR(aic32x4->mclk);
-- }
--
- ret = aic32x4_register_clocks(dev, aic32x4->mclk_name);
- if (ret)
- return ret;
+++ /dev/null
-From e54269cdeb78beb5131594de702daeecc2b05ec2 Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Mar 2019 17:58:54 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Allow 192000 Sample Rate
-
-commit 6d56ee1550b8a81bc63c80051ff78d8d704b09ba upstream.
-
-The clocking and processing blocks are now properly set up to
-support 192000 sample rates. Allow drivers to ask for that.
-
----
- sound/soc/codecs/tlv320aic32x4.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -859,7 +859,7 @@ static int aic32x4_set_bias_level(struct
- return 0;
- }
-
--#define AIC32X4_RATES SNDRV_PCM_RATE_8000_96000
-+#define AIC32X4_RATES SNDRV_PCM_RATE_8000_192000
- #define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
- | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
-
--- /dev/null
+From c667b06f616d5dec68469ac73764abd5bcb1d694 Mon Sep 17 00:00:00 2001
+Date: Fri, 5 Apr 2019 13:06:42 +0100
+Subject: [PATCH] Audiophonics I-Sabre 9038Q2M DAC driver
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 +
+ .../boot/dts/overlays/i-sabre-q2m-overlay.dts | 39 ++
+ sound/soc/bcm/Kconfig | 7 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/i-sabre-q2m.c | 157 +++++++
+ sound/soc/codecs/Kconfig | 5 +
+ sound/soc/codecs/Makefile | 2 +
+ sound/soc/codecs/i-sabre-codec.c | 392 ++++++++++++++++++
+ sound/soc/codecs/i-sabre-codec.h | 42 ++
+ 13 files changed, 656 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts
+ create mode 100644 sound/soc/bcm/i-sabre-q2m.c
+ create mode 100644 sound/soc/codecs/i-sabre-codec.c
+ create mode 100644 sound/soc/codecs/i-sabre-codec.h
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -55,6 +55,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ hy28a.dtbo \
+ hy28b.dtbo \
+ hy28b-2017.dtbo \
++ i-sabre-q2m.dtbo \
+ i2c-bcm2708.dtbo \
+ i2c-gpio.dtbo \
+ i2c-mux.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -869,6 +869,12 @@ Params: speed Display
+ ledgpio GPIO used to control backlight
+
+
++Name: i-sabre-q2m
++Info: Configures the Audiophonics I-SABRE Q2M DAC
++Load: dtoverlay=i-sabre-q2m
++Params: <None>
++
++
+ Name: i2c-bcm2708
+ Info: Fall back to the i2c_bcm2708 driver for the i2c_arm bus.
+ Load: dtoverlay=i2c-bcm2708
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts
+@@ -0,0 +1,39 @@
++// Definitions for I-Sabre Q2M
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&sound>;
++ frag0: __overlay__ {
++ compatible = "audiophonics,i-sabre-q2m";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ i-sabre-codec@48 {
++ #sound-dai-cells = <0>;
++ compatible = "audiophonics,i-sabre-codec";
++ reg = <0x48>;
++ status = "okay";
++ };
++ };
++ };
++};
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -123,6 +123,13 @@ config SND_BCM2708_SOC_IQAUDIO_DIGI
+ help
+ Say Y or M if you want to add support for IQAudIO Digital IO board.
+
++config SND_BCM2708_SOC_I_SABRE_Q2M
++ tristate "Support for Audiophonics I-Sabre Q2M DAC"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_I_SABRE_CODEC
++ help
++ Say Y or M if you want to add support for Audiophonics I-SABRE Q2M DAC
++
+ config SND_BCM2708_SOC_ADAU1977_ADC
+ tristate "Support for ADAU1977 ADC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -19,6 +19,7 @@ snd-soc-justboom-dac-objs := justboom-da
+ snd-soc-rpi-cirrus-objs := rpi-cirrus.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
++ snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o
+ snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
+ snd-soc-audioinjector-octo-soundcard-objs := audioinjector-octo-soundcard.o
+ snd-soc-audiosense-pi-objs := audiosense-pi.o
+@@ -42,6 +43,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DA
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
++ obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o
+ obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o
+ obj-$(CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD) += snd-soc-audioinjector-octo-soundcard.o
+ obj-$(CONFIG_SND_AUDIOSENSE_PI) += snd-soc-audiosense-pi.o
+--- /dev/null
++++ b/sound/soc/bcm/i-sabre-q2m.c
+@@ -0,0 +1,157 @@
++/*
++ * ASoC Driver for I-Sabre Q2M
++ *
++ * Author: Satoru Kawase
++ * Modified by: Xiao Qingyong
++ * Update kernel v4.18+ by : Audiophonics
++ * Copyright 2018 Audiophonics
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/fs.h>
++#include <asm/uaccess.h>
++#include <sound/core.h>
++#include <sound/soc.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++
++#include "../codecs/i-sabre-codec.h"
++
++
++static int snd_rpi_i_sabre_q2m_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_component *component = rtd->codec_dai->component;
++ unsigned int value;
++
++ /* Device ID */
++ value = snd_soc_component_read32(component, ISABRECODEC_REG_01);
++ dev_info(component->card->dev, "Audiophonics Device ID : %02X\n", value);
++
++ /* API revision */
++ value = snd_soc_component_read32(component, ISABRECODEC_REG_02);
++ dev_info(component->card->dev, "Audiophonics API revision : %02X\n", value);
++
++ return 0;
++}
++
++static int snd_rpi_i_sabre_q2m_hw_params(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++ int bclk_ratio;
++
++ bclk_ratio = snd_pcm_format_physical_width(
++ params_format(params)) * params_channels(params);
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, bclk_ratio);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_i_sabre_q2m_ops = {
++ .hw_params = snd_rpi_i_sabre_q2m_hw_params,
++};
++
++
++static struct snd_soc_dai_link snd_rpi_i_sabre_q2m_dai[] = {
++ {
++ .name = "I-Sabre Q2M",
++ .stream_name = "I-Sabre Q2M DAC",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "i-sabre-codec-dai",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "i-sabre-codec-i2c.1-0048",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBS_CFS,
++ .init = snd_rpi_i_sabre_q2m_init,
++ .ops = &snd_rpi_i_sabre_q2m_ops,
++ }
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_i_sabre_q2m = {
++ .name = "I-Sabre Q2M DAC",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_i_sabre_q2m_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_i_sabre_q2m_dai)
++};
++
++
++static int snd_rpi_i_sabre_q2m_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_i_sabre_q2m.dev = &pdev->dev;
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai;
++
++ dai = &snd_rpi_i_sabre_q2m_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ } else {
++ dev_err(&pdev->dev,
++ "Property 'i2s-controller' missing or invalid\n");
++ return (-EINVAL);
++ }
++
++ dai->name = "I-Sabre Q2M";
++ dai->stream_name = "I-Sabre Q2M DAC";
++ dai->dai_fmt = SND_SOC_DAIFMT_I2S
++ | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBS_CFS;
++ }
++
++ /* Wait for registering codec driver */
++ mdelay(50);
++
++ ret = snd_soc_register_card(&snd_rpi_i_sabre_q2m);
++ if (ret) {
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++ }
++
++ return ret;
++}
++
++static int snd_rpi_i_sabre_q2m_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_i_sabre_q2m);
++}
++
++static const struct of_device_id snd_rpi_i_sabre_q2m_of_match[] = {
++ { .compatible = "audiophonics,i-sabre-q2m", },
++ {}
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_i_sabre_q2m_of_match);
++
++static struct platform_driver snd_rpi_i_sabre_q2m_driver = {
++ .driver = {
++ .name = "snd-rpi-i-sabre-q2m",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_i_sabre_q2m_of_match,
++ },
++ .probe = snd_rpi_i_sabre_q2m_probe,
++ .remove = snd_rpi_i_sabre_q2m_remove,
++};
++module_platform_driver(snd_rpi_i_sabre_q2m_driver);
++
++MODULE_DESCRIPTION("ASoC Driver for I-Sabre Q2M");
++MODULE_AUTHOR("Audiophonics <http://www.audiophonics.fr>");
++MODULE_LICENSE("GPL");
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -85,6 +85,7 @@ config SND_SOC_ALL_CODECS
+ select SND_SOC_ICS43432
+ select SND_SOC_INNO_RK3036
+ select SND_SOC_ISABELLE if I2C
++ select SND_SOC_I_SABRE_CODEC if I2C
+ select SND_SOC_JZ4740_CODEC
+ select SND_SOC_LM4857 if I2C
+ select SND_SOC_LM49453 if I2C
+@@ -1322,4 +1323,8 @@ config SND_SOC_TPA6130A2
+ tristate "Texas Instruments TPA6130A2 headphone amplifier"
+ depends on I2C
+
++config SND_SOC_I_SABRE_CODEC
++ tristate "Audiophonics I-SABRE Codec"
++ depends on I2C
++
+ endmenu
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -81,6 +81,7 @@ snd-soc-hdac-hdmi-objs := hdac_hdmi.o
+ snd-soc-ics43432-objs := ics43432.o
+ snd-soc-inno-rk3036-objs := inno_rk3036.o
+ snd-soc-isabelle-objs := isabelle.o
++snd-soc-i-sabre-codec-objs := i-sabre-codec.o
+ snd-soc-jz4740-codec-objs := jz4740.o
+ snd-soc-l3-objs := l3.o
+ snd-soc-lm4857-objs := lm4857.o
+@@ -343,6 +344,7 @@ obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-s
+ obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o
+ obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o
+ obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
++obj-$(CONFIG_SND_SOC_I_SABRE_CODEC) += snd-soc-i-sabre-codec.o
+ obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
+ obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
+ obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
+--- /dev/null
++++ b/sound/soc/codecs/i-sabre-codec.c
+@@ -0,0 +1,392 @@
++/*
++ * Driver for I-Sabre Q2M
++ *
++ * Author: Satoru Kawase
++ * Modified by: Xiao Qingyong
++ * Modified by: JC BARBAUD (Mute)
++ * Update kernel v4.18+ by : Audiophonics
++ * Copyright 2018 Audiophonics
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/regmap.h>
++#include <linux/i2c.h>
++#include <sound/soc.h>
++#include <sound/pcm_params.h>
++#include <sound/tlv.h>
++
++#include "i-sabre-codec.h"
++
++
++/* I-Sabre Q2M Codec Private Data */
++struct i_sabre_codec_priv {
++ struct regmap *regmap;
++ unsigned int fmt;
++};
++
++
++/* I-Sabre Q2M Codec Default Register Value */
++static const struct reg_default i_sabre_codec_reg_defaults[] = {
++ { ISABRECODEC_REG_10, 0x00 },
++ { ISABRECODEC_REG_20, 0x00 },
++ { ISABRECODEC_REG_21, 0x00 },
++ { ISABRECODEC_REG_22, 0x00 },
++ { ISABRECODEC_REG_24, 0x00 },
++};
++
++
++static bool i_sabre_codec_writeable(struct device *dev, unsigned int reg)
++{
++ switch (reg) {
++ case ISABRECODEC_REG_10:
++ case ISABRECODEC_REG_20:
++ case ISABRECODEC_REG_21:
++ case ISABRECODEC_REG_22:
++ case ISABRECODEC_REG_24:
++ return true;
++
++ default:
++ return false;
++ }
++}
++
++static bool i_sabre_codec_readable(struct device *dev, unsigned int reg)
++{
++ switch (reg) {
++ case ISABRECODEC_REG_01:
++ case ISABRECODEC_REG_02:
++ case ISABRECODEC_REG_10:
++ case ISABRECODEC_REG_20:
++ case ISABRECODEC_REG_21:
++ case ISABRECODEC_REG_22:
++ case ISABRECODEC_REG_24:
++ return true;
++
++ default:
++ return false;
++ }
++}
++
++static bool i_sabre_codec_volatile(struct device *dev, unsigned int reg)
++{
++ switch (reg) {
++ case ISABRECODEC_REG_01:
++ case ISABRECODEC_REG_02:
++ return true;
++
++ default:
++ return false;
++ }
++}
++
++
++/* Volume Scale */
++static const DECLARE_TLV_DB_SCALE(volume_tlv, -10000, 100, 0);
++
++
++/* Filter Type */
++static const char * const fir_filter_type_texts[] = {
++ "brick wall",
++ "corrected minimum phase fast",
++ "minimum phase slow",
++ "minimum phase fast",
++ "linear phase slow",
++ "linear phase fast",
++ "apodizing fast",
++};
++
++static SOC_ENUM_SINGLE_DECL(i_sabre_fir_filter_type_enum,
++ ISABRECODEC_REG_22, 0, fir_filter_type_texts);
++
++
++/* I2S / SPDIF Select */
++static const char * const iis_spdif_sel_texts[] = {
++ "I2S",
++ "SPDIF",
++};
++
++static SOC_ENUM_SINGLE_DECL(i_sabre_iis_spdif_sel_enum,
++ ISABRECODEC_REG_24, 0, iis_spdif_sel_texts);
++
++
++/* Control */
++static const struct snd_kcontrol_new i_sabre_codec_controls[] = {
++SOC_SINGLE_RANGE_TLV("Digital Playback Volume", ISABRECODEC_REG_20, 0, 0, 100, 1, volume_tlv),
++SOC_SINGLE("Digital Playback Switch", ISABRECODEC_REG_21, 0, 1, 1),
++SOC_ENUM("FIR Filter Type", i_sabre_fir_filter_type_enum),
++SOC_ENUM("I2S/SPDIF Select", i_sabre_iis_spdif_sel_enum),
++};
++
++
++static const u32 i_sabre_codec_dai_rates_slave[] = {
++ 8000, 11025, 16000, 22050, 32000,
++ 44100, 48000, 64000, 88200, 96000,
++ 176400, 192000, 352800, 384000,
++ 705600, 768000, 1411200, 1536000
++};
++
++static const struct snd_pcm_hw_constraint_list constraints_slave = {
++ .list = i_sabre_codec_dai_rates_slave,
++ .count = ARRAY_SIZE(i_sabre_codec_dai_rates_slave),
++};
++
++static int i_sabre_codec_dai_startup_slave(
++ struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
++{
++ struct snd_soc_component *component = dai->component;
++ int ret;
++
++ ret = snd_pcm_hw_constraint_list(substream->runtime,
++ 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_slave);
++ if (ret != 0) {
++ dev_err(component->card->dev, "Failed to setup rates constraints: %d\n", ret);
++ }
++
++ return ret;
++}
++
++static int i_sabre_codec_dai_startup(
++ struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
++{
++ struct snd_soc_component *component = dai->component;
++ struct i_sabre_codec_priv *i_sabre_codec
++ = snd_soc_component_get_drvdata(component);
++
++ switch (i_sabre_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++ case SND_SOC_DAIFMT_CBS_CFS:
++ return i_sabre_codec_dai_startup_slave(substream, dai);
++
++ default:
++ return (-EINVAL);
++ }
++}
++
++static int i_sabre_codec_hw_params(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
++ struct snd_soc_dai *dai)
++{
++ struct snd_soc_component *component = dai->component;
++ struct i_sabre_codec_priv *i_sabre_codec
++ = snd_soc_component_get_drvdata(component);
++ unsigned int daifmt;
++ int format_width;
++
++ dev_dbg(component->card->dev, "hw_params %u Hz, %u channels\n",
++ params_rate(params), params_channels(params));
++
++ /* Check I2S Format (Bit Size) */
++ format_width = snd_pcm_format_width(params_format(params));
++ if ((format_width != 32) && (format_width != 16)) {
++ dev_err(component->card->dev, "Bad frame size: %d\n",
++ snd_pcm_format_width(params_format(params)));
++ return (-EINVAL);
++ }
++
++ /* Check Slave Mode */
++ daifmt = i_sabre_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK;
++ if (daifmt != SND_SOC_DAIFMT_CBS_CFS) {
++ return (-EINVAL);
++ }
++
++ /* Notify Sampling Frequency */
++ switch (params_rate(params))
++ {
++ case 44100:
++ case 48000:
++ case 88200:
++ case 96000:
++ case 176400:
++ case 192000:
++ snd_soc_component_update_bits(component, ISABRECODEC_REG_10, 0x01, 0x00);
++ break;
++
++ case 352800:
++ case 384000:
++ case 705600:
++ case 768000:
++ case 1411200:
++ case 1536000:
++ snd_soc_component_update_bits(component, ISABRECODEC_REG_10, 0x01, 0x01);
++ break;
++ }
++
++ return 0;
++}
++
++static int i_sabre_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
++{
++ struct snd_soc_component *component = dai->component;
++ struct i_sabre_codec_priv *i_sabre_codec
++ = snd_soc_component_get_drvdata(component);
++
++ /* interface format */
++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
++ case SND_SOC_DAIFMT_I2S:
++ break;
++
++ case SND_SOC_DAIFMT_RIGHT_J:
++ case SND_SOC_DAIFMT_LEFT_J:
++ default:
++ return (-EINVAL);
++ }
++
++ /* clock inversion */
++ if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
++ return (-EINVAL);
++ }
++
++ /* Set Audio Data Format */
++ i_sabre_codec->fmt = fmt;
++
++ return 0;
++}
++
++static int i_sabre_codec_dac_mute(struct snd_soc_dai *dai, int mute)
++{
++ struct snd_soc_component *component = dai->component;
++
++ if (mute) {
++ snd_soc_component_update_bits(component, ISABRECODEC_REG_21, 0x01, 0x01);
++ } else {
++ snd_soc_component_update_bits(component, ISABRECODEC_REG_21, 0x01, 0x00);
++ }
++
++ return 0;
++}
++
++
++static const struct snd_soc_dai_ops i_sabre_codec_dai_ops = {
++ .startup = i_sabre_codec_dai_startup,
++ .hw_params = i_sabre_codec_hw_params,
++ .set_fmt = i_sabre_codec_set_fmt,
++ .digital_mute = i_sabre_codec_dac_mute,
++};
++
++static struct snd_soc_dai_driver i_sabre_codec_dai = {
++ .name = "i-sabre-codec-dai",
++ .playback = {
++ .stream_name = "Playback",
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SNDRV_PCM_RATE_CONTINUOUS,
++ .rate_min = 8000,
++ .rate_max = 1536000,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE
++ | SNDRV_PCM_FMTBIT_S32_LE,
++ },
++ .ops = &i_sabre_codec_dai_ops,
++};
++
++static struct snd_soc_component_driver i_sabre_codec_codec_driver = {
++ .controls = i_sabre_codec_controls,
++ .num_controls = ARRAY_SIZE(i_sabre_codec_controls),
++};
++
++
++static const struct regmap_config i_sabre_codec_regmap = {
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = ISABRECODEC_MAX_REG,
++
++ .reg_defaults = i_sabre_codec_reg_defaults,
++ .num_reg_defaults = ARRAY_SIZE(i_sabre_codec_reg_defaults),
++
++ .writeable_reg = i_sabre_codec_writeable,
++ .readable_reg = i_sabre_codec_readable,
++ .volatile_reg = i_sabre_codec_volatile,
++
++ .cache_type = REGCACHE_RBTREE,
++};
++
++
++static int i_sabre_codec_probe(struct device *dev, struct regmap *regmap)
++{
++ struct i_sabre_codec_priv *i_sabre_codec;
++ int ret;
++
++ i_sabre_codec = devm_kzalloc(dev, sizeof(*i_sabre_codec), GFP_KERNEL);
++ if (!i_sabre_codec) {
++ dev_err(dev, "devm_kzalloc");
++ return (-ENOMEM);
++ }
++
++ i_sabre_codec->regmap = regmap;
++
++ dev_set_drvdata(dev, i_sabre_codec);
++
++ ret = snd_soc_register_component(dev,
++ &i_sabre_codec_codec_driver, &i_sabre_codec_dai, 1);
++ if (ret != 0) {
++ dev_err(dev, "Failed to register CODEC: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static void i_sabre_codec_remove(struct device *dev)
++{
++ snd_soc_unregister_component(dev);
++}
++
++
++static int i_sabre_codec_i2c_probe(
++ struct i2c_client *i2c, const struct i2c_device_id *id)
++{
++ struct regmap *regmap;
++
++ regmap = devm_regmap_init_i2c(i2c, &i_sabre_codec_regmap);
++ if (IS_ERR(regmap)) {
++ return PTR_ERR(regmap);
++ }
++
++ return i_sabre_codec_probe(&i2c->dev, regmap);
++}
++
++static int i_sabre_codec_i2c_remove(struct i2c_client *i2c)
++{
++ i_sabre_codec_remove(&i2c->dev);
++
++ return 0;
++}
++
++
++static const struct i2c_device_id i_sabre_codec_i2c_id[] = {
++ { "i-sabre-codec", },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, i_sabre_codec_i2c_id);
++
++static const struct of_device_id i_sabre_codec_of_match[] = {
++ { .compatible = "audiophonics,i-sabre-codec", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, i_sabre_codec_of_match);
++
++static struct i2c_driver i_sabre_codec_i2c_driver = {
++ .driver = {
++ .name = "i-sabre-codec-i2c",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(i_sabre_codec_of_match),
++ },
++ .probe = i_sabre_codec_i2c_probe,
++ .remove = i_sabre_codec_i2c_remove,
++ .id_table = i_sabre_codec_i2c_id,
++};
++module_i2c_driver(i_sabre_codec_i2c_driver);
++
++
++MODULE_DESCRIPTION("ASoC I-Sabre Q2M codec driver");
++MODULE_AUTHOR("Audiophonics <http://www.audiophonics.fr>");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/sound/soc/codecs/i-sabre-codec.h
+@@ -0,0 +1,42 @@
++/*
++ * Driver for I-Sabre Q2M
++ *
++ * Author: Satoru Kawase
++ * Modified by: Xiao Qingyong
++ * Copyright 2018 Audiophonics
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#ifndef _SND_SOC_ISABRECODEC
++#define _SND_SOC_ISABRECODEC
++
++
++/* ISABRECODEC Register Address */
++#define ISABRECODEC_REG_01 0x01 /* Virtual Device ID : 0x01 = es9038q2m */
++#define ISABRECODEC_REG_02 0x02 /* API revision : 0x01 = Revision 01 */
++#define ISABRECODEC_REG_10 0x10 /* 0x01 = above 192kHz, 0x00 = otherwise */
++#define ISABRECODEC_REG_20 0x20 /* 0 - 100 (decimal value, 0 = min., 100 = max.) */
++#define ISABRECODEC_REG_21 0x21 /* 0x00 = Mute OFF, 0x01 = Mute ON */
++#define ISABRECODEC_REG_22 0x22
++/*
++ 0x00 = brick wall,
++ 0x01 = corrected minimum phase fast,
++ 0x02 = minimum phase slow,
++ 0x03 = minimum phase fast,
++ 0x04 = linear phase slow,
++ 0x05 = linear phase fast,
++ 0x06 = apodizing fast,
++*/
++//#define ISABRECODEC_REG_23 0x23 /* reserved */
++#define ISABRECODEC_REG_24 0x24 /* 0x00 = I2S, 0x01 = SPDIF */
++#define ISABRECODEC_MAX_REG 0x24 /* Maximum Register Number */
++
++#endif /* _SND_SOC_ISABRECODEC */
--- /dev/null
+From 5942d9e650ce419236d5a7dc53c2513889ed3453 Mon Sep 17 00:00:00 2001
+Date: Wed, 3 Apr 2019 21:17:15 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Change author's name
+
+commit 7297ba6c74c5b9e78d8e936af82eecfcf7d32dfb upstream.
+
+The author of these files has changed her name. Update
+instances in the code of her dead name to current legal
+name.
+
+---
+ sound/soc/codecs/tlv320aic32x4-i2c.c | 4 ++--
+ sound/soc/codecs/tlv320aic32x4-spi.c | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4-i2c.c
++++ b/sound/soc/codecs/tlv320aic32x4-i2c.c
+@@ -3,7 +3,7 @@
+ *
+ * Copyright 2011 NW Digital Radio
+ *
+ *
+ * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
+ *
+@@ -72,5 +72,5 @@ static struct i2c_driver aic32x4_i2c_dri
+ module_i2c_driver(aic32x4_i2c_driver);
+
+ MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver I2C");
+ MODULE_LICENSE("GPL");
+--- a/sound/soc/codecs/tlv320aic32x4-spi.c
++++ b/sound/soc/codecs/tlv320aic32x4-spi.c
+@@ -3,7 +3,7 @@
+ *
+ * Copyright 2011 NW Digital Radio
+ *
+ *
+ * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
+ *
+@@ -74,5 +74,5 @@ static struct spi_driver aic32x4_spi_dri
+ module_spi_driver(aic32x4_spi_driver);
+
+ MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver SPI");
+ MODULE_LICENSE("GPL");
+++ /dev/null
-From 0ef20f96802fac1ce888a1e0b56e14b6b3fd4f72 Mon Sep 17 00:00:00 2001
-Date: Tue, 26 Mar 2019 13:10:13 +0000
-Subject: [PATCH] ASoC: tlv320aic32x4: Only enable with common clock
-
-commit 64f01d2b5ccc621c3aa66b82daf9154f5581f36a upstream.
-
-Some architectures do not yet support the common clock API at all but
-the tlv320aic32x4 driver now requires it.
-
----
- sound/soc/codecs/Kconfig | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
---- a/sound/soc/codecs/Kconfig
-+++ b/sound/soc/codecs/Kconfig
-@@ -170,8 +170,8 @@ config SND_SOC_ALL_CODECS
- select SND_SOC_TAS5713 if I2C
- select SND_SOC_TLV320AIC26 if SPI_MASTER
- select SND_SOC_TLV320AIC31XX if I2C
-- select SND_SOC_TLV320AIC32X4_I2C if I2C
-- select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER
-+ select SND_SOC_TLV320AIC32X4_I2C if I2C && COMMON_CLK
-+ select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER && COMMON_CLK
- select SND_SOC_TLV320AIC3X if I2C
- select SND_SOC_TPA6130A2 if I2C
- select SND_SOC_TLV320DAC33 if I2C
-@@ -1030,11 +1030,13 @@ config SND_SOC_TLV320AIC32X4
- config SND_SOC_TLV320AIC32X4_I2C
- tristate "Texas Instruments TLV320AIC32x4 audio CODECs - I2C"
- depends on I2C
-+ depends on COMMON_CLK
- select SND_SOC_TLV320AIC32X4
-
- config SND_SOC_TLV320AIC32X4_SPI
- tristate "Texas Instruments TLV320AIC32x4 audio CODECs - SPI"
- depends on SPI_MASTER
-+ depends on COMMON_CLK
- select SND_SOC_TLV320AIC32X4
-
- config SND_SOC_TLV320AIC3X
--- /dev/null
+From 1ed86adfa457ecd9668f2541dabfebd3ee82d035 Mon Sep 17 00:00:00 2001
+Date: Wed, 3 Apr 2019 21:17:16 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Update copyright and use SPDX
+ identifier
+
+commit 8a1d95c393d971e624fc28f11516b0bc3a7fa706 upstream.
+
+Update the copyright dates and use the SPDX identifier instead
+of reciting the license.
+
+---
+ sound/soc/codecs/tlv320aic32x4-i2c.c | 14 ++------------
+ sound/soc/codecs/tlv320aic32x4-spi.c | 14 ++------------
+ 2 files changed, 4 insertions(+), 24 deletions(-)
+
+--- a/sound/soc/codecs/tlv320aic32x4-i2c.c
++++ b/sound/soc/codecs/tlv320aic32x4-i2c.c
+@@ -1,21 +1,11 @@
+-/*
+- * linux/sound/soc/codecs/tlv320aic32x4-i2c.c
++/* SPDX-License-Identifier: GPL-2.0
+ *
+- * Copyright 2011 NW Digital Radio
++ * Copyright 2011-2019 NW Digital Radio
+ *
+ *
+ * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
+ *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+ */
+
+ #include <linux/i2c.h>
+--- a/sound/soc/codecs/tlv320aic32x4-spi.c
++++ b/sound/soc/codecs/tlv320aic32x4-spi.c
+@@ -1,21 +1,11 @@
+-/*
+- * linux/sound/soc/codecs/tlv320aic32x4-spi.c
++/* SPDX-License-Identifier: GPL-2.0
+ *
+- * Copyright 2011 NW Digital Radio
++ * Copyright 2011-2019 NW Digital Radio
+ *
+ *
+ * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
+ *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+ */
+
+ #include <linux/spi/spi.h>
+++ /dev/null
-From c667b06f616d5dec68469ac73764abd5bcb1d694 Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Apr 2019 13:06:42 +0100
-Subject: [PATCH] Audiophonics I-Sabre 9038Q2M DAC driver
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 6 +
- .../boot/dts/overlays/i-sabre-q2m-overlay.dts | 39 ++
- sound/soc/bcm/Kconfig | 7 +
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/i-sabre-q2m.c | 157 +++++++
- sound/soc/codecs/Kconfig | 5 +
- sound/soc/codecs/Makefile | 2 +
- sound/soc/codecs/i-sabre-codec.c | 392 ++++++++++++++++++
- sound/soc/codecs/i-sabre-codec.h | 42 ++
- 13 files changed, 656 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts
- create mode 100644 sound/soc/bcm/i-sabre-q2m.c
- create mode 100644 sound/soc/codecs/i-sabre-codec.c
- create mode 100644 sound/soc/codecs/i-sabre-codec.h
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -55,6 +55,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- hy28a.dtbo \
- hy28b.dtbo \
- hy28b-2017.dtbo \
-+ i-sabre-q2m.dtbo \
- i2c-bcm2708.dtbo \
- i2c-gpio.dtbo \
- i2c-mux.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -869,6 +869,12 @@ Params: speed Display
- ledgpio GPIO used to control backlight
-
-
-+Name: i-sabre-q2m
-+Info: Configures the Audiophonics I-SABRE Q2M DAC
-+Load: dtoverlay=i-sabre-q2m
-+Params: <None>
-+
-+
- Name: i2c-bcm2708
- Info: Fall back to the i2c_bcm2708 driver for the i2c_arm bus.
- Load: dtoverlay=i2c-bcm2708
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts
-@@ -0,0 +1,39 @@
-+// Definitions for I-Sabre Q2M
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&sound>;
-+ frag0: __overlay__ {
-+ compatible = "audiophonics,i-sabre-q2m";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ i-sabre-codec@48 {
-+ #sound-dai-cells = <0>;
-+ compatible = "audiophonics,i-sabre-codec";
-+ reg = <0x48>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -123,6 +123,13 @@ config SND_BCM2708_SOC_IQAUDIO_DIGI
- help
- Say Y or M if you want to add support for IQAudIO Digital IO board.
-
-+config SND_BCM2708_SOC_I_SABRE_Q2M
-+ tristate "Support for Audiophonics I-Sabre Q2M DAC"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_I_SABRE_CODEC
-+ help
-+ Say Y or M if you want to add support for Audiophonics I-SABRE Q2M DAC
-+
- config SND_BCM2708_SOC_ADAU1977_ADC
- tristate "Support for ADAU1977 ADC"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -19,6 +19,7 @@ snd-soc-justboom-dac-objs := justboom-da
- snd-soc-rpi-cirrus-objs := rpi-cirrus.o
- snd-soc-rpi-proto-objs := rpi-proto.o
- snd-soc-iqaudio-dac-objs := iqaudio-dac.o
-+ snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o
- snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
- snd-soc-audioinjector-octo-soundcard-objs := audioinjector-octo-soundcard.o
- snd-soc-audiosense-pi-objs := audiosense-pi.o
-@@ -42,6 +43,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DA
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
- obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
-+ obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o
- obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o
- obj-$(CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD) += snd-soc-audioinjector-octo-soundcard.o
- obj-$(CONFIG_SND_AUDIOSENSE_PI) += snd-soc-audiosense-pi.o
---- /dev/null
-+++ b/sound/soc/bcm/i-sabre-q2m.c
-@@ -0,0 +1,157 @@
-+/*
-+ * ASoC Driver for I-Sabre Q2M
-+ *
-+ * Author: Satoru Kawase
-+ * Modified by: Xiao Qingyong
-+ * Update kernel v4.18+ by : Audiophonics
-+ * Copyright 2018 Audiophonics
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/fs.h>
-+#include <asm/uaccess.h>
-+#include <sound/core.h>
-+#include <sound/soc.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+
-+#include "../codecs/i-sabre-codec.h"
-+
-+
-+static int snd_rpi_i_sabre_q2m_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ struct snd_soc_component *component = rtd->codec_dai->component;
-+ unsigned int value;
-+
-+ /* Device ID */
-+ value = snd_soc_component_read32(component, ISABRECODEC_REG_01);
-+ dev_info(component->card->dev, "Audiophonics Device ID : %02X\n", value);
-+
-+ /* API revision */
-+ value = snd_soc_component_read32(component, ISABRECODEC_REG_02);
-+ dev_info(component->card->dev, "Audiophonics API revision : %02X\n", value);
-+
-+ return 0;
-+}
-+
-+static int snd_rpi_i_sabre_q2m_hw_params(
-+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+ int bclk_ratio;
-+
-+ bclk_ratio = snd_pcm_format_physical_width(
-+ params_format(params)) * params_channels(params);
-+ return snd_soc_dai_set_bclk_ratio(cpu_dai, bclk_ratio);
-+}
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_i_sabre_q2m_ops = {
-+ .hw_params = snd_rpi_i_sabre_q2m_hw_params,
-+};
-+
-+
-+static struct snd_soc_dai_link snd_rpi_i_sabre_q2m_dai[] = {
-+ {
-+ .name = "I-Sabre Q2M",
-+ .stream_name = "I-Sabre Q2M DAC",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .codec_dai_name = "i-sabre-codec-dai",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codec_name = "i-sabre-codec-i2c.1-0048",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-+ | SND_SOC_DAIFMT_CBS_CFS,
-+ .init = snd_rpi_i_sabre_q2m_init,
-+ .ops = &snd_rpi_i_sabre_q2m_ops,
-+ }
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_i_sabre_q2m = {
-+ .name = "I-Sabre Q2M DAC",
-+ .owner = THIS_MODULE,
-+ .dai_link = snd_rpi_i_sabre_q2m_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_i_sabre_q2m_dai)
-+};
-+
-+
-+static int snd_rpi_i_sabre_q2m_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ snd_rpi_i_sabre_q2m.dev = &pdev->dev;
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai;
-+
-+ dai = &snd_rpi_i_sabre_q2m_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+ if (i2s_node) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ } else {
-+ dev_err(&pdev->dev,
-+ "Property 'i2s-controller' missing or invalid\n");
-+ return (-EINVAL);
-+ }
-+
-+ dai->name = "I-Sabre Q2M";
-+ dai->stream_name = "I-Sabre Q2M DAC";
-+ dai->dai_fmt = SND_SOC_DAIFMT_I2S
-+ | SND_SOC_DAIFMT_NB_NF
-+ | SND_SOC_DAIFMT_CBS_CFS;
-+ }
-+
-+ /* Wait for registering codec driver */
-+ mdelay(50);
-+
-+ ret = snd_soc_register_card(&snd_rpi_i_sabre_q2m);
-+ if (ret) {
-+ dev_err(&pdev->dev,
-+ "snd_soc_register_card() failed: %d\n", ret);
-+ }
-+
-+ return ret;
-+}
-+
-+static int snd_rpi_i_sabre_q2m_remove(struct platform_device *pdev)
-+{
-+ return snd_soc_unregister_card(&snd_rpi_i_sabre_q2m);
-+}
-+
-+static const struct of_device_id snd_rpi_i_sabre_q2m_of_match[] = {
-+ { .compatible = "audiophonics,i-sabre-q2m", },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(of, snd_rpi_i_sabre_q2m_of_match);
-+
-+static struct platform_driver snd_rpi_i_sabre_q2m_driver = {
-+ .driver = {
-+ .name = "snd-rpi-i-sabre-q2m",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_i_sabre_q2m_of_match,
-+ },
-+ .probe = snd_rpi_i_sabre_q2m_probe,
-+ .remove = snd_rpi_i_sabre_q2m_remove,
-+};
-+module_platform_driver(snd_rpi_i_sabre_q2m_driver);
-+
-+MODULE_DESCRIPTION("ASoC Driver for I-Sabre Q2M");
-+MODULE_AUTHOR("Audiophonics <http://www.audiophonics.fr>");
-+MODULE_LICENSE("GPL");
---- a/sound/soc/codecs/Kconfig
-+++ b/sound/soc/codecs/Kconfig
-@@ -85,6 +85,7 @@ config SND_SOC_ALL_CODECS
- select SND_SOC_ICS43432
- select SND_SOC_INNO_RK3036
- select SND_SOC_ISABELLE if I2C
-+ select SND_SOC_I_SABRE_CODEC if I2C
- select SND_SOC_JZ4740_CODEC
- select SND_SOC_LM4857 if I2C
- select SND_SOC_LM49453 if I2C
-@@ -1322,4 +1323,8 @@ config SND_SOC_TPA6130A2
- tristate "Texas Instruments TPA6130A2 headphone amplifier"
- depends on I2C
-
-+config SND_SOC_I_SABRE_CODEC
-+ tristate "Audiophonics I-SABRE Codec"
-+ depends on I2C
-+
- endmenu
---- a/sound/soc/codecs/Makefile
-+++ b/sound/soc/codecs/Makefile
-@@ -81,6 +81,7 @@ snd-soc-hdac-hdmi-objs := hdac_hdmi.o
- snd-soc-ics43432-objs := ics43432.o
- snd-soc-inno-rk3036-objs := inno_rk3036.o
- snd-soc-isabelle-objs := isabelle.o
-+snd-soc-i-sabre-codec-objs := i-sabre-codec.o
- snd-soc-jz4740-codec-objs := jz4740.o
- snd-soc-l3-objs := l3.o
- snd-soc-lm4857-objs := lm4857.o
-@@ -343,6 +344,7 @@ obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-s
- obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o
- obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o
- obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
-+obj-$(CONFIG_SND_SOC_I_SABRE_CODEC) += snd-soc-i-sabre-codec.o
- obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
- obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
- obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
---- /dev/null
-+++ b/sound/soc/codecs/i-sabre-codec.c
-@@ -0,0 +1,392 @@
-+/*
-+ * Driver for I-Sabre Q2M
-+ *
-+ * Author: Satoru Kawase
-+ * Modified by: Xiao Qingyong
-+ * Modified by: JC BARBAUD (Mute)
-+ * Update kernel v4.18+ by : Audiophonics
-+ * Copyright 2018 Audiophonics
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/regmap.h>
-+#include <linux/i2c.h>
-+#include <sound/soc.h>
-+#include <sound/pcm_params.h>
-+#include <sound/tlv.h>
-+
-+#include "i-sabre-codec.h"
-+
-+
-+/* I-Sabre Q2M Codec Private Data */
-+struct i_sabre_codec_priv {
-+ struct regmap *regmap;
-+ unsigned int fmt;
-+};
-+
-+
-+/* I-Sabre Q2M Codec Default Register Value */
-+static const struct reg_default i_sabre_codec_reg_defaults[] = {
-+ { ISABRECODEC_REG_10, 0x00 },
-+ { ISABRECODEC_REG_20, 0x00 },
-+ { ISABRECODEC_REG_21, 0x00 },
-+ { ISABRECODEC_REG_22, 0x00 },
-+ { ISABRECODEC_REG_24, 0x00 },
-+};
-+
-+
-+static bool i_sabre_codec_writeable(struct device *dev, unsigned int reg)
-+{
-+ switch (reg) {
-+ case ISABRECODEC_REG_10:
-+ case ISABRECODEC_REG_20:
-+ case ISABRECODEC_REG_21:
-+ case ISABRECODEC_REG_22:
-+ case ISABRECODEC_REG_24:
-+ return true;
-+
-+ default:
-+ return false;
-+ }
-+}
-+
-+static bool i_sabre_codec_readable(struct device *dev, unsigned int reg)
-+{
-+ switch (reg) {
-+ case ISABRECODEC_REG_01:
-+ case ISABRECODEC_REG_02:
-+ case ISABRECODEC_REG_10:
-+ case ISABRECODEC_REG_20:
-+ case ISABRECODEC_REG_21:
-+ case ISABRECODEC_REG_22:
-+ case ISABRECODEC_REG_24:
-+ return true;
-+
-+ default:
-+ return false;
-+ }
-+}
-+
-+static bool i_sabre_codec_volatile(struct device *dev, unsigned int reg)
-+{
-+ switch (reg) {
-+ case ISABRECODEC_REG_01:
-+ case ISABRECODEC_REG_02:
-+ return true;
-+
-+ default:
-+ return false;
-+ }
-+}
-+
-+
-+/* Volume Scale */
-+static const DECLARE_TLV_DB_SCALE(volume_tlv, -10000, 100, 0);
-+
-+
-+/* Filter Type */
-+static const char * const fir_filter_type_texts[] = {
-+ "brick wall",
-+ "corrected minimum phase fast",
-+ "minimum phase slow",
-+ "minimum phase fast",
-+ "linear phase slow",
-+ "linear phase fast",
-+ "apodizing fast",
-+};
-+
-+static SOC_ENUM_SINGLE_DECL(i_sabre_fir_filter_type_enum,
-+ ISABRECODEC_REG_22, 0, fir_filter_type_texts);
-+
-+
-+/* I2S / SPDIF Select */
-+static const char * const iis_spdif_sel_texts[] = {
-+ "I2S",
-+ "SPDIF",
-+};
-+
-+static SOC_ENUM_SINGLE_DECL(i_sabre_iis_spdif_sel_enum,
-+ ISABRECODEC_REG_24, 0, iis_spdif_sel_texts);
-+
-+
-+/* Control */
-+static const struct snd_kcontrol_new i_sabre_codec_controls[] = {
-+SOC_SINGLE_RANGE_TLV("Digital Playback Volume", ISABRECODEC_REG_20, 0, 0, 100, 1, volume_tlv),
-+SOC_SINGLE("Digital Playback Switch", ISABRECODEC_REG_21, 0, 1, 1),
-+SOC_ENUM("FIR Filter Type", i_sabre_fir_filter_type_enum),
-+SOC_ENUM("I2S/SPDIF Select", i_sabre_iis_spdif_sel_enum),
-+};
-+
-+
-+static const u32 i_sabre_codec_dai_rates_slave[] = {
-+ 8000, 11025, 16000, 22050, 32000,
-+ 44100, 48000, 64000, 88200, 96000,
-+ 176400, 192000, 352800, 384000,
-+ 705600, 768000, 1411200, 1536000
-+};
-+
-+static const struct snd_pcm_hw_constraint_list constraints_slave = {
-+ .list = i_sabre_codec_dai_rates_slave,
-+ .count = ARRAY_SIZE(i_sabre_codec_dai_rates_slave),
-+};
-+
-+static int i_sabre_codec_dai_startup_slave(
-+ struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
-+{
-+ struct snd_soc_component *component = dai->component;
-+ int ret;
-+
-+ ret = snd_pcm_hw_constraint_list(substream->runtime,
-+ 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_slave);
-+ if (ret != 0) {
-+ dev_err(component->card->dev, "Failed to setup rates constraints: %d\n", ret);
-+ }
-+
-+ return ret;
-+}
-+
-+static int i_sabre_codec_dai_startup(
-+ struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
-+{
-+ struct snd_soc_component *component = dai->component;
-+ struct i_sabre_codec_priv *i_sabre_codec
-+ = snd_soc_component_get_drvdata(component);
-+
-+ switch (i_sabre_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-+ case SND_SOC_DAIFMT_CBS_CFS:
-+ return i_sabre_codec_dai_startup_slave(substream, dai);
-+
-+ default:
-+ return (-EINVAL);
-+ }
-+}
-+
-+static int i_sabre_codec_hw_params(
-+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
-+ struct snd_soc_dai *dai)
-+{
-+ struct snd_soc_component *component = dai->component;
-+ struct i_sabre_codec_priv *i_sabre_codec
-+ = snd_soc_component_get_drvdata(component);
-+ unsigned int daifmt;
-+ int format_width;
-+
-+ dev_dbg(component->card->dev, "hw_params %u Hz, %u channels\n",
-+ params_rate(params), params_channels(params));
-+
-+ /* Check I2S Format (Bit Size) */
-+ format_width = snd_pcm_format_width(params_format(params));
-+ if ((format_width != 32) && (format_width != 16)) {
-+ dev_err(component->card->dev, "Bad frame size: %d\n",
-+ snd_pcm_format_width(params_format(params)));
-+ return (-EINVAL);
-+ }
-+
-+ /* Check Slave Mode */
-+ daifmt = i_sabre_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK;
-+ if (daifmt != SND_SOC_DAIFMT_CBS_CFS) {
-+ return (-EINVAL);
-+ }
-+
-+ /* Notify Sampling Frequency */
-+ switch (params_rate(params))
-+ {
-+ case 44100:
-+ case 48000:
-+ case 88200:
-+ case 96000:
-+ case 176400:
-+ case 192000:
-+ snd_soc_component_update_bits(component, ISABRECODEC_REG_10, 0x01, 0x00);
-+ break;
-+
-+ case 352800:
-+ case 384000:
-+ case 705600:
-+ case 768000:
-+ case 1411200:
-+ case 1536000:
-+ snd_soc_component_update_bits(component, ISABRECODEC_REG_10, 0x01, 0x01);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static int i_sabre_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-+{
-+ struct snd_soc_component *component = dai->component;
-+ struct i_sabre_codec_priv *i_sabre_codec
-+ = snd_soc_component_get_drvdata(component);
-+
-+ /* interface format */
-+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-+ case SND_SOC_DAIFMT_I2S:
-+ break;
-+
-+ case SND_SOC_DAIFMT_RIGHT_J:
-+ case SND_SOC_DAIFMT_LEFT_J:
-+ default:
-+ return (-EINVAL);
-+ }
-+
-+ /* clock inversion */
-+ if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
-+ return (-EINVAL);
-+ }
-+
-+ /* Set Audio Data Format */
-+ i_sabre_codec->fmt = fmt;
-+
-+ return 0;
-+}
-+
-+static int i_sabre_codec_dac_mute(struct snd_soc_dai *dai, int mute)
-+{
-+ struct snd_soc_component *component = dai->component;
-+
-+ if (mute) {
-+ snd_soc_component_update_bits(component, ISABRECODEC_REG_21, 0x01, 0x01);
-+ } else {
-+ snd_soc_component_update_bits(component, ISABRECODEC_REG_21, 0x01, 0x00);
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static const struct snd_soc_dai_ops i_sabre_codec_dai_ops = {
-+ .startup = i_sabre_codec_dai_startup,
-+ .hw_params = i_sabre_codec_hw_params,
-+ .set_fmt = i_sabre_codec_set_fmt,
-+ .digital_mute = i_sabre_codec_dac_mute,
-+};
-+
-+static struct snd_soc_dai_driver i_sabre_codec_dai = {
-+ .name = "i-sabre-codec-dai",
-+ .playback = {
-+ .stream_name = "Playback",
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
-+ .rate_min = 8000,
-+ .rate_max = 1536000,
-+ .formats = SNDRV_PCM_FMTBIT_S16_LE
-+ | SNDRV_PCM_FMTBIT_S32_LE,
-+ },
-+ .ops = &i_sabre_codec_dai_ops,
-+};
-+
-+static struct snd_soc_component_driver i_sabre_codec_codec_driver = {
-+ .controls = i_sabre_codec_controls,
-+ .num_controls = ARRAY_SIZE(i_sabre_codec_controls),
-+};
-+
-+
-+static const struct regmap_config i_sabre_codec_regmap = {
-+ .reg_bits = 8,
-+ .val_bits = 8,
-+ .max_register = ISABRECODEC_MAX_REG,
-+
-+ .reg_defaults = i_sabre_codec_reg_defaults,
-+ .num_reg_defaults = ARRAY_SIZE(i_sabre_codec_reg_defaults),
-+
-+ .writeable_reg = i_sabre_codec_writeable,
-+ .readable_reg = i_sabre_codec_readable,
-+ .volatile_reg = i_sabre_codec_volatile,
-+
-+ .cache_type = REGCACHE_RBTREE,
-+};
-+
-+
-+static int i_sabre_codec_probe(struct device *dev, struct regmap *regmap)
-+{
-+ struct i_sabre_codec_priv *i_sabre_codec;
-+ int ret;
-+
-+ i_sabre_codec = devm_kzalloc(dev, sizeof(*i_sabre_codec), GFP_KERNEL);
-+ if (!i_sabre_codec) {
-+ dev_err(dev, "devm_kzalloc");
-+ return (-ENOMEM);
-+ }
-+
-+ i_sabre_codec->regmap = regmap;
-+
-+ dev_set_drvdata(dev, i_sabre_codec);
-+
-+ ret = snd_soc_register_component(dev,
-+ &i_sabre_codec_codec_driver, &i_sabre_codec_dai, 1);
-+ if (ret != 0) {
-+ dev_err(dev, "Failed to register CODEC: %d\n", ret);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static void i_sabre_codec_remove(struct device *dev)
-+{
-+ snd_soc_unregister_component(dev);
-+}
-+
-+
-+static int i_sabre_codec_i2c_probe(
-+ struct i2c_client *i2c, const struct i2c_device_id *id)
-+{
-+ struct regmap *regmap;
-+
-+ regmap = devm_regmap_init_i2c(i2c, &i_sabre_codec_regmap);
-+ if (IS_ERR(regmap)) {
-+ return PTR_ERR(regmap);
-+ }
-+
-+ return i_sabre_codec_probe(&i2c->dev, regmap);
-+}
-+
-+static int i_sabre_codec_i2c_remove(struct i2c_client *i2c)
-+{
-+ i_sabre_codec_remove(&i2c->dev);
-+
-+ return 0;
-+}
-+
-+
-+static const struct i2c_device_id i_sabre_codec_i2c_id[] = {
-+ { "i-sabre-codec", },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(i2c, i_sabre_codec_i2c_id);
-+
-+static const struct of_device_id i_sabre_codec_of_match[] = {
-+ { .compatible = "audiophonics,i-sabre-codec", },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, i_sabre_codec_of_match);
-+
-+static struct i2c_driver i_sabre_codec_i2c_driver = {
-+ .driver = {
-+ .name = "i-sabre-codec-i2c",
-+ .owner = THIS_MODULE,
-+ .of_match_table = of_match_ptr(i_sabre_codec_of_match),
-+ },
-+ .probe = i_sabre_codec_i2c_probe,
-+ .remove = i_sabre_codec_i2c_remove,
-+ .id_table = i_sabre_codec_i2c_id,
-+};
-+module_i2c_driver(i_sabre_codec_i2c_driver);
-+
-+
-+MODULE_DESCRIPTION("ASoC I-Sabre Q2M codec driver");
-+MODULE_AUTHOR("Audiophonics <http://www.audiophonics.fr>");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/sound/soc/codecs/i-sabre-codec.h
-@@ -0,0 +1,42 @@
-+/*
-+ * Driver for I-Sabre Q2M
-+ *
-+ * Author: Satoru Kawase
-+ * Modified by: Xiao Qingyong
-+ * Copyright 2018 Audiophonics
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#ifndef _SND_SOC_ISABRECODEC
-+#define _SND_SOC_ISABRECODEC
-+
-+
-+/* ISABRECODEC Register Address */
-+#define ISABRECODEC_REG_01 0x01 /* Virtual Device ID : 0x01 = es9038q2m */
-+#define ISABRECODEC_REG_02 0x02 /* API revision : 0x01 = Revision 01 */
-+#define ISABRECODEC_REG_10 0x10 /* 0x01 = above 192kHz, 0x00 = otherwise */
-+#define ISABRECODEC_REG_20 0x20 /* 0 - 100 (decimal value, 0 = min., 100 = max.) */
-+#define ISABRECODEC_REG_21 0x21 /* 0x00 = Mute OFF, 0x01 = Mute ON */
-+#define ISABRECODEC_REG_22 0x22
-+/*
-+ 0x00 = brick wall,
-+ 0x01 = corrected minimum phase fast,
-+ 0x02 = minimum phase slow,
-+ 0x03 = minimum phase fast,
-+ 0x04 = linear phase slow,
-+ 0x05 = linear phase fast,
-+ 0x06 = apodizing fast,
-+*/
-+//#define ISABRECODEC_REG_23 0x23 /* reserved */
-+#define ISABRECODEC_REG_24 0x24 /* 0x00 = I2S, 0x01 = SPDIF */
-+#define ISABRECODEC_MAX_REG 0x24 /* Maximum Register Number */
-+
-+#endif /* _SND_SOC_ISABRECODEC */
--- /dev/null
+From 0962637c67a56c1ae42ccb14c9e71c62f4aa1403 Mon Sep 17 00:00:00 2001
+Date: Wed, 3 Apr 2019 21:01:54 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Add Switch for Setting Common
+ Mode Voltage
+
+commit 44ceee847e27c828f2f1ef4e400e6bc0c8d04de3 upstream.
+
+Add a switch for setting common mode voltage. This can allow
+for higher drive levels on the amplifier outputs.
+
+---
+ sound/soc/codecs/tlv320aic32x4.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -242,6 +242,12 @@ static DECLARE_TLV_DB_SCALE(tlv_driver_g
+ /* -12dB min, 0.5dB steps */
+ static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
+
++static const char * const lo_cm_text[] = {
++ "Full Chip", "1.65V",
++};
++
++static SOC_ENUM_SINGLE_DECL(lo_cm_enum, AIC32X4_CMMODE, 3, lo_cm_text);
++
+ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
+ SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
+ AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
+@@ -255,6 +261,7 @@ static const struct snd_kcontrol_new aic
+ AIC32X4_HPRGAIN, 6, 0x01, 1),
+ SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
+ AIC32X4_LORGAIN, 6, 0x01, 1),
++ SOC_ENUM("LO Playback Common Mode Switch", lo_cm_enum),
+ SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL,
+ AIC32X4_RMICPGAVOL, 7, 0x01, 1),
+
+++ /dev/null
-From 5942d9e650ce419236d5a7dc53c2513889ed3453 Mon Sep 17 00:00:00 2001
-Date: Wed, 3 Apr 2019 21:17:15 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Change author's name
-
-commit 7297ba6c74c5b9e78d8e936af82eecfcf7d32dfb upstream.
-
-The author of these files has changed her name. Update
-instances in the code of her dead name to current legal
-name.
-
----
- sound/soc/codecs/tlv320aic32x4-i2c.c | 4 ++--
- sound/soc/codecs/tlv320aic32x4-spi.c | 4 ++--
- 2 files changed, 4 insertions(+), 4 deletions(-)
-
---- a/sound/soc/codecs/tlv320aic32x4-i2c.c
-+++ b/sound/soc/codecs/tlv320aic32x4-i2c.c
-@@ -3,7 +3,7 @@
- *
- * Copyright 2011 NW Digital Radio
- *
- *
- * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
- *
-@@ -72,5 +72,5 @@ static struct i2c_driver aic32x4_i2c_dri
- module_i2c_driver(aic32x4_i2c_driver);
-
- MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver I2C");
- MODULE_LICENSE("GPL");
---- a/sound/soc/codecs/tlv320aic32x4-spi.c
-+++ b/sound/soc/codecs/tlv320aic32x4-spi.c
-@@ -3,7 +3,7 @@
- *
- * Copyright 2011 NW Digital Radio
- *
- *
- * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
- *
-@@ -74,5 +74,5 @@ static struct spi_driver aic32x4_spi_dri
- module_spi_driver(aic32x4_spi_driver);
-
- MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver SPI");
- MODULE_LICENSE("GPL");
--- /dev/null
+From 6e5099288c946037476abd1488e4c7ab6b818e2b Mon Sep 17 00:00:00 2001
+Date: Wed, 3 Apr 2019 21:01:55 -0700
+Subject: [PATCH] ASoC: tlv320aic32x4: Add Playback PowerTune Controls
+
+commit d3e6e374566e1154820a9a3dc82f7eef646fcf95 upstream.
+
+PowerTune controls the power level of the chip. On playback this
+indirectly controls things like the gain of the various output
+amplifiers. This can allow for the decrease of output levels
+from the codec. This adds controls for those power levels to
+the driver.
+
+---
+ sound/soc/codecs/tlv320aic32x4.c | 9 +++++++++
+ sound/soc/codecs/tlv320aic32x4.h | 2 ++
+ 2 files changed, 11 insertions(+)
+
+--- a/sound/soc/codecs/tlv320aic32x4.c
++++ b/sound/soc/codecs/tlv320aic32x4.c
+@@ -248,9 +248,18 @@ static const char * const lo_cm_text[] =
+
+ static SOC_ENUM_SINGLE_DECL(lo_cm_enum, AIC32X4_CMMODE, 3, lo_cm_text);
+
++static const char * const ptm_text[] = {
++ "P3", "P2", "P1",
++};
++
++static SOC_ENUM_SINGLE_DECL(l_ptm_enum, AIC32X4_LPLAYBACK, 2, ptm_text);
++static SOC_ENUM_SINGLE_DECL(r_ptm_enum, AIC32X4_RPLAYBACK, 2, ptm_text);
++
+ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
+ SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
+ AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
++ SOC_ENUM("DAC Left Playback PowerTune Switch", l_ptm_enum),
++ SOC_ENUM("DAC Right Playback PowerTune Switch", r_ptm_enum),
+ SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
+ AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
+ tlv_driver_gain),
+--- a/sound/soc/codecs/tlv320aic32x4.h
++++ b/sound/soc/codecs/tlv320aic32x4.h
+@@ -78,6 +78,8 @@ int aic32x4_register_clocks(struct devic
+
+ #define AIC32X4_PWRCFG AIC32X4_REG(1, 1)
+ #define AIC32X4_LDOCTL AIC32X4_REG(1, 2)
++#define AIC32X4_LPLAYBACK AIC32X4_REG(1, 3)
++#define AIC32X4_RPLAYBACK AIC32X4_REG(1, 4)
+ #define AIC32X4_OUTPWRCTL AIC32X4_REG(1, 9)
+ #define AIC32X4_CMMODE AIC32X4_REG(1, 10)
+ #define AIC32X4_HPLROUTE AIC32X4_REG(1, 12)
+++ /dev/null
-From 1ed86adfa457ecd9668f2541dabfebd3ee82d035 Mon Sep 17 00:00:00 2001
-Date: Wed, 3 Apr 2019 21:17:16 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Update copyright and use SPDX
- identifier
-
-commit 8a1d95c393d971e624fc28f11516b0bc3a7fa706 upstream.
-
-Update the copyright dates and use the SPDX identifier instead
-of reciting the license.
-
----
- sound/soc/codecs/tlv320aic32x4-i2c.c | 14 ++------------
- sound/soc/codecs/tlv320aic32x4-spi.c | 14 ++------------
- 2 files changed, 4 insertions(+), 24 deletions(-)
-
---- a/sound/soc/codecs/tlv320aic32x4-i2c.c
-+++ b/sound/soc/codecs/tlv320aic32x4-i2c.c
-@@ -1,21 +1,11 @@
--/*
-- * linux/sound/soc/codecs/tlv320aic32x4-i2c.c
-+/* SPDX-License-Identifier: GPL-2.0
- *
-- * Copyright 2011 NW Digital Radio
-+ * Copyright 2011-2019 NW Digital Radio
- *
- *
- * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
- *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License as published by
-- * the Free Software Foundation; either version 2 of the License, or
-- * (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- * GNU General Public License for more details.
- */
-
- #include <linux/i2c.h>
---- a/sound/soc/codecs/tlv320aic32x4-spi.c
-+++ b/sound/soc/codecs/tlv320aic32x4-spi.c
-@@ -1,21 +1,11 @@
--/*
-- * linux/sound/soc/codecs/tlv320aic32x4-spi.c
-+/* SPDX-License-Identifier: GPL-2.0
- *
-- * Copyright 2011 NW Digital Radio
-+ * Copyright 2011-2019 NW Digital Radio
- *
- *
- * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
- *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License as published by
-- * the Free Software Foundation; either version 2 of the License, or
-- * (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- * GNU General Public License for more details.
- */
-
- #include <linux/spi/spi.h>
+++ /dev/null
-From 0962637c67a56c1ae42ccb14c9e71c62f4aa1403 Mon Sep 17 00:00:00 2001
-Date: Wed, 3 Apr 2019 21:01:54 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Add Switch for Setting Common
- Mode Voltage
-
-commit 44ceee847e27c828f2f1ef4e400e6bc0c8d04de3 upstream.
-
-Add a switch for setting common mode voltage. This can allow
-for higher drive levels on the amplifier outputs.
-
----
- sound/soc/codecs/tlv320aic32x4.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -242,6 +242,12 @@ static DECLARE_TLV_DB_SCALE(tlv_driver_g
- /* -12dB min, 0.5dB steps */
- static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
-
-+static const char * const lo_cm_text[] = {
-+ "Full Chip", "1.65V",
-+};
-+
-+static SOC_ENUM_SINGLE_DECL(lo_cm_enum, AIC32X4_CMMODE, 3, lo_cm_text);
-+
- static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
- SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
- AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
-@@ -255,6 +261,7 @@ static const struct snd_kcontrol_new aic
- AIC32X4_HPRGAIN, 6, 0x01, 1),
- SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
- AIC32X4_LORGAIN, 6, 0x01, 1),
-+ SOC_ENUM("LO Playback Common Mode Switch", lo_cm_enum),
- SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL,
- AIC32X4_RMICPGAVOL, 7, 0x01, 1),
-
--- /dev/null
+From 1d3aeba25b10d1ed2b5ae4cf0b535d821539a531 Mon Sep 17 00:00:00 2001
+Date: Sun, 17 Mar 2019 16:48:36 -0700
+Subject: [PATCH] dtoverlays: Add Support for the UDRC/DRAWS
+
+Adds a new overlay to support the Northwest Digital Radio
+DRAWS and UDRC HATs. See http://nwdigitalradio.com.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 2 +
+ arch/arm/boot/dts/overlays/README | 59 ++++++
+ arch/arm/boot/dts/overlays/draws-overlay.dts | 200 +++++++++++++++++++
+ arch/arm/boot/dts/overlays/udrc-overlay.dts | 128 ++++++++++++
+ 4 files changed, 389 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/draws-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/udrc-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -29,6 +29,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ dionaudio-loco-v2.dtbo \
+ dpi18.dtbo \
+ dpi24.dtbo \
++ draws.dtbo \
+ dwc-otg.dtbo \
+ dwc2.dtbo \
+ enc28j60.dtbo \
+@@ -146,6 +147,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ tpm-slb9670.dtbo \
+ uart0.dtbo \
+ uart1.dtbo \
++ udrc.dtbo \
+ upstream.dtbo \
+ upstream-aux-interrupt.dtbo \
+ vc4-fkms-v3d.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -531,6 +531,59 @@ Load: dtoverlay=dpi24
+ Params: <None>
+
+
++Name: draws
++Info: Configures the NW Digital Radio DRAWS Hat
++
++ The board includes an ADC to measure various board values and also
++ provides two analog user inputs on the expansion header. The ADC
++ can be configured for various sample rates and gain values to adjust
++ the input range. Tables describing the two parameters follow.
++
++ ADC Gain Values:
++ 0 = +/- 6.144V
++ 1 = +/- 4.096V
++ 2 = +/- 2.048V
++ 3 = +/- 1.024V
++ 4 = +/- 0.512V
++ 5 = +/- 0.256V
++ 6 = +/- 0.256V
++ 7 = +/- 0.256V
++
++ ADC Datarate Values:
++ 0 = 128sps
++ 1 = 250sps
++ 2 = 490sps
++ 3 = 920sps
++ 4 = 1600sps (default)
++ 5 = 2400sps
++ 6 = 3300sps
++ 7 = 3300sps
++Load: dtoverlay=draws,<param>=<val>
++Params: draws_adc_ch4_gain Sets the full scale resolution of the ADCs
++ input voltage sensor (default 1)
++
++ draws_adc_ch4_datarate Sets the datarate of the ADCs input voltage
++ sensor
++
++ draws_adc_ch5_gain Sets the full scale resolution of the ADCs
++ 5V rail voltage sensor (default 1)
++
++ draws_adc_ch5_datarate Sets the datarate of the ADCs 4V rail voltage
++ sensor
++
++ draws_adc_ch6_gain Sets the full scale resolution of the ADCs
++ AIN2 input (default 2)
++
++ draws_adc_ch6_datarate Sets the datarate of the ADCs AIN2 input
++
++ draws_adc_ch7_gain Sets the full scale resolution of the ADCs
++ AIN3 input (default 2)
++
++ draws_adc_ch7_datarate Sets the datarate of the ADCs AIN3 input
++
++ alsaname Name of the ALSA audio device (default "draws")
++
++
+ Name: dwc-otg
+ Info: Selects the dwc_otg USB controller driver which has fiq support. This
+ is the default on all except the Pi Zero which defaults to dwc2.
+@@ -2117,6 +2170,12 @@ Params: txd1_pin GPIO pin
+ rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
+
+
++Name: udrc
++Info: Configures the NW Digital Radio UDRC Hat
++Load: dtoverlay=udrc,<param>=<val>
++Params: alsaname Name of the ALSA audio device (default "udrc")
++
++
+ Name: upstream
+ Info: Allow usage of downstream .dtb with upstream kernel. Comprises
+ vc4-kms-v3d, dwc2 and upstream-aux-interrupt overlays.
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/draws-overlay.dts
+@@ -0,0 +1,200 @@
++#include <dt-bindings/clock/bcm2835.h>
++/*
++ * Device tree overlay for the DRAWS Hardware
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target-path = "/";
++ __overlay__ {
++ regulators {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ udrc0_ldoin: udrc0_ldoin {
++ compatible = "regulator-fixed";
++ regulator-name = "ldoin";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++ };
++
++ pps: pps {
++ compatible = "pps-gpio";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pps_pins>;
++ gpios = <&gpio 7 0>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c_arm>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ tlv320aic32x4: tlv320aic32x4@18 {
++ compatible = "ti,tlv320aic32x4";
++ reg = <0x18>;
++ #sound-dai-cells = <0>;
++ status = "okay";
++
++ clocks = <&clocks BCM2835_CLOCK_GP0>;
++ clock-names = "mclk";
++ assigned-clocks = <&clocks BCM2835_CLOCK_GP0>;
++ assigned-clock-rates = <25000000>;
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&gpclk0_pin &aic3204_reset>;
++
++ reset-gpios = <&gpio 13 0>;
++
++ iov-supply = <&udrc0_ldoin>;
++ ldoin-supply = <&udrc0_ldoin>;
++ };
++
++ sc16is752: sc16is752@50 {
++ compatible = "nxp,sc16is752";
++ reg = <0x50>;
++ clocks = <&sc16is752_clk>;
++ interrupt-parent = <&gpio>;
++ interrupts = <17 2>; /* IRQ_TYPE_EDGE_FALLING */
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&sc16is752_irq>;
++
++ sc16is752_clk: sc16is752_clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <1843200>;
++ };
++ };
++
++ tla2024: tla2024@48 {
++ compatible = "ti,ads1015";
++ reg = <0x48>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ adc_ch4: channel@4 {
++ reg = <4>;
++ ti,gain = <1>;
++ ti,datarate = <4>;
++ };
++
++ adc_ch5: channel@5 {
++ reg = <5>;
++ ti,gain = <1>;
++ ti,datarate = <4>;
++ };
++
++ adc_ch6: channel@6 {
++ reg = <6>;
++ ti,gain = <2>;
++ ti,datarate = <4>;
++ };
++
++ adc_ch7: channel@7 {
++ reg = <7>;
++ ti,gain = <2>;
++ ti,datarate = <4>;
++ };
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&sound>;
++ snd: __overlay__ {
++ compatible = "simple-audio-card";
++ i2s-controller = <&i2s>;
++ status = "okay";
++
++ simple-audio-card,name = "draws";
++ simple-audio-card,format = "i2s";
++
++ simple-audio-card,bitclock-master = <&dailink0_master>;
++ simple-audio-card,frame-master = <&dailink0_master>;
++
++ simple-audio-card,widgets =
++ "Line", "Line In",
++ "Line", "Line Out";
++
++ simple-audio-card,routing =
++ "IN1_R", "Line In",
++ "IN1_L", "Line In",
++ "CM_L", "Line In",
++ "CM_R", "Line In",
++ "Line Out", "LOR",
++ "Line Out", "LOL";
++
++ dailink0_master: simple-audio-card,cpu {
++ sound-dai = <&i2s>;
++ };
++
++ simple-audio-card,codec {
++ sound-dai = <&tlv320aic32x4>;
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&gpio>;
++ __overlay__ {
++ gpclk0_pin: gpclk0_pin {
++ brcm,pins = <4>;
++ brcm,function = <4>;
++ };
++
++ aic3204_reset: aic3204_reset {
++ brcm,pins = <13>;
++ brcm,function = <1>;
++ brcm,pull = <1>;
++ };
++
++ aic3204_gpio: aic3204_gpio {
++ brcm,pins = <26>;
++ };
++
++ sc16is752_irq: sc16is752_irq {
++ brcm,pins = <17>;
++ brcm,function = <0>;
++ brcm,pull = <2>;
++ };
++
++ pps_pins: pps_pins {
++ brcm,pins = <7>;
++ brcm,function = <0>;
++ brcm,pull = <0>;
++ };
++ };
++ };
++
++ __overrides__ {
++ draws_adc_ch4_gain = <&adc_ch4>,"ti,gain:0";
++ draws_adc_ch4_datarate = <&adc_ch4>,"ti,datarate:0";
++ draws_adc_ch5_gain = <&adc_ch5>,"ti,gain:0";
++ draws_adc_ch5_datarate = <&adc_ch5>,"ti,datarate:0";
++ draws_adc_ch6_gain = <&adc_ch6>,"ti,gain:0";
++ draws_adc_ch6_datarate = <&adc_ch6>,"ti,datarate:0";
++ draws_adc_ch7_gain = <&adc_ch7>,"ti,gain:0";
++ draws_adc_ch7_datarate = <&adc_ch7>,"ti,datarate:0";
++ alsaname = <&snd>, "simple-audio-card,name";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/udrc-overlay.dts
+@@ -0,0 +1,128 @@
++#include <dt-bindings/clock/bcm2835.h>
++/*
++ * Device tree overlay for the Universal Digital Radio Controller
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ clocks = <&clocks BCM2835_CLOCK_PCM>;
++ clock-names = "pcm";
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target-path = "/";
++ __overlay__ {
++ regulators {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ udrc0_ldoin: udrc0_ldoin {
++ compatible = "regulator-fixed";
++ regulator-name = "ldoin";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ clock-frequency = <400000>;
++
++ tlv320aic32x4: tlv320aic32x4@18 {
++ compatible = "ti,tlv320aic32x4";
++ #sound-dai-cells = <0>;
++ reg = <0x18>;
++ status = "okay";
++
++ clocks = <&clocks BCM2835_CLOCK_GP0>;
++ clock-names = "mclk";
++ assigned-clocks = <&clocks BCM2835_CLOCK_GP0>;
++ assigned-clock-rates = <25000000>;
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&gpclk0_pin &aic3204_reset>;
++
++ reset-gpios = <&gpio 13 0>;
++
++ iov-supply = <&udrc0_ldoin>;
++ ldoin-supply = <&udrc0_ldoin>;
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&sound>;
++ snd: __overlay__ {
++ compatible = "simple-audio-card";
++ i2s-controller = <&i2s>;
++ status = "okay";
++
++ simple-audio-card,name = "udrc";
++ simple-audio-card,format = "i2s";
++
++ simple-audio-card,bitclock-master = <&dailink0_master>;
++ simple-audio-card,frame-master = <&dailink0_master>;
++
++ simple-audio-card,widgets =
++ "Line", "Line In",
++ "Line", "Line Out";
++
++ simple-audio-card,routing =
++ "IN1_R", "Line In",
++ "IN1_L", "Line In",
++ "CM_L", "Line In",
++ "CM_R", "Line In",
++ "Line Out", "LOR",
++ "Line Out", "LOL";
++
++ dailink0_master: simple-audio-card,cpu {
++ sound-dai = <&i2s>;
++ };
++
++ simple-audio-card,codec {
++ sound-dai = <&tlv320aic32x4>;
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&gpio>;
++ __overlay__ {
++ gpclk0_pin: gpclk0_pin {
++ brcm,pins = <4>;
++ brcm,function = <4>;
++ };
++
++ aic3204_reset: aic3204_reset {
++ brcm,pins = <13>;
++ brcm,function = <1>;
++ brcm,pull = <1>;
++ };
++
++ aic3204_gpio: aic3204_gpio {
++ brcm,pins = <26>;
++ };
++ };
++ };
++
++ __overrides__ {
++ alsaname = <&snd>, "simple-audio-card,name";
++ };
++};
+++ /dev/null
-From 6e5099288c946037476abd1488e4c7ab6b818e2b Mon Sep 17 00:00:00 2001
-Date: Wed, 3 Apr 2019 21:01:55 -0700
-Subject: [PATCH] ASoC: tlv320aic32x4: Add Playback PowerTune Controls
-
-commit d3e6e374566e1154820a9a3dc82f7eef646fcf95 upstream.
-
-PowerTune controls the power level of the chip. On playback this
-indirectly controls things like the gain of the various output
-amplifiers. This can allow for the decrease of output levels
-from the codec. This adds controls for those power levels to
-the driver.
-
----
- sound/soc/codecs/tlv320aic32x4.c | 9 +++++++++
- sound/soc/codecs/tlv320aic32x4.h | 2 ++
- 2 files changed, 11 insertions(+)
-
---- a/sound/soc/codecs/tlv320aic32x4.c
-+++ b/sound/soc/codecs/tlv320aic32x4.c
-@@ -248,9 +248,18 @@ static const char * const lo_cm_text[] =
-
- static SOC_ENUM_SINGLE_DECL(lo_cm_enum, AIC32X4_CMMODE, 3, lo_cm_text);
-
-+static const char * const ptm_text[] = {
-+ "P3", "P2", "P1",
-+};
-+
-+static SOC_ENUM_SINGLE_DECL(l_ptm_enum, AIC32X4_LPLAYBACK, 2, ptm_text);
-+static SOC_ENUM_SINGLE_DECL(r_ptm_enum, AIC32X4_RPLAYBACK, 2, ptm_text);
-+
- static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
- SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
- AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
-+ SOC_ENUM("DAC Left Playback PowerTune Switch", l_ptm_enum),
-+ SOC_ENUM("DAC Right Playback PowerTune Switch", r_ptm_enum),
- SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
- AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
- tlv_driver_gain),
---- a/sound/soc/codecs/tlv320aic32x4.h
-+++ b/sound/soc/codecs/tlv320aic32x4.h
-@@ -78,6 +78,8 @@ int aic32x4_register_clocks(struct devic
-
- #define AIC32X4_PWRCFG AIC32X4_REG(1, 1)
- #define AIC32X4_LDOCTL AIC32X4_REG(1, 2)
-+#define AIC32X4_LPLAYBACK AIC32X4_REG(1, 3)
-+#define AIC32X4_RPLAYBACK AIC32X4_REG(1, 4)
- #define AIC32X4_OUTPWRCTL AIC32X4_REG(1, 9)
- #define AIC32X4_CMMODE AIC32X4_REG(1, 10)
- #define AIC32X4_HPLROUTE AIC32X4_REG(1, 12)
--- /dev/null
+From 0c988aed71773be4481b886ccf03c40a52f57cdb Mon Sep 17 00:00:00 2001
+Date: Mon, 8 Apr 2019 12:45:23 +0100
+Subject: [PATCH] dwc_otg: only do_split when we actually need to do a
+ split
+
+The previous test would fail if the root port was in fullspeed mode
+and there was a hub between the FS device and the root port. While
+the transfer worked, the schedule mangling performed for high-speed
+split transfers would break leading to an 8ms polling interval.
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
+@@ -167,8 +167,10 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_ot
+ char *speed, *type;
+ int dev_speed;
+ uint32_t hub_addr, hub_port;
++ hprt0_data_t hprt;
+
+ dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
++ hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
+
+ /* Initialize QH */
+ qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
+@@ -191,9 +193,8 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_ot
+
+ qh->nak_frame = 0xffff;
+
+- if (((dev_speed == USB_SPEED_LOW) ||
+- (dev_speed == USB_SPEED_FULL)) &&
+- (hub_addr != 0 && hub_addr != 1)) {
++ if (hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED &&
++ dev_speed != USB_SPEED_HIGH) {
+ DWC_DEBUGPL(DBG_HCD,
+ "QH init: EP %d: TT found at hub addr %d, for port %d\n",
+ dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
+@@ -204,7 +205,6 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_ot
+
+ if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
+ /* Compute scheduling parameters once and save them. */
+- hprt0_data_t hprt;
+
+ /** @todo Account for split transfers in the bus time. */
+ int bytecount =
+@@ -219,7 +219,6 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_ot
+ SCHEDULE_SLOP);
+ qh->interval = urb->interval;
+
+- hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
+ if (hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) {
+ if (dev_speed == USB_SPEED_LOW ||
+ dev_speed == USB_SPEED_FULL) {
--- /dev/null
+From 9c823e2ee1ec1b815b8ec29c231b112c5e397202 Mon Sep 17 00:00:00 2001
+Date: Mon, 8 Apr 2019 16:42:17 +0200
+Subject: [PATCH] Input: ili210x - fetch touchscreen geometry from DT
+
+commit f67cc3e927d8414ad3872e046764534ea1f5db0d upstream
+
+Fetching the geometry from the ILI251x registers seems unreliable and
+sometimes returns all zeroes. Add support for fetching the geometry and
+axis inversion from DT instead.
+
+---
+ drivers/input/touchscreen/ili210x.c | 321 +++++++++++++++++-----------
+ 1 file changed, 194 insertions(+), 127 deletions(-)
+
+--- a/drivers/input/touchscreen/ili210x.c
++++ b/drivers/input/touchscreen/ili210x.c
+@@ -4,11 +4,15 @@
+ #include <linux/slab.h>
+ #include <linux/input.h>
+ #include <linux/input/mt.h>
++#include <linux/input/touchscreen.h>
+ #include <linux/delay.h>
+ #include <linux/workqueue.h>
+-#include <linux/input/ili210x.h>
++#include <linux/gpio/consumer.h>
++#include <linux/of_device.h>
++#include <asm/unaligned.h>
+
+-#define MAX_TOUCHES 2
++#define ILI210X_TOUCHES 2
++#define ILI251X_TOUCHES 10
+ #define DEFAULT_POLL_PERIOD 20
+
+ /* Touchscreen commands */
+@@ -17,41 +21,32 @@
+ #define REG_FIRMWARE_VERSION 0x40
+ #define REG_CALIBRATE 0xcc
+
+-struct finger {
+- u8 x_low;
+- u8 x_high;
+- u8 y_low;
+- u8 y_high;
+-} __packed;
+-
+-struct touchdata {
+- u8 status;
+- struct finger finger[MAX_TOUCHES];
+-} __packed;
+-
+-struct panel_info {
+- struct finger finger_max;
+- u8 xchannel_num;
+- u8 ychannel_num;
+-} __packed;
+-
+ struct firmware_version {
+ u8 id;
+ u8 major;
+ u8 minor;
+ } __packed;
+
++enum ili2xxx_model {
++ MODEL_ILI210X,
++ MODEL_ILI251X,
++};
++
+ struct ili210x {
+ struct i2c_client *client;
+ struct input_dev *input;
+- bool (*get_pendown_state)(void);
+ unsigned int poll_period;
+ struct delayed_work dwork;
++ struct gpio_desc *reset_gpio;
++ struct touchscreen_properties prop;
++ enum ili2xxx_model model;
++ unsigned int max_touches;
+ };
+
+ static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
+ size_t len)
+ {
++ struct ili210x *priv = i2c_get_clientdata(client);
+ struct i2c_msg msg[2] = {
+ {
+ .addr = client->addr,
+@@ -67,7 +62,38 @@ static int ili210x_read_reg(struct i2c_c
+ }
+ };
+
+- if (i2c_transfer(client->adapter, msg, 2) != 2) {
++ if (priv->model == MODEL_ILI251X) {
++ if (i2c_transfer(client->adapter, msg, 1) != 1) {
++ dev_err(&client->dev, "i2c transfer failed\n");
++ return -EIO;
++ }
++
++ usleep_range(5000, 5500);
++
++ if (i2c_transfer(client->adapter, msg + 1, 1) != 1) {
++ dev_err(&client->dev, "i2c transfer failed\n");
++ return -EIO;
++ }
++ } else {
++ if (i2c_transfer(client->adapter, msg, 2) != 2) {
++ dev_err(&client->dev, "i2c transfer failed\n");
++ return -EIO;
++ }
++ }
++
++ return 0;
++}
++
++static int ili210x_read(struct i2c_client *client, void *buf, size_t len)
++{
++ struct i2c_msg msg = {
++ .addr = client->addr,
++ .flags = I2C_M_RD,
++ .len = len,
++ .buf = buf,
++ };
++
++ if (i2c_transfer(client->adapter, &msg, 1) != 1) {
+ dev_err(&client->dev, "i2c transfer failed\n");
+ return -EIO;
+ }
+@@ -75,42 +101,72 @@ static int ili210x_read_reg(struct i2c_c
+ return 0;
+ }
+
+-static void ili210x_report_events(struct input_dev *input,
+- const struct touchdata *touchdata)
++static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
++ unsigned int finger,
++ unsigned int *x, unsigned int *y)
+ {
+- int i;
+- bool touch;
+- unsigned int x, y;
+- const struct finger *finger;
++ if (finger >= ILI210X_TOUCHES)
++ return false;
+
+- for (i = 0; i < MAX_TOUCHES; i++) {
+- input_mt_slot(input, i);
++ if (touchdata[0] & BIT(finger))
++ return false;
+
+- finger = &touchdata->finger[i];
++ *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0);
++ *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2);
+
+- touch = touchdata->status & (1 << i);
+- input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+- if (touch) {
+- x = finger->x_low | (finger->x_high << 8);
+- y = finger->y_low | (finger->y_high << 8);
++ return true;
++}
++
++static bool ili251x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
++ unsigned int finger,
++ unsigned int *x, unsigned int *y)
++{
++ if (finger >= ILI251X_TOUCHES)
++ return false;
++
++ *x = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0);
++ if (!(*x & BIT(15))) /* Touch indication */
++ return false;
++
++ *x &= 0x3fff;
++ *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2);
++
++ return true;
++}
++
++static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
++{
++ struct input_dev *input = priv->input;
++ int i;
++ bool contact = false, touch = false;
++ unsigned int x = 0, y = 0;
+
+- input_report_abs(input, ABS_MT_POSITION_X, x);
+- input_report_abs(input, ABS_MT_POSITION_Y, y);
++ for (i = 0; i < priv->max_touches; i++) {
++ if (priv->model == MODEL_ILI210X) {
++ touch = ili210x_touchdata_to_coords(priv, touchdata,
++ i, &x, &y);
++ } else if (priv->model == MODEL_ILI251X) {
++ touch = ili251x_touchdata_to_coords(priv, touchdata,
++ i, &x, &y);
++ if (touch)
++ contact = true;
+ }
++
++ input_mt_slot(input, i);
++ input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
++ if (!touch)
++ continue;
++ touchscreen_report_pos(input, &priv->prop, x, y,
++ true);
+ }
+
+ input_mt_report_pointer_emulation(input, false);
+ input_sync(input);
+-}
+
+-static bool get_pendown_state(const struct ili210x *priv)
+-{
+- bool state = false;
+-
+- if (priv->get_pendown_state)
+- state = priv->get_pendown_state();
++ if (priv->model == MODEL_ILI210X)
++ contact = touchdata[0] & 0xf3;
+
+- return state;
++ return contact;
+ }
+
+ static void ili210x_work(struct work_struct *work)
+@@ -118,20 +174,29 @@ static void ili210x_work(struct work_str
+ struct ili210x *priv = container_of(work, struct ili210x,
+ dwork.work);
+ struct i2c_client *client = priv->client;
+- struct touchdata touchdata;
+- int error;
++ u8 touchdata[64] = { 0 };
++ bool touch;
++ int error = -EINVAL;
++
++ if (priv->model == MODEL_ILI210X) {
++ error = ili210x_read_reg(client, REG_TOUCHDATA,
++ touchdata, sizeof(touchdata));
++ } else if (priv->model == MODEL_ILI251X) {
++ error = ili210x_read_reg(client, REG_TOUCHDATA,
++ touchdata, 31);
++ if (!error && touchdata[0] == 2)
++ error = ili210x_read(client, &touchdata[31], 20);
++ }
+
+- error = ili210x_read_reg(client, REG_TOUCHDATA,
+- &touchdata, sizeof(touchdata));
+ if (error) {
+ dev_err(&client->dev,
+ "Unable to get touchdata, err = %d\n", error);
+ return;
+ }
+
+- ili210x_report_events(priv->input, &touchdata);
++ touch = ili210x_report_events(priv, touchdata);
+
+- if ((touchdata.status & 0xf3) || get_pendown_state(priv))
++ if (touch)
+ schedule_delayed_work(&priv->dwork,
+ msecs_to_jiffies(priv->poll_period));
+ }
+@@ -180,30 +245,76 @@ static const struct attribute_group ili2
+ .attrs = ili210x_attributes,
+ };
+
++static void ili210x_power_down(void *data)
++{
++ struct gpio_desc *reset_gpio = data;
++
++ gpiod_set_value_cansleep(reset_gpio, 1);
++}
++
++static void ili210x_cancel_work(void *data)
++{
++ struct ili210x *priv = data;
++
++ cancel_delayed_work_sync(&priv->dwork);
++}
++
+ static int ili210x_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+ struct device *dev = &client->dev;
+- const struct ili210x_platform_data *pdata = dev_get_platdata(dev);
+ struct ili210x *priv;
++ struct gpio_desc *reset_gpio;
+ struct input_dev *input;
+- struct panel_info panel;
+ struct firmware_version firmware;
+- int xmax, ymax;
++ enum ili2xxx_model model;
+ int error;
+
+- dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
++ model = (enum ili2xxx_model)id->driver_data;
+
+- if (!pdata) {
+- dev_err(dev, "No platform data!\n");
+- return -EINVAL;
+- }
++ dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
+
+ if (client->irq <= 0) {
+ dev_err(dev, "No IRQ!\n");
+ return -EINVAL;
+ }
+
++ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
++ if (IS_ERR(reset_gpio))
++ return PTR_ERR(reset_gpio);
++
++ if (reset_gpio) {
++ error = devm_add_action_or_reset(dev, ili210x_power_down,
++ reset_gpio);
++ if (error)
++ return error;
++
++ usleep_range(50, 100);
++ gpiod_set_value_cansleep(reset_gpio, 0);
++ msleep(100);
++ }
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ input = devm_input_allocate_device(dev);
++ if (!input)
++ return -ENOMEM;
++
++ priv->client = client;
++ priv->input = input;
++ priv->poll_period = DEFAULT_POLL_PERIOD;
++ INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
++ priv->reset_gpio = reset_gpio;
++ priv->model = model;
++ if (model == MODEL_ILI210X)
++ priv->max_touches = ILI210X_TOUCHES;
++ if (model == MODEL_ILI251X)
++ priv->max_touches = ILI251X_TOUCHES;
++
++ i2c_set_clientdata(client, priv);
++
+ /* Get firmware version */
+ error = ili210x_read_reg(client, REG_FIRMWARE_VERSION,
+ &firmware, sizeof(firmware));
+@@ -213,70 +324,40 @@ static int ili210x_i2c_probe(struct i2c_
+ return error;
+ }
+
+- /* get panel info */
+- error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel));
+- if (error) {
+- dev_err(dev, "Failed to get panel information, err: %d\n",
+- error);
+- return error;
+- }
+-
+- xmax = panel.finger_max.x_low | (panel.finger_max.x_high << 8);
+- ymax = panel.finger_max.y_low | (panel.finger_max.y_high << 8);
+-
+- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+- input = input_allocate_device();
+- if (!priv || !input) {
+- error = -ENOMEM;
+- goto err_free_mem;
+- }
+-
+- priv->client = client;
+- priv->input = input;
+- priv->get_pendown_state = pdata->get_pendown_state;
+- priv->poll_period = pdata->poll_period ? : DEFAULT_POLL_PERIOD;
+- INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
+-
+ /* Setup input device */
+ input->name = "ILI210x Touchscreen";
+ input->id.bustype = BUS_I2C;
+ input->dev.parent = dev;
+
+- __set_bit(EV_SYN, input->evbit);
+- __set_bit(EV_KEY, input->evbit);
+- __set_bit(EV_ABS, input->evbit);
+- __set_bit(BTN_TOUCH, input->keybit);
+-
+- /* Single touch */
+- input_set_abs_params(input, ABS_X, 0, xmax, 0, 0);
+- input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
+-
+ /* Multi touch */
+- input_mt_init_slots(input, MAX_TOUCHES, 0);
+- input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0);
+- input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0);
++ input_set_abs_params(input, ABS_MT_POSITION_X, 0, 0xffff, 0, 0);
++ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 0xffff, 0, 0);
++ touchscreen_parse_properties(input, true, &priv->prop);
++ input_mt_init_slots(input, priv->max_touches, INPUT_MT_DIRECT);
+
+- i2c_set_clientdata(client, priv);
++ error = devm_add_action(dev, ili210x_cancel_work, priv);
++ if (error)
++ return error;
+
+- error = request_irq(client->irq, ili210x_irq, pdata->irq_flags,
+- client->name, priv);
++ error = devm_request_irq(dev, client->irq, ili210x_irq, 0,
++ client->name, priv);
+ if (error) {
+ dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
+ error);
+- goto err_free_mem;
++ return error;
+ }
+
+- error = sysfs_create_group(&dev->kobj, &ili210x_attr_group);
++ error = devm_device_add_group(dev, &ili210x_attr_group);
+ if (error) {
+ dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
+ error);
+- goto err_free_irq;
++ return error;
+ }
+
+ error = input_register_device(priv->input);
+ if (error) {
+ dev_err(dev, "Cannot register input device, err: %d\n", error);
+- goto err_remove_sysfs;
++ return error;
+ }
+
+ device_init_wakeup(dev, 1);
+@@ -286,28 +367,6 @@ static int ili210x_i2c_probe(struct i2c_
+ client->irq, firmware.id, firmware.major, firmware.minor);
+
+ return 0;
+-
+-err_remove_sysfs:
+- sysfs_remove_group(&dev->kobj, &ili210x_attr_group);
+-err_free_irq:
+- free_irq(client->irq, priv);
+-err_free_mem:
+- input_free_device(input);
+- kfree(priv);
+- return error;
+-}
+-
+-static int ili210x_i2c_remove(struct i2c_client *client)
+-{
+- struct ili210x *priv = i2c_get_clientdata(client);
+-
+- sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group);
+- free_irq(priv->client->irq, priv);
+- cancel_delayed_work_sync(&priv->dwork);
+- input_unregister_device(priv->input);
+- kfree(priv);
+-
+- return 0;
+ }
+
+ static int __maybe_unused ili210x_i2c_suspend(struct device *dev)
+@@ -334,19 +393,27 @@ static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm,
+ ili210x_i2c_suspend, ili210x_i2c_resume);
+
+ static const struct i2c_device_id ili210x_i2c_id[] = {
+- { "ili210x", 0 },
++ { "ili210x", MODEL_ILI210X },
++ { "ili251x", MODEL_ILI251X },
+ { }
+ };
+ MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
+
++static const struct of_device_id ili210x_dt_ids[] = {
++ { .compatible = "ilitek,ili210x", .data = (void *)MODEL_ILI210X },
++ { .compatible = "ilitek,ili251x", .data = (void *)MODEL_ILI251X },
++ { },
++};
++MODULE_DEVICE_TABLE(of, ili210x_dt_ids);
++
+ static struct i2c_driver ili210x_ts_driver = {
+ .driver = {
+ .name = "ili210x_i2c",
+ .pm = &ili210x_i2c_pm,
++ .of_match_table = ili210x_dt_ids,
+ },
+ .id_table = ili210x_i2c_id,
+ .probe = ili210x_i2c_probe,
+- .remove = ili210x_i2c_remove,
+ };
+
+ module_i2c_driver(ili210x_ts_driver);
+++ /dev/null
-From 1d3aeba25b10d1ed2b5ae4cf0b535d821539a531 Mon Sep 17 00:00:00 2001
-Date: Sun, 17 Mar 2019 16:48:36 -0700
-Subject: [PATCH] dtoverlays: Add Support for the UDRC/DRAWS
-
-Adds a new overlay to support the Northwest Digital Radio
-DRAWS and UDRC HATs. See http://nwdigitalradio.com.
-
----
- arch/arm/boot/dts/overlays/Makefile | 2 +
- arch/arm/boot/dts/overlays/README | 59 ++++++
- arch/arm/boot/dts/overlays/draws-overlay.dts | 200 +++++++++++++++++++
- arch/arm/boot/dts/overlays/udrc-overlay.dts | 128 ++++++++++++
- 4 files changed, 389 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/draws-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/udrc-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -29,6 +29,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- dionaudio-loco-v2.dtbo \
- dpi18.dtbo \
- dpi24.dtbo \
-+ draws.dtbo \
- dwc-otg.dtbo \
- dwc2.dtbo \
- enc28j60.dtbo \
-@@ -146,6 +147,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- tpm-slb9670.dtbo \
- uart0.dtbo \
- uart1.dtbo \
-+ udrc.dtbo \
- upstream.dtbo \
- upstream-aux-interrupt.dtbo \
- vc4-fkms-v3d.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -531,6 +531,59 @@ Load: dtoverlay=dpi24
- Params: <None>
-
-
-+Name: draws
-+Info: Configures the NW Digital Radio DRAWS Hat
-+
-+ The board includes an ADC to measure various board values and also
-+ provides two analog user inputs on the expansion header. The ADC
-+ can be configured for various sample rates and gain values to adjust
-+ the input range. Tables describing the two parameters follow.
-+
-+ ADC Gain Values:
-+ 0 = +/- 6.144V
-+ 1 = +/- 4.096V
-+ 2 = +/- 2.048V
-+ 3 = +/- 1.024V
-+ 4 = +/- 0.512V
-+ 5 = +/- 0.256V
-+ 6 = +/- 0.256V
-+ 7 = +/- 0.256V
-+
-+ ADC Datarate Values:
-+ 0 = 128sps
-+ 1 = 250sps
-+ 2 = 490sps
-+ 3 = 920sps
-+ 4 = 1600sps (default)
-+ 5 = 2400sps
-+ 6 = 3300sps
-+ 7 = 3300sps
-+Load: dtoverlay=draws,<param>=<val>
-+Params: draws_adc_ch4_gain Sets the full scale resolution of the ADCs
-+ input voltage sensor (default 1)
-+
-+ draws_adc_ch4_datarate Sets the datarate of the ADCs input voltage
-+ sensor
-+
-+ draws_adc_ch5_gain Sets the full scale resolution of the ADCs
-+ 5V rail voltage sensor (default 1)
-+
-+ draws_adc_ch5_datarate Sets the datarate of the ADCs 4V rail voltage
-+ sensor
-+
-+ draws_adc_ch6_gain Sets the full scale resolution of the ADCs
-+ AIN2 input (default 2)
-+
-+ draws_adc_ch6_datarate Sets the datarate of the ADCs AIN2 input
-+
-+ draws_adc_ch7_gain Sets the full scale resolution of the ADCs
-+ AIN3 input (default 2)
-+
-+ draws_adc_ch7_datarate Sets the datarate of the ADCs AIN3 input
-+
-+ alsaname Name of the ALSA audio device (default "draws")
-+
-+
- Name: dwc-otg
- Info: Selects the dwc_otg USB controller driver which has fiq support. This
- is the default on all except the Pi Zero which defaults to dwc2.
-@@ -2117,6 +2170,12 @@ Params: txd1_pin GPIO pin
- rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
-
-
-+Name: udrc
-+Info: Configures the NW Digital Radio UDRC Hat
-+Load: dtoverlay=udrc,<param>=<val>
-+Params: alsaname Name of the ALSA audio device (default "udrc")
-+
-+
- Name: upstream
- Info: Allow usage of downstream .dtb with upstream kernel. Comprises
- vc4-kms-v3d, dwc2 and upstream-aux-interrupt overlays.
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/draws-overlay.dts
-@@ -0,0 +1,200 @@
-+#include <dt-bindings/clock/bcm2835.h>
-+/*
-+ * Device tree overlay for the DRAWS Hardware
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+ fragment@0 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target-path = "/";
-+ __overlay__ {
-+ regulators {
-+ compatible = "simple-bus";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ udrc0_ldoin: udrc0_ldoin {
-+ compatible = "regulator-fixed";
-+ regulator-name = "ldoin";
-+ regulator-min-microvolt = <3300000>;
-+ regulator-max-microvolt = <3300000>;
-+ regulator-always-on;
-+ };
-+ };
-+
-+ pps: pps {
-+ compatible = "pps-gpio";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pps_pins>;
-+ gpios = <&gpio 7 0>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c_arm>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ tlv320aic32x4: tlv320aic32x4@18 {
-+ compatible = "ti,tlv320aic32x4";
-+ reg = <0x18>;
-+ #sound-dai-cells = <0>;
-+ status = "okay";
-+
-+ clocks = <&clocks BCM2835_CLOCK_GP0>;
-+ clock-names = "mclk";
-+ assigned-clocks = <&clocks BCM2835_CLOCK_GP0>;
-+ assigned-clock-rates = <25000000>;
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&gpclk0_pin &aic3204_reset>;
-+
-+ reset-gpios = <&gpio 13 0>;
-+
-+ iov-supply = <&udrc0_ldoin>;
-+ ldoin-supply = <&udrc0_ldoin>;
-+ };
-+
-+ sc16is752: sc16is752@50 {
-+ compatible = "nxp,sc16is752";
-+ reg = <0x50>;
-+ clocks = <&sc16is752_clk>;
-+ interrupt-parent = <&gpio>;
-+ interrupts = <17 2>; /* IRQ_TYPE_EDGE_FALLING */
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sc16is752_irq>;
-+
-+ sc16is752_clk: sc16is752_clk {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <1843200>;
-+ };
-+ };
-+
-+ tla2024: tla2024@48 {
-+ compatible = "ti,ads1015";
-+ reg = <0x48>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ adc_ch4: channel@4 {
-+ reg = <4>;
-+ ti,gain = <1>;
-+ ti,datarate = <4>;
-+ };
-+
-+ adc_ch5: channel@5 {
-+ reg = <5>;
-+ ti,gain = <1>;
-+ ti,datarate = <4>;
-+ };
-+
-+ adc_ch6: channel@6 {
-+ reg = <6>;
-+ ti,gain = <2>;
-+ ti,datarate = <4>;
-+ };
-+
-+ adc_ch7: channel@7 {
-+ reg = <7>;
-+ ti,gain = <2>;
-+ ti,datarate = <4>;
-+ };
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&sound>;
-+ snd: __overlay__ {
-+ compatible = "simple-audio-card";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+
-+ simple-audio-card,name = "draws";
-+ simple-audio-card,format = "i2s";
-+
-+ simple-audio-card,bitclock-master = <&dailink0_master>;
-+ simple-audio-card,frame-master = <&dailink0_master>;
-+
-+ simple-audio-card,widgets =
-+ "Line", "Line In",
-+ "Line", "Line Out";
-+
-+ simple-audio-card,routing =
-+ "IN1_R", "Line In",
-+ "IN1_L", "Line In",
-+ "CM_L", "Line In",
-+ "CM_R", "Line In",
-+ "Line Out", "LOR",
-+ "Line Out", "LOL";
-+
-+ dailink0_master: simple-audio-card,cpu {
-+ sound-dai = <&i2s>;
-+ };
-+
-+ simple-audio-card,codec {
-+ sound-dai = <&tlv320aic32x4>;
-+ };
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ gpclk0_pin: gpclk0_pin {
-+ brcm,pins = <4>;
-+ brcm,function = <4>;
-+ };
-+
-+ aic3204_reset: aic3204_reset {
-+ brcm,pins = <13>;
-+ brcm,function = <1>;
-+ brcm,pull = <1>;
-+ };
-+
-+ aic3204_gpio: aic3204_gpio {
-+ brcm,pins = <26>;
-+ };
-+
-+ sc16is752_irq: sc16is752_irq {
-+ brcm,pins = <17>;
-+ brcm,function = <0>;
-+ brcm,pull = <2>;
-+ };
-+
-+ pps_pins: pps_pins {
-+ brcm,pins = <7>;
-+ brcm,function = <0>;
-+ brcm,pull = <0>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ draws_adc_ch4_gain = <&adc_ch4>,"ti,gain:0";
-+ draws_adc_ch4_datarate = <&adc_ch4>,"ti,datarate:0";
-+ draws_adc_ch5_gain = <&adc_ch5>,"ti,gain:0";
-+ draws_adc_ch5_datarate = <&adc_ch5>,"ti,datarate:0";
-+ draws_adc_ch6_gain = <&adc_ch6>,"ti,gain:0";
-+ draws_adc_ch6_datarate = <&adc_ch6>,"ti,datarate:0";
-+ draws_adc_ch7_gain = <&adc_ch7>,"ti,gain:0";
-+ draws_adc_ch7_datarate = <&adc_ch7>,"ti,datarate:0";
-+ alsaname = <&snd>, "simple-audio-card,name";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/udrc-overlay.dts
-@@ -0,0 +1,128 @@
-+#include <dt-bindings/clock/bcm2835.h>
-+/*
-+ * Device tree overlay for the Universal Digital Radio Controller
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+ fragment@0 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ clocks = <&clocks BCM2835_CLOCK_PCM>;
-+ clock-names = "pcm";
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target-path = "/";
-+ __overlay__ {
-+ regulators {
-+ compatible = "simple-bus";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ udrc0_ldoin: udrc0_ldoin {
-+ compatible = "regulator-fixed";
-+ regulator-name = "ldoin";
-+ regulator-min-microvolt = <3300000>;
-+ regulator-max-microvolt = <3300000>;
-+ regulator-always-on;
-+ };
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ clock-frequency = <400000>;
-+
-+ tlv320aic32x4: tlv320aic32x4@18 {
-+ compatible = "ti,tlv320aic32x4";
-+ #sound-dai-cells = <0>;
-+ reg = <0x18>;
-+ status = "okay";
-+
-+ clocks = <&clocks BCM2835_CLOCK_GP0>;
-+ clock-names = "mclk";
-+ assigned-clocks = <&clocks BCM2835_CLOCK_GP0>;
-+ assigned-clock-rates = <25000000>;
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&gpclk0_pin &aic3204_reset>;
-+
-+ reset-gpios = <&gpio 13 0>;
-+
-+ iov-supply = <&udrc0_ldoin>;
-+ ldoin-supply = <&udrc0_ldoin>;
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&sound>;
-+ snd: __overlay__ {
-+ compatible = "simple-audio-card";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+
-+ simple-audio-card,name = "udrc";
-+ simple-audio-card,format = "i2s";
-+
-+ simple-audio-card,bitclock-master = <&dailink0_master>;
-+ simple-audio-card,frame-master = <&dailink0_master>;
-+
-+ simple-audio-card,widgets =
-+ "Line", "Line In",
-+ "Line", "Line Out";
-+
-+ simple-audio-card,routing =
-+ "IN1_R", "Line In",
-+ "IN1_L", "Line In",
-+ "CM_L", "Line In",
-+ "CM_R", "Line In",
-+ "Line Out", "LOR",
-+ "Line Out", "LOL";
-+
-+ dailink0_master: simple-audio-card,cpu {
-+ sound-dai = <&i2s>;
-+ };
-+
-+ simple-audio-card,codec {
-+ sound-dai = <&tlv320aic32x4>;
-+ };
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ gpclk0_pin: gpclk0_pin {
-+ brcm,pins = <4>;
-+ brcm,function = <4>;
-+ };
-+
-+ aic3204_reset: aic3204_reset {
-+ brcm,pins = <13>;
-+ brcm,function = <1>;
-+ brcm,pull = <1>;
-+ };
-+
-+ aic3204_gpio: aic3204_gpio {
-+ brcm,pins = <26>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ alsaname = <&snd>, "simple-audio-card,name";
-+ };
-+};
--- /dev/null
+From 9ee66e1acf33fd1dcf4beb8a6fce4fdade01ab05 Mon Sep 17 00:00:00 2001
+Date: Mon, 8 Apr 2019 16:49:51 +0200
+Subject: [PATCH] Input: ili210x - add DT binding document
+
+commit 41a852e002e65ab7a1e6841b485d72d022e95df2 upstream
+
+Add DT binding document for the Ilitek ILI210x and ILI251x
+touchscreen controllers.
+
+---
+ .../bindings/input/ilitek,ili2xxx.txt | 26 +++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/input/ilitek,ili2xxx.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/input/ilitek,ili2xxx.txt
+@@ -0,0 +1,26 @@
++Ilitek ILI210x/ILI251x touchscreen controller
++
++Required properties:
++- compatible:
++ ilitek,ili210x for ILI210x
++ ilitek,ili251x for ILI251x
++
++- reg: The I2C address of the device
++
++- interrupts: The sink for the touchscreen's IRQ output
++ See ../interrupt-controller/interrupts.txt
++
++Optional properties for main touchpad device:
++
++- reset-gpios: GPIO specifier for the touchscreen's reset pin (active low)
++
++Example:
++
++ touchscreen@41 {
++ compatible = "ilitek,ili251x";
++ reg = <0x41>;
++ interrupt-parent = <&gpio4>;
++ interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
++ reset-gpios = <&gpio5 21 GPIO_ACTIVE_LOW>;
++ };
++
+++ /dev/null
-From 0c988aed71773be4481b886ccf03c40a52f57cdb Mon Sep 17 00:00:00 2001
-Date: Mon, 8 Apr 2019 12:45:23 +0100
-Subject: [PATCH] dwc_otg: only do_split when we actually need to do a
- split
-
-The previous test would fail if the root port was in fullspeed mode
-and there was a hub between the FS device and the root port. While
-the transfer worked, the schedule mangling performed for high-speed
-split transfers would break leading to an 8ms polling interval.
----
- drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 9 ++++-----
- 1 file changed, 4 insertions(+), 5 deletions(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
-@@ -167,8 +167,10 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_ot
- char *speed, *type;
- int dev_speed;
- uint32_t hub_addr, hub_port;
-+ hprt0_data_t hprt;
-
- dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
-+ hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
-
- /* Initialize QH */
- qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
-@@ -191,9 +193,8 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_ot
-
- qh->nak_frame = 0xffff;
-
-- if (((dev_speed == USB_SPEED_LOW) ||
-- (dev_speed == USB_SPEED_FULL)) &&
-- (hub_addr != 0 && hub_addr != 1)) {
-+ if (hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED &&
-+ dev_speed != USB_SPEED_HIGH) {
- DWC_DEBUGPL(DBG_HCD,
- "QH init: EP %d: TT found at hub addr %d, for port %d\n",
- dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
-@@ -204,7 +205,6 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_ot
-
- if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
- /* Compute scheduling parameters once and save them. */
-- hprt0_data_t hprt;
-
- /** @todo Account for split transfers in the bus time. */
- int bytecount =
-@@ -219,7 +219,6 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_ot
- SCHEDULE_SLOP);
- qh->interval = urb->interval;
-
-- hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
- if (hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) {
- if (dev_speed == USB_SPEED_LOW ||
- dev_speed == USB_SPEED_FULL) {
--- /dev/null
+From c0dfc87e355a7c6e434122e1a4fcc69729970610 Mon Sep 17 00:00:00 2001
+Date: Mon, 8 Apr 2019 17:06:44 +0200
+Subject: [PATCH] BCM2708: Add core Device Tree support, ilitek251x
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 11 +++++
+ .../boot/dts/overlays/ilitek251x-overlay.dts | 45 +++++++++++++++++++
+ 3 files changed, 57 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/ilitek251x-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -67,6 +67,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ i2c0-bcm2708.dtbo \
+ i2c1-bcm2708.dtbo \
+ i2s-gpio28-31.dtbo \
++ ilitek251x.dtbo \
+ iqaudio-dac.dtbo \
+ iqaudio-dacplus.dtbo \
+ iqaudio-digi-wm8804-audio.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1146,6 +1146,17 @@ Load: dtoverlay=i2s-gpio28-31
+ Params: <None>
+
+
++Name: ilitek251x
++Info: Enables I2C connected Ilitek 251x multiple touch controller using
++ GPIO 4 (pin 7 on GPIO header) for interrupt.
++Load: dtoverlay=ilitek251x,<param>=<val>
++Params: interrupt GPIO used for interrupt (default 4)
++ sizex Touchscreen size x, horizontal resolution of
++ touchscreen (in pixels)
++ sizey Touchscreen size y, vertical resolution of
++ touchscreen (in pixels)
++
++
+ Name: iqaudio-dac
+ Info: Configures the IQaudio DAC audio card
+ Load: dtoverlay=iqaudio-dac,<param>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/ilitek251x-overlay.dts
+@@ -0,0 +1,45 @@
++// Device tree overlay for I2C connected Ilitek multiple touch controller
++/dts-v1/;
++/plugin/;
++
++ / {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&gpio>;
++ __overlay__ {
++ ili251x_pins: ili251x_pins {
++ brcm,pins = <4>; // interrupt
++ brcm,function = <0>; // in
++ brcm,pull = <2>; // pull-up //
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ ili251x: ili251x@41 {
++ compatible = "ilitek,ili251x";
++ reg = <0x41>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&ili251x_pins>;
++ interrupt-parent = <&gpio>;
++ interrupts = <4 8>; // high-to-low edge triggered
++ touchscreen-size-x = <16384>;
++ touchscreen-size-y = <9600>;
++ };
++ };
++ };
++
++ __overrides__ {
++ interrupt = <&ili251x_pins>,"brcm,pins:0",
++ <&ili251x>,"interrupts:0";
++ sizex = <&ili251x>,"touchscreen-size-x:0";
++ sizey = <&ili251x>,"touchscreen-size-y:0";
++ };
++};
+++ /dev/null
-From 9c823e2ee1ec1b815b8ec29c231b112c5e397202 Mon Sep 17 00:00:00 2001
-Date: Mon, 8 Apr 2019 16:42:17 +0200
-Subject: [PATCH] Input: ili210x - fetch touchscreen geometry from DT
-
-commit f67cc3e927d8414ad3872e046764534ea1f5db0d upstream
-
-Fetching the geometry from the ILI251x registers seems unreliable and
-sometimes returns all zeroes. Add support for fetching the geometry and
-axis inversion from DT instead.
-
----
- drivers/input/touchscreen/ili210x.c | 321 +++++++++++++++++-----------
- 1 file changed, 194 insertions(+), 127 deletions(-)
-
---- a/drivers/input/touchscreen/ili210x.c
-+++ b/drivers/input/touchscreen/ili210x.c
-@@ -4,11 +4,15 @@
- #include <linux/slab.h>
- #include <linux/input.h>
- #include <linux/input/mt.h>
-+#include <linux/input/touchscreen.h>
- #include <linux/delay.h>
- #include <linux/workqueue.h>
--#include <linux/input/ili210x.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/of_device.h>
-+#include <asm/unaligned.h>
-
--#define MAX_TOUCHES 2
-+#define ILI210X_TOUCHES 2
-+#define ILI251X_TOUCHES 10
- #define DEFAULT_POLL_PERIOD 20
-
- /* Touchscreen commands */
-@@ -17,41 +21,32 @@
- #define REG_FIRMWARE_VERSION 0x40
- #define REG_CALIBRATE 0xcc
-
--struct finger {
-- u8 x_low;
-- u8 x_high;
-- u8 y_low;
-- u8 y_high;
--} __packed;
--
--struct touchdata {
-- u8 status;
-- struct finger finger[MAX_TOUCHES];
--} __packed;
--
--struct panel_info {
-- struct finger finger_max;
-- u8 xchannel_num;
-- u8 ychannel_num;
--} __packed;
--
- struct firmware_version {
- u8 id;
- u8 major;
- u8 minor;
- } __packed;
-
-+enum ili2xxx_model {
-+ MODEL_ILI210X,
-+ MODEL_ILI251X,
-+};
-+
- struct ili210x {
- struct i2c_client *client;
- struct input_dev *input;
-- bool (*get_pendown_state)(void);
- unsigned int poll_period;
- struct delayed_work dwork;
-+ struct gpio_desc *reset_gpio;
-+ struct touchscreen_properties prop;
-+ enum ili2xxx_model model;
-+ unsigned int max_touches;
- };
-
- static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
- size_t len)
- {
-+ struct ili210x *priv = i2c_get_clientdata(client);
- struct i2c_msg msg[2] = {
- {
- .addr = client->addr,
-@@ -67,7 +62,38 @@ static int ili210x_read_reg(struct i2c_c
- }
- };
-
-- if (i2c_transfer(client->adapter, msg, 2) != 2) {
-+ if (priv->model == MODEL_ILI251X) {
-+ if (i2c_transfer(client->adapter, msg, 1) != 1) {
-+ dev_err(&client->dev, "i2c transfer failed\n");
-+ return -EIO;
-+ }
-+
-+ usleep_range(5000, 5500);
-+
-+ if (i2c_transfer(client->adapter, msg + 1, 1) != 1) {
-+ dev_err(&client->dev, "i2c transfer failed\n");
-+ return -EIO;
-+ }
-+ } else {
-+ if (i2c_transfer(client->adapter, msg, 2) != 2) {
-+ dev_err(&client->dev, "i2c transfer failed\n");
-+ return -EIO;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int ili210x_read(struct i2c_client *client, void *buf, size_t len)
-+{
-+ struct i2c_msg msg = {
-+ .addr = client->addr,
-+ .flags = I2C_M_RD,
-+ .len = len,
-+ .buf = buf,
-+ };
-+
-+ if (i2c_transfer(client->adapter, &msg, 1) != 1) {
- dev_err(&client->dev, "i2c transfer failed\n");
- return -EIO;
- }
-@@ -75,42 +101,72 @@ static int ili210x_read_reg(struct i2c_c
- return 0;
- }
-
--static void ili210x_report_events(struct input_dev *input,
-- const struct touchdata *touchdata)
-+static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
-+ unsigned int finger,
-+ unsigned int *x, unsigned int *y)
- {
-- int i;
-- bool touch;
-- unsigned int x, y;
-- const struct finger *finger;
-+ if (finger >= ILI210X_TOUCHES)
-+ return false;
-
-- for (i = 0; i < MAX_TOUCHES; i++) {
-- input_mt_slot(input, i);
-+ if (touchdata[0] & BIT(finger))
-+ return false;
-
-- finger = &touchdata->finger[i];
-+ *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0);
-+ *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2);
-
-- touch = touchdata->status & (1 << i);
-- input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
-- if (touch) {
-- x = finger->x_low | (finger->x_high << 8);
-- y = finger->y_low | (finger->y_high << 8);
-+ return true;
-+}
-+
-+static bool ili251x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
-+ unsigned int finger,
-+ unsigned int *x, unsigned int *y)
-+{
-+ if (finger >= ILI251X_TOUCHES)
-+ return false;
-+
-+ *x = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0);
-+ if (!(*x & BIT(15))) /* Touch indication */
-+ return false;
-+
-+ *x &= 0x3fff;
-+ *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2);
-+
-+ return true;
-+}
-+
-+static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
-+{
-+ struct input_dev *input = priv->input;
-+ int i;
-+ bool contact = false, touch = false;
-+ unsigned int x = 0, y = 0;
-
-- input_report_abs(input, ABS_MT_POSITION_X, x);
-- input_report_abs(input, ABS_MT_POSITION_Y, y);
-+ for (i = 0; i < priv->max_touches; i++) {
-+ if (priv->model == MODEL_ILI210X) {
-+ touch = ili210x_touchdata_to_coords(priv, touchdata,
-+ i, &x, &y);
-+ } else if (priv->model == MODEL_ILI251X) {
-+ touch = ili251x_touchdata_to_coords(priv, touchdata,
-+ i, &x, &y);
-+ if (touch)
-+ contact = true;
- }
-+
-+ input_mt_slot(input, i);
-+ input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
-+ if (!touch)
-+ continue;
-+ touchscreen_report_pos(input, &priv->prop, x, y,
-+ true);
- }
-
- input_mt_report_pointer_emulation(input, false);
- input_sync(input);
--}
-
--static bool get_pendown_state(const struct ili210x *priv)
--{
-- bool state = false;
--
-- if (priv->get_pendown_state)
-- state = priv->get_pendown_state();
-+ if (priv->model == MODEL_ILI210X)
-+ contact = touchdata[0] & 0xf3;
-
-- return state;
-+ return contact;
- }
-
- static void ili210x_work(struct work_struct *work)
-@@ -118,20 +174,29 @@ static void ili210x_work(struct work_str
- struct ili210x *priv = container_of(work, struct ili210x,
- dwork.work);
- struct i2c_client *client = priv->client;
-- struct touchdata touchdata;
-- int error;
-+ u8 touchdata[64] = { 0 };
-+ bool touch;
-+ int error = -EINVAL;
-+
-+ if (priv->model == MODEL_ILI210X) {
-+ error = ili210x_read_reg(client, REG_TOUCHDATA,
-+ touchdata, sizeof(touchdata));
-+ } else if (priv->model == MODEL_ILI251X) {
-+ error = ili210x_read_reg(client, REG_TOUCHDATA,
-+ touchdata, 31);
-+ if (!error && touchdata[0] == 2)
-+ error = ili210x_read(client, &touchdata[31], 20);
-+ }
-
-- error = ili210x_read_reg(client, REG_TOUCHDATA,
-- &touchdata, sizeof(touchdata));
- if (error) {
- dev_err(&client->dev,
- "Unable to get touchdata, err = %d\n", error);
- return;
- }
-
-- ili210x_report_events(priv->input, &touchdata);
-+ touch = ili210x_report_events(priv, touchdata);
-
-- if ((touchdata.status & 0xf3) || get_pendown_state(priv))
-+ if (touch)
- schedule_delayed_work(&priv->dwork,
- msecs_to_jiffies(priv->poll_period));
- }
-@@ -180,30 +245,76 @@ static const struct attribute_group ili2
- .attrs = ili210x_attributes,
- };
-
-+static void ili210x_power_down(void *data)
-+{
-+ struct gpio_desc *reset_gpio = data;
-+
-+ gpiod_set_value_cansleep(reset_gpio, 1);
-+}
-+
-+static void ili210x_cancel_work(void *data)
-+{
-+ struct ili210x *priv = data;
-+
-+ cancel_delayed_work_sync(&priv->dwork);
-+}
-+
- static int ili210x_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
- {
- struct device *dev = &client->dev;
-- const struct ili210x_platform_data *pdata = dev_get_platdata(dev);
- struct ili210x *priv;
-+ struct gpio_desc *reset_gpio;
- struct input_dev *input;
-- struct panel_info panel;
- struct firmware_version firmware;
-- int xmax, ymax;
-+ enum ili2xxx_model model;
- int error;
-
-- dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
-+ model = (enum ili2xxx_model)id->driver_data;
-
-- if (!pdata) {
-- dev_err(dev, "No platform data!\n");
-- return -EINVAL;
-- }
-+ dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
-
- if (client->irq <= 0) {
- dev_err(dev, "No IRQ!\n");
- return -EINVAL;
- }
-
-+ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
-+ if (IS_ERR(reset_gpio))
-+ return PTR_ERR(reset_gpio);
-+
-+ if (reset_gpio) {
-+ error = devm_add_action_or_reset(dev, ili210x_power_down,
-+ reset_gpio);
-+ if (error)
-+ return error;
-+
-+ usleep_range(50, 100);
-+ gpiod_set_value_cansleep(reset_gpio, 0);
-+ msleep(100);
-+ }
-+
-+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ input = devm_input_allocate_device(dev);
-+ if (!input)
-+ return -ENOMEM;
-+
-+ priv->client = client;
-+ priv->input = input;
-+ priv->poll_period = DEFAULT_POLL_PERIOD;
-+ INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
-+ priv->reset_gpio = reset_gpio;
-+ priv->model = model;
-+ if (model == MODEL_ILI210X)
-+ priv->max_touches = ILI210X_TOUCHES;
-+ if (model == MODEL_ILI251X)
-+ priv->max_touches = ILI251X_TOUCHES;
-+
-+ i2c_set_clientdata(client, priv);
-+
- /* Get firmware version */
- error = ili210x_read_reg(client, REG_FIRMWARE_VERSION,
- &firmware, sizeof(firmware));
-@@ -213,70 +324,40 @@ static int ili210x_i2c_probe(struct i2c_
- return error;
- }
-
-- /* get panel info */
-- error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel));
-- if (error) {
-- dev_err(dev, "Failed to get panel information, err: %d\n",
-- error);
-- return error;
-- }
--
-- xmax = panel.finger_max.x_low | (panel.finger_max.x_high << 8);
-- ymax = panel.finger_max.y_low | (panel.finger_max.y_high << 8);
--
-- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-- input = input_allocate_device();
-- if (!priv || !input) {
-- error = -ENOMEM;
-- goto err_free_mem;
-- }
--
-- priv->client = client;
-- priv->input = input;
-- priv->get_pendown_state = pdata->get_pendown_state;
-- priv->poll_period = pdata->poll_period ? : DEFAULT_POLL_PERIOD;
-- INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
--
- /* Setup input device */
- input->name = "ILI210x Touchscreen";
- input->id.bustype = BUS_I2C;
- input->dev.parent = dev;
-
-- __set_bit(EV_SYN, input->evbit);
-- __set_bit(EV_KEY, input->evbit);
-- __set_bit(EV_ABS, input->evbit);
-- __set_bit(BTN_TOUCH, input->keybit);
--
-- /* Single touch */
-- input_set_abs_params(input, ABS_X, 0, xmax, 0, 0);
-- input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
--
- /* Multi touch */
-- input_mt_init_slots(input, MAX_TOUCHES, 0);
-- input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0);
-- input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0);
-+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, 0xffff, 0, 0);
-+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 0xffff, 0, 0);
-+ touchscreen_parse_properties(input, true, &priv->prop);
-+ input_mt_init_slots(input, priv->max_touches, INPUT_MT_DIRECT);
-
-- i2c_set_clientdata(client, priv);
-+ error = devm_add_action(dev, ili210x_cancel_work, priv);
-+ if (error)
-+ return error;
-
-- error = request_irq(client->irq, ili210x_irq, pdata->irq_flags,
-- client->name, priv);
-+ error = devm_request_irq(dev, client->irq, ili210x_irq, 0,
-+ client->name, priv);
- if (error) {
- dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
- error);
-- goto err_free_mem;
-+ return error;
- }
-
-- error = sysfs_create_group(&dev->kobj, &ili210x_attr_group);
-+ error = devm_device_add_group(dev, &ili210x_attr_group);
- if (error) {
- dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
- error);
-- goto err_free_irq;
-+ return error;
- }
-
- error = input_register_device(priv->input);
- if (error) {
- dev_err(dev, "Cannot register input device, err: %d\n", error);
-- goto err_remove_sysfs;
-+ return error;
- }
-
- device_init_wakeup(dev, 1);
-@@ -286,28 +367,6 @@ static int ili210x_i2c_probe(struct i2c_
- client->irq, firmware.id, firmware.major, firmware.minor);
-
- return 0;
--
--err_remove_sysfs:
-- sysfs_remove_group(&dev->kobj, &ili210x_attr_group);
--err_free_irq:
-- free_irq(client->irq, priv);
--err_free_mem:
-- input_free_device(input);
-- kfree(priv);
-- return error;
--}
--
--static int ili210x_i2c_remove(struct i2c_client *client)
--{
-- struct ili210x *priv = i2c_get_clientdata(client);
--
-- sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group);
-- free_irq(priv->client->irq, priv);
-- cancel_delayed_work_sync(&priv->dwork);
-- input_unregister_device(priv->input);
-- kfree(priv);
--
-- return 0;
- }
-
- static int __maybe_unused ili210x_i2c_suspend(struct device *dev)
-@@ -334,19 +393,27 @@ static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm,
- ili210x_i2c_suspend, ili210x_i2c_resume);
-
- static const struct i2c_device_id ili210x_i2c_id[] = {
-- { "ili210x", 0 },
-+ { "ili210x", MODEL_ILI210X },
-+ { "ili251x", MODEL_ILI251X },
- { }
- };
- MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
-
-+static const struct of_device_id ili210x_dt_ids[] = {
-+ { .compatible = "ilitek,ili210x", .data = (void *)MODEL_ILI210X },
-+ { .compatible = "ilitek,ili251x", .data = (void *)MODEL_ILI251X },
-+ { },
-+};
-+MODULE_DEVICE_TABLE(of, ili210x_dt_ids);
-+
- static struct i2c_driver ili210x_ts_driver = {
- .driver = {
- .name = "ili210x_i2c",
- .pm = &ili210x_i2c_pm,
-+ .of_match_table = ili210x_dt_ids,
- },
- .id_table = ili210x_i2c_id,
- .probe = ili210x_i2c_probe,
-- .remove = ili210x_i2c_remove,
- };
-
- module_i2c_driver(ili210x_ts_driver);
+++ /dev/null
-From 9ee66e1acf33fd1dcf4beb8a6fce4fdade01ab05 Mon Sep 17 00:00:00 2001
-Date: Mon, 8 Apr 2019 16:49:51 +0200
-Subject: [PATCH] Input: ili210x - add DT binding document
-
-commit 41a852e002e65ab7a1e6841b485d72d022e95df2 upstream
-
-Add DT binding document for the Ilitek ILI210x and ILI251x
-touchscreen controllers.
-
----
- .../bindings/input/ilitek,ili2xxx.txt | 26 +++++++++++++++++++
- 1 file changed, 26 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/input/ilitek,ili2xxx.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/input/ilitek,ili2xxx.txt
-@@ -0,0 +1,26 @@
-+Ilitek ILI210x/ILI251x touchscreen controller
-+
-+Required properties:
-+- compatible:
-+ ilitek,ili210x for ILI210x
-+ ilitek,ili251x for ILI251x
-+
-+- reg: The I2C address of the device
-+
-+- interrupts: The sink for the touchscreen's IRQ output
-+ See ../interrupt-controller/interrupts.txt
-+
-+Optional properties for main touchpad device:
-+
-+- reset-gpios: GPIO specifier for the touchscreen's reset pin (active low)
-+
-+Example:
-+
-+ touchscreen@41 {
-+ compatible = "ilitek,ili251x";
-+ reg = <0x41>;
-+ interrupt-parent = <&gpio4>;
-+ interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
-+ reset-gpios = <&gpio5 21 GPIO_ACTIVE_LOW>;
-+ };
-+
--- /dev/null
+From ea7ff2070d564858c445cfdbd883ea00927c0ada Mon Sep 17 00:00:00 2001
+Date: Tue, 9 Apr 2019 16:40:48 +0100
+Subject: [PATCH] dwc_otg: fix locking around dequeueing and killing
+ URBs
+
+kill_urbs_in_qh_list() is practically only ever called with the fiq lock
+already held, so don't spinlock twice in the case where we need to cancel
+an isochronous transfer.
+
+Also fix up a case where the global interrupt register could be read with
+the fiq lock not held.
+
+Fixes the deadlock seen in https://github.com/raspberrypi/linux/issues/2907
+---
+ drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 9 +++++++--
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4 ----
+ 2 files changed, 7 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
+@@ -1344,16 +1344,21 @@ static inline uint32_t dwc_otg_read_comm
+ */
+ gintmsk_common.b.portintr = 1;
+ }
+- gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
+- gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
+ if(fiq_enable) {
+ local_fiq_disable();
++ fiq_fsm_spin_lock(&hcd->fiq_state->lock);
++ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++ gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
+ /* Pull in the interrupts that the FIQ has masked */
+ gintmsk.d32 |= ~(hcd->fiq_state->gintmsk_saved.d32);
+ gintmsk.d32 |= gintmsk_common.d32;
+ /* for the upstairs function to reenable - have to read it here in case FIQ triggers again */
+ reenable_gintmsk->d32 = gintmsk.d32;
++ fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
+ local_fiq_enable();
++ } else {
++ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++ gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
+ }
+
+ gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+@@ -195,15 +195,11 @@ static void kill_urbs_in_qh_list(dwc_otg
+ * but not yet been through the IRQ handler.
+ */
+ if (fiq_fsm_enable && (hcd->fiq_state->channel[qh->channel->hc_num].fsm != FIQ_PASSTHROUGH)) {
+- local_fiq_disable();
+- fiq_fsm_spin_lock(&hcd->fiq_state->lock);
+ qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
+ qh->channel->halt_pending = 1;
+ if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO ||
+ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
+ hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED;
+- fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
+- local_fiq_enable();
+ } else {
+ dwc_otg_hc_halt(hcd->core_if, qh->channel,
+ DWC_OTG_HC_XFER_URB_DEQUEUE);
+++ /dev/null
-From c0dfc87e355a7c6e434122e1a4fcc69729970610 Mon Sep 17 00:00:00 2001
-Date: Mon, 8 Apr 2019 17:06:44 +0200
-Subject: [PATCH] BCM2708: Add core Device Tree support, ilitek251x
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 11 +++++
- .../boot/dts/overlays/ilitek251x-overlay.dts | 45 +++++++++++++++++++
- 3 files changed, 57 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/ilitek251x-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -67,6 +67,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- i2c0-bcm2708.dtbo \
- i2c1-bcm2708.dtbo \
- i2s-gpio28-31.dtbo \
-+ ilitek251x.dtbo \
- iqaudio-dac.dtbo \
- iqaudio-dacplus.dtbo \
- iqaudio-digi-wm8804-audio.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1146,6 +1146,17 @@ Load: dtoverlay=i2s-gpio28-31
- Params: <None>
-
-
-+Name: ilitek251x
-+Info: Enables I2C connected Ilitek 251x multiple touch controller using
-+ GPIO 4 (pin 7 on GPIO header) for interrupt.
-+Load: dtoverlay=ilitek251x,<param>=<val>
-+Params: interrupt GPIO used for interrupt (default 4)
-+ sizex Touchscreen size x, horizontal resolution of
-+ touchscreen (in pixels)
-+ sizey Touchscreen size y, vertical resolution of
-+ touchscreen (in pixels)
-+
-+
- Name: iqaudio-dac
- Info: Configures the IQaudio DAC audio card
- Load: dtoverlay=iqaudio-dac,<param>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/ilitek251x-overlay.dts
-@@ -0,0 +1,45 @@
-+// Device tree overlay for I2C connected Ilitek multiple touch controller
-+/dts-v1/;
-+/plugin/;
-+
-+ / {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ ili251x_pins: ili251x_pins {
-+ brcm,pins = <4>; // interrupt
-+ brcm,function = <0>; // in
-+ brcm,pull = <2>; // pull-up //
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ ili251x: ili251x@41 {
-+ compatible = "ilitek,ili251x";
-+ reg = <0x41>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&ili251x_pins>;
-+ interrupt-parent = <&gpio>;
-+ interrupts = <4 8>; // high-to-low edge triggered
-+ touchscreen-size-x = <16384>;
-+ touchscreen-size-y = <9600>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ interrupt = <&ili251x_pins>,"brcm,pins:0",
-+ <&ili251x>,"interrupts:0";
-+ sizex = <&ili251x>,"touchscreen-size-x:0";
-+ sizey = <&ili251x>,"touchscreen-size-y:0";
-+ };
-+};
--- /dev/null
+From fb4e195012c405a04b1a7a86e240ceada0c8aa65 Mon Sep 17 00:00:00 2001
+Date: Fri, 29 Mar 2019 10:53:14 +0000
+Subject: [PATCH] rtc: rv3028: Add backup switchover mode support
+
+---
+ drivers/rtc/rtc-rv3028.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/drivers/rtc/rtc-rv3028.c
++++ b/drivers/rtc/rtc-rv3028.c
+@@ -74,6 +74,7 @@
+
+ #define RV3028_BACKUP_TCE BIT(5)
+ #define RV3028_BACKUP_TCR_MASK GENMASK(1,0)
++#define RV3028_BACKUP_BSM_MASK 0x0C
+
+ #define OFFSET_STEP_PPT 953674
+
+@@ -601,6 +602,7 @@ static int rv3028_probe(struct i2c_clien
+ struct rv3028_data *rv3028;
+ int ret, status;
+ u32 ohms;
++ u8 bsm;
+ struct nvmem_config nvmem_cfg = {
+ .name = "rv3028_nvram",
+ .word_size = 1,
+@@ -671,6 +673,21 @@ static int rv3028_probe(struct i2c_clien
+ if (ret)
+ return ret;
+
++ /* setup backup switchover mode */
++ if (!device_property_read_u8(&client->dev, "backup-switchover-mode",
++ &bsm)) {
++ if (bsm <= 3) {
++ ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP,
++ RV3028_BACKUP_BSM_MASK,
++ (bsm & 0x03) << 2);
++
++ if (ret)
++ return ret;
++ } else {
++ dev_warn(&client->dev, "invalid backup switchover mode value\n");
++ }
++ }
++
+ /* setup trickle charger */
+ if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms",
+ &ohms)) {
--- /dev/null
+From 48598900ebd06f5880b01fcc60e240ea4a04858c Mon Sep 17 00:00:00 2001
+Date: Fri, 29 Mar 2019 10:57:07 +0000
+Subject: [PATCH] dt-bindings: rv3028 backup switchover support
+
+---
+ Documentation/devicetree/bindings/rtc/rtc.txt | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/Documentation/devicetree/bindings/rtc/rtc.txt
++++ b/Documentation/devicetree/bindings/rtc/rtc.txt
+@@ -26,6 +26,7 @@ below.
+ - trickle-diode-disable : Do not use internal trickle charger diode Should be
+ given if internal trickle charger diode should be
+ disabled
++- backup-switchover-mode : Configure RTC backup power supply switch behaviour
+ - wakeup-source : Enables wake up of host system on alarm
+ - quartz-load-femtofarads : The capacitive load of the quartz(x-tal),
+ expressed in femto Farad (fF).
+++ /dev/null
-From ea7ff2070d564858c445cfdbd883ea00927c0ada Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2019 16:40:48 +0100
-Subject: [PATCH] dwc_otg: fix locking around dequeueing and killing
- URBs
-
-kill_urbs_in_qh_list() is practically only ever called with the fiq lock
-already held, so don't spinlock twice in the case where we need to cancel
-an isochronous transfer.
-
-Also fix up a case where the global interrupt register could be read with
-the fiq lock not held.
-
-Fixes the deadlock seen in https://github.com/raspberrypi/linux/issues/2907
----
- drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 9 +++++++--
- drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4 ----
- 2 files changed, 7 insertions(+), 6 deletions(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
-@@ -1344,16 +1344,21 @@ static inline uint32_t dwc_otg_read_comm
- */
- gintmsk_common.b.portintr = 1;
- }
-- gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-- gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
- if(fiq_enable) {
- local_fiq_disable();
-+ fiq_fsm_spin_lock(&hcd->fiq_state->lock);
-+ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
- /* Pull in the interrupts that the FIQ has masked */
- gintmsk.d32 |= ~(hcd->fiq_state->gintmsk_saved.d32);
- gintmsk.d32 |= gintmsk_common.d32;
- /* for the upstairs function to reenable - have to read it here in case FIQ triggers again */
- reenable_gintmsk->d32 = gintmsk.d32;
-+ fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
- local_fiq_enable();
-+ } else {
-+ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
- }
-
- gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-@@ -195,15 +195,11 @@ static void kill_urbs_in_qh_list(dwc_otg
- * but not yet been through the IRQ handler.
- */
- if (fiq_fsm_enable && (hcd->fiq_state->channel[qh->channel->hc_num].fsm != FIQ_PASSTHROUGH)) {
-- local_fiq_disable();
-- fiq_fsm_spin_lock(&hcd->fiq_state->lock);
- qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
- qh->channel->halt_pending = 1;
- if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO ||
- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
- hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED;
-- fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
-- local_fiq_enable();
- } else {
- dwc_otg_hc_halt(hcd->core_if, qh->channel,
- DWC_OTG_HC_XFER_URB_DEQUEUE);
--- /dev/null
+From a2fdc7a590566d99d5261badeecb644664ff0fb3 Mon Sep 17 00:00:00 2001
+Date: Fri, 29 Mar 2019 10:59:55 +0000
+Subject: [PATCH] overlays: Add rv3028 backup switchover support to
+ i2c-rtc
+
+---
+ arch/arm/boot/dts/overlays/README | 3 +++
+ arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 1 +
+ 2 files changed, 4 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1013,6 +1013,9 @@ Params: abx80x Select o
+ wakeup-source Specify that the RTC can be used as a wakeup
+ source
+
++ backup-switchover-mode Backup power supply switch mode. Must be 0 for
++ off or 1 for Vdd < VBackup (RV3028 only)
++
+
+ Name: i2c-rtc-gpio
+ Info: Adds support for a number of I2C Real Time Clock devices
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+@@ -200,6 +200,7 @@
+ trickle-resistor-ohms = <&ds1339>,"trickle-resistor-ohms:0",
+ <&abx80x>,"abracon,tc-resistor",
+ <&rv3028>,"trickle-resistor-ohms:0";
++ backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0";
+ wakeup-source = <&ds1339>,"wakeup-source?",
+ <&ds3231>,"wakeup-source?",
+ <&mcp7940x>,"wakeup-source?",
+++ /dev/null
-From fb4e195012c405a04b1a7a86e240ceada0c8aa65 Mon Sep 17 00:00:00 2001
-Date: Fri, 29 Mar 2019 10:53:14 +0000
-Subject: [PATCH] rtc: rv3028: Add backup switchover mode support
-
----
- drivers/rtc/rtc-rv3028.c | 17 +++++++++++++++++
- 1 file changed, 17 insertions(+)
-
---- a/drivers/rtc/rtc-rv3028.c
-+++ b/drivers/rtc/rtc-rv3028.c
-@@ -74,6 +74,7 @@
-
- #define RV3028_BACKUP_TCE BIT(5)
- #define RV3028_BACKUP_TCR_MASK GENMASK(1,0)
-+#define RV3028_BACKUP_BSM_MASK 0x0C
-
- #define OFFSET_STEP_PPT 953674
-
-@@ -601,6 +602,7 @@ static int rv3028_probe(struct i2c_clien
- struct rv3028_data *rv3028;
- int ret, status;
- u32 ohms;
-+ u8 bsm;
- struct nvmem_config nvmem_cfg = {
- .name = "rv3028_nvram",
- .word_size = 1,
-@@ -671,6 +673,21 @@ static int rv3028_probe(struct i2c_clien
- if (ret)
- return ret;
-
-+ /* setup backup switchover mode */
-+ if (!device_property_read_u8(&client->dev, "backup-switchover-mode",
-+ &bsm)) {
-+ if (bsm <= 3) {
-+ ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP,
-+ RV3028_BACKUP_BSM_MASK,
-+ (bsm & 0x03) << 2);
-+
-+ if (ret)
-+ return ret;
-+ } else {
-+ dev_warn(&client->dev, "invalid backup switchover mode value\n");
-+ }
-+ }
-+
- /* setup trickle charger */
- if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms",
- &ohms)) {
--- /dev/null
+From 5962d99b5efed4297ed5c1807d21b406ab86aef1 Mon Sep 17 00:00:00 2001
+Date: Mon, 15 Apr 2019 10:00:20 +0100
+Subject: [PATCH] Maxim MAX98357A I2S DAC overlay (#2935)
+
+Add overlay for Maxim MAX98357A I2S DAC.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 9 ++
+ .../boot/dts/overlays/max98357a-overlay.dts | 84 +++++++++++++++++++
+ 3 files changed, 94 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/max98357a-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -75,6 +75,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ justboom-dac.dtbo \
+ justboom-digi.dtbo \
+ ltc294x.dtbo \
++ max98357a.dtbo \
+ mbed-dac.dtbo \
+ mcp23017.dtbo \
+ mcp23s17.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1276,6 +1276,15 @@ Params: ltc2941 Select t
+ See the datasheet for more information.
+
+
++Name: max98357a
++Info: Configures the Maxim MAX98357A I2S DAC
++Load: dtoverlay=max98357a,<param>=<val>
++Params: no-sdmode Driver does not manage the state of the DAC's
++ SD_MODE pin (i.e. chip is always on).
++ sdmode-pin integer, GPIO pin connected to the SD_MODE input
++ of the DAC (default GPIO4 if parameter omitted).
++
++
+ Name: mbed-dac
+ Info: Configures the mbed AudioCODEC (TLV320AIC23B)
+ Load: dtoverlay=mbed-dac
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/max98357a-overlay.dts
+@@ -0,0 +1,84 @@
++// Overlay for Maxim MAX98357A audio DAC
++
++// dtparams:
++// no-sdmode - SD_MODE pin not managed by driver.
++// sdmode-pin - Specify GPIO pin to which SD_MODE is connected (default 4).
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++
++ /* Enable I2S */
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ /* DAC whose SD_MODE pin is managed by driver (via GPIO pin) */
++ fragment@1 {
++ target-path = "/";
++ __overlay__ {
++ max98357a_dac: max98357a {
++ compatible = "maxim,max98357a";
++ #sound-dai-cells = <0>;
++ sdmode-gpios = <&gpio 4 0>; /* 2nd word overwritten by sdmode-pin parameter */
++ status = "okay";
++ };
++ };
++ };
++
++ /* DAC whose SD_MODE pin is not managed by driver */
++ fragment@2 {
++ target-path = "/";
++ __dormant__ {
++ max98357a_nsd: max98357a {
++ compatible = "maxim,max98357a";
++ #sound-dai-cells = <0>;
++ status = "okay";
++ };
++ };
++ };
++
++ /* Soundcard connecting I2S to DAC with SD_MODE */
++ fragment@3 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "simple-audio-card";
++ simple-audio-card,format = "i2s";
++ simple-audio-card,name = "MAX98357A";
++ status = "okay";
++ simple-audio-card,cpu {
++ sound-dai = <&i2s>;
++ };
++ simple-audio-card,codec {
++ sound-dai = <&max98357a_dac>;
++ };
++ };
++ };
++
++ /* Soundcard connecting I2S to DAC without SD_MODE */
++ fragment@4 {
++ target = <&sound>;
++ __dormant__ {
++ compatible = "simple-audio-card";
++ simple-audio-card,format = "i2s";
++ simple-audio-card,name = "MAX98357A";
++ status = "okay";
++ simple-audio-card,cpu {
++ sound-dai = <&i2s>;
++ };
++ simple-audio-card,codec {
++ sound-dai = <&max98357a_nsd>;
++ };
++ };
++ };
++
++ __overrides__ {
++ no-sdmode = <0>,"-1+2-3+4";
++ sdmode-pin = <&max98357a_dac>,"sdmode-gpios:4";
++ };
++};
+++ /dev/null
-From 48598900ebd06f5880b01fcc60e240ea4a04858c Mon Sep 17 00:00:00 2001
-Date: Fri, 29 Mar 2019 10:57:07 +0000
-Subject: [PATCH] dt-bindings: rv3028 backup switchover support
-
----
- Documentation/devicetree/bindings/rtc/rtc.txt | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/Documentation/devicetree/bindings/rtc/rtc.txt
-+++ b/Documentation/devicetree/bindings/rtc/rtc.txt
-@@ -26,6 +26,7 @@ below.
- - trickle-diode-disable : Do not use internal trickle charger diode Should be
- given if internal trickle charger diode should be
- disabled
-+- backup-switchover-mode : Configure RTC backup power supply switch behaviour
- - wakeup-source : Enables wake up of host system on alarm
- - quartz-load-femtofarads : The capacitive load of the quartz(x-tal),
- expressed in femto Farad (fF).
+++ /dev/null
-From a2fdc7a590566d99d5261badeecb644664ff0fb3 Mon Sep 17 00:00:00 2001
-Date: Fri, 29 Mar 2019 10:59:55 +0000
-Subject: [PATCH] overlays: Add rv3028 backup switchover support to
- i2c-rtc
-
----
- arch/arm/boot/dts/overlays/README | 3 +++
- arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 1 +
- 2 files changed, 4 insertions(+)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1013,6 +1013,9 @@ Params: abx80x Select o
- wakeup-source Specify that the RTC can be used as a wakeup
- source
-
-+ backup-switchover-mode Backup power supply switch mode. Must be 0 for
-+ off or 1 for Vdd < VBackup (RV3028 only)
-+
-
- Name: i2c-rtc-gpio
- Info: Adds support for a number of I2C Real Time Clock devices
---- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-@@ -200,6 +200,7 @@
- trickle-resistor-ohms = <&ds1339>,"trickle-resistor-ohms:0",
- <&abx80x>,"abracon,tc-resistor",
- <&rv3028>,"trickle-resistor-ohms:0";
-+ backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0";
- wakeup-source = <&ds1339>,"wakeup-source?",
- <&ds3231>,"wakeup-source?",
- <&mcp7940x>,"wakeup-source?",
--- /dev/null
+From d003eff5bc4d19902867ad585292780a94746705 Mon Sep 17 00:00:00 2001
+Date: Thu, 21 Mar 2019 11:19:46 +0000
+Subject: [PATCH] sound: Fixes for audioinjector-octo under 4.19
+
+1. Move the DT alias declaration to the I2C shim in the cases
+where the shim is enabled. This works around a problem caused by a
+4.19 commit [1] that generates DT/OF uevents for I2C drivers.
+
+2. Fix the diagnostics in an error path of the soundcard driver to
+correctly identify the reason for the failure to load.
+
+3. Move the declaration of the clock node in the overlay outside
+the I2C node to avoid warnings.
+
+4. Sort the overlay nodes so that dependencies are only to earlier
+fragments, in an attempt to get runtime dtoverlay application to
+work (it still doesn't...)
+
+See: https://github.com/Audio-Injector/Octo/issues/14
+
+[1] af503716ac14 ("i2c: core: report OF style module alias for devices registered via OF")
+---
+ .../overlays/audioinjector-addons-overlay.dts | 19 ++++++++++++-------
+ sound/soc/bcm/audioinjector-octo-soundcard.c | 2 +-
+ sound/soc/codecs/cs42xx8-i2c.c | 7 +++++++
+ sound/soc/codecs/cs42xx8.c | 2 ++
+ 4 files changed, 22 insertions(+), 8 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
++++ b/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
+@@ -13,6 +13,17 @@
+ };
+
+ fragment@1 {
++ target-path = "/";
++ __overlay__ {
++ cs42448_mclk: codec-mclk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <49152000>;
++ };
++ };
++ };
++
++ fragment@2 {
+ target = <&i2c1>;
+ __overlay__ {
+ #address-cells = <1>;
+@@ -27,16 +38,10 @@
+ clock-names = "mclk";
+ status = "okay";
+ };
+-
+- cs42448_mclk: codec-mclk {
+- compatible = "fixed-clock";
+- #clock-cells = <0>;
+- clock-frequency = <49152000>;
+- };
+ };
+ };
+
+- fragment@2 {
++ fragment@3 {
+ target = <&sound>;
+ snd: __overlay__ {
+ compatible = "ai,audioinjector-octo-soundcard";
+--- a/sound/soc/bcm/audioinjector-octo-soundcard.c
++++ b/sound/soc/bcm/audioinjector-octo-soundcard.c
+@@ -297,7 +297,7 @@ static int audioinjector_octo_probe(stru
+ dai->codec_name = NULL;
+ dai->codec_of_node = codec_node;
+ } else
+- if (!dai->cpu_of_node) {
++ if (!i2s_node) {
+ dev_err(&pdev->dev,
+ "i2s-controller missing or invalid in DT\n");
+ return -EINVAL;
+--- a/sound/soc/codecs/cs42xx8-i2c.c
++++ b/sound/soc/codecs/cs42xx8-i2c.c
+@@ -45,6 +45,13 @@ static struct i2c_device_id cs42xx8_i2c_
+ };
+ MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
+
++const struct of_device_id cs42xx8_of_match[] = {
++ { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
++ { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
++
+ static struct i2c_driver cs42xx8_i2c_driver = {
+ .driver = {
+ .name = "cs42xx8",
+--- a/sound/soc/codecs/cs42xx8.c
++++ b/sound/soc/codecs/cs42xx8.c
+@@ -436,8 +436,10 @@ const struct of_device_id cs42xx8_of_mat
+ { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
+ { /* sentinel */ }
+ };
++#if !IS_ENABLED(CONFIG_SND_SOC_CS42XX8_I2C)
+ MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
+ EXPORT_SYMBOL_GPL(cs42xx8_of_match);
++#endif
+
+ int cs42xx8_probe(struct device *dev, struct regmap *regmap)
+ {
+++ /dev/null
-From 5962d99b5efed4297ed5c1807d21b406ab86aef1 Mon Sep 17 00:00:00 2001
-Date: Mon, 15 Apr 2019 10:00:20 +0100
-Subject: [PATCH] Maxim MAX98357A I2S DAC overlay (#2935)
-
-Add overlay for Maxim MAX98357A I2S DAC.
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 9 ++
- .../boot/dts/overlays/max98357a-overlay.dts | 84 +++++++++++++++++++
- 3 files changed, 94 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/max98357a-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -75,6 +75,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- justboom-dac.dtbo \
- justboom-digi.dtbo \
- ltc294x.dtbo \
-+ max98357a.dtbo \
- mbed-dac.dtbo \
- mcp23017.dtbo \
- mcp23s17.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1276,6 +1276,15 @@ Params: ltc2941 Select t
- See the datasheet for more information.
-
-
-+Name: max98357a
-+Info: Configures the Maxim MAX98357A I2S DAC
-+Load: dtoverlay=max98357a,<param>=<val>
-+Params: no-sdmode Driver does not manage the state of the DAC's
-+ SD_MODE pin (i.e. chip is always on).
-+ sdmode-pin integer, GPIO pin connected to the SD_MODE input
-+ of the DAC (default GPIO4 if parameter omitted).
-+
-+
- Name: mbed-dac
- Info: Configures the mbed AudioCODEC (TLV320AIC23B)
- Load: dtoverlay=mbed-dac
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/max98357a-overlay.dts
-@@ -0,0 +1,84 @@
-+// Overlay for Maxim MAX98357A audio DAC
-+
-+// dtparams:
-+// no-sdmode - SD_MODE pin not managed by driver.
-+// sdmode-pin - Specify GPIO pin to which SD_MODE is connected (default 4).
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+
-+ /* Enable I2S */
-+ fragment@0 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ /* DAC whose SD_MODE pin is managed by driver (via GPIO pin) */
-+ fragment@1 {
-+ target-path = "/";
-+ __overlay__ {
-+ max98357a_dac: max98357a {
-+ compatible = "maxim,max98357a";
-+ #sound-dai-cells = <0>;
-+ sdmode-gpios = <&gpio 4 0>; /* 2nd word overwritten by sdmode-pin parameter */
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ /* DAC whose SD_MODE pin is not managed by driver */
-+ fragment@2 {
-+ target-path = "/";
-+ __dormant__ {
-+ max98357a_nsd: max98357a {
-+ compatible = "maxim,max98357a";
-+ #sound-dai-cells = <0>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ /* Soundcard connecting I2S to DAC with SD_MODE */
-+ fragment@3 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "simple-audio-card";
-+ simple-audio-card,format = "i2s";
-+ simple-audio-card,name = "MAX98357A";
-+ status = "okay";
-+ simple-audio-card,cpu {
-+ sound-dai = <&i2s>;
-+ };
-+ simple-audio-card,codec {
-+ sound-dai = <&max98357a_dac>;
-+ };
-+ };
-+ };
-+
-+ /* Soundcard connecting I2S to DAC without SD_MODE */
-+ fragment@4 {
-+ target = <&sound>;
-+ __dormant__ {
-+ compatible = "simple-audio-card";
-+ simple-audio-card,format = "i2s";
-+ simple-audio-card,name = "MAX98357A";
-+ status = "okay";
-+ simple-audio-card,cpu {
-+ sound-dai = <&i2s>;
-+ };
-+ simple-audio-card,codec {
-+ sound-dai = <&max98357a_nsd>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ no-sdmode = <0>,"-1+2-3+4";
-+ sdmode-pin = <&max98357a_dac>,"sdmode-gpios:4";
-+ };
-+};
--- /dev/null
+From 615467f56356a2054d3a86854d391b7a2e0d5811 Mon Sep 17 00:00:00 2001
+Date: Mon, 29 Apr 2019 19:35:33 +0200
+Subject: [PATCH] overlays: Add PiGlow overlay
+
+The PiGlow is a small add-on board for the Raspberry Pi that provides
+18 individually controllable LEDs (SN3218) and uses the following pins:
+
+P1 & P17 (3V3)
+P2 (5V)
+P3 (SDA)
+P5 (SCL)
+P14 (GND)
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 ++
+ arch/arm/boot/dts/overlays/piglow-overlay.dts | 97 +++++++++++++++++++
+ 3 files changed, 104 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/piglow-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -97,6 +97,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ pi3-disable-wifi.dtbo \
+ pi3-miniuart-bt.dtbo \
+ pibell.dtbo \
++ piglow.dtbo \
+ piscreen.dtbo \
+ piscreen2r.dtbo \
+ pisound.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1532,6 +1532,12 @@ Params: alsaname Set the
+ "PiBell")
+
+
++Name: piglow
++Info: Configures the PiGlow by pimoroni.com
++Load: dtoverlay=piglow
++Params: <None>
++
++
+ Name: piscreen
+ Info: PiScreen display by OzzMaker.com
+ Load: dtoverlay=piscreen,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/piglow-overlay.dts
+@@ -0,0 +1,97 @@
++// Definitions for SN3218 LED driver from Si-En Technology on PiGlow
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2c_arm>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ sn3218@54 {
++ compatible = "si-en,sn3218";
++ reg = <0x54>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ led@1 {
++ reg = <1>;
++ label = "piglow:red:led1";
++ };
++ led@2 {
++ reg = <2>;
++ label = "piglow:orange:led2";
++ };
++ led@3 {
++ reg = <3>;
++ label = "piglow:yellow:led3";
++ };
++ led@4 {
++ reg = <4>;
++ label = "piglow:green:led4";
++ };
++ led@5 {
++ reg = <5>;
++ label = "piglow:blue:led5";
++ };
++ led@6 {
++ reg = <6>;
++ label = "piglow:green:led6";
++ };
++ led@7 {
++ reg = <7>;
++ label = "piglow:red:led7";
++ };
++ led@8 {
++ reg = <8>;
++ label = "piglow:orange:led8";
++ };
++ led@9 {
++ reg = <9>;
++ label = "piglow:yellow:led9";
++ };
++ led@10 {
++ reg = <10>;
++ label = "piglow:white:led10";
++ };
++ led@11 {
++ reg = <11>;
++ label = "piglow:white:led11";
++ };
++ led@12 {
++ reg = <12>;
++ label = "piglow:blue:led12";
++ };
++ led@13 {
++ reg = <13>;
++ label = "piglow:white:led13";
++ };
++ led@14 {
++ reg = <14>;
++ label = "piglow:green:led14";
++ };
++ led@15 {
++ reg = <15>;
++ label = "piglow:blue:led15";
++ };
++ led@16 {
++ reg = <16>;
++ label = "piglow:yellow:led16";
++ };
++ led@17 {
++ reg = <17>;
++ label = "piglow:orange:led17";
++ };
++ led@18 {
++ reg = <18>;
++ label = "piglow:red:led18";
++ };
++ };
++ };
++ };
++};
+++ /dev/null
-From d003eff5bc4d19902867ad585292780a94746705 Mon Sep 17 00:00:00 2001
-Date: Thu, 21 Mar 2019 11:19:46 +0000
-Subject: [PATCH] sound: Fixes for audioinjector-octo under 4.19
-
-1. Move the DT alias declaration to the I2C shim in the cases
-where the shim is enabled. This works around a problem caused by a
-4.19 commit [1] that generates DT/OF uevents for I2C drivers.
-
-2. Fix the diagnostics in an error path of the soundcard driver to
-correctly identify the reason for the failure to load.
-
-3. Move the declaration of the clock node in the overlay outside
-the I2C node to avoid warnings.
-
-4. Sort the overlay nodes so that dependencies are only to earlier
-fragments, in an attempt to get runtime dtoverlay application to
-work (it still doesn't...)
-
-See: https://github.com/Audio-Injector/Octo/issues/14
-
-[1] af503716ac14 ("i2c: core: report OF style module alias for devices registered via OF")
----
- .../overlays/audioinjector-addons-overlay.dts | 19 ++++++++++++-------
- sound/soc/bcm/audioinjector-octo-soundcard.c | 2 +-
- sound/soc/codecs/cs42xx8-i2c.c | 7 +++++++
- sound/soc/codecs/cs42xx8.c | 2 ++
- 4 files changed, 22 insertions(+), 8 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
-@@ -13,6 +13,17 @@
- };
-
- fragment@1 {
-+ target-path = "/";
-+ __overlay__ {
-+ cs42448_mclk: codec-mclk {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <49152000>;
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
- target = <&i2c1>;
- __overlay__ {
- #address-cells = <1>;
-@@ -27,16 +38,10 @@
- clock-names = "mclk";
- status = "okay";
- };
--
-- cs42448_mclk: codec-mclk {
-- compatible = "fixed-clock";
-- #clock-cells = <0>;
-- clock-frequency = <49152000>;
-- };
- };
- };
-
-- fragment@2 {
-+ fragment@3 {
- target = <&sound>;
- snd: __overlay__ {
- compatible = "ai,audioinjector-octo-soundcard";
---- a/sound/soc/bcm/audioinjector-octo-soundcard.c
-+++ b/sound/soc/bcm/audioinjector-octo-soundcard.c
-@@ -297,7 +297,7 @@ static int audioinjector_octo_probe(stru
- dai->codec_name = NULL;
- dai->codec_of_node = codec_node;
- } else
-- if (!dai->cpu_of_node) {
-+ if (!i2s_node) {
- dev_err(&pdev->dev,
- "i2s-controller missing or invalid in DT\n");
- return -EINVAL;
---- a/sound/soc/codecs/cs42xx8-i2c.c
-+++ b/sound/soc/codecs/cs42xx8-i2c.c
-@@ -45,6 +45,13 @@ static struct i2c_device_id cs42xx8_i2c_
- };
- MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
-
-+const struct of_device_id cs42xx8_of_match[] = {
-+ { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
-+ { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
-+
- static struct i2c_driver cs42xx8_i2c_driver = {
- .driver = {
- .name = "cs42xx8",
---- a/sound/soc/codecs/cs42xx8.c
-+++ b/sound/soc/codecs/cs42xx8.c
-@@ -436,8 +436,10 @@ const struct of_device_id cs42xx8_of_mat
- { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
- { /* sentinel */ }
- };
-+#if !IS_ENABLED(CONFIG_SND_SOC_CS42XX8_I2C)
- MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
- EXPORT_SYMBOL_GPL(cs42xx8_of_match);
-+#endif
-
- int cs42xx8_probe(struct device *dev, struct regmap *regmap)
- {
--- /dev/null
+From 96588b9ccaddd69a832a07e2e3f2f3299e6d6c3a Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:30 +0200
+Subject: [PATCH] staging: bcm2835-audio: Clean up mutex locks
+
+commit ce4bb1aa271a97047b80ac917a5d91b54925913b upstream.
+
+snd-bcm2835 driver takes the lock with mutex_lock_interruptible() in
+all places, which don't make sense. Replace them with the simple
+mutex_lock().
+
+Also taking a mutex lock right after creating it for each PCM object
+is nonsense, too. It cannot be racy at that point. We can get rid of
+it.
+
+Last but not least, initializing chip->audio_mutex at each place is
+error-prone. Initialize properly at creating the chip object in
+snd_bcm2835_create() instead.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 18 +++----
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 33 ++-----------
+ .../bcm2835-audio/bcm2835-vchiq.c | 47 ++++---------------
+ .../vc04_services/bcm2835-audio/bcm2835.c | 1 +
+ 4 files changed, 20 insertions(+), 79 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
+@@ -77,8 +77,7 @@ static int snd_bcm2835_ctl_get(struct sn
+ {
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+
+- if (mutex_lock_interruptible(&chip->audio_mutex))
+- return -EINTR;
++ mutex_lock(&chip->audio_mutex);
+
+ BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
+
+@@ -99,8 +98,7 @@ static int snd_bcm2835_ctl_put(struct sn
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+
+- if (mutex_lock_interruptible(&chip->audio_mutex))
+- return -EINTR;
++ mutex_lock(&chip->audio_mutex);
+
+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
+ audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
+@@ -187,8 +185,7 @@ static int snd_bcm2835_spdif_default_get
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ int i;
+
+- if (mutex_lock_interruptible(&chip->audio_mutex))
+- return -EINTR;
++ mutex_lock(&chip->audio_mutex);
+
+ for (i = 0; i < 4; i++)
+ ucontrol->value.iec958.status[i] =
+@@ -205,8 +202,7 @@ static int snd_bcm2835_spdif_default_put
+ unsigned int val = 0;
+ int i, change;
+
+- if (mutex_lock_interruptible(&chip->audio_mutex))
+- return -EINTR;
++ mutex_lock(&chip->audio_mutex);
+
+ for (i = 0; i < 4; i++)
+ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
+@@ -251,8 +247,7 @@ static int snd_bcm2835_spdif_stream_get(
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ int i;
+
+- if (mutex_lock_interruptible(&chip->audio_mutex))
+- return -EINTR;
++ mutex_lock(&chip->audio_mutex);
+
+ for (i = 0; i < 4; i++)
+ ucontrol->value.iec958.status[i] =
+@@ -269,8 +264,7 @@ static int snd_bcm2835_spdif_stream_put(
+ unsigned int val = 0;
+ int i, change;
+
+- if (mutex_lock_interruptible(&chip->audio_mutex))
+- return -EINTR;
++ mutex_lock(&chip->audio_mutex);
+
+ for (i = 0; i < 4; i++)
+ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -99,10 +99,7 @@ static int snd_bcm2835_playback_open_gen
+ int idx;
+ int err;
+
+- if (mutex_lock_interruptible(&chip->audio_mutex)) {
+- audio_error("Interrupted whilst waiting for lock\n");
+- return -EINTR;
+- }
++ mutex_lock(&chip->audio_mutex);
+ audio_info("Alsa open (%d)\n", substream->number);
+ idx = substream->number;
+
+@@ -194,10 +191,7 @@ static int snd_bcm2835_playback_close(st
+ struct bcm2835_alsa_stream *alsa_stream;
+
+ chip = snd_pcm_substream_chip(substream);
+- if (mutex_lock_interruptible(&chip->audio_mutex)) {
+- audio_error("Interrupted whilst waiting for lock\n");
+- return -EINTR;
+- }
++ mutex_lock(&chip->audio_mutex);
+ runtime = substream->runtime;
+ alsa_stream = runtime->private_data;
+
+@@ -274,8 +268,7 @@ static int snd_bcm2835_pcm_prepare(struc
+ int channels;
+ int err;
+
+- if (mutex_lock_interruptible(&chip->audio_mutex))
+- return -EINTR;
++ mutex_lock(&chip->audio_mutex);
+
+ /* notify the vchiq that it should enter spdif passthrough mode by
+ * setting channels=0 (see
+@@ -449,14 +442,9 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
+ struct snd_pcm *pcm;
+ int err;
+
+- mutex_init(&chip->audio_mutex);
+- if (mutex_lock_interruptible(&chip->audio_mutex)) {
+- audio_error("Interrupted whilst waiting for lock\n");
+- return -EINTR;
+- }
+ err = snd_pcm_new(chip->card, "bcm2835 ALSA", 0, numchannels, 0, &pcm);
+ if (err < 0)
+- goto out;
++ return err;
+ pcm->private_data = chip;
+ strcpy(pcm->name, "bcm2835 ALSA");
+ chip->pcm = pcm;
+@@ -474,9 +462,6 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
+ snd_bcm2835_playback_hw.buffer_bytes_max,
+ snd_bcm2835_playback_hw.buffer_bytes_max);
+
+-out:
+- mutex_unlock(&chip->audio_mutex);
+-
+ return 0;
+ }
+
+@@ -485,13 +470,9 @@ int snd_bcm2835_new_spdif_pcm(struct bcm
+ struct snd_pcm *pcm;
+ int err;
+
+- if (mutex_lock_interruptible(&chip->audio_mutex)) {
+- audio_error("Interrupted whilst waiting for lock\n");
+- return -EINTR;
+- }
+ err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
+ if (err < 0)
+- goto out;
++ return err;
+
+ pcm->private_data = chip;
+ strcpy(pcm->name, "bcm2835 IEC958/HDMI");
+@@ -504,8 +485,6 @@ int snd_bcm2835_new_spdif_pcm(struct bcm
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ snd_bcm2835_playback_spdif_hw.buffer_bytes_max, snd_bcm2835_playback_spdif_hw.buffer_bytes_max);
+-out:
+- mutex_unlock(&chip->audio_mutex);
+
+ return 0;
+ }
+@@ -518,8 +497,6 @@ int snd_bcm2835_new_simple_pcm(struct bc
+ struct snd_pcm *pcm;
+ int err;
+
+- mutex_init(&chip->audio_mutex);
+-
+ err = snd_pcm_new(chip->card, name, 0, numchannels,
+ 0, &pcm);
+ if (err)
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -319,11 +319,7 @@ static int vc_vchi_audio_deinit(struct b
+ }
+
+ LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
+- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
+- instance->num_connections);
+- return -EINTR;
+- }
++ mutex_lock(&instance->vchi_mutex);
+
+ /* Close all VCHI service connections */
+ for (i = 0; i < instance->num_connections; i++) {
+@@ -434,11 +430,7 @@ int bcm2835_audio_open(struct bcm2835_al
+ instance = alsa_stream->instance;
+ LOG_DBG(" instance (%p)\n", instance);
+
+- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections);
+- ret = -EINTR;
+- goto free_wq;
+- }
++ mutex_lock(&instance->vchi_mutex);
+ vchi_service_use(instance->vchi_handle[0]);
+
+ m.type = VC_AUDIO_MSG_TYPE_OPEN;
+@@ -479,11 +471,7 @@ static int bcm2835_audio_set_ctls_chan(s
+ LOG_INFO(" Setting ALSA dest(%d), volume(%d)\n",
+ chip->dest, chip->volume);
+
+- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
+- instance->num_connections);
+- return -EINTR;
+- }
++ mutex_lock(&instance->vchi_mutex);
+ vchi_service_use(instance->vchi_handle[0]);
+
+ instance->result = -1;
+@@ -569,10 +557,7 @@ int bcm2835_audio_set_params(struct bcm2
+ return -EINVAL;
+ }
+
+- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections);
+- return -EINTR;
+- }
++ mutex_lock(&instance->vchi_mutex);
+ vchi_service_use(instance->vchi_handle[0]);
+
+ instance->result = -1;
+@@ -629,11 +614,7 @@ static int bcm2835_audio_start_worker(st
+ int status;
+ int ret;
+
+- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
+- instance->num_connections);
+- return -EINTR;
+- }
++ mutex_lock(&instance->vchi_mutex);
+ vchi_service_use(instance->vchi_handle[0]);
+
+ m.type = VC_AUDIO_MSG_TYPE_START;
+@@ -665,11 +646,7 @@ static int bcm2835_audio_stop_worker(str
+ int status;
+ int ret;
+
+- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
+- instance->num_connections);
+- return -EINTR;
+- }
++ mutex_lock(&instance->vchi_mutex);
+ vchi_service_use(instance->vchi_handle[0]);
+
+ m.type = VC_AUDIO_MSG_TYPE_STOP;
+@@ -704,11 +681,7 @@ int bcm2835_audio_close(struct bcm2835_a
+
+ my_workqueue_quit(alsa_stream);
+
+- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
+- instance->num_connections);
+- return -EINTR;
+- }
++ mutex_lock(&instance->vchi_mutex);
+ vchi_service_use(instance->vchi_handle[0]);
+
+ m.type = VC_AUDIO_MSG_TYPE_CLOSE;
+@@ -761,11 +734,7 @@ static int bcm2835_audio_write_worker(st
+
+ LOG_INFO(" Writing %d bytes from %p\n", count, src);
+
+- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
+- instance->num_connections);
+- return -EINTR;
+- }
++ mutex_lock(&instance->vchi_mutex);
+ vchi_service_use(instance->vchi_handle[0]);
+
+ if (instance->peer_version == 0 &&
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -149,6 +149,7 @@ static int snd_bcm2835_create(struct snd
+ return -ENOMEM;
+
+ chip->card = card;
++ mutex_init(&chip->audio_mutex);
+
+ chip->vchi_ctx = devres_find(card->dev->parent,
+ bcm2835_devm_free_vchi_ctx, NULL, NULL);
+++ /dev/null
-From 615467f56356a2054d3a86854d391b7a2e0d5811 Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Apr 2019 19:35:33 +0200
-Subject: [PATCH] overlays: Add PiGlow overlay
-
-The PiGlow is a small add-on board for the Raspberry Pi that provides
-18 individually controllable LEDs (SN3218) and uses the following pins:
-
-P1 & P17 (3V3)
-P2 (5V)
-P3 (SDA)
-P5 (SCL)
-P14 (GND)
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 6 ++
- arch/arm/boot/dts/overlays/piglow-overlay.dts | 97 +++++++++++++++++++
- 3 files changed, 104 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/piglow-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -97,6 +97,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- pi3-disable-wifi.dtbo \
- pi3-miniuart-bt.dtbo \
- pibell.dtbo \
-+ piglow.dtbo \
- piscreen.dtbo \
- piscreen2r.dtbo \
- pisound.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1532,6 +1532,12 @@ Params: alsaname Set the
- "PiBell")
-
-
-+Name: piglow
-+Info: Configures the PiGlow by pimoroni.com
-+Load: dtoverlay=piglow
-+Params: <None>
-+
-+
- Name: piscreen
- Info: PiScreen display by OzzMaker.com
- Load: dtoverlay=piscreen,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/piglow-overlay.dts
-@@ -0,0 +1,97 @@
-+// Definitions for SN3218 LED driver from Si-En Technology on PiGlow
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&i2c_arm>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ sn3218@54 {
-+ compatible = "si-en,sn3218";
-+ reg = <0x54>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ led@1 {
-+ reg = <1>;
-+ label = "piglow:red:led1";
-+ };
-+ led@2 {
-+ reg = <2>;
-+ label = "piglow:orange:led2";
-+ };
-+ led@3 {
-+ reg = <3>;
-+ label = "piglow:yellow:led3";
-+ };
-+ led@4 {
-+ reg = <4>;
-+ label = "piglow:green:led4";
-+ };
-+ led@5 {
-+ reg = <5>;
-+ label = "piglow:blue:led5";
-+ };
-+ led@6 {
-+ reg = <6>;
-+ label = "piglow:green:led6";
-+ };
-+ led@7 {
-+ reg = <7>;
-+ label = "piglow:red:led7";
-+ };
-+ led@8 {
-+ reg = <8>;
-+ label = "piglow:orange:led8";
-+ };
-+ led@9 {
-+ reg = <9>;
-+ label = "piglow:yellow:led9";
-+ };
-+ led@10 {
-+ reg = <10>;
-+ label = "piglow:white:led10";
-+ };
-+ led@11 {
-+ reg = <11>;
-+ label = "piglow:white:led11";
-+ };
-+ led@12 {
-+ reg = <12>;
-+ label = "piglow:blue:led12";
-+ };
-+ led@13 {
-+ reg = <13>;
-+ label = "piglow:white:led13";
-+ };
-+ led@14 {
-+ reg = <14>;
-+ label = "piglow:green:led14";
-+ };
-+ led@15 {
-+ reg = <15>;
-+ label = "piglow:blue:led15";
-+ };
-+ led@16 {
-+ reg = <16>;
-+ label = "piglow:yellow:led16";
-+ };
-+ led@17 {
-+ reg = <17>;
-+ label = "piglow:orange:led17";
-+ };
-+ led@18 {
-+ reg = <18>;
-+ label = "piglow:red:led18";
-+ };
-+ };
-+ };
-+ };
-+};
--- /dev/null
+From a1a77a925422be3f0c48002c2aa6c6d898a37f95 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:31 +0200
+Subject: [PATCH] staging: bcm2835-audio: Remove redundant spdif stream
+ ctls
+
+commit ab91e26229eaca2832df51e13c1285aea3be33ab upstream.
+
+The "IEC958 Playback Stream" control does basically the very same
+thing as "IEC958 Playback Default" redundantly. The former should
+have been stream-specific and restored after closing the stream, but
+we don't do in that way.
+
+Since it's nothing but confusion, remove this fake.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 51 -------------------
+ 1 file changed, 51 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
+@@ -233,48 +233,6 @@ static int snd_bcm2835_spdif_mask_get(st
+ return 0;
+ }
+
+-static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_info *uinfo)
+-{
+- uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+- uinfo->count = 1;
+- return 0;
+-}
+-
+-static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
+-{
+- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+- int i;
+-
+- mutex_lock(&chip->audio_mutex);
+-
+- for (i = 0; i < 4; i++)
+- ucontrol->value.iec958.status[i] =
+- (chip->spdif_status >> (i * 8)) & 0xff;
+-
+- mutex_unlock(&chip->audio_mutex);
+- return 0;
+-}
+-
+-static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
+-{
+- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+- unsigned int val = 0;
+- int i, change;
+-
+- mutex_lock(&chip->audio_mutex);
+-
+- for (i = 0; i < 4; i++)
+- val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
+- change = val != chip->spdif_status;
+- chip->spdif_status = val;
+-
+- mutex_unlock(&chip->audio_mutex);
+- return change;
+-}
+-
+ static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+@@ -290,15 +248,6 @@ static struct snd_kcontrol_new snd_bcm28
+ .info = snd_bcm2835_spdif_mask_info,
+ .get = snd_bcm2835_spdif_mask_get,
+ },
+- {
+- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+- SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+- .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
+- .info = snd_bcm2835_spdif_stream_info,
+- .get = snd_bcm2835_spdif_stream_get,
+- .put = snd_bcm2835_spdif_stream_put,
+- },
+ };
+
+ int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
--- /dev/null
+From 8eb8e04a27188f6abc22d09b4a1fffbec10d45f4 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:32 +0200
+Subject: [PATCH] staging: bcm2835-audio: Clean up include files in
+ bcm2835-ctl.c
+
+commit 821950d3da4bf97bcfedcb812176a0f26b833db0 upstream.
+
+Only a few of them are really needed.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 15 ---------------
+ 1 file changed, 15 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
+@@ -1,23 +1,8 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /* Copyright 2011 Broadcom Corporation. All rights reserved. */
+
+-#include <linux/platform_device.h>
+-#include <linux/init.h>
+-#include <linux/io.h>
+-#include <linux/jiffies.h>
+-#include <linux/slab.h>
+-#include <linux/time.h>
+-#include <linux/wait.h>
+-#include <linux/delay.h>
+-#include <linux/moduleparam.h>
+-#include <linux/sched.h>
+-
+ #include <sound/core.h>
+ #include <sound/control.h>
+-#include <sound/pcm.h>
+-#include <sound/pcm_params.h>
+-#include <sound/rawmidi.h>
+-#include <sound/initval.h>
+ #include <sound/tlv.h>
+ #include <sound/asoundef.h>
+
+++ /dev/null
-From 96588b9ccaddd69a832a07e2e3f2f3299e6d6c3a Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:30 +0200
-Subject: [PATCH] staging: bcm2835-audio: Clean up mutex locks
-
-commit ce4bb1aa271a97047b80ac917a5d91b54925913b upstream.
-
-snd-bcm2835 driver takes the lock with mutex_lock_interruptible() in
-all places, which don't make sense. Replace them with the simple
-mutex_lock().
-
-Also taking a mutex lock right after creating it for each PCM object
-is nonsense, too. It cannot be racy at that point. We can get rid of
-it.
-
-Last but not least, initializing chip->audio_mutex at each place is
-error-prone. Initialize properly at creating the chip object in
-snd_bcm2835_create() instead.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 18 +++----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 33 ++-----------
- .../bcm2835-audio/bcm2835-vchiq.c | 47 ++++---------------
- .../vc04_services/bcm2835-audio/bcm2835.c | 1 +
- 4 files changed, 20 insertions(+), 79 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
-@@ -77,8 +77,7 @@ static int snd_bcm2835_ctl_get(struct sn
- {
- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-
-- if (mutex_lock_interruptible(&chip->audio_mutex))
-- return -EINTR;
-+ mutex_lock(&chip->audio_mutex);
-
- BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
-
-@@ -99,8 +98,7 @@ static int snd_bcm2835_ctl_put(struct sn
- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
- int changed = 0;
-
-- if (mutex_lock_interruptible(&chip->audio_mutex))
-- return -EINTR;
-+ mutex_lock(&chip->audio_mutex);
-
- if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
- audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
-@@ -187,8 +185,7 @@ static int snd_bcm2835_spdif_default_get
- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
- int i;
-
-- if (mutex_lock_interruptible(&chip->audio_mutex))
-- return -EINTR;
-+ mutex_lock(&chip->audio_mutex);
-
- for (i = 0; i < 4; i++)
- ucontrol->value.iec958.status[i] =
-@@ -205,8 +202,7 @@ static int snd_bcm2835_spdif_default_put
- unsigned int val = 0;
- int i, change;
-
-- if (mutex_lock_interruptible(&chip->audio_mutex))
-- return -EINTR;
-+ mutex_lock(&chip->audio_mutex);
-
- for (i = 0; i < 4; i++)
- val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
-@@ -251,8 +247,7 @@ static int snd_bcm2835_spdif_stream_get(
- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
- int i;
-
-- if (mutex_lock_interruptible(&chip->audio_mutex))
-- return -EINTR;
-+ mutex_lock(&chip->audio_mutex);
-
- for (i = 0; i < 4; i++)
- ucontrol->value.iec958.status[i] =
-@@ -269,8 +264,7 @@ static int snd_bcm2835_spdif_stream_put(
- unsigned int val = 0;
- int i, change;
-
-- if (mutex_lock_interruptible(&chip->audio_mutex))
-- return -EINTR;
-+ mutex_lock(&chip->audio_mutex);
-
- for (i = 0; i < 4; i++)
- val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -99,10 +99,7 @@ static int snd_bcm2835_playback_open_gen
- int idx;
- int err;
-
-- if (mutex_lock_interruptible(&chip->audio_mutex)) {
-- audio_error("Interrupted whilst waiting for lock\n");
-- return -EINTR;
-- }
-+ mutex_lock(&chip->audio_mutex);
- audio_info("Alsa open (%d)\n", substream->number);
- idx = substream->number;
-
-@@ -194,10 +191,7 @@ static int snd_bcm2835_playback_close(st
- struct bcm2835_alsa_stream *alsa_stream;
-
- chip = snd_pcm_substream_chip(substream);
-- if (mutex_lock_interruptible(&chip->audio_mutex)) {
-- audio_error("Interrupted whilst waiting for lock\n");
-- return -EINTR;
-- }
-+ mutex_lock(&chip->audio_mutex);
- runtime = substream->runtime;
- alsa_stream = runtime->private_data;
-
-@@ -274,8 +268,7 @@ static int snd_bcm2835_pcm_prepare(struc
- int channels;
- int err;
-
-- if (mutex_lock_interruptible(&chip->audio_mutex))
-- return -EINTR;
-+ mutex_lock(&chip->audio_mutex);
-
- /* notify the vchiq that it should enter spdif passthrough mode by
- * setting channels=0 (see
-@@ -449,14 +442,9 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
- struct snd_pcm *pcm;
- int err;
-
-- mutex_init(&chip->audio_mutex);
-- if (mutex_lock_interruptible(&chip->audio_mutex)) {
-- audio_error("Interrupted whilst waiting for lock\n");
-- return -EINTR;
-- }
- err = snd_pcm_new(chip->card, "bcm2835 ALSA", 0, numchannels, 0, &pcm);
- if (err < 0)
-- goto out;
-+ return err;
- pcm->private_data = chip;
- strcpy(pcm->name, "bcm2835 ALSA");
- chip->pcm = pcm;
-@@ -474,9 +462,6 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
- snd_bcm2835_playback_hw.buffer_bytes_max,
- snd_bcm2835_playback_hw.buffer_bytes_max);
-
--out:
-- mutex_unlock(&chip->audio_mutex);
--
- return 0;
- }
-
-@@ -485,13 +470,9 @@ int snd_bcm2835_new_spdif_pcm(struct bcm
- struct snd_pcm *pcm;
- int err;
-
-- if (mutex_lock_interruptible(&chip->audio_mutex)) {
-- audio_error("Interrupted whilst waiting for lock\n");
-- return -EINTR;
-- }
- err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
- if (err < 0)
-- goto out;
-+ return err;
-
- pcm->private_data = chip;
- strcpy(pcm->name, "bcm2835 IEC958/HDMI");
-@@ -504,8 +485,6 @@ int snd_bcm2835_new_spdif_pcm(struct bcm
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- snd_bcm2835_playback_spdif_hw.buffer_bytes_max, snd_bcm2835_playback_spdif_hw.buffer_bytes_max);
--out:
-- mutex_unlock(&chip->audio_mutex);
-
- return 0;
- }
-@@ -518,8 +497,6 @@ int snd_bcm2835_new_simple_pcm(struct bc
- struct snd_pcm *pcm;
- int err;
-
-- mutex_init(&chip->audio_mutex);
--
- err = snd_pcm_new(chip->card, name, 0, numchannels,
- 0, &pcm);
- if (err)
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -319,11 +319,7 @@ static int vc_vchi_audio_deinit(struct b
- }
-
- LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
-- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
-- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
-- instance->num_connections);
-- return -EINTR;
-- }
-+ mutex_lock(&instance->vchi_mutex);
-
- /* Close all VCHI service connections */
- for (i = 0; i < instance->num_connections; i++) {
-@@ -434,11 +430,7 @@ int bcm2835_audio_open(struct bcm2835_al
- instance = alsa_stream->instance;
- LOG_DBG(" instance (%p)\n", instance);
-
-- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
-- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections);
-- ret = -EINTR;
-- goto free_wq;
-- }
-+ mutex_lock(&instance->vchi_mutex);
- vchi_service_use(instance->vchi_handle[0]);
-
- m.type = VC_AUDIO_MSG_TYPE_OPEN;
-@@ -479,11 +471,7 @@ static int bcm2835_audio_set_ctls_chan(s
- LOG_INFO(" Setting ALSA dest(%d), volume(%d)\n",
- chip->dest, chip->volume);
-
-- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
-- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
-- instance->num_connections);
-- return -EINTR;
-- }
-+ mutex_lock(&instance->vchi_mutex);
- vchi_service_use(instance->vchi_handle[0]);
-
- instance->result = -1;
-@@ -569,10 +557,7 @@ int bcm2835_audio_set_params(struct bcm2
- return -EINVAL;
- }
-
-- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
-- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections);
-- return -EINTR;
-- }
-+ mutex_lock(&instance->vchi_mutex);
- vchi_service_use(instance->vchi_handle[0]);
-
- instance->result = -1;
-@@ -629,11 +614,7 @@ static int bcm2835_audio_start_worker(st
- int status;
- int ret;
-
-- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
-- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
-- instance->num_connections);
-- return -EINTR;
-- }
-+ mutex_lock(&instance->vchi_mutex);
- vchi_service_use(instance->vchi_handle[0]);
-
- m.type = VC_AUDIO_MSG_TYPE_START;
-@@ -665,11 +646,7 @@ static int bcm2835_audio_stop_worker(str
- int status;
- int ret;
-
-- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
-- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
-- instance->num_connections);
-- return -EINTR;
-- }
-+ mutex_lock(&instance->vchi_mutex);
- vchi_service_use(instance->vchi_handle[0]);
-
- m.type = VC_AUDIO_MSG_TYPE_STOP;
-@@ -704,11 +681,7 @@ int bcm2835_audio_close(struct bcm2835_a
-
- my_workqueue_quit(alsa_stream);
-
-- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
-- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
-- instance->num_connections);
-- return -EINTR;
-- }
-+ mutex_lock(&instance->vchi_mutex);
- vchi_service_use(instance->vchi_handle[0]);
-
- m.type = VC_AUDIO_MSG_TYPE_CLOSE;
-@@ -761,11 +734,7 @@ static int bcm2835_audio_write_worker(st
-
- LOG_INFO(" Writing %d bytes from %p\n", count, src);
-
-- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
-- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
-- instance->num_connections);
-- return -EINTR;
-- }
-+ mutex_lock(&instance->vchi_mutex);
- vchi_service_use(instance->vchi_handle[0]);
-
- if (instance->peer_version == 0 &&
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -149,6 +149,7 @@ static int snd_bcm2835_create(struct snd
- return -ENOMEM;
-
- chip->card = card;
-+ mutex_init(&chip->audio_mutex);
-
- chip->vchi_ctx = devres_find(card->dev->parent,
- bcm2835_devm_free_vchi_ctx, NULL, NULL);
+++ /dev/null
-From a1a77a925422be3f0c48002c2aa6c6d898a37f95 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:31 +0200
-Subject: [PATCH] staging: bcm2835-audio: Remove redundant spdif stream
- ctls
-
-commit ab91e26229eaca2832df51e13c1285aea3be33ab upstream.
-
-The "IEC958 Playback Stream" control does basically the very same
-thing as "IEC958 Playback Default" redundantly. The former should
-have been stream-specific and restored after closing the stream, but
-we don't do in that way.
-
-Since it's nothing but confusion, remove this fake.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 51 -------------------
- 1 file changed, 51 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
-@@ -233,48 +233,6 @@ static int snd_bcm2835_spdif_mask_get(st
- return 0;
- }
-
--static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
-- struct snd_ctl_elem_info *uinfo)
--{
-- uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
-- uinfo->count = 1;
-- return 0;
--}
--
--static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
-- struct snd_ctl_elem_value *ucontrol)
--{
-- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-- int i;
--
-- mutex_lock(&chip->audio_mutex);
--
-- for (i = 0; i < 4; i++)
-- ucontrol->value.iec958.status[i] =
-- (chip->spdif_status >> (i * 8)) & 0xff;
--
-- mutex_unlock(&chip->audio_mutex);
-- return 0;
--}
--
--static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
-- struct snd_ctl_elem_value *ucontrol)
--{
-- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-- unsigned int val = 0;
-- int i, change;
--
-- mutex_lock(&chip->audio_mutex);
--
-- for (i = 0; i < 4; i++)
-- val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
-- change = val != chip->spdif_status;
-- chip->spdif_status = val;
--
-- mutex_unlock(&chip->audio_mutex);
-- return change;
--}
--
- static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-@@ -290,15 +248,6 @@ static struct snd_kcontrol_new snd_bcm28
- .info = snd_bcm2835_spdif_mask_info,
- .get = snd_bcm2835_spdif_mask_get,
- },
-- {
-- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-- SNDRV_CTL_ELEM_ACCESS_INACTIVE,
-- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-- .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
-- .info = snd_bcm2835_spdif_stream_info,
-- .get = snd_bcm2835_spdif_stream_get,
-- .put = snd_bcm2835_spdif_stream_put,
-- },
- };
-
- int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
--- /dev/null
+From 1120b4699738a3ee748314c433a96e45182a3411 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:33 +0200
+Subject: [PATCH] staging: bcm2835-audio: Remove redundant substream
+ mask checks
+
+commit 14b1f4cba853a11c7b381ad919622f38eb194bd7 upstream.
+
+The avail_substreams bit mask is checked for the possible racy
+accesses, but this cannot happen in practice; i.e. the assignment and
+the check are superfluous.
+
+Let's rip them off.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 2 --
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 8 --------
+ .../vc04_services/bcm2835-audio/bcm2835-vchiq.c | 17 +++++++----------
+ .../vc04_services/bcm2835-audio/bcm2835.c | 5 +----
+ .../vc04_services/bcm2835-audio/bcm2835.h | 2 --
+ 5 files changed, 8 insertions(+), 26 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
+@@ -64,8 +64,6 @@ static int snd_bcm2835_ctl_get(struct sn
+
+ mutex_lock(&chip->audio_mutex);
+
+- BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
+-
+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
+ ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
+ else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -118,14 +118,6 @@ static int snd_bcm2835_playback_open_gen
+ goto out;
+ }
+
+- /* Check if we are ready */
+- if (!(chip->avail_substreams & (1 << idx))) {
+- /* We are not ready yet */
+- audio_error("substream(%d) device is not ready yet\n", idx);
+- err = -EAGAIN;
+- goto out;
+- }
+-
+ alsa_stream = kzalloc(sizeof(*alsa_stream), GFP_KERNEL);
+ if (!alsa_stream) {
+ err = -ENOMEM;
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -523,16 +523,13 @@ int bcm2835_audio_set_ctls(struct bcm283
+
+ /* change ctls for all substreams */
+ for (i = 0; i < MAX_SUBSTREAMS; i++) {
+- if (chip->avail_substreams & (1 << i)) {
+- if (!chip->alsa_stream[i]) {
+- LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
+- ret = 0;
+- } else if (bcm2835_audio_set_ctls_chan(chip->alsa_stream[i], chip) != 0) {
+- LOG_ERR("Couldn't set the controls for stream %d\n", i);
+- ret = -1;
+- } else {
+- LOG_DBG(" Controls set for stream %d\n", i);
+- }
++ if (!chip->alsa_stream[i])
++ continue;
++ if (bcm2835_audio_set_ctls_chan(chip->alsa_stream[i], chip) != 0) {
++ LOG_ERR("Couldn't set the controls for stream %d\n", i);
++ ret = -1;
++ } else {
++ LOG_DBG(" Controls set for stream %d\n", i);
+ }
+ }
+ return ret;
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -280,7 +280,7 @@ static int snd_add_child_device(struct d
+ struct snd_card *card;
+ struct device *child;
+ struct bcm2835_chip *chip;
+- int err, i;
++ int err;
+
+ child = snd_create_device(device, &audio_driver->driver,
+ audio_driver->driver.name);
+@@ -325,9 +325,6 @@ static int snd_add_child_device(struct d
+ return err;
+ }
+
+- for (i = 0; i < numchans; i++)
+- chip->avail_substreams |= (1 << i);
+-
+ err = snd_card_register(card);
+ if (err) {
+ dev_err(child, "Failed to register card, error %d\n", err);
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -98,8 +98,6 @@ struct bcm2835_chip {
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ struct snd_pcm *pcm_spdif;
+- /* Bitmat for valid reg_base and irq numbers */
+- unsigned int avail_substreams;
+ struct device *dev;
+ struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
+
+++ /dev/null
-From 8eb8e04a27188f6abc22d09b4a1fffbec10d45f4 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:32 +0200
-Subject: [PATCH] staging: bcm2835-audio: Clean up include files in
- bcm2835-ctl.c
-
-commit 821950d3da4bf97bcfedcb812176a0f26b833db0 upstream.
-
-Only a few of them are really needed.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 15 ---------------
- 1 file changed, 15 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
-@@ -1,23 +1,8 @@
- // SPDX-License-Identifier: GPL-2.0
- /* Copyright 2011 Broadcom Corporation. All rights reserved. */
-
--#include <linux/platform_device.h>
--#include <linux/init.h>
--#include <linux/io.h>
--#include <linux/jiffies.h>
--#include <linux/slab.h>
--#include <linux/time.h>
--#include <linux/wait.h>
--#include <linux/delay.h>
--#include <linux/moduleparam.h>
--#include <linux/sched.h>
--
- #include <sound/core.h>
- #include <sound/control.h>
--#include <sound/pcm.h>
--#include <sound/pcm_params.h>
--#include <sound/rawmidi.h>
--#include <sound/initval.h>
- #include <sound/tlv.h>
- #include <sound/asoundef.h>
-
--- /dev/null
+From 31e4f118a750f4ddb2aeaaf02c5f3630fb50a176 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:34 +0200
+Subject: [PATCH] staging: bcm2835-audio: Fix mute controls, volume
+ handling cleanup
+
+commit 495e5a0d83d3902c741771f267a702ae19da8ab6 upstream.
+
+In the current code, the mute control is dealt in a special manner,
+modifying the current volume and saving the old volume, etc. This is
+inconsistent (e.g. change the volume while muted, then unmute), and
+way too complex.
+
+Also, the whole volume handling code has conversion between ALSA
+volume and raw volume values, which can lead to another
+inconsistency and complexity.
+
+This patch simplifies these points:
+- The ALSA volume value is saved in chip->volume
+- volume->mute saves the mute state
+- The mute state is evaluated only when the actual volume is passed to
+ the hardware, bcm2835_audio_set_ctls()
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 84 +++++++------------
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 6 +-
+ .../bcm2835-audio/bcm2835-vchiq.c | 32 ++-----
+ .../vc04_services/bcm2835-audio/bcm2835.h | 5 +-
+ 4 files changed, 45 insertions(+), 82 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
+@@ -12,6 +12,21 @@
+ #define CTRL_VOL_MAX 400
+ #define CTRL_VOL_MIN -10239 /* originally -10240 */
+
++static int bcm2835_audio_set_chip_ctls(struct bcm2835_chip *chip)
++{
++ int i, err = 0;
++
++ /* change ctls for all substreams */
++ for (i = 0; i < MAX_SUBSTREAMS; i++) {
++ if (chip->alsa_stream[i]) {
++ err = bcm2835_audio_set_ctls(chip->alsa_stream[i]);
++ if (err < 0)
++ break;
++ }
++ }
++ return err;
++}
++
+ static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+ {
+@@ -34,29 +49,6 @@ static int snd_bcm2835_ctl_info(struct s
+ return 0;
+ }
+
+-/* toggles mute on or off depending on the value of nmute, and returns
+- * 1 if the mute value was changed, otherwise 0
+- */
+-static int toggle_mute(struct bcm2835_chip *chip, int nmute)
+-{
+- /* if settings are ok, just return 0 */
+- if (chip->mute == nmute)
+- return 0;
+-
+- /* if the sound is muted then we need to unmute */
+- if (chip->mute == CTRL_VOL_MUTE) {
+- chip->volume = chip->old_volume; /* copy the old volume back */
+- audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
+- } else /* otherwise we mute */ {
+- chip->old_volume = chip->volume;
+- chip->volume = 26214; /* set volume to minimum level AKA mute */
+- audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
+- }
+-
+- chip->mute = nmute;
+- return 1;
+-}
+-
+ static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+@@ -65,7 +57,7 @@ static int snd_bcm2835_ctl_get(struct sn
+ mutex_lock(&chip->audio_mutex);
+
+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
+- ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
++ ucontrol->value.integer.value[0] = chip->volume;
+ else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
+ ucontrol->value.integer.value[0] = chip->mute;
+ else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
+@@ -79,38 +71,26 @@ static int snd_bcm2835_ctl_put(struct sn
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
++ int val, *valp;
+ int changed = 0;
+
+- mutex_lock(&chip->audio_mutex);
+-
+- if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
+- audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
+- if (chip->mute == CTRL_VOL_MUTE) {
+- /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
+- changed = 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
+- goto unlock;
+- }
+- if (changed || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
+- chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
+- changed = 1;
+- }
+-
+- } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
+- /* Now implemented */
+- audio_info(" Mute attempted\n");
+- changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
++ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
++ valp = &chip->volume;
++ else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
++ valp = &chip->mute;
++ else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
++ valp = &chip->dest;
++ else
++ return -EINVAL;
+
+- } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
+- if (ucontrol->value.integer.value[0] != chip->dest) {
+- chip->dest = ucontrol->value.integer.value[0];
+- changed = 1;
+- }
++ val = ucontrol->value.integer.value[0];
++ mutex_lock(&chip->audio_mutex);
++ if (val != *valp) {
++ *valp = val;
++ changed = 1;
++ if (bcm2835_audio_set_chip_ctls(chip))
++ dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
+ }
+-
+- if (changed && bcm2835_audio_set_ctls(chip))
+- dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
+-
+-unlock:
+ mutex_unlock(&chip->audio_mutex);
+ return changed;
+ }
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -280,7 +280,7 @@ static int snd_bcm2835_pcm_prepare(struc
+ bcm2835_audio_setup(alsa_stream);
+
+ /* in preparation of the stream, set the controls (volume level) of the stream */
+- bcm2835_audio_set_ctls(alsa_stream->chip);
++ bcm2835_audio_set_ctls(alsa_stream);
+
+ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
+
+@@ -441,7 +441,7 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
+ strcpy(pcm->name, "bcm2835 ALSA");
+ chip->pcm = pcm;
+ chip->dest = AUDIO_DEST_AUTO;
+- chip->volume = alsa2chip(0);
++ chip->volume = 0;
+ chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
+ /* set operators */
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+@@ -498,7 +498,7 @@ int snd_bcm2835_new_simple_pcm(struct bc
+ strcpy(pcm->name, name);
+ chip->pcm = pcm;
+ chip->dest = route;
+- chip->volume = alsa2chip(0);
++ chip->volume = 0;
+ chip->mute = CTRL_VOL_UNMUTE;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -460,11 +460,11 @@ free_wq:
+ return ret;
+ }
+
+-static int bcm2835_audio_set_ctls_chan(struct bcm2835_alsa_stream *alsa_stream,
+- struct bcm2835_chip *chip)
++int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
+ {
+ struct vc_audio_msg m;
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
++ struct bcm2835_chip *chip = alsa_stream->chip;
+ int status;
+ int ret;
+
+@@ -478,7 +478,10 @@ static int bcm2835_audio_set_ctls_chan(s
+
+ m.type = VC_AUDIO_MSG_TYPE_CONTROL;
+ m.u.control.dest = chip->dest;
+- m.u.control.volume = chip->volume;
++ if (!chip->mute)
++ m.u.control.volume = CHIP_MIN_VOLUME;
++ else
++ m.u.control.volume = alsa2chip(chip->volume);
+
+ /* Create the message available completion */
+ init_completion(&instance->msg_avail_comp);
+@@ -514,27 +517,6 @@ unlock:
+ return ret;
+ }
+
+-int bcm2835_audio_set_ctls(struct bcm2835_chip *chip)
+-{
+- int i;
+- int ret = 0;
+-
+- LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
+-
+- /* change ctls for all substreams */
+- for (i = 0; i < MAX_SUBSTREAMS; i++) {
+- if (!chip->alsa_stream[i])
+- continue;
+- if (bcm2835_audio_set_ctls_chan(chip->alsa_stream[i], chip) != 0) {
+- LOG_ERR("Couldn't set the controls for stream %d\n", i);
+- ret = -1;
+- } else {
+- LOG_DBG(" Controls set for stream %d\n", i);
+- }
+- }
+- return ret;
+-}
+-
+ int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int channels, unsigned int samplerate,
+ unsigned int bps)
+@@ -548,7 +530,7 @@ int bcm2835_audio_set_params(struct bcm2
+ channels, samplerate, bps);
+
+ /* resend ctls - alsa_stream may not have been open when first send */
+- ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
++ ret = bcm2835_audio_set_ctls(alsa_stream);
+ if (ret) {
+ LOG_ERR(" Alsa controls not supported\n");
+ return -EINVAL;
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -74,6 +74,8 @@ enum {
+ // convert chip to alsa volume
+ #define chip2alsa(vol) -(((vol) * 100) >> 8)
+
++#define CHIP_MIN_VOLUME 26214 /* minimum level aka mute */
++
+ /* Some constants for values .. */
+ enum snd_bcm2835_route {
+ AUDIO_DEST_AUTO = 0,
+@@ -102,7 +104,6 @@ struct bcm2835_chip {
+ struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
+
+ int volume;
+- int old_volume; /* stores the volume value whist muted */
+ int dest;
+ int mute;
+
+@@ -160,7 +161,7 @@ int bcm2835_audio_set_params(struct bcm2
+ int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream);
+ int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream);
+ int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream);
+-int bcm2835_audio_set_ctls(struct bcm2835_chip *chip);
++int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream);
+ int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int count,
+ void *src);
--- /dev/null
+From 79a3c1a4419b2bf04f6ff5ef84cd74b0456fdd9a Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:35 +0200
+Subject: [PATCH] staging: bcm2835-audio: Remove redundant function
+ calls
+
+commit 124950ebe9fa8547c59e8d4acc8d6c59e6278ed6 upstream.
+
+bcm2835_audio_setup(), bcm2835_audio_flush_buffers() and
+bcm2835_audio_flush_playback_buffers() functions do implement
+nothing.
+
+Also, bcm2835_audio_set_ctls() is already called inside
+bcm2835_audio_set_params(), so the later call is superfluous.
+
+This patch removes these superfluous implementations.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 5 -----
+ .../bcm2835-audio/bcm2835-vchiq.c | 21 -------------------
+ .../vc04_services/bcm2835-audio/bcm2835.h | 3 ---
+ 3 files changed, 29 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -277,11 +277,6 @@ static int snd_bcm2835_pcm_prepare(struc
+ if (err < 0)
+ audio_error(" error setting hw params\n");
+
+- bcm2835_audio_setup(alsa_stream);
+-
+- /* in preparation of the stream, set the controls (volume level) of the stream */
+- bcm2835_audio_set_ctls(alsa_stream);
+-
+ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
+
+ alsa_stream->pcm_indirect.hw_buffer_size =
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -580,12 +580,6 @@ unlock:
+ return ret;
+ }
+
+-int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream)
+-{
+-
+- return 0;
+-}
+-
+ static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
+ {
+ struct vc_audio_msg m;
+@@ -774,21 +768,6 @@ unlock:
+ return ret;
+ }
+
+-/**
+- * Returns all buffers from arm->vc
+- */
+-void bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream *alsa_stream)
+-{
+-}
+-
+-/**
+- * Forces VC to flush(drop) its filled playback buffers and
+- * return them the us. (VC->ARM)
+- */
+-void bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream *alsa_stream)
+-{
+-}
+-
+ unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)
+ {
+ unsigned int count = atomic_read(&alsa_stream->retrieved);
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -158,7 +158,6 @@ int bcm2835_audio_close(struct bcm2835_a
+ int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int channels, unsigned int samplerate,
+ unsigned int bps);
+-int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream);
+ int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream);
+ int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream);
+ int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream);
+@@ -167,7 +166,5 @@ int bcm2835_audio_write(struct bcm2835_a
+ void *src);
+ void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream);
+ unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream);
+-void bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream *alsa_stream);
+-void bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream *alsa_stream);
+
+ #endif /* __SOUND_ARM_BCM2835_H */
+++ /dev/null
-From 1120b4699738a3ee748314c433a96e45182a3411 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:33 +0200
-Subject: [PATCH] staging: bcm2835-audio: Remove redundant substream
- mask checks
-
-commit 14b1f4cba853a11c7b381ad919622f38eb194bd7 upstream.
-
-The avail_substreams bit mask is checked for the possible racy
-accesses, but this cannot happen in practice; i.e. the assignment and
-the check are superfluous.
-
-Let's rip them off.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 2 --
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 8 --------
- .../vc04_services/bcm2835-audio/bcm2835-vchiq.c | 17 +++++++----------
- .../vc04_services/bcm2835-audio/bcm2835.c | 5 +----
- .../vc04_services/bcm2835-audio/bcm2835.h | 2 --
- 5 files changed, 8 insertions(+), 26 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
-@@ -64,8 +64,6 @@ static int snd_bcm2835_ctl_get(struct sn
-
- mutex_lock(&chip->audio_mutex);
-
-- BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
--
- if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
- ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
- else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -118,14 +118,6 @@ static int snd_bcm2835_playback_open_gen
- goto out;
- }
-
-- /* Check if we are ready */
-- if (!(chip->avail_substreams & (1 << idx))) {
-- /* We are not ready yet */
-- audio_error("substream(%d) device is not ready yet\n", idx);
-- err = -EAGAIN;
-- goto out;
-- }
--
- alsa_stream = kzalloc(sizeof(*alsa_stream), GFP_KERNEL);
- if (!alsa_stream) {
- err = -ENOMEM;
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -523,16 +523,13 @@ int bcm2835_audio_set_ctls(struct bcm283
-
- /* change ctls for all substreams */
- for (i = 0; i < MAX_SUBSTREAMS; i++) {
-- if (chip->avail_substreams & (1 << i)) {
-- if (!chip->alsa_stream[i]) {
-- LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
-- ret = 0;
-- } else if (bcm2835_audio_set_ctls_chan(chip->alsa_stream[i], chip) != 0) {
-- LOG_ERR("Couldn't set the controls for stream %d\n", i);
-- ret = -1;
-- } else {
-- LOG_DBG(" Controls set for stream %d\n", i);
-- }
-+ if (!chip->alsa_stream[i])
-+ continue;
-+ if (bcm2835_audio_set_ctls_chan(chip->alsa_stream[i], chip) != 0) {
-+ LOG_ERR("Couldn't set the controls for stream %d\n", i);
-+ ret = -1;
-+ } else {
-+ LOG_DBG(" Controls set for stream %d\n", i);
- }
- }
- return ret;
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -280,7 +280,7 @@ static int snd_add_child_device(struct d
- struct snd_card *card;
- struct device *child;
- struct bcm2835_chip *chip;
-- int err, i;
-+ int err;
-
- child = snd_create_device(device, &audio_driver->driver,
- audio_driver->driver.name);
-@@ -325,9 +325,6 @@ static int snd_add_child_device(struct d
- return err;
- }
-
-- for (i = 0; i < numchans; i++)
-- chip->avail_substreams |= (1 << i);
--
- err = snd_card_register(card);
- if (err) {
- dev_err(child, "Failed to register card, error %d\n", err);
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -98,8 +98,6 @@ struct bcm2835_chip {
- struct snd_card *card;
- struct snd_pcm *pcm;
- struct snd_pcm *pcm_spdif;
-- /* Bitmat for valid reg_base and irq numbers */
-- unsigned int avail_substreams;
- struct device *dev;
- struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
-
+++ /dev/null
-From 31e4f118a750f4ddb2aeaaf02c5f3630fb50a176 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:34 +0200
-Subject: [PATCH] staging: bcm2835-audio: Fix mute controls, volume
- handling cleanup
-
-commit 495e5a0d83d3902c741771f267a702ae19da8ab6 upstream.
-
-In the current code, the mute control is dealt in a special manner,
-modifying the current volume and saving the old volume, etc. This is
-inconsistent (e.g. change the volume while muted, then unmute), and
-way too complex.
-
-Also, the whole volume handling code has conversion between ALSA
-volume and raw volume values, which can lead to another
-inconsistency and complexity.
-
-This patch simplifies these points:
-- The ALSA volume value is saved in chip->volume
-- volume->mute saves the mute state
-- The mute state is evaluated only when the actual volume is passed to
- the hardware, bcm2835_audio_set_ctls()
-
----
- .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 84 +++++++------------
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 6 +-
- .../bcm2835-audio/bcm2835-vchiq.c | 32 ++-----
- .../vc04_services/bcm2835-audio/bcm2835.h | 5 +-
- 4 files changed, 45 insertions(+), 82 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
-@@ -12,6 +12,21 @@
- #define CTRL_VOL_MAX 400
- #define CTRL_VOL_MIN -10239 /* originally -10240 */
-
-+static int bcm2835_audio_set_chip_ctls(struct bcm2835_chip *chip)
-+{
-+ int i, err = 0;
-+
-+ /* change ctls for all substreams */
-+ for (i = 0; i < MAX_SUBSTREAMS; i++) {
-+ if (chip->alsa_stream[i]) {
-+ err = bcm2835_audio_set_ctls(chip->alsa_stream[i]);
-+ if (err < 0)
-+ break;
-+ }
-+ }
-+ return err;
-+}
-+
- static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
-@@ -34,29 +49,6 @@ static int snd_bcm2835_ctl_info(struct s
- return 0;
- }
-
--/* toggles mute on or off depending on the value of nmute, and returns
-- * 1 if the mute value was changed, otherwise 0
-- */
--static int toggle_mute(struct bcm2835_chip *chip, int nmute)
--{
-- /* if settings are ok, just return 0 */
-- if (chip->mute == nmute)
-- return 0;
--
-- /* if the sound is muted then we need to unmute */
-- if (chip->mute == CTRL_VOL_MUTE) {
-- chip->volume = chip->old_volume; /* copy the old volume back */
-- audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
-- } else /* otherwise we mute */ {
-- chip->old_volume = chip->volume;
-- chip->volume = 26214; /* set volume to minimum level AKA mute */
-- audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
-- }
--
-- chip->mute = nmute;
-- return 1;
--}
--
- static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
-@@ -65,7 +57,7 @@ static int snd_bcm2835_ctl_get(struct sn
- mutex_lock(&chip->audio_mutex);
-
- if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
-- ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
-+ ucontrol->value.integer.value[0] = chip->volume;
- else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
- ucontrol->value.integer.value[0] = chip->mute;
- else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
-@@ -79,38 +71,26 @@ static int snd_bcm2835_ctl_put(struct sn
- struct snd_ctl_elem_value *ucontrol)
- {
- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-+ int val, *valp;
- int changed = 0;
-
-- mutex_lock(&chip->audio_mutex);
--
-- if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
-- audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
-- if (chip->mute == CTRL_VOL_MUTE) {
-- /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
-- changed = 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
-- goto unlock;
-- }
-- if (changed || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
-- chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
-- changed = 1;
-- }
--
-- } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
-- /* Now implemented */
-- audio_info(" Mute attempted\n");
-- changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
-+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
-+ valp = &chip->volume;
-+ else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
-+ valp = &chip->mute;
-+ else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
-+ valp = &chip->dest;
-+ else
-+ return -EINVAL;
-
-- } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
-- if (ucontrol->value.integer.value[0] != chip->dest) {
-- chip->dest = ucontrol->value.integer.value[0];
-- changed = 1;
-- }
-+ val = ucontrol->value.integer.value[0];
-+ mutex_lock(&chip->audio_mutex);
-+ if (val != *valp) {
-+ *valp = val;
-+ changed = 1;
-+ if (bcm2835_audio_set_chip_ctls(chip))
-+ dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
- }
--
-- if (changed && bcm2835_audio_set_ctls(chip))
-- dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
--
--unlock:
- mutex_unlock(&chip->audio_mutex);
- return changed;
- }
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -280,7 +280,7 @@ static int snd_bcm2835_pcm_prepare(struc
- bcm2835_audio_setup(alsa_stream);
-
- /* in preparation of the stream, set the controls (volume level) of the stream */
-- bcm2835_audio_set_ctls(alsa_stream->chip);
-+ bcm2835_audio_set_ctls(alsa_stream);
-
- memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
-
-@@ -441,7 +441,7 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
- strcpy(pcm->name, "bcm2835 ALSA");
- chip->pcm = pcm;
- chip->dest = AUDIO_DEST_AUTO;
-- chip->volume = alsa2chip(0);
-+ chip->volume = 0;
- chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
- /* set operators */
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-@@ -498,7 +498,7 @@ int snd_bcm2835_new_simple_pcm(struct bc
- strcpy(pcm->name, name);
- chip->pcm = pcm;
- chip->dest = route;
-- chip->volume = alsa2chip(0);
-+ chip->volume = 0;
- chip->mute = CTRL_VOL_UNMUTE;
-
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -460,11 +460,11 @@ free_wq:
- return ret;
- }
-
--static int bcm2835_audio_set_ctls_chan(struct bcm2835_alsa_stream *alsa_stream,
-- struct bcm2835_chip *chip)
-+int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
- {
- struct vc_audio_msg m;
- struct bcm2835_audio_instance *instance = alsa_stream->instance;
-+ struct bcm2835_chip *chip = alsa_stream->chip;
- int status;
- int ret;
-
-@@ -478,7 +478,10 @@ static int bcm2835_audio_set_ctls_chan(s
-
- m.type = VC_AUDIO_MSG_TYPE_CONTROL;
- m.u.control.dest = chip->dest;
-- m.u.control.volume = chip->volume;
-+ if (!chip->mute)
-+ m.u.control.volume = CHIP_MIN_VOLUME;
-+ else
-+ m.u.control.volume = alsa2chip(chip->volume);
-
- /* Create the message available completion */
- init_completion(&instance->msg_avail_comp);
-@@ -514,27 +517,6 @@ unlock:
- return ret;
- }
-
--int bcm2835_audio_set_ctls(struct bcm2835_chip *chip)
--{
-- int i;
-- int ret = 0;
--
-- LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
--
-- /* change ctls for all substreams */
-- for (i = 0; i < MAX_SUBSTREAMS; i++) {
-- if (!chip->alsa_stream[i])
-- continue;
-- if (bcm2835_audio_set_ctls_chan(chip->alsa_stream[i], chip) != 0) {
-- LOG_ERR("Couldn't set the controls for stream %d\n", i);
-- ret = -1;
-- } else {
-- LOG_DBG(" Controls set for stream %d\n", i);
-- }
-- }
-- return ret;
--}
--
- int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
- unsigned int channels, unsigned int samplerate,
- unsigned int bps)
-@@ -548,7 +530,7 @@ int bcm2835_audio_set_params(struct bcm2
- channels, samplerate, bps);
-
- /* resend ctls - alsa_stream may not have been open when first send */
-- ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
-+ ret = bcm2835_audio_set_ctls(alsa_stream);
- if (ret) {
- LOG_ERR(" Alsa controls not supported\n");
- return -EINVAL;
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -74,6 +74,8 @@ enum {
- // convert chip to alsa volume
- #define chip2alsa(vol) -(((vol) * 100) >> 8)
-
-+#define CHIP_MIN_VOLUME 26214 /* minimum level aka mute */
-+
- /* Some constants for values .. */
- enum snd_bcm2835_route {
- AUDIO_DEST_AUTO = 0,
-@@ -102,7 +104,6 @@ struct bcm2835_chip {
- struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
-
- int volume;
-- int old_volume; /* stores the volume value whist muted */
- int dest;
- int mute;
-
-@@ -160,7 +161,7 @@ int bcm2835_audio_set_params(struct bcm2
- int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream);
- int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream);
- int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream);
--int bcm2835_audio_set_ctls(struct bcm2835_chip *chip);
-+int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream);
- int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
- unsigned int count,
- void *src);
--- /dev/null
+From af2fe52ef43c1aa6a24d1c51ad3ccddc39a12c51 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:36 +0200
+Subject: [PATCH] staging: bcm2835-audio: Remove superfluous open flag
+
+commit ad13924de6b07cb52714ea1809c57b2e72a24504 upstream.
+
+All the alsa_stream->open flag checks in the current code are
+redundant, and they cannot be racy. For the code simplification,
+let's remove the flag and its check.
+
+---
+ .../staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 9 ++-------
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835.h | 1 -
+ 2 files changed, 2 insertions(+), 8 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -57,8 +57,7 @@ void bcm2835_playback_fifo(struct bcm283
+ audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
+ alsa_stream ? alsa_stream->substream : 0);
+
+- if (alsa_stream->open)
+- consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
++ consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
+
+ /* We get called only if playback was triggered, So, the number of buffers we retrieve in
+ * each iteration are the buffers that have been played out already
+@@ -154,7 +153,6 @@ static int snd_bcm2835_playback_open_gen
+ chip->alsa_stream[idx] = alsa_stream;
+
+ chip->opened |= (1 << idx);
+- alsa_stream->open = 1;
+ alsa_stream->draining = 1;
+
+ out:
+@@ -205,10 +203,7 @@ static int snd_bcm2835_playback_close(st
+ alsa_stream->period_size = 0;
+ alsa_stream->buffer_size = 0;
+
+- if (alsa_stream->open) {
+- alsa_stream->open = 0;
+- bcm2835_audio_close(alsa_stream);
+- }
++ bcm2835_audio_close(alsa_stream);
+ if (alsa_stream->chip)
+ alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
+ /*
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -121,7 +121,6 @@ struct bcm2835_alsa_stream {
+
+ spinlock_t lock;
+
+- int open;
+ int running;
+ int draining;
+
--- /dev/null
+From e8a202b4d06a07ba42b91a1dd3c2d9e9cedff32d Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:37 +0200
+Subject: [PATCH] staging: bcm2835-audio: Drop useless running flag and
+ check
+
+commit 02f2376321d75e78117f39ff81f215254ee6b4ef upstream.
+
+The running flag of alsa_stream is basically useless. The running
+state is strictly controlled in ALSA PCM core side, hence the check in
+PCM trigger and close callbacks are superfluous.
+
+Also, the prefill ack at trigger start became superfluous nowadays
+with the ALSA PCM core update.
+
+Let's rip them off.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 46 ++++---------------
+ .../vc04_services/bcm2835-audio/bcm2835.h | 1 -
+ 2 files changed, 8 insertions(+), 39 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -187,19 +187,6 @@ static int snd_bcm2835_playback_close(st
+
+ audio_info("Alsa close\n");
+
+- /*
+- * Call stop if it's still running. This happens when app
+- * is force killed and we don't get a stop trigger.
+- */
+- if (alsa_stream->running) {
+- int err;
+-
+- err = bcm2835_audio_stop(alsa_stream);
+- alsa_stream->running = 0;
+- if (err)
+- audio_error(" Failed to STOP alsa device\n");
+- }
+-
+ alsa_stream->period_size = 0;
+ alsa_stream->buffer_size = 0;
+
+@@ -324,27 +311,13 @@ static int snd_bcm2835_pcm_trigger(struc
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+- audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
+- alsa_stream->running);
+- if (!alsa_stream->running) {
+- err = bcm2835_audio_start(alsa_stream);
+- if (!err) {
+- alsa_stream->pcm_indirect.hw_io =
+- alsa_stream->pcm_indirect.hw_data =
+- bytes_to_frames(runtime,
+- alsa_stream->pos);
+- substream->ops->ack(substream);
+- alsa_stream->running = 1;
+- alsa_stream->draining = 1;
+- } else {
+- audio_error(" Failed to START alsa device (%d)\n", err);
+- }
+- }
++ err = bcm2835_audio_start(alsa_stream);
++ if (!err)
++ alsa_stream->draining = 1;
++ else
++ audio_error(" Failed to START alsa device (%d)\n", err);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+- audio_debug
+- ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
+- alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
+ audio_info("DRAINING\n");
+ alsa_stream->draining = 1;
+@@ -352,12 +325,9 @@ static int snd_bcm2835_pcm_trigger(struc
+ audio_info("DROPPING\n");
+ alsa_stream->draining = 0;
+ }
+- if (alsa_stream->running) {
+- err = bcm2835_audio_stop(alsa_stream);
+- if (err != 0)
+- audio_error(" Failed to STOP alsa device (%d)\n", err);
+- alsa_stream->running = 0;
+- }
++ err = bcm2835_audio_stop(alsa_stream);
++ if (err != 0)
++ audio_error(" Failed to STOP alsa device (%d)\n", err);
+ break;
+ default:
+ err = -EINVAL;
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -121,7 +121,6 @@ struct bcm2835_alsa_stream {
+
+ spinlock_t lock;
+
+- int running;
+ int draining;
+
+ int channels;
+++ /dev/null
-From 79a3c1a4419b2bf04f6ff5ef84cd74b0456fdd9a Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:35 +0200
-Subject: [PATCH] staging: bcm2835-audio: Remove redundant function
- calls
-
-commit 124950ebe9fa8547c59e8d4acc8d6c59e6278ed6 upstream.
-
-bcm2835_audio_setup(), bcm2835_audio_flush_buffers() and
-bcm2835_audio_flush_playback_buffers() functions do implement
-nothing.
-
-Also, bcm2835_audio_set_ctls() is already called inside
-bcm2835_audio_set_params(), so the later call is superfluous.
-
-This patch removes these superfluous implementations.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 5 -----
- .../bcm2835-audio/bcm2835-vchiq.c | 21 -------------------
- .../vc04_services/bcm2835-audio/bcm2835.h | 3 ---
- 3 files changed, 29 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -277,11 +277,6 @@ static int snd_bcm2835_pcm_prepare(struc
- if (err < 0)
- audio_error(" error setting hw params\n");
-
-- bcm2835_audio_setup(alsa_stream);
--
-- /* in preparation of the stream, set the controls (volume level) of the stream */
-- bcm2835_audio_set_ctls(alsa_stream);
--
- memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
-
- alsa_stream->pcm_indirect.hw_buffer_size =
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -580,12 +580,6 @@ unlock:
- return ret;
- }
-
--int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream)
--{
--
-- return 0;
--}
--
- static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
- {
- struct vc_audio_msg m;
-@@ -774,21 +768,6 @@ unlock:
- return ret;
- }
-
--/**
-- * Returns all buffers from arm->vc
-- */
--void bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream *alsa_stream)
--{
--}
--
--/**
-- * Forces VC to flush(drop) its filled playback buffers and
-- * return them the us. (VC->ARM)
-- */
--void bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream *alsa_stream)
--{
--}
--
- unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)
- {
- unsigned int count = atomic_read(&alsa_stream->retrieved);
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -158,7 +158,6 @@ int bcm2835_audio_close(struct bcm2835_a
- int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
- unsigned int channels, unsigned int samplerate,
- unsigned int bps);
--int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream);
- int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream);
- int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream);
- int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream);
-@@ -167,7 +166,5 @@ int bcm2835_audio_write(struct bcm2835_a
- void *src);
- void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream);
- unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream);
--void bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream *alsa_stream);
--void bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream *alsa_stream);
-
- #endif /* __SOUND_ARM_BCM2835_H */
--- /dev/null
+From e5414b543a330c64b2e0b5e96d604cf580c2b9b7 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:38 +0200
+Subject: [PATCH] staging: bcm2835-audio: Fix incorrect draining
+ handling
+
+commit 7d2a91f5f1bcf08ca257bcf1ed9721fcd341f834 upstream.
+
+The handling of SNDRV_PCM_TRIGGER_STOP at the trigger callback is
+incorrect: when the STOP is issued, the driver is supposed to drop the
+stream immediately. Meanwhile bcm2835 driver checks the DRAINING
+state and tries to issue some different command.
+
+This patch straightens things a bit, dropping the incorrect state
+checks. The draining behavior would be still not perfect at this
+point, but will be improved in a later patch.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 18 ++++++------------
+ 1 file changed, 6 insertions(+), 12 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -153,7 +153,6 @@ static int snd_bcm2835_playback_open_gen
+ chip->alsa_stream[idx] = alsa_stream;
+
+ chip->opened |= (1 << idx);
+- alsa_stream->draining = 1;
+
+ out:
+ mutex_unlock(&chip->audio_mutex);
+@@ -268,6 +267,7 @@ static int snd_bcm2835_pcm_prepare(struc
+ alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
+ alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
+ alsa_stream->pos = 0;
++ alsa_stream->draining = false;
+
+ audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
+ alsa_stream->buffer_size, alsa_stream->period_size,
+@@ -312,21 +312,15 @@ static int snd_bcm2835_pcm_trigger(struc
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ err = bcm2835_audio_start(alsa_stream);
+- if (!err)
+- alsa_stream->draining = 1;
+- else
++ if (err)
+ audio_error(" Failed to START alsa device (%d)\n", err);
+ break;
++ case SNDRV_PCM_TRIGGER_DRAIN:
++ alsa_stream->draining = true;
++ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+- if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
+- audio_info("DRAINING\n");
+- alsa_stream->draining = 1;
+- } else {
+- audio_info("DROPPING\n");
+- alsa_stream->draining = 0;
+- }
+ err = bcm2835_audio_stop(alsa_stream);
+- if (err != 0)
++ if (err)
+ audio_error(" Failed to STOP alsa device (%d)\n", err);
+ break;
+ default:
+++ /dev/null
-From af2fe52ef43c1aa6a24d1c51ad3ccddc39a12c51 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:36 +0200
-Subject: [PATCH] staging: bcm2835-audio: Remove superfluous open flag
-
-commit ad13924de6b07cb52714ea1809c57b2e72a24504 upstream.
-
-All the alsa_stream->open flag checks in the current code are
-redundant, and they cannot be racy. For the code simplification,
-let's remove the flag and its check.
-
----
- .../staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 9 ++-------
- drivers/staging/vc04_services/bcm2835-audio/bcm2835.h | 1 -
- 2 files changed, 2 insertions(+), 8 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -57,8 +57,7 @@ void bcm2835_playback_fifo(struct bcm283
- audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
- alsa_stream ? alsa_stream->substream : 0);
-
-- if (alsa_stream->open)
-- consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
-+ consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
-
- /* We get called only if playback was triggered, So, the number of buffers we retrieve in
- * each iteration are the buffers that have been played out already
-@@ -154,7 +153,6 @@ static int snd_bcm2835_playback_open_gen
- chip->alsa_stream[idx] = alsa_stream;
-
- chip->opened |= (1 << idx);
-- alsa_stream->open = 1;
- alsa_stream->draining = 1;
-
- out:
-@@ -205,10 +203,7 @@ static int snd_bcm2835_playback_close(st
- alsa_stream->period_size = 0;
- alsa_stream->buffer_size = 0;
-
-- if (alsa_stream->open) {
-- alsa_stream->open = 0;
-- bcm2835_audio_close(alsa_stream);
-- }
-+ bcm2835_audio_close(alsa_stream);
- if (alsa_stream->chip)
- alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
- /*
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -121,7 +121,6 @@ struct bcm2835_alsa_stream {
-
- spinlock_t lock;
-
-- int open;
- int running;
- int draining;
-
+++ /dev/null
-From e8a202b4d06a07ba42b91a1dd3c2d9e9cedff32d Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:37 +0200
-Subject: [PATCH] staging: bcm2835-audio: Drop useless running flag and
- check
-
-commit 02f2376321d75e78117f39ff81f215254ee6b4ef upstream.
-
-The running flag of alsa_stream is basically useless. The running
-state is strictly controlled in ALSA PCM core side, hence the check in
-PCM trigger and close callbacks are superfluous.
-
-Also, the prefill ack at trigger start became superfluous nowadays
-with the ALSA PCM core update.
-
-Let's rip them off.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 46 ++++---------------
- .../vc04_services/bcm2835-audio/bcm2835.h | 1 -
- 2 files changed, 8 insertions(+), 39 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -187,19 +187,6 @@ static int snd_bcm2835_playback_close(st
-
- audio_info("Alsa close\n");
-
-- /*
-- * Call stop if it's still running. This happens when app
-- * is force killed and we don't get a stop trigger.
-- */
-- if (alsa_stream->running) {
-- int err;
--
-- err = bcm2835_audio_stop(alsa_stream);
-- alsa_stream->running = 0;
-- if (err)
-- audio_error(" Failed to STOP alsa device\n");
-- }
--
- alsa_stream->period_size = 0;
- alsa_stream->buffer_size = 0;
-
-@@ -324,27 +311,13 @@ static int snd_bcm2835_pcm_trigger(struc
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
-- audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
-- alsa_stream->running);
-- if (!alsa_stream->running) {
-- err = bcm2835_audio_start(alsa_stream);
-- if (!err) {
-- alsa_stream->pcm_indirect.hw_io =
-- alsa_stream->pcm_indirect.hw_data =
-- bytes_to_frames(runtime,
-- alsa_stream->pos);
-- substream->ops->ack(substream);
-- alsa_stream->running = 1;
-- alsa_stream->draining = 1;
-- } else {
-- audio_error(" Failed to START alsa device (%d)\n", err);
-- }
-- }
-+ err = bcm2835_audio_start(alsa_stream);
-+ if (!err)
-+ alsa_stream->draining = 1;
-+ else
-+ audio_error(" Failed to START alsa device (%d)\n", err);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
-- audio_debug
-- ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
-- alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
- if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
- audio_info("DRAINING\n");
- alsa_stream->draining = 1;
-@@ -352,12 +325,9 @@ static int snd_bcm2835_pcm_trigger(struc
- audio_info("DROPPING\n");
- alsa_stream->draining = 0;
- }
-- if (alsa_stream->running) {
-- err = bcm2835_audio_stop(alsa_stream);
-- if (err != 0)
-- audio_error(" Failed to STOP alsa device (%d)\n", err);
-- alsa_stream->running = 0;
-- }
-+ err = bcm2835_audio_stop(alsa_stream);
-+ if (err != 0)
-+ audio_error(" Failed to STOP alsa device (%d)\n", err);
- break;
- default:
- err = -EINVAL;
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -121,7 +121,6 @@ struct bcm2835_alsa_stream {
-
- spinlock_t lock;
-
-- int running;
- int draining;
-
- int channels;
--- /dev/null
+From d9aef1329c29c20d8e0db9929a3235bfb1d718d3 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:39 +0200
+Subject: [PATCH] staging: bcm2835-audio: Kill unused spinlock
+
+commit 5332f6f012c0bf3a45c77dbc0f79814443a884d4 upstream.
+
+The alsa_stream->lock is never used. Kill it.
+
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 2 --
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835.h | 2 --
+ 2 files changed, 4 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -128,8 +128,6 @@ static int snd_bcm2835_playback_open_gen
+ alsa_stream->substream = substream;
+ alsa_stream->idx = idx;
+
+- spin_lock_init(&alsa_stream->lock);
+-
+ err = bcm2835_audio_open(alsa_stream);
+ if (err) {
+ kfree(alsa_stream);
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -119,8 +119,6 @@ struct bcm2835_alsa_stream {
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_indirect pcm_indirect;
+
+- spinlock_t lock;
+-
+ int draining;
+
+ int channels;
+++ /dev/null
-From e5414b543a330c64b2e0b5e96d604cf580c2b9b7 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:38 +0200
-Subject: [PATCH] staging: bcm2835-audio: Fix incorrect draining
- handling
-
-commit 7d2a91f5f1bcf08ca257bcf1ed9721fcd341f834 upstream.
-
-The handling of SNDRV_PCM_TRIGGER_STOP at the trigger callback is
-incorrect: when the STOP is issued, the driver is supposed to drop the
-stream immediately. Meanwhile bcm2835 driver checks the DRAINING
-state and tries to issue some different command.
-
-This patch straightens things a bit, dropping the incorrect state
-checks. The draining behavior would be still not perfect at this
-point, but will be improved in a later patch.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 18 ++++++------------
- 1 file changed, 6 insertions(+), 12 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -153,7 +153,6 @@ static int snd_bcm2835_playback_open_gen
- chip->alsa_stream[idx] = alsa_stream;
-
- chip->opened |= (1 << idx);
-- alsa_stream->draining = 1;
-
- out:
- mutex_unlock(&chip->audio_mutex);
-@@ -268,6 +267,7 @@ static int snd_bcm2835_pcm_prepare(struc
- alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
- alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
- alsa_stream->pos = 0;
-+ alsa_stream->draining = false;
-
- audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
- alsa_stream->buffer_size, alsa_stream->period_size,
-@@ -312,21 +312,15 @@ static int snd_bcm2835_pcm_trigger(struc
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- err = bcm2835_audio_start(alsa_stream);
-- if (!err)
-- alsa_stream->draining = 1;
-- else
-+ if (err)
- audio_error(" Failed to START alsa device (%d)\n", err);
- break;
-+ case SNDRV_PCM_TRIGGER_DRAIN:
-+ alsa_stream->draining = true;
-+ break;
- case SNDRV_PCM_TRIGGER_STOP:
-- if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
-- audio_info("DRAINING\n");
-- alsa_stream->draining = 1;
-- } else {
-- audio_info("DROPPING\n");
-- alsa_stream->draining = 0;
-- }
- err = bcm2835_audio_stop(alsa_stream);
-- if (err != 0)
-+ if (err)
- audio_error(" Failed to STOP alsa device (%d)\n", err);
- break;
- default:
--- /dev/null
+From 4efb059f297f8234bc188b6bc1e4af673ce9f9e3 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:40 +0200
+Subject: [PATCH] staging: bcm2835-audio: Use PCM runtime values
+ instead
+
+commit b8f7fdd50890b848e085c0519469aed4ff4d9b54 upstream.
+
+Some fields in alsa_stream are the values we keep already in PCM
+runtime object, hence they are redundant. Use the standard PCM
+runtime values instead of the private copies.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 23 ++++---------------
+ .../vc04_services/bcm2835-audio/bcm2835.h | 4 ----
+ 2 files changed, 4 insertions(+), 23 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -206,22 +206,7 @@ static int snd_bcm2835_playback_close(st
+ static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+ {
+- struct snd_pcm_runtime *runtime = substream->runtime;
+- struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
+- int err;
+-
+- err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+- if (err < 0) {
+- audio_error
+- (" pcm_lib_malloc failed to allocated pages for buffers\n");
+- return err;
+- }
+-
+- alsa_stream->channels = params_channels(params);
+- alsa_stream->params_rate = params_rate(params);
+- alsa_stream->pcm_format_width = snd_pcm_format_width(params_format(params));
+-
+- return err;
++ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+ }
+
+ /* hw_free callback */
+@@ -248,11 +233,11 @@ static int snd_bcm2835_pcm_prepare(struc
+ if (chip->spdif_status & IEC958_AES0_NONAUDIO)
+ channels = 0;
+ else
+- channels = alsa_stream->channels;
++ channels = runtime->channels;
+
+ err = bcm2835_audio_set_params(alsa_stream, channels,
+- alsa_stream->params_rate,
+- alsa_stream->pcm_format_width);
++ runtime->rate,
++ snd_pcm_format_width(runtime->format));
+ if (err < 0)
+ audio_error(" error setting hw params\n");
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -121,10 +121,6 @@ struct bcm2835_alsa_stream {
+
+ int draining;
+
+- int channels;
+- int params_rate;
+- int pcm_format_width;
+-
+ unsigned int pos;
+ unsigned int buffer_size;
+ unsigned int period_size;
--- /dev/null
+From a08260154f88b0b97e3c8de6b3cdb7187e8c3d8a Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:41 +0200
+Subject: [PATCH] staging: bcm2835-audio: Drop unnecessary pcm indirect
+ setup
+
+commit 7318ec896f4856fae2bb013858e422fa078201e1 upstream.
+
+The hw_queue_size of PCM indirect helper doesn't need to be set up if
+you use the whole given buffer size. Drop the useless
+initialization, which just confuses readers.
+
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -280,7 +280,6 @@ static int snd_bcm2835_pcm_ack(struct sn
+ struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
+ struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
+
+- pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
+ return snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
+ snd_bcm2835_pcm_transfer);
+ }
+++ /dev/null
-From d9aef1329c29c20d8e0db9929a3235bfb1d718d3 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:39 +0200
-Subject: [PATCH] staging: bcm2835-audio: Kill unused spinlock
-
-commit 5332f6f012c0bf3a45c77dbc0f79814443a884d4 upstream.
-
-The alsa_stream->lock is never used. Kill it.
-
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 2 --
- drivers/staging/vc04_services/bcm2835-audio/bcm2835.h | 2 --
- 2 files changed, 4 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -128,8 +128,6 @@ static int snd_bcm2835_playback_open_gen
- alsa_stream->substream = substream;
- alsa_stream->idx = idx;
-
-- spin_lock_init(&alsa_stream->lock);
--
- err = bcm2835_audio_open(alsa_stream);
- if (err) {
- kfree(alsa_stream);
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -119,8 +119,6 @@ struct bcm2835_alsa_stream {
- struct snd_pcm_substream *substream;
- struct snd_pcm_indirect pcm_indirect;
-
-- spinlock_t lock;
--
- int draining;
-
- int channels;
--- /dev/null
+From 9f3956e7bbf868894b5aee41110dbe28f117918c Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:42 +0200
+Subject: [PATCH] staging: bcm2835-audio: Drop useless NULL check
+
+commit 8bcf9f252c29c2d5bcce3db605c0ebf1ef230f9c upstream.
+
+alsa_stream->chip can be never NULL.
+
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -188,8 +188,7 @@ static int snd_bcm2835_playback_close(st
+ alsa_stream->buffer_size = 0;
+
+ bcm2835_audio_close(alsa_stream);
+- if (alsa_stream->chip)
+- alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
++ alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
+ /*
+ * Do not free up alsa_stream here, it will be freed up by
+ * runtime->private_free callback we registered in *_open above
+++ /dev/null
-From 4efb059f297f8234bc188b6bc1e4af673ce9f9e3 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:40 +0200
-Subject: [PATCH] staging: bcm2835-audio: Use PCM runtime values
- instead
-
-commit b8f7fdd50890b848e085c0519469aed4ff4d9b54 upstream.
-
-Some fields in alsa_stream are the values we keep already in PCM
-runtime object, hence they are redundant. Use the standard PCM
-runtime values instead of the private copies.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 23 ++++---------------
- .../vc04_services/bcm2835-audio/bcm2835.h | 4 ----
- 2 files changed, 4 insertions(+), 23 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -206,22 +206,7 @@ static int snd_bcm2835_playback_close(st
- static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
- {
-- struct snd_pcm_runtime *runtime = substream->runtime;
-- struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
-- int err;
--
-- err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-- if (err < 0) {
-- audio_error
-- (" pcm_lib_malloc failed to allocated pages for buffers\n");
-- return err;
-- }
--
-- alsa_stream->channels = params_channels(params);
-- alsa_stream->params_rate = params_rate(params);
-- alsa_stream->pcm_format_width = snd_pcm_format_width(params_format(params));
--
-- return err;
-+ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
- }
-
- /* hw_free callback */
-@@ -248,11 +233,11 @@ static int snd_bcm2835_pcm_prepare(struc
- if (chip->spdif_status & IEC958_AES0_NONAUDIO)
- channels = 0;
- else
-- channels = alsa_stream->channels;
-+ channels = runtime->channels;
-
- err = bcm2835_audio_set_params(alsa_stream, channels,
-- alsa_stream->params_rate,
-- alsa_stream->pcm_format_width);
-+ runtime->rate,
-+ snd_pcm_format_width(runtime->format));
- if (err < 0)
- audio_error(" error setting hw params\n");
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -121,10 +121,6 @@ struct bcm2835_alsa_stream {
-
- int draining;
-
-- int channels;
-- int params_rate;
-- int pcm_format_width;
--
- unsigned int pos;
- unsigned int buffer_size;
- unsigned int period_size;
+++ /dev/null
-From a08260154f88b0b97e3c8de6b3cdb7187e8c3d8a Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:41 +0200
-Subject: [PATCH] staging: bcm2835-audio: Drop unnecessary pcm indirect
- setup
-
-commit 7318ec896f4856fae2bb013858e422fa078201e1 upstream.
-
-The hw_queue_size of PCM indirect helper doesn't need to be set up if
-you use the whole given buffer size. Drop the useless
-initialization, which just confuses readers.
-
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -280,7 +280,6 @@ static int snd_bcm2835_pcm_ack(struct sn
- struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
- struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
-
-- pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
- return snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
- snd_bcm2835_pcm_transfer);
- }
--- /dev/null
+From 2ab24bca59da765a12f4617527e671170230bf3a Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:43 +0200
+Subject: [PATCH] staging: bcm2835-audio: Propagate parameter setup
+ error
+
+commit fee5638fe552ff8222c3a5bdcc4a34255e248d8c upstream.
+
+When the parameter setup fails, the driver should propagate the error
+code instead of silently ignoring it.
+
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -238,7 +238,7 @@ static int snd_bcm2835_pcm_prepare(struc
+ runtime->rate,
+ snd_pcm_format_width(runtime->format));
+ if (err < 0)
+- audio_error(" error setting hw params\n");
++ goto out;
+
+ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
+
+@@ -255,8 +255,9 @@ static int snd_bcm2835_pcm_prepare(struc
+ alsa_stream->buffer_size, alsa_stream->period_size,
+ alsa_stream->pos, runtime->frame_bits);
+
++ out:
+ mutex_unlock(&chip->audio_mutex);
+- return 0;
++ return err;
+ }
+
+ static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
--- /dev/null
+From e109804fa00a139a05626c1b8ceebcfe3577fc6d Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:44 +0200
+Subject: [PATCH] staging: bcm2835-audio: Drop debug messages in
+ bcm2835-pcm.c
+
+commit 055e1c330d04df87d4730a5db837161c11ddaafc upstream.
+
+These debug messages worsen the code readability a lot while they give
+little debuggability (which we already have via tracing, in anyway).
+
+Let's clean them up. This allows us to reduce the
+snd_bcm2835_pcm_lib_ioctl() function to be a direct call of the
+snd_pcm_lib_ioctl callback (like most other drivers do), too.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 51 +++----------------
+ 1 file changed, 7 insertions(+), 44 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -44,9 +44,7 @@ static const struct snd_pcm_hardware snd
+
+ static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
+ {
+- audio_info("Freeing up alsa stream here ..\n");
+ kfree(runtime->private_data);
+- runtime->private_data = NULL;
+ }
+
+ void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream)
+@@ -99,7 +97,6 @@ static int snd_bcm2835_playback_open_gen
+ int err;
+
+ mutex_lock(&chip->audio_mutex);
+- audio_info("Alsa open (%d)\n", substream->number);
+ idx = substream->number;
+
+ if (spdif && chip->opened) {
+@@ -182,8 +179,6 @@ static int snd_bcm2835_playback_close(st
+ runtime = substream->runtime;
+ alsa_stream = runtime->private_data;
+
+- audio_info("Alsa close\n");
+-
+ alsa_stream->period_size = 0;
+ alsa_stream->buffer_size = 0;
+
+@@ -251,10 +246,6 @@ static int snd_bcm2835_pcm_prepare(struc
+ alsa_stream->pos = 0;
+ alsa_stream->draining = false;
+
+- audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
+- alsa_stream->buffer_size, alsa_stream->period_size,
+- alsa_stream->pos, runtime->frame_bits);
+-
+ out:
+ mutex_unlock(&chip->audio_mutex);
+ return err;
+@@ -266,12 +257,8 @@ static void snd_bcm2835_pcm_transfer(str
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
+ void *src = (void *) (substream->runtime->dma_area + rec->sw_data);
+- int err;
+-
+- err = bcm2835_audio_write(alsa_stream, bytes, src);
+- if (err)
+- audio_error(" Failed to transfer to alsa device (%d)\n", err);
+
++ bcm2835_audio_write(alsa_stream, bytes, src);
+ }
+
+ static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
+@@ -289,27 +276,18 @@ static int snd_bcm2835_pcm_trigger(struc
+ {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
+- int err = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+- err = bcm2835_audio_start(alsa_stream);
+- if (err)
+- audio_error(" Failed to START alsa device (%d)\n", err);
+- break;
++ return bcm2835_audio_start(alsa_stream);
+ case SNDRV_PCM_TRIGGER_DRAIN:
+ alsa_stream->draining = true;
+- break;
++ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+- err = bcm2835_audio_stop(alsa_stream);
+- if (err)
+- audio_error(" Failed to STOP alsa device (%d)\n", err);
+- break;
++ return bcm2835_audio_stop(alsa_stream);
+ default:
+- err = -EINVAL;
++ return -EINVAL;
+ }
+-
+- return err;
+ }
+
+ /* pointer callback */
+@@ -319,31 +297,16 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
+
+- audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
+- frames_to_bytes(runtime, runtime->status->hw_ptr),
+- frames_to_bytes(runtime, runtime->control->appl_ptr),
+- alsa_stream->pos);
+-
+ return snd_pcm_indirect_playback_pointer(substream,
+ &alsa_stream->pcm_indirect,
+ alsa_stream->pos);
+ }
+
+-static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
+- unsigned int cmd, void *arg)
+-{
+- int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+-
+- audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
+- cmd, arg, arg ? *(unsigned int *)arg : 0, ret);
+- return ret;
+-}
+-
+ /* operators */
+ static const struct snd_pcm_ops snd_bcm2835_playback_ops = {
+ .open = snd_bcm2835_playback_open,
+ .close = snd_bcm2835_playback_close,
+- .ioctl = snd_bcm2835_pcm_lib_ioctl,
++ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_bcm2835_pcm_hw_params,
+ .hw_free = snd_bcm2835_pcm_hw_free,
+ .prepare = snd_bcm2835_pcm_prepare,
+@@ -355,7 +318,7 @@ static const struct snd_pcm_ops snd_bcm2
+ static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
+ .open = snd_bcm2835_playback_spdif_open,
+ .close = snd_bcm2835_playback_close,
+- .ioctl = snd_bcm2835_pcm_lib_ioctl,
++ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_bcm2835_pcm_hw_params,
+ .hw_free = snd_bcm2835_pcm_hw_free,
+ .prepare = snd_bcm2835_pcm_prepare,
+++ /dev/null
-From 9f3956e7bbf868894b5aee41110dbe28f117918c Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:42 +0200
-Subject: [PATCH] staging: bcm2835-audio: Drop useless NULL check
-
-commit 8bcf9f252c29c2d5bcce3db605c0ebf1ef230f9c upstream.
-
-alsa_stream->chip can be never NULL.
-
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -188,8 +188,7 @@ static int snd_bcm2835_playback_close(st
- alsa_stream->buffer_size = 0;
-
- bcm2835_audio_close(alsa_stream);
-- if (alsa_stream->chip)
-- alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
-+ alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
- /*
- * Do not free up alsa_stream here, it will be freed up by
- * runtime->private_free callback we registered in *_open above
--- /dev/null
+From 3c7663a9b1763f64250db4b975a3ce246ef32e0f Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:45 +0200
+Subject: [PATCH] staging: bcm2835-audio: Drop superfluous mutex lock
+ during prepare
+
+commit f0eb15d055380ff127e5f12c8fad2b36bdb3c006 upstream.
+
+The chip->audio_mutex is used basically for protecting the opened
+stream assignment, and the prepare callback is irrelevant with it.
+
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -218,8 +218,6 @@ static int snd_bcm2835_pcm_prepare(struc
+ int channels;
+ int err;
+
+- mutex_lock(&chip->audio_mutex);
+-
+ /* notify the vchiq that it should enter spdif passthrough mode by
+ * setting channels=0 (see
+ * https://github.com/raspberrypi/linux/issues/528)
+@@ -233,7 +231,7 @@ static int snd_bcm2835_pcm_prepare(struc
+ runtime->rate,
+ snd_pcm_format_width(runtime->format));
+ if (err < 0)
+- goto out;
++ return err;
+
+ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
+
+@@ -246,9 +244,7 @@ static int snd_bcm2835_pcm_prepare(struc
+ alsa_stream->pos = 0;
+ alsa_stream->draining = false;
+
+- out:
+- mutex_unlock(&chip->audio_mutex);
+- return err;
++ return 0;
+ }
+
+ static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
+++ /dev/null
-From 2ab24bca59da765a12f4617527e671170230bf3a Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:43 +0200
-Subject: [PATCH] staging: bcm2835-audio: Propagate parameter setup
- error
-
-commit fee5638fe552ff8222c3a5bdcc4a34255e248d8c upstream.
-
-When the parameter setup fails, the driver should propagate the error
-code instead of silently ignoring it.
-
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -238,7 +238,7 @@ static int snd_bcm2835_pcm_prepare(struc
- runtime->rate,
- snd_pcm_format_width(runtime->format));
- if (err < 0)
-- audio_error(" error setting hw params\n");
-+ goto out;
-
- memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
-
-@@ -255,8 +255,9 @@ static int snd_bcm2835_pcm_prepare(struc
- alsa_stream->buffer_size, alsa_stream->period_size,
- alsa_stream->pos, runtime->frame_bits);
-
-+ out:
- mutex_unlock(&chip->audio_mutex);
-- return 0;
-+ return err;
- }
-
- static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
--- /dev/null
+From daa78c198ece1ec901ee565c869ee1a60a95061d Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:46 +0200
+Subject: [PATCH] staging: bcm2835-audio: Add 10ms period constraint
+
+commit 93c66acaf68b5247c3121a46a71ff6a70fc1d492 upstream.
+
+It seems that the resolution of vc04 callback is in 10 msec; i.e. the
+minimal period size is also 10 msec.
+
+This patch adds the corresponding hw constraint.
+
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -145,6 +145,11 @@ static int snd_bcm2835_playback_open_gen
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ 16);
+
++ /* position update is in 10ms order */
++ snd_pcm_hw_constraint_minmax(runtime,
++ SNDRV_PCM_HW_PARAM_PERIOD_TIME,
++ 10 * 1000, UINT_MAX);
++
+ chip->alsa_stream[idx] = alsa_stream;
+
+ chip->opened |= (1 << idx);
+++ /dev/null
-From e109804fa00a139a05626c1b8ceebcfe3577fc6d Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:44 +0200
-Subject: [PATCH] staging: bcm2835-audio: Drop debug messages in
- bcm2835-pcm.c
-
-commit 055e1c330d04df87d4730a5db837161c11ddaafc upstream.
-
-These debug messages worsen the code readability a lot while they give
-little debuggability (which we already have via tracing, in anyway).
-
-Let's clean them up. This allows us to reduce the
-snd_bcm2835_pcm_lib_ioctl() function to be a direct call of the
-snd_pcm_lib_ioctl callback (like most other drivers do), too.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 51 +++----------------
- 1 file changed, 7 insertions(+), 44 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -44,9 +44,7 @@ static const struct snd_pcm_hardware snd
-
- static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
- {
-- audio_info("Freeing up alsa stream here ..\n");
- kfree(runtime->private_data);
-- runtime->private_data = NULL;
- }
-
- void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream)
-@@ -99,7 +97,6 @@ static int snd_bcm2835_playback_open_gen
- int err;
-
- mutex_lock(&chip->audio_mutex);
-- audio_info("Alsa open (%d)\n", substream->number);
- idx = substream->number;
-
- if (spdif && chip->opened) {
-@@ -182,8 +179,6 @@ static int snd_bcm2835_playback_close(st
- runtime = substream->runtime;
- alsa_stream = runtime->private_data;
-
-- audio_info("Alsa close\n");
--
- alsa_stream->period_size = 0;
- alsa_stream->buffer_size = 0;
-
-@@ -251,10 +246,6 @@ static int snd_bcm2835_pcm_prepare(struc
- alsa_stream->pos = 0;
- alsa_stream->draining = false;
-
-- audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
-- alsa_stream->buffer_size, alsa_stream->period_size,
-- alsa_stream->pos, runtime->frame_bits);
--
- out:
- mutex_unlock(&chip->audio_mutex);
- return err;
-@@ -266,12 +257,8 @@ static void snd_bcm2835_pcm_transfer(str
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
- void *src = (void *) (substream->runtime->dma_area + rec->sw_data);
-- int err;
--
-- err = bcm2835_audio_write(alsa_stream, bytes, src);
-- if (err)
-- audio_error(" Failed to transfer to alsa device (%d)\n", err);
-
-+ bcm2835_audio_write(alsa_stream, bytes, src);
- }
-
- static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
-@@ -289,27 +276,18 @@ static int snd_bcm2835_pcm_trigger(struc
- {
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
-- int err = 0;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
-- err = bcm2835_audio_start(alsa_stream);
-- if (err)
-- audio_error(" Failed to START alsa device (%d)\n", err);
-- break;
-+ return bcm2835_audio_start(alsa_stream);
- case SNDRV_PCM_TRIGGER_DRAIN:
- alsa_stream->draining = true;
-- break;
-+ return 0;
- case SNDRV_PCM_TRIGGER_STOP:
-- err = bcm2835_audio_stop(alsa_stream);
-- if (err)
-- audio_error(" Failed to STOP alsa device (%d)\n", err);
-- break;
-+ return bcm2835_audio_stop(alsa_stream);
- default:
-- err = -EINVAL;
-+ return -EINVAL;
- }
--
-- return err;
- }
-
- /* pointer callback */
-@@ -319,31 +297,16 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
-
-- audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
-- frames_to_bytes(runtime, runtime->status->hw_ptr),
-- frames_to_bytes(runtime, runtime->control->appl_ptr),
-- alsa_stream->pos);
--
- return snd_pcm_indirect_playback_pointer(substream,
- &alsa_stream->pcm_indirect,
- alsa_stream->pos);
- }
-
--static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
-- unsigned int cmd, void *arg)
--{
-- int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
--
-- audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
-- cmd, arg, arg ? *(unsigned int *)arg : 0, ret);
-- return ret;
--}
--
- /* operators */
- static const struct snd_pcm_ops snd_bcm2835_playback_ops = {
- .open = snd_bcm2835_playback_open,
- .close = snd_bcm2835_playback_close,
-- .ioctl = snd_bcm2835_pcm_lib_ioctl,
-+ .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_bcm2835_pcm_hw_params,
- .hw_free = snd_bcm2835_pcm_hw_free,
- .prepare = snd_bcm2835_pcm_prepare,
-@@ -355,7 +318,7 @@ static const struct snd_pcm_ops snd_bcm2
- static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
- .open = snd_bcm2835_playback_spdif_open,
- .close = snd_bcm2835_playback_close,
-- .ioctl = snd_bcm2835_pcm_lib_ioctl,
-+ .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_bcm2835_pcm_hw_params,
- .hw_free = snd_bcm2835_pcm_hw_free,
- .prepare = snd_bcm2835_pcm_prepare,
+++ /dev/null
-From 3c7663a9b1763f64250db4b975a3ce246ef32e0f Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:45 +0200
-Subject: [PATCH] staging: bcm2835-audio: Drop superfluous mutex lock
- during prepare
-
-commit f0eb15d055380ff127e5f12c8fad2b36bdb3c006 upstream.
-
-The chip->audio_mutex is used basically for protecting the opened
-stream assignment, and the prepare callback is irrelevant with it.
-
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 8 ++------
- 1 file changed, 2 insertions(+), 6 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -218,8 +218,6 @@ static int snd_bcm2835_pcm_prepare(struc
- int channels;
- int err;
-
-- mutex_lock(&chip->audio_mutex);
--
- /* notify the vchiq that it should enter spdif passthrough mode by
- * setting channels=0 (see
- * https://github.com/raspberrypi/linux/issues/528)
-@@ -233,7 +231,7 @@ static int snd_bcm2835_pcm_prepare(struc
- runtime->rate,
- snd_pcm_format_width(runtime->format));
- if (err < 0)
-- goto out;
-+ return err;
-
- memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
-
-@@ -246,9 +244,7 @@ static int snd_bcm2835_pcm_prepare(struc
- alsa_stream->pos = 0;
- alsa_stream->draining = false;
-
-- out:
-- mutex_unlock(&chip->audio_mutex);
-- return err;
-+ return 0;
- }
-
- static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
--- /dev/null
+From 98a1612b199cb3060306c05d1a6d7ca18ef08475 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:47 +0200
+Subject: [PATCH] staging: bcm2835-audio: Make single vchi handle
+
+commit 326a6edcb2ada56375bd7d3fc24c83f58e8da7f3 upstream.
+
+The bcm2835_audio_instance object contains the array of
+VCHI_SERVICE_HANDLE_T, while the code assumes and uses only the first
+element explicitly. Let's reduce to a single vchi handle for
+simplifying the code.
+
+---
+ .../bcm2835-audio/bcm2835-vchiq.c | 170 ++++++------------
+ 1 file changed, 58 insertions(+), 112 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -44,8 +44,7 @@
+ #endif
+
+ struct bcm2835_audio_instance {
+- unsigned int num_connections;
+- VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
++ VCHI_SERVICE_HANDLE_T vchi_handle;
+ struct completion msg_avail_comp;
+ struct mutex vchi_mutex;
+ struct bcm2835_alsa_stream *alsa_stream;
+@@ -202,12 +201,12 @@ static void audio_vchi_callback(void *pa
+ BUG();
+ return;
+ }
+- if (!instance->vchi_handle[0]) {
+- LOG_ERR(" .. instance->vchi_handle[0] is null\n");
++ if (!instance->vchi_handle) {
++ LOG_ERR(" .. instance->vchi_handle is null\n");
+ BUG();
+ return;
+ }
+- status = vchi_msg_dequeue(instance->vchi_handle[0],
++ status = vchi_msg_dequeue(instance->vchi_handle,
+ &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
+ if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
+ LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
+@@ -237,102 +236,61 @@ static void audio_vchi_callback(void *pa
+
+ static struct bcm2835_audio_instance *
+ vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
+- VCHI_CONNECTION_T **vchi_connections,
+- unsigned int num_connections)
++ VCHI_CONNECTION_T *vchi_connection)
+ {
+- unsigned int i;
++ SERVICE_CREATION_T params = {
++ .version = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
++ .service_id = VC_AUDIO_SERVER_NAME,
++ .connection = vchi_connection,
++ .rx_fifo_size = 0,
++ .tx_fifo_size = 0,
++ .callback = audio_vchi_callback,
++ .want_unaligned_bulk_rx = 1, //TODO: remove VCOS_FALSE
++ .want_unaligned_bulk_tx = 1, //TODO: remove VCOS_FALSE
++ .want_crc = 0
++ };
+ struct bcm2835_audio_instance *instance;
+ int status;
+- int ret;
+-
+- LOG_DBG("%s: start", __func__);
+
+- if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
+- LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
+- __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
+-
+- return ERR_PTR(-EINVAL);
+- }
+ /* Allocate memory for this instance */
+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+ if (!instance)
+ return ERR_PTR(-ENOMEM);
+
+- instance->num_connections = num_connections;
+-
+ /* Create a lock for exclusive, serialized VCHI connection access */
+ mutex_init(&instance->vchi_mutex);
+ /* Open the VCHI service connections */
+- for (i = 0; i < num_connections; i++) {
+- SERVICE_CREATION_T params = {
+- .version = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
+- .service_id = VC_AUDIO_SERVER_NAME,
+- .connection = vchi_connections[i],
+- .rx_fifo_size = 0,
+- .tx_fifo_size = 0,
+- .callback = audio_vchi_callback,
+- .callback_param = instance,
+- .want_unaligned_bulk_rx = 1, //TODO: remove VCOS_FALSE
+- .want_unaligned_bulk_tx = 1, //TODO: remove VCOS_FALSE
+- .want_crc = 0
+- };
+-
+- LOG_DBG("%s: about to open %i\n", __func__, i);
+- status = vchi_service_open(vchi_instance, ¶ms,
+- &instance->vchi_handle[i]);
++ params.callback_param = instance,
+
+- LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
+- if (status) {
+- LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
+- __func__, status);
+- ret = -EPERM;
+- goto err_close_services;
+- }
+- /* Finished with the service for now */
+- vchi_service_release(instance->vchi_handle[i]);
+- }
+-
+- LOG_DBG("%s: okay\n", __func__);
+- return instance;
++ status = vchi_service_open(vchi_instance, ¶ms,
++ &instance->vchi_handle);
+
+-err_close_services:
+- for (i = 0; i < instance->num_connections; i++) {
+- LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]);
+- if (instance->vchi_handle[i])
+- vchi_service_close(instance->vchi_handle[i]);
++ if (status) {
++ LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
++ __func__, status);
++ kfree(instance);
++ return ERR_PTR(-EPERM);
+ }
+
+- kfree(instance);
+- LOG_ERR("%s: error\n", __func__);
++ /* Finished with the service for now */
++ vchi_service_release(instance->vchi_handle);
+
+- return ERR_PTR(ret);
++ return instance;
+ }
+
+ static int vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
+ {
+- unsigned int i;
+-
+- if (!instance) {
+- LOG_ERR("%s: invalid handle %p\n", __func__, instance);
+-
+- return -1;
+- }
++ int status;
+
+- LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
+ mutex_lock(&instance->vchi_mutex);
+
+ /* Close all VCHI service connections */
+- for (i = 0; i < instance->num_connections; i++) {
+- int status;
+-
+- LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
+- vchi_service_use(instance->vchi_handle[i]);
++ vchi_service_use(instance->vchi_handle);
+
+- status = vchi_service_close(instance->vchi_handle[i]);
+- if (status) {
+- LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
+- __func__, status);
+- }
++ status = vchi_service_close(instance->vchi_handle);
++ if (status) {
++ LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
++ __func__, status);
+ }
+
+ mutex_unlock(&instance->vchi_mutex);
+@@ -383,19 +341,9 @@ static int bcm2835_audio_open_connection
+ (struct bcm2835_audio_instance *)alsa_stream->instance;
+ struct bcm2835_vchi_ctx *vhci_ctx = alsa_stream->chip->vchi_ctx;
+
+- LOG_INFO("%s: start\n", __func__);
+- BUG_ON(instance);
+- if (instance) {
+- LOG_ERR("%s: VCHI instance already open (%p)\n",
+- __func__, instance);
+- instance->alsa_stream = alsa_stream;
+- alsa_stream->instance = instance;
+- return 0;
+- }
+-
+ /* Initialize an instance of the audio service */
+ instance = vc_vchi_audio_init(vhci_ctx->vchi_instance,
+- &vhci_ctx->vchi_connection, 1);
++ vhci_ctx->vchi_connection);
+
+ if (IS_ERR(instance)) {
+ LOG_ERR("%s: failed to initialize audio service\n", __func__);
+@@ -407,8 +355,6 @@ static int bcm2835_audio_open_connection
+ instance->alsa_stream = alsa_stream;
+ alsa_stream->instance = instance;
+
+- LOG_DBG(" success !\n");
+-
+ return 0;
+ }
+
+@@ -431,12 +377,12 @@ int bcm2835_audio_open(struct bcm2835_al
+ LOG_DBG(" instance (%p)\n", instance);
+
+ mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle[0]);
++ vchi_service_use(instance->vchi_handle);
+
+ m.type = VC_AUDIO_MSG_TYPE_OPEN;
+
+ /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
++ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+ &m, sizeof(m));
+
+ if (status) {
+@@ -450,7 +396,7 @@ int bcm2835_audio_open(struct bcm2835_al
+ ret = 0;
+
+ unlock:
+- vchi_service_release(instance->vchi_handle[0]);
++ vchi_service_release(instance->vchi_handle);
+ mutex_unlock(&instance->vchi_mutex);
+
+ free_wq:
+@@ -472,7 +418,7 @@ int bcm2835_audio_set_ctls(struct bcm283
+ chip->dest, chip->volume);
+
+ mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle[0]);
++ vchi_service_use(instance->vchi_handle);
+
+ instance->result = -1;
+
+@@ -487,7 +433,7 @@ int bcm2835_audio_set_ctls(struct bcm283
+ init_completion(&instance->msg_avail_comp);
+
+ /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
++ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+ &m, sizeof(m));
+
+ if (status) {
+@@ -511,7 +457,7 @@ int bcm2835_audio_set_ctls(struct bcm283
+ ret = 0;
+
+ unlock:
+- vchi_service_release(instance->vchi_handle[0]);
++ vchi_service_release(instance->vchi_handle);
+ mutex_unlock(&instance->vchi_mutex);
+
+ return ret;
+@@ -537,7 +483,7 @@ int bcm2835_audio_set_params(struct bcm2
+ }
+
+ mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle[0]);
++ vchi_service_use(instance->vchi_handle);
+
+ instance->result = -1;
+
+@@ -550,7 +496,7 @@ int bcm2835_audio_set_params(struct bcm2
+ init_completion(&instance->msg_avail_comp);
+
+ /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
++ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+ &m, sizeof(m));
+
+ if (status) {
+@@ -574,7 +520,7 @@ int bcm2835_audio_set_params(struct bcm2
+ ret = 0;
+
+ unlock:
+- vchi_service_release(instance->vchi_handle[0]);
++ vchi_service_release(instance->vchi_handle);
+ mutex_unlock(&instance->vchi_mutex);
+
+ return ret;
+@@ -588,12 +534,12 @@ static int bcm2835_audio_start_worker(st
+ int ret;
+
+ mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle[0]);
++ vchi_service_use(instance->vchi_handle);
+
+ m.type = VC_AUDIO_MSG_TYPE_START;
+
+ /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
++ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+ &m, sizeof(m));
+
+ if (status) {
+@@ -607,7 +553,7 @@ static int bcm2835_audio_start_worker(st
+ ret = 0;
+
+ unlock:
+- vchi_service_release(instance->vchi_handle[0]);
++ vchi_service_release(instance->vchi_handle);
+ mutex_unlock(&instance->vchi_mutex);
+ return ret;
+ }
+@@ -620,13 +566,13 @@ static int bcm2835_audio_stop_worker(str
+ int ret;
+
+ mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle[0]);
++ vchi_service_use(instance->vchi_handle);
+
+ m.type = VC_AUDIO_MSG_TYPE_STOP;
+ m.u.stop.draining = alsa_stream->draining;
+
+ /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
++ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+ &m, sizeof(m));
+
+ if (status) {
+@@ -640,7 +586,7 @@ static int bcm2835_audio_stop_worker(str
+ ret = 0;
+
+ unlock:
+- vchi_service_release(instance->vchi_handle[0]);
++ vchi_service_release(instance->vchi_handle);
+ mutex_unlock(&instance->vchi_mutex);
+ return ret;
+ }
+@@ -655,7 +601,7 @@ int bcm2835_audio_close(struct bcm2835_a
+ my_workqueue_quit(alsa_stream);
+
+ mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle[0]);
++ vchi_service_use(instance->vchi_handle);
+
+ m.type = VC_AUDIO_MSG_TYPE_CLOSE;
+
+@@ -663,7 +609,7 @@ int bcm2835_audio_close(struct bcm2835_a
+ init_completion(&instance->msg_avail_comp);
+
+ /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
++ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+ &m, sizeof(m));
+
+ if (status) {
+@@ -687,7 +633,7 @@ int bcm2835_audio_close(struct bcm2835_a
+ ret = 0;
+
+ unlock:
+- vchi_service_release(instance->vchi_handle[0]);
++ vchi_service_release(instance->vchi_handle);
+ mutex_unlock(&instance->vchi_mutex);
+
+ /* Stop the audio service */
+@@ -708,10 +654,10 @@ static int bcm2835_audio_write_worker(st
+ LOG_INFO(" Writing %d bytes from %p\n", count, src);
+
+ mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle[0]);
++ vchi_service_use(instance->vchi_handle);
+
+ if (instance->peer_version == 0 &&
+- vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0)
++ vchi_get_peer_version(instance->vchi_handle, &instance->peer_version) == 0)
+ LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
+
+ m.type = VC_AUDIO_MSG_TYPE_WRITE;
+@@ -723,7 +669,7 @@ static int bcm2835_audio_write_worker(st
+ m.u.write.silence = src == NULL;
+
+ /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
++ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+ &m, sizeof(m));
+
+ if (status) {
+@@ -736,7 +682,7 @@ static int bcm2835_audio_write_worker(st
+ if (!m.u.write.silence) {
+ if (!m.u.write.max_packet) {
+ /* Send the message to the videocore */
+- status = vchi_bulk_queue_transmit(instance->vchi_handle[0],
++ status = vchi_bulk_queue_transmit(instance->vchi_handle,
+ src, count,
+ 0 * VCHI_FLAGS_BLOCK_UNTIL_QUEUED
+ +
+@@ -746,7 +692,7 @@ static int bcm2835_audio_write_worker(st
+ while (count > 0) {
+ int bytes = min_t(int, m.u.write.max_packet, count);
+
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
++ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+ src, bytes);
+ src = (char *)src + bytes;
+ count -= bytes;
+@@ -763,7 +709,7 @@ static int bcm2835_audio_write_worker(st
+ ret = 0;
+
+ unlock:
+- vchi_service_release(instance->vchi_handle[0]);
++ vchi_service_release(instance->vchi_handle);
+ mutex_unlock(&instance->vchi_mutex);
+ return ret;
+ }
+++ /dev/null
-From daa78c198ece1ec901ee565c869ee1a60a95061d Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:46 +0200
-Subject: [PATCH] staging: bcm2835-audio: Add 10ms period constraint
-
-commit 93c66acaf68b5247c3121a46a71ff6a70fc1d492 upstream.
-
-It seems that the resolution of vc04 callback is in 10 msec; i.e. the
-minimal period size is also 10 msec.
-
-This patch adds the corresponding hw constraint.
-
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -145,6 +145,11 @@ static int snd_bcm2835_playback_open_gen
- SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
- 16);
-
-+ /* position update is in 10ms order */
-+ snd_pcm_hw_constraint_minmax(runtime,
-+ SNDRV_PCM_HW_PARAM_PERIOD_TIME,
-+ 10 * 1000, UINT_MAX);
-+
- chip->alsa_stream[idx] = alsa_stream;
-
- chip->opened |= (1 << idx);
--- /dev/null
+From 43f89ac74f3f221e3036a1ec311b24016860d15e Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:48 +0200
+Subject: [PATCH] staging: bcm2835-audio: Code refactoring of vchiq
+ accessor codes
+
+commit 769a8e9bf5cf39813f52962fdafdf7e4d52ad585 upstream.
+
+This is a cleanup and code refactoring in bcm2835-vchiq.c.
+
+The major code changes are to provide local helpers for easier use of
+lock / unlock, and message passing with/without response wait. This
+allows us to reduce lots of open codes.
+
+Also, the max packet is set at opening the stream, not at each time
+when the write gets called.
+
+---
+ .../bcm2835-audio/bcm2835-vchiq.c | 440 ++++++------------
+ 1 file changed, 142 insertions(+), 298 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -49,6 +49,7 @@ struct bcm2835_audio_instance {
+ struct mutex vchi_mutex;
+ struct bcm2835_alsa_stream *alsa_stream;
+ int result;
++ unsigned int max_packet;
+ short peer_version;
+ };
+
+@@ -65,16 +66,68 @@ static int bcm2835_audio_start_worker(st
+ static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int count, void *src);
+
+-// Routine to send a message across a service
++static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
++{
++ mutex_lock(&instance->vchi_mutex);
++ vchi_service_use(instance->vchi_handle);
++}
++
++static void bcm2835_audio_unlock(struct bcm2835_audio_instance *instance)
++{
++ vchi_service_release(instance->vchi_handle);
++ mutex_unlock(&instance->vchi_mutex);
++}
++
++static int bcm2835_audio_send_msg_locked(struct bcm2835_audio_instance *instance,
++ struct vc_audio_msg *m, bool wait)
++{
++ int status;
++
++ if (wait) {
++ instance->result = -1;
++ init_completion(&instance->msg_avail_comp);
++ }
++
++ status = vchi_queue_kernel_message(instance->vchi_handle,
++ m, sizeof(*m));
++ if (status) {
++ LOG_ERR("vchi message queue failed: %d, msg=%d\n",
++ status, m->type);
++ return -EIO;
++ }
++
++ if (wait) {
++ if (!wait_for_completion_timeout(&instance->msg_avail_comp,
++ msecs_to_jiffies(10 * 1000))) {
++ LOG_ERR("vchi message timeout, msg=%d\n", m->type);
++ return -ETIMEDOUT;
++ } else if (instance->result) {
++ LOG_ERR("vchi message response error:%d, msg=%d\n",
++ instance->result, m->type);
++ return -EIO;
++ }
++ }
++
++ return 0;
++}
+
+-static int
+-bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
+- void *data,
+- unsigned int size)
+-{
+- return vchi_queue_kernel_message(handle,
+- data,
+- size);
++static int bcm2835_audio_send_msg(struct bcm2835_audio_instance *instance,
++ struct vc_audio_msg *m, bool wait)
++{
++ int err;
++
++ bcm2835_audio_lock(instance);
++ err = bcm2835_audio_send_msg_locked(instance, m, wait);
++ bcm2835_audio_unlock(instance);
++ return err;
++}
++
++static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance,
++ int type, bool wait)
++{
++ struct vc_audio_msg m = { .type = type };
++
++ return bcm2835_audio_send_msg(instance, &m, wait);
+ }
+
+ static const u32 BCM2835_AUDIO_WRITE_COOKIE1 = ('B' << 24 | 'C' << 16 |
+@@ -283,10 +336,9 @@ static int vc_vchi_audio_deinit(struct b
+ int status;
+
+ mutex_lock(&instance->vchi_mutex);
+-
+- /* Close all VCHI service connections */
+ vchi_service_use(instance->vchi_handle);
+
++ /* Close all VCHI service connections */
+ status = vchi_service_close(instance->vchi_handle);
+ if (status) {
+ LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
+@@ -345,12 +397,8 @@ static int bcm2835_audio_open_connection
+ instance = vc_vchi_audio_init(vhci_ctx->vchi_instance,
+ vhci_ctx->vchi_connection);
+
+- if (IS_ERR(instance)) {
+- LOG_ERR("%s: failed to initialize audio service\n", __func__);
+-
+- /* vchi_instance is retained for use the next time. */
++ if (IS_ERR(instance))
+ return PTR_ERR(instance);
+- }
+
+ instance->alsa_stream = alsa_stream;
+ alsa_stream->instance = instance;
+@@ -361,66 +409,44 @@ static int bcm2835_audio_open_connection
+ int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
+ {
+ struct bcm2835_audio_instance *instance;
+- struct vc_audio_msg m;
+- int status;
+- int ret;
++ int err;
+
+ alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
+ if (!alsa_stream->my_wq)
+ return -ENOMEM;
+
+- ret = bcm2835_audio_open_connection(alsa_stream);
+- if (ret)
++ err = bcm2835_audio_open_connection(alsa_stream);
++ if (err < 0)
+ goto free_wq;
+
+ instance = alsa_stream->instance;
+- LOG_DBG(" instance (%p)\n", instance);
+-
+- mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle);
+-
+- m.type = VC_AUDIO_MSG_TYPE_OPEN;
+-
+- /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+- &m, sizeof(m));
+-
+- if (status) {
+- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+- __func__, status);
+-
+- ret = -1;
+- goto unlock;
+- }
+-
+- ret = 0;
+
+-unlock:
+- vchi_service_release(instance->vchi_handle);
+- mutex_unlock(&instance->vchi_mutex);
++ err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
++ false);
++ if (err < 0)
++ goto deinit;
++
++ bcm2835_audio_lock(instance);
++ vchi_get_peer_version(instance->vchi_handle, &instance->peer_version);
++ bcm2835_audio_unlock(instance);
++ if (instance->peer_version < 2 || force_bulk)
++ instance->max_packet = 0; /* bulk transfer */
++ else
++ instance->max_packet = 4000;
+
+-free_wq:
+- if (ret)
+- destroy_workqueue(alsa_stream->my_wq);
++ return 0;
+
+- return ret;
++ deinit:
++ vc_vchi_audio_deinit(instance);
++ free_wq:
++ destroy_workqueue(alsa_stream->my_wq);
++ return err;
+ }
+
+ int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
+ {
+- struct vc_audio_msg m;
+- struct bcm2835_audio_instance *instance = alsa_stream->instance;
+ struct bcm2835_chip *chip = alsa_stream->chip;
+- int status;
+- int ret;
+-
+- LOG_INFO(" Setting ALSA dest(%d), volume(%d)\n",
+- chip->dest, chip->volume);
+-
+- mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle);
+-
+- instance->result = -1;
++ struct vc_audio_msg m = {};
+
+ m.type = VC_AUDIO_MSG_TYPE_CONTROL;
+ m.u.control.dest = chip->dest;
+@@ -429,289 +455,107 @@ int bcm2835_audio_set_ctls(struct bcm283
+ else
+ m.u.control.volume = alsa2chip(chip->volume);
+
+- /* Create the message available completion */
+- init_completion(&instance->msg_avail_comp);
+-
+- /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+- &m, sizeof(m));
+-
+- if (status) {
+- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+- __func__, status);
+-
+- ret = -1;
+- goto unlock;
+- }
+-
+- /* We are expecting a reply from the videocore */
+- wait_for_completion(&instance->msg_avail_comp);
+-
+- if (instance->result) {
+- LOG_ERR("%s: result=%d\n", __func__, instance->result);
+-
+- ret = -1;
+- goto unlock;
+- }
+-
+- ret = 0;
+-
+-unlock:
+- vchi_service_release(instance->vchi_handle);
+- mutex_unlock(&instance->vchi_mutex);
+-
+- return ret;
++ return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
+ }
+
+ int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int channels, unsigned int samplerate,
+ unsigned int bps)
+ {
+- struct vc_audio_msg m;
+- struct bcm2835_audio_instance *instance = alsa_stream->instance;
+- int status;
+- int ret;
+-
+- LOG_INFO(" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
+- channels, samplerate, bps);
++ struct vc_audio_msg m = {
++ .type = VC_AUDIO_MSG_TYPE_CONFIG,
++ .u.config.channels = channels,
++ .u.config.samplerate = samplerate,
++ .u.config.bps = bps,
++ };
++ int err;
+
+ /* resend ctls - alsa_stream may not have been open when first send */
+- ret = bcm2835_audio_set_ctls(alsa_stream);
+- if (ret) {
+- LOG_ERR(" Alsa controls not supported\n");
+- return -EINVAL;
+- }
++ err = bcm2835_audio_set_ctls(alsa_stream);
++ if (err)
++ return err;
+
+- mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle);
+-
+- instance->result = -1;
+-
+- m.type = VC_AUDIO_MSG_TYPE_CONFIG;
+- m.u.config.channels = channels;
+- m.u.config.samplerate = samplerate;
+- m.u.config.bps = bps;
+-
+- /* Create the message available completion */
+- init_completion(&instance->msg_avail_comp);
+-
+- /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+- &m, sizeof(m));
+-
+- if (status) {
+- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+- __func__, status);
+-
+- ret = -1;
+- goto unlock;
+- }
+-
+- /* We are expecting a reply from the videocore */
+- wait_for_completion(&instance->msg_avail_comp);
+-
+- if (instance->result) {
+- LOG_ERR("%s: result=%d", __func__, instance->result);
+-
+- ret = -1;
+- goto unlock;
+- }
+-
+- ret = 0;
+-
+-unlock:
+- vchi_service_release(instance->vchi_handle);
+- mutex_unlock(&instance->vchi_mutex);
+-
+- return ret;
++ return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
+ }
+
+ static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
+ {
+- struct vc_audio_msg m;
+- struct bcm2835_audio_instance *instance = alsa_stream->instance;
+- int status;
+- int ret;
+-
+- mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle);
+-
+- m.type = VC_AUDIO_MSG_TYPE_START;
+-
+- /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+- &m, sizeof(m));
+-
+- if (status) {
+- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+- __func__, status);
+-
+- ret = -1;
+- goto unlock;
+- }
+-
+- ret = 0;
+-
+-unlock:
+- vchi_service_release(instance->vchi_handle);
+- mutex_unlock(&instance->vchi_mutex);
+- return ret;
++ return bcm2835_audio_send_simple(alsa_stream->instance,
++ VC_AUDIO_MSG_TYPE_START, false);
+ }
+
+ static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
+ {
+- struct vc_audio_msg m;
+- struct bcm2835_audio_instance *instance = alsa_stream->instance;
+- int status;
+- int ret;
+-
+- mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle);
+-
+- m.type = VC_AUDIO_MSG_TYPE_STOP;
+- m.u.stop.draining = alsa_stream->draining;
+-
+- /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+- &m, sizeof(m));
+-
+- if (status) {
+- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+- __func__, status);
+-
+- ret = -1;
+- goto unlock;
+- }
+-
+- ret = 0;
+-
+-unlock:
+- vchi_service_release(instance->vchi_handle);
+- mutex_unlock(&instance->vchi_mutex);
+- return ret;
++ return bcm2835_audio_send_simple(alsa_stream->instance,
++ VC_AUDIO_MSG_TYPE_STOP, false);
+ }
+
+ int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
+ {
+- struct vc_audio_msg m;
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
+- int status;
+- int ret;
++ int err;
+
+ my_workqueue_quit(alsa_stream);
+
+- mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle);
+-
+- m.type = VC_AUDIO_MSG_TYPE_CLOSE;
+-
+- /* Create the message available completion */
+- init_completion(&instance->msg_avail_comp);
+-
+- /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+- &m, sizeof(m));
+-
+- if (status) {
+- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+- __func__, status);
+- ret = -1;
+- goto unlock;
+- }
+-
+- /* We are expecting a reply from the videocore */
+- wait_for_completion(&instance->msg_avail_comp);
+-
+- if (instance->result) {
+- LOG_ERR("%s: failed result (result=%d)\n",
+- __func__, instance->result);
+-
+- ret = -1;
+- goto unlock;
+- }
+-
+- ret = 0;
+-
+-unlock:
+- vchi_service_release(instance->vchi_handle);
+- mutex_unlock(&instance->vchi_mutex);
++ err = bcm2835_audio_send_simple(alsa_stream->instance,
++ VC_AUDIO_MSG_TYPE_CLOSE, true);
+
+ /* Stop the audio service */
+ vc_vchi_audio_deinit(instance);
+ alsa_stream->instance = NULL;
+
+- return ret;
++ return err;
+ }
+
+ static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
+- unsigned int count, void *src)
++ unsigned int size, void *src)
+ {
+- struct vc_audio_msg m;
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
+- int status;
+- int ret;
+-
+- LOG_INFO(" Writing %d bytes from %p\n", count, src);
+-
+- mutex_lock(&instance->vchi_mutex);
+- vchi_service_use(instance->vchi_handle);
++ struct vc_audio_msg m = {
++ .type = VC_AUDIO_MSG_TYPE_WRITE,
++ .u.write.count = size,
++ .u.write.max_packet = instance->max_packet,
++ .u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1,
++ .u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2,
++ };
++ unsigned int count;
++ int err, status;
+
+- if (instance->peer_version == 0 &&
+- vchi_get_peer_version(instance->vchi_handle, &instance->peer_version) == 0)
+- LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
+-
+- m.type = VC_AUDIO_MSG_TYPE_WRITE;
+- m.u.write.count = count;
+- // old version uses bulk, new version uses control
+- m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0 : 4000;
+- m.u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1;
+- m.u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2;
+- m.u.write.silence = src == NULL;
+-
+- /* Send the message to the videocore */
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+- &m, sizeof(m));
++ if (!size)
++ return 0;
+
+- if (status) {
+- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+- __func__, status);
+-
+- ret = -1;
++ bcm2835_audio_lock(instance);
++ err = bcm2835_audio_send_msg_locked(instance, &m, false);
++ if (err < 0)
+ goto unlock;
+- }
+- if (!m.u.write.silence) {
+- if (!m.u.write.max_packet) {
+- /* Send the message to the videocore */
+- status = vchi_bulk_queue_transmit(instance->vchi_handle,
+- src, count,
+- 0 * VCHI_FLAGS_BLOCK_UNTIL_QUEUED
+- +
+- 1 * VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
+- NULL);
+- } else {
+- while (count > 0) {
+- int bytes = min_t(int, m.u.write.max_packet, count);
+
+- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+- src, bytes);
+- src = (char *)src + bytes;
+- count -= bytes;
+- }
+- }
+- if (status) {
+- LOG_ERR("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
+- __func__, status);
++ count = size;
++ if (!instance->max_packet) {
++ /* Send the message to the videocore */
++ status = vchi_bulk_queue_transmit(instance->vchi_handle,
++ src, count,
++ VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
++ NULL);
++ } else {
++ while (count > 0) {
++ int bytes = min(instance->max_packet, count);
+
+- ret = -1;
+- goto unlock;
++ status = vchi_queue_kernel_message(instance->vchi_handle,
++ src, bytes);
++ src += bytes;
++ count -= bytes;
+ }
+ }
+- ret = 0;
+
+-unlock:
+- vchi_service_release(instance->vchi_handle);
+- mutex_unlock(&instance->vchi_mutex);
+- return ret;
++ if (status) {
++ LOG_ERR("failed on %d bytes transfer (status=%d)\n",
++ size, status);
++ err = -EIO;
++ }
++
++ unlock:
++ bcm2835_audio_unlock(instance);
++ return err;
+ }
+
+ unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)
+++ /dev/null
-From 98a1612b199cb3060306c05d1a6d7ca18ef08475 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:47 +0200
-Subject: [PATCH] staging: bcm2835-audio: Make single vchi handle
-
-commit 326a6edcb2ada56375bd7d3fc24c83f58e8da7f3 upstream.
-
-The bcm2835_audio_instance object contains the array of
-VCHI_SERVICE_HANDLE_T, while the code assumes and uses only the first
-element explicitly. Let's reduce to a single vchi handle for
-simplifying the code.
-
----
- .../bcm2835-audio/bcm2835-vchiq.c | 170 ++++++------------
- 1 file changed, 58 insertions(+), 112 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -44,8 +44,7 @@
- #endif
-
- struct bcm2835_audio_instance {
-- unsigned int num_connections;
-- VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
-+ VCHI_SERVICE_HANDLE_T vchi_handle;
- struct completion msg_avail_comp;
- struct mutex vchi_mutex;
- struct bcm2835_alsa_stream *alsa_stream;
-@@ -202,12 +201,12 @@ static void audio_vchi_callback(void *pa
- BUG();
- return;
- }
-- if (!instance->vchi_handle[0]) {
-- LOG_ERR(" .. instance->vchi_handle[0] is null\n");
-+ if (!instance->vchi_handle) {
-+ LOG_ERR(" .. instance->vchi_handle is null\n");
- BUG();
- return;
- }
-- status = vchi_msg_dequeue(instance->vchi_handle[0],
-+ status = vchi_msg_dequeue(instance->vchi_handle,
- &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
- if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
- LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
-@@ -237,102 +236,61 @@ static void audio_vchi_callback(void *pa
-
- static struct bcm2835_audio_instance *
- vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
-- VCHI_CONNECTION_T **vchi_connections,
-- unsigned int num_connections)
-+ VCHI_CONNECTION_T *vchi_connection)
- {
-- unsigned int i;
-+ SERVICE_CREATION_T params = {
-+ .version = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
-+ .service_id = VC_AUDIO_SERVER_NAME,
-+ .connection = vchi_connection,
-+ .rx_fifo_size = 0,
-+ .tx_fifo_size = 0,
-+ .callback = audio_vchi_callback,
-+ .want_unaligned_bulk_rx = 1, //TODO: remove VCOS_FALSE
-+ .want_unaligned_bulk_tx = 1, //TODO: remove VCOS_FALSE
-+ .want_crc = 0
-+ };
- struct bcm2835_audio_instance *instance;
- int status;
-- int ret;
--
-- LOG_DBG("%s: start", __func__);
-
-- if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
-- LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
-- __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
--
-- return ERR_PTR(-EINVAL);
-- }
- /* Allocate memory for this instance */
- instance = kzalloc(sizeof(*instance), GFP_KERNEL);
- if (!instance)
- return ERR_PTR(-ENOMEM);
-
-- instance->num_connections = num_connections;
--
- /* Create a lock for exclusive, serialized VCHI connection access */
- mutex_init(&instance->vchi_mutex);
- /* Open the VCHI service connections */
-- for (i = 0; i < num_connections; i++) {
-- SERVICE_CREATION_T params = {
-- .version = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
-- .service_id = VC_AUDIO_SERVER_NAME,
-- .connection = vchi_connections[i],
-- .rx_fifo_size = 0,
-- .tx_fifo_size = 0,
-- .callback = audio_vchi_callback,
-- .callback_param = instance,
-- .want_unaligned_bulk_rx = 1, //TODO: remove VCOS_FALSE
-- .want_unaligned_bulk_tx = 1, //TODO: remove VCOS_FALSE
-- .want_crc = 0
-- };
--
-- LOG_DBG("%s: about to open %i\n", __func__, i);
-- status = vchi_service_open(vchi_instance, ¶ms,
-- &instance->vchi_handle[i]);
-+ params.callback_param = instance,
-
-- LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
-- if (status) {
-- LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
-- __func__, status);
-- ret = -EPERM;
-- goto err_close_services;
-- }
-- /* Finished with the service for now */
-- vchi_service_release(instance->vchi_handle[i]);
-- }
--
-- LOG_DBG("%s: okay\n", __func__);
-- return instance;
-+ status = vchi_service_open(vchi_instance, ¶ms,
-+ &instance->vchi_handle);
-
--err_close_services:
-- for (i = 0; i < instance->num_connections; i++) {
-- LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]);
-- if (instance->vchi_handle[i])
-- vchi_service_close(instance->vchi_handle[i]);
-+ if (status) {
-+ LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
-+ __func__, status);
-+ kfree(instance);
-+ return ERR_PTR(-EPERM);
- }
-
-- kfree(instance);
-- LOG_ERR("%s: error\n", __func__);
-+ /* Finished with the service for now */
-+ vchi_service_release(instance->vchi_handle);
-
-- return ERR_PTR(ret);
-+ return instance;
- }
-
- static int vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
- {
-- unsigned int i;
--
-- if (!instance) {
-- LOG_ERR("%s: invalid handle %p\n", __func__, instance);
--
-- return -1;
-- }
-+ int status;
-
-- LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
- mutex_lock(&instance->vchi_mutex);
-
- /* Close all VCHI service connections */
-- for (i = 0; i < instance->num_connections; i++) {
-- int status;
--
-- LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
-- vchi_service_use(instance->vchi_handle[i]);
-+ vchi_service_use(instance->vchi_handle);
-
-- status = vchi_service_close(instance->vchi_handle[i]);
-- if (status) {
-- LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
-- __func__, status);
-- }
-+ status = vchi_service_close(instance->vchi_handle);
-+ if (status) {
-+ LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
-+ __func__, status);
- }
-
- mutex_unlock(&instance->vchi_mutex);
-@@ -383,19 +341,9 @@ static int bcm2835_audio_open_connection
- (struct bcm2835_audio_instance *)alsa_stream->instance;
- struct bcm2835_vchi_ctx *vhci_ctx = alsa_stream->chip->vchi_ctx;
-
-- LOG_INFO("%s: start\n", __func__);
-- BUG_ON(instance);
-- if (instance) {
-- LOG_ERR("%s: VCHI instance already open (%p)\n",
-- __func__, instance);
-- instance->alsa_stream = alsa_stream;
-- alsa_stream->instance = instance;
-- return 0;
-- }
--
- /* Initialize an instance of the audio service */
- instance = vc_vchi_audio_init(vhci_ctx->vchi_instance,
-- &vhci_ctx->vchi_connection, 1);
-+ vhci_ctx->vchi_connection);
-
- if (IS_ERR(instance)) {
- LOG_ERR("%s: failed to initialize audio service\n", __func__);
-@@ -407,8 +355,6 @@ static int bcm2835_audio_open_connection
- instance->alsa_stream = alsa_stream;
- alsa_stream->instance = instance;
-
-- LOG_DBG(" success !\n");
--
- return 0;
- }
-
-@@ -431,12 +377,12 @@ int bcm2835_audio_open(struct bcm2835_al
- LOG_DBG(" instance (%p)\n", instance);
-
- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle[0]);
-+ vchi_service_use(instance->vchi_handle);
-
- m.type = VC_AUDIO_MSG_TYPE_OPEN;
-
- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
-+ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
- &m, sizeof(m));
-
- if (status) {
-@@ -450,7 +396,7 @@ int bcm2835_audio_open(struct bcm2835_al
- ret = 0;
-
- unlock:
-- vchi_service_release(instance->vchi_handle[0]);
-+ vchi_service_release(instance->vchi_handle);
- mutex_unlock(&instance->vchi_mutex);
-
- free_wq:
-@@ -472,7 +418,7 @@ int bcm2835_audio_set_ctls(struct bcm283
- chip->dest, chip->volume);
-
- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle[0]);
-+ vchi_service_use(instance->vchi_handle);
-
- instance->result = -1;
-
-@@ -487,7 +433,7 @@ int bcm2835_audio_set_ctls(struct bcm283
- init_completion(&instance->msg_avail_comp);
-
- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
-+ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
- &m, sizeof(m));
-
- if (status) {
-@@ -511,7 +457,7 @@ int bcm2835_audio_set_ctls(struct bcm283
- ret = 0;
-
- unlock:
-- vchi_service_release(instance->vchi_handle[0]);
-+ vchi_service_release(instance->vchi_handle);
- mutex_unlock(&instance->vchi_mutex);
-
- return ret;
-@@ -537,7 +483,7 @@ int bcm2835_audio_set_params(struct bcm2
- }
-
- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle[0]);
-+ vchi_service_use(instance->vchi_handle);
-
- instance->result = -1;
-
-@@ -550,7 +496,7 @@ int bcm2835_audio_set_params(struct bcm2
- init_completion(&instance->msg_avail_comp);
-
- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
-+ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
- &m, sizeof(m));
-
- if (status) {
-@@ -574,7 +520,7 @@ int bcm2835_audio_set_params(struct bcm2
- ret = 0;
-
- unlock:
-- vchi_service_release(instance->vchi_handle[0]);
-+ vchi_service_release(instance->vchi_handle);
- mutex_unlock(&instance->vchi_mutex);
-
- return ret;
-@@ -588,12 +534,12 @@ static int bcm2835_audio_start_worker(st
- int ret;
-
- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle[0]);
-+ vchi_service_use(instance->vchi_handle);
-
- m.type = VC_AUDIO_MSG_TYPE_START;
-
- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
-+ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
- &m, sizeof(m));
-
- if (status) {
-@@ -607,7 +553,7 @@ static int bcm2835_audio_start_worker(st
- ret = 0;
-
- unlock:
-- vchi_service_release(instance->vchi_handle[0]);
-+ vchi_service_release(instance->vchi_handle);
- mutex_unlock(&instance->vchi_mutex);
- return ret;
- }
-@@ -620,13 +566,13 @@ static int bcm2835_audio_stop_worker(str
- int ret;
-
- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle[0]);
-+ vchi_service_use(instance->vchi_handle);
-
- m.type = VC_AUDIO_MSG_TYPE_STOP;
- m.u.stop.draining = alsa_stream->draining;
-
- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
-+ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
- &m, sizeof(m));
-
- if (status) {
-@@ -640,7 +586,7 @@ static int bcm2835_audio_stop_worker(str
- ret = 0;
-
- unlock:
-- vchi_service_release(instance->vchi_handle[0]);
-+ vchi_service_release(instance->vchi_handle);
- mutex_unlock(&instance->vchi_mutex);
- return ret;
- }
-@@ -655,7 +601,7 @@ int bcm2835_audio_close(struct bcm2835_a
- my_workqueue_quit(alsa_stream);
-
- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle[0]);
-+ vchi_service_use(instance->vchi_handle);
-
- m.type = VC_AUDIO_MSG_TYPE_CLOSE;
-
-@@ -663,7 +609,7 @@ int bcm2835_audio_close(struct bcm2835_a
- init_completion(&instance->msg_avail_comp);
-
- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
-+ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
- &m, sizeof(m));
-
- if (status) {
-@@ -687,7 +633,7 @@ int bcm2835_audio_close(struct bcm2835_a
- ret = 0;
-
- unlock:
-- vchi_service_release(instance->vchi_handle[0]);
-+ vchi_service_release(instance->vchi_handle);
- mutex_unlock(&instance->vchi_mutex);
-
- /* Stop the audio service */
-@@ -708,10 +654,10 @@ static int bcm2835_audio_write_worker(st
- LOG_INFO(" Writing %d bytes from %p\n", count, src);
-
- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle[0]);
-+ vchi_service_use(instance->vchi_handle);
-
- if (instance->peer_version == 0 &&
-- vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0)
-+ vchi_get_peer_version(instance->vchi_handle, &instance->peer_version) == 0)
- LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
-
- m.type = VC_AUDIO_MSG_TYPE_WRITE;
-@@ -723,7 +669,7 @@ static int bcm2835_audio_write_worker(st
- m.u.write.silence = src == NULL;
-
- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
-+ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
- &m, sizeof(m));
-
- if (status) {
-@@ -736,7 +682,7 @@ static int bcm2835_audio_write_worker(st
- if (!m.u.write.silence) {
- if (!m.u.write.max_packet) {
- /* Send the message to the videocore */
-- status = vchi_bulk_queue_transmit(instance->vchi_handle[0],
-+ status = vchi_bulk_queue_transmit(instance->vchi_handle,
- src, count,
- 0 * VCHI_FLAGS_BLOCK_UNTIL_QUEUED
- +
-@@ -746,7 +692,7 @@ static int bcm2835_audio_write_worker(st
- while (count > 0) {
- int bytes = min_t(int, m.u.write.max_packet, count);
-
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
-+ status = bcm2835_vchi_msg_queue(instance->vchi_handle,
- src, bytes);
- src = (char *)src + bytes;
- count -= bytes;
-@@ -763,7 +709,7 @@ static int bcm2835_audio_write_worker(st
- ret = 0;
-
- unlock:
-- vchi_service_release(instance->vchi_handle[0]);
-+ vchi_service_release(instance->vchi_handle);
- mutex_unlock(&instance->vchi_mutex);
- return ret;
- }
--- /dev/null
+From 87ba8310e9f0882e85926ac1ef91333f8906b303 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:49 +0200
+Subject: [PATCH] staging: bcm2835-audio: Operate non-atomic PCM ops
+
+commit 5c7883e5f27e829f3f3a2ba174d4a724bfd5f026 upstream.
+
+This is the most significant part in the patch series.
+
+The bcm2835-audio driver used to queue the commands to vc04 core via
+workqueue, but basically the whole accesses to vc04 core are done in
+the sleepable context, including the callback calls. In such a case,
+rewriting the code using non-atomic PCM ops will simplify the logic a
+lot.
+
+This patch does it: all workqueue are gone and each former-work
+implementation is now directly called from PCM ops like trigger and
+write transfer.
+
+Along with it, the DMA position updater, bcm2835_playback_fifo(), was
+also rewritten to use a simpler logic. Now it handles the XRUN and
+draining properly by calling snd_pcm_stop() conditionally.
+
+The current position is kept in atomic_t value so that it can be read
+concurrently from the pointer callback.
+
+Also, the bcm2835_audio_instance object is allocated at the beginning
+of bcm2835_audio_open(). This makes the resource management clearer.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 74 +++---
+ .../bcm2835-audio/bcm2835-vchiq.c | 244 +++---------------
+ .../vc04_services/bcm2835-audio/bcm2835.h | 9 +-
+ 3 files changed, 82 insertions(+), 245 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -11,7 +11,8 @@
+ /* hardware definition */
+ static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
++ SNDRV_PCM_INFO_DRAIN_TRIGGER),
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+@@ -27,7 +28,8 @@ static const struct snd_pcm_hardware snd
+
+ static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
++ SNDRV_PCM_INFO_DRAIN_TRIGGER),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000,
+@@ -47,42 +49,34 @@ static void snd_bcm2835_playback_free(st
+ kfree(runtime->private_data);
+ }
+
+-void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream)
++void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream,
++ unsigned int bytes)
+ {
+- unsigned int consumed = 0;
+- int new_period = 0;
++ struct snd_pcm_substream *substream = alsa_stream->substream;
++ unsigned int pos;
+
+- audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
+- alsa_stream ? alsa_stream->substream : 0);
++ if (!alsa_stream->period_size)
++ return;
+
+- consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
+-
+- /* We get called only if playback was triggered, So, the number of buffers we retrieve in
+- * each iteration are the buffers that have been played out already
+- */
+-
+- if (alsa_stream->period_size) {
+- if ((alsa_stream->pos / alsa_stream->period_size) !=
+- ((alsa_stream->pos + consumed) / alsa_stream->period_size))
+- new_period = 1;
+- }
+- audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
+- alsa_stream->pos,
+- consumed,
+- alsa_stream->buffer_size,
+- (int) (alsa_stream->period_size * alsa_stream->substream->runtime->periods),
+- frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
+- new_period);
+- if (alsa_stream->buffer_size) {
+- alsa_stream->pos += consumed & ~(1 << 30);
+- alsa_stream->pos %= alsa_stream->buffer_size;
++ if (bytes >= alsa_stream->buffer_size) {
++ snd_pcm_stream_lock(substream);
++ snd_pcm_stop(substream,
++ alsa_stream->draining ?
++ SNDRV_PCM_STATE_SETUP :
++ SNDRV_PCM_STATE_XRUN);
++ snd_pcm_stream_unlock(substream);
++ return;
+ }
+
+- if (alsa_stream->substream) {
+- if (new_period)
+- snd_pcm_period_elapsed(alsa_stream->substream);
+- } else {
+- audio_warning(" unexpected NULL substream\n");
++ pos = atomic_read(&alsa_stream->pos);
++ pos += bytes;
++ pos %= alsa_stream->buffer_size;
++ atomic_set(&alsa_stream->pos, pos);
++
++ alsa_stream->period_offset += bytes;
++ if (alsa_stream->period_offset >= alsa_stream->period_size) {
++ alsa_stream->period_offset %= alsa_stream->period_size;
++ snd_pcm_period_elapsed(substream);
+ }
+ }
+
+@@ -246,7 +240,8 @@ static int snd_bcm2835_pcm_prepare(struc
+
+ alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
+ alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
+- alsa_stream->pos = 0;
++ atomic_set(&alsa_stream->pos, 0);
++ alsa_stream->period_offset = 0;
+ alsa_stream->draining = false;
+
+ return 0;
+@@ -283,7 +278,7 @@ static int snd_bcm2835_pcm_trigger(struc
+ return bcm2835_audio_start(alsa_stream);
+ case SNDRV_PCM_TRIGGER_DRAIN:
+ alsa_stream->draining = true;
+- return 0;
++ return bcm2835_audio_drain(alsa_stream);
+ case SNDRV_PCM_TRIGGER_STOP:
+ return bcm2835_audio_stop(alsa_stream);
+ default:
+@@ -300,7 +295,7 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
+
+ return snd_pcm_indirect_playback_pointer(substream,
+ &alsa_stream->pcm_indirect,
+- alsa_stream->pos);
++ atomic_read(&alsa_stream->pos));
+ }
+
+ /* operators */
+@@ -338,6 +333,7 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
+ if (err < 0)
+ return err;
+ pcm->private_data = chip;
++ pcm->nonatomic = true;
+ strcpy(pcm->name, "bcm2835 ALSA");
+ chip->pcm = pcm;
+ chip->dest = AUDIO_DEST_AUTO;
+@@ -367,6 +363,7 @@ int snd_bcm2835_new_spdif_pcm(struct bcm
+ return err;
+
+ pcm->private_data = chip;
++ pcm->nonatomic = true;
+ strcpy(pcm->name, "bcm2835 IEC958/HDMI");
+ chip->pcm_spdif = pcm;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+@@ -395,6 +392,7 @@ int snd_bcm2835_new_simple_pcm(struct bc
+ return err;
+
+ pcm->private_data = chip;
++ pcm->nonatomic = true;
+ strcpy(pcm->name, name);
+ chip->pcm = pcm;
+ chip->dest = route;
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -26,10 +26,6 @@
+
+ /* ---- Private Constants and Types ------------------------------------------ */
+
+-#define BCM2835_AUDIO_STOP 0
+-#define BCM2835_AUDIO_START 1
+-#define BCM2835_AUDIO_WRITE 2
+-
+ /* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
+ #ifdef AUDIO_DEBUG_ENABLE
+ #define LOG_ERR(fmt, arg...) pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
+@@ -55,17 +51,6 @@ struct bcm2835_audio_instance {
+
+ static bool force_bulk;
+
+-/* ---- Private Variables ---------------------------------------------------- */
+-
+-/* ---- Private Function Prototypes ------------------------------------------ */
+-
+-/* ---- Private Functions ---------------------------------------------------- */
+-
+-static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream);
+-static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream);
+-static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
+- unsigned int count, void *src);
+-
+ static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
+ {
+ mutex_lock(&instance->vchi_mutex);
+@@ -135,108 +120,6 @@ static const u32 BCM2835_AUDIO_WRITE_COO
+ static const u32 BCM2835_AUDIO_WRITE_COOKIE2 = ('D' << 24 | 'A' << 16 |
+ 'T' << 8 | 'A');
+
+-struct bcm2835_audio_work {
+- struct work_struct my_work;
+- struct bcm2835_alsa_stream *alsa_stream;
+- int cmd;
+- void *src;
+- unsigned int count;
+-};
+-
+-static void my_wq_function(struct work_struct *work)
+-{
+- struct bcm2835_audio_work *w =
+- container_of(work, struct bcm2835_audio_work, my_work);
+- int ret = -9;
+-
+- switch (w->cmd) {
+- case BCM2835_AUDIO_START:
+- ret = bcm2835_audio_start_worker(w->alsa_stream);
+- break;
+- case BCM2835_AUDIO_STOP:
+- ret = bcm2835_audio_stop_worker(w->alsa_stream);
+- break;
+- case BCM2835_AUDIO_WRITE:
+- ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
+- w->src);
+- break;
+- default:
+- LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
+- break;
+- }
+- kfree((void *)work);
+-}
+-
+-int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
+-{
+- struct bcm2835_audio_work *work;
+-
+- work = kmalloc(sizeof(*work), GFP_ATOMIC);
+- /*--- Queue some work (item 1) ---*/
+- if (!work) {
+- LOG_ERR(" .. Error: NULL work kmalloc\n");
+- return -ENOMEM;
+- }
+- INIT_WORK(&work->my_work, my_wq_function);
+- work->alsa_stream = alsa_stream;
+- work->cmd = BCM2835_AUDIO_START;
+- if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
+- kfree(work);
+- return -EBUSY;
+- }
+- return 0;
+-}
+-
+-int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
+-{
+- struct bcm2835_audio_work *work;
+-
+- work = kmalloc(sizeof(*work), GFP_ATOMIC);
+- /*--- Queue some work (item 1) ---*/
+- if (!work) {
+- LOG_ERR(" .. Error: NULL work kmalloc\n");
+- return -ENOMEM;
+- }
+- INIT_WORK(&work->my_work, my_wq_function);
+- work->alsa_stream = alsa_stream;
+- work->cmd = BCM2835_AUDIO_STOP;
+- if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
+- kfree(work);
+- return -EBUSY;
+- }
+- return 0;
+-}
+-
+-int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
+- unsigned int count, void *src)
+-{
+- struct bcm2835_audio_work *work;
+-
+- work = kmalloc(sizeof(*work), GFP_ATOMIC);
+- /*--- Queue some work (item 1) ---*/
+- if (!work) {
+- LOG_ERR(" .. Error: NULL work kmalloc\n");
+- return -ENOMEM;
+- }
+- INIT_WORK(&work->my_work, my_wq_function);
+- work->alsa_stream = alsa_stream;
+- work->cmd = BCM2835_AUDIO_WRITE;
+- work->src = src;
+- work->count = count;
+- if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
+- kfree(work);
+- return -EBUSY;
+- }
+- return 0;
+-}
+-
+-static void my_workqueue_quit(struct bcm2835_alsa_stream *alsa_stream)
+-{
+- flush_workqueue(alsa_stream->my_wq);
+- destroy_workqueue(alsa_stream->my_wq);
+- alsa_stream->my_wq = NULL;
+-}
+-
+ static void audio_vchi_callback(void *param,
+ const VCHI_CALLBACK_REASON_T reason,
+ void *msg_handle)
+@@ -249,47 +132,27 @@ static void audio_vchi_callback(void *pa
+ if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
+ return;
+
+- if (!instance) {
+- LOG_ERR(" .. instance is null\n");
+- BUG();
+- return;
+- }
+- if (!instance->vchi_handle) {
+- LOG_ERR(" .. instance->vchi_handle is null\n");
+- BUG();
+- return;
+- }
+ status = vchi_msg_dequeue(instance->vchi_handle,
+ &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
+ if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
+- LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
+- instance, m.u.result.success);
+ instance->result = m.u.result.success;
+ complete(&instance->msg_avail_comp);
+ } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
+- struct bcm2835_alsa_stream *alsa_stream = instance->alsa_stream;
+-
+- LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
+- instance, m.u.complete.count);
+ if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
+ m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
+- LOG_ERR(" .. response is corrupt\n");
+- else if (alsa_stream) {
+- atomic_add(m.u.complete.count,
+- &alsa_stream->retrieved);
+- bcm2835_playback_fifo(alsa_stream);
+- } else {
+- LOG_ERR(" .. unexpected alsa_stream=%p\n",
+- alsa_stream);
+- }
++ LOG_ERR("invalid cookie\n");
++ else
++ bcm2835_playback_fifo(instance->alsa_stream,
++ m.u.complete.count);
+ } else {
+- LOG_ERR(" .. unexpected m.type=%d\n", m.type);
++ LOG_ERR("unexpected callback type=%d\n", m.type);
+ }
+ }
+
+-static struct bcm2835_audio_instance *
++static int
+ vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
+- VCHI_CONNECTION_T *vchi_connection)
++ VCHI_CONNECTION_T *vchi_connection,
++ struct bcm2835_audio_instance *instance)
+ {
+ SERVICE_CREATION_T params = {
+ .version = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
+@@ -298,23 +161,14 @@ vc_vchi_audio_init(VCHI_INSTANCE_T vchi_
+ .rx_fifo_size = 0,
+ .tx_fifo_size = 0,
+ .callback = audio_vchi_callback,
++ .callback_param = instance,
+ .want_unaligned_bulk_rx = 1, //TODO: remove VCOS_FALSE
+ .want_unaligned_bulk_tx = 1, //TODO: remove VCOS_FALSE
+ .want_crc = 0
+ };
+- struct bcm2835_audio_instance *instance;
+ int status;
+
+- /* Allocate memory for this instance */
+- instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+- if (!instance)
+- return ERR_PTR(-ENOMEM);
+-
+- /* Create a lock for exclusive, serialized VCHI connection access */
+- mutex_init(&instance->vchi_mutex);
+ /* Open the VCHI service connections */
+- params.callback_param = instance,
+-
+ status = vchi_service_open(vchi_instance, ¶ms,
+ &instance->vchi_handle);
+
+@@ -322,16 +176,16 @@ vc_vchi_audio_init(VCHI_INSTANCE_T vchi_
+ LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
+ __func__, status);
+ kfree(instance);
+- return ERR_PTR(-EPERM);
++ return -EPERM;
+ }
+
+ /* Finished with the service for now */
+ vchi_service_release(instance->vchi_handle);
+
+- return instance;
++ return 0;
+ }
+
+-static int vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
++static void vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
+ {
+ int status;
+
+@@ -346,10 +200,6 @@ static int vc_vchi_audio_deinit(struct b
+ }
+
+ mutex_unlock(&instance->vchi_mutex);
+-
+- kfree(instance);
+-
+- return 0;
+ }
+
+ int bcm2835_new_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
+@@ -387,39 +237,25 @@ void bcm2835_free_vchi_ctx(struct bcm283
+ vchi_ctx->vchi_instance = NULL;
+ }
+
+-static int bcm2835_audio_open_connection(struct bcm2835_alsa_stream *alsa_stream)
+-{
+- struct bcm2835_audio_instance *instance =
+- (struct bcm2835_audio_instance *)alsa_stream->instance;
+- struct bcm2835_vchi_ctx *vhci_ctx = alsa_stream->chip->vchi_ctx;
+-
+- /* Initialize an instance of the audio service */
+- instance = vc_vchi_audio_init(vhci_ctx->vchi_instance,
+- vhci_ctx->vchi_connection);
+-
+- if (IS_ERR(instance))
+- return PTR_ERR(instance);
+-
+- instance->alsa_stream = alsa_stream;
+- alsa_stream->instance = instance;
+-
+- return 0;
+-}
+-
+ int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
+ {
++ struct bcm2835_vchi_ctx *vchi_ctx = alsa_stream->chip->vchi_ctx;
+ struct bcm2835_audio_instance *instance;
+ int err;
+
+- alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
+- if (!alsa_stream->my_wq)
++ /* Allocate memory for this instance */
++ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
++ if (!instance)
+ return -ENOMEM;
++ mutex_init(&instance->vchi_mutex);
++ instance->alsa_stream = alsa_stream;
++ alsa_stream->instance = instance;
+
+- err = bcm2835_audio_open_connection(alsa_stream);
++ err = vc_vchi_audio_init(vchi_ctx->vchi_instance,
++ vchi_ctx->vchi_connection,
++ instance);
+ if (err < 0)
+- goto free_wq;
+-
+- instance = alsa_stream->instance;
++ goto free_instance;
+
+ err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
+ false);
+@@ -438,8 +274,9 @@ int bcm2835_audio_open(struct bcm2835_al
+
+ deinit:
+ vc_vchi_audio_deinit(instance);
+- free_wq:
+- destroy_workqueue(alsa_stream->my_wq);
++ free_instance:
++ alsa_stream->instance = NULL;
++ kfree(instance);
+ return err;
+ }
+
+@@ -478,37 +315,46 @@ int bcm2835_audio_set_params(struct bcm2
+ return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
+ }
+
+-static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
++int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
+ {
+ return bcm2835_audio_send_simple(alsa_stream->instance,
+ VC_AUDIO_MSG_TYPE_START, false);
+ }
+
+-static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
++int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
+ {
+ return bcm2835_audio_send_simple(alsa_stream->instance,
+ VC_AUDIO_MSG_TYPE_STOP, false);
+ }
+
++int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream)
++{
++ struct vc_audio_msg m = {
++ .type = VC_AUDIO_MSG_TYPE_STOP,
++ .u.stop.draining = 1,
++ };
++
++ return bcm2835_audio_send_msg(alsa_stream->instance, &m, false);
++}
++
+ int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
+ {
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
+ int err;
+
+- my_workqueue_quit(alsa_stream);
+-
+ err = bcm2835_audio_send_simple(alsa_stream->instance,
+ VC_AUDIO_MSG_TYPE_CLOSE, true);
+
+ /* Stop the audio service */
+ vc_vchi_audio_deinit(instance);
+ alsa_stream->instance = NULL;
++ kfree(instance);
+
+ return err;
+ }
+
+-static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
+- unsigned int size, void *src)
++int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
++ unsigned int size, void *src)
+ {
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
+ struct vc_audio_msg m = {
+@@ -558,13 +404,5 @@ static int bcm2835_audio_write_worker(st
+ return err;
+ }
+
+-unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)
+-{
+- unsigned int count = atomic_read(&alsa_stream->retrieved);
+-
+- atomic_sub(count, &alsa_stream->retrieved);
+- return count;
+-}
+-
+ module_param(force_bulk, bool, 0444);
+ MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -121,13 +121,12 @@ struct bcm2835_alsa_stream {
+
+ int draining;
+
+- unsigned int pos;
++ atomic_t pos;
++ unsigned int period_offset;
+ unsigned int buffer_size;
+ unsigned int period_size;
+
+- atomic_t retrieved;
+ struct bcm2835_audio_instance *instance;
+- struct workqueue_struct *my_wq;
+ int idx;
+ };
+
+@@ -152,11 +151,13 @@ int bcm2835_audio_set_params(struct bcm2
+ unsigned int bps);
+ int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream);
+ int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream);
++int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream);
+ int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream);
+ int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int count,
+ void *src);
+-void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream);
++void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream,
++ unsigned int size);
+ unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream);
+
+ #endif /* __SOUND_ARM_BCM2835_H */
+++ /dev/null
-From 43f89ac74f3f221e3036a1ec311b24016860d15e Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:48 +0200
-Subject: [PATCH] staging: bcm2835-audio: Code refactoring of vchiq
- accessor codes
-
-commit 769a8e9bf5cf39813f52962fdafdf7e4d52ad585 upstream.
-
-This is a cleanup and code refactoring in bcm2835-vchiq.c.
-
-The major code changes are to provide local helpers for easier use of
-lock / unlock, and message passing with/without response wait. This
-allows us to reduce lots of open codes.
-
-Also, the max packet is set at opening the stream, not at each time
-when the write gets called.
-
----
- .../bcm2835-audio/bcm2835-vchiq.c | 440 ++++++------------
- 1 file changed, 142 insertions(+), 298 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -49,6 +49,7 @@ struct bcm2835_audio_instance {
- struct mutex vchi_mutex;
- struct bcm2835_alsa_stream *alsa_stream;
- int result;
-+ unsigned int max_packet;
- short peer_version;
- };
-
-@@ -65,16 +66,68 @@ static int bcm2835_audio_start_worker(st
- static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
- unsigned int count, void *src);
-
--// Routine to send a message across a service
-+static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
-+{
-+ mutex_lock(&instance->vchi_mutex);
-+ vchi_service_use(instance->vchi_handle);
-+}
-+
-+static void bcm2835_audio_unlock(struct bcm2835_audio_instance *instance)
-+{
-+ vchi_service_release(instance->vchi_handle);
-+ mutex_unlock(&instance->vchi_mutex);
-+}
-+
-+static int bcm2835_audio_send_msg_locked(struct bcm2835_audio_instance *instance,
-+ struct vc_audio_msg *m, bool wait)
-+{
-+ int status;
-+
-+ if (wait) {
-+ instance->result = -1;
-+ init_completion(&instance->msg_avail_comp);
-+ }
-+
-+ status = vchi_queue_kernel_message(instance->vchi_handle,
-+ m, sizeof(*m));
-+ if (status) {
-+ LOG_ERR("vchi message queue failed: %d, msg=%d\n",
-+ status, m->type);
-+ return -EIO;
-+ }
-+
-+ if (wait) {
-+ if (!wait_for_completion_timeout(&instance->msg_avail_comp,
-+ msecs_to_jiffies(10 * 1000))) {
-+ LOG_ERR("vchi message timeout, msg=%d\n", m->type);
-+ return -ETIMEDOUT;
-+ } else if (instance->result) {
-+ LOG_ERR("vchi message response error:%d, msg=%d\n",
-+ instance->result, m->type);
-+ return -EIO;
-+ }
-+ }
-+
-+ return 0;
-+}
-
--static int
--bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
-- void *data,
-- unsigned int size)
--{
-- return vchi_queue_kernel_message(handle,
-- data,
-- size);
-+static int bcm2835_audio_send_msg(struct bcm2835_audio_instance *instance,
-+ struct vc_audio_msg *m, bool wait)
-+{
-+ int err;
-+
-+ bcm2835_audio_lock(instance);
-+ err = bcm2835_audio_send_msg_locked(instance, m, wait);
-+ bcm2835_audio_unlock(instance);
-+ return err;
-+}
-+
-+static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance,
-+ int type, bool wait)
-+{
-+ struct vc_audio_msg m = { .type = type };
-+
-+ return bcm2835_audio_send_msg(instance, &m, wait);
- }
-
- static const u32 BCM2835_AUDIO_WRITE_COOKIE1 = ('B' << 24 | 'C' << 16 |
-@@ -283,10 +336,9 @@ static int vc_vchi_audio_deinit(struct b
- int status;
-
- mutex_lock(&instance->vchi_mutex);
--
-- /* Close all VCHI service connections */
- vchi_service_use(instance->vchi_handle);
-
-+ /* Close all VCHI service connections */
- status = vchi_service_close(instance->vchi_handle);
- if (status) {
- LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
-@@ -345,12 +397,8 @@ static int bcm2835_audio_open_connection
- instance = vc_vchi_audio_init(vhci_ctx->vchi_instance,
- vhci_ctx->vchi_connection);
-
-- if (IS_ERR(instance)) {
-- LOG_ERR("%s: failed to initialize audio service\n", __func__);
--
-- /* vchi_instance is retained for use the next time. */
-+ if (IS_ERR(instance))
- return PTR_ERR(instance);
-- }
-
- instance->alsa_stream = alsa_stream;
- alsa_stream->instance = instance;
-@@ -361,66 +409,44 @@ static int bcm2835_audio_open_connection
- int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
- {
- struct bcm2835_audio_instance *instance;
-- struct vc_audio_msg m;
-- int status;
-- int ret;
-+ int err;
-
- alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
- if (!alsa_stream->my_wq)
- return -ENOMEM;
-
-- ret = bcm2835_audio_open_connection(alsa_stream);
-- if (ret)
-+ err = bcm2835_audio_open_connection(alsa_stream);
-+ if (err < 0)
- goto free_wq;
-
- instance = alsa_stream->instance;
-- LOG_DBG(" instance (%p)\n", instance);
--
-- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle);
--
-- m.type = VC_AUDIO_MSG_TYPE_OPEN;
--
-- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
-- &m, sizeof(m));
--
-- if (status) {
-- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-- __func__, status);
--
-- ret = -1;
-- goto unlock;
-- }
--
-- ret = 0;
-
--unlock:
-- vchi_service_release(instance->vchi_handle);
-- mutex_unlock(&instance->vchi_mutex);
-+ err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
-+ false);
-+ if (err < 0)
-+ goto deinit;
-+
-+ bcm2835_audio_lock(instance);
-+ vchi_get_peer_version(instance->vchi_handle, &instance->peer_version);
-+ bcm2835_audio_unlock(instance);
-+ if (instance->peer_version < 2 || force_bulk)
-+ instance->max_packet = 0; /* bulk transfer */
-+ else
-+ instance->max_packet = 4000;
-
--free_wq:
-- if (ret)
-- destroy_workqueue(alsa_stream->my_wq);
-+ return 0;
-
-- return ret;
-+ deinit:
-+ vc_vchi_audio_deinit(instance);
-+ free_wq:
-+ destroy_workqueue(alsa_stream->my_wq);
-+ return err;
- }
-
- int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
- {
-- struct vc_audio_msg m;
-- struct bcm2835_audio_instance *instance = alsa_stream->instance;
- struct bcm2835_chip *chip = alsa_stream->chip;
-- int status;
-- int ret;
--
-- LOG_INFO(" Setting ALSA dest(%d), volume(%d)\n",
-- chip->dest, chip->volume);
--
-- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle);
--
-- instance->result = -1;
-+ struct vc_audio_msg m = {};
-
- m.type = VC_AUDIO_MSG_TYPE_CONTROL;
- m.u.control.dest = chip->dest;
-@@ -429,289 +455,107 @@ int bcm2835_audio_set_ctls(struct bcm283
- else
- m.u.control.volume = alsa2chip(chip->volume);
-
-- /* Create the message available completion */
-- init_completion(&instance->msg_avail_comp);
--
-- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
-- &m, sizeof(m));
--
-- if (status) {
-- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-- __func__, status);
--
-- ret = -1;
-- goto unlock;
-- }
--
-- /* We are expecting a reply from the videocore */
-- wait_for_completion(&instance->msg_avail_comp);
--
-- if (instance->result) {
-- LOG_ERR("%s: result=%d\n", __func__, instance->result);
--
-- ret = -1;
-- goto unlock;
-- }
--
-- ret = 0;
--
--unlock:
-- vchi_service_release(instance->vchi_handle);
-- mutex_unlock(&instance->vchi_mutex);
--
-- return ret;
-+ return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
- }
-
- int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
- unsigned int channels, unsigned int samplerate,
- unsigned int bps)
- {
-- struct vc_audio_msg m;
-- struct bcm2835_audio_instance *instance = alsa_stream->instance;
-- int status;
-- int ret;
--
-- LOG_INFO(" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
-- channels, samplerate, bps);
-+ struct vc_audio_msg m = {
-+ .type = VC_AUDIO_MSG_TYPE_CONFIG,
-+ .u.config.channels = channels,
-+ .u.config.samplerate = samplerate,
-+ .u.config.bps = bps,
-+ };
-+ int err;
-
- /* resend ctls - alsa_stream may not have been open when first send */
-- ret = bcm2835_audio_set_ctls(alsa_stream);
-- if (ret) {
-- LOG_ERR(" Alsa controls not supported\n");
-- return -EINVAL;
-- }
-+ err = bcm2835_audio_set_ctls(alsa_stream);
-+ if (err)
-+ return err;
-
-- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle);
--
-- instance->result = -1;
--
-- m.type = VC_AUDIO_MSG_TYPE_CONFIG;
-- m.u.config.channels = channels;
-- m.u.config.samplerate = samplerate;
-- m.u.config.bps = bps;
--
-- /* Create the message available completion */
-- init_completion(&instance->msg_avail_comp);
--
-- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
-- &m, sizeof(m));
--
-- if (status) {
-- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-- __func__, status);
--
-- ret = -1;
-- goto unlock;
-- }
--
-- /* We are expecting a reply from the videocore */
-- wait_for_completion(&instance->msg_avail_comp);
--
-- if (instance->result) {
-- LOG_ERR("%s: result=%d", __func__, instance->result);
--
-- ret = -1;
-- goto unlock;
-- }
--
-- ret = 0;
--
--unlock:
-- vchi_service_release(instance->vchi_handle);
-- mutex_unlock(&instance->vchi_mutex);
--
-- return ret;
-+ return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
- }
-
- static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
- {
-- struct vc_audio_msg m;
-- struct bcm2835_audio_instance *instance = alsa_stream->instance;
-- int status;
-- int ret;
--
-- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle);
--
-- m.type = VC_AUDIO_MSG_TYPE_START;
--
-- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
-- &m, sizeof(m));
--
-- if (status) {
-- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-- __func__, status);
--
-- ret = -1;
-- goto unlock;
-- }
--
-- ret = 0;
--
--unlock:
-- vchi_service_release(instance->vchi_handle);
-- mutex_unlock(&instance->vchi_mutex);
-- return ret;
-+ return bcm2835_audio_send_simple(alsa_stream->instance,
-+ VC_AUDIO_MSG_TYPE_START, false);
- }
-
- static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
- {
-- struct vc_audio_msg m;
-- struct bcm2835_audio_instance *instance = alsa_stream->instance;
-- int status;
-- int ret;
--
-- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle);
--
-- m.type = VC_AUDIO_MSG_TYPE_STOP;
-- m.u.stop.draining = alsa_stream->draining;
--
-- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
-- &m, sizeof(m));
--
-- if (status) {
-- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-- __func__, status);
--
-- ret = -1;
-- goto unlock;
-- }
--
-- ret = 0;
--
--unlock:
-- vchi_service_release(instance->vchi_handle);
-- mutex_unlock(&instance->vchi_mutex);
-- return ret;
-+ return bcm2835_audio_send_simple(alsa_stream->instance,
-+ VC_AUDIO_MSG_TYPE_STOP, false);
- }
-
- int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
- {
-- struct vc_audio_msg m;
- struct bcm2835_audio_instance *instance = alsa_stream->instance;
-- int status;
-- int ret;
-+ int err;
-
- my_workqueue_quit(alsa_stream);
-
-- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle);
--
-- m.type = VC_AUDIO_MSG_TYPE_CLOSE;
--
-- /* Create the message available completion */
-- init_completion(&instance->msg_avail_comp);
--
-- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
-- &m, sizeof(m));
--
-- if (status) {
-- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-- __func__, status);
-- ret = -1;
-- goto unlock;
-- }
--
-- /* We are expecting a reply from the videocore */
-- wait_for_completion(&instance->msg_avail_comp);
--
-- if (instance->result) {
-- LOG_ERR("%s: failed result (result=%d)\n",
-- __func__, instance->result);
--
-- ret = -1;
-- goto unlock;
-- }
--
-- ret = 0;
--
--unlock:
-- vchi_service_release(instance->vchi_handle);
-- mutex_unlock(&instance->vchi_mutex);
-+ err = bcm2835_audio_send_simple(alsa_stream->instance,
-+ VC_AUDIO_MSG_TYPE_CLOSE, true);
-
- /* Stop the audio service */
- vc_vchi_audio_deinit(instance);
- alsa_stream->instance = NULL;
-
-- return ret;
-+ return err;
- }
-
- static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
-- unsigned int count, void *src)
-+ unsigned int size, void *src)
- {
-- struct vc_audio_msg m;
- struct bcm2835_audio_instance *instance = alsa_stream->instance;
-- int status;
-- int ret;
--
-- LOG_INFO(" Writing %d bytes from %p\n", count, src);
--
-- mutex_lock(&instance->vchi_mutex);
-- vchi_service_use(instance->vchi_handle);
-+ struct vc_audio_msg m = {
-+ .type = VC_AUDIO_MSG_TYPE_WRITE,
-+ .u.write.count = size,
-+ .u.write.max_packet = instance->max_packet,
-+ .u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1,
-+ .u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2,
-+ };
-+ unsigned int count;
-+ int err, status;
-
-- if (instance->peer_version == 0 &&
-- vchi_get_peer_version(instance->vchi_handle, &instance->peer_version) == 0)
-- LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
--
-- m.type = VC_AUDIO_MSG_TYPE_WRITE;
-- m.u.write.count = count;
-- // old version uses bulk, new version uses control
-- m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0 : 4000;
-- m.u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1;
-- m.u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2;
-- m.u.write.silence = src == NULL;
--
-- /* Send the message to the videocore */
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
-- &m, sizeof(m));
-+ if (!size)
-+ return 0;
-
-- if (status) {
-- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-- __func__, status);
--
-- ret = -1;
-+ bcm2835_audio_lock(instance);
-+ err = bcm2835_audio_send_msg_locked(instance, &m, false);
-+ if (err < 0)
- goto unlock;
-- }
-- if (!m.u.write.silence) {
-- if (!m.u.write.max_packet) {
-- /* Send the message to the videocore */
-- status = vchi_bulk_queue_transmit(instance->vchi_handle,
-- src, count,
-- 0 * VCHI_FLAGS_BLOCK_UNTIL_QUEUED
-- +
-- 1 * VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
-- NULL);
-- } else {
-- while (count > 0) {
-- int bytes = min_t(int, m.u.write.max_packet, count);
-
-- status = bcm2835_vchi_msg_queue(instance->vchi_handle,
-- src, bytes);
-- src = (char *)src + bytes;
-- count -= bytes;
-- }
-- }
-- if (status) {
-- LOG_ERR("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
-- __func__, status);
-+ count = size;
-+ if (!instance->max_packet) {
-+ /* Send the message to the videocore */
-+ status = vchi_bulk_queue_transmit(instance->vchi_handle,
-+ src, count,
-+ VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
-+ NULL);
-+ } else {
-+ while (count > 0) {
-+ int bytes = min(instance->max_packet, count);
-
-- ret = -1;
-- goto unlock;
-+ status = vchi_queue_kernel_message(instance->vchi_handle,
-+ src, bytes);
-+ src += bytes;
-+ count -= bytes;
- }
- }
-- ret = 0;
-
--unlock:
-- vchi_service_release(instance->vchi_handle);
-- mutex_unlock(&instance->vchi_mutex);
-- return ret;
-+ if (status) {
-+ LOG_ERR("failed on %d bytes transfer (status=%d)\n",
-+ size, status);
-+ err = -EIO;
-+ }
-+
-+ unlock:
-+ bcm2835_audio_unlock(instance);
-+ return err;
- }
-
- unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)
--- /dev/null
+From af0ded6e9dd38f08a9ee621066e583b5cf972926 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:50 +0200
+Subject: [PATCH] staging: bcm2835-audio: Use card->private_data
+
+commit 898001a0c845cefe5d47d133485712412853f0a8 upstream.
+
+Instead of allocating a separate snd_device object, let snd_card_new()
+allocate the private resource. This simplifies the code.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835.c | 91 +++----------------
+ 1 file changed, 13 insertions(+), 78 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -86,9 +86,6 @@ static int bcm2835_devm_add_vchi_ctx(str
+
+ static void snd_bcm2835_release(struct device *dev)
+ {
+- struct bcm2835_chip *chip = dev_get_drvdata(dev);
+-
+- kfree(chip);
+ }
+
+ static struct device *
+@@ -117,69 +114,6 @@ snd_create_device(struct device *parent,
+ return device;
+ }
+
+-/* component-destructor
+- * (see "Management of Cards and Components")
+- */
+-static int snd_bcm2835_dev_free(struct snd_device *device)
+-{
+- struct bcm2835_chip *chip = device->device_data;
+- struct snd_card *card = chip->card;
+-
+- snd_device_free(card, chip);
+-
+- return 0;
+-}
+-
+-/* chip-specific constructor
+- * (see "Management of Cards and Components")
+- */
+-static int snd_bcm2835_create(struct snd_card *card,
+- struct bcm2835_chip **rchip)
+-{
+- struct bcm2835_chip *chip;
+- int err;
+- static struct snd_device_ops ops = {
+- .dev_free = snd_bcm2835_dev_free,
+- };
+-
+- *rchip = NULL;
+-
+- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+- if (!chip)
+- return -ENOMEM;
+-
+- chip->card = card;
+- mutex_init(&chip->audio_mutex);
+-
+- chip->vchi_ctx = devres_find(card->dev->parent,
+- bcm2835_devm_free_vchi_ctx, NULL, NULL);
+- if (!chip->vchi_ctx) {
+- kfree(chip);
+- return -ENODEV;
+- }
+-
+- err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+- if (err) {
+- kfree(chip);
+- return err;
+- }
+-
+- *rchip = chip;
+- return 0;
+-}
+-
+-static struct snd_card *snd_bcm2835_card_new(struct device *dev)
+-{
+- struct snd_card *card;
+- int ret;
+-
+- ret = snd_card_new(dev, -1, NULL, THIS_MODULE, 0, &card);
+- if (ret)
+- return ERR_PTR(ret);
+-
+- return card;
+-}
+-
+ typedef int (*bcm2835_audio_newpcm_func)(struct bcm2835_chip *chip,
+ const char *name,
+ enum snd_bcm2835_route route,
+@@ -292,25 +226,26 @@ static int snd_add_child_device(struct d
+ return PTR_ERR(child);
+ }
+
+- card = snd_bcm2835_card_new(child);
+- if (IS_ERR(card)) {
++ err = snd_card_new(child, -1, NULL, THIS_MODULE, sizeof(*chip), &card);
++ if (err < 0) {
+ dev_err(child, "Failed to create card");
+- return PTR_ERR(card);
++ return err;
+ }
+
+- snd_card_set_dev(card, child);
++ chip = card->private_data;
++ chip->card = card;
++ chip->dev = child;
++ mutex_init(&chip->audio_mutex);
++
++ chip->vchi_ctx = devres_find(device,
++ bcm2835_devm_free_vchi_ctx, NULL, NULL);
++ if (!chip->vchi_ctx)
++ return -ENODEV;
++
+ strcpy(card->driver, audio_driver->driver.name);
+ strcpy(card->shortname, audio_driver->shortname);
+ strcpy(card->longname, audio_driver->longname);
+
+- err = snd_bcm2835_create(card, &chip);
+- if (err) {
+- dev_err(child, "Failed to create chip, error %d\n", err);
+- return err;
+- }
+-
+- chip->dev = child;
+-
+ err = audio_driver->newpcm(chip, audio_driver->shortname,
+ audio_driver->route,
+ numchans);
+++ /dev/null
-From 87ba8310e9f0882e85926ac1ef91333f8906b303 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:49 +0200
-Subject: [PATCH] staging: bcm2835-audio: Operate non-atomic PCM ops
-
-commit 5c7883e5f27e829f3f3a2ba174d4a724bfd5f026 upstream.
-
-This is the most significant part in the patch series.
-
-The bcm2835-audio driver used to queue the commands to vc04 core via
-workqueue, but basically the whole accesses to vc04 core are done in
-the sleepable context, including the callback calls. In such a case,
-rewriting the code using non-atomic PCM ops will simplify the logic a
-lot.
-
-This patch does it: all workqueue are gone and each former-work
-implementation is now directly called from PCM ops like trigger and
-write transfer.
-
-Along with it, the DMA position updater, bcm2835_playback_fifo(), was
-also rewritten to use a simpler logic. Now it handles the XRUN and
-draining properly by calling snd_pcm_stop() conditionally.
-
-The current position is kept in atomic_t value so that it can be read
-concurrently from the pointer callback.
-
-Also, the bcm2835_audio_instance object is allocated at the beginning
-of bcm2835_audio_open(). This makes the resource management clearer.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 74 +++---
- .../bcm2835-audio/bcm2835-vchiq.c | 244 +++---------------
- .../vc04_services/bcm2835-audio/bcm2835.h | 9 +-
- 3 files changed, 82 insertions(+), 245 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -11,7 +11,8 @@
- /* hardware definition */
- static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
-+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-+ SNDRV_PCM_INFO_DRAIN_TRIGGER),
- .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
- .rate_min = 8000,
-@@ -27,7 +28,8 @@ static const struct snd_pcm_hardware snd
-
- static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
-+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-+ SNDRV_PCM_INFO_DRAIN_TRIGGER),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000,
-@@ -47,42 +49,34 @@ static void snd_bcm2835_playback_free(st
- kfree(runtime->private_data);
- }
-
--void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream)
-+void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream,
-+ unsigned int bytes)
- {
-- unsigned int consumed = 0;
-- int new_period = 0;
-+ struct snd_pcm_substream *substream = alsa_stream->substream;
-+ unsigned int pos;
-
-- audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
-- alsa_stream ? alsa_stream->substream : 0);
-+ if (!alsa_stream->period_size)
-+ return;
-
-- consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
--
-- /* We get called only if playback was triggered, So, the number of buffers we retrieve in
-- * each iteration are the buffers that have been played out already
-- */
--
-- if (alsa_stream->period_size) {
-- if ((alsa_stream->pos / alsa_stream->period_size) !=
-- ((alsa_stream->pos + consumed) / alsa_stream->period_size))
-- new_period = 1;
-- }
-- audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
-- alsa_stream->pos,
-- consumed,
-- alsa_stream->buffer_size,
-- (int) (alsa_stream->period_size * alsa_stream->substream->runtime->periods),
-- frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
-- new_period);
-- if (alsa_stream->buffer_size) {
-- alsa_stream->pos += consumed & ~(1 << 30);
-- alsa_stream->pos %= alsa_stream->buffer_size;
-+ if (bytes >= alsa_stream->buffer_size) {
-+ snd_pcm_stream_lock(substream);
-+ snd_pcm_stop(substream,
-+ alsa_stream->draining ?
-+ SNDRV_PCM_STATE_SETUP :
-+ SNDRV_PCM_STATE_XRUN);
-+ snd_pcm_stream_unlock(substream);
-+ return;
- }
-
-- if (alsa_stream->substream) {
-- if (new_period)
-- snd_pcm_period_elapsed(alsa_stream->substream);
-- } else {
-- audio_warning(" unexpected NULL substream\n");
-+ pos = atomic_read(&alsa_stream->pos);
-+ pos += bytes;
-+ pos %= alsa_stream->buffer_size;
-+ atomic_set(&alsa_stream->pos, pos);
-+
-+ alsa_stream->period_offset += bytes;
-+ if (alsa_stream->period_offset >= alsa_stream->period_size) {
-+ alsa_stream->period_offset %= alsa_stream->period_size;
-+ snd_pcm_period_elapsed(substream);
- }
- }
-
-@@ -246,7 +240,8 @@ static int snd_bcm2835_pcm_prepare(struc
-
- alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
- alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
-- alsa_stream->pos = 0;
-+ atomic_set(&alsa_stream->pos, 0);
-+ alsa_stream->period_offset = 0;
- alsa_stream->draining = false;
-
- return 0;
-@@ -283,7 +278,7 @@ static int snd_bcm2835_pcm_trigger(struc
- return bcm2835_audio_start(alsa_stream);
- case SNDRV_PCM_TRIGGER_DRAIN:
- alsa_stream->draining = true;
-- return 0;
-+ return bcm2835_audio_drain(alsa_stream);
- case SNDRV_PCM_TRIGGER_STOP:
- return bcm2835_audio_stop(alsa_stream);
- default:
-@@ -300,7 +295,7 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
-
- return snd_pcm_indirect_playback_pointer(substream,
- &alsa_stream->pcm_indirect,
-- alsa_stream->pos);
-+ atomic_read(&alsa_stream->pos));
- }
-
- /* operators */
-@@ -338,6 +333,7 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
- if (err < 0)
- return err;
- pcm->private_data = chip;
-+ pcm->nonatomic = true;
- strcpy(pcm->name, "bcm2835 ALSA");
- chip->pcm = pcm;
- chip->dest = AUDIO_DEST_AUTO;
-@@ -367,6 +363,7 @@ int snd_bcm2835_new_spdif_pcm(struct bcm
- return err;
-
- pcm->private_data = chip;
-+ pcm->nonatomic = true;
- strcpy(pcm->name, "bcm2835 IEC958/HDMI");
- chip->pcm_spdif = pcm;
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-@@ -395,6 +392,7 @@ int snd_bcm2835_new_simple_pcm(struct bc
- return err;
-
- pcm->private_data = chip;
-+ pcm->nonatomic = true;
- strcpy(pcm->name, name);
- chip->pcm = pcm;
- chip->dest = route;
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -26,10 +26,6 @@
-
- /* ---- Private Constants and Types ------------------------------------------ */
-
--#define BCM2835_AUDIO_STOP 0
--#define BCM2835_AUDIO_START 1
--#define BCM2835_AUDIO_WRITE 2
--
- /* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
- #ifdef AUDIO_DEBUG_ENABLE
- #define LOG_ERR(fmt, arg...) pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
-@@ -55,17 +51,6 @@ struct bcm2835_audio_instance {
-
- static bool force_bulk;
-
--/* ---- Private Variables ---------------------------------------------------- */
--
--/* ---- Private Function Prototypes ------------------------------------------ */
--
--/* ---- Private Functions ---------------------------------------------------- */
--
--static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream);
--static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream);
--static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
-- unsigned int count, void *src);
--
- static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
- {
- mutex_lock(&instance->vchi_mutex);
-@@ -135,108 +120,6 @@ static const u32 BCM2835_AUDIO_WRITE_COO
- static const u32 BCM2835_AUDIO_WRITE_COOKIE2 = ('D' << 24 | 'A' << 16 |
- 'T' << 8 | 'A');
-
--struct bcm2835_audio_work {
-- struct work_struct my_work;
-- struct bcm2835_alsa_stream *alsa_stream;
-- int cmd;
-- void *src;
-- unsigned int count;
--};
--
--static void my_wq_function(struct work_struct *work)
--{
-- struct bcm2835_audio_work *w =
-- container_of(work, struct bcm2835_audio_work, my_work);
-- int ret = -9;
--
-- switch (w->cmd) {
-- case BCM2835_AUDIO_START:
-- ret = bcm2835_audio_start_worker(w->alsa_stream);
-- break;
-- case BCM2835_AUDIO_STOP:
-- ret = bcm2835_audio_stop_worker(w->alsa_stream);
-- break;
-- case BCM2835_AUDIO_WRITE:
-- ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
-- w->src);
-- break;
-- default:
-- LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
-- break;
-- }
-- kfree((void *)work);
--}
--
--int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
--{
-- struct bcm2835_audio_work *work;
--
-- work = kmalloc(sizeof(*work), GFP_ATOMIC);
-- /*--- Queue some work (item 1) ---*/
-- if (!work) {
-- LOG_ERR(" .. Error: NULL work kmalloc\n");
-- return -ENOMEM;
-- }
-- INIT_WORK(&work->my_work, my_wq_function);
-- work->alsa_stream = alsa_stream;
-- work->cmd = BCM2835_AUDIO_START;
-- if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
-- kfree(work);
-- return -EBUSY;
-- }
-- return 0;
--}
--
--int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
--{
-- struct bcm2835_audio_work *work;
--
-- work = kmalloc(sizeof(*work), GFP_ATOMIC);
-- /*--- Queue some work (item 1) ---*/
-- if (!work) {
-- LOG_ERR(" .. Error: NULL work kmalloc\n");
-- return -ENOMEM;
-- }
-- INIT_WORK(&work->my_work, my_wq_function);
-- work->alsa_stream = alsa_stream;
-- work->cmd = BCM2835_AUDIO_STOP;
-- if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
-- kfree(work);
-- return -EBUSY;
-- }
-- return 0;
--}
--
--int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
-- unsigned int count, void *src)
--{
-- struct bcm2835_audio_work *work;
--
-- work = kmalloc(sizeof(*work), GFP_ATOMIC);
-- /*--- Queue some work (item 1) ---*/
-- if (!work) {
-- LOG_ERR(" .. Error: NULL work kmalloc\n");
-- return -ENOMEM;
-- }
-- INIT_WORK(&work->my_work, my_wq_function);
-- work->alsa_stream = alsa_stream;
-- work->cmd = BCM2835_AUDIO_WRITE;
-- work->src = src;
-- work->count = count;
-- if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
-- kfree(work);
-- return -EBUSY;
-- }
-- return 0;
--}
--
--static void my_workqueue_quit(struct bcm2835_alsa_stream *alsa_stream)
--{
-- flush_workqueue(alsa_stream->my_wq);
-- destroy_workqueue(alsa_stream->my_wq);
-- alsa_stream->my_wq = NULL;
--}
--
- static void audio_vchi_callback(void *param,
- const VCHI_CALLBACK_REASON_T reason,
- void *msg_handle)
-@@ -249,47 +132,27 @@ static void audio_vchi_callback(void *pa
- if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
- return;
-
-- if (!instance) {
-- LOG_ERR(" .. instance is null\n");
-- BUG();
-- return;
-- }
-- if (!instance->vchi_handle) {
-- LOG_ERR(" .. instance->vchi_handle is null\n");
-- BUG();
-- return;
-- }
- status = vchi_msg_dequeue(instance->vchi_handle,
- &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
- if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
-- LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
-- instance, m.u.result.success);
- instance->result = m.u.result.success;
- complete(&instance->msg_avail_comp);
- } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
-- struct bcm2835_alsa_stream *alsa_stream = instance->alsa_stream;
--
-- LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
-- instance, m.u.complete.count);
- if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
- m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
-- LOG_ERR(" .. response is corrupt\n");
-- else if (alsa_stream) {
-- atomic_add(m.u.complete.count,
-- &alsa_stream->retrieved);
-- bcm2835_playback_fifo(alsa_stream);
-- } else {
-- LOG_ERR(" .. unexpected alsa_stream=%p\n",
-- alsa_stream);
-- }
-+ LOG_ERR("invalid cookie\n");
-+ else
-+ bcm2835_playback_fifo(instance->alsa_stream,
-+ m.u.complete.count);
- } else {
-- LOG_ERR(" .. unexpected m.type=%d\n", m.type);
-+ LOG_ERR("unexpected callback type=%d\n", m.type);
- }
- }
-
--static struct bcm2835_audio_instance *
-+static int
- vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
-- VCHI_CONNECTION_T *vchi_connection)
-+ VCHI_CONNECTION_T *vchi_connection,
-+ struct bcm2835_audio_instance *instance)
- {
- SERVICE_CREATION_T params = {
- .version = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
-@@ -298,23 +161,14 @@ vc_vchi_audio_init(VCHI_INSTANCE_T vchi_
- .rx_fifo_size = 0,
- .tx_fifo_size = 0,
- .callback = audio_vchi_callback,
-+ .callback_param = instance,
- .want_unaligned_bulk_rx = 1, //TODO: remove VCOS_FALSE
- .want_unaligned_bulk_tx = 1, //TODO: remove VCOS_FALSE
- .want_crc = 0
- };
-- struct bcm2835_audio_instance *instance;
- int status;
-
-- /* Allocate memory for this instance */
-- instance = kzalloc(sizeof(*instance), GFP_KERNEL);
-- if (!instance)
-- return ERR_PTR(-ENOMEM);
--
-- /* Create a lock for exclusive, serialized VCHI connection access */
-- mutex_init(&instance->vchi_mutex);
- /* Open the VCHI service connections */
-- params.callback_param = instance,
--
- status = vchi_service_open(vchi_instance, ¶ms,
- &instance->vchi_handle);
-
-@@ -322,16 +176,16 @@ vc_vchi_audio_init(VCHI_INSTANCE_T vchi_
- LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
- __func__, status);
- kfree(instance);
-- return ERR_PTR(-EPERM);
-+ return -EPERM;
- }
-
- /* Finished with the service for now */
- vchi_service_release(instance->vchi_handle);
-
-- return instance;
-+ return 0;
- }
-
--static int vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
-+static void vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
- {
- int status;
-
-@@ -346,10 +200,6 @@ static int vc_vchi_audio_deinit(struct b
- }
-
- mutex_unlock(&instance->vchi_mutex);
--
-- kfree(instance);
--
-- return 0;
- }
-
- int bcm2835_new_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
-@@ -387,39 +237,25 @@ void bcm2835_free_vchi_ctx(struct bcm283
- vchi_ctx->vchi_instance = NULL;
- }
-
--static int bcm2835_audio_open_connection(struct bcm2835_alsa_stream *alsa_stream)
--{
-- struct bcm2835_audio_instance *instance =
-- (struct bcm2835_audio_instance *)alsa_stream->instance;
-- struct bcm2835_vchi_ctx *vhci_ctx = alsa_stream->chip->vchi_ctx;
--
-- /* Initialize an instance of the audio service */
-- instance = vc_vchi_audio_init(vhci_ctx->vchi_instance,
-- vhci_ctx->vchi_connection);
--
-- if (IS_ERR(instance))
-- return PTR_ERR(instance);
--
-- instance->alsa_stream = alsa_stream;
-- alsa_stream->instance = instance;
--
-- return 0;
--}
--
- int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
- {
-+ struct bcm2835_vchi_ctx *vchi_ctx = alsa_stream->chip->vchi_ctx;
- struct bcm2835_audio_instance *instance;
- int err;
-
-- alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
-- if (!alsa_stream->my_wq)
-+ /* Allocate memory for this instance */
-+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
-+ if (!instance)
- return -ENOMEM;
-+ mutex_init(&instance->vchi_mutex);
-+ instance->alsa_stream = alsa_stream;
-+ alsa_stream->instance = instance;
-
-- err = bcm2835_audio_open_connection(alsa_stream);
-+ err = vc_vchi_audio_init(vchi_ctx->vchi_instance,
-+ vchi_ctx->vchi_connection,
-+ instance);
- if (err < 0)
-- goto free_wq;
--
-- instance = alsa_stream->instance;
-+ goto free_instance;
-
- err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
- false);
-@@ -438,8 +274,9 @@ int bcm2835_audio_open(struct bcm2835_al
-
- deinit:
- vc_vchi_audio_deinit(instance);
-- free_wq:
-- destroy_workqueue(alsa_stream->my_wq);
-+ free_instance:
-+ alsa_stream->instance = NULL;
-+ kfree(instance);
- return err;
- }
-
-@@ -478,37 +315,46 @@ int bcm2835_audio_set_params(struct bcm2
- return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
- }
-
--static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
-+int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
- {
- return bcm2835_audio_send_simple(alsa_stream->instance,
- VC_AUDIO_MSG_TYPE_START, false);
- }
-
--static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
-+int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
- {
- return bcm2835_audio_send_simple(alsa_stream->instance,
- VC_AUDIO_MSG_TYPE_STOP, false);
- }
-
-+int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream)
-+{
-+ struct vc_audio_msg m = {
-+ .type = VC_AUDIO_MSG_TYPE_STOP,
-+ .u.stop.draining = 1,
-+ };
-+
-+ return bcm2835_audio_send_msg(alsa_stream->instance, &m, false);
-+}
-+
- int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
- {
- struct bcm2835_audio_instance *instance = alsa_stream->instance;
- int err;
-
-- my_workqueue_quit(alsa_stream);
--
- err = bcm2835_audio_send_simple(alsa_stream->instance,
- VC_AUDIO_MSG_TYPE_CLOSE, true);
-
- /* Stop the audio service */
- vc_vchi_audio_deinit(instance);
- alsa_stream->instance = NULL;
-+ kfree(instance);
-
- return err;
- }
-
--static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
-- unsigned int size, void *src)
-+int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
-+ unsigned int size, void *src)
- {
- struct bcm2835_audio_instance *instance = alsa_stream->instance;
- struct vc_audio_msg m = {
-@@ -558,13 +404,5 @@ static int bcm2835_audio_write_worker(st
- return err;
- }
-
--unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)
--{
-- unsigned int count = atomic_read(&alsa_stream->retrieved);
--
-- atomic_sub(count, &alsa_stream->retrieved);
-- return count;
--}
--
- module_param(force_bulk, bool, 0444);
- MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -121,13 +121,12 @@ struct bcm2835_alsa_stream {
-
- int draining;
-
-- unsigned int pos;
-+ atomic_t pos;
-+ unsigned int period_offset;
- unsigned int buffer_size;
- unsigned int period_size;
-
-- atomic_t retrieved;
- struct bcm2835_audio_instance *instance;
-- struct workqueue_struct *my_wq;
- int idx;
- };
-
-@@ -152,11 +151,13 @@ int bcm2835_audio_set_params(struct bcm2
- unsigned int bps);
- int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream);
- int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream);
-+int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream);
- int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream);
- int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
- unsigned int count,
- void *src);
--void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream);
-+void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream,
-+ unsigned int size);
- unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream);
-
- #endif /* __SOUND_ARM_BCM2835_H */
--- /dev/null
+From ec788d7c115d3ec59b39b6aac17d57ad86b7fbfe Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:51 +0200
+Subject: [PATCH] staging: bcm2835-audio: Use standard error print
+ helpers
+
+commit b7584b64168208ebc14160770c0966b8b12fc16b upstream.
+
+For making the whole code more consistent, replace the home-made debug
+print macros with the standard dev_err() & co.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 4 +-
+ .../bcm2835-audio/bcm2835-vchiq.c | 52 ++++++++-----------
+ .../vc04_services/bcm2835-audio/bcm2835.c | 2 +-
+ .../vc04_services/bcm2835-audio/bcm2835.h | 43 +--------------
+ 4 files changed, 27 insertions(+), 74 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -101,8 +101,8 @@ static int snd_bcm2835_playback_open_gen
+ goto out;
+ }
+ if (idx >= MAX_SUBSTREAMS) {
+- audio_error
+- ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
++ dev_err(chip->dev,
++ "substream(%d) device doesn't exist max(%d) substreams allowed\n",
+ idx, MAX_SUBSTREAMS);
+ err = -ENODEV;
+ goto out;
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -26,20 +26,8 @@
+
+ /* ---- Private Constants and Types ------------------------------------------ */
+
+-/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
+-#ifdef AUDIO_DEBUG_ENABLE
+-#define LOG_ERR(fmt, arg...) pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
+-#define LOG_WARN(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
+-#define LOG_INFO(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
+-#define LOG_DBG(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
+-#else
+-#define LOG_ERR(fmt, arg...) pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
+-#define LOG_WARN(fmt, arg...) no_printk(fmt, ##arg)
+-#define LOG_INFO(fmt, arg...) no_printk(fmt, ##arg)
+-#define LOG_DBG(fmt, arg...) no_printk(fmt, ##arg)
+-#endif
+-
+ struct bcm2835_audio_instance {
++ struct device *dev;
+ VCHI_SERVICE_HANDLE_T vchi_handle;
+ struct completion msg_avail_comp;
+ struct mutex vchi_mutex;
+@@ -76,7 +64,8 @@ static int bcm2835_audio_send_msg_locked
+ status = vchi_queue_kernel_message(instance->vchi_handle,
+ m, sizeof(*m));
+ if (status) {
+- LOG_ERR("vchi message queue failed: %d, msg=%d\n",
++ dev_err(instance->dev,
++ "vchi message queue failed: %d, msg=%d\n",
+ status, m->type);
+ return -EIO;
+ }
+@@ -84,10 +73,12 @@ static int bcm2835_audio_send_msg_locked
+ if (wait) {
+ if (!wait_for_completion_timeout(&instance->msg_avail_comp,
+ msecs_to_jiffies(10 * 1000))) {
+- LOG_ERR("vchi message timeout, msg=%d\n", m->type);
++ dev_err(instance->dev,
++ "vchi message timeout, msg=%d\n", m->type);
+ return -ETIMEDOUT;
+ } else if (instance->result) {
+- LOG_ERR("vchi message response error:%d, msg=%d\n",
++ dev_err(instance->dev,
++ "vchi message response error:%d, msg=%d\n",
+ instance->result, m->type);
+ return -EIO;
+ }
+@@ -140,12 +131,12 @@ static void audio_vchi_callback(void *pa
+ } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
+ if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
+ m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
+- LOG_ERR("invalid cookie\n");
++ dev_err(instance->dev, "invalid cookie\n");
+ else
+ bcm2835_playback_fifo(instance->alsa_stream,
+ m.u.complete.count);
+ } else {
+- LOG_ERR("unexpected callback type=%d\n", m.type);
++ dev_err(instance->dev, "unexpected callback type=%d\n", m.type);
+ }
+ }
+
+@@ -173,8 +164,9 @@ vc_vchi_audio_init(VCHI_INSTANCE_T vchi_
+ &instance->vchi_handle);
+
+ if (status) {
+- LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
+- __func__, status);
++ dev_err(instance->dev,
++ "failed to open VCHI service connection (status=%d)\n",
++ status);
+ kfree(instance);
+ return -EPERM;
+ }
+@@ -195,30 +187,30 @@ static void vc_vchi_audio_deinit(struct
+ /* Close all VCHI service connections */
+ status = vchi_service_close(instance->vchi_handle);
+ if (status) {
+- LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
+- __func__, status);
++ dev_err(instance->dev,
++ "failed to close VCHI service connection (status=%d)\n",
++ status);
+ }
+
+ mutex_unlock(&instance->vchi_mutex);
+ }
+
+-int bcm2835_new_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
++int bcm2835_new_vchi_ctx(struct device *dev, struct bcm2835_vchi_ctx *vchi_ctx)
+ {
+ int ret;
+
+ /* Initialize and create a VCHI connection */
+ ret = vchi_initialise(&vchi_ctx->vchi_instance);
+ if (ret) {
+- LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
+- __func__, ret);
+-
++ dev_err(dev, "failed to initialise VCHI instance (ret=%d)\n",
++ ret);
+ return -EIO;
+ }
+
+ ret = vchi_connect(NULL, 0, vchi_ctx->vchi_instance);
+ if (ret) {
+- LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
+- __func__, ret);
++ dev_dbg(dev, "failed to connect VCHI instance (ret=%d)\n",
++ ret);
+
+ kfree(vchi_ctx->vchi_instance);
+ vchi_ctx->vchi_instance = NULL;
+@@ -248,6 +240,7 @@ int bcm2835_audio_open(struct bcm2835_al
+ if (!instance)
+ return -ENOMEM;
+ mutex_init(&instance->vchi_mutex);
++ instance->dev = alsa_stream->chip->dev;
+ instance->alsa_stream = alsa_stream;
+ alsa_stream->instance = instance;
+
+@@ -394,7 +387,8 @@ int bcm2835_audio_write(struct bcm2835_a
+ }
+
+ if (status) {
+- LOG_ERR("failed on %d bytes transfer (status=%d)\n",
++ dev_err(instance->dev,
++ "failed on %d bytes transfer (status=%d)\n",
+ size, status);
+ err = -EIO;
+ }
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -73,7 +73,7 @@ static int bcm2835_devm_add_vchi_ctx(str
+
+ memset(vchi_ctx, 0, sizeof(*vchi_ctx));
+
+- ret = bcm2835_new_vchi_ctx(vchi_ctx);
++ ret = bcm2835_new_vchi_ctx(dev, vchi_ctx);
+ if (ret) {
+ devres_free(vchi_ctx);
+ return ret;
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -17,47 +17,6 @@
+
+ #include "interface/vchi/vchi.h"
+
+-/*
+- * #define AUDIO_DEBUG_ENABLE
+- * #define AUDIO_VERBOSE_DEBUG_ENABLE
+- */
+-
+-/* Debug macros */
+-
+-#ifdef AUDIO_DEBUG_ENABLE
+-#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
+-
+-#define audio_debug(fmt, arg...) \
+- pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
+-
+-#define audio_info(fmt, arg...) \
+- pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
+-
+-#else
+-
+-#define audio_debug(fmt, arg...)
+-
+-#define audio_info(fmt, arg...)
+-
+-#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
+-
+-#else
+-
+-#define audio_debug(fmt, arg...)
+-
+-#define audio_info(fmt, arg...)
+-
+-#endif /* AUDIO_DEBUG_ENABLE */
+-
+-#define audio_error(fmt, arg...) \
+- pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
+-
+-#define audio_warning(fmt, arg...) \
+- pr_warn("%s:%d " fmt, __func__, __LINE__, ##arg)
+-
+-#define audio_alert(fmt, arg...) \
+- pr_alert("%s:%d " fmt, __func__, __LINE__, ##arg)
+-
+ #define MAX_SUBSTREAMS (8)
+ #define AVAIL_SUBSTREAMS_MASK (0xff)
+
+@@ -141,7 +100,7 @@ int snd_bcm2835_new_simple_pcm(struct bc
+ int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip);
+ int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip);
+
+-int bcm2835_new_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx);
++int bcm2835_new_vchi_ctx(struct device *dev, struct bcm2835_vchi_ctx *vchi_ctx);
+ void bcm2835_free_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx);
+
+ int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream);
--- /dev/null
+From 8deead340379eeb09571476e0412ce50036c08d1 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:52 +0200
+Subject: [PATCH] staging: bcm2835-audio: Remove unnecessary header
+ file includes
+
+commit 7e46fff5f19ce2b8a9891e4c08631c64d06e9e17 upstream.
+
+Yet a few header files are included unnecessarily. Drop them.
+
+Also remove trivial comments.
+
+---
+ .../bcm2835-audio/bcm2835-vchiq.c | 19 -------------------
+ .../vc04_services/bcm2835-audio/bcm2835.h | 6 ------
+ 2 files changed, 25 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -1,31 +1,12 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /* Copyright 2011 Broadcom Corporation. All rights reserved. */
+
+-#include <linux/device.h>
+-#include <sound/core.h>
+-#include <sound/initval.h>
+-#include <sound/pcm.h>
+-#include <linux/io.h>
+-#include <linux/interrupt.h>
+-#include <linux/fs.h>
+-#include <linux/file.h>
+-#include <linux/mm.h>
+-#include <linux/syscalls.h>
+-#include <linux/uaccess.h>
+ #include <linux/slab.h>
+-#include <linux/delay.h>
+-#include <linux/atomic.h>
+ #include <linux/module.h>
+ #include <linux/completion.h>
+-
+ #include "bcm2835.h"
+-
+-/* ---- Include Files -------------------------------------------------------- */
+-
+ #include "vc_vchi_audioserv_defs.h"
+
+-/* ---- Private Constants and Types ------------------------------------------ */
+-
+ struct bcm2835_audio_instance {
+ struct device *dev;
+ VCHI_SERVICE_HANDLE_T vchi_handle;
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -5,16 +5,10 @@
+ #define __SOUND_ARM_BCM2835_H
+
+ #include <linux/device.h>
+-#include <linux/list.h>
+-#include <linux/interrupt.h>
+ #include <linux/wait.h>
+ #include <sound/core.h>
+-#include <sound/initval.h>
+ #include <sound/pcm.h>
+-#include <sound/pcm_params.h>
+ #include <sound/pcm-indirect.h>
+-#include <linux/workqueue.h>
+-
+ #include "interface/vchi/vchi.h"
+
+ #define MAX_SUBSTREAMS (8)
+++ /dev/null
-From af0ded6e9dd38f08a9ee621066e583b5cf972926 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:50 +0200
-Subject: [PATCH] staging: bcm2835-audio: Use card->private_data
-
-commit 898001a0c845cefe5d47d133485712412853f0a8 upstream.
-
-Instead of allocating a separate snd_device object, let snd_card_new()
-allocate the private resource. This simplifies the code.
-
----
- .../vc04_services/bcm2835-audio/bcm2835.c | 91 +++----------------
- 1 file changed, 13 insertions(+), 78 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -86,9 +86,6 @@ static int bcm2835_devm_add_vchi_ctx(str
-
- static void snd_bcm2835_release(struct device *dev)
- {
-- struct bcm2835_chip *chip = dev_get_drvdata(dev);
--
-- kfree(chip);
- }
-
- static struct device *
-@@ -117,69 +114,6 @@ snd_create_device(struct device *parent,
- return device;
- }
-
--/* component-destructor
-- * (see "Management of Cards and Components")
-- */
--static int snd_bcm2835_dev_free(struct snd_device *device)
--{
-- struct bcm2835_chip *chip = device->device_data;
-- struct snd_card *card = chip->card;
--
-- snd_device_free(card, chip);
--
-- return 0;
--}
--
--/* chip-specific constructor
-- * (see "Management of Cards and Components")
-- */
--static int snd_bcm2835_create(struct snd_card *card,
-- struct bcm2835_chip **rchip)
--{
-- struct bcm2835_chip *chip;
-- int err;
-- static struct snd_device_ops ops = {
-- .dev_free = snd_bcm2835_dev_free,
-- };
--
-- *rchip = NULL;
--
-- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-- if (!chip)
-- return -ENOMEM;
--
-- chip->card = card;
-- mutex_init(&chip->audio_mutex);
--
-- chip->vchi_ctx = devres_find(card->dev->parent,
-- bcm2835_devm_free_vchi_ctx, NULL, NULL);
-- if (!chip->vchi_ctx) {
-- kfree(chip);
-- return -ENODEV;
-- }
--
-- err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
-- if (err) {
-- kfree(chip);
-- return err;
-- }
--
-- *rchip = chip;
-- return 0;
--}
--
--static struct snd_card *snd_bcm2835_card_new(struct device *dev)
--{
-- struct snd_card *card;
-- int ret;
--
-- ret = snd_card_new(dev, -1, NULL, THIS_MODULE, 0, &card);
-- if (ret)
-- return ERR_PTR(ret);
--
-- return card;
--}
--
- typedef int (*bcm2835_audio_newpcm_func)(struct bcm2835_chip *chip,
- const char *name,
- enum snd_bcm2835_route route,
-@@ -292,25 +226,26 @@ static int snd_add_child_device(struct d
- return PTR_ERR(child);
- }
-
-- card = snd_bcm2835_card_new(child);
-- if (IS_ERR(card)) {
-+ err = snd_card_new(child, -1, NULL, THIS_MODULE, sizeof(*chip), &card);
-+ if (err < 0) {
- dev_err(child, "Failed to create card");
-- return PTR_ERR(card);
-+ return err;
- }
-
-- snd_card_set_dev(card, child);
-+ chip = card->private_data;
-+ chip->card = card;
-+ chip->dev = child;
-+ mutex_init(&chip->audio_mutex);
-+
-+ chip->vchi_ctx = devres_find(device,
-+ bcm2835_devm_free_vchi_ctx, NULL, NULL);
-+ if (!chip->vchi_ctx)
-+ return -ENODEV;
-+
- strcpy(card->driver, audio_driver->driver.name);
- strcpy(card->shortname, audio_driver->shortname);
- strcpy(card->longname, audio_driver->longname);
-
-- err = snd_bcm2835_create(card, &chip);
-- if (err) {
-- dev_err(child, "Failed to create chip, error %d\n", err);
-- return err;
-- }
--
-- chip->dev = child;
--
- err = audio_driver->newpcm(chip, audio_driver->shortname,
- audio_driver->route,
- numchans);
--- /dev/null
+From fb05aeb91f3e94e89ad2d9aa68104e6e4cc97239 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:53 +0200
+Subject: [PATCH] staging: bcm2835-audio: Move module parameter
+ description
+
+commit b876f2075808e95e244053caa53fa7e86e929a99 upstream.
+
+For more consistency, move the module parameter description right
+after its variable definition.
+
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -19,6 +19,8 @@ struct bcm2835_audio_instance {
+ };
+
+ static bool force_bulk;
++module_param(force_bulk, bool, 0444);
++MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
+
+ static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
+ {
+@@ -378,6 +380,3 @@ int bcm2835_audio_write(struct bcm2835_a
+ bcm2835_audio_unlock(instance);
+ return err;
+ }
+-
+-module_param(force_bulk, bool, 0444);
+-MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
+++ /dev/null
-From ec788d7c115d3ec59b39b6aac17d57ad86b7fbfe Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:51 +0200
-Subject: [PATCH] staging: bcm2835-audio: Use standard error print
- helpers
-
-commit b7584b64168208ebc14160770c0966b8b12fc16b upstream.
-
-For making the whole code more consistent, replace the home-made debug
-print macros with the standard dev_err() & co.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 4 +-
- .../bcm2835-audio/bcm2835-vchiq.c | 52 ++++++++-----------
- .../vc04_services/bcm2835-audio/bcm2835.c | 2 +-
- .../vc04_services/bcm2835-audio/bcm2835.h | 43 +--------------
- 4 files changed, 27 insertions(+), 74 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -101,8 +101,8 @@ static int snd_bcm2835_playback_open_gen
- goto out;
- }
- if (idx >= MAX_SUBSTREAMS) {
-- audio_error
-- ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
-+ dev_err(chip->dev,
-+ "substream(%d) device doesn't exist max(%d) substreams allowed\n",
- idx, MAX_SUBSTREAMS);
- err = -ENODEV;
- goto out;
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -26,20 +26,8 @@
-
- /* ---- Private Constants and Types ------------------------------------------ */
-
--/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
--#ifdef AUDIO_DEBUG_ENABLE
--#define LOG_ERR(fmt, arg...) pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
--#define LOG_WARN(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
--#define LOG_INFO(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
--#define LOG_DBG(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
--#else
--#define LOG_ERR(fmt, arg...) pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
--#define LOG_WARN(fmt, arg...) no_printk(fmt, ##arg)
--#define LOG_INFO(fmt, arg...) no_printk(fmt, ##arg)
--#define LOG_DBG(fmt, arg...) no_printk(fmt, ##arg)
--#endif
--
- struct bcm2835_audio_instance {
-+ struct device *dev;
- VCHI_SERVICE_HANDLE_T vchi_handle;
- struct completion msg_avail_comp;
- struct mutex vchi_mutex;
-@@ -76,7 +64,8 @@ static int bcm2835_audio_send_msg_locked
- status = vchi_queue_kernel_message(instance->vchi_handle,
- m, sizeof(*m));
- if (status) {
-- LOG_ERR("vchi message queue failed: %d, msg=%d\n",
-+ dev_err(instance->dev,
-+ "vchi message queue failed: %d, msg=%d\n",
- status, m->type);
- return -EIO;
- }
-@@ -84,10 +73,12 @@ static int bcm2835_audio_send_msg_locked
- if (wait) {
- if (!wait_for_completion_timeout(&instance->msg_avail_comp,
- msecs_to_jiffies(10 * 1000))) {
-- LOG_ERR("vchi message timeout, msg=%d\n", m->type);
-+ dev_err(instance->dev,
-+ "vchi message timeout, msg=%d\n", m->type);
- return -ETIMEDOUT;
- } else if (instance->result) {
-- LOG_ERR("vchi message response error:%d, msg=%d\n",
-+ dev_err(instance->dev,
-+ "vchi message response error:%d, msg=%d\n",
- instance->result, m->type);
- return -EIO;
- }
-@@ -140,12 +131,12 @@ static void audio_vchi_callback(void *pa
- } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
- if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
- m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
-- LOG_ERR("invalid cookie\n");
-+ dev_err(instance->dev, "invalid cookie\n");
- else
- bcm2835_playback_fifo(instance->alsa_stream,
- m.u.complete.count);
- } else {
-- LOG_ERR("unexpected callback type=%d\n", m.type);
-+ dev_err(instance->dev, "unexpected callback type=%d\n", m.type);
- }
- }
-
-@@ -173,8 +164,9 @@ vc_vchi_audio_init(VCHI_INSTANCE_T vchi_
- &instance->vchi_handle);
-
- if (status) {
-- LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
-- __func__, status);
-+ dev_err(instance->dev,
-+ "failed to open VCHI service connection (status=%d)\n",
-+ status);
- kfree(instance);
- return -EPERM;
- }
-@@ -195,30 +187,30 @@ static void vc_vchi_audio_deinit(struct
- /* Close all VCHI service connections */
- status = vchi_service_close(instance->vchi_handle);
- if (status) {
-- LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
-- __func__, status);
-+ dev_err(instance->dev,
-+ "failed to close VCHI service connection (status=%d)\n",
-+ status);
- }
-
- mutex_unlock(&instance->vchi_mutex);
- }
-
--int bcm2835_new_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
-+int bcm2835_new_vchi_ctx(struct device *dev, struct bcm2835_vchi_ctx *vchi_ctx)
- {
- int ret;
-
- /* Initialize and create a VCHI connection */
- ret = vchi_initialise(&vchi_ctx->vchi_instance);
- if (ret) {
-- LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
-- __func__, ret);
--
-+ dev_err(dev, "failed to initialise VCHI instance (ret=%d)\n",
-+ ret);
- return -EIO;
- }
-
- ret = vchi_connect(NULL, 0, vchi_ctx->vchi_instance);
- if (ret) {
-- LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
-- __func__, ret);
-+ dev_dbg(dev, "failed to connect VCHI instance (ret=%d)\n",
-+ ret);
-
- kfree(vchi_ctx->vchi_instance);
- vchi_ctx->vchi_instance = NULL;
-@@ -248,6 +240,7 @@ int bcm2835_audio_open(struct bcm2835_al
- if (!instance)
- return -ENOMEM;
- mutex_init(&instance->vchi_mutex);
-+ instance->dev = alsa_stream->chip->dev;
- instance->alsa_stream = alsa_stream;
- alsa_stream->instance = instance;
-
-@@ -394,7 +387,8 @@ int bcm2835_audio_write(struct bcm2835_a
- }
-
- if (status) {
-- LOG_ERR("failed on %d bytes transfer (status=%d)\n",
-+ dev_err(instance->dev,
-+ "failed on %d bytes transfer (status=%d)\n",
- size, status);
- err = -EIO;
- }
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -73,7 +73,7 @@ static int bcm2835_devm_add_vchi_ctx(str
-
- memset(vchi_ctx, 0, sizeof(*vchi_ctx));
-
-- ret = bcm2835_new_vchi_ctx(vchi_ctx);
-+ ret = bcm2835_new_vchi_ctx(dev, vchi_ctx);
- if (ret) {
- devres_free(vchi_ctx);
- return ret;
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -17,47 +17,6 @@
-
- #include "interface/vchi/vchi.h"
-
--/*
-- * #define AUDIO_DEBUG_ENABLE
-- * #define AUDIO_VERBOSE_DEBUG_ENABLE
-- */
--
--/* Debug macros */
--
--#ifdef AUDIO_DEBUG_ENABLE
--#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
--
--#define audio_debug(fmt, arg...) \
-- pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
--
--#define audio_info(fmt, arg...) \
-- pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
--
--#else
--
--#define audio_debug(fmt, arg...)
--
--#define audio_info(fmt, arg...)
--
--#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
--
--#else
--
--#define audio_debug(fmt, arg...)
--
--#define audio_info(fmt, arg...)
--
--#endif /* AUDIO_DEBUG_ENABLE */
--
--#define audio_error(fmt, arg...) \
-- pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
--
--#define audio_warning(fmt, arg...) \
-- pr_warn("%s:%d " fmt, __func__, __LINE__, ##arg)
--
--#define audio_alert(fmt, arg...) \
-- pr_alert("%s:%d " fmt, __func__, __LINE__, ##arg)
--
- #define MAX_SUBSTREAMS (8)
- #define AVAIL_SUBSTREAMS_MASK (0xff)
-
-@@ -141,7 +100,7 @@ int snd_bcm2835_new_simple_pcm(struct bc
- int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip);
- int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip);
-
--int bcm2835_new_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx);
-+int bcm2835_new_vchi_ctx(struct device *dev, struct bcm2835_vchi_ctx *vchi_ctx);
- void bcm2835_free_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx);
-
- int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream);
+++ /dev/null
-From 8deead340379eeb09571476e0412ce50036c08d1 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:52 +0200
-Subject: [PATCH] staging: bcm2835-audio: Remove unnecessary header
- file includes
-
-commit 7e46fff5f19ce2b8a9891e4c08631c64d06e9e17 upstream.
-
-Yet a few header files are included unnecessarily. Drop them.
-
-Also remove trivial comments.
-
----
- .../bcm2835-audio/bcm2835-vchiq.c | 19 -------------------
- .../vc04_services/bcm2835-audio/bcm2835.h | 6 ------
- 2 files changed, 25 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -1,31 +1,12 @@
- // SPDX-License-Identifier: GPL-2.0
- /* Copyright 2011 Broadcom Corporation. All rights reserved. */
-
--#include <linux/device.h>
--#include <sound/core.h>
--#include <sound/initval.h>
--#include <sound/pcm.h>
--#include <linux/io.h>
--#include <linux/interrupt.h>
--#include <linux/fs.h>
--#include <linux/file.h>
--#include <linux/mm.h>
--#include <linux/syscalls.h>
--#include <linux/uaccess.h>
- #include <linux/slab.h>
--#include <linux/delay.h>
--#include <linux/atomic.h>
- #include <linux/module.h>
- #include <linux/completion.h>
--
- #include "bcm2835.h"
--
--/* ---- Include Files -------------------------------------------------------- */
--
- #include "vc_vchi_audioserv_defs.h"
-
--/* ---- Private Constants and Types ------------------------------------------ */
--
- struct bcm2835_audio_instance {
- struct device *dev;
- VCHI_SERVICE_HANDLE_T vchi_handle;
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -5,16 +5,10 @@
- #define __SOUND_ARM_BCM2835_H
-
- #include <linux/device.h>
--#include <linux/list.h>
--#include <linux/interrupt.h>
- #include <linux/wait.h>
- #include <sound/core.h>
--#include <sound/initval.h>
- #include <sound/pcm.h>
--#include <sound/pcm_params.h>
- #include <sound/pcm-indirect.h>
--#include <linux/workqueue.h>
--
- #include "interface/vchi/vchi.h"
-
- #define MAX_SUBSTREAMS (8)
--- /dev/null
+From 8a01a25d0ad7e9d06f64fddae871deb91c3988ac Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:54 +0200
+Subject: [PATCH] staging: bcm2835-audio: Use coherent device buffers
+
+commit ad29c6e6cbf6f2af7362b043adad51a3be3d39c7 upstream.
+
+The memory access to the pages allocated with
+SNDRV_DMA_TYPE_CONTINUOUS are basically non-coherent, and it becomes a
+problem when a process accesses via mmap.
+
+For the more consistent access, use the device coherent memory, just
+by replacing the call pattern in the allocator helpers.
+
+The only point we need to be careful for is the device object passed
+there; since bcm2835-audio driver creates fake devices and each card
+is created on top of that, we need to pass its parent device as the
+real device object.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -345,8 +345,8 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
+
+ /* pre-allocation of buffers */
+ /* NOTE: this may fail */
+- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+- snd_dma_continuous_data(GFP_KERNEL),
++ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
++ chip->card->dev->parent,
+ snd_bcm2835_playback_hw.buffer_bytes_max,
+ snd_bcm2835_playback_hw.buffer_bytes_max);
+
+@@ -371,8 +371,8 @@ int snd_bcm2835_new_spdif_pcm(struct bcm
+
+ /* pre-allocation of buffers */
+ /* NOTE: this may fail */
+- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+- snd_dma_continuous_data(GFP_KERNEL),
++ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
++ chip->card->dev->parent,
+ snd_bcm2835_playback_spdif_hw.buffer_bytes_max, snd_bcm2835_playback_spdif_hw.buffer_bytes_max);
+
+ return 0;
+@@ -404,8 +404,8 @@ int snd_bcm2835_new_simple_pcm(struct bc
+
+ snd_pcm_lib_preallocate_pages_for_all(
+ pcm,
+- SNDRV_DMA_TYPE_CONTINUOUS,
+- snd_dma_continuous_data(GFP_KERNEL),
++ SNDRV_DMA_TYPE_DEV,
++ chip->card->dev->parent,
+ snd_bcm2835_playback_hw.buffer_bytes_max,
+ snd_bcm2835_playback_hw.buffer_bytes_max);
+
+++ /dev/null
-From fb05aeb91f3e94e89ad2d9aa68104e6e4cc97239 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:53 +0200
-Subject: [PATCH] staging: bcm2835-audio: Move module parameter
- description
-
-commit b876f2075808e95e244053caa53fa7e86e929a99 upstream.
-
-For more consistency, move the module parameter description right
-after its variable definition.
-
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -19,6 +19,8 @@ struct bcm2835_audio_instance {
- };
-
- static bool force_bulk;
-+module_param(force_bulk, bool, 0444);
-+MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
-
- static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
- {
-@@ -378,6 +380,3 @@ int bcm2835_audio_write(struct bcm2835_a
- bcm2835_audio_unlock(instance);
- return err;
- }
--
--module_param(force_bulk, bool, 0444);
--MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
--- /dev/null
+From 27417ac1fa4894dc46d71cc34af17fe6a5186f2f Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:55 +0200
+Subject: [PATCH] staging: bcm2835-audio: Set
+ SNDRV_PCM_INFO_SYNC_APPLPTR
+
+commit b59d6a5f73501f74848d6700101e7736afe3d54a upstream.
+
+The recent ALSA PCM core supports the SNDRV_PCM_INFO_SYNC_APPLPTR flag
+indicating that the driver needs the ack call at each appl_ptr
+update. This is requirement for the indirect PCM implementations like
+bcm2835-audio driver, too.
+
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -12,7 +12,7 @@
+ static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+- SNDRV_PCM_INFO_DRAIN_TRIGGER),
++ SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+@@ -29,7 +29,7 @@ static const struct snd_pcm_hardware snd
+ static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+- SNDRV_PCM_INFO_DRAIN_TRIGGER),
++ SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000,
--- /dev/null
+From 706f9b2b95a2fff44f92deada99545036c249658 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:56 +0200
+Subject: [PATCH] staging: bcm2835-audio: Simplify PCM creation helpers
+
+commit 74470ffeb9aed5548654cfca881bf1d7469fe9c4 upstream.
+
+All three functions to create PCM objects are fairly resemble, and can
+be unified to a single common helper.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 87 ++++---------------
+ .../vc04_services/bcm2835-audio/bcm2835.c | 17 +++-
+ .../vc04_services/bcm2835-audio/bcm2835.h | 9 +-
+ 3 files changed, 32 insertions(+), 81 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -324,91 +324,36 @@ static const struct snd_pcm_ops snd_bcm2
+ };
+
+ /* create a pcm device */
+-int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, u32 numchannels)
++int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name,
++ int idx, enum snd_bcm2835_route route,
++ u32 numchannels, bool spdif)
+ {
+ struct snd_pcm *pcm;
+ int err;
+
+- err = snd_pcm_new(chip->card, "bcm2835 ALSA", 0, numchannels, 0, &pcm);
+- if (err < 0)
+- return err;
+- pcm->private_data = chip;
+- pcm->nonatomic = true;
+- strcpy(pcm->name, "bcm2835 ALSA");
+- chip->pcm = pcm;
+- chip->dest = AUDIO_DEST_AUTO;
+- chip->volume = 0;
+- chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
+- /* set operators */
+- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+- &snd_bcm2835_playback_ops);
+-
+- /* pre-allocation of buffers */
+- /* NOTE: this may fail */
+- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+- chip->card->dev->parent,
+- snd_bcm2835_playback_hw.buffer_bytes_max,
+- snd_bcm2835_playback_hw.buffer_bytes_max);
+-
+- return 0;
+-}
+-
+-int snd_bcm2835_new_spdif_pcm(struct bcm2835_chip *chip)
+-{
+- struct snd_pcm *pcm;
+- int err;
+-
+- err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
+- if (err < 0)
+- return err;
+-
+- pcm->private_data = chip;
+- pcm->nonatomic = true;
+- strcpy(pcm->name, "bcm2835 IEC958/HDMI");
+- chip->pcm_spdif = pcm;
+- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+- &snd_bcm2835_playback_spdif_ops);
+-
+- /* pre-allocation of buffers */
+- /* NOTE: this may fail */
+- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+- chip->card->dev->parent,
+- snd_bcm2835_playback_spdif_hw.buffer_bytes_max, snd_bcm2835_playback_spdif_hw.buffer_bytes_max);
+-
+- return 0;
+-}
+-
+-int snd_bcm2835_new_simple_pcm(struct bcm2835_chip *chip,
+- const char *name,
+- enum snd_bcm2835_route route,
+- u32 numchannels)
+-{
+- struct snd_pcm *pcm;
+- int err;
+-
+- err = snd_pcm_new(chip->card, name, 0, numchannels,
+- 0, &pcm);
++ err = snd_pcm_new(chip->card, name, idx, numchannels, 0, &pcm);
+ if (err)
+ return err;
+
+ pcm->private_data = chip;
+ pcm->nonatomic = true;
+ strcpy(pcm->name, name);
+- chip->pcm = pcm;
+- chip->dest = route;
+- chip->volume = 0;
+- chip->mute = CTRL_VOL_UNMUTE;
++ if (!spdif) {
++ chip->dest = route;
++ chip->volume = 0;
++ chip->mute = CTRL_VOL_UNMUTE;
++ }
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
++ spdif ? &snd_bcm2835_playback_spdif_ops :
+ &snd_bcm2835_playback_ops);
+
+- snd_pcm_lib_preallocate_pages_for_all(
+- pcm,
+- SNDRV_DMA_TYPE_DEV,
+- chip->card->dev->parent,
+- snd_bcm2835_playback_hw.buffer_bytes_max,
+- snd_bcm2835_playback_hw.buffer_bytes_max);
++ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
++ chip->card->dev->parent, 128 * 1024, 128 * 1024);
+
++ if (spdif)
++ chip->pcm_spdif = pcm;
++ else
++ chip->pcm = pcm;
+ return 0;
+ }
+-
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -138,17 +138,26 @@ static int bcm2835_audio_alsa_newpcm(str
+ {
+ int err;
+
+- err = snd_bcm2835_new_pcm(chip, numchannels - 1);
++ err = snd_bcm2835_new_pcm(chip, "bcm2835 ALSA", 0, AUDIO_DEST_AUTO,
++ numchannels - 1, false);
+ if (err)
+ return err;
+
+- err = snd_bcm2835_new_spdif_pcm(chip);
++ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true);
+ if (err)
+ return err;
+
+ return 0;
+ }
+
++static int bcm2835_audio_simple_newpcm(struct bcm2835_chip *chip,
++ const char *name,
++ enum snd_bcm2835_route route,
++ u32 numchannels)
++{
++ return snd_bcm2835_new_pcm(chip, name, 0, route, numchannels, false);
++}
++
+ static struct bcm2835_audio_driver bcm2835_audio_alsa = {
+ .driver = {
+ .name = "bcm2835_alsa",
+@@ -169,7 +178,7 @@ static struct bcm2835_audio_driver bcm28
+ .shortname = "bcm2835 HDMI",
+ .longname = "bcm2835 HDMI",
+ .minchannels = 1,
+- .newpcm = snd_bcm2835_new_simple_pcm,
++ .newpcm = bcm2835_audio_simple_newpcm,
+ .newctl = snd_bcm2835_new_hdmi_ctl,
+ .route = AUDIO_DEST_HDMI
+ };
+@@ -182,7 +191,7 @@ static struct bcm2835_audio_driver bcm28
+ .shortname = "bcm2835 Headphones",
+ .longname = "bcm2835 Headphones",
+ .minchannels = 1,
+- .newpcm = snd_bcm2835_new_simple_pcm,
++ .newpcm = bcm2835_audio_simple_newpcm,
+ .newctl = snd_bcm2835_new_headphones_ctl,
+ .route = AUDIO_DEST_HEADPHONES
+ };
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -84,12 +84,9 @@ struct bcm2835_alsa_stream {
+ };
+
+ int snd_bcm2835_new_ctl(struct bcm2835_chip *chip);
+-int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, u32 numchannels);
+-int snd_bcm2835_new_spdif_pcm(struct bcm2835_chip *chip);
+-int snd_bcm2835_new_simple_pcm(struct bcm2835_chip *chip,
+- const char *name,
+- enum snd_bcm2835_route route,
+- u32 numchannels);
++int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name,
++ int idx, enum snd_bcm2835_route route,
++ u32 numchannels, bool spdif);
+
+ int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip);
+ int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip);
+++ /dev/null
-From 8a01a25d0ad7e9d06f64fddae871deb91c3988ac Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:54 +0200
-Subject: [PATCH] staging: bcm2835-audio: Use coherent device buffers
-
-commit ad29c6e6cbf6f2af7362b043adad51a3be3d39c7 upstream.
-
-The memory access to the pages allocated with
-SNDRV_DMA_TYPE_CONTINUOUS are basically non-coherent, and it becomes a
-problem when a process accesses via mmap.
-
-For the more consistent access, use the device coherent memory, just
-by replacing the call pattern in the allocator helpers.
-
-The only point we need to be careful for is the device object passed
-there; since bcm2835-audio driver creates fake devices and each card
-is created on top of that, we need to pass its parent device as the
-real device object.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 12 ++++++------
- 1 file changed, 6 insertions(+), 6 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -345,8 +345,8 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
-
- /* pre-allocation of buffers */
- /* NOTE: this may fail */
-- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
-- snd_dma_continuous_data(GFP_KERNEL),
-+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-+ chip->card->dev->parent,
- snd_bcm2835_playback_hw.buffer_bytes_max,
- snd_bcm2835_playback_hw.buffer_bytes_max);
-
-@@ -371,8 +371,8 @@ int snd_bcm2835_new_spdif_pcm(struct bcm
-
- /* pre-allocation of buffers */
- /* NOTE: this may fail */
-- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
-- snd_dma_continuous_data(GFP_KERNEL),
-+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-+ chip->card->dev->parent,
- snd_bcm2835_playback_spdif_hw.buffer_bytes_max, snd_bcm2835_playback_spdif_hw.buffer_bytes_max);
-
- return 0;
-@@ -404,8 +404,8 @@ int snd_bcm2835_new_simple_pcm(struct bc
-
- snd_pcm_lib_preallocate_pages_for_all(
- pcm,
-- SNDRV_DMA_TYPE_CONTINUOUS,
-- snd_dma_continuous_data(GFP_KERNEL),
-+ SNDRV_DMA_TYPE_DEV,
-+ chip->card->dev->parent,
- snd_bcm2835_playback_hw.buffer_bytes_max,
- snd_bcm2835_playback_hw.buffer_bytes_max);
-
+++ /dev/null
-From 27417ac1fa4894dc46d71cc34af17fe6a5186f2f Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:55 +0200
-Subject: [PATCH] staging: bcm2835-audio: Set
- SNDRV_PCM_INFO_SYNC_APPLPTR
-
-commit b59d6a5f73501f74848d6700101e7736afe3d54a upstream.
-
-The recent ALSA PCM core supports the SNDRV_PCM_INFO_SYNC_APPLPTR flag
-indicating that the driver needs the ack call at each appl_ptr
-update. This is requirement for the indirect PCM implementations like
-bcm2835-audio driver, too.
-
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -12,7 +12,7 @@
- static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-- SNDRV_PCM_INFO_DRAIN_TRIGGER),
-+ SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
- .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
- .rate_min = 8000,
-@@ -29,7 +29,7 @@ static const struct snd_pcm_hardware snd
- static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-- SNDRV_PCM_INFO_DRAIN_TRIGGER),
-+ SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000,
--- /dev/null
+From c4766c1589a25608ffe6848722632be2f65d0951 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:57 +0200
+Subject: [PATCH] staging: bcm2835-audio: Simplify kctl creation
+ helpers
+
+commit dc5c0eb1e8601206dffbfc302cbd190f89dcd040 upstream.
+
+Just a minor code refactoring and adding some const prefix.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 69 +++++++------------
+ 1 file changed, 25 insertions(+), 44 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
+@@ -97,40 +97,34 @@ static int snd_bcm2835_ctl_put(struct sn
+
+ static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
+
+-static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
++static const struct snd_kcontrol_new snd_bcm2835_ctl[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
+- .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .private_value = PCM_PLAYBACK_VOLUME,
+ .info = snd_bcm2835_ctl_info,
+ .get = snd_bcm2835_ctl_get,
+ .put = snd_bcm2835_ctl_put,
+- .count = 1,
+ .tlv = {.p = snd_bcm2835_db_scale}
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Switch",
+- .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = PCM_PLAYBACK_MUTE,
+ .info = snd_bcm2835_ctl_info,
+ .get = snd_bcm2835_ctl_get,
+ .put = snd_bcm2835_ctl_put,
+- .count = 1,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Route",
+- .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = PCM_PLAYBACK_DEVICE,
+ .info = snd_bcm2835_ctl_info,
+ .get = snd_bcm2835_ctl_get,
+ .put = snd_bcm2835_ctl_put,
+- .count = 1,
+ },
+ };
+
+@@ -196,7 +190,7 @@ static int snd_bcm2835_spdif_mask_get(st
+ return 0;
+ }
+
+-static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
++static const struct snd_kcontrol_new snd_bcm2835_spdif[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+@@ -213,28 +207,32 @@ static struct snd_kcontrol_new snd_bcm28
+ },
+ };
+
+-int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
++static int create_ctls(struct bcm2835_chip *chip, size_t size,
++ const struct snd_kcontrol_new *kctls)
+ {
+- int err;
+- unsigned int idx;
++ int i, err;
+
+- strcpy(chip->card->mixername, "Broadcom Mixer");
+- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
+- err = snd_ctl_add(chip->card,
+- snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
+- if (err < 0)
+- return err;
+- }
+- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
+- err = snd_ctl_add(chip->card,
+- snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
++ for (i = 0; i < size; i++) {
++ err = snd_ctl_add(chip->card, snd_ctl_new1(&kctls[i], chip));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+ }
+
+-static struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
++int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
++{
++ int err;
++
++ strcpy(chip->card->mixername, "Broadcom Mixer");
++ err = create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl), snd_bcm2835_ctl);
++ if (err < 0)
++ return err;
++ return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_spdif),
++ snd_bcm2835_spdif);
++}
++
++static const struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphone Playback Volume",
+@@ -263,21 +261,12 @@ static struct snd_kcontrol_new snd_bcm28
+
+ int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip)
+ {
+- int err;
+- unsigned int idx;
+-
+ strcpy(chip->card->mixername, "Broadcom Mixer");
+- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_headphones_ctl); idx++) {
+- err = snd_ctl_add(chip->card,
+- snd_ctl_new1(&snd_bcm2835_headphones_ctl[idx],
+- chip));
+- if (err)
+- return err;
+- }
+- return 0;
++ return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_headphones_ctl),
++ snd_bcm2835_headphones_ctl);
+ }
+
+-static struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
++static const struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "HDMI Playback Volume",
+@@ -306,16 +295,8 @@ static struct snd_kcontrol_new snd_bcm28
+
+ int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip)
+ {
+- int err;
+- unsigned int idx;
+-
+ strcpy(chip->card->mixername, "Broadcom Mixer");
+- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_hdmi); idx++) {
+- err = snd_ctl_add(chip->card,
+- snd_ctl_new1(&snd_bcm2835_hdmi[idx], chip));
+- if (err)
+- return err;
+- }
+- return 0;
++ return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_hdmi),
++ snd_bcm2835_hdmi);
+ }
+
+++ /dev/null
-From 706f9b2b95a2fff44f92deada99545036c249658 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:56 +0200
-Subject: [PATCH] staging: bcm2835-audio: Simplify PCM creation helpers
-
-commit 74470ffeb9aed5548654cfca881bf1d7469fe9c4 upstream.
-
-All three functions to create PCM objects are fairly resemble, and can
-be unified to a single common helper.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 87 ++++---------------
- .../vc04_services/bcm2835-audio/bcm2835.c | 17 +++-
- .../vc04_services/bcm2835-audio/bcm2835.h | 9 +-
- 3 files changed, 32 insertions(+), 81 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -324,91 +324,36 @@ static const struct snd_pcm_ops snd_bcm2
- };
-
- /* create a pcm device */
--int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, u32 numchannels)
-+int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name,
-+ int idx, enum snd_bcm2835_route route,
-+ u32 numchannels, bool spdif)
- {
- struct snd_pcm *pcm;
- int err;
-
-- err = snd_pcm_new(chip->card, "bcm2835 ALSA", 0, numchannels, 0, &pcm);
-- if (err < 0)
-- return err;
-- pcm->private_data = chip;
-- pcm->nonatomic = true;
-- strcpy(pcm->name, "bcm2835 ALSA");
-- chip->pcm = pcm;
-- chip->dest = AUDIO_DEST_AUTO;
-- chip->volume = 0;
-- chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
-- /* set operators */
-- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-- &snd_bcm2835_playback_ops);
--
-- /* pre-allocation of buffers */
-- /* NOTE: this may fail */
-- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-- chip->card->dev->parent,
-- snd_bcm2835_playback_hw.buffer_bytes_max,
-- snd_bcm2835_playback_hw.buffer_bytes_max);
--
-- return 0;
--}
--
--int snd_bcm2835_new_spdif_pcm(struct bcm2835_chip *chip)
--{
-- struct snd_pcm *pcm;
-- int err;
--
-- err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
-- if (err < 0)
-- return err;
--
-- pcm->private_data = chip;
-- pcm->nonatomic = true;
-- strcpy(pcm->name, "bcm2835 IEC958/HDMI");
-- chip->pcm_spdif = pcm;
-- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-- &snd_bcm2835_playback_spdif_ops);
--
-- /* pre-allocation of buffers */
-- /* NOTE: this may fail */
-- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-- chip->card->dev->parent,
-- snd_bcm2835_playback_spdif_hw.buffer_bytes_max, snd_bcm2835_playback_spdif_hw.buffer_bytes_max);
--
-- return 0;
--}
--
--int snd_bcm2835_new_simple_pcm(struct bcm2835_chip *chip,
-- const char *name,
-- enum snd_bcm2835_route route,
-- u32 numchannels)
--{
-- struct snd_pcm *pcm;
-- int err;
--
-- err = snd_pcm_new(chip->card, name, 0, numchannels,
-- 0, &pcm);
-+ err = snd_pcm_new(chip->card, name, idx, numchannels, 0, &pcm);
- if (err)
- return err;
-
- pcm->private_data = chip;
- pcm->nonatomic = true;
- strcpy(pcm->name, name);
-- chip->pcm = pcm;
-- chip->dest = route;
-- chip->volume = 0;
-- chip->mute = CTRL_VOL_UNMUTE;
-+ if (!spdif) {
-+ chip->dest = route;
-+ chip->volume = 0;
-+ chip->mute = CTRL_VOL_UNMUTE;
-+ }
-
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-+ spdif ? &snd_bcm2835_playback_spdif_ops :
- &snd_bcm2835_playback_ops);
-
-- snd_pcm_lib_preallocate_pages_for_all(
-- pcm,
-- SNDRV_DMA_TYPE_DEV,
-- chip->card->dev->parent,
-- snd_bcm2835_playback_hw.buffer_bytes_max,
-- snd_bcm2835_playback_hw.buffer_bytes_max);
-+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-+ chip->card->dev->parent, 128 * 1024, 128 * 1024);
-
-+ if (spdif)
-+ chip->pcm_spdif = pcm;
-+ else
-+ chip->pcm = pcm;
- return 0;
- }
--
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -138,17 +138,26 @@ static int bcm2835_audio_alsa_newpcm(str
- {
- int err;
-
-- err = snd_bcm2835_new_pcm(chip, numchannels - 1);
-+ err = snd_bcm2835_new_pcm(chip, "bcm2835 ALSA", 0, AUDIO_DEST_AUTO,
-+ numchannels - 1, false);
- if (err)
- return err;
-
-- err = snd_bcm2835_new_spdif_pcm(chip);
-+ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true);
- if (err)
- return err;
-
- return 0;
- }
-
-+static int bcm2835_audio_simple_newpcm(struct bcm2835_chip *chip,
-+ const char *name,
-+ enum snd_bcm2835_route route,
-+ u32 numchannels)
-+{
-+ return snd_bcm2835_new_pcm(chip, name, 0, route, numchannels, false);
-+}
-+
- static struct bcm2835_audio_driver bcm2835_audio_alsa = {
- .driver = {
- .name = "bcm2835_alsa",
-@@ -169,7 +178,7 @@ static struct bcm2835_audio_driver bcm28
- .shortname = "bcm2835 HDMI",
- .longname = "bcm2835 HDMI",
- .minchannels = 1,
-- .newpcm = snd_bcm2835_new_simple_pcm,
-+ .newpcm = bcm2835_audio_simple_newpcm,
- .newctl = snd_bcm2835_new_hdmi_ctl,
- .route = AUDIO_DEST_HDMI
- };
-@@ -182,7 +191,7 @@ static struct bcm2835_audio_driver bcm28
- .shortname = "bcm2835 Headphones",
- .longname = "bcm2835 Headphones",
- .minchannels = 1,
-- .newpcm = snd_bcm2835_new_simple_pcm,
-+ .newpcm = bcm2835_audio_simple_newpcm,
- .newctl = snd_bcm2835_new_headphones_ctl,
- .route = AUDIO_DEST_HEADPHONES
- };
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -84,12 +84,9 @@ struct bcm2835_alsa_stream {
- };
-
- int snd_bcm2835_new_ctl(struct bcm2835_chip *chip);
--int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, u32 numchannels);
--int snd_bcm2835_new_spdif_pcm(struct bcm2835_chip *chip);
--int snd_bcm2835_new_simple_pcm(struct bcm2835_chip *chip,
-- const char *name,
-- enum snd_bcm2835_route route,
-- u32 numchannels);
-+int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name,
-+ int idx, enum snd_bcm2835_route route,
-+ u32 numchannels, bool spdif);
-
- int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip);
- int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip);
--- /dev/null
+From b19ed31a1ced7b6d4c4c04967a509d91a134e5bb Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 17:58:58 +0200
+Subject: [PATCH] staging: bcm2835-audio: Simplify card object
+ management
+
+commit 872ae2d63d516a2a3b9c833d8685afcfa7814542 upstream.
+
+Instead of creating a dummy child device to manage the card object,
+just use devm stuff directly for releasing with snd_card_free().
+This results in a lot of code reduction.
+
+Since the dummy child devices are gone, the device object to be passed
+to the memory allocator needs to be adjusted as well.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 2 +-
+ .../vc04_services/bcm2835-audio/bcm2835.c | 120 +++++-------------
+ 2 files changed, 33 insertions(+), 89 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -349,7 +349,7 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
+ &snd_bcm2835_playback_ops);
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+- chip->card->dev->parent, 128 * 1024, 128 * 1024);
++ chip->card->dev, 128 * 1024, 128 * 1024);
+
+ if (spdif)
+ chip->pcm_spdif = pcm;
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -22,38 +22,6 @@ module_param(enable_compat_alsa, bool, 0
+ MODULE_PARM_DESC(enable_compat_alsa,
+ "Enables ALSA compatibility virtual audio device");
+
+-static void snd_devm_unregister_child(struct device *dev, void *res)
+-{
+- struct device *childdev = *(struct device **)res;
+- struct bcm2835_chip *chip = dev_get_drvdata(childdev);
+- struct snd_card *card = chip->card;
+-
+- snd_card_free(card);
+-
+- device_unregister(childdev);
+-}
+-
+-static int snd_devm_add_child(struct device *dev, struct device *child)
+-{
+- struct device **dr;
+- int ret;
+-
+- dr = devres_alloc(snd_devm_unregister_child, sizeof(*dr), GFP_KERNEL);
+- if (!dr)
+- return -ENOMEM;
+-
+- ret = device_add(child);
+- if (ret) {
+- devres_free(dr);
+- return ret;
+- }
+-
+- *dr = child;
+- devres_add(dev, dr);
+-
+- return 0;
+-}
+-
+ static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res)
+ {
+ struct bcm2835_vchi_ctx *vchi_ctx = res;
+@@ -84,36 +52,6 @@ static int bcm2835_devm_add_vchi_ctx(str
+ return 0;
+ }
+
+-static void snd_bcm2835_release(struct device *dev)
+-{
+-}
+-
+-static struct device *
+-snd_create_device(struct device *parent,
+- struct device_driver *driver,
+- const char *name)
+-{
+- struct device *device;
+- int ret;
+-
+- device = devm_kzalloc(parent, sizeof(*device), GFP_KERNEL);
+- if (!device)
+- return ERR_PTR(-ENOMEM);
+-
+- device_initialize(device);
+- device->parent = parent;
+- device->driver = driver;
+- device->release = snd_bcm2835_release;
+-
+- dev_set_name(device, "%s", name);
+-
+- ret = snd_devm_add_child(parent, device);
+- if (ret)
+- return ERR_PTR(ret);
+-
+- return device;
+-}
+-
+ typedef int (*bcm2835_audio_newpcm_func)(struct bcm2835_chip *chip,
+ const char *name,
+ enum snd_bcm2835_route route,
+@@ -216,40 +154,36 @@ static struct bcm2835_audio_drivers chil
+ },
+ };
+
+-static int snd_add_child_device(struct device *device,
++static void bcm2835_card_free(void *data)
++{
++ snd_card_free(data);
++}
++
++static int snd_add_child_device(struct device *dev,
+ struct bcm2835_audio_driver *audio_driver,
+ u32 numchans)
+ {
+ struct snd_card *card;
+- struct device *child;
+ struct bcm2835_chip *chip;
+ int err;
+
+- child = snd_create_device(device, &audio_driver->driver,
+- audio_driver->driver.name);
+- if (IS_ERR(child)) {
+- dev_err(device,
+- "Unable to create child device %p, error %ld",
+- audio_driver->driver.name,
+- PTR_ERR(child));
+- return PTR_ERR(child);
+- }
+-
+- err = snd_card_new(child, -1, NULL, THIS_MODULE, sizeof(*chip), &card);
++ err = snd_card_new(dev, -1, NULL, THIS_MODULE, sizeof(*chip), &card);
+ if (err < 0) {
+- dev_err(child, "Failed to create card");
++ dev_err(dev, "Failed to create card");
+ return err;
+ }
+
+ chip = card->private_data;
+ chip->card = card;
+- chip->dev = child;
++ chip->dev = dev;
+ mutex_init(&chip->audio_mutex);
+
+- chip->vchi_ctx = devres_find(device,
++ chip->vchi_ctx = devres_find(dev,
+ bcm2835_devm_free_vchi_ctx, NULL, NULL);
+- if (!chip->vchi_ctx)
+- return -ENODEV;
++ if (!chip->vchi_ctx) {
++ err = -ENODEV;
++ goto error;
++ }
+
+ strcpy(card->driver, audio_driver->driver.name);
+ strcpy(card->shortname, audio_driver->shortname);
+@@ -259,26 +193,36 @@ static int snd_add_child_device(struct d
+ audio_driver->route,
+ numchans);
+ if (err) {
+- dev_err(child, "Failed to create pcm, error %d\n", err);
+- return err;
++ dev_err(dev, "Failed to create pcm, error %d\n", err);
++ goto error;
+ }
+
+ err = audio_driver->newctl(chip);
+ if (err) {
+- dev_err(child, "Failed to create controls, error %d\n", err);
+- return err;
++ dev_err(dev, "Failed to create controls, error %d\n", err);
++ goto error;
+ }
+
+ err = snd_card_register(card);
+ if (err) {
+- dev_err(child, "Failed to register card, error %d\n", err);
+- return err;
++ dev_err(dev, "Failed to register card, error %d\n", err);
++ goto error;
+ }
+
+- dev_set_drvdata(child, chip);
+- dev_info(child, "card created with %d channels\n", numchans);
++ dev_set_drvdata(dev, chip);
+
++ err = devm_add_action(dev, bcm2835_card_free, card);
++ if (err < 0) {
++ dev_err(dev, "Failed to add devm action, err %d\n", err);
++ goto error;
++ }
++
++ dev_info(dev, "card created with %d channels\n", numchans);
+ return 0;
++
++ error:
++ snd_card_free(card);
++ return err;
+ }
+
+ static int snd_add_child_devices(struct device *device, u32 numchans)
+++ /dev/null
-From c4766c1589a25608ffe6848722632be2f65d0951 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:57 +0200
-Subject: [PATCH] staging: bcm2835-audio: Simplify kctl creation
- helpers
-
-commit dc5c0eb1e8601206dffbfc302cbd190f89dcd040 upstream.
-
-Just a minor code refactoring and adding some const prefix.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-ctl.c | 69 +++++++------------
- 1 file changed, 25 insertions(+), 44 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
-@@ -97,40 +97,34 @@ static int snd_bcm2835_ctl_put(struct sn
-
- static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
-
--static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
-+static const struct snd_kcontrol_new snd_bcm2835_ctl[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PCM Playback Volume",
-- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .private_value = PCM_PLAYBACK_VOLUME,
- .info = snd_bcm2835_ctl_info,
- .get = snd_bcm2835_ctl_get,
- .put = snd_bcm2835_ctl_put,
-- .count = 1,
- .tlv = {.p = snd_bcm2835_db_scale}
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PCM Playback Switch",
-- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .private_value = PCM_PLAYBACK_MUTE,
- .info = snd_bcm2835_ctl_info,
- .get = snd_bcm2835_ctl_get,
- .put = snd_bcm2835_ctl_put,
-- .count = 1,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PCM Playback Route",
-- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .private_value = PCM_PLAYBACK_DEVICE,
- .info = snd_bcm2835_ctl_info,
- .get = snd_bcm2835_ctl_get,
- .put = snd_bcm2835_ctl_put,
-- .count = 1,
- },
- };
-
-@@ -196,7 +190,7 @@ static int snd_bcm2835_spdif_mask_get(st
- return 0;
- }
-
--static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
-+static const struct snd_kcontrol_new snd_bcm2835_spdif[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
- .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
-@@ -213,28 +207,32 @@ static struct snd_kcontrol_new snd_bcm28
- },
- };
-
--int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
-+static int create_ctls(struct bcm2835_chip *chip, size_t size,
-+ const struct snd_kcontrol_new *kctls)
- {
-- int err;
-- unsigned int idx;
-+ int i, err;
-
-- strcpy(chip->card->mixername, "Broadcom Mixer");
-- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
-- err = snd_ctl_add(chip->card,
-- snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
-- if (err < 0)
-- return err;
-- }
-- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
-- err = snd_ctl_add(chip->card,
-- snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
-+ for (i = 0; i < size; i++) {
-+ err = snd_ctl_add(chip->card, snd_ctl_new1(&kctls[i], chip));
- if (err < 0)
- return err;
- }
- return 0;
- }
-
--static struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
-+int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
-+{
-+ int err;
-+
-+ strcpy(chip->card->mixername, "Broadcom Mixer");
-+ err = create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl), snd_bcm2835_ctl);
-+ if (err < 0)
-+ return err;
-+ return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_spdif),
-+ snd_bcm2835_spdif);
-+}
-+
-+static const struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Headphone Playback Volume",
-@@ -263,21 +261,12 @@ static struct snd_kcontrol_new snd_bcm28
-
- int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip)
- {
-- int err;
-- unsigned int idx;
--
- strcpy(chip->card->mixername, "Broadcom Mixer");
-- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_headphones_ctl); idx++) {
-- err = snd_ctl_add(chip->card,
-- snd_ctl_new1(&snd_bcm2835_headphones_ctl[idx],
-- chip));
-- if (err)
-- return err;
-- }
-- return 0;
-+ return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_headphones_ctl),
-+ snd_bcm2835_headphones_ctl);
- }
-
--static struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
-+static const struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "HDMI Playback Volume",
-@@ -306,16 +295,8 @@ static struct snd_kcontrol_new snd_bcm28
-
- int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip)
- {
-- int err;
-- unsigned int idx;
--
- strcpy(chip->card->mixername, "Broadcom Mixer");
-- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_hdmi); idx++) {
-- err = snd_ctl_add(chip->card,
-- snd_ctl_new1(&snd_bcm2835_hdmi[idx], chip));
-- if (err)
-- return err;
-- }
-- return 0;
-+ return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_hdmi),
-+ snd_bcm2835_hdmi);
- }
-
--- /dev/null
+From 26693d4d1239b8239644ce6da50b8ce06ff18ae5 Mon Sep 17 00:00:00 2001
+Date: Wed, 17 Oct 2018 21:01:50 +0200
+Subject: [PATCH] staging: bcm2835-audio: unify FOURCC command
+ definitions
+
+commit a90d8f49cc7fd7220aa24b85fc74ef3cfd62b96f upstream.
+
+The device communicates with the audio core using FOURCC codes. The
+driver was generating them using different macros/expressions. We now
+use the same macro to create them and centralize all the definitions.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-vchiq.c | 13 ++++---------
+ .../bcm2835-audio/vc_vchi_audioserv_defs.h | 4 +++-
+ 2 files changed, 7 insertions(+), 10 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -89,11 +89,6 @@ static int bcm2835_audio_send_simple(str
+ return bcm2835_audio_send_msg(instance, &m, wait);
+ }
+
+-static const u32 BCM2835_AUDIO_WRITE_COOKIE1 = ('B' << 24 | 'C' << 16 |
+- 'M' << 8 | 'A');
+-static const u32 BCM2835_AUDIO_WRITE_COOKIE2 = ('D' << 24 | 'A' << 16 |
+- 'T' << 8 | 'A');
+-
+ static void audio_vchi_callback(void *param,
+ const VCHI_CALLBACK_REASON_T reason,
+ void *msg_handle)
+@@ -112,8 +107,8 @@ static void audio_vchi_callback(void *pa
+ instance->result = m.u.result.success;
+ complete(&instance->msg_avail_comp);
+ } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
+- if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
+- m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
++ if (m.u.complete.cookie1 != VC_AUDIO_WRITE_COOKIE1 ||
++ m.u.complete.cookie2 != VC_AUDIO_WRITE_COOKIE2)
+ dev_err(instance->dev, "invalid cookie\n");
+ else
+ bcm2835_playback_fifo(instance->alsa_stream,
+@@ -337,8 +332,8 @@ int bcm2835_audio_write(struct bcm2835_a
+ .type = VC_AUDIO_MSG_TYPE_WRITE,
+ .u.write.count = size,
+ .u.write.max_packet = instance->max_packet,
+- .u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1,
+- .u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2,
++ .u.write.cookie1 = VC_AUDIO_WRITE_COOKIE1,
++ .u.write.cookie2 = VC_AUDIO_WRITE_COOKIE2,
+ };
+ unsigned int count;
+ int err, status;
+--- a/drivers/staging/vc04_services/bcm2835-audio/vc_vchi_audioserv_defs.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/vc_vchi_audioserv_defs.h
+@@ -7,8 +7,10 @@
+ #define VC_AUDIOSERV_MIN_VER 1
+ #define VC_AUDIOSERV_VER 2
+
+-/* FourCC code used for VCHI connection */
++/* FourCC codes used for VCHI communication */
+ #define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
++#define VC_AUDIO_WRITE_COOKIE1 MAKE_FOURCC("BCMA")
++#define VC_AUDIO_WRITE_COOKIE2 MAKE_FOURCC("DATA")
+
+ /*
+ * List of screens that are currently supported
+++ /dev/null
-From b19ed31a1ced7b6d4c4c04967a509d91a134e5bb Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 17:58:58 +0200
-Subject: [PATCH] staging: bcm2835-audio: Simplify card object
- management
-
-commit 872ae2d63d516a2a3b9c833d8685afcfa7814542 upstream.
-
-Instead of creating a dummy child device to manage the card object,
-just use devm stuff directly for releasing with snd_card_free().
-This results in a lot of code reduction.
-
-Since the dummy child devices are gone, the device object to be passed
-to the memory allocator needs to be adjusted as well.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 2 +-
- .../vc04_services/bcm2835-audio/bcm2835.c | 120 +++++-------------
- 2 files changed, 33 insertions(+), 89 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -349,7 +349,7 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
- &snd_bcm2835_playback_ops);
-
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-- chip->card->dev->parent, 128 * 1024, 128 * 1024);
-+ chip->card->dev, 128 * 1024, 128 * 1024);
-
- if (spdif)
- chip->pcm_spdif = pcm;
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -22,38 +22,6 @@ module_param(enable_compat_alsa, bool, 0
- MODULE_PARM_DESC(enable_compat_alsa,
- "Enables ALSA compatibility virtual audio device");
-
--static void snd_devm_unregister_child(struct device *dev, void *res)
--{
-- struct device *childdev = *(struct device **)res;
-- struct bcm2835_chip *chip = dev_get_drvdata(childdev);
-- struct snd_card *card = chip->card;
--
-- snd_card_free(card);
--
-- device_unregister(childdev);
--}
--
--static int snd_devm_add_child(struct device *dev, struct device *child)
--{
-- struct device **dr;
-- int ret;
--
-- dr = devres_alloc(snd_devm_unregister_child, sizeof(*dr), GFP_KERNEL);
-- if (!dr)
-- return -ENOMEM;
--
-- ret = device_add(child);
-- if (ret) {
-- devres_free(dr);
-- return ret;
-- }
--
-- *dr = child;
-- devres_add(dev, dr);
--
-- return 0;
--}
--
- static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res)
- {
- struct bcm2835_vchi_ctx *vchi_ctx = res;
-@@ -84,36 +52,6 @@ static int bcm2835_devm_add_vchi_ctx(str
- return 0;
- }
-
--static void snd_bcm2835_release(struct device *dev)
--{
--}
--
--static struct device *
--snd_create_device(struct device *parent,
-- struct device_driver *driver,
-- const char *name)
--{
-- struct device *device;
-- int ret;
--
-- device = devm_kzalloc(parent, sizeof(*device), GFP_KERNEL);
-- if (!device)
-- return ERR_PTR(-ENOMEM);
--
-- device_initialize(device);
-- device->parent = parent;
-- device->driver = driver;
-- device->release = snd_bcm2835_release;
--
-- dev_set_name(device, "%s", name);
--
-- ret = snd_devm_add_child(parent, device);
-- if (ret)
-- return ERR_PTR(ret);
--
-- return device;
--}
--
- typedef int (*bcm2835_audio_newpcm_func)(struct bcm2835_chip *chip,
- const char *name,
- enum snd_bcm2835_route route,
-@@ -216,40 +154,36 @@ static struct bcm2835_audio_drivers chil
- },
- };
-
--static int snd_add_child_device(struct device *device,
-+static void bcm2835_card_free(void *data)
-+{
-+ snd_card_free(data);
-+}
-+
-+static int snd_add_child_device(struct device *dev,
- struct bcm2835_audio_driver *audio_driver,
- u32 numchans)
- {
- struct snd_card *card;
-- struct device *child;
- struct bcm2835_chip *chip;
- int err;
-
-- child = snd_create_device(device, &audio_driver->driver,
-- audio_driver->driver.name);
-- if (IS_ERR(child)) {
-- dev_err(device,
-- "Unable to create child device %p, error %ld",
-- audio_driver->driver.name,
-- PTR_ERR(child));
-- return PTR_ERR(child);
-- }
--
-- err = snd_card_new(child, -1, NULL, THIS_MODULE, sizeof(*chip), &card);
-+ err = snd_card_new(dev, -1, NULL, THIS_MODULE, sizeof(*chip), &card);
- if (err < 0) {
-- dev_err(child, "Failed to create card");
-+ dev_err(dev, "Failed to create card");
- return err;
- }
-
- chip = card->private_data;
- chip->card = card;
-- chip->dev = child;
-+ chip->dev = dev;
- mutex_init(&chip->audio_mutex);
-
-- chip->vchi_ctx = devres_find(device,
-+ chip->vchi_ctx = devres_find(dev,
- bcm2835_devm_free_vchi_ctx, NULL, NULL);
-- if (!chip->vchi_ctx)
-- return -ENODEV;
-+ if (!chip->vchi_ctx) {
-+ err = -ENODEV;
-+ goto error;
-+ }
-
- strcpy(card->driver, audio_driver->driver.name);
- strcpy(card->shortname, audio_driver->shortname);
-@@ -259,26 +193,36 @@ static int snd_add_child_device(struct d
- audio_driver->route,
- numchans);
- if (err) {
-- dev_err(child, "Failed to create pcm, error %d\n", err);
-- return err;
-+ dev_err(dev, "Failed to create pcm, error %d\n", err);
-+ goto error;
- }
-
- err = audio_driver->newctl(chip);
- if (err) {
-- dev_err(child, "Failed to create controls, error %d\n", err);
-- return err;
-+ dev_err(dev, "Failed to create controls, error %d\n", err);
-+ goto error;
- }
-
- err = snd_card_register(card);
- if (err) {
-- dev_err(child, "Failed to register card, error %d\n", err);
-- return err;
-+ dev_err(dev, "Failed to register card, error %d\n", err);
-+ goto error;
- }
-
-- dev_set_drvdata(child, chip);
-- dev_info(child, "card created with %d channels\n", numchans);
-+ dev_set_drvdata(dev, chip);
-
-+ err = devm_add_action(dev, bcm2835_card_free, card);
-+ if (err < 0) {
-+ dev_err(dev, "Failed to add devm action, err %d\n", err);
-+ goto error;
-+ }
-+
-+ dev_info(dev, "card created with %d channels\n", numchans);
- return 0;
-+
-+ error:
-+ snd_card_free(card);
-+ return err;
- }
-
- static int snd_add_child_devices(struct device *device, u32 numchans)
--- /dev/null
+From 7250c9d3d3f1b861d8f0c6220a81a465e45d70eb Mon Sep 17 00:00:00 2001
+Date: Wed, 17 Oct 2018 21:01:51 +0200
+Subject: [PATCH] staging: bcm2835-audio: don't initialize memory twice
+
+commit 2e5f59fb77397cab3bc3d156e8be4164a67d32ef upstream.
+
+The memory is being allocated with devres_alloc(), wich ultimately uses
+__GFP_ZERO to call kmalloc. We don't need to zero the memory area again
+in bcm2835-audio.
+
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -39,8 +39,6 @@ static int bcm2835_devm_add_vchi_ctx(str
+ if (!vchi_ctx)
+ return -ENOMEM;
+
+- memset(vchi_ctx, 0, sizeof(*vchi_ctx));
+-
+ ret = bcm2835_new_vchi_ctx(dev, vchi_ctx);
+ if (ret) {
+ devres_free(vchi_ctx);
--- /dev/null
+From 604f0019cc1eaed6a316d7875fe697e53f5f105c Mon Sep 17 00:00:00 2001
+Date: Wed, 17 Oct 2018 21:01:52 +0200
+Subject: [PATCH] staging: bcm2835-audio: reorder variable declarations
+ & remove trivial comments
+
+commit d048385a070552ae819f99f05bd03ec41072783d upstream.
+
+When it comes to declaring variables it's preferred, when possible, to
+use an inverted tree organization scheme.
+
+Also, removes some comments that were useless.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 10 ++--------
+ .../vc04_services/bcm2835-audio/bcm2835-vchiq.c | 4 ++--
+ .../staging/vc04_services/bcm2835-audio/bcm2835.c | 14 +++++++-------
+ 3 files changed, 11 insertions(+), 17 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -164,14 +164,11 @@ static int snd_bcm2835_playback_spdif_op
+ return snd_bcm2835_playback_open_generic(substream, 1);
+ }
+
+-/* close callback */
+ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
+ {
+- /* the hardware-specific codes will be here */
+-
+- struct bcm2835_chip *chip;
+- struct snd_pcm_runtime *runtime;
+ struct bcm2835_alsa_stream *alsa_stream;
++ struct snd_pcm_runtime *runtime;
++ struct bcm2835_chip *chip;
+
+ chip = snd_pcm_substream_chip(substream);
+ mutex_lock(&chip->audio_mutex);
+@@ -195,20 +192,17 @@ static int snd_bcm2835_playback_close(st
+ return 0;
+ }
+
+-/* hw_params callback */
+ static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+ {
+ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+ }
+
+-/* hw_free callback */
+ static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
+ {
+ return snd_pcm_lib_free_pages(substream);
+ }
+
+-/* prepare callback */
+ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
+ {
+ struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -94,9 +94,9 @@ static void audio_vchi_callback(void *pa
+ void *msg_handle)
+ {
+ struct bcm2835_audio_instance *instance = param;
+- int status;
+- int msg_len;
+ struct vc_audio_msg m;
++ int msg_len;
++ int status;
+
+ if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
+ return;
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -161,8 +161,8 @@ static int snd_add_child_device(struct d
+ struct bcm2835_audio_driver *audio_driver,
+ u32 numchans)
+ {
+- struct snd_card *card;
+ struct bcm2835_chip *chip;
++ struct snd_card *card;
+ int err;
+
+ err = snd_card_new(dev, -1, NULL, THIS_MODULE, sizeof(*chip), &card);
+@@ -225,12 +225,12 @@ static int snd_add_child_device(struct d
+
+ static int snd_add_child_devices(struct device *device, u32 numchans)
+ {
+- int i;
+- int count_devices = 0;
+- int minchannels = 0;
+- int extrachannels = 0;
+ int extrachannels_per_driver = 0;
+ int extrachannels_remainder = 0;
++ int count_devices = 0;
++ int extrachannels = 0;
++ int minchannels = 0;
++ int i;
+
+ for (i = 0; i < ARRAY_SIZE(children_devices); i++)
+ if (*children_devices[i].is_enabled)
+@@ -258,9 +258,9 @@ static int snd_add_child_devices(struct
+ extrachannels_remainder);
+
+ for (i = 0; i < ARRAY_SIZE(children_devices); i++) {
+- int err;
+- int numchannels_this_device;
+ struct bcm2835_audio_driver *audio_driver;
++ int numchannels_this_device;
++ int err;
+
+ if (!*children_devices[i].is_enabled)
+ continue;
+++ /dev/null
-From 26693d4d1239b8239644ce6da50b8ce06ff18ae5 Mon Sep 17 00:00:00 2001
-Date: Wed, 17 Oct 2018 21:01:50 +0200
-Subject: [PATCH] staging: bcm2835-audio: unify FOURCC command
- definitions
-
-commit a90d8f49cc7fd7220aa24b85fc74ef3cfd62b96f upstream.
-
-The device communicates with the audio core using FOURCC codes. The
-driver was generating them using different macros/expressions. We now
-use the same macro to create them and centralize all the definitions.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-vchiq.c | 13 ++++---------
- .../bcm2835-audio/vc_vchi_audioserv_defs.h | 4 +++-
- 2 files changed, 7 insertions(+), 10 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -89,11 +89,6 @@ static int bcm2835_audio_send_simple(str
- return bcm2835_audio_send_msg(instance, &m, wait);
- }
-
--static const u32 BCM2835_AUDIO_WRITE_COOKIE1 = ('B' << 24 | 'C' << 16 |
-- 'M' << 8 | 'A');
--static const u32 BCM2835_AUDIO_WRITE_COOKIE2 = ('D' << 24 | 'A' << 16 |
-- 'T' << 8 | 'A');
--
- static void audio_vchi_callback(void *param,
- const VCHI_CALLBACK_REASON_T reason,
- void *msg_handle)
-@@ -112,8 +107,8 @@ static void audio_vchi_callback(void *pa
- instance->result = m.u.result.success;
- complete(&instance->msg_avail_comp);
- } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
-- if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
-- m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
-+ if (m.u.complete.cookie1 != VC_AUDIO_WRITE_COOKIE1 ||
-+ m.u.complete.cookie2 != VC_AUDIO_WRITE_COOKIE2)
- dev_err(instance->dev, "invalid cookie\n");
- else
- bcm2835_playback_fifo(instance->alsa_stream,
-@@ -337,8 +332,8 @@ int bcm2835_audio_write(struct bcm2835_a
- .type = VC_AUDIO_MSG_TYPE_WRITE,
- .u.write.count = size,
- .u.write.max_packet = instance->max_packet,
-- .u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1,
-- .u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2,
-+ .u.write.cookie1 = VC_AUDIO_WRITE_COOKIE1,
-+ .u.write.cookie2 = VC_AUDIO_WRITE_COOKIE2,
- };
- unsigned int count;
- int err, status;
---- a/drivers/staging/vc04_services/bcm2835-audio/vc_vchi_audioserv_defs.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/vc_vchi_audioserv_defs.h
-@@ -7,8 +7,10 @@
- #define VC_AUDIOSERV_MIN_VER 1
- #define VC_AUDIOSERV_VER 2
-
--/* FourCC code used for VCHI connection */
-+/* FourCC codes used for VCHI communication */
- #define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
-+#define VC_AUDIO_WRITE_COOKIE1 MAKE_FOURCC("BCMA")
-+#define VC_AUDIO_WRITE_COOKIE2 MAKE_FOURCC("DATA")
-
- /*
- * List of screens that are currently supported
+++ /dev/null
-From 7250c9d3d3f1b861d8f0c6220a81a465e45d70eb Mon Sep 17 00:00:00 2001
-Date: Wed, 17 Oct 2018 21:01:51 +0200
-Subject: [PATCH] staging: bcm2835-audio: don't initialize memory twice
-
-commit 2e5f59fb77397cab3bc3d156e8be4164a67d32ef upstream.
-
-The memory is being allocated with devres_alloc(), wich ultimately uses
-__GFP_ZERO to call kmalloc. We don't need to zero the memory area again
-in bcm2835-audio.
-
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835.c | 2 --
- 1 file changed, 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -39,8 +39,6 @@ static int bcm2835_devm_add_vchi_ctx(str
- if (!vchi_ctx)
- return -ENOMEM;
-
-- memset(vchi_ctx, 0, sizeof(*vchi_ctx));
--
- ret = bcm2835_new_vchi_ctx(dev, vchi_ctx);
- if (ret) {
- devres_free(vchi_ctx);
--- /dev/null
+From 23b89436030e64196a1bc317901d08edd54fb772 Mon Sep 17 00:00:00 2001
+Date: Wed, 17 Oct 2018 21:01:53 +0200
+Subject: [PATCH] staging: bcm2835-audio: use anonymous union in struct
+ vc_audio_msg
+
+commit 9c2eaf7da855d314a369d48b9cbf8ac80717a1d0 upstream.
+
+In this case explicitly naming the union doesn't help overall code
+comprehension and clutters it.
+
+---
+ .../bcm2835-audio/bcm2835-vchiq.c | 30 +++++++++----------
+ .../bcm2835-audio/vc_vchi_audioserv_defs.h | 2 +-
+ 2 files changed, 16 insertions(+), 16 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -104,15 +104,15 @@ static void audio_vchi_callback(void *pa
+ status = vchi_msg_dequeue(instance->vchi_handle,
+ &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
+ if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
+- instance->result = m.u.result.success;
++ instance->result = m.result.success;
+ complete(&instance->msg_avail_comp);
+ } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
+- if (m.u.complete.cookie1 != VC_AUDIO_WRITE_COOKIE1 ||
+- m.u.complete.cookie2 != VC_AUDIO_WRITE_COOKIE2)
++ if (m.complete.cookie1 != VC_AUDIO_WRITE_COOKIE1 ||
++ m.complete.cookie2 != VC_AUDIO_WRITE_COOKIE2)
+ dev_err(instance->dev, "invalid cookie\n");
+ else
+ bcm2835_playback_fifo(instance->alsa_stream,
+- m.u.complete.count);
++ m.complete.count);
+ } else {
+ dev_err(instance->dev, "unexpected callback type=%d\n", m.type);
+ }
+@@ -257,11 +257,11 @@ int bcm2835_audio_set_ctls(struct bcm283
+ struct vc_audio_msg m = {};
+
+ m.type = VC_AUDIO_MSG_TYPE_CONTROL;
+- m.u.control.dest = chip->dest;
++ m.control.dest = chip->dest;
+ if (!chip->mute)
+- m.u.control.volume = CHIP_MIN_VOLUME;
++ m.control.volume = CHIP_MIN_VOLUME;
+ else
+- m.u.control.volume = alsa2chip(chip->volume);
++ m.control.volume = alsa2chip(chip->volume);
+
+ return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
+ }
+@@ -272,9 +272,9 @@ int bcm2835_audio_set_params(struct bcm2
+ {
+ struct vc_audio_msg m = {
+ .type = VC_AUDIO_MSG_TYPE_CONFIG,
+- .u.config.channels = channels,
+- .u.config.samplerate = samplerate,
+- .u.config.bps = bps,
++ .config.channels = channels,
++ .config.samplerate = samplerate,
++ .config.bps = bps,
+ };
+ int err;
+
+@@ -302,7 +302,7 @@ int bcm2835_audio_drain(struct bcm2835_a
+ {
+ struct vc_audio_msg m = {
+ .type = VC_AUDIO_MSG_TYPE_STOP,
+- .u.stop.draining = 1,
++ .stop.draining = 1,
+ };
+
+ return bcm2835_audio_send_msg(alsa_stream->instance, &m, false);
+@@ -330,10 +330,10 @@ int bcm2835_audio_write(struct bcm2835_a
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
+ struct vc_audio_msg m = {
+ .type = VC_AUDIO_MSG_TYPE_WRITE,
+- .u.write.count = size,
+- .u.write.max_packet = instance->max_packet,
+- .u.write.cookie1 = VC_AUDIO_WRITE_COOKIE1,
+- .u.write.cookie2 = VC_AUDIO_WRITE_COOKIE2,
++ .write.count = size,
++ .write.max_packet = instance->max_packet,
++ .write.cookie1 = VC_AUDIO_WRITE_COOKIE1,
++ .write.cookie2 = VC_AUDIO_WRITE_COOKIE2,
+ };
+ unsigned int count;
+ int err, status;
+--- a/drivers/staging/vc04_services/bcm2835-audio/vc_vchi_audioserv_defs.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/vc_vchi_audioserv_defs.h
+@@ -93,7 +93,7 @@ struct vc_audio_msg {
+ struct vc_audio_write write;
+ struct vc_audio_result result;
+ struct vc_audio_complete complete;
+- } u;
++ };
+ };
+
+ #endif /* _VC_AUDIO_DEFS_H_ */
--- /dev/null
+From 0b7d959b0d0c18959c66696844a1c9956370ab99 Mon Sep 17 00:00:00 2001
+Date: Wed, 17 Oct 2018 21:01:54 +0200
+Subject: [PATCH] staging: bcm2835-audio: more generic probe function
+ name
+
+commit 96f3bd8ae6516898c7b411ecb87064bb0dd25415 upstream.
+
+There will only be one probe function, there is no use for appendig
+"_dt" the end of the name.
+
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -291,7 +291,7 @@ static int snd_add_child_devices(struct
+ return 0;
+ }
+
+-static int snd_bcm2835_alsa_probe_dt(struct platform_device *pdev)
++static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+ u32 numchans;
+@@ -344,7 +344,7 @@ static const struct of_device_id snd_bcm
+ MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table);
+
+ static struct platform_driver bcm2835_alsa0_driver = {
+- .probe = snd_bcm2835_alsa_probe_dt,
++ .probe = snd_bcm2835_alsa_probe,
+ #ifdef CONFIG_PM
+ .suspend = snd_bcm2835_alsa_suspend,
+ .resume = snd_bcm2835_alsa_resume,
+++ /dev/null
-From 604f0019cc1eaed6a316d7875fe697e53f5f105c Mon Sep 17 00:00:00 2001
-Date: Wed, 17 Oct 2018 21:01:52 +0200
-Subject: [PATCH] staging: bcm2835-audio: reorder variable declarations
- & remove trivial comments
-
-commit d048385a070552ae819f99f05bd03ec41072783d upstream.
-
-When it comes to declaring variables it's preferred, when possible, to
-use an inverted tree organization scheme.
-
-Also, removes some comments that were useless.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 10 ++--------
- .../vc04_services/bcm2835-audio/bcm2835-vchiq.c | 4 ++--
- .../staging/vc04_services/bcm2835-audio/bcm2835.c | 14 +++++++-------
- 3 files changed, 11 insertions(+), 17 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -164,14 +164,11 @@ static int snd_bcm2835_playback_spdif_op
- return snd_bcm2835_playback_open_generic(substream, 1);
- }
-
--/* close callback */
- static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
- {
-- /* the hardware-specific codes will be here */
--
-- struct bcm2835_chip *chip;
-- struct snd_pcm_runtime *runtime;
- struct bcm2835_alsa_stream *alsa_stream;
-+ struct snd_pcm_runtime *runtime;
-+ struct bcm2835_chip *chip;
-
- chip = snd_pcm_substream_chip(substream);
- mutex_lock(&chip->audio_mutex);
-@@ -195,20 +192,17 @@ static int snd_bcm2835_playback_close(st
- return 0;
- }
-
--/* hw_params callback */
- static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
- {
- return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
- }
-
--/* hw_free callback */
- static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
- {
- return snd_pcm_lib_free_pages(substream);
- }
-
--/* prepare callback */
- static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
- {
- struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -94,9 +94,9 @@ static void audio_vchi_callback(void *pa
- void *msg_handle)
- {
- struct bcm2835_audio_instance *instance = param;
-- int status;
-- int msg_len;
- struct vc_audio_msg m;
-+ int msg_len;
-+ int status;
-
- if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
- return;
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -161,8 +161,8 @@ static int snd_add_child_device(struct d
- struct bcm2835_audio_driver *audio_driver,
- u32 numchans)
- {
-- struct snd_card *card;
- struct bcm2835_chip *chip;
-+ struct snd_card *card;
- int err;
-
- err = snd_card_new(dev, -1, NULL, THIS_MODULE, sizeof(*chip), &card);
-@@ -225,12 +225,12 @@ static int snd_add_child_device(struct d
-
- static int snd_add_child_devices(struct device *device, u32 numchans)
- {
-- int i;
-- int count_devices = 0;
-- int minchannels = 0;
-- int extrachannels = 0;
- int extrachannels_per_driver = 0;
- int extrachannels_remainder = 0;
-+ int count_devices = 0;
-+ int extrachannels = 0;
-+ int minchannels = 0;
-+ int i;
-
- for (i = 0; i < ARRAY_SIZE(children_devices); i++)
- if (*children_devices[i].is_enabled)
-@@ -258,9 +258,9 @@ static int snd_add_child_devices(struct
- extrachannels_remainder);
-
- for (i = 0; i < ARRAY_SIZE(children_devices); i++) {
-- int err;
-- int numchannels_this_device;
- struct bcm2835_audio_driver *audio_driver;
-+ int numchannels_this_device;
-+ int err;
-
- if (!*children_devices[i].is_enabled)
- continue;
--- /dev/null
+From b06f01038711efc5182267cfc68e358a89ee2502 Mon Sep 17 00:00:00 2001
+Date: Wed, 17 Oct 2018 21:01:55 +0200
+Subject: [PATCH] staging: bcm2835-audio: rename platform_driver
+ structure
+
+commit 82cdc0c6b6faf877e2aecb957cffa9cb578cc572 upstream.
+
+It was called bcm2835_alsa0_driver, that "0" didn't mean much.
+
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -343,7 +343,7 @@ static const struct of_device_id snd_bcm
+ };
+ MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table);
+
+-static struct platform_driver bcm2835_alsa0_driver = {
++static struct platform_driver bcm2835_alsa_driver = {
+ .probe = snd_bcm2835_alsa_probe,
+ #ifdef CONFIG_PM
+ .suspend = snd_bcm2835_alsa_suspend,
+@@ -359,7 +359,7 @@ static int bcm2835_alsa_device_init(void
+ {
+ int retval;
+
+- retval = platform_driver_register(&bcm2835_alsa0_driver);
++ retval = platform_driver_register(&bcm2835_alsa_driver);
+ if (retval)
+ pr_err("Error registering bcm2835_audio driver %d .\n", retval);
+
+@@ -368,7 +368,7 @@ static int bcm2835_alsa_device_init(void
+
+ static void bcm2835_alsa_device_exit(void)
+ {
+- platform_driver_unregister(&bcm2835_alsa0_driver);
++ platform_driver_unregister(&bcm2835_alsa_driver);
+ }
+
+ late_initcall(bcm2835_alsa_device_init);
+++ /dev/null
-From 23b89436030e64196a1bc317901d08edd54fb772 Mon Sep 17 00:00:00 2001
-Date: Wed, 17 Oct 2018 21:01:53 +0200
-Subject: [PATCH] staging: bcm2835-audio: use anonymous union in struct
- vc_audio_msg
-
-commit 9c2eaf7da855d314a369d48b9cbf8ac80717a1d0 upstream.
-
-In this case explicitly naming the union doesn't help overall code
-comprehension and clutters it.
-
----
- .../bcm2835-audio/bcm2835-vchiq.c | 30 +++++++++----------
- .../bcm2835-audio/vc_vchi_audioserv_defs.h | 2 +-
- 2 files changed, 16 insertions(+), 16 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -104,15 +104,15 @@ static void audio_vchi_callback(void *pa
- status = vchi_msg_dequeue(instance->vchi_handle,
- &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
- if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
-- instance->result = m.u.result.success;
-+ instance->result = m.result.success;
- complete(&instance->msg_avail_comp);
- } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
-- if (m.u.complete.cookie1 != VC_AUDIO_WRITE_COOKIE1 ||
-- m.u.complete.cookie2 != VC_AUDIO_WRITE_COOKIE2)
-+ if (m.complete.cookie1 != VC_AUDIO_WRITE_COOKIE1 ||
-+ m.complete.cookie2 != VC_AUDIO_WRITE_COOKIE2)
- dev_err(instance->dev, "invalid cookie\n");
- else
- bcm2835_playback_fifo(instance->alsa_stream,
-- m.u.complete.count);
-+ m.complete.count);
- } else {
- dev_err(instance->dev, "unexpected callback type=%d\n", m.type);
- }
-@@ -257,11 +257,11 @@ int bcm2835_audio_set_ctls(struct bcm283
- struct vc_audio_msg m = {};
-
- m.type = VC_AUDIO_MSG_TYPE_CONTROL;
-- m.u.control.dest = chip->dest;
-+ m.control.dest = chip->dest;
- if (!chip->mute)
-- m.u.control.volume = CHIP_MIN_VOLUME;
-+ m.control.volume = CHIP_MIN_VOLUME;
- else
-- m.u.control.volume = alsa2chip(chip->volume);
-+ m.control.volume = alsa2chip(chip->volume);
-
- return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
- }
-@@ -272,9 +272,9 @@ int bcm2835_audio_set_params(struct bcm2
- {
- struct vc_audio_msg m = {
- .type = VC_AUDIO_MSG_TYPE_CONFIG,
-- .u.config.channels = channels,
-- .u.config.samplerate = samplerate,
-- .u.config.bps = bps,
-+ .config.channels = channels,
-+ .config.samplerate = samplerate,
-+ .config.bps = bps,
- };
- int err;
-
-@@ -302,7 +302,7 @@ int bcm2835_audio_drain(struct bcm2835_a
- {
- struct vc_audio_msg m = {
- .type = VC_AUDIO_MSG_TYPE_STOP,
-- .u.stop.draining = 1,
-+ .stop.draining = 1,
- };
-
- return bcm2835_audio_send_msg(alsa_stream->instance, &m, false);
-@@ -330,10 +330,10 @@ int bcm2835_audio_write(struct bcm2835_a
- struct bcm2835_audio_instance *instance = alsa_stream->instance;
- struct vc_audio_msg m = {
- .type = VC_AUDIO_MSG_TYPE_WRITE,
-- .u.write.count = size,
-- .u.write.max_packet = instance->max_packet,
-- .u.write.cookie1 = VC_AUDIO_WRITE_COOKIE1,
-- .u.write.cookie2 = VC_AUDIO_WRITE_COOKIE2,
-+ .write.count = size,
-+ .write.max_packet = instance->max_packet,
-+ .write.cookie1 = VC_AUDIO_WRITE_COOKIE1,
-+ .write.cookie2 = VC_AUDIO_WRITE_COOKIE2,
- };
- unsigned int count;
- int err, status;
---- a/drivers/staging/vc04_services/bcm2835-audio/vc_vchi_audioserv_defs.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/vc_vchi_audioserv_defs.h
-@@ -93,7 +93,7 @@ struct vc_audio_msg {
- struct vc_audio_write write;
- struct vc_audio_result result;
- struct vc_audio_complete complete;
-- } u;
-+ };
- };
-
- #endif /* _VC_AUDIO_DEFS_H_ */
+++ /dev/null
-From 0b7d959b0d0c18959c66696844a1c9956370ab99 Mon Sep 17 00:00:00 2001
-Date: Wed, 17 Oct 2018 21:01:54 +0200
-Subject: [PATCH] staging: bcm2835-audio: more generic probe function
- name
-
-commit 96f3bd8ae6516898c7b411ecb87064bb0dd25415 upstream.
-
-There will only be one probe function, there is no use for appendig
-"_dt" the end of the name.
-
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -291,7 +291,7 @@ static int snd_add_child_devices(struct
- return 0;
- }
-
--static int snd_bcm2835_alsa_probe_dt(struct platform_device *pdev)
-+static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- u32 numchans;
-@@ -344,7 +344,7 @@ static const struct of_device_id snd_bcm
- MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table);
-
- static struct platform_driver bcm2835_alsa0_driver = {
-- .probe = snd_bcm2835_alsa_probe_dt,
-+ .probe = snd_bcm2835_alsa_probe,
- #ifdef CONFIG_PM
- .suspend = snd_bcm2835_alsa_suspend,
- .resume = snd_bcm2835_alsa_resume,
--- /dev/null
+From 56b704581afbd8d9ccd73cfa7935b6178749a3e9 Mon Sep 17 00:00:00 2001
+Date: Wed, 17 Oct 2018 21:01:56 +0200
+Subject: [PATCH] staging: bcm2835-audio: update TODO
+
+commit 01ec7398c56e8f1b903ecb3c5c75400e263eef43 upstream.
+
+The following tasks were completed or not the right solution:
+
+1/2- Not the proper solution, we should register a platform device in
+vchiq the same way it's done with bcm2835-camera as commented here:
+https://lkml.org/lkml/2018/10/16/1131
+
+2/3- Fixed by Takashi Iwai here: https://lkml.org/lkml/2018/9/4/587
+
+Also, adds a new task as per mailing list conversation.
+
+---
+ .../staging/vc04_services/bcm2835-audio/TODO | 25 +++----------------
+ 1 file changed, 3 insertions(+), 22 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/TODO
++++ b/drivers/staging/vc04_services/bcm2835-audio/TODO
+@@ -4,26 +4,7 @@
+ * *
+ *****************************************************************************
+
++1) Revisit multi-cards options and PCM route mixer control (as per comment
++https://lkml.org/lkml/2018/9/8/200)
+
+-1) Document the device tree node
+-
+-The downstream tree(the tree that the driver was imported from) at
+-http://www.github.com/raspberrypi/linux uses this node:
+-
+-audio: audio {
+- compatible = "brcm,bcm2835-audio";
+- brcm,pwm-channels = <8>;
+-};
+-
+-Since the driver requires the use of VCHIQ, it may be useful to have a link
+-in the device tree to the VCHIQ driver.
+-
+-2) Gracefully handle the case where VCHIQ is missing from the device tree or
+-it has not been initialized yet.
+-
+-3) Review error handling and remove duplicate code.
+-
+-4) Cleanup the logging mechanism. The driver should probably be using the
+-standard kernel logging mechanisms such as dev_info, dev_dbg, and friends.
+-
+-5) Fix the remaining checkpatch.pl errors and warnings.
++2) Fix the remaining checkpatch.pl errors and warnings.
--- /dev/null
+From 2ba82d9516203ce41f33e98adb667bedee3622bc Mon Sep 17 00:00:00 2001
+Date: Mon, 22 Oct 2018 20:17:08 +0100
+Subject: [PATCH] staging: bcm2835-audio: interpolate audio delay
+
+commit a105a3a72824e0ac685a0711a67e4dbe29de62d0 upstream.
+
+When the BCM2835 audio output is used, userspace sees a jitter up to 10ms
+in the audio position, aka "delay" -- the number of frames that must
+be output before a new frame would be played.
+Make this a bit nicer for userspace by interpolating the position
+using the CPU clock.
+The overhead is small -- an extra ktime_get() every time a GPU message
+is sent -- and another call and a few calculations whenever the delay
+is sought from userland.
+At 48,000 frames per second, i.e. approximately 20 microseconds per
+frame, it would take a clock inaccuracy of
+20 microseconds in 10 milliseconds -- 2,000 parts per million --
+to result in an inaccurate estimate, whereas
+crystal- or resonator-based clocks typically have an
+inaccuracy of 10s to 100s of parts per million.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 20 +++++++++++++++++++
+ .../vc04_services/bcm2835-audio/bcm2835.h | 1 +
+ 2 files changed, 21 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -74,6 +74,7 @@ void bcm2835_playback_fifo(struct bcm283
+ atomic_set(&alsa_stream->pos, pos);
+
+ alsa_stream->period_offset += bytes;
++ alsa_stream->interpolate_start = ktime_get();
+ if (alsa_stream->period_offset >= alsa_stream->period_size) {
+ alsa_stream->period_offset %= alsa_stream->period_size;
+ snd_pcm_period_elapsed(substream);
+@@ -237,6 +238,7 @@ static int snd_bcm2835_pcm_prepare(struc
+ atomic_set(&alsa_stream->pos, 0);
+ alsa_stream->period_offset = 0;
+ alsa_stream->draining = false;
++ alsa_stream->interpolate_start = ktime_get();
+
+ return 0;
+ }
+@@ -286,6 +288,24 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
+ {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
++ ktime_t now = ktime_get();
++
++ /* Give userspace better delay reporting by interpolating between GPU
++ * notifications, assuming audio speed is close enough to the clock
++ * used for ktime
++ */
++
++ if ((ktime_to_ns(alsa_stream->interpolate_start)) &&
++ (ktime_compare(alsa_stream->interpolate_start, now) < 0)) {
++ u64 interval =
++ (ktime_to_ns(ktime_sub(now,
++ alsa_stream->interpolate_start)));
++ u64 frames_output_in_interval =
++ div_u64((interval * runtime->rate), 1000000000);
++ snd_pcm_sframes_t frames_output_in_interval_sized =
++ -frames_output_in_interval;
++ runtime->delay = frames_output_in_interval_sized;
++ }
+
+ return snd_pcm_indirect_playback_pointer(substream,
+ &alsa_stream->pcm_indirect,
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -78,6 +78,7 @@ struct bcm2835_alsa_stream {
+ unsigned int period_offset;
+ unsigned int buffer_size;
+ unsigned int period_size;
++ ktime_t interpolate_start;
+
+ struct bcm2835_audio_instance *instance;
+ int idx;
+++ /dev/null
-From b06f01038711efc5182267cfc68e358a89ee2502 Mon Sep 17 00:00:00 2001
-Date: Wed, 17 Oct 2018 21:01:55 +0200
-Subject: [PATCH] staging: bcm2835-audio: rename platform_driver
- structure
-
-commit 82cdc0c6b6faf877e2aecb957cffa9cb578cc572 upstream.
-
-It was called bcm2835_alsa0_driver, that "0" didn't mean much.
-
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -343,7 +343,7 @@ static const struct of_device_id snd_bcm
- };
- MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table);
-
--static struct platform_driver bcm2835_alsa0_driver = {
-+static struct platform_driver bcm2835_alsa_driver = {
- .probe = snd_bcm2835_alsa_probe,
- #ifdef CONFIG_PM
- .suspend = snd_bcm2835_alsa_suspend,
-@@ -359,7 +359,7 @@ static int bcm2835_alsa_device_init(void
- {
- int retval;
-
-- retval = platform_driver_register(&bcm2835_alsa0_driver);
-+ retval = platform_driver_register(&bcm2835_alsa_driver);
- if (retval)
- pr_err("Error registering bcm2835_audio driver %d .\n", retval);
-
-@@ -368,7 +368,7 @@ static int bcm2835_alsa_device_init(void
-
- static void bcm2835_alsa_device_exit(void)
- {
-- platform_driver_unregister(&bcm2835_alsa0_driver);
-+ platform_driver_unregister(&bcm2835_alsa_driver);
- }
-
- late_initcall(bcm2835_alsa_device_init);
--- /dev/null
+From b338fbb56955b74b5f41a623aceab4d74ba7c173 Mon Sep 17 00:00:00 2001
+Date: Thu, 6 Dec 2018 19:28:56 +0100
+Subject: [PATCH] staging: bcm2835-audio: Enable compile test
+
+commit 458d4866a34d0c129ffc3bd56345b2166ba46d77 upstream.
+
+Enable the compilation test for bcm2835-audio to gain more build coverage.
+
+---
+ drivers/staging/vc04_services/bcm2835-audio/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/Kconfig
++++ b/drivers/staging/vc04_services/bcm2835-audio/Kconfig
+@@ -1,6 +1,6 @@
+ config SND_BCM2835
+ tristate "BCM2835 Audio"
+- depends on ARCH_BCM2835 && SND
++ depends on (ARCH_BCM2835 || COMPILE_TEST) && SND
+ select SND_PCM
+ select BCM2835_VCHIQ
+ help
+++ /dev/null
-From 56b704581afbd8d9ccd73cfa7935b6178749a3e9 Mon Sep 17 00:00:00 2001
-Date: Wed, 17 Oct 2018 21:01:56 +0200
-Subject: [PATCH] staging: bcm2835-audio: update TODO
-
-commit 01ec7398c56e8f1b903ecb3c5c75400e263eef43 upstream.
-
-The following tasks were completed or not the right solution:
-
-1/2- Not the proper solution, we should register a platform device in
-vchiq the same way it's done with bcm2835-camera as commented here:
-https://lkml.org/lkml/2018/10/16/1131
-
-2/3- Fixed by Takashi Iwai here: https://lkml.org/lkml/2018/9/4/587
-
-Also, adds a new task as per mailing list conversation.
-
----
- .../staging/vc04_services/bcm2835-audio/TODO | 25 +++----------------
- 1 file changed, 3 insertions(+), 22 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/TODO
-+++ b/drivers/staging/vc04_services/bcm2835-audio/TODO
-@@ -4,26 +4,7 @@
- * *
- *****************************************************************************
-
-+1) Revisit multi-cards options and PCM route mixer control (as per comment
-+https://lkml.org/lkml/2018/9/8/200)
-
--1) Document the device tree node
--
--The downstream tree(the tree that the driver was imported from) at
--http://www.github.com/raspberrypi/linux uses this node:
--
--audio: audio {
-- compatible = "brcm,bcm2835-audio";
-- brcm,pwm-channels = <8>;
--};
--
--Since the driver requires the use of VCHIQ, it may be useful to have a link
--in the device tree to the VCHIQ driver.
--
--2) Gracefully handle the case where VCHIQ is missing from the device tree or
--it has not been initialized yet.
--
--3) Review error handling and remove duplicate code.
--
--4) Cleanup the logging mechanism. The driver should probably be using the
--standard kernel logging mechanisms such as dev_info, dev_dbg, and friends.
--
--5) Fix the remaining checkpatch.pl errors and warnings.
-+2) Fix the remaining checkpatch.pl errors and warnings.
+++ /dev/null
-From 2ba82d9516203ce41f33e98adb667bedee3622bc Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Oct 2018 20:17:08 +0100
-Subject: [PATCH] staging: bcm2835-audio: interpolate audio delay
-
-commit a105a3a72824e0ac685a0711a67e4dbe29de62d0 upstream.
-
-When the BCM2835 audio output is used, userspace sees a jitter up to 10ms
-in the audio position, aka "delay" -- the number of frames that must
-be output before a new frame would be played.
-Make this a bit nicer for userspace by interpolating the position
-using the CPU clock.
-The overhead is small -- an extra ktime_get() every time a GPU message
-is sent -- and another call and a few calculations whenever the delay
-is sought from userland.
-At 48,000 frames per second, i.e. approximately 20 microseconds per
-frame, it would take a clock inaccuracy of
-20 microseconds in 10 milliseconds -- 2,000 parts per million --
-to result in an inaccurate estimate, whereas
-crystal- or resonator-based clocks typically have an
-inaccuracy of 10s to 100s of parts per million.
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 20 +++++++++++++++++++
- .../vc04_services/bcm2835-audio/bcm2835.h | 1 +
- 2 files changed, 21 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -74,6 +74,7 @@ void bcm2835_playback_fifo(struct bcm283
- atomic_set(&alsa_stream->pos, pos);
-
- alsa_stream->period_offset += bytes;
-+ alsa_stream->interpolate_start = ktime_get();
- if (alsa_stream->period_offset >= alsa_stream->period_size) {
- alsa_stream->period_offset %= alsa_stream->period_size;
- snd_pcm_period_elapsed(substream);
-@@ -237,6 +238,7 @@ static int snd_bcm2835_pcm_prepare(struc
- atomic_set(&alsa_stream->pos, 0);
- alsa_stream->period_offset = 0;
- alsa_stream->draining = false;
-+ alsa_stream->interpolate_start = ktime_get();
-
- return 0;
- }
-@@ -286,6 +288,24 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
- {
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
-+ ktime_t now = ktime_get();
-+
-+ /* Give userspace better delay reporting by interpolating between GPU
-+ * notifications, assuming audio speed is close enough to the clock
-+ * used for ktime
-+ */
-+
-+ if ((ktime_to_ns(alsa_stream->interpolate_start)) &&
-+ (ktime_compare(alsa_stream->interpolate_start, now) < 0)) {
-+ u64 interval =
-+ (ktime_to_ns(ktime_sub(now,
-+ alsa_stream->interpolate_start)));
-+ u64 frames_output_in_interval =
-+ div_u64((interval * runtime->rate), 1000000000);
-+ snd_pcm_sframes_t frames_output_in_interval_sized =
-+ -frames_output_in_interval;
-+ runtime->delay = frames_output_in_interval_sized;
-+ }
-
- return snd_pcm_indirect_playback_pointer(substream,
- &alsa_stream->pcm_indirect,
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -78,6 +78,7 @@ struct bcm2835_alsa_stream {
- unsigned int period_offset;
- unsigned int buffer_size;
- unsigned int period_size;
-+ ktime_t interpolate_start;
-
- struct bcm2835_audio_instance *instance;
- int idx;
--- /dev/null
+From 72c059360457babd76009697e652c96cb282856e Mon Sep 17 00:00:00 2001
+Date: Thu, 6 Dec 2018 19:28:57 +0100
+Subject: [PATCH] staging: bcm2835-audio: use module_platform_driver()
+ macro
+
+commit 1e55d56344b0777d6cee9b9e4a813d53728ee798 upstream.
+
+There is not much value behind this boilerplate, so use
+module_platform_driver() instead.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835.c | 20 +------------------
+ 1 file changed, 1 insertion(+), 19 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -354,25 +354,7 @@ static struct platform_driver bcm2835_al
+ .of_match_table = snd_bcm2835_of_match_table,
+ },
+ };
+-
+-static int bcm2835_alsa_device_init(void)
+-{
+- int retval;
+-
+- retval = platform_driver_register(&bcm2835_alsa_driver);
+- if (retval)
+- pr_err("Error registering bcm2835_audio driver %d .\n", retval);
+-
+- return retval;
+-}
+-
+-static void bcm2835_alsa_device_exit(void)
+-{
+- platform_driver_unregister(&bcm2835_alsa_driver);
+-}
+-
+-late_initcall(bcm2835_alsa_device_init);
+-module_exit(bcm2835_alsa_device_exit);
++module_platform_driver(bcm2835_alsa_driver);
+
+ MODULE_AUTHOR("Dom Cobley");
+ MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
+++ /dev/null
-From b338fbb56955b74b5f41a623aceab4d74ba7c173 Mon Sep 17 00:00:00 2001
-Date: Thu, 6 Dec 2018 19:28:56 +0100
-Subject: [PATCH] staging: bcm2835-audio: Enable compile test
-
-commit 458d4866a34d0c129ffc3bd56345b2166ba46d77 upstream.
-
-Enable the compilation test for bcm2835-audio to gain more build coverage.
-
----
- drivers/staging/vc04_services/bcm2835-audio/Kconfig | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/Kconfig
-+++ b/drivers/staging/vc04_services/bcm2835-audio/Kconfig
-@@ -1,6 +1,6 @@
- config SND_BCM2835
- tristate "BCM2835 Audio"
-- depends on ARCH_BCM2835 && SND
-+ depends on (ARCH_BCM2835 || COMPILE_TEST) && SND
- select SND_PCM
- select BCM2835_VCHIQ
- help
--- /dev/null
+From 360a1982333c8e8f583663155479115d6eb7cd14 Mon Sep 17 00:00:00 2001
+Date: Mon, 17 Dec 2018 10:08:54 +0300
+Subject: [PATCH] staging: bcm2835-audio: double free in init error
+ path
+
+commit 136ff5e49271c4c8fceeca5491c48e66b961564b upstream.
+
+We free instance here and in the caller. It should be only the caller
+which handles it.
+
+Fixes: d7ca3a71545b ("staging: bcm2835-audio: Operate non-atomic PCM ops")
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -145,7 +145,6 @@ vc_vchi_audio_init(VCHI_INSTANCE_T vchi_
+ dev_err(instance->dev,
+ "failed to open VCHI service connection (status=%d)\n",
+ status);
+- kfree(instance);
+ return -EPERM;
+ }
+
--- /dev/null
+From e13c663bfc75a628ba25afdf3f3b4a40a2c0250e Mon Sep 17 00:00:00 2001
+Date: Wed, 1 May 2019 15:00:05 +0100
+Subject: [PATCH] dts: Increase default coherent pool size
+
+dwc_otg allocates DMA-coherent buffers in atomic context for misaligned
+transfer buffers. The pool that these allocations come from is set up
+at boot-time but can be overridden by a commandline parameter -
+increase this for now to prevent failures seen on 4.19 with multiple
+USB Ethernet devices.
+
+see: https://github.com/raspberrypi/linux/issues/2924
+---
+ arch/arm/boot/dts/bcm270x.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm270x.dtsi
++++ b/arch/arm/boot/dts/bcm270x.dtsi
+@@ -3,7 +3,7 @@
+
+ / {
+ chosen {
+- bootargs = "";
++ bootargs = "coherent_pool=1M";
+ /delete-property/ stdout-path;
+ };
+
+++ /dev/null
-From 72c059360457babd76009697e652c96cb282856e Mon Sep 17 00:00:00 2001
-Date: Thu, 6 Dec 2018 19:28:57 +0100
-Subject: [PATCH] staging: bcm2835-audio: use module_platform_driver()
- macro
-
-commit 1e55d56344b0777d6cee9b9e4a813d53728ee798 upstream.
-
-There is not much value behind this boilerplate, so use
-module_platform_driver() instead.
-
----
- .../vc04_services/bcm2835-audio/bcm2835.c | 20 +------------------
- 1 file changed, 1 insertion(+), 19 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -354,25 +354,7 @@ static struct platform_driver bcm2835_al
- .of_match_table = snd_bcm2835_of_match_table,
- },
- };
--
--static int bcm2835_alsa_device_init(void)
--{
-- int retval;
--
-- retval = platform_driver_register(&bcm2835_alsa_driver);
-- if (retval)
-- pr_err("Error registering bcm2835_audio driver %d .\n", retval);
--
-- return retval;
--}
--
--static void bcm2835_alsa_device_exit(void)
--{
-- platform_driver_unregister(&bcm2835_alsa_driver);
--}
--
--late_initcall(bcm2835_alsa_device_init);
--module_exit(bcm2835_alsa_device_exit);
-+module_platform_driver(bcm2835_alsa_driver);
-
- MODULE_AUTHOR("Dom Cobley");
- MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
--- /dev/null
+From fdbe849f960ee92befd781cff14d9b76142b0981 Mon Sep 17 00:00:00 2001
+Date: Thu, 2 May 2019 11:53:45 +0100
+Subject: [PATCH] lan78xx: use default alignment for rx buffers
+
+The lan78xx uses a 12-byte hardware rx header, so there is no need
+to allocate SKBs with NET_IP_ALIGN set. Removes alignment faults
+in both dwc_otg and in ipv6 processing.
+---
+ drivers/net/usb/lan78xx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/usb/lan78xx.c
++++ b/drivers/net/usb/lan78xx.c
+@@ -3257,7 +3257,7 @@ static int rx_submit(struct lan78xx_net
+ size_t size = dev->rx_urb_size;
+ int ret = 0;
+
+- skb = netdev_alloc_skb_ip_align(dev->net, size);
++ skb = netdev_alloc_skb(dev->net, size);
+ if (!skb) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+++ /dev/null
-From 360a1982333c8e8f583663155479115d6eb7cd14 Mon Sep 17 00:00:00 2001
-Date: Mon, 17 Dec 2018 10:08:54 +0300
-Subject: [PATCH] staging: bcm2835-audio: double free in init error
- path
-
-commit 136ff5e49271c4c8fceeca5491c48e66b961564b upstream.
-
-We free instance here and in the caller. It should be only the caller
-which handles it.
-
-Fixes: d7ca3a71545b ("staging: bcm2835-audio: Operate non-atomic PCM ops")
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -145,7 +145,6 @@ vc_vchi_audio_init(VCHI_INSTANCE_T vchi_
- dev_err(instance->dev,
- "failed to open VCHI service connection (status=%d)\n",
- status);
-- kfree(instance);
- return -EPERM;
- }
-
+++ /dev/null
-From e13c663bfc75a628ba25afdf3f3b4a40a2c0250e Mon Sep 17 00:00:00 2001
-Date: Wed, 1 May 2019 15:00:05 +0100
-Subject: [PATCH] dts: Increase default coherent pool size
-
-dwc_otg allocates DMA-coherent buffers in atomic context for misaligned
-transfer buffers. The pool that these allocations come from is set up
-at boot-time but can be overridden by a commandline parameter -
-increase this for now to prevent failures seen on 4.19 with multiple
-USB Ethernet devices.
-
-see: https://github.com/raspberrypi/linux/issues/2924
----
- arch/arm/boot/dts/bcm270x.dtsi | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm270x.dtsi
-+++ b/arch/arm/boot/dts/bcm270x.dtsi
-@@ -3,7 +3,7 @@
-
- / {
- chosen {
-- bootargs = "";
-+ bootargs = "coherent_pool=1M";
- /delete-property/ stdout-path;
- };
-
--- /dev/null
+From 453caa19909edf2de1add80b369fb30570a440ed Mon Sep 17 00:00:00 2001
+Date: Thu, 2 May 2019 14:30:24 +0100
+Subject: [PATCH] staging: bcm2835-codec: Correct port width calc for
+ truncation
+
+The calculation converting from V4L2 bytesperline to MMAL
+width had an operator ordering issue that lead to Bayer raw 10
+(and 12 and 14) setting an incorrect stride for the buffer.
+Correct this operation ordering issue.
+
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -605,8 +605,8 @@ static void setup_mmal_port_format(struc
+
+ if (!(q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) {
+ /* Raw image format - set width/height */
+- port->es.video.width = q_data->bytesperline /
+- (q_data->fmt->depth >> 3);
++ port->es.video.width = (q_data->bytesperline << 3) /
++ q_data->fmt->depth;
+ port->es.video.height = q_data->height;
+ port->es.video.crop.width = q_data->crop_width;
+ port->es.video.crop.height = q_data->crop_height;
+++ /dev/null
-From fdbe849f960ee92befd781cff14d9b76142b0981 Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2019 11:53:45 +0100
-Subject: [PATCH] lan78xx: use default alignment for rx buffers
-
-The lan78xx uses a 12-byte hardware rx header, so there is no need
-to allocate SKBs with NET_IP_ALIGN set. Removes alignment faults
-in both dwc_otg and in ipv6 processing.
----
- drivers/net/usb/lan78xx.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/usb/lan78xx.c
-+++ b/drivers/net/usb/lan78xx.c
-@@ -3257,7 +3257,7 @@ static int rx_submit(struct lan78xx_net
- size_t size = dev->rx_urb_size;
- int ret = 0;
-
-- skb = netdev_alloc_skb_ip_align(dev->net, size);
-+ skb = netdev_alloc_skb(dev->net, size);
- if (!skb) {
- usb_free_urb(urb);
- return -ENOMEM;
--- /dev/null
+From 52e50b0f5017e823428849c42c1029306d790939 Mon Sep 17 00:00:00 2001
+Date: Thu, 2 May 2019 14:32:21 +0100
+Subject: [PATCH] staging: bcm2835-codec: Remove height padding for ISP
+ role
+
+The ISP has no need for heights to be a multiple of macroblock
+sizes, therefore doesn't require the align on the height.
+Remove it for the ISP role. (It is required for the codecs).
+
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1015,7 +1015,8 @@ static int vidioc_g_fmt_vid_cap(struct f
+ return vidioc_g_fmt(file2ctx(file), f);
+ }
+
+-static int vidioc_try_fmt(struct v4l2_format *f, struct bcm2835_codec_fmt *fmt)
++static int vidioc_try_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
++ struct bcm2835_codec_fmt *fmt)
+ {
+ /*
+ * The V4L2 specification requires the driver to correct the format
+@@ -1034,11 +1035,13 @@ static int vidioc_try_fmt(struct v4l2_fo
+ f->fmt.pix.height = MIN_H;
+
+ /*
+- * Buffer must have a vertical alignment of 16 lines.
++ * For codecs the buffer must have a vertical alignment of 16
++ * lines.
+ * The selection will reflect any cropping rectangle when only
+ * some of the pixels are active.
+ */
+- f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
++ if (ctx->dev->role != ISP)
++ f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
+ }
+ f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
+ fmt);
+@@ -1065,7 +1068,7 @@ static int vidioc_try_fmt_vid_cap(struct
+ fmt = find_format(f, ctx->dev, true);
+ }
+
+- return vidioc_try_fmt(f, fmt);
++ return vidioc_try_fmt(ctx, f, fmt);
+ }
+
+ static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+@@ -1084,7 +1087,7 @@ static int vidioc_try_fmt_vid_out(struct
+ if (!f->fmt.pix.colorspace)
+ f->fmt.pix.colorspace = ctx->colorspace;
+
+- return vidioc_try_fmt(f, fmt);
++ return vidioc_try_fmt(ctx, f, fmt);
+ }
+
+ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
+++ /dev/null
-From 453caa19909edf2de1add80b369fb30570a440ed Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2019 14:30:24 +0100
-Subject: [PATCH] staging: bcm2835-codec: Correct port width calc for
- truncation
-
-The calculation converting from V4L2 bytesperline to MMAL
-width had an operator ordering issue that lead to Bayer raw 10
-(and 12 and 14) setting an incorrect stride for the buffer.
-Correct this operation ordering issue.
-
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -605,8 +605,8 @@ static void setup_mmal_port_format(struc
-
- if (!(q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) {
- /* Raw image format - set width/height */
-- port->es.video.width = q_data->bytesperline /
-- (q_data->fmt->depth >> 3);
-+ port->es.video.width = (q_data->bytesperline << 3) /
-+ q_data->fmt->depth;
- port->es.video.height = q_data->height;
- port->es.video.crop.width = q_data->crop_width;
- port->es.video.crop.height = q_data->crop_height;
--- /dev/null
+From 6737574b4d3af54a56d2f9c49f516fb75d06a556 Mon Sep 17 00:00:00 2001
+Date: Wed, 1 May 2019 13:27:23 +0100
+Subject: [PATCH] staging: mmal-vchiq: Free the event context for
+ control ports
+
+vchiq_mmal_component_init calls init_event_context for the
+control port, but vchiq_mmal_component_finalise didn't free
+it, causing a memory leak..
+
+Add the free call.
+
+---
+ drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -1982,6 +1982,8 @@ int vchiq_mmal_component_finalise(struct
+ for (idx = 0; idx < component->clocks; idx++)
+ free_event_context(&component->clock[idx]);
+
++ free_event_context(&component->control);
++
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
--- /dev/null
+From f9c0f8057ffee5c039fe20c3e2dcd7fea70222e9 Mon Sep 17 00:00:00 2001
+Date: Thu, 2 May 2019 22:14:34 +0100
+Subject: [PATCH] BCM270X_DT: Also set coherent_pool=1M for BT Pis
+
+See: https://github.com/raspberrypi/linux/issues/2924
+
+---
+ arch/arm/boot/dts/bcm2708-rpi-0-w.dts | 2 +-
+ arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 2 +-
+ arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
+@@ -8,7 +8,7 @@
+ model = "Raspberry Pi Zero W";
+
+ chosen {
+- bootargs = "8250.nr_uarts=1";
++ bootargs = "coherent_pool=1M 8250.nr_uarts=1";
+ };
+
+ aliases {
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
+@@ -9,7 +9,7 @@
+ model = "Raspberry Pi 3 Model B+";
+
+ chosen {
+- bootargs = "8250.nr_uarts=1";
++ bootargs = "coherent_pool=1M 8250.nr_uarts=1";
+ };
+
+ aliases {
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
+@@ -9,7 +9,7 @@
+ model = "Raspberry Pi 3 Model B";
+
+ chosen {
+- bootargs = "8250.nr_uarts=1";
++ bootargs = "coherent_pool=1M 8250.nr_uarts=1";
+ };
+
+ aliases {
+++ /dev/null
-From 52e50b0f5017e823428849c42c1029306d790939 Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2019 14:32:21 +0100
-Subject: [PATCH] staging: bcm2835-codec: Remove height padding for ISP
- role
-
-The ISP has no need for heights to be a multiple of macroblock
-sizes, therefore doesn't require the align on the height.
-Remove it for the ISP role. (It is required for the codecs).
-
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 13 ++++++++-----
- 1 file changed, 8 insertions(+), 5 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1015,7 +1015,8 @@ static int vidioc_g_fmt_vid_cap(struct f
- return vidioc_g_fmt(file2ctx(file), f);
- }
-
--static int vidioc_try_fmt(struct v4l2_format *f, struct bcm2835_codec_fmt *fmt)
-+static int vidioc_try_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
-+ struct bcm2835_codec_fmt *fmt)
- {
- /*
- * The V4L2 specification requires the driver to correct the format
-@@ -1034,11 +1035,13 @@ static int vidioc_try_fmt(struct v4l2_fo
- f->fmt.pix.height = MIN_H;
-
- /*
-- * Buffer must have a vertical alignment of 16 lines.
-+ * For codecs the buffer must have a vertical alignment of 16
-+ * lines.
- * The selection will reflect any cropping rectangle when only
- * some of the pixels are active.
- */
-- f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
-+ if (ctx->dev->role != ISP)
-+ f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
- }
- f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
- fmt);
-@@ -1065,7 +1068,7 @@ static int vidioc_try_fmt_vid_cap(struct
- fmt = find_format(f, ctx->dev, true);
- }
-
-- return vidioc_try_fmt(f, fmt);
-+ return vidioc_try_fmt(ctx, f, fmt);
- }
-
- static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
-@@ -1084,7 +1087,7 @@ static int vidioc_try_fmt_vid_out(struct
- if (!f->fmt.pix.colorspace)
- f->fmt.pix.colorspace = ctx->colorspace;
-
-- return vidioc_try_fmt(f, fmt);
-+ return vidioc_try_fmt(ctx, f, fmt);
- }
-
- static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f,
--- /dev/null
+From 50d3f15ea5d6ca2705a009722dd7d4108c9f75d9 Mon Sep 17 00:00:00 2001
+Date: Sun, 5 May 2019 21:07:12 +0100
+Subject: [PATCH] arm: dts: overlays: rpi-sense: add upstream humidity
+ compatible
+
+The upstream humidiity driver uses "st,hts221" for the compatible
+string so add that in as well so it will work with an unmodified
+upstream kernel driver. We leave the downstream as the priority.
+
+---
+ arch/arm/boot/dts/overlays/rpi-sense-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
+@@ -38,7 +38,7 @@
+ };
+
+ hts221-humid@5f {
+- compatible = "st,hts221-humid";
++ compatible = "st,hts221-humid", "st,hts221";
+ reg = <0x5f>;
+ status = "okay";
+ };
+++ /dev/null
-From 6737574b4d3af54a56d2f9c49f516fb75d06a556 Mon Sep 17 00:00:00 2001
-Date: Wed, 1 May 2019 13:27:23 +0100
-Subject: [PATCH] staging: mmal-vchiq: Free the event context for
- control ports
-
-vchiq_mmal_component_init calls init_event_context for the
-control port, but vchiq_mmal_component_finalise didn't free
-it, causing a memory leak..
-
-Add the free call.
-
----
- drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -1982,6 +1982,8 @@ int vchiq_mmal_component_finalise(struct
- for (idx = 0; idx < component->clocks; idx++)
- free_event_context(&component->clock[idx]);
-
-+ free_event_context(&component->control);
-+
- mutex_unlock(&instance->vchiq_mutex);
-
- return ret;
+++ /dev/null
-From f9c0f8057ffee5c039fe20c3e2dcd7fea70222e9 Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2019 22:14:34 +0100
-Subject: [PATCH] BCM270X_DT: Also set coherent_pool=1M for BT Pis
-
-See: https://github.com/raspberrypi/linux/issues/2924
-
----
- arch/arm/boot/dts/bcm2708-rpi-0-w.dts | 2 +-
- arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 2 +-
- arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 2 +-
- 3 files changed, 3 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
-+++ b/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
-@@ -8,7 +8,7 @@
- model = "Raspberry Pi Zero W";
-
- chosen {
-- bootargs = "8250.nr_uarts=1";
-+ bootargs = "coherent_pool=1M 8250.nr_uarts=1";
- };
-
- aliases {
---- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
-@@ -9,7 +9,7 @@
- model = "Raspberry Pi 3 Model B+";
-
- chosen {
-- bootargs = "8250.nr_uarts=1";
-+ bootargs = "coherent_pool=1M 8250.nr_uarts=1";
- };
-
- aliases {
---- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-@@ -9,7 +9,7 @@
- model = "Raspberry Pi 3 Model B";
-
- chosen {
-- bootargs = "8250.nr_uarts=1";
-+ bootargs = "coherent_pool=1M 8250.nr_uarts=1";
- };
-
- aliases {
--- /dev/null
+From 250db0df9643d122e00313313102c642f1adac72 Mon Sep 17 00:00:00 2001
+Date: Thu, 2 May 2019 15:50:01 +0100
+Subject: [PATCH] staging: mmal-vchiq: Fix memory leak in error path
+
+On error, vchiq_mmal_component_init could leave the
+event context allocated for ports.
+Clean them up in the error path.
+
+---
+ .../vc04_services/vchiq-mmal/mmal-vchiq.c | 27 +++++++++++++------
+ 1 file changed, 19 insertions(+), 8 deletions(-)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -1848,9 +1848,26 @@ static void free_event_context(struct vc
+ {
+ struct mmal_msg_context *ctx = port->event_context;
+
++ if (!ctx)
++ return;
++
+ kfree(ctx->u.bulk.buffer->buffer);
+ kfree(ctx->u.bulk.buffer);
+ release_msg_context(ctx);
++ port->event_context = NULL;
++}
++
++static void release_all_event_contexts(struct vchiq_mmal_component *component)
++{
++ int idx;
++
++ for (idx = 0; idx < component->inputs; idx++)
++ free_event_context(&component->input[idx]);
++ for (idx = 0; idx < component->outputs; idx++)
++ free_event_context(&component->output[idx]);
++ for (idx = 0; idx < component->clocks; idx++)
++ free_event_context(&component->clock[idx]);
++ free_event_context(&component->control);
+ }
+
+ /* Initialise a mmal component and its ports
+@@ -1948,6 +1965,7 @@ int vchiq_mmal_component_init(struct vch
+
+ release_component:
+ destroy_component(instance, component);
++ release_all_event_contexts(component);
+ unlock:
+ if (component)
+ component->in_use = 0;
+@@ -1975,14 +1993,7 @@ int vchiq_mmal_component_finalise(struct
+
+ component->in_use = 0;
+
+- for (idx = 0; idx < component->inputs; idx++)
+- free_event_context(&component->input[idx]);
+- for (idx = 0; idx < component->outputs; idx++)
+- free_event_context(&component->output[idx]);
+- for (idx = 0; idx < component->clocks; idx++)
+- free_event_context(&component->clock[idx]);
+-
+- free_event_context(&component->control);
++ release_all_event_contexts(component);
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+++ /dev/null
-From 50d3f15ea5d6ca2705a009722dd7d4108c9f75d9 Mon Sep 17 00:00:00 2001
-Date: Sun, 5 May 2019 21:07:12 +0100
-Subject: [PATCH] arm: dts: overlays: rpi-sense: add upstream humidity
- compatible
-
-The upstream humidiity driver uses "st,hts221" for the compatible
-string so add that in as well so it will work with an unmodified
-upstream kernel driver. We leave the downstream as the priority.
-
----
- arch/arm/boot/dts/overlays/rpi-sense-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
-@@ -38,7 +38,7 @@
- };
-
- hts221-humid@5f {
-- compatible = "st,hts221-humid";
-+ compatible = "st,hts221-humid", "st,hts221";
- reg = <0x5f>;
- status = "okay";
- };
--- /dev/null
+From 3e246d402582c6f19e5e636f89952d11e18e6442 Mon Sep 17 00:00:00 2001
+Date: Fri, 3 May 2019 13:27:51 +0100
+Subject: [PATCH] staging: vchiq-mmal: Fix memory leak of vchiq
+ instance
+
+The vchiq instance was allocated from vchiq_mmal_init via
+vchi_initialise, but was never released with vchi_disconnect.
+
+Retain the handle and release it from vchiq_mmal_finalise.
+
+---
+ drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+@@ -176,6 +176,7 @@ struct mmal_msg_context {
+ };
+
+ struct vchiq_mmal_instance {
++ VCHI_INSTANCE_T vchi_instance;
+ VCHI_SERVICE_HANDLE_T handle;
+
+ /* ensure serialised access to service */
+@@ -1981,7 +1982,7 @@ EXPORT_SYMBOL_GPL(vchiq_mmal_component_i
+ int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component)
+ {
+- int ret, idx;
++ int ret;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+@@ -2094,6 +2095,8 @@ int vchiq_mmal_finalise(struct vchiq_mma
+
+ idr_destroy(&instance->context_map);
+
++ vchi_disconnect(instance->vchi_instance);
++
+ kfree(instance);
+
+ return status;
+@@ -2105,7 +2108,7 @@ int vchiq_mmal_init(struct vchiq_mmal_in
+ int status;
+ struct vchiq_mmal_instance *instance;
+ static VCHI_CONNECTION_T *vchi_connection;
+- static VCHI_INSTANCE_T vchi_instance;
++ VCHI_INSTANCE_T vchi_instance;
+ SERVICE_CREATION_T params = {
+ .version = VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER),
+ .service_id = VC_MMAL_SERVER_NAME,
+@@ -2151,6 +2154,8 @@ int vchiq_mmal_init(struct vchiq_mmal_in
+ if (!instance)
+ return -ENOMEM;
+
++ instance->vchi_instance = vchi_instance;
++
+ mutex_init(&instance->vchiq_mutex);
+
+ instance->bulk_scratch = vmalloc(PAGE_SIZE);
--- /dev/null
+From 930c49de8674acda0f143f7bc182ed2fad8c4f9d Mon Sep 17 00:00:00 2001
+Date: Mon, 13 May 2019 21:53:05 +0100
+Subject: [PATCH] Added IQaudIO Pi-Codec board support (#2969)
+
+Add support for the IQaudIO Pi-Codec board.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 +
+ .../dts/overlays/iqaudio-codec-overlay.dts | 42 +++
+ sound/soc/bcm/Kconfig | 7 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/iqaudio-codec.c | 250 ++++++++++++++++++
+ 9 files changed, 311 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
+ create mode 100644 sound/soc/bcm/iqaudio-codec.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -68,6 +68,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ i2c1-bcm2708.dtbo \
+ i2s-gpio28-31.dtbo \
+ ilitek251x.dtbo \
++ iqaudio-codec.dtbo \
+ iqaudio-dac.dtbo \
+ iqaudio-dacplus.dtbo \
+ iqaudio-digi-wm8804-audio.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1160,6 +1160,12 @@ Params: interrupt GPIO use
+ touchscreen (in pixels)
+
+
++Name: iqaudio-codec
++Info: Configures the IQaudio Codec audio card
++Load: dtoverlay=iqaudio-codec
++Params: <None>
++
++
+ Name: iqaudio-dac
+ Info: Configures the IQaudio DAC audio card
+ Load: dtoverlay=iqaudio-dac,<param>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
+@@ -0,0 +1,42 @@
++// Definitions for IQaudIO CODEC
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ da2713@1a {
++ #sound-dai-cells = <0>;
++ compatible = "dlg,da7213";
++ reg = <0x1a>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&sound>;
++ iqaudio_dac: __overlay__ {
++ compatible = "iqaudio,iqaudio-codec";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ };
++};
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -108,6 +108,13 @@ config SND_BCM2708_SOC_JUSTBOOM_DIGI
+ help
+ Say Y or M if you want to add support for JustBoom Digi.
+
++config SND_BCM2708_SOC_IQAUDIO_CODEC
++ tristate "Support for IQaudIO-CODEC"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_DA7213
++ help
++ Say Y or M if you want to add support for IQaudIO-CODEC.
++
+ config SND_BCM2708_SOC_IQAUDIO_DAC
+ tristate "Support for IQaudIO-DAC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -18,6 +18,7 @@ snd-soc-hifiberry-dacplusadc-objs := hif
+ snd-soc-justboom-dac-objs := justboom-dac.o
+ snd-soc-rpi-cirrus-objs := rpi-cirrus.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
++snd-soc-iqaudio-codec-objs := iqaudio-codec.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
+ snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o
+ snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
+@@ -42,6 +43,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
+ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
++obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC) += snd-soc-iqaudio-codec.o
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o
+ obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o
+--- /dev/null
++++ b/sound/soc/bcm/iqaudio-codec.c
+@@ -0,0 +1,250 @@
++/*
++ * ASoC Driver for IQaudIO Raspberry Pi Codec board
++ *
++ * (C) Copyright IQaudio Limited, 2017-2019
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/gpio/consumer.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++#include <linux/acpi.h>
++#include <linux/slab.h>
++#include "../codecs/da7213.h"
++
++static int pll_out = DA7213_PLL_FREQ_OUT_90316800;
++
++static int snd_rpi_iqaudio_pll_control(struct snd_soc_dapm_widget *w,
++ struct snd_kcontrol *k, int event)
++{
++ int ret = 0;
++ struct snd_soc_dapm_context *dapm = w->dapm;
++ struct snd_soc_card *card = dapm->card;
++ struct snd_soc_pcm_runtime *rtd =
++ snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++
++ if (SND_SOC_DAPM_EVENT_OFF(event)) {
++ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_MCLK, 0,
++ 0);
++ if (ret)
++ dev_err(card->dev, "Failed to bypass PLL: %d\n", ret);
++ } else if (SND_SOC_DAPM_EVENT_ON(event)) {
++ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0,
++ pll_out);
++ if (ret)
++ dev_err(card->dev, "Failed to enable PLL: %d\n", ret);
++ }
++
++ return ret;
++}
++
++static int snd_rpi_iqaudio_post_dapm_event(struct snd_soc_dapm_widget *w,
++ struct snd_kcontrol *kcontrol,
++ int event)
++{
++ switch (event) {
++ case SND_SOC_DAPM_POST_PMU:
++ /* Delay for mic bias ramp */
++ msleep(1000);
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++static const struct snd_soc_dapm_widget dapm_widgets[] = {
++ SND_SOC_DAPM_HP("HP Jack", NULL),
++ SND_SOC_DAPM_MIC("MIC Jack", NULL),
++ SND_SOC_DAPM_MIC("Onboard MIC", NULL),
++ SND_SOC_DAPM_LINE("AUX Jack", NULL),
++ SND_SOC_DAPM_SUPPLY("PLL Control", SND_SOC_NOPM, 0, 0,
++ snd_rpi_iqaudio_pll_control,
++ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
++ SND_SOC_DAPM_POST("Post Power Up Event", snd_rpi_iqaudio_post_dapm_event),
++};
++
++static const struct snd_soc_dapm_route audio_map[] = {
++ {"HP Jack", NULL, "HPL"},
++ {"HP Jack", NULL, "HPR"},
++ {"HP Jack", NULL, "PLL Control"},
++
++ {"AUX Jack", NULL, "AUXR"},
++ {"AUX Jack", NULL, "AUXL"},
++ {"AUX Jack", NULL, "PLL Control"},
++
++ /* Assume Mic1 is linked to Headset and Mic2 to on-board mic */
++ {"MIC Jack", NULL, "MIC1"},
++ {"MIC Jack", NULL, "PLL Control"},
++ {"Onboard MIC", NULL, "MIC2"},
++ {"Onboard MIC", NULL, "PLL Control"},
++};
++
++/* machine stream operations */
++
++static int snd_rpi_iqaudio_codec_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++ int ret;
++
++ /* Set bclk ratio to align with codec's BCLK rate */
++ ret = snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
++ if (ret) {
++ dev_err(rtd->dev, "Failed to set CPU BLCK ratio\n");
++ return ret;
++ }
++
++ /* Set MCLK frequency to codec, onboard 11.2896MHz clock */
++ return snd_soc_dai_set_sysclk(codec_dai, DA7213_CLKSRC_MCLK, 11289600,
++ SND_SOC_CLOCK_OUT);
++}
++
++static int snd_rpi_iqaudio_codec_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ unsigned int samplerate = params_rate(params);
++
++ switch (samplerate) {
++ case 8000:
++ case 16000:
++ case 32000:
++ case 48000:
++ case 96000:
++ pll_out = DA7213_PLL_FREQ_OUT_98304000;
++ return 0;
++ case 44100:
++ case 88200:
++ pll_out = DA7213_PLL_FREQ_OUT_90316800;
++ return 0;
++ default:
++ dev_err(rtd->dev,"Unsupported samplerate %d\n", samplerate);
++ return -EINVAL;
++ }
++}
++
++static const struct snd_soc_ops snd_rpi_iqaudio_codec_ops = {
++ .hw_params = snd_rpi_iqaudio_codec_hw_params,
++};
++
++
++static struct snd_soc_dai_link snd_rpi_iqaudio_codec_dai[] = {
++{
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "da7213-hifi",
++ .platform_name = "bmc2708-i2s.0",
++ .codec_name = "da7213.1-001a",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM,
++ .init = snd_rpi_iqaudio_codec_init,
++ .ops = &snd_rpi_iqaudio_codec_ops,
++ .symmetric_rates = 1,
++ .symmetric_channels = 1,
++ .symmetric_samplebits = 1,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_iqaudio_codec = {
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_iqaudio_codec_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_codec_dai),
++ .dapm_widgets = dapm_widgets,
++ .num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
++ .dapm_routes = audio_map,
++ .num_dapm_routes = ARRAY_SIZE(audio_map),
++};
++
++static int snd_rpi_iqaudio_codec_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_iqaudio_codec.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_card *card = &snd_rpi_iqaudio_codec;
++ struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_codec_dai[0];
++
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++
++ if (of_property_read_string(pdev->dev.of_node, "card_name",
++ &card->name))
++ card->name = "IQaudIOCODEC";
++
++ if (of_property_read_string(pdev->dev.of_node, "dai_name",
++ &dai->name))
++ dai->name = "IQaudIO CODEC";
++
++ if (of_property_read_string(pdev->dev.of_node,
++ "dai_stream_name", &dai->stream_name))
++ dai->stream_name = "IQaudIO CODEC HiFi v1.1";
++
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_iqaudio_codec);
++ if (ret) {
++ if (ret != -EPROBE_DEFER)
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int snd_rpi_iqaudio_codec_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_iqaudio_codec);
++}
++
++static const struct of_device_id iqaudio_of_match[] = {
++ { .compatible = "iqaudio,iqaudio-codec", },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, iqaudio_of_match);
++
++static struct platform_driver snd_rpi_iqaudio_codec_driver = {
++ .driver = {
++ .name = "snd-rpi-iqaudio-codec",
++ .owner = THIS_MODULE,
++ .of_match_table = iqaudio_of_match,
++ },
++ .probe = snd_rpi_iqaudio_codec_probe,
++ .remove = snd_rpi_iqaudio_codec_remove,
++};
++
++
++
++module_platform_driver(snd_rpi_iqaudio_codec_driver);
++
++MODULE_DESCRIPTION("ASoC Driver for IQaudIO CODEC");
++MODULE_LICENSE("GPL v2");
+++ /dev/null
-From 250db0df9643d122e00313313102c642f1adac72 Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2019 15:50:01 +0100
-Subject: [PATCH] staging: mmal-vchiq: Fix memory leak in error path
-
-On error, vchiq_mmal_component_init could leave the
-event context allocated for ports.
-Clean them up in the error path.
-
----
- .../vc04_services/vchiq-mmal/mmal-vchiq.c | 27 +++++++++++++------
- 1 file changed, 19 insertions(+), 8 deletions(-)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -1848,9 +1848,26 @@ static void free_event_context(struct vc
- {
- struct mmal_msg_context *ctx = port->event_context;
-
-+ if (!ctx)
-+ return;
-+
- kfree(ctx->u.bulk.buffer->buffer);
- kfree(ctx->u.bulk.buffer);
- release_msg_context(ctx);
-+ port->event_context = NULL;
-+}
-+
-+static void release_all_event_contexts(struct vchiq_mmal_component *component)
-+{
-+ int idx;
-+
-+ for (idx = 0; idx < component->inputs; idx++)
-+ free_event_context(&component->input[idx]);
-+ for (idx = 0; idx < component->outputs; idx++)
-+ free_event_context(&component->output[idx]);
-+ for (idx = 0; idx < component->clocks; idx++)
-+ free_event_context(&component->clock[idx]);
-+ free_event_context(&component->control);
- }
-
- /* Initialise a mmal component and its ports
-@@ -1948,6 +1965,7 @@ int vchiq_mmal_component_init(struct vch
-
- release_component:
- destroy_component(instance, component);
-+ release_all_event_contexts(component);
- unlock:
- if (component)
- component->in_use = 0;
-@@ -1975,14 +1993,7 @@ int vchiq_mmal_component_finalise(struct
-
- component->in_use = 0;
-
-- for (idx = 0; idx < component->inputs; idx++)
-- free_event_context(&component->input[idx]);
-- for (idx = 0; idx < component->outputs; idx++)
-- free_event_context(&component->output[idx]);
-- for (idx = 0; idx < component->clocks; idx++)
-- free_event_context(&component->clock[idx]);
--
-- free_event_context(&component->control);
-+ release_all_event_contexts(component);
-
- mutex_unlock(&instance->vchiq_mutex);
-
+++ /dev/null
-From 3e246d402582c6f19e5e636f89952d11e18e6442 Mon Sep 17 00:00:00 2001
-Date: Fri, 3 May 2019 13:27:51 +0100
-Subject: [PATCH] staging: vchiq-mmal: Fix memory leak of vchiq
- instance
-
-The vchiq instance was allocated from vchiq_mmal_init via
-vchi_initialise, but was never released with vchi_disconnect.
-
-Retain the handle and release it from vchiq_mmal_finalise.
-
----
- drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 9 +++++++--
- 1 file changed, 7 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
-@@ -176,6 +176,7 @@ struct mmal_msg_context {
- };
-
- struct vchiq_mmal_instance {
-+ VCHI_INSTANCE_T vchi_instance;
- VCHI_SERVICE_HANDLE_T handle;
-
- /* ensure serialised access to service */
-@@ -1981,7 +1982,7 @@ EXPORT_SYMBOL_GPL(vchiq_mmal_component_i
- int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
- struct vchiq_mmal_component *component)
- {
-- int ret, idx;
-+ int ret;
-
- if (mutex_lock_interruptible(&instance->vchiq_mutex))
- return -EINTR;
-@@ -2094,6 +2095,8 @@ int vchiq_mmal_finalise(struct vchiq_mma
-
- idr_destroy(&instance->context_map);
-
-+ vchi_disconnect(instance->vchi_instance);
-+
- kfree(instance);
-
- return status;
-@@ -2105,7 +2108,7 @@ int vchiq_mmal_init(struct vchiq_mmal_in
- int status;
- struct vchiq_mmal_instance *instance;
- static VCHI_CONNECTION_T *vchi_connection;
-- static VCHI_INSTANCE_T vchi_instance;
-+ VCHI_INSTANCE_T vchi_instance;
- SERVICE_CREATION_T params = {
- .version = VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER),
- .service_id = VC_MMAL_SERVER_NAME,
-@@ -2151,6 +2154,8 @@ int vchiq_mmal_init(struct vchiq_mmal_in
- if (!instance)
- return -ENOMEM;
-
-+ instance->vchi_instance = vchi_instance;
-+
- mutex_init(&instance->vchiq_mutex);
-
- instance->bulk_scratch = vmalloc(PAGE_SIZE);
--- /dev/null
+From 714580d7c11f81afb5e08c71f79a03a1ed4ae44e Mon Sep 17 00:00:00 2001
+Date: Thu, 28 Mar 2019 12:41:11 -0400
+Subject: [PATCH] w1: ds2408: reset on output_write retry with readback
+
+commit 49695ac46861180baf2b2b92c62da8619b6bf28f upstream.
+
+When we have success in 'Channel Access Write' but reading back latch
+states fails, a write is retried without doing a proper slave reset.
+This leads to protocol errors as the slave treats the next 'Channel
+Access Write' as the continuation of previous command.
+
+This commit is fixing this by making sure if the retry loop re-runs, a
+reset is performed, whatever the failure (CONFIRM_BYTE or the read
+back).
+
+The loop was quite due for a cleanup and this change mandated it. By
+isolating the CONFIG_W1_SLAVE_DS2408_READBACK case into it's own
+function, we vastly reduce the visual and branching(runtime and
+compile-time) noise.
+
+---
+ drivers/w1/slaves/w1_ds2408.c | 76 ++++++++++++++++++-----------------
+ 1 file changed, 39 insertions(+), 37 deletions(-)
+
+--- a/drivers/w1/slaves/w1_ds2408.c
++++ b/drivers/w1/slaves/w1_ds2408.c
+@@ -138,14 +138,37 @@ static ssize_t status_control_read(struc
+ W1_F29_REG_CONTROL_AND_STATUS, buf);
+ }
+
++#ifdef fCONFIG_W1_SLAVE_DS2408_READBACK
++static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)
++{
++ u8 w1_buf[3];
++
++ if (w1_reset_resume_command(sl->master))
++ return false;
++
++ w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
++ w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
++ w1_buf[2] = 0;
++
++ w1_write_block(sl->master, w1_buf, 3);
++
++ return (w1_read_8(sl->master) == expected);
++}
++#else
++static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)
++{
++ return true;
++}
++#endif
++
+ static ssize_t output_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
+ {
+ struct w1_slave *sl = kobj_to_w1_slave(kobj);
+ u8 w1_buf[3];
+- u8 readBack;
+ unsigned int retries = W1_F29_RETRIES;
++ ssize_t bytes_written = -EIO;
+
+ if (count != 1 || off != 0)
+ return -EFAULT;
+@@ -155,54 +178,33 @@ static ssize_t output_write(struct file
+ dev_dbg(&sl->dev, "mutex locked");
+
+ if (w1_reset_select_slave(sl))
+- goto error;
++ goto out;
+
+- while (retries--) {
++ do {
+ w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE;
+ w1_buf[1] = *buf;
+ w1_buf[2] = ~(*buf);
+- w1_write_block(sl->master, w1_buf, 3);
+
+- readBack = w1_read_8(sl->master);
++ w1_write_block(sl->master, w1_buf, 3);
+
+- if (readBack != W1_F29_SUCCESS_CONFIRM_BYTE) {
+- if (w1_reset_resume_command(sl->master))
+- goto error;
+- /* try again, the slave is ready for a command */
+- continue;
++ if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE &&
++ optional_read_back_valid(sl, *buf)) {
++ bytes_written = 1;
++ goto out;
+ }
+
+-#ifdef CONFIG_W1_SLAVE_DS2408_READBACK
+- /* here the master could read another byte which
+- would be the PIO reg (the actual pin logic state)
+- since in this driver we don't know which pins are
+- in and outs, there's no value to read the state and
+- compare. with (*buf) so end this command abruptly: */
+ if (w1_reset_resume_command(sl->master))
+- goto error;
++ goto out; /* unrecoverable error */
++ /* try again, the slave is ready for a command */
++ } while (--retries);
+
+- /* go read back the output latches */
+- /* (the direct effect of the write above) */
+- w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
+- w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
+- w1_buf[2] = 0;
+- w1_write_block(sl->master, w1_buf, 3);
+- /* read the result of the READ_PIO_REGS command */
+- if (w1_read_8(sl->master) == *buf)
+-#endif
+- {
+- /* success! */
+- mutex_unlock(&sl->master->bus_mutex);
+- dev_dbg(&sl->dev,
+- "mutex unlocked, retries:%d", retries);
+- return 1;
+- }
+- }
+-error:
++out:
+ mutex_unlock(&sl->master->bus_mutex);
+- dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
+
+- return -EIO;
++ dev_dbg(&sl->dev, "%s, mutex unlocked retries:%d\n",
++ (bytes_written > 0) ? "succeeded" : "error", retries);
++
++ return bytes_written;
+ }
+
+
+++ /dev/null
-From 930c49de8674acda0f143f7bc182ed2fad8c4f9d Mon Sep 17 00:00:00 2001
-Date: Mon, 13 May 2019 21:53:05 +0100
-Subject: [PATCH] Added IQaudIO Pi-Codec board support (#2969)
-
-Add support for the IQaudIO Pi-Codec board.
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 6 +
- .../dts/overlays/iqaudio-codec-overlay.dts | 42 +++
- sound/soc/bcm/Kconfig | 7 +
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/iqaudio-codec.c | 250 ++++++++++++++++++
- 9 files changed, 311 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
- create mode 100644 sound/soc/bcm/iqaudio-codec.c
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -68,6 +68,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- i2c1-bcm2708.dtbo \
- i2s-gpio28-31.dtbo \
- ilitek251x.dtbo \
-+ iqaudio-codec.dtbo \
- iqaudio-dac.dtbo \
- iqaudio-dacplus.dtbo \
- iqaudio-digi-wm8804-audio.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1160,6 +1160,12 @@ Params: interrupt GPIO use
- touchscreen (in pixels)
-
-
-+Name: iqaudio-codec
-+Info: Configures the IQaudio Codec audio card
-+Load: dtoverlay=iqaudio-codec
-+Params: <None>
-+
-+
- Name: iqaudio-dac
- Info: Configures the IQaudio DAC audio card
- Load: dtoverlay=iqaudio-dac,<param>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
-@@ -0,0 +1,42 @@
-+// Definitions for IQaudIO CODEC
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ da2713@1a {
-+ #sound-dai-cells = <0>;
-+ compatible = "dlg,da7213";
-+ reg = <0x1a>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&sound>;
-+ iqaudio_dac: __overlay__ {
-+ compatible = "iqaudio,iqaudio-codec";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ };
-+};
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -108,6 +108,13 @@ config SND_BCM2708_SOC_JUSTBOOM_DIGI
- help
- Say Y or M if you want to add support for JustBoom Digi.
-
-+config SND_BCM2708_SOC_IQAUDIO_CODEC
-+ tristate "Support for IQaudIO-CODEC"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_DA7213
-+ help
-+ Say Y or M if you want to add support for IQaudIO-CODEC.
-+
- config SND_BCM2708_SOC_IQAUDIO_DAC
- tristate "Support for IQaudIO-DAC"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -18,6 +18,7 @@ snd-soc-hifiberry-dacplusadc-objs := hif
- snd-soc-justboom-dac-objs := justboom-dac.o
- snd-soc-rpi-cirrus-objs := rpi-cirrus.o
- snd-soc-rpi-proto-objs := rpi-proto.o
-+snd-soc-iqaudio-codec-objs := iqaudio-codec.o
- snd-soc-iqaudio-dac-objs := iqaudio-dac.o
- snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o
- snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
-@@ -42,6 +43,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
- obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
-+obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC) += snd-soc-iqaudio-codec.o
- obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o
- obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o
---- /dev/null
-+++ b/sound/soc/bcm/iqaudio-codec.c
-@@ -0,0 +1,250 @@
-+/*
-+ * ASoC Driver for IQaudIO Raspberry Pi Codec board
-+ *
-+ * (C) Copyright IQaudio Limited, 2017-2019
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+
-+#include <linux/acpi.h>
-+#include <linux/slab.h>
-+#include "../codecs/da7213.h"
-+
-+static int pll_out = DA7213_PLL_FREQ_OUT_90316800;
-+
-+static int snd_rpi_iqaudio_pll_control(struct snd_soc_dapm_widget *w,
-+ struct snd_kcontrol *k, int event)
-+{
-+ int ret = 0;
-+ struct snd_soc_dapm_context *dapm = w->dapm;
-+ struct snd_soc_card *card = dapm->card;
-+ struct snd_soc_pcm_runtime *rtd =
-+ snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
-+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
-+
-+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
-+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_MCLK, 0,
-+ 0);
-+ if (ret)
-+ dev_err(card->dev, "Failed to bypass PLL: %d\n", ret);
-+ } else if (SND_SOC_DAPM_EVENT_ON(event)) {
-+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0,
-+ pll_out);
-+ if (ret)
-+ dev_err(card->dev, "Failed to enable PLL: %d\n", ret);
-+ }
-+
-+ return ret;
-+}
-+
-+static int snd_rpi_iqaudio_post_dapm_event(struct snd_soc_dapm_widget *w,
-+ struct snd_kcontrol *kcontrol,
-+ int event)
-+{
-+ switch (event) {
-+ case SND_SOC_DAPM_POST_PMU:
-+ /* Delay for mic bias ramp */
-+ msleep(1000);
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct snd_soc_dapm_widget dapm_widgets[] = {
-+ SND_SOC_DAPM_HP("HP Jack", NULL),
-+ SND_SOC_DAPM_MIC("MIC Jack", NULL),
-+ SND_SOC_DAPM_MIC("Onboard MIC", NULL),
-+ SND_SOC_DAPM_LINE("AUX Jack", NULL),
-+ SND_SOC_DAPM_SUPPLY("PLL Control", SND_SOC_NOPM, 0, 0,
-+ snd_rpi_iqaudio_pll_control,
-+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-+ SND_SOC_DAPM_POST("Post Power Up Event", snd_rpi_iqaudio_post_dapm_event),
-+};
-+
-+static const struct snd_soc_dapm_route audio_map[] = {
-+ {"HP Jack", NULL, "HPL"},
-+ {"HP Jack", NULL, "HPR"},
-+ {"HP Jack", NULL, "PLL Control"},
-+
-+ {"AUX Jack", NULL, "AUXR"},
-+ {"AUX Jack", NULL, "AUXL"},
-+ {"AUX Jack", NULL, "PLL Control"},
-+
-+ /* Assume Mic1 is linked to Headset and Mic2 to on-board mic */
-+ {"MIC Jack", NULL, "MIC1"},
-+ {"MIC Jack", NULL, "PLL Control"},
-+ {"Onboard MIC", NULL, "MIC2"},
-+ {"Onboard MIC", NULL, "PLL Control"},
-+};
-+
-+/* machine stream operations */
-+
-+static int snd_rpi_iqaudio_codec_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+ int ret;
-+
-+ /* Set bclk ratio to align with codec's BCLK rate */
-+ ret = snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
-+ if (ret) {
-+ dev_err(rtd->dev, "Failed to set CPU BLCK ratio\n");
-+ return ret;
-+ }
-+
-+ /* Set MCLK frequency to codec, onboard 11.2896MHz clock */
-+ return snd_soc_dai_set_sysclk(codec_dai, DA7213_CLKSRC_MCLK, 11289600,
-+ SND_SOC_CLOCK_OUT);
-+}
-+
-+static int snd_rpi_iqaudio_codec_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ unsigned int samplerate = params_rate(params);
-+
-+ switch (samplerate) {
-+ case 8000:
-+ case 16000:
-+ case 32000:
-+ case 48000:
-+ case 96000:
-+ pll_out = DA7213_PLL_FREQ_OUT_98304000;
-+ return 0;
-+ case 44100:
-+ case 88200:
-+ pll_out = DA7213_PLL_FREQ_OUT_90316800;
-+ return 0;
-+ default:
-+ dev_err(rtd->dev,"Unsupported samplerate %d\n", samplerate);
-+ return -EINVAL;
-+ }
-+}
-+
-+static const struct snd_soc_ops snd_rpi_iqaudio_codec_ops = {
-+ .hw_params = snd_rpi_iqaudio_codec_hw_params,
-+};
-+
-+
-+static struct snd_soc_dai_link snd_rpi_iqaudio_codec_dai[] = {
-+{
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .codec_dai_name = "da7213-hifi",
-+ .platform_name = "bmc2708-i2s.0",
-+ .codec_name = "da7213.1-001a",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBM_CFM,
-+ .init = snd_rpi_iqaudio_codec_init,
-+ .ops = &snd_rpi_iqaudio_codec_ops,
-+ .symmetric_rates = 1,
-+ .symmetric_channels = 1,
-+ .symmetric_samplebits = 1,
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_iqaudio_codec = {
-+ .owner = THIS_MODULE,
-+ .dai_link = snd_rpi_iqaudio_codec_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_codec_dai),
-+ .dapm_widgets = dapm_widgets,
-+ .num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
-+ .dapm_routes = audio_map,
-+ .num_dapm_routes = ARRAY_SIZE(audio_map),
-+};
-+
-+static int snd_rpi_iqaudio_codec_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ snd_rpi_iqaudio_codec.dev = &pdev->dev;
-+
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_card *card = &snd_rpi_iqaudio_codec;
-+ struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_codec_dai[0];
-+
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+ if (i2s_node) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
-+
-+ if (of_property_read_string(pdev->dev.of_node, "card_name",
-+ &card->name))
-+ card->name = "IQaudIOCODEC";
-+
-+ if (of_property_read_string(pdev->dev.of_node, "dai_name",
-+ &dai->name))
-+ dai->name = "IQaudIO CODEC";
-+
-+ if (of_property_read_string(pdev->dev.of_node,
-+ "dai_stream_name", &dai->stream_name))
-+ dai->stream_name = "IQaudIO CODEC HiFi v1.1";
-+
-+ }
-+
-+ ret = snd_soc_register_card(&snd_rpi_iqaudio_codec);
-+ if (ret) {
-+ if (ret != -EPROBE_DEFER)
-+ dev_err(&pdev->dev,
-+ "snd_soc_register_card() failed: %d\n", ret);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int snd_rpi_iqaudio_codec_remove(struct platform_device *pdev)
-+{
-+ return snd_soc_unregister_card(&snd_rpi_iqaudio_codec);
-+}
-+
-+static const struct of_device_id iqaudio_of_match[] = {
-+ { .compatible = "iqaudio,iqaudio-codec", },
-+ {},
-+};
-+
-+MODULE_DEVICE_TABLE(of, iqaudio_of_match);
-+
-+static struct platform_driver snd_rpi_iqaudio_codec_driver = {
-+ .driver = {
-+ .name = "snd-rpi-iqaudio-codec",
-+ .owner = THIS_MODULE,
-+ .of_match_table = iqaudio_of_match,
-+ },
-+ .probe = snd_rpi_iqaudio_codec_probe,
-+ .remove = snd_rpi_iqaudio_codec_remove,
-+};
-+
-+
-+
-+module_platform_driver(snd_rpi_iqaudio_codec_driver);
-+
-+MODULE_DESCRIPTION("ASoC Driver for IQaudIO CODEC");
-+MODULE_LICENSE("GPL v2");
--- /dev/null
+From 2bf6a79fb6555b5ebf21d03b1295e017804474c4 Mon Sep 17 00:00:00 2001
+Date: Mon, 4 Mar 2019 12:23:36 +0100
+Subject: [PATCH] w1: ds2482: cosmetic fixes after 54865314f5a1
+
+commit 5cb27d30fc3a281e830a2099d520b469e2b82008 upstream.
+
+We have a helper function ds2482_calculate_config() which is calculating
+the config value, so just use it instead of passing the same variable
+in all calls to this function.
+
+Also fixes the placement of module parameters to match with:
+50fa2951bd74 (w1: Organize driver source to natural/common order)
+by Andrew F. Davis
+
+---
+ drivers/w1/masters/ds2482.c | 18 +++++++++++-------
+ 1 file changed, 11 insertions(+), 7 deletions(-)
+
+--- a/drivers/w1/masters/ds2482.c
++++ b/drivers/w1/masters/ds2482.c
+@@ -37,6 +37,11 @@ module_param_named(active_pullup, ds2482
+ MODULE_PARM_DESC(active_pullup, "Active pullup (apply to all buses): " \
+ "0-disable, 1-enable (default)");
+
++/* extra configurations - e.g. 1WS */
++static int extra_config;
++module_param(extra_config, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(extra_config, "Extra Configuration settings 1=APU,2=PPM,3=SPU,8=1WS");
++
+ /**
+ * The DS2482 registers - there are 3 registers that are addressed by a read
+ * pointer. The read pointer is set by the last command executed.
+@@ -70,8 +75,6 @@ MODULE_PARM_DESC(active_pullup, "Active
+ #define DS2482_REG_CFG_PPM 0x02 /* presence pulse masking */
+ #define DS2482_REG_CFG_APU 0x01 /* active pull-up */
+
+-/* extra configurations - e.g. 1WS */
+-static int extra_config;
+
+ /**
+ * Write and verify codes for the CHANNEL_SELECT command (DS2482-800 only).
+@@ -130,6 +133,8 @@ struct ds2482_data {
+ */
+ static inline u8 ds2482_calculate_config(u8 conf)
+ {
++ conf |= extra_config;
++
+ if (ds2482_active_pullup)
+ conf |= DS2482_REG_CFG_APU;
+
+@@ -405,7 +410,7 @@ static u8 ds2482_w1_reset_bus(void *data
+ /* If the chip did reset since detect, re-config it */
+ if (err & DS2482_REG_STS_RST)
+ ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
+- ds2482_calculate_config(extra_config));
++ ds2482_calculate_config(0x00));
+ }
+
+ mutex_unlock(&pdev->access_lock);
+@@ -431,7 +436,8 @@ static u8 ds2482_w1_set_pullup(void *dat
+ ds2482_wait_1wire_idle(pdev);
+ /* note: it seems like both SPU and APU have to be set! */
+ retval = ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
+- ds2482_calculate_config(extra_config|DS2482_REG_CFG_SPU|DS2482_REG_CFG_APU));
++ ds2482_calculate_config(DS2482_REG_CFG_SPU |
++ DS2482_REG_CFG_APU));
+ ds2482_wait_1wire_idle(pdev);
+ }
+
+@@ -484,7 +490,7 @@ static int ds2482_probe(struct i2c_clien
+
+ /* Set all config items to 0 (off) */
+ ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG,
+- ds2482_calculate_config(extra_config));
++ ds2482_calculate_config(0x00));
+
+ mutex_init(&data->access_lock);
+
+@@ -559,7 +565,5 @@ module_i2c_driver(ds2482_driver);
+
+ MODULE_DESCRIPTION("DS2482 driver");
+-module_param(extra_config, int, S_IRUGO | S_IWUSR);
+-MODULE_PARM_DESC(extra_config, "Extra Configuration settings 1=APU,2=PPM,3=SPU,8=1WS");
+
+ MODULE_LICENSE("GPL");
--- /dev/null
+From 2c1e36e477550ea66824433c132fdff03b4ee020 Mon Sep 17 00:00:00 2001
+Date: Thu, 16 May 2019 13:35:32 +0200
+Subject: [PATCH] sound: pcm512x-codec: Adding 352.8kHz samplerate
+ support
+
+---
+ sound/soc/codecs/pcm512x.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/codecs/pcm512x.c
++++ b/sound/soc/codecs/pcm512x.c
+@@ -542,7 +542,7 @@ static unsigned long pcm512x_ncp_target(
+
+ static const u32 pcm512x_dai_rates[] = {
+ 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+- 88200, 96000, 176400, 192000, 384000,
++ 88200, 96000, 176400, 192000, 352800, 384000,
+ };
+
+ static const struct snd_pcm_hw_constraint_list constraints_slave = {
+++ /dev/null
-From 714580d7c11f81afb5e08c71f79a03a1ed4ae44e Mon Sep 17 00:00:00 2001
-Date: Thu, 28 Mar 2019 12:41:11 -0400
-Subject: [PATCH] w1: ds2408: reset on output_write retry with readback
-
-commit 49695ac46861180baf2b2b92c62da8619b6bf28f upstream.
-
-When we have success in 'Channel Access Write' but reading back latch
-states fails, a write is retried without doing a proper slave reset.
-This leads to protocol errors as the slave treats the next 'Channel
-Access Write' as the continuation of previous command.
-
-This commit is fixing this by making sure if the retry loop re-runs, a
-reset is performed, whatever the failure (CONFIRM_BYTE or the read
-back).
-
-The loop was quite due for a cleanup and this change mandated it. By
-isolating the CONFIG_W1_SLAVE_DS2408_READBACK case into it's own
-function, we vastly reduce the visual and branching(runtime and
-compile-time) noise.
-
----
- drivers/w1/slaves/w1_ds2408.c | 76 ++++++++++++++++++-----------------
- 1 file changed, 39 insertions(+), 37 deletions(-)
-
---- a/drivers/w1/slaves/w1_ds2408.c
-+++ b/drivers/w1/slaves/w1_ds2408.c
-@@ -138,14 +138,37 @@ static ssize_t status_control_read(struc
- W1_F29_REG_CONTROL_AND_STATUS, buf);
- }
-
-+#ifdef fCONFIG_W1_SLAVE_DS2408_READBACK
-+static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)
-+{
-+ u8 w1_buf[3];
-+
-+ if (w1_reset_resume_command(sl->master))
-+ return false;
-+
-+ w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
-+ w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
-+ w1_buf[2] = 0;
-+
-+ w1_write_block(sl->master, w1_buf, 3);
-+
-+ return (w1_read_8(sl->master) == expected);
-+}
-+#else
-+static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)
-+{
-+ return true;
-+}
-+#endif
-+
- static ssize_t output_write(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr, char *buf,
- loff_t off, size_t count)
- {
- struct w1_slave *sl = kobj_to_w1_slave(kobj);
- u8 w1_buf[3];
-- u8 readBack;
- unsigned int retries = W1_F29_RETRIES;
-+ ssize_t bytes_written = -EIO;
-
- if (count != 1 || off != 0)
- return -EFAULT;
-@@ -155,54 +178,33 @@ static ssize_t output_write(struct file
- dev_dbg(&sl->dev, "mutex locked");
-
- if (w1_reset_select_slave(sl))
-- goto error;
-+ goto out;
-
-- while (retries--) {
-+ do {
- w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE;
- w1_buf[1] = *buf;
- w1_buf[2] = ~(*buf);
-- w1_write_block(sl->master, w1_buf, 3);
-
-- readBack = w1_read_8(sl->master);
-+ w1_write_block(sl->master, w1_buf, 3);
-
-- if (readBack != W1_F29_SUCCESS_CONFIRM_BYTE) {
-- if (w1_reset_resume_command(sl->master))
-- goto error;
-- /* try again, the slave is ready for a command */
-- continue;
-+ if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE &&
-+ optional_read_back_valid(sl, *buf)) {
-+ bytes_written = 1;
-+ goto out;
- }
-
--#ifdef CONFIG_W1_SLAVE_DS2408_READBACK
-- /* here the master could read another byte which
-- would be the PIO reg (the actual pin logic state)
-- since in this driver we don't know which pins are
-- in and outs, there's no value to read the state and
-- compare. with (*buf) so end this command abruptly: */
- if (w1_reset_resume_command(sl->master))
-- goto error;
-+ goto out; /* unrecoverable error */
-+ /* try again, the slave is ready for a command */
-+ } while (--retries);
-
-- /* go read back the output latches */
-- /* (the direct effect of the write above) */
-- w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
-- w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
-- w1_buf[2] = 0;
-- w1_write_block(sl->master, w1_buf, 3);
-- /* read the result of the READ_PIO_REGS command */
-- if (w1_read_8(sl->master) == *buf)
--#endif
-- {
-- /* success! */
-- mutex_unlock(&sl->master->bus_mutex);
-- dev_dbg(&sl->dev,
-- "mutex unlocked, retries:%d", retries);
-- return 1;
-- }
-- }
--error:
-+out:
- mutex_unlock(&sl->master->bus_mutex);
-- dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
-
-- return -EIO;
-+ dev_dbg(&sl->dev, "%s, mutex unlocked retries:%d\n",
-+ (bytes_written > 0) ? "succeeded" : "error", retries);
-+
-+ return bytes_written;
- }
-
-
--- /dev/null
+From 3150326498ba9388b85e5af2c8fcfeafc46eeaad Mon Sep 17 00:00:00 2001
+Date: Sat, 6 Apr 2019 21:16:39 +0100
+Subject: [PATCH] ASoC: decommissioning driver for 3Dlab Nano soundcard
+
+---
+ .../overlays/3dlab-nano-player-overlay.dts | 32 --
+ arch/arm/boot/dts/overlays/Makefile | 1 -
+ arch/arm/boot/dts/overlays/README | 6 -
+ sound/soc/bcm/3dlab-nano-player.c | 370 ------------------
+ sound/soc/bcm/Kconfig | 6 -
+ sound/soc/bcm/Makefile | 6 +-
+ 8 files changed, 2 insertions(+), 421 deletions(-)
+ delete mode 100644 arch/arm/boot/dts/overlays/3dlab-nano-player-overlay.dts
+ delete mode 100644 sound/soc/bcm/3dlab-nano-player.c
+
+--- a/arch/arm/boot/dts/overlays/3dlab-nano-player-overlay.dts
++++ /dev/null
+@@ -1,32 +0,0 @@
+-// Definitions for 3Dlab Nano Player
+-/dts-v1/;
+-/plugin/;
+-
+-/ {
+- compatible = "brcm,bcm2708";
+-
+- fragment@0 {
+- target = <&i2s>;
+- __overlay__ {
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+- target = <&i2c>;
+- __overlay__ {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "okay";
+-
+- nano-player@41 {
+- compatible = "3dlab,nano-player";
+- reg = <0x41>;
+- i2s-controller = <&i2s>;
+- status = "okay";
+- };
+- };
+- };
+-};
+-
+-// EOF
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -1,7 +1,6 @@
+ # Overlays for the Raspberry Pi platform
+
+ dtbo-$(CONFIG_ARCH_BCM2835) += \
+- 3dlab-nano-player.dtbo \
+ adau1977-adc.dtbo \
+ adau7002-simple.dtbo \
+ ads1015.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -205,12 +205,6 @@ Params:
+ and the other i2c baudrate parameters.
+
+
+-Name: 3dlab-nano-player
+-Info: Configures the 3Dlab Nano Player
+-Load: dtoverlay=3dlab-nano-player
+-Params: <None>
+-
+-
+ Name: adau1977-adc
+ Info: Overlay for activation of ADAU1977 ADC codec over I2C for control
+ and I2S for data.
+--- a/sound/soc/bcm/3dlab-nano-player.c
++++ /dev/null
+@@ -1,370 +0,0 @@
+-/*
+- * 3Dlab Nano Player ALSA SoC Audio driver.
+- *
+- * Copyright (C) 2018 3Dlab.
+- *
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License
+- * version 2 as published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * General Public License for more details.
+- */
+-
+-#include <linux/module.h>
+-#include <linux/i2c.h>
+-#include <sound/soc.h>
+-#include <sound/pcm.h>
+-#include <sound/pcm_params.h>
+-#include <sound/control.h>
+-
+-#define NANO_ID 0x00
+-#define NANO_VER 0x01
+-#define NANO_CFG 0x02
+-#define NANO_STATUS 0x03
+-#define NANO_SPI_ADDR 0x04
+-#define NANO_SPI_DATA 0x05
+-
+-#define NANO_ID_VAL 0x3D
+-#define NANO_CFG_OFF 0x00
+-#define NANO_CFG_MULT1 0
+-#define NANO_CFG_MULT2 1
+-#define NANO_CFG_MULT4 2
+-#define NANO_CFG_MULT8 3
+-#define NANO_CFG_MULT16 4
+-#define NANO_CFG_CLK22 0
+-#define NANO_CFG_CLK24 BIT(3)
+-#define NANO_CFG_DSD BIT(4)
+-#define NANO_CFG_ENA BIT(5)
+-#define NANO_CFG_BLINK BIT(6)
+-#define NANO_STATUS_P1 BIT(0)
+-#define NANO_STATUS_P2 BIT(1)
+-#define NANO_STATUS_FLG BIT(2)
+-#define NANO_STATUS_CLK BIT(3)
+-#define NANO_SPI_READ 0
+-#define NANO_SPI_WRITE BIT(5)
+-
+-#define NANO_DAC_CTRL1 0x00
+-#define NANO_DAC_CTRL2 0x01
+-#define NANO_DAC_CTRL3 0x02
+-#define NANO_DAC_LATT 0x03
+-#define NANO_DAC_RATT 0x04
+-
+-#define NANO_CTRL2_VAL 0x22
+-
+-static int nano_player_spi_write(struct regmap *map,
+- unsigned int reg, unsigned int val)
+-{
+- /* indirect register access */
+- regmap_write(map, NANO_SPI_DATA, val);
+- regmap_write(map, NANO_SPI_ADDR, reg | NANO_SPI_WRITE);
+- return 0;
+-}
+-
+-static int nano_player_ctrl_info(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_info *uinfo)
+-{
+- /* describe control element */
+- if (strstr(kcontrol->id.name, "Volume")) {
+- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+- uinfo->count = 1;
+- uinfo->value.integer.min = 0;
+- uinfo->value.integer.max = 100;
+- } else {
+- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+- uinfo->count = 1;
+- uinfo->value.integer.min = 0;
+- uinfo->value.integer.max = 1;
+- }
+-
+- return 0;
+-}
+-
+-static int nano_player_ctrl_put(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
+-{
+- /* program control value to hardware */
+- struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+- struct regmap *regmap = snd_soc_card_get_drvdata(card);
+-
+- if (strstr(kcontrol->id.name, "Volume")) {
+- unsigned int vol = ucontrol->value.integer.value[0];
+- unsigned int att = 255 - (2 * (100 - vol));
+-
+- nano_player_spi_write(regmap, NANO_DAC_LATT, att);
+- nano_player_spi_write(regmap, NANO_DAC_RATT, att);
+- kcontrol->private_value = vol;
+- } else {
+- unsigned int mute = ucontrol->value.integer.value[0];
+- unsigned int reg = NANO_CTRL2_VAL | mute;
+-
+- nano_player_spi_write(regmap, NANO_DAC_CTRL2, reg);
+- kcontrol->private_value = mute;
+- }
+- return 0;
+-}
+-
+-static int nano_player_ctrl_get(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
+-{
+- /* return last programmed value */
+- ucontrol->value.integer.value[0] = kcontrol->private_value;
+- return 0;
+-}
+-
+-#define SOC_NANO_PLAYER_CTRL(xname) \
+-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+- .info = nano_player_ctrl_info, \
+- .put = nano_player_ctrl_put, \
+- .get = nano_player_ctrl_get }
+-
+-static const struct snd_kcontrol_new nano_player_controls[] = {
+- SOC_NANO_PLAYER_CTRL("Master Playback Volume"),
+- SOC_NANO_PLAYER_CTRL("Master Playback Switch"),
+-};
+-
+-static const unsigned int nano_player_rates[] = {
+- 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000,
+- 705600, 768000 /* only possible with fast clocks */
+-};
+-
+-static struct snd_pcm_hw_constraint_list nano_player_constraint_rates = {
+- .list = nano_player_rates,
+- .count = ARRAY_SIZE(nano_player_rates),
+-};
+-
+-static int nano_player_init(struct snd_soc_pcm_runtime *rtd)
+-{
+- struct snd_soc_card *card = rtd->card;
+- struct regmap *regmap = snd_soc_card_get_drvdata(card);
+- struct snd_soc_pcm_stream *cpu = &rtd->cpu_dai->driver->playback;
+- struct snd_soc_pcm_stream *codec = &rtd->codec_dai->driver->playback;
+- unsigned int sample_bits = 32;
+- unsigned int val;
+-
+- /* configure cpu dai */
+- cpu->formats |= SNDRV_PCM_FMTBIT_DSD_U32_LE;
+- cpu->rate_max = 768000;
+-
+- /* configure dummy codec dai */
+- codec->rate_min = 44100;
+- codec->rates = SNDRV_PCM_RATE_KNOT;
+- codec->formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_DSD_U32_LE;
+-
+- /* configure max supported rate */
+- regmap_read(regmap, NANO_STATUS, &val);
+- if (val & NANO_STATUS_CLK) {
+- dev_notice(card->dev, "Board with fast clocks installed\n");
+- codec->rate_max = 768000;
+- } else {
+- dev_notice(card->dev, "Board with normal clocks installed\n");
+- codec->rate_max = 384000;
+- }
+-
+- /* frame length enforced by hardware */
+- return snd_soc_dai_set_bclk_ratio(rtd->cpu_dai, sample_bits * 2);
+-}
+-
+-static int nano_player_startup(struct snd_pcm_substream *substream)
+-{
+- return snd_pcm_hw_constraint_list(substream->runtime, 0,
+- SNDRV_PCM_HW_PARAM_RATE,
+- &nano_player_constraint_rates);
+-}
+-
+-static int nano_player_hw_params(struct snd_pcm_substream *substream,
+- struct snd_pcm_hw_params *params)
+-{
+- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+- struct snd_soc_card *card = rtd->card;
+- struct regmap *regmap = snd_soc_card_get_drvdata(card);
+- unsigned int config = NANO_CFG_ENA;
+- struct snd_mask *fmt;
+-
+- /* configure PCM or DSD */
+- fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+- if (snd_mask_test(fmt, SNDRV_PCM_FORMAT_DSD_U32_LE)) {
+- /* embed DSD in PCM data */
+- snd_mask_none(fmt);
+- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S32_LE);
+- /* enable DSD mode */
+- config |= NANO_CFG_DSD;
+- }
+-
+- /* configure clocks */
+- switch (params_rate(params)) {
+- case 44100:
+- config |= NANO_CFG_MULT1 | NANO_CFG_CLK22;
+- break;
+- case 88200:
+- config |= NANO_CFG_MULT2 | NANO_CFG_CLK22;
+- break;
+- case 176400:
+- config |= NANO_CFG_MULT4 | NANO_CFG_CLK22;
+- break;
+- case 352800:
+- config |= NANO_CFG_MULT8 | NANO_CFG_CLK22;
+- break;
+- case 705600:
+- config |= NANO_CFG_MULT16 | NANO_CFG_CLK22;
+- break;
+- case 48000:
+- config |= NANO_CFG_MULT1 | NANO_CFG_CLK24;
+- break;
+- case 96000:
+- config |= NANO_CFG_MULT2 | NANO_CFG_CLK24;
+- break;
+- case 192000:
+- config |= NANO_CFG_MULT4 | NANO_CFG_CLK24;
+- break;
+- case 384000:
+- config |= NANO_CFG_MULT8 | NANO_CFG_CLK24;
+- break;
+- case 768000:
+- config |= NANO_CFG_MULT16 | NANO_CFG_CLK24;
+- break;
+- default:
+- return -EINVAL;
+- }
+-
+- dev_dbg(card->dev, "Send CFG register 0x%02X\n", config);
+- return regmap_write(regmap, NANO_CFG, config);
+-}
+-
+-static struct snd_soc_ops nano_player_ops = {
+- .startup = nano_player_startup,
+- .hw_params = nano_player_hw_params,
+-};
+-
+-static struct snd_soc_dai_link nano_player_link = {
+- .name = "3Dlab Nano Player",
+- .stream_name = "3Dlab Nano Player HiFi",
+- .platform_name = "bcm2708-i2s.0",
+- .cpu_dai_name = "bcm2708-i2s.0",
+- .codec_name = "snd-soc-dummy",
+- .codec_dai_name = "snd-soc-dummy-dai",
+- .dai_fmt = SND_SOC_DAIFMT_I2S |
+- SND_SOC_DAIFMT_CONT |
+- SND_SOC_DAIFMT_NB_NF |
+- SND_SOC_DAIFMT_CBM_CFM,
+- .init = nano_player_init,
+- .ops = &nano_player_ops,
+-};
+-
+-static const struct regmap_config nano_player_regmap = {
+- .reg_bits = 8,
+- .val_bits = 8,
+- .max_register = 128,
+- .cache_type = REGCACHE_RBTREE,
+-};
+-
+-static int nano_player_card_probe(struct snd_soc_card *card)
+-{
+- struct regmap *regmap = snd_soc_card_get_drvdata(card);
+- unsigned int val;
+-
+- /* check hardware integrity */
+- regmap_read(regmap, NANO_ID, &val);
+- if (val != NANO_ID_VAL) {
+- dev_err(card->dev, "Invalid ID register 0x%02X\n", val);
+- return -ENODEV;
+- }
+-
+- /* report version to the user */
+- regmap_read(regmap, NANO_VER, &val);
+- dev_notice(card->dev, "Started 3Dlab Nano Player driver (v%d)\n", val);
+-
+- /* enable internal audio bus and blink status LED */
+- return regmap_write(regmap, NANO_CFG, NANO_CFG_ENA | NANO_CFG_BLINK);
+-}
+-
+-static int nano_player_card_remove(struct snd_soc_card *card)
+-{
+- /* disable internal audio bus */
+- struct regmap *regmap = snd_soc_card_get_drvdata(card);
+-
+- return regmap_write(regmap, NANO_CFG, NANO_CFG_OFF);
+-}
+-
+-static struct snd_soc_card nano_player_card = {
+- .name = "3Dlab_Nano_Player",
+- .owner = THIS_MODULE,
+- .dai_link = &nano_player_link,
+- .num_links = 1,
+- .controls = nano_player_controls,
+- .num_controls = ARRAY_SIZE(nano_player_controls),
+- .probe = nano_player_card_probe,
+- .remove = nano_player_card_remove,
+-};
+-
+-static int nano_player_i2c_probe(struct i2c_client *i2c,
+- const struct i2c_device_id *id)
+-{
+- struct regmap *regmap;
+- int ret;
+-
+- regmap = devm_regmap_init_i2c(i2c, &nano_player_regmap);
+- if (IS_ERR(regmap)) {
+- ret = PTR_ERR(regmap);
+- dev_err(&i2c->dev, "Failed to init regmap %d\n", ret);
+- return ret;
+- }
+-
+- if (i2c->dev.of_node) {
+- struct snd_soc_dai_link *dai = &nano_player_link;
+- struct device_node *node;
+-
+- /* cpu handle configured by device tree */
+- node = of_parse_phandle(i2c->dev.of_node, "i2s-controller", 0);
+- if (node) {
+- dai->platform_name = NULL;
+- dai->platform_of_node = node;
+- dai->cpu_dai_name = NULL;
+- dai->cpu_of_node = node;
+- }
+- }
+-
+- nano_player_card.dev = &i2c->dev;
+- snd_soc_card_set_drvdata(&nano_player_card, regmap);
+- ret = devm_snd_soc_register_card(&i2c->dev, &nano_player_card);
+-
+- if (ret && ret != -EPROBE_DEFER)
+- dev_err(&i2c->dev, "Failed to register card %d\n", ret);
+-
+- return ret;
+-}
+-
+-static const struct of_device_id nano_player_of_match[] = {
+- { .compatible = "3dlab,nano-player", },
+- { }
+-};
+-MODULE_DEVICE_TABLE(of, nano_player_of_match);
+-
+-static const struct i2c_device_id nano_player_i2c_id[] = {
+- { "nano-player", 0 },
+- { }
+-};
+-MODULE_DEVICE_TABLE(i2c, nano_player_i2c_id);
+-
+-static struct i2c_driver nano_player_i2c_driver = {
+- .probe = nano_player_i2c_probe,
+- .id_table = nano_player_i2c_id,
+- .driver = {
+- .name = "nano-player",
+- .owner = THIS_MODULE,
+- .of_match_table = nano_player_of_match,
+- },
+-};
+-
+-module_i2c_driver(nano_player_i2c_driver);
+-
+-MODULE_DESCRIPTION("ASoC 3Dlab Nano Player driver");
+-MODULE_LICENSE("GPL v2");
+-
+-/* EOF */
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -17,12 +17,6 @@ config SND_SOC_CYGNUS
+
+ If you don't know what to do here, say N.
+
+-config SND_BCM2708_SOC_3DLAB_NANO_PLAYER
+- tristate "Support for 3Dlab Nano Player"
+- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+- help
+- Say Y or M if you want to add support for 3Dlab Nano Player.
+-
+ config SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD
+ tristate "Support for Google voiceHAT soundcard"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -12,7 +12,6 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-
+ snd-soc-googlevoicehat-codec-objs := googlevoicehat-codec.o
+
+ # BCM2708 Machine Support
+-snd-soc-3dlab-nano-player-objs := 3dlab-nano-player.o
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
+ snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
+ snd-soc-justboom-dac-objs := justboom-dac.o
+@@ -20,7 +19,7 @@ snd-soc-rpi-cirrus-objs := rpi-cirrus.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+ snd-soc-iqaudio-codec-objs := iqaudio-codec.o
+ snd-soc-iqaudio-dac-objs := iqaudio-dac.o
+- snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o
++snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o
+ snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
+ snd-soc-audioinjector-octo-soundcard-objs := audioinjector-octo-soundcard.o
+ snd-soc-audiosense-pi-objs := audiosense-pi.o
+@@ -36,7 +35,6 @@ snd-soc-fe-pi-audio-objs := fe-pi-audio.
+ snd-soc-rpi-simple-soundcard-objs := rpi-simple-soundcard.o
+ snd-soc-rpi-wm8804-soundcard-objs := rpi-wm8804-soundcard.o
+
+-obj-$(CONFIG_SND_BCM2708_SOC_3DLAB_NANO_PLAYER) += snd-soc-3dlab-nano-player.o
+ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
+@@ -45,7 +43,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS)
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC) += snd-soc-iqaudio-codec.o
+ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
+- obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o
++obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o
+ obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o
+ obj-$(CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD) += snd-soc-audioinjector-octo-soundcard.o
+ obj-$(CONFIG_SND_AUDIOSENSE_PI) += snd-soc-audiosense-pi.o
+++ /dev/null
-From 2bf6a79fb6555b5ebf21d03b1295e017804474c4 Mon Sep 17 00:00:00 2001
-Date: Mon, 4 Mar 2019 12:23:36 +0100
-Subject: [PATCH] w1: ds2482: cosmetic fixes after 54865314f5a1
-
-commit 5cb27d30fc3a281e830a2099d520b469e2b82008 upstream.
-
-We have a helper function ds2482_calculate_config() which is calculating
-the config value, so just use it instead of passing the same variable
-in all calls to this function.
-
-Also fixes the placement of module parameters to match with:
-50fa2951bd74 (w1: Organize driver source to natural/common order)
-by Andrew F. Davis
-
----
- drivers/w1/masters/ds2482.c | 18 +++++++++++-------
- 1 file changed, 11 insertions(+), 7 deletions(-)
-
---- a/drivers/w1/masters/ds2482.c
-+++ b/drivers/w1/masters/ds2482.c
-@@ -37,6 +37,11 @@ module_param_named(active_pullup, ds2482
- MODULE_PARM_DESC(active_pullup, "Active pullup (apply to all buses): " \
- "0-disable, 1-enable (default)");
-
-+/* extra configurations - e.g. 1WS */
-+static int extra_config;
-+module_param(extra_config, int, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(extra_config, "Extra Configuration settings 1=APU,2=PPM,3=SPU,8=1WS");
-+
- /**
- * The DS2482 registers - there are 3 registers that are addressed by a read
- * pointer. The read pointer is set by the last command executed.
-@@ -70,8 +75,6 @@ MODULE_PARM_DESC(active_pullup, "Active
- #define DS2482_REG_CFG_PPM 0x02 /* presence pulse masking */
- #define DS2482_REG_CFG_APU 0x01 /* active pull-up */
-
--/* extra configurations - e.g. 1WS */
--static int extra_config;
-
- /**
- * Write and verify codes for the CHANNEL_SELECT command (DS2482-800 only).
-@@ -130,6 +133,8 @@ struct ds2482_data {
- */
- static inline u8 ds2482_calculate_config(u8 conf)
- {
-+ conf |= extra_config;
-+
- if (ds2482_active_pullup)
- conf |= DS2482_REG_CFG_APU;
-
-@@ -405,7 +410,7 @@ static u8 ds2482_w1_reset_bus(void *data
- /* If the chip did reset since detect, re-config it */
- if (err & DS2482_REG_STS_RST)
- ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
-- ds2482_calculate_config(extra_config));
-+ ds2482_calculate_config(0x00));
- }
-
- mutex_unlock(&pdev->access_lock);
-@@ -431,7 +436,8 @@ static u8 ds2482_w1_set_pullup(void *dat
- ds2482_wait_1wire_idle(pdev);
- /* note: it seems like both SPU and APU have to be set! */
- retval = ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
-- ds2482_calculate_config(extra_config|DS2482_REG_CFG_SPU|DS2482_REG_CFG_APU));
-+ ds2482_calculate_config(DS2482_REG_CFG_SPU |
-+ DS2482_REG_CFG_APU));
- ds2482_wait_1wire_idle(pdev);
- }
-
-@@ -484,7 +490,7 @@ static int ds2482_probe(struct i2c_clien
-
- /* Set all config items to 0 (off) */
- ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG,
-- ds2482_calculate_config(extra_config));
-+ ds2482_calculate_config(0x00));
-
- mutex_init(&data->access_lock);
-
-@@ -559,7 +565,5 @@ module_i2c_driver(ds2482_driver);
-
- MODULE_DESCRIPTION("DS2482 driver");
--module_param(extra_config, int, S_IRUGO | S_IWUSR);
--MODULE_PARM_DESC(extra_config, "Extra Configuration settings 1=APU,2=PPM,3=SPU,8=1WS");
-
- MODULE_LICENSE("GPL");
--- /dev/null
+From bd4e0a6ad64c1211094776923bf61bd6ede3f043 Mon Sep 17 00:00:00 2001
+Date: Tue, 21 May 2019 15:17:33 +0100
+Subject: [PATCH] .gitignore: Add *.dtbo explicitly
+
+---
+ .gitignore | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/.gitignore
++++ b/.gitignore
+@@ -15,7 +15,8 @@
+ *.bin
+ *.bz2
+ *.c.[012]*.*
+-*.dtb*
++*.dtb
++*.dtbo
+ *.dtb.S
+ *.dwo
+ *.elf
+++ /dev/null
-From 2c1e36e477550ea66824433c132fdff03b4ee020 Mon Sep 17 00:00:00 2001
-Date: Thu, 16 May 2019 13:35:32 +0200
-Subject: [PATCH] sound: pcm512x-codec: Adding 352.8kHz samplerate
- support
-
----
- sound/soc/codecs/pcm512x.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/sound/soc/codecs/pcm512x.c
-+++ b/sound/soc/codecs/pcm512x.c
-@@ -542,7 +542,7 @@ static unsigned long pcm512x_ncp_target(
-
- static const u32 pcm512x_dai_rates[] = {
- 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
-- 88200, 96000, 176400, 192000, 384000,
-+ 88200, 96000, 176400, 192000, 352800, 384000,
- };
-
- static const struct snd_pcm_hw_constraint_list constraints_slave = {
+++ /dev/null
-From 3150326498ba9388b85e5af2c8fcfeafc46eeaad Mon Sep 17 00:00:00 2001
-Date: Sat, 6 Apr 2019 21:16:39 +0100
-Subject: [PATCH] ASoC: decommissioning driver for 3Dlab Nano soundcard
-
----
- .../overlays/3dlab-nano-player-overlay.dts | 32 --
- arch/arm/boot/dts/overlays/Makefile | 1 -
- arch/arm/boot/dts/overlays/README | 6 -
- sound/soc/bcm/3dlab-nano-player.c | 370 ------------------
- sound/soc/bcm/Kconfig | 6 -
- sound/soc/bcm/Makefile | 6 +-
- 8 files changed, 2 insertions(+), 421 deletions(-)
- delete mode 100644 arch/arm/boot/dts/overlays/3dlab-nano-player-overlay.dts
- delete mode 100644 sound/soc/bcm/3dlab-nano-player.c
-
---- a/arch/arm/boot/dts/overlays/3dlab-nano-player-overlay.dts
-+++ /dev/null
-@@ -1,32 +0,0 @@
--// Definitions for 3Dlab Nano Player
--/dts-v1/;
--/plugin/;
--
--/ {
-- compatible = "brcm,bcm2708";
--
-- fragment@0 {
-- target = <&i2s>;
-- __overlay__ {
-- status = "okay";
-- };
-- };
--
-- fragment@1 {
-- target = <&i2c>;
-- __overlay__ {
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "okay";
--
-- nano-player@41 {
-- compatible = "3dlab,nano-player";
-- reg = <0x41>;
-- i2s-controller = <&i2s>;
-- status = "okay";
-- };
-- };
-- };
--};
--
--// EOF
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -1,7 +1,6 @@
- # Overlays for the Raspberry Pi platform
-
- dtbo-$(CONFIG_ARCH_BCM2835) += \
-- 3dlab-nano-player.dtbo \
- adau1977-adc.dtbo \
- adau7002-simple.dtbo \
- ads1015.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -205,12 +205,6 @@ Params:
- and the other i2c baudrate parameters.
-
-
--Name: 3dlab-nano-player
--Info: Configures the 3Dlab Nano Player
--Load: dtoverlay=3dlab-nano-player
--Params: <None>
--
--
- Name: adau1977-adc
- Info: Overlay for activation of ADAU1977 ADC codec over I2C for control
- and I2S for data.
---- a/sound/soc/bcm/3dlab-nano-player.c
-+++ /dev/null
-@@ -1,370 +0,0 @@
--/*
-- * 3Dlab Nano Player ALSA SoC Audio driver.
-- *
-- * Copyright (C) 2018 3Dlab.
-- *
-- *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public License
-- * version 2 as published by the Free Software Foundation.
-- *
-- * This program is distributed in the hope that it will be useful, but
-- * WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- * General Public License for more details.
-- */
--
--#include <linux/module.h>
--#include <linux/i2c.h>
--#include <sound/soc.h>
--#include <sound/pcm.h>
--#include <sound/pcm_params.h>
--#include <sound/control.h>
--
--#define NANO_ID 0x00
--#define NANO_VER 0x01
--#define NANO_CFG 0x02
--#define NANO_STATUS 0x03
--#define NANO_SPI_ADDR 0x04
--#define NANO_SPI_DATA 0x05
--
--#define NANO_ID_VAL 0x3D
--#define NANO_CFG_OFF 0x00
--#define NANO_CFG_MULT1 0
--#define NANO_CFG_MULT2 1
--#define NANO_CFG_MULT4 2
--#define NANO_CFG_MULT8 3
--#define NANO_CFG_MULT16 4
--#define NANO_CFG_CLK22 0
--#define NANO_CFG_CLK24 BIT(3)
--#define NANO_CFG_DSD BIT(4)
--#define NANO_CFG_ENA BIT(5)
--#define NANO_CFG_BLINK BIT(6)
--#define NANO_STATUS_P1 BIT(0)
--#define NANO_STATUS_P2 BIT(1)
--#define NANO_STATUS_FLG BIT(2)
--#define NANO_STATUS_CLK BIT(3)
--#define NANO_SPI_READ 0
--#define NANO_SPI_WRITE BIT(5)
--
--#define NANO_DAC_CTRL1 0x00
--#define NANO_DAC_CTRL2 0x01
--#define NANO_DAC_CTRL3 0x02
--#define NANO_DAC_LATT 0x03
--#define NANO_DAC_RATT 0x04
--
--#define NANO_CTRL2_VAL 0x22
--
--static int nano_player_spi_write(struct regmap *map,
-- unsigned int reg, unsigned int val)
--{
-- /* indirect register access */
-- regmap_write(map, NANO_SPI_DATA, val);
-- regmap_write(map, NANO_SPI_ADDR, reg | NANO_SPI_WRITE);
-- return 0;
--}
--
--static int nano_player_ctrl_info(struct snd_kcontrol *kcontrol,
-- struct snd_ctl_elem_info *uinfo)
--{
-- /* describe control element */
-- if (strstr(kcontrol->id.name, "Volume")) {
-- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-- uinfo->count = 1;
-- uinfo->value.integer.min = 0;
-- uinfo->value.integer.max = 100;
-- } else {
-- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-- uinfo->count = 1;
-- uinfo->value.integer.min = 0;
-- uinfo->value.integer.max = 1;
-- }
--
-- return 0;
--}
--
--static int nano_player_ctrl_put(struct snd_kcontrol *kcontrol,
-- struct snd_ctl_elem_value *ucontrol)
--{
-- /* program control value to hardware */
-- struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
-- struct regmap *regmap = snd_soc_card_get_drvdata(card);
--
-- if (strstr(kcontrol->id.name, "Volume")) {
-- unsigned int vol = ucontrol->value.integer.value[0];
-- unsigned int att = 255 - (2 * (100 - vol));
--
-- nano_player_spi_write(regmap, NANO_DAC_LATT, att);
-- nano_player_spi_write(regmap, NANO_DAC_RATT, att);
-- kcontrol->private_value = vol;
-- } else {
-- unsigned int mute = ucontrol->value.integer.value[0];
-- unsigned int reg = NANO_CTRL2_VAL | mute;
--
-- nano_player_spi_write(regmap, NANO_DAC_CTRL2, reg);
-- kcontrol->private_value = mute;
-- }
-- return 0;
--}
--
--static int nano_player_ctrl_get(struct snd_kcontrol *kcontrol,
-- struct snd_ctl_elem_value *ucontrol)
--{
-- /* return last programmed value */
-- ucontrol->value.integer.value[0] = kcontrol->private_value;
-- return 0;
--}
--
--#define SOC_NANO_PLAYER_CTRL(xname) \
--{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
-- .info = nano_player_ctrl_info, \
-- .put = nano_player_ctrl_put, \
-- .get = nano_player_ctrl_get }
--
--static const struct snd_kcontrol_new nano_player_controls[] = {
-- SOC_NANO_PLAYER_CTRL("Master Playback Volume"),
-- SOC_NANO_PLAYER_CTRL("Master Playback Switch"),
--};
--
--static const unsigned int nano_player_rates[] = {
-- 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000,
-- 705600, 768000 /* only possible with fast clocks */
--};
--
--static struct snd_pcm_hw_constraint_list nano_player_constraint_rates = {
-- .list = nano_player_rates,
-- .count = ARRAY_SIZE(nano_player_rates),
--};
--
--static int nano_player_init(struct snd_soc_pcm_runtime *rtd)
--{
-- struct snd_soc_card *card = rtd->card;
-- struct regmap *regmap = snd_soc_card_get_drvdata(card);
-- struct snd_soc_pcm_stream *cpu = &rtd->cpu_dai->driver->playback;
-- struct snd_soc_pcm_stream *codec = &rtd->codec_dai->driver->playback;
-- unsigned int sample_bits = 32;
-- unsigned int val;
--
-- /* configure cpu dai */
-- cpu->formats |= SNDRV_PCM_FMTBIT_DSD_U32_LE;
-- cpu->rate_max = 768000;
--
-- /* configure dummy codec dai */
-- codec->rate_min = 44100;
-- codec->rates = SNDRV_PCM_RATE_KNOT;
-- codec->formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_DSD_U32_LE;
--
-- /* configure max supported rate */
-- regmap_read(regmap, NANO_STATUS, &val);
-- if (val & NANO_STATUS_CLK) {
-- dev_notice(card->dev, "Board with fast clocks installed\n");
-- codec->rate_max = 768000;
-- } else {
-- dev_notice(card->dev, "Board with normal clocks installed\n");
-- codec->rate_max = 384000;
-- }
--
-- /* frame length enforced by hardware */
-- return snd_soc_dai_set_bclk_ratio(rtd->cpu_dai, sample_bits * 2);
--}
--
--static int nano_player_startup(struct snd_pcm_substream *substream)
--{
-- return snd_pcm_hw_constraint_list(substream->runtime, 0,
-- SNDRV_PCM_HW_PARAM_RATE,
-- &nano_player_constraint_rates);
--}
--
--static int nano_player_hw_params(struct snd_pcm_substream *substream,
-- struct snd_pcm_hw_params *params)
--{
-- struct snd_soc_pcm_runtime *rtd = substream->private_data;
-- struct snd_soc_card *card = rtd->card;
-- struct regmap *regmap = snd_soc_card_get_drvdata(card);
-- unsigned int config = NANO_CFG_ENA;
-- struct snd_mask *fmt;
--
-- /* configure PCM or DSD */
-- fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-- if (snd_mask_test(fmt, SNDRV_PCM_FORMAT_DSD_U32_LE)) {
-- /* embed DSD in PCM data */
-- snd_mask_none(fmt);
-- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S32_LE);
-- /* enable DSD mode */
-- config |= NANO_CFG_DSD;
-- }
--
-- /* configure clocks */
-- switch (params_rate(params)) {
-- case 44100:
-- config |= NANO_CFG_MULT1 | NANO_CFG_CLK22;
-- break;
-- case 88200:
-- config |= NANO_CFG_MULT2 | NANO_CFG_CLK22;
-- break;
-- case 176400:
-- config |= NANO_CFG_MULT4 | NANO_CFG_CLK22;
-- break;
-- case 352800:
-- config |= NANO_CFG_MULT8 | NANO_CFG_CLK22;
-- break;
-- case 705600:
-- config |= NANO_CFG_MULT16 | NANO_CFG_CLK22;
-- break;
-- case 48000:
-- config |= NANO_CFG_MULT1 | NANO_CFG_CLK24;
-- break;
-- case 96000:
-- config |= NANO_CFG_MULT2 | NANO_CFG_CLK24;
-- break;
-- case 192000:
-- config |= NANO_CFG_MULT4 | NANO_CFG_CLK24;
-- break;
-- case 384000:
-- config |= NANO_CFG_MULT8 | NANO_CFG_CLK24;
-- break;
-- case 768000:
-- config |= NANO_CFG_MULT16 | NANO_CFG_CLK24;
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- dev_dbg(card->dev, "Send CFG register 0x%02X\n", config);
-- return regmap_write(regmap, NANO_CFG, config);
--}
--
--static struct snd_soc_ops nano_player_ops = {
-- .startup = nano_player_startup,
-- .hw_params = nano_player_hw_params,
--};
--
--static struct snd_soc_dai_link nano_player_link = {
-- .name = "3Dlab Nano Player",
-- .stream_name = "3Dlab Nano Player HiFi",
-- .platform_name = "bcm2708-i2s.0",
-- .cpu_dai_name = "bcm2708-i2s.0",
-- .codec_name = "snd-soc-dummy",
-- .codec_dai_name = "snd-soc-dummy-dai",
-- .dai_fmt = SND_SOC_DAIFMT_I2S |
-- SND_SOC_DAIFMT_CONT |
-- SND_SOC_DAIFMT_NB_NF |
-- SND_SOC_DAIFMT_CBM_CFM,
-- .init = nano_player_init,
-- .ops = &nano_player_ops,
--};
--
--static const struct regmap_config nano_player_regmap = {
-- .reg_bits = 8,
-- .val_bits = 8,
-- .max_register = 128,
-- .cache_type = REGCACHE_RBTREE,
--};
--
--static int nano_player_card_probe(struct snd_soc_card *card)
--{
-- struct regmap *regmap = snd_soc_card_get_drvdata(card);
-- unsigned int val;
--
-- /* check hardware integrity */
-- regmap_read(regmap, NANO_ID, &val);
-- if (val != NANO_ID_VAL) {
-- dev_err(card->dev, "Invalid ID register 0x%02X\n", val);
-- return -ENODEV;
-- }
--
-- /* report version to the user */
-- regmap_read(regmap, NANO_VER, &val);
-- dev_notice(card->dev, "Started 3Dlab Nano Player driver (v%d)\n", val);
--
-- /* enable internal audio bus and blink status LED */
-- return regmap_write(regmap, NANO_CFG, NANO_CFG_ENA | NANO_CFG_BLINK);
--}
--
--static int nano_player_card_remove(struct snd_soc_card *card)
--{
-- /* disable internal audio bus */
-- struct regmap *regmap = snd_soc_card_get_drvdata(card);
--
-- return regmap_write(regmap, NANO_CFG, NANO_CFG_OFF);
--}
--
--static struct snd_soc_card nano_player_card = {
-- .name = "3Dlab_Nano_Player",
-- .owner = THIS_MODULE,
-- .dai_link = &nano_player_link,
-- .num_links = 1,
-- .controls = nano_player_controls,
-- .num_controls = ARRAY_SIZE(nano_player_controls),
-- .probe = nano_player_card_probe,
-- .remove = nano_player_card_remove,
--};
--
--static int nano_player_i2c_probe(struct i2c_client *i2c,
-- const struct i2c_device_id *id)
--{
-- struct regmap *regmap;
-- int ret;
--
-- regmap = devm_regmap_init_i2c(i2c, &nano_player_regmap);
-- if (IS_ERR(regmap)) {
-- ret = PTR_ERR(regmap);
-- dev_err(&i2c->dev, "Failed to init regmap %d\n", ret);
-- return ret;
-- }
--
-- if (i2c->dev.of_node) {
-- struct snd_soc_dai_link *dai = &nano_player_link;
-- struct device_node *node;
--
-- /* cpu handle configured by device tree */
-- node = of_parse_phandle(i2c->dev.of_node, "i2s-controller", 0);
-- if (node) {
-- dai->platform_name = NULL;
-- dai->platform_of_node = node;
-- dai->cpu_dai_name = NULL;
-- dai->cpu_of_node = node;
-- }
-- }
--
-- nano_player_card.dev = &i2c->dev;
-- snd_soc_card_set_drvdata(&nano_player_card, regmap);
-- ret = devm_snd_soc_register_card(&i2c->dev, &nano_player_card);
--
-- if (ret && ret != -EPROBE_DEFER)
-- dev_err(&i2c->dev, "Failed to register card %d\n", ret);
--
-- return ret;
--}
--
--static const struct of_device_id nano_player_of_match[] = {
-- { .compatible = "3dlab,nano-player", },
-- { }
--};
--MODULE_DEVICE_TABLE(of, nano_player_of_match);
--
--static const struct i2c_device_id nano_player_i2c_id[] = {
-- { "nano-player", 0 },
-- { }
--};
--MODULE_DEVICE_TABLE(i2c, nano_player_i2c_id);
--
--static struct i2c_driver nano_player_i2c_driver = {
-- .probe = nano_player_i2c_probe,
-- .id_table = nano_player_i2c_id,
-- .driver = {
-- .name = "nano-player",
-- .owner = THIS_MODULE,
-- .of_match_table = nano_player_of_match,
-- },
--};
--
--module_i2c_driver(nano_player_i2c_driver);
--
--MODULE_DESCRIPTION("ASoC 3Dlab Nano Player driver");
--MODULE_LICENSE("GPL v2");
--
--/* EOF */
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -17,12 +17,6 @@ config SND_SOC_CYGNUS
-
- If you don't know what to do here, say N.
-
--config SND_BCM2708_SOC_3DLAB_NANO_PLAYER
-- tristate "Support for 3Dlab Nano Player"
-- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-- help
-- Say Y or M if you want to add support for 3Dlab Nano Player.
--
- config SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD
- tristate "Support for Google voiceHAT soundcard"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -12,7 +12,6 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-
- snd-soc-googlevoicehat-codec-objs := googlevoicehat-codec.o
-
- # BCM2708 Machine Support
--snd-soc-3dlab-nano-player-objs := 3dlab-nano-player.o
- snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
- snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
- snd-soc-justboom-dac-objs := justboom-dac.o
-@@ -20,7 +19,7 @@ snd-soc-rpi-cirrus-objs := rpi-cirrus.o
- snd-soc-rpi-proto-objs := rpi-proto.o
- snd-soc-iqaudio-codec-objs := iqaudio-codec.o
- snd-soc-iqaudio-dac-objs := iqaudio-dac.o
-- snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o
-+snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o
- snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
- snd-soc-audioinjector-octo-soundcard-objs := audioinjector-octo-soundcard.o
- snd-soc-audiosense-pi-objs := audiosense-pi.o
-@@ -36,7 +35,6 @@ snd-soc-fe-pi-audio-objs := fe-pi-audio.
- snd-soc-rpi-simple-soundcard-objs := rpi-simple-soundcard.o
- snd-soc-rpi-wm8804-soundcard-objs := rpi-wm8804-soundcard.o
-
--obj-$(CONFIG_SND_BCM2708_SOC_3DLAB_NANO_PLAYER) += snd-soc-3dlab-nano-player.o
- obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
-@@ -45,7 +43,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS)
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
- obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC) += snd-soc-iqaudio-codec.o
- obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
-- obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o
-+obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o
- obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o
- obj-$(CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD) += snd-soc-audioinjector-octo-soundcard.o
- obj-$(CONFIG_SND_AUDIOSENSE_PI) += snd-soc-audiosense-pi.o
--- /dev/null
+From 83f0a8986ae42e33bc16acda0451dce2cf4dfb55 Mon Sep 17 00:00:00 2001
+Date: Wed, 22 May 2019 09:05:40 +0200
+Subject: [PATCH] Bluetooth: Check key sizes only when Secure Simple
+ Pairing is enabled
+
+The encryption is only mandatory to be enforced when both sides are using
+Secure Simple Pairing and this means the key size check makes only sense
+in that case.
+
+On legacy Bluetooth 2.0 and earlier devices like mice the encryption was
+optional and thus causing an issue if the key size check is not bound to
+using Secure Simple Pairing.
+
+Fixes: d5bb334a8e17 ("Bluetooth: Align minimum encryption key size for LE and BR/EDR connections")
+---
+ net/bluetooth/hci_conn.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/net/bluetooth/hci_conn.c
++++ b/net/bluetooth/hci_conn.c
+@@ -1282,8 +1282,13 @@ int hci_conn_check_link_mode(struct hci_
+ return 0;
+ }
+
+- if (hci_conn_ssp_enabled(conn) &&
+- !test_bit(HCI_CONN_ENCRYPT, &conn->flags))
++ /* If Secure Simple Pairing is not enabled, then legacy connection
++ * setup is used and no encryption or key sizes can be enforced.
++ */
++ if (!hci_conn_ssp_enabled(conn))
++ return 1;
++
++ if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
+ return 0;
+
+ return 1;
+++ /dev/null
-From bd4e0a6ad64c1211094776923bf61bd6ede3f043 Mon Sep 17 00:00:00 2001
-Date: Tue, 21 May 2019 15:17:33 +0100
-Subject: [PATCH] .gitignore: Add *.dtbo explicitly
-
----
- .gitignore | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/.gitignore
-+++ b/.gitignore
-@@ -15,7 +15,8 @@
- *.bin
- *.bz2
- *.c.[012]*.*
--*.dtb*
-+*.dtb
-+*.dtbo
- *.dtb.S
- *.dwo
- *.elf
--- /dev/null
+From efb54d0f0445f3d279a7eae7395b566c96d080de Mon Sep 17 00:00:00 2001
+Date: Tue, 7 May 2019 17:23:41 +0100
+Subject: [PATCH] usb: dwc_otg: Clean up interrupt claiming code
+
+The FIQ/IRQ interrupt number identification code is scattered through
+the dwc_otg driver. Rationalise it, simplifying the code and solving
+an existing issue.
+
+See: https://github.com/raspberrypi/linux/issues/2612
+
+---
+ drivers/usb/host/dwc_otg/dwc_otg_driver.c | 18 +++++++++-----
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 10 +++-----
+ drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 6 +++++
+ drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c | 26 +++-----------------
+ 4 files changed, 25 insertions(+), 35 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
+@@ -624,11 +624,7 @@ static int dwc_otg_driver_remove(
+ * Free the IRQ
+ */
+ if (otg_dev->common_irq_installed) {
+-#ifdef PLATFORM_INTERFACE
+- free_irq(platform_get_irq(_dev, 0), otg_dev);
+-#else
+- free_irq(_dev->irq, otg_dev);
+-#endif
++ free_irq(otg_dev->os_dep.irq_num, otg_dev);
+ } else {
+ DWC_DEBUGPL(DBG_ANY, "%s: There is no installed irq!\n", __func__);
+ return REM_RETVAL(-ENXIO);
+@@ -905,7 +901,9 @@ static int dwc_otg_driver_probe(
+ */
+
+ #if defined(PLATFORM_INTERFACE)
+- devirq = platform_get_irq(_dev, fiq_enable ? 0 : 1);
++ devirq = platform_get_irq_byname(_dev, fiq_enable ? "soft" : "usb");
++ if (devirq < 0)
++ devirq = platform_get_irq(_dev, fiq_enable ? 0 : 1);
+ #else
+ devirq = _dev->irq;
+ #endif
+@@ -922,6 +920,14 @@ static int dwc_otg_driver_probe(
+ } else {
+ dwc_otg_device->common_irq_installed = 1;
+ }
++ dwc_otg_device->os_dep.irq_num = devirq;
++ dwc_otg_device->os_dep.fiq_num = -EINVAL;
++ if (fiq_enable) {
++ int devfiq = platform_get_irq_byname(_dev, "usb");
++ if (devfiq < 0)
++ devfiq = platform_get_irq(_dev, 1);
++ dwc_otg_device->os_dep.fiq_num = devfiq;
++ }
+
+ #ifndef IRQF_TRIGGER_LOW
+ #if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
+@@ -492,7 +492,7 @@ static void hcd_init_fiq(void *cookie)
+ #endif
+ // Enable FIQ interrupt from USB peripheral
+ #ifdef CONFIG_ARM64
+- irq = platform_get_irq(otg_dev->os_dep.platformdev, 1);
++ irq = otg_dev->os_dep.fiq_num;
+
+ if (irq < 0) {
+ DWC_ERROR("Can't get SIM-FIQ irq");
+@@ -509,7 +509,7 @@ static void hcd_init_fiq(void *cookie)
+ simfiq_irq = irq;
+ #else
+ #ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER
+- irq = platform_get_irq(otg_dev->os_dep.platformdev, 1);
++ irq = otg_dev->os_dep.fiq_num;
+ #else
+ irq = INTERRUPT_VC_USB;
+ #endif
+@@ -626,11 +626,7 @@ int hcd_init(dwc_bus_dev_t *_dev)
+ * allocates the DMA buffer pool, registers the USB bus, requests the
+ * IRQ line, and calls hcd_start method.
+ */
+-#ifdef PLATFORM_INTERFACE
+- retval = usb_add_hcd(hcd, platform_get_irq(_dev, fiq_enable ? 0 : 1), IRQF_SHARED);
+-#else
+- retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED);
+-#endif
++ retval = usb_add_hcd(hcd, otg_dev->os_dep.irq_num, IRQF_SHARED);
+ if (retval < 0) {
+ goto error2;
+ }
+--- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
++++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
+@@ -102,6 +102,12 @@ typedef struct os_dependent {
+ /** Base address for MPHI peripheral */
+ void *mphi_base;
+
++ /** IRQ number (<0 if not valid) */
++ int irq_num;
++
++ /** FIQ number (<0 if not valid) */
++ int fiq_num;
++
+ #ifdef LM_INTERFACE
+ struct lm_device *lmdev;
+ #elif defined(PCI_INTERFACE)
+--- a/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
+@@ -1224,30 +1224,16 @@ int pcd_init(dwc_bus_dev_t *_dev)
+ /*
+ * Setup interupt handler
+ */
+-#ifdef PLATFORM_INTERFACE
+ DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
+- platform_get_irq(_dev, fiq_enable ? 0 : 1));
+- retval = request_irq(platform_get_irq(_dev, fiq_enable ? 0 : 1), dwc_otg_pcd_irq,
++ otg_dev->os_dep.irq_num);
++ retval = request_irq(otg_dev->os_dep.irq_num, dwc_otg_pcd_irq,
+ IRQF_SHARED, gadget_wrapper->gadget.name,
+ otg_dev->pcd);
+ if (retval != 0) {
+- DWC_ERROR("request of irq%d failed\n",
+- platform_get_irq(_dev, fiq_enable ? 0 : 1));
++ DWC_ERROR("request of irq%d failed\n", otg_dev->os_dep.irq_num);
+ free_wrapper(gadget_wrapper);
+ return -EBUSY;
+ }
+-#else
+- DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
+- _dev->irq);
+- retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
+- IRQF_SHARED | IRQF_DISABLED,
+- gadget_wrapper->gadget.name, otg_dev->pcd);
+- if (retval != 0) {
+- DWC_ERROR("request of irq%d failed\n", _dev->irq);
+- free_wrapper(gadget_wrapper);
+- return -EBUSY;
+- }
+-#endif
+
+ dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
+
+@@ -1267,11 +1253,7 @@ void pcd_remove(dwc_bus_dev_t *_dev)
+ /*
+ * Free the IRQ
+ */
+-#ifdef PLATFORM_INTERFACE
+- free_irq(platform_get_irq(_dev, 0), pcd);
+-#else
+- free_irq(_dev->irq, pcd);
+-#endif
++ free_irq(otg_dev->os_dep.irq_num, pcd);
+ dwc_otg_pcd_remove(otg_dev->pcd);
+ free_wrapper(gadget_wrapper);
+ otg_dev->pcd = 0;
+++ /dev/null
-From 83f0a8986ae42e33bc16acda0451dce2cf4dfb55 Mon Sep 17 00:00:00 2001
-Date: Wed, 22 May 2019 09:05:40 +0200
-Subject: [PATCH] Bluetooth: Check key sizes only when Secure Simple
- Pairing is enabled
-
-The encryption is only mandatory to be enforced when both sides are using
-Secure Simple Pairing and this means the key size check makes only sense
-in that case.
-
-On legacy Bluetooth 2.0 and earlier devices like mice the encryption was
-optional and thus causing an issue if the key size check is not bound to
-using Secure Simple Pairing.
-
-Fixes: d5bb334a8e17 ("Bluetooth: Align minimum encryption key size for LE and BR/EDR connections")
----
- net/bluetooth/hci_conn.c | 9 +++++++--
- 1 file changed, 7 insertions(+), 2 deletions(-)
-
---- a/net/bluetooth/hci_conn.c
-+++ b/net/bluetooth/hci_conn.c
-@@ -1282,8 +1282,13 @@ int hci_conn_check_link_mode(struct hci_
- return 0;
- }
-
-- if (hci_conn_ssp_enabled(conn) &&
-- !test_bit(HCI_CONN_ENCRYPT, &conn->flags))
-+ /* If Secure Simple Pairing is not enabled, then legacy connection
-+ * setup is used and no encryption or key sizes can be enforced.
-+ */
-+ if (!hci_conn_ssp_enabled(conn))
-+ return 1;
-+
-+ if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
- return 0;
-
- return 1;
--- /dev/null
+From 5edb8789ba5f9694698386683f2e4e97c70e765a Mon Sep 17 00:00:00 2001
+Date: Tue, 7 May 2019 14:27:35 +0100
+Subject: [PATCH] overlays: Delete the deprecated sdio-1bit overlay
+
+Use dtoverlay=sdio,bus_width=1,gpios_22_25 instead.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 -
+ .../boot/dts/overlays/sdio-1bit-overlay.dts | 63 -------------------
+ 2 files changed, 64 deletions(-)
+ delete mode 100644 arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -126,7 +126,6 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ sc16is752-spi1.dtbo \
+ sdhost.dtbo \
+ sdio.dtbo \
+- sdio-1bit.dtbo \
+ sdtweak.dtbo \
+ smi.dtbo \
+ smi-dev.dtbo \
+--- a/arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts
++++ /dev/null
+@@ -1,63 +0,0 @@
+-/dts-v1/;
+-/plugin/;
+-
+-/* Enable 1-bit SDIO from MMC interface via GPIOs 22-25. Includes sdhost overlay. */
+-
+-/{
+- compatible = "brcm,bcm2708";
+-
+- fragment@0 {
+- target = <&mmc>;
+- __overlay__ {
+- status = "disabled";
+- };
+- };
+-
+- fragment@1 {
+- target = <&soc>;
+- __overlay__ {
+- #address-cells = <1>;
+- #size-cells = <1>;
+-
+- sdio_1bit: sdio@7e300000 {
+- compatible = "brcm,bcm2835-mmc",
+- "brcm,bcm2835-sdhci";
+- reg = <0x7e300000 0x100>;
+- interrupts = <2 30>;
+- clocks = <&clocks 28/*BCM2835_CLOCK_EMMC*/>;
+- dmas = <&dma 11>;
+- dma-names = "rx-tx";
+- brcm,overclock-50 = <0>;
+- status = "okay";
+- pinctrl-names = "default";
+- pinctrl-0 = <&sdio_1bit_pins>;
+- non-removable;
+- bus-width = <1>;
+- };
+- };
+- };
+-
+- fragment@2 {
+- target = <&gpio>;
+- __overlay__ {
+- sdio_1bit_pins: sdio_1bit_pins {
+- brcm,pins = <22 23 24 25>;
+- brcm,function = <7>; /* ALT3 = SD1 */
+- brcm,pull = <0 2 2 2>;
+- };
+- };
+- };
+-
+- fragment@3 {
+- target-path = "/aliases";
+- __overlay__ {
+- mmc1 = "/soc/sdio@7e300000";
+- };
+- };
+-
+-
+- __overrides__ {
+- poll_once = <&sdio_1bit>,"non-removable?";
+- sdio_overclock = <&sdio_1bit>,"brcm,overclock-50:0";
+- };
+-};
--- /dev/null
+From 2b584d25f295e07ef58efc2a60057be58015d693 Mon Sep 17 00:00:00 2001
+Date: Tue, 7 May 2019 10:06:04 +0100
+Subject: [PATCH] overlays: Remove upstream-aux-interrupt overlay
+
+We no longer have a downstream-specific auxilliary interrupt
+driver, so the overlay to disable it is no longer needed.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 -
+ arch/arm/boot/dts/overlays/README | 12 +++----
+ .../upstream-aux-interrupt-overlay.dts | 33 -------------------
+ .../boot/dts/overlays/upstream-overlay.dts | 2 +-
+ 4 files changed, 6 insertions(+), 42 deletions(-)
+ delete mode 100644 arch/arm/boot/dts/overlays/upstream-aux-interrupt-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -151,7 +151,6 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ uart1.dtbo \
+ udrc.dtbo \
+ upstream.dtbo \
+- upstream-aux-interrupt.dtbo \
+ vc4-fkms-v3d.dtbo \
+ vc4-kms-kippah-7inch.dtbo \
+ vc4-kms-v3d.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2206,18 +2206,16 @@ Params: alsaname Name of
+
+
+ Name: upstream
+-Info: Allow usage of downstream .dtb with upstream kernel. Comprises
+- vc4-kms-v3d, dwc2 and upstream-aux-interrupt overlays.
++Info: Allow usage of downstream .dtb with upstream kernel. Comprises the
++ vc4-kms-v3d and dwc2 overlays.
+ Load: dtoverlay=upstream
+ Params: <None>
+
+
+ Name: upstream-aux-interrupt
+-Info: Allow usage of downstream .dtb with upstream kernel by binding AUX
+- devices directly to the shared AUX interrupt line. One of the parts
+- of the 'upstream' overlay
+-Load: dtoverlay=upstream-aux-interrupt
+-Params: <None>
++Info: This overlay has been deprecated and removed because it is no longer
++ necessary.
++Load: <Deprecated>
+
+
+ Name: vc4-fkms-v3d
+--- a/arch/arm/boot/dts/overlays/upstream-aux-interrupt-overlay.dts
++++ /dev/null
+@@ -1,33 +0,0 @@
+-// Overlay for missing AUX interrupt controller
+-// Instead we bind all AUX devices to the generic AUX interrupt line
+-/dts-v1/;
+-/plugin/;
+-
+-/ {
+- compatible = "brcm,bcm2708";
+-
+- fragment@0 {
+- target = <&uart1>;
+- __overlay__ {
+- interrupt-parent = <&intc>;
+- interrupts = <0x1 0x1d>;
+- };
+- };
+-
+- fragment@1 {
+- target = <&spi1>;
+- __overlay__ {
+- interrupt-parent = <&intc>;
+- interrupts = <0x1 0x1d>;
+- };
+- };
+-
+- fragment@2 {
+- target = <&spi2>;
+- __overlay__ {
+- interrupt-parent = <&intc>;
+- interrupts = <0x1 0x1d>;
+- };
+- };
+-};
+-
+--- 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-96 dwc2-overlay.dts,dr_mode=otg upstream-aux-interrupt-overlay.dts,
++// redo: ovmerge -c vc4-kms-v3d-overlay.dts,cma-96 dwc2-overlay.dts,dr_mode=otg
+
+ /dts-v1/;
+ /plugin/;
+++ /dev/null
-From efb54d0f0445f3d279a7eae7395b566c96d080de Mon Sep 17 00:00:00 2001
-Date: Tue, 7 May 2019 17:23:41 +0100
-Subject: [PATCH] usb: dwc_otg: Clean up interrupt claiming code
-
-The FIQ/IRQ interrupt number identification code is scattered through
-the dwc_otg driver. Rationalise it, simplifying the code and solving
-an existing issue.
-
-See: https://github.com/raspberrypi/linux/issues/2612
-
----
- drivers/usb/host/dwc_otg/dwc_otg_driver.c | 18 +++++++++-----
- drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 10 +++-----
- drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 6 +++++
- drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c | 26 +++-----------------
- 4 files changed, 25 insertions(+), 35 deletions(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
-@@ -624,11 +624,7 @@ static int dwc_otg_driver_remove(
- * Free the IRQ
- */
- if (otg_dev->common_irq_installed) {
--#ifdef PLATFORM_INTERFACE
-- free_irq(platform_get_irq(_dev, 0), otg_dev);
--#else
-- free_irq(_dev->irq, otg_dev);
--#endif
-+ free_irq(otg_dev->os_dep.irq_num, otg_dev);
- } else {
- DWC_DEBUGPL(DBG_ANY, "%s: There is no installed irq!\n", __func__);
- return REM_RETVAL(-ENXIO);
-@@ -905,7 +901,9 @@ static int dwc_otg_driver_probe(
- */
-
- #if defined(PLATFORM_INTERFACE)
-- devirq = platform_get_irq(_dev, fiq_enable ? 0 : 1);
-+ devirq = platform_get_irq_byname(_dev, fiq_enable ? "soft" : "usb");
-+ if (devirq < 0)
-+ devirq = platform_get_irq(_dev, fiq_enable ? 0 : 1);
- #else
- devirq = _dev->irq;
- #endif
-@@ -922,6 +920,14 @@ static int dwc_otg_driver_probe(
- } else {
- dwc_otg_device->common_irq_installed = 1;
- }
-+ dwc_otg_device->os_dep.irq_num = devirq;
-+ dwc_otg_device->os_dep.fiq_num = -EINVAL;
-+ if (fiq_enable) {
-+ int devfiq = platform_get_irq_byname(_dev, "usb");
-+ if (devfiq < 0)
-+ devfiq = platform_get_irq(_dev, 1);
-+ dwc_otg_device->os_dep.fiq_num = devfiq;
-+ }
-
- #ifndef IRQF_TRIGGER_LOW
- #if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-@@ -492,7 +492,7 @@ static void hcd_init_fiq(void *cookie)
- #endif
- // Enable FIQ interrupt from USB peripheral
- #ifdef CONFIG_ARM64
-- irq = platform_get_irq(otg_dev->os_dep.platformdev, 1);
-+ irq = otg_dev->os_dep.fiq_num;
-
- if (irq < 0) {
- DWC_ERROR("Can't get SIM-FIQ irq");
-@@ -509,7 +509,7 @@ static void hcd_init_fiq(void *cookie)
- simfiq_irq = irq;
- #else
- #ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER
-- irq = platform_get_irq(otg_dev->os_dep.platformdev, 1);
-+ irq = otg_dev->os_dep.fiq_num;
- #else
- irq = INTERRUPT_VC_USB;
- #endif
-@@ -626,11 +626,7 @@ int hcd_init(dwc_bus_dev_t *_dev)
- * allocates the DMA buffer pool, registers the USB bus, requests the
- * IRQ line, and calls hcd_start method.
- */
--#ifdef PLATFORM_INTERFACE
-- retval = usb_add_hcd(hcd, platform_get_irq(_dev, fiq_enable ? 0 : 1), IRQF_SHARED);
--#else
-- retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED);
--#endif
-+ retval = usb_add_hcd(hcd, otg_dev->os_dep.irq_num, IRQF_SHARED);
- if (retval < 0) {
- goto error2;
- }
---- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
-@@ -102,6 +102,12 @@ typedef struct os_dependent {
- /** Base address for MPHI peripheral */
- void *mphi_base;
-
-+ /** IRQ number (<0 if not valid) */
-+ int irq_num;
-+
-+ /** FIQ number (<0 if not valid) */
-+ int fiq_num;
-+
- #ifdef LM_INTERFACE
- struct lm_device *lmdev;
- #elif defined(PCI_INTERFACE)
---- a/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
-@@ -1224,30 +1224,16 @@ int pcd_init(dwc_bus_dev_t *_dev)
- /*
- * Setup interupt handler
- */
--#ifdef PLATFORM_INTERFACE
- DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
-- platform_get_irq(_dev, fiq_enable ? 0 : 1));
-- retval = request_irq(platform_get_irq(_dev, fiq_enable ? 0 : 1), dwc_otg_pcd_irq,
-+ otg_dev->os_dep.irq_num);
-+ retval = request_irq(otg_dev->os_dep.irq_num, dwc_otg_pcd_irq,
- IRQF_SHARED, gadget_wrapper->gadget.name,
- otg_dev->pcd);
- if (retval != 0) {
-- DWC_ERROR("request of irq%d failed\n",
-- platform_get_irq(_dev, fiq_enable ? 0 : 1));
-+ DWC_ERROR("request of irq%d failed\n", otg_dev->os_dep.irq_num);
- free_wrapper(gadget_wrapper);
- return -EBUSY;
- }
--#else
-- DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
-- _dev->irq);
-- retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
-- IRQF_SHARED | IRQF_DISABLED,
-- gadget_wrapper->gadget.name, otg_dev->pcd);
-- if (retval != 0) {
-- DWC_ERROR("request of irq%d failed\n", _dev->irq);
-- free_wrapper(gadget_wrapper);
-- return -EBUSY;
-- }
--#endif
-
- dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
-
-@@ -1267,11 +1253,7 @@ void pcd_remove(dwc_bus_dev_t *_dev)
- /*
- * Free the IRQ
- */
--#ifdef PLATFORM_INTERFACE
-- free_irq(platform_get_irq(_dev, 0), pcd);
--#else
-- free_irq(_dev->irq, pcd);
--#endif
-+ free_irq(otg_dev->os_dep.irq_num, pcd);
- dwc_otg_pcd_remove(otg_dev->pcd);
- free_wrapper(gadget_wrapper);
- otg_dev->pcd = 0;
+++ /dev/null
-From 5edb8789ba5f9694698386683f2e4e97c70e765a Mon Sep 17 00:00:00 2001
-Date: Tue, 7 May 2019 14:27:35 +0100
-Subject: [PATCH] overlays: Delete the deprecated sdio-1bit overlay
-
-Use dtoverlay=sdio,bus_width=1,gpios_22_25 instead.
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 -
- .../boot/dts/overlays/sdio-1bit-overlay.dts | 63 -------------------
- 2 files changed, 64 deletions(-)
- delete mode 100644 arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -126,7 +126,6 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- sc16is752-spi1.dtbo \
- sdhost.dtbo \
- sdio.dtbo \
-- sdio-1bit.dtbo \
- sdtweak.dtbo \
- smi.dtbo \
- smi-dev.dtbo \
---- a/arch/arm/boot/dts/overlays/sdio-1bit-overlay.dts
-+++ /dev/null
-@@ -1,63 +0,0 @@
--/dts-v1/;
--/plugin/;
--
--/* Enable 1-bit SDIO from MMC interface via GPIOs 22-25. Includes sdhost overlay. */
--
--/{
-- compatible = "brcm,bcm2708";
--
-- fragment@0 {
-- target = <&mmc>;
-- __overlay__ {
-- status = "disabled";
-- };
-- };
--
-- fragment@1 {
-- target = <&soc>;
-- __overlay__ {
-- #address-cells = <1>;
-- #size-cells = <1>;
--
-- sdio_1bit: sdio@7e300000 {
-- compatible = "brcm,bcm2835-mmc",
-- "brcm,bcm2835-sdhci";
-- reg = <0x7e300000 0x100>;
-- interrupts = <2 30>;
-- clocks = <&clocks 28/*BCM2835_CLOCK_EMMC*/>;
-- dmas = <&dma 11>;
-- dma-names = "rx-tx";
-- brcm,overclock-50 = <0>;
-- status = "okay";
-- pinctrl-names = "default";
-- pinctrl-0 = <&sdio_1bit_pins>;
-- non-removable;
-- bus-width = <1>;
-- };
-- };
-- };
--
-- fragment@2 {
-- target = <&gpio>;
-- __overlay__ {
-- sdio_1bit_pins: sdio_1bit_pins {
-- brcm,pins = <22 23 24 25>;
-- brcm,function = <7>; /* ALT3 = SD1 */
-- brcm,pull = <0 2 2 2>;
-- };
-- };
-- };
--
-- fragment@3 {
-- target-path = "/aliases";
-- __overlay__ {
-- mmc1 = "/soc/sdio@7e300000";
-- };
-- };
--
--
-- __overrides__ {
-- poll_once = <&sdio_1bit>,"non-removable?";
-- sdio_overclock = <&sdio_1bit>,"brcm,overclock-50:0";
-- };
--};
--- /dev/null
+From ba6646d6bc62108f33a7a3e95367534a0a634beb Mon Sep 17 00:00:00 2001
+Date: Tue, 14 May 2019 13:33:05 +0100
+Subject: [PATCH] overlays: Standardise on compatible="brcm,bcm2835"
+
+Curb the proliferation of compatible string combinations by
+standardising on "brcm,bcm2835" to denote BCM2835 and its descendants.
+
+As nothing in the firmware or kernel is checking overlay compatible
+strings, this should be a purely cosmetic change.
+
+---
+ arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/ads1015-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/ads1115-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/ads7846-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/adv7282m-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/adv728x-m-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts | 2 +-
+ .../boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/allo-digione-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts | 2 +-
+ .../boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts | 2 +-
+ .../dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/applepi-dac-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts | 2 +-
+ .../boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/audremap-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/balena-fin-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/dht11-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/dpi18-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/dpi24-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/draws-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/dwc-otg-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/dwc2-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/enc28j60-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/enc28j60-spi2-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/exc3000-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/goodix-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/gpio-fan-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/gpio-ir-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/gpio-ir-tx-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/gpio-key-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hy28a-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hy28b-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c-bcm2708-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c-mux-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/ilitek251x-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts | 2 +-
+ .../arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/justboom-dac-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/justboom-digi-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/max98357a-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/mbed-dac-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/mcp23s17-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/mcp3008-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/mcp3202-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/mcp342x-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/media-center-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/mmc-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/mpu6050-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/ov5647-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/papirus-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pibell-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/piglow-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/piscreen-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/piscreen2r-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pisound-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pitft22-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pps-gpio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/qca7000-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/rpi-dac-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/rpi-display-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/rpi-poe-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/rpi-proto-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/rpi-sense-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/rpi-tv-overlay.dts | 2 +-
+ .../arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/sc16is752-spi1-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/sdhost-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/sdio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/sdtweak-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/smi-nand-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/smi-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi-rtc-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi0-cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi0-hw-cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/ssd1306-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/superaudioboard-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/sx150x-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/tc358743-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/tinylcd35-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/uart0-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/uart1-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/udrc-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/upstream-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/vga666-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/w1-gpio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/wittypi-overlay.dts | 2 +-
+ 146 files changed, 146 insertions(+), 146 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c>;
+--- a/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts
++++ b/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/ads1015-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ads1015-overlay.dts
+@@ -5,7 +5,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+ /* ----------- ADS1015 ------------ */
+ fragment@0 {
+ target = <&i2c_arm>;
+--- a/arch/arm/boot/dts/overlays/ads1115-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ads1115-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_arm>;
+--- a/arch/arm/boot/dts/overlays/ads7846-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ads7846-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/adv7282m-overlay.dts
++++ b/arch/arm/boot/dts/overlays/adv7282m-overlay.dts
+@@ -4,7 +4,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_vc>;
+--- a/arch/arm/boot/dts/overlays/adv728x-m-overlay.dts
++++ b/arch/arm/boot/dts/overlays/adv728x-m-overlay.dts
+@@ -5,7 +5,7 @@
+ #include "adv7282m-overlay.dts"
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ // Fragment numbers deliberately high to avoid conflicts with the
+ // included adv7282m overlay file.
+--- a/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/clocks";
+--- a/arch/arm/boot/dts/overlays/allo-digione-overlay.dts
++++ b/arch/arm/boot/dts/overlays/allo-digione-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts
+@@ -13,7 +13,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&sound>;
+--- a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
++++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
+@@ -4,7 +4,7 @@
+ /* Overlay for Atmel AT86RF233 IEEE 802.15.4 WPAN transceiver on spi0.0 */
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
++++ b/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts
++++ b/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts
+@@ -5,7 +5,7 @@
+ #include <dt-bindings/gpio/gpio.h>
+
+ / {
+- compatible = "brcm,bcm2837", "brcm,bcm2836", "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/audremap-overlay.dts
++++ b/arch/arm/boot/dts/overlays/audremap-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&audio_pins>;
+--- a/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
++++ b/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&mmc>;
+--- a/arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts
++++ b/arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_arm>;
+--- a/arch/arm/boot/dts/overlays/dht11-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dht11-overlay.dts
+@@ -5,7 +5,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts
+@@ -8,7 +8,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts
+@@ -9,7 +9,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&sound>;
+--- a/arch/arm/boot/dts/overlays/dpi18-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dpi18-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ // There is no DPI driver module, but we need a platform device
+ // node (that doesn't already use pinctrl) to hang the pinctrl
+--- a/arch/arm/boot/dts/overlays/dpi24-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dpi24-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ // There is no DPI driver module, but we need a platform device
+ // node (that doesn't already use pinctrl) to hang the pinctrl
+--- a/arch/arm/boot/dts/overlays/draws-overlay.dts
++++ b/arch/arm/boot/dts/overlays/draws-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+ fragment@0 {
+ target = <&i2s>;
+ __overlay__ {
+--- a/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&usb>;
+--- a/arch/arm/boot/dts/overlays/dwc2-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&usb>;
+--- a/arch/arm/boot/dts/overlays/enc28j60-overlay.dts
++++ b/arch/arm/boot/dts/overlays/enc28j60-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/enc28j60-spi2-overlay.dts
++++ b/arch/arm/boot/dts/overlays/enc28j60-spi2-overlay.dts
+@@ -4,7 +4,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi2>;
+--- a/arch/arm/boot/dts/overlays/exc3000-overlay.dts
++++ b/arch/arm/boot/dts/overlays/exc3000-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&clocks>;
+--- a/arch/arm/boot/dts/overlays/goodix-overlay.dts
++++ b/arch/arm/boot/dts/overlays/goodix-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts
++++ b/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts
+@@ -38,7 +38,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/gpio-ir-tx-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-ir-tx-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/gpio-key-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-key-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ // Configure the gpio pin controller
+--- a/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts
+@@ -10,7 +10,7 @@
+ // note that GPIO3 has an external pullup on at least some boards).
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ // Configure the gpio pin controller
+--- a/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/clocks";
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/clocks";
+--- a/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/hy28a-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hy28a-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/hy28b-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hy28b-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&sound>;
+--- a/arch/arm/boot/dts/overlays/i2c-bcm2708-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-bcm2708-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_arm>;
+--- a/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts
+@@ -4,7 +4,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_arm>;
+--- a/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_arm>;
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
+@@ -4,7 +4,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_arm>;
+--- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_arm>;
+--- a/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
+@@ -9,7 +9,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c0>;
+--- a/arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts
+@@ -9,7 +9,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c1>;
+--- a/arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s_pins>;
+--- a/arch/arm/boot/dts/overlays/ilitek251x-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ilitek251x-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts
++++ b/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts
+@@ -13,7 +13,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ // disable spi-dev on spi0.0
+ fragment@0 {
+--- a/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/max98357a-overlay.dts
++++ b/arch/arm/boot/dts/overlays/max98357a-overlay.dts
+@@ -8,7 +8,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ /* Enable I2S */
+ fragment@0 {
+--- a/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
+@@ -4,7 +4,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c1>;
+--- a/arch/arm/boot/dts/overlays/mcp23s17-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp23s17-overlay.dts
+@@ -20,7 +20,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ // disable spi-dev on spi0.0
+ fragment@0 {
+--- a/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+ /* disable spi-dev for spi0.0 */
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+ /* disable spi-dev for spi0.1 */
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/mcp3008-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp3008-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spidev0>;
+--- a/arch/arm/boot/dts/overlays/mcp3202-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp3202-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spidev0>;
+--- a/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
+@@ -4,7 +4,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c1>;
+--- a/arch/arm/boot/dts/overlays/media-center-overlay.dts
++++ b/arch/arm/boot/dts/overlays/media-center-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/mmc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&mmc>;
+--- a/arch/arm/boot/dts/overlays/mpu6050-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mpu6050-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c1>;
+--- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/ov5647-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts
+@@ -4,7 +4,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_vc>;
+--- a/arch/arm/boot/dts/overlays/papirus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/papirus-overlay.dts
+@@ -4,7 +4,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_arm>;
+--- a/arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts
+@@ -11,7 +11,7 @@
+ */
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&act_led>;
+--- a/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
+@@ -9,7 +9,7 @@
+ */
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&uart1>;
+--- a/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&mmc>;
+--- a/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
+@@ -16,7 +16,7 @@
+ */
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&uart0>;
+--- a/arch/arm/boot/dts/overlays/pibell-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pibell-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/piglow-overlay.dts
++++ b/arch/arm/boot/dts/overlays/piglow-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_arm>;
+--- a/arch/arm/boot/dts/overlays/piscreen-overlay.dts
++++ b/arch/arm/boot/dts/overlays/piscreen-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts
++++ b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/pisound-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pisound-overlay.dts
+@@ -23,7 +23,7 @@
+ #include <dt-bindings/gpio/gpio.h>
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/pitft22-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pitft22-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+ fragment@0 {
+ target-path = "/";
+ __overlay__ {
+--- a/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/qca7000-overlay.dts
++++ b/arch/arm/boot/dts/overlays/qca7000-overlay.dts
+@@ -5,7 +5,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spidev0>;
+--- a/arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
+@@ -6,7 +6,7 @@
+ #include <dt-bindings/mfd/arizona.h>
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/rpi-display-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-display-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts
+@@ -5,7 +5,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c1>;
+--- a/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts
+@@ -4,7 +4,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spidev0>;
+--- a/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_arm>;
+--- a/arch/arm/boot/dts/overlays/sc16is752-spi1-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sc16is752-spi1-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts
+@@ -4,7 +4,7 @@
+ /* Provide backwards compatible aliases for the old sdhost dtparams. */
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&sdhost>;
+--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
+@@ -4,7 +4,7 @@
+ /* Enable SDIO from MMC interface via GPIOs 22-27. Includes sdhost overlay. */
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&mmc>;
+--- a/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
+@@ -4,7 +4,7 @@
+ /* Provide backwards compatible aliases for the old sdhost dtparams. */
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&sdhost>;
+--- a/arch/arm/boot/dts/overlays/smi-nand-overlay.dts
++++ b/arch/arm/boot/dts/overlays/smi-nand-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&smi>;
+--- a/arch/arm/boot/dts/overlays/smi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/smi-overlay.dts
+@@ -5,7 +5,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&smi>;
+--- a/arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/spi-rtc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi-rtc-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spidev0>;
+--- a/arch/arm/boot/dts/overlays/spi0-cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi0-cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0_cs_pins>;
+--- a/arch/arm/boot/dts/overlays/spi0-hw-cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi0-hw-cs-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+--- a/arch/arm/boot/dts/overlays/ssd1306-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ssd1306-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2718";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c1>;
+--- a/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts
++++ b/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&sound>;
+--- a/arch/arm/boot/dts/overlays/sx150x-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sx150x-overlay.dts
+@@ -22,7 +22,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ // Enable I2C#0 interface
+ fragment@0 {
+--- a/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts
+@@ -5,7 +5,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/tc358743-overlay.dts
++++ b/arch/arm/boot/dts/overlays/tc358743-overlay.dts
+@@ -4,7 +4,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c_vc>;
+--- a/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
++++ b/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
+@@ -24,7 +24,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts
++++ b/arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts
+@@ -8,7 +8,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&spi0>;
+--- a/arch/arm/boot/dts/overlays/uart0-overlay.dts
++++ b/arch/arm/boot/dts/overlays/uart0-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&uart0>;
+--- a/arch/arm/boot/dts/overlays/uart1-overlay.dts
++++ b/arch/arm/boot/dts/overlays/uart1-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&uart1>;
+--- a/arch/arm/boot/dts/overlays/udrc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/udrc-overlay.dts
+@@ -7,7 +7,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+ fragment@0 {
+ target = <&i2s>;
+ __overlay__ {
+--- a/arch/arm/boot/dts/overlays/upstream-overlay.dts
++++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts
+@@ -6,7 +6,7 @@
+ #include <dt-bindings/clock/bcm2835.h>
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+ fragment@0 {
+ target-path = "/chosen";
+ __dormant__ {
+--- a/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts
+@@ -6,7 +6,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/chosen";
+--- a/arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts
+@@ -8,7 +8,7 @@
+ #include <dt-bindings/pinctrl/bcm2835.h>
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
+@@ -8,7 +8,7 @@
+ #include <dt-bindings/clock/bcm2835.h>
+
+ / {
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/chosen";
+--- a/arch/arm/boot/dts/overlays/vga666-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vga666-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ // There is no VGA driver module, but we need a platform device
+ // node (that doesn't already use pinctrl) to hang the pinctrl
+--- a/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
++++ b/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/";
+--- a/arch/arm/boot/dts/overlays/wittypi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/wittypi-overlay.dts
+@@ -8,7 +8,7 @@
+
+ / {
+
+- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&leds>;
+++ /dev/null
-From 2b584d25f295e07ef58efc2a60057be58015d693 Mon Sep 17 00:00:00 2001
-Date: Tue, 7 May 2019 10:06:04 +0100
-Subject: [PATCH] overlays: Remove upstream-aux-interrupt overlay
-
-We no longer have a downstream-specific auxilliary interrupt
-driver, so the overlay to disable it is no longer needed.
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 -
- arch/arm/boot/dts/overlays/README | 12 +++----
- .../upstream-aux-interrupt-overlay.dts | 33 -------------------
- .../boot/dts/overlays/upstream-overlay.dts | 2 +-
- 4 files changed, 6 insertions(+), 42 deletions(-)
- delete mode 100644 arch/arm/boot/dts/overlays/upstream-aux-interrupt-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -151,7 +151,6 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- uart1.dtbo \
- udrc.dtbo \
- upstream.dtbo \
-- upstream-aux-interrupt.dtbo \
- vc4-fkms-v3d.dtbo \
- vc4-kms-kippah-7inch.dtbo \
- vc4-kms-v3d.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -2206,18 +2206,16 @@ Params: alsaname Name of
-
-
- Name: upstream
--Info: Allow usage of downstream .dtb with upstream kernel. Comprises
-- vc4-kms-v3d, dwc2 and upstream-aux-interrupt overlays.
-+Info: Allow usage of downstream .dtb with upstream kernel. Comprises the
-+ vc4-kms-v3d and dwc2 overlays.
- Load: dtoverlay=upstream
- Params: <None>
-
-
- Name: upstream-aux-interrupt
--Info: Allow usage of downstream .dtb with upstream kernel by binding AUX
-- devices directly to the shared AUX interrupt line. One of the parts
-- of the 'upstream' overlay
--Load: dtoverlay=upstream-aux-interrupt
--Params: <None>
-+Info: This overlay has been deprecated and removed because it is no longer
-+ necessary.
-+Load: <Deprecated>
-
-
- Name: vc4-fkms-v3d
---- a/arch/arm/boot/dts/overlays/upstream-aux-interrupt-overlay.dts
-+++ /dev/null
-@@ -1,33 +0,0 @@
--// Overlay for missing AUX interrupt controller
--// Instead we bind all AUX devices to the generic AUX interrupt line
--/dts-v1/;
--/plugin/;
--
--/ {
-- compatible = "brcm,bcm2708";
--
-- fragment@0 {
-- target = <&uart1>;
-- __overlay__ {
-- interrupt-parent = <&intc>;
-- interrupts = <0x1 0x1d>;
-- };
-- };
--
-- fragment@1 {
-- target = <&spi1>;
-- __overlay__ {
-- interrupt-parent = <&intc>;
-- interrupts = <0x1 0x1d>;
-- };
-- };
--
-- fragment@2 {
-- target = <&spi2>;
-- __overlay__ {
-- interrupt-parent = <&intc>;
-- interrupts = <0x1 0x1d>;
-- };
-- };
--};
--
---- 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-96 dwc2-overlay.dts,dr_mode=otg upstream-aux-interrupt-overlay.dts,
-+// redo: ovmerge -c vc4-kms-v3d-overlay.dts,cma-96 dwc2-overlay.dts,dr_mode=otg
-
- /dts-v1/;
- /plugin/;
--- /dev/null
+From 343e24f4a112e1118e955fd58316e71b208a22f3 Mon Sep 17 00:00:00 2001
+Date: Wed, 22 May 2019 12:58:47 +0100
+Subject: [PATCH] vc4: Remove interrupt and DMA trampling
+
+As part of the effort to clean up the overlays, remove the interrupt
+and DMA mask declarations from the vc4 overlays which just duplicate
+that which is in the base DTBs.
+
+---
+ .../boot/dts/overlays/vc4-fkms-v3d-overlay.dts | 8 --------
+ .../boot/dts/overlays/vc4-kms-v3d-overlay.dts | 18 ++----------------
+ 2 files changed, 2 insertions(+), 24 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts
+@@ -60,7 +60,6 @@
+ fragment@7 {
+ target = <&v3d>;
+ __overlay__ {
+- interrupts = <1 10>;
+ status = "okay";
+ };
+ };
+@@ -72,13 +71,6 @@
+ };
+ };
+
+- fragment@9 {
+- target-path = "/soc/dma";
+- __overlay__ {
+- brcm,dma-channel-mask = <0x7f35>;
+- };
+- };
+-
+ __overrides__ {
+ cma-256 = <0>,"+0-1-2-3-4";
+ cma-192 = <0>,"-0+1-2-3-4";
+--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
+@@ -62,7 +62,6 @@
+ fragment@7 {
+ target = <&pixelvalve0>;
+ __overlay__ {
+- interrupts = <2 13>; /* pwa0 */
+ status = "okay";
+ };
+ };
+@@ -70,7 +69,6 @@
+ fragment@8 {
+ target = <&pixelvalve1>;
+ __overlay__ {
+- interrupts = <2 14>; /* pwa1 */
+ status = "okay";
+ };
+ };
+@@ -78,7 +76,6 @@
+ fragment@9 {
+ target = <&pixelvalve2>;
+ __overlay__ {
+- interrupts = <2 10>; /* pixelvalve */
+ status = "okay";
+ };
+ };
+@@ -86,7 +83,6 @@
+ fragment@10 {
+ target = <&hvs>;
+ __overlay__ {
+- interrupts = <2 1>;
+ status = "okay";
+ };
+ };
+@@ -94,7 +90,6 @@
+ fragment@11 {
+ target = <&hdmi>;
+ __overlay__ {
+- interrupts = <2 8>, <2 9>;
+ status = "okay";
+ };
+ };
+@@ -102,7 +97,6 @@
+ fragment@12 {
+ target = <&v3d>;
+ __overlay__ {
+- interrupts = <1 10>;
+ status = "okay";
+ };
+ };
+@@ -115,14 +109,6 @@
+ };
+
+ fragment@14 {
+- target-path = "/soc/dma";
+- __overlay__ {
+- brcm,dma-channel-mask = <0x7f35>;
+- };
+- };
+-
+-
+- fragment@15 {
+ target = <&clocks>;
+ __overlay__ {
+ claim-clocks = <
+@@ -134,14 +120,14 @@
+ };
+ };
+
+- fragment@16 {
++ fragment@15 {
+ target = <&vec>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+- fragment@17 {
++ fragment@16 {
+ target = <&txp>;
+ __overlay__ {
+ status = "okay";
--- /dev/null
+From c63b13bddf317347ba0b69807c1591526d50ba47 Mon Sep 17 00:00:00 2001
+Date: Tue, 7 May 2019 14:29:38 +0100
+Subject: [PATCH] BCM270X_DT: Add non-removable clone of mmc node
+
+non-removable is a boolean property, and as such can't be unset by an
+overlay if it is set in a base DTB. Until now the workaround for this
+problem has been for overlays to clone non-removable nodes without
+the offending property, but this involves a lot of unnecessary
+replication. Instead, add a clone of the mmc node with non-removable
+already set to the base DTB, selecting the required version using
+the status properties.
+
+---
+ arch/arm/boot/dts/bcm2708-rpi-0-w.dts | 4 +--
+ arch/arm/boot/dts/bcm2708-rpi.dtsi | 3 +-
+ arch/arm/boot/dts/bcm270x.dtsi | 13 ++++++++
+ arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 5 ++--
+ arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 5 ++--
+ arch/arm/boot/dts/overlays/mmc-overlay.dts | 7 +++++
+ arch/arm/boot/dts/overlays/sdio-overlay.dts | 33 +++++++--------------
+ 7 files changed, 38 insertions(+), 32 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
+@@ -14,6 +14,7 @@
+ aliases {
+ serial0 = &uart1;
+ serial1 = &uart0;
++ mmc1 = &mmcnr;
+ };
+ };
+
+@@ -73,10 +74,9 @@
+ };
+ };
+
+-&mmc {
++&mmcnr {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdio_pins>;
+- non-removable;
+ bus-width = <4>;
+ status = "okay";
+ };
+--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
+@@ -118,7 +118,8 @@
+ sd_force_pio = <&sdhost>,"brcm,force-pio?";
+ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
+ sd_debug = <&sdhost>,"brcm,debug";
+- sdio_overclock = <&mmc>,"brcm,overclock-50:0";
++ sdio_overclock = <&mmc>,"brcm,overclock-50:0",
++ <&mmcnr>,"brcm,overclock-50:0";
+ axiperf = <&axiperf>,"status";
+ };
+ };
+--- a/arch/arm/boot/dts/bcm270x.dtsi
++++ b/arch/arm/boot/dts/bcm270x.dtsi
+@@ -79,6 +79,19 @@
+ status = "disabled";
+ };
+
++ /* A clone of mmc but with non-removable set */
++ mmcnr: mmcnr@7e300000 {
++ compatible = "brcm,bcm2835-mmc", "brcm,bcm2835-sdhci";
++ reg = <0x7e300000 0x100>;
++ interrupts = <2 30>;
++ clocks = <&clocks BCM2835_CLOCK_EMMC>;
++ dmas = <&dma 11>;
++ dma-names = "rx-tx";
++ brcm,overclock-50 = <0>;
++ non-removable;
++ status = "disabled";
++ };
++
+ hvs: hvs@7e400000 {
+ /* Add alias */
+ status = "disabled";
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
+@@ -15,6 +15,7 @@
+ aliases {
+ serial0 = &uart1;
+ serial1 = &uart0;
++ mmc1 = &mmcnr;
+ };
+ };
+
+@@ -74,13 +75,11 @@
+ };
+ };
+
+-&mmc {
++&mmcnr {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdio_pins>;
+- non-removable;
+ bus-width = <4>;
+ status = "okay";
+- brcm,overclock-50 = <0>;
+ };
+
+ &firmware {
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
+@@ -15,6 +15,7 @@
+ aliases {
+ serial0 = &uart1;
+ serial1 = &uart0;
++ mmc1 = &mmcnr;
+ };
+ };
+
+@@ -74,13 +75,11 @@
+ };
+ };
+
+-&mmc {
++&mmcnr {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdio_pins>;
+- non-removable;
+ bus-width = <4>;
+ status = "okay";
+- brcm,overclock-50 = <0>;
+ };
+
+ &soc {
+--- a/arch/arm/boot/dts/overlays/mmc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts
+@@ -33,6 +33,13 @@
+ };
+ };
+
++ fragment@3 {
++ target = <&mmcnr>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
+ __overrides__ {
+ overclock_50 = <&frag0>,"brcm,overclock-50:0";
+ };
+--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
+@@ -1,39 +1,26 @@
+ /dts-v1/;
+ /plugin/;
+
+-/* Enable SDIO from MMC interface via GPIOs 22-27. Includes sdhost overlay. */
++/* Enable SDIO from MMC interface via various GPIO groups */
+
+ /{
+ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+- target = <&mmc>;
++ target = <&mmcnr>;
+ __overlay__ {
+ status = "disabled";
+ };
+ };
+
+ fragment@1 {
+- target = <&soc>;
+- __overlay__ {
+- #address-cells = <1>;
+- #size-cells = <1>;
+-
+- sdio_ovl: sdio@7e300000 {
+- compatible = "brcm,bcm2835-mmc",
+- "brcm,bcm2835-sdhci";
+- reg = <0x7e300000 0x100>;
+- interrupts = <2 30>;
+- clocks = <&clocks 28/*BCM2835_CLOCK_EMMC*/>;
+- dmas = <&dma 11>;
+- dma-names = "rx-tx";
+- brcm,overclock-50 = <0>;
+- status = "okay";
+- pinctrl-names = "default";
+- pinctrl-0 = <&sdio_ovl_pins>;
+- non-removable;
+- bus-width = <4>;
+- };
++ target = <&mmc>;
++ sdio_ovl: __overlay__ {
++ pinctrl-0 = <&sdio_ovl_pins>;
++ pinctrl-names = "default";
++ non-removable;
++ bus-width = <4>;
++ status = "okay";
+ };
+ };
+
+@@ -75,7 +62,7 @@
+ fragment@6 {
+ target-path = "/aliases";
+ __overlay__ {
+- mmc1 = "/soc/sdio@7e300000";
++ mmc1 = "/soc/mmc@7e300000";
+ };
+ };
+
+++ /dev/null
-From ba6646d6bc62108f33a7a3e95367534a0a634beb Mon Sep 17 00:00:00 2001
-Date: Tue, 14 May 2019 13:33:05 +0100
-Subject: [PATCH] overlays: Standardise on compatible="brcm,bcm2835"
-
-Curb the proliferation of compatible string combinations by
-standardising on "brcm,bcm2835" to denote BCM2835 and its descendants.
-
-As nothing in the firmware or kernel is checking overlay compatible
-strings, this should be a purely cosmetic change.
-
----
- arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/ads1015-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/ads1115-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/ads7846-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/adv7282m-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/adv728x-m-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts | 2 +-
- .../boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/allo-digione-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts | 2 +-
- .../boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts | 2 +-
- .../dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/applepi-dac-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/at86rf233-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts | 2 +-
- .../boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/audremap-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/balena-fin-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/dht11-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/dpi18-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/dpi24-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/draws-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/dwc-otg-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/dwc2-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/enc28j60-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/enc28j60-spi2-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/exc3000-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/goodix-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/gpio-fan-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/gpio-ir-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/gpio-ir-tx-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/gpio-key-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hy28a-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hy28b-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c-bcm2708-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c-mux-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/ilitek251x-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts | 2 +-
- .../arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/justboom-dac-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/justboom-digi-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/max98357a-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/mbed-dac-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/mcp23s17-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/mcp3008-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/mcp3202-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/mcp342x-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/media-center-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/mmc-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/mpu6050-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/mz61581-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/ov5647-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/papirus-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pibell-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/piglow-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/piscreen-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/piscreen2r-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pisound-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pitft22-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pps-gpio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/qca7000-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/rpi-dac-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/rpi-display-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/rpi-poe-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/rpi-proto-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/rpi-sense-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/rpi-tv-overlay.dts | 2 +-
- .../arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/sc16is752-spi1-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/sdhost-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/sdio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/sdtweak-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/smi-nand-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/smi-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi-rtc-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi0-cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi0-hw-cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/ssd1306-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/superaudioboard-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/sx150x-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/tc358743-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/tinylcd35-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/uart0-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/uart1-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/udrc-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/upstream-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/vga666-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/w1-gpio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/wittypi-overlay.dts | 2 +-
- 146 files changed, 146 insertions(+), 146 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/adau1977-adc-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c>;
---- a/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/adau7002-simple-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/ads1015-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/ads1015-overlay.dts
-@@ -5,7 +5,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
- /* ----------- ADS1015 ------------ */
- fragment@0 {
- target = <&i2c_arm>;
---- a/arch/arm/boot/dts/overlays/ads1115-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/ads1115-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_arm>;
---- a/arch/arm/boot/dts/overlays/ads7846-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/ads7846-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/adv7282m-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/adv7282m-overlay.dts
-@@ -4,7 +4,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_vc>;
---- a/arch/arm/boot/dts/overlays/adv728x-m-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/adv728x-m-overlay.dts
-@@ -5,7 +5,7 @@
- #include "adv7282m-overlay.dts"
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- // Fragment numbers deliberately high to avoid conflicts with the
- // included adv7282m overlay file.
---- a/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/akkordion-iqdacplus-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/clocks";
---- a/arch/arm/boot/dts/overlays/allo-digione-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/allo-digione-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/allo-piano-dac-pcm512x-audio-overlay.dts
-@@ -13,7 +13,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/allo-piano-dac-plus-pcm512x-audio-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/applepi-dac-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&sound>;
---- a/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
-@@ -4,7 +4,7 @@
- /* Overlay for Atmel AT86RF233 IEEE 802.15.4 WPAN transceiver on spi0.0 */
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/audioinjector-addons-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/audioinjector-ultra-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/audioinjector-wm8731-audio-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/audiosense-pi-overlay.dts
-@@ -5,7 +5,7 @@
- #include <dt-bindings/gpio/gpio.h>
-
- / {
-- compatible = "brcm,bcm2837", "brcm,bcm2836", "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/audremap-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/audremap-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&audio_pins>;
---- a/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&mmc>;
---- a/arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_arm>;
---- a/arch/arm/boot/dts/overlays/dht11-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dht11-overlay.dts
-@@ -5,7 +5,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dionaudio-loco-overlay.dts
-@@ -8,7 +8,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dionaudio-loco-v2-overlay.dts
-@@ -9,7 +9,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&sound>;
---- a/arch/arm/boot/dts/overlays/dpi18-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dpi18-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- // There is no DPI driver module, but we need a platform device
- // node (that doesn't already use pinctrl) to hang the pinctrl
---- a/arch/arm/boot/dts/overlays/dpi24-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dpi24-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- // There is no DPI driver module, but we need a platform device
- // node (that doesn't already use pinctrl) to hang the pinctrl
---- a/arch/arm/boot/dts/overlays/draws-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/draws-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
- fragment@0 {
- target = <&i2s>;
- __overlay__ {
---- a/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&usb>;
---- a/arch/arm/boot/dts/overlays/dwc2-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&usb>;
---- a/arch/arm/boot/dts/overlays/enc28j60-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/enc28j60-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/enc28j60-spi2-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/enc28j60-spi2-overlay.dts
-@@ -4,7 +4,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi2>;
---- a/arch/arm/boot/dts/overlays/exc3000-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/exc3000-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/fe-pi-audio-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&clocks>;
---- a/arch/arm/boot/dts/overlays/goodix-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/goodix-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/googlevoicehat-soundcard-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts
-@@ -38,7 +38,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/gpio-ir-tx-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/gpio-ir-tx-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/gpio-key-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/gpio-key-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- // Configure the gpio pin controller
---- a/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts
-@@ -10,7 +10,7 @@
- // note that GPIO3 has an external pullup on at least some boards).
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- // Configure the gpio pin controller
---- a/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-amp-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/clocks";
---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/clocks";
---- a/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-digi-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-digi-pro-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/hy28a-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hy28a-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hy28b-2017-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/hy28b-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hy28b-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i-sabre-q2m-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&sound>;
---- a/arch/arm/boot/dts/overlays/i2c-bcm2708-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-bcm2708-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_arm>;
---- a/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-mux-overlay.dts
-@@ -4,7 +4,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_arm>;
---- a/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_arm>;
---- a/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
-@@ -4,7 +4,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_arm>;
---- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_arm>;
---- a/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
-@@ -9,7 +9,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c0>;
---- a/arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts
-@@ -9,7 +9,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c1>;
---- a/arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2s-gpio28-31-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s_pins>;
---- a/arch/arm/boot/dts/overlays/ilitek251x-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/ilitek251x-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/iqaudio-dac-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/iqaudio-digi-wm8804-audio-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts
-@@ -13,7 +13,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- // disable spi-dev on spi0.0
- fragment@0 {
---- a/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/justboom-dac-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/justboom-digi-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/max98357a-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/max98357a-overlay.dts
-@@ -8,7 +8,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- /* Enable I2S */
- fragment@0 {
---- a/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mbed-dac-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
-@@ -4,7 +4,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c1>;
---- a/arch/arm/boot/dts/overlays/mcp23s17-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp23s17-overlay.dts
-@@ -20,7 +20,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- // disable spi-dev on spi0.0
- fragment@0 {
---- a/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
- /* disable spi-dev for spi0.0 */
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp2515-can1-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
- /* disable spi-dev for spi0.1 */
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/mcp3008-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp3008-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spidev0>;
---- a/arch/arm/boot/dts/overlays/mcp3202-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp3202-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spidev0>;
---- a/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
-@@ -4,7 +4,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c1>;
---- a/arch/arm/boot/dts/overlays/media-center-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/media-center-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/mmc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&mmc>;
---- a/arch/arm/boot/dts/overlays/mpu6050-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mpu6050-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c1>;
---- a/arch/arm/boot/dts/overlays/mz61581-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mz61581-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/ov5647-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts
-@@ -4,7 +4,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_vc>;
---- a/arch/arm/boot/dts/overlays/papirus-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/papirus-overlay.dts
-@@ -4,7 +4,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_arm>;
---- a/arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts
-@@ -11,7 +11,7 @@
- */
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&act_led>;
---- a/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
-@@ -9,7 +9,7 @@
- */
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&uart1>;
---- a/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&mmc>;
---- a/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
-@@ -16,7 +16,7 @@
- */
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&uart0>;
---- a/arch/arm/boot/dts/overlays/pibell-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pibell-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/piglow-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/piglow-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_arm>;
---- a/arch/arm/boot/dts/overlays/piscreen-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/piscreen-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/piscreen2r-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/pisound-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pisound-overlay.dts
-@@ -23,7 +23,7 @@
- #include <dt-bindings/gpio/gpio.h>
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/pitft22-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pitft22-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pitft28-capacitive-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
- fragment@0 {
- target-path = "/";
- __overlay__ {
---- a/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pwm-ir-tx-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/qca7000-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/qca7000-overlay.dts
-@@ -5,7 +5,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spidev0>;
---- a/arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rotary-encoder-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
-@@ -6,7 +6,7 @@
- #include <dt-bindings/mfd/arizona.h>
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-dac-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/rpi-display-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-display-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts
-@@ -5,7 +5,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-proto-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-sense-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c1>;
---- a/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts
-@@ -4,7 +4,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spidev0>;
---- a/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rra-digidac1-wm8741-audio-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_arm>;
---- a/arch/arm/boot/dts/overlays/sc16is752-spi1-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sc16is752-spi1-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts
-@@ -4,7 +4,7 @@
- /* Provide backwards compatible aliases for the old sdhost dtparams. */
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&sdhost>;
---- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
-@@ -4,7 +4,7 @@
- /* Enable SDIO from MMC interface via GPIOs 22-27. Includes sdhost overlay. */
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&mmc>;
---- a/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdtweak-overlay.dts
-@@ -4,7 +4,7 @@
- /* Provide backwards compatible aliases for the old sdhost dtparams. */
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&sdhost>;
---- a/arch/arm/boot/dts/overlays/smi-nand-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/smi-nand-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&smi>;
---- a/arch/arm/boot/dts/overlays/smi-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/smi-overlay.dts
-@@ -5,7 +5,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&smi>;
---- a/arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi-gpio35-39-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/spi-rtc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi-rtc-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spidev0>;
---- a/arch/arm/boot/dts/overlays/spi0-cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi0-cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0_cs_pins>;
---- a/arch/arm/boot/dts/overlays/spi0-hw-cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi0-hw-cs-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi1-1cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi1-2cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi1-3cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi2-1cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi2-2cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi2-3cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&gpio>;
---- a/arch/arm/boot/dts/overlays/ssd1306-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/ssd1306-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2718";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c1>;
---- a/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/superaudioboard-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&sound>;
---- a/arch/arm/boot/dts/overlays/sx150x-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sx150x-overlay.dts
-@@ -22,7 +22,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- // Enable I2C#0 interface
- fragment@0 {
---- a/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/tc358743-audio-overlay.dts
-@@ -5,7 +5,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/tc358743-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/tc358743-overlay.dts
-@@ -4,7 +4,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2c_vc>;
---- a/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
-@@ -24,7 +24,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/tpm-slb9670-overlay.dts
-@@ -8,7 +8,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&spi0>;
---- a/arch/arm/boot/dts/overlays/uart0-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/uart0-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&uart0>;
---- a/arch/arm/boot/dts/overlays/uart1-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/uart1-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&uart1>;
---- a/arch/arm/boot/dts/overlays/udrc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/udrc-overlay.dts
-@@ -7,7 +7,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
- fragment@0 {
- target = <&i2s>;
- __overlay__ {
---- a/arch/arm/boot/dts/overlays/upstream-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts
-@@ -6,7 +6,7 @@
- #include <dt-bindings/clock/bcm2835.h>
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
- fragment@0 {
- target-path = "/chosen";
- __dormant__ {
---- a/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts
-@@ -6,7 +6,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/chosen";
---- a/arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/vc4-kms-kippah-7inch-overlay.dts
-@@ -8,7 +8,7 @@
- #include <dt-bindings/pinctrl/bcm2835.h>
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
-@@ -8,7 +8,7 @@
- #include <dt-bindings/clock/bcm2835.h>
-
- / {
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/chosen";
---- a/arch/arm/boot/dts/overlays/vga666-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/vga666-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- // There is no VGA driver module, but we need a platform device
- // node (that doesn't already use pinctrl) to hang the pinctrl
---- a/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/";
---- a/arch/arm/boot/dts/overlays/wittypi-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/wittypi-overlay.dts
-@@ -8,7 +8,7 @@
-
- / {
-
-- compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&leds>;
--- /dev/null
+From 61c44e24ea212b92bf6a420b94070ee6fc715811 Mon Sep 17 00:00:00 2001
+Date: Wed, 8 May 2019 10:08:31 +0100
+Subject: [PATCH] BCM270X_DT: usb: Refactor DTS and overlays
+
+Move the IRQ interrupt declaration in the usb node before the FIQ
+declaration, so that the dwc2 driver will find it. Name the
+interrupts appropriately so that the dwc_otg driver can still find
+them. Then remove the interrupt rewriting from the overlays.
+
+---
+ arch/arm/boot/dts/bcm270x.dtsi | 6 ++++--
+ arch/arm/boot/dts/overlays/dwc-otg-overlay.dts | 6 ------
+ arch/arm/boot/dts/overlays/dwc2-overlay.dts | 2 --
+ 3 files changed, 4 insertions(+), 10 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm270x.dtsi
++++ b/arch/arm/boot/dts/bcm270x.dtsi
+@@ -131,8 +131,10 @@
+ compatible = "brcm,bcm2708-usb";
+ reg = <0x7e980000 0x10000>,
+ <0x7e006000 0x1000>;
+- interrupts = <2 0>,
+- <1 9>;
++ interrupt-names = "usb",
++ "soft";
++ interrupts = <1 9>,
++ <2 0>;
+ };
+
+ v3d@7ec00000 { /* vd3 */
+--- a/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
+@@ -6,14 +6,8 @@
+
+ fragment@0 {
+ target = <&usb>;
+- #address-cells = <1>;
+- #size-cells = <1>;
+ __overlay__ {
+ compatible = "brcm,bcm2708-usb";
+- reg = <0x7e980000 0x10000>,
+- <0x7e006000 0x1000>;
+- interrupts = <2 0>,
+- <1 9>;
+ status = "okay";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/dwc2-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts
+@@ -10,8 +10,6 @@
+ #size-cells = <1>;
+ dwc2_usb: __overlay__ {
+ compatible = "brcm,bcm2835-usb";
+- reg = <0x7e980000 0x10000>;
+- interrupts = <1 9>;
+ dr_mode = "otg";
+ g-np-tx-fifo-size = <32>;
+ g-rx-fifo-size = <256>;
+++ /dev/null
-From 343e24f4a112e1118e955fd58316e71b208a22f3 Mon Sep 17 00:00:00 2001
-Date: Wed, 22 May 2019 12:58:47 +0100
-Subject: [PATCH] vc4: Remove interrupt and DMA trampling
-
-As part of the effort to clean up the overlays, remove the interrupt
-and DMA mask declarations from the vc4 overlays which just duplicate
-that which is in the base DTBs.
-
----
- .../boot/dts/overlays/vc4-fkms-v3d-overlay.dts | 8 --------
- .../boot/dts/overlays/vc4-kms-v3d-overlay.dts | 18 ++----------------
- 2 files changed, 2 insertions(+), 24 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts
-@@ -60,7 +60,6 @@
- fragment@7 {
- target = <&v3d>;
- __overlay__ {
-- interrupts = <1 10>;
- status = "okay";
- };
- };
-@@ -72,13 +71,6 @@
- };
- };
-
-- fragment@9 {
-- target-path = "/soc/dma";
-- __overlay__ {
-- brcm,dma-channel-mask = <0x7f35>;
-- };
-- };
--
- __overrides__ {
- cma-256 = <0>,"+0-1-2-3-4";
- cma-192 = <0>,"-0+1-2-3-4";
---- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
-@@ -62,7 +62,6 @@
- fragment@7 {
- target = <&pixelvalve0>;
- __overlay__ {
-- interrupts = <2 13>; /* pwa0 */
- status = "okay";
- };
- };
-@@ -70,7 +69,6 @@
- fragment@8 {
- target = <&pixelvalve1>;
- __overlay__ {
-- interrupts = <2 14>; /* pwa1 */
- status = "okay";
- };
- };
-@@ -78,7 +76,6 @@
- fragment@9 {
- target = <&pixelvalve2>;
- __overlay__ {
-- interrupts = <2 10>; /* pixelvalve */
- status = "okay";
- };
- };
-@@ -86,7 +83,6 @@
- fragment@10 {
- target = <&hvs>;
- __overlay__ {
-- interrupts = <2 1>;
- status = "okay";
- };
- };
-@@ -94,7 +90,6 @@
- fragment@11 {
- target = <&hdmi>;
- __overlay__ {
-- interrupts = <2 8>, <2 9>;
- status = "okay";
- };
- };
-@@ -102,7 +97,6 @@
- fragment@12 {
- target = <&v3d>;
- __overlay__ {
-- interrupts = <1 10>;
- status = "okay";
- };
- };
-@@ -115,14 +109,6 @@
- };
-
- fragment@14 {
-- target-path = "/soc/dma";
-- __overlay__ {
-- brcm,dma-channel-mask = <0x7f35>;
-- };
-- };
--
--
-- fragment@15 {
- target = <&clocks>;
- __overlay__ {
- claim-clocks = <
-@@ -134,14 +120,14 @@
- };
- };
-
-- fragment@16 {
-+ fragment@15 {
- target = <&vec>;
- __overlay__ {
- status = "okay";
- };
- };
-
-- fragment@17 {
-+ fragment@16 {
- target = <&txp>;
- __overlay__ {
- status = "okay";
+++ /dev/null
-From c63b13bddf317347ba0b69807c1591526d50ba47 Mon Sep 17 00:00:00 2001
-Date: Tue, 7 May 2019 14:29:38 +0100
-Subject: [PATCH] BCM270X_DT: Add non-removable clone of mmc node
-
-non-removable is a boolean property, and as such can't be unset by an
-overlay if it is set in a base DTB. Until now the workaround for this
-problem has been for overlays to clone non-removable nodes without
-the offending property, but this involves a lot of unnecessary
-replication. Instead, add a clone of the mmc node with non-removable
-already set to the base DTB, selecting the required version using
-the status properties.
-
----
- arch/arm/boot/dts/bcm2708-rpi-0-w.dts | 4 +--
- arch/arm/boot/dts/bcm2708-rpi.dtsi | 3 +-
- arch/arm/boot/dts/bcm270x.dtsi | 13 ++++++++
- arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 5 ++--
- arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 5 ++--
- arch/arm/boot/dts/overlays/mmc-overlay.dts | 7 +++++
- arch/arm/boot/dts/overlays/sdio-overlay.dts | 33 +++++++--------------
- 7 files changed, 38 insertions(+), 32 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
-+++ b/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
-@@ -14,6 +14,7 @@
- aliases {
- serial0 = &uart1;
- serial1 = &uart0;
-+ mmc1 = &mmcnr;
- };
- };
-
-@@ -73,10 +74,9 @@
- };
- };
-
--&mmc {
-+&mmcnr {
- pinctrl-names = "default";
- pinctrl-0 = <&sdio_pins>;
-- non-removable;
- bus-width = <4>;
- status = "okay";
- };
---- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
-@@ -118,7 +118,8 @@
- sd_force_pio = <&sdhost>,"brcm,force-pio?";
- sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
- sd_debug = <&sdhost>,"brcm,debug";
-- sdio_overclock = <&mmc>,"brcm,overclock-50:0";
-+ sdio_overclock = <&mmc>,"brcm,overclock-50:0",
-+ <&mmcnr>,"brcm,overclock-50:0";
- axiperf = <&axiperf>,"status";
- };
- };
---- a/arch/arm/boot/dts/bcm270x.dtsi
-+++ b/arch/arm/boot/dts/bcm270x.dtsi
-@@ -79,6 +79,19 @@
- status = "disabled";
- };
-
-+ /* A clone of mmc but with non-removable set */
-+ mmcnr: mmcnr@7e300000 {
-+ compatible = "brcm,bcm2835-mmc", "brcm,bcm2835-sdhci";
-+ reg = <0x7e300000 0x100>;
-+ interrupts = <2 30>;
-+ clocks = <&clocks BCM2835_CLOCK_EMMC>;
-+ dmas = <&dma 11>;
-+ dma-names = "rx-tx";
-+ brcm,overclock-50 = <0>;
-+ non-removable;
-+ status = "disabled";
-+ };
-+
- hvs: hvs@7e400000 {
- /* Add alias */
- status = "disabled";
---- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
-@@ -15,6 +15,7 @@
- aliases {
- serial0 = &uart1;
- serial1 = &uart0;
-+ mmc1 = &mmcnr;
- };
- };
-
-@@ -74,13 +75,11 @@
- };
- };
-
--&mmc {
-+&mmcnr {
- pinctrl-names = "default";
- pinctrl-0 = <&sdio_pins>;
-- non-removable;
- bus-width = <4>;
- status = "okay";
-- brcm,overclock-50 = <0>;
- };
-
- &firmware {
---- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-@@ -15,6 +15,7 @@
- aliases {
- serial0 = &uart1;
- serial1 = &uart0;
-+ mmc1 = &mmcnr;
- };
- };
-
-@@ -74,13 +75,11 @@
- };
- };
-
--&mmc {
-+&mmcnr {
- pinctrl-names = "default";
- pinctrl-0 = <&sdio_pins>;
-- non-removable;
- bus-width = <4>;
- status = "okay";
-- brcm,overclock-50 = <0>;
- };
-
- &soc {
---- a/arch/arm/boot/dts/overlays/mmc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts
-@@ -33,6 +33,13 @@
- };
- };
-
-+ fragment@3 {
-+ target = <&mmcnr>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
- __overrides__ {
- overclock_50 = <&frag0>,"brcm,overclock-50:0";
- };
---- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
-@@ -1,39 +1,26 @@
- /dts-v1/;
- /plugin/;
-
--/* Enable SDIO from MMC interface via GPIOs 22-27. Includes sdhost overlay. */
-+/* Enable SDIO from MMC interface via various GPIO groups */
-
- /{
- compatible = "brcm,bcm2835";
-
- fragment@0 {
-- target = <&mmc>;
-+ target = <&mmcnr>;
- __overlay__ {
- status = "disabled";
- };
- };
-
- fragment@1 {
-- target = <&soc>;
-- __overlay__ {
-- #address-cells = <1>;
-- #size-cells = <1>;
--
-- sdio_ovl: sdio@7e300000 {
-- compatible = "brcm,bcm2835-mmc",
-- "brcm,bcm2835-sdhci";
-- reg = <0x7e300000 0x100>;
-- interrupts = <2 30>;
-- clocks = <&clocks 28/*BCM2835_CLOCK_EMMC*/>;
-- dmas = <&dma 11>;
-- dma-names = "rx-tx";
-- brcm,overclock-50 = <0>;
-- status = "okay";
-- pinctrl-names = "default";
-- pinctrl-0 = <&sdio_ovl_pins>;
-- non-removable;
-- bus-width = <4>;
-- };
-+ target = <&mmc>;
-+ sdio_ovl: __overlay__ {
-+ pinctrl-0 = <&sdio_ovl_pins>;
-+ pinctrl-names = "default";
-+ non-removable;
-+ bus-width = <4>;
-+ status = "okay";
- };
- };
-
-@@ -75,7 +62,7 @@
- fragment@6 {
- target-path = "/aliases";
- __overlay__ {
-- mmc1 = "/soc/sdio@7e300000";
-+ mmc1 = "/soc/mmc@7e300000";
- };
- };
-
--- /dev/null
+From 61c487e6a1985e52307d6df5834b610a50219819 Mon Sep 17 00:00:00 2001
+Date: Wed, 22 May 2019 13:29:56 +0100
+Subject: [PATCH] overlays: Update upstream overlay
+
+The recent DT/overlay changes have had a corresponding effect on the
+upstream overlay, which is a composite of the vc4-kms-v3d and dwc2
+overlays.
+
+---
+ .../boot/dts/overlays/upstream-overlay.dts | 41 ++-----------------
+ 1 file changed, 3 insertions(+), 38 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/upstream-overlay.dts
++++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts
+@@ -52,42 +52,36 @@
+ fragment@7 {
+ target = <&pixelvalve0>;
+ __overlay__ {
+- interrupts = <2 13>;
+ status = "okay";
+ };
+ };
+ fragment@8 {
+ target = <&pixelvalve1>;
+ __overlay__ {
+- interrupts = <2 14>;
+ status = "okay";
+ };
+ };
+ fragment@9 {
+ target = <&pixelvalve2>;
+ __overlay__ {
+- interrupts = <2 10>;
+ status = "okay";
+ };
+ };
+ fragment@10 {
+ target = <&hvs>;
+ __overlay__ {
+- interrupts = <2 1>;
+ status = "okay";
+ };
+ };
+ fragment@11 {
+ target = <&hdmi>;
+ __overlay__ {
+- interrupts = <2 8>, <2 9>;
+ status = "okay";
+ };
+ };
+ fragment@12 {
+ target = <&v3d>;
+ __overlay__ {
+- interrupts = <1 10>;
+ status = "okay";
+ };
+ };
+@@ -98,37 +92,29 @@
+ };
+ };
+ fragment@14 {
+- target-path = "/soc/dma";
+- __overlay__ {
+- brcm,dma-channel-mask = <0x7f35>;
+- };
+- };
+- fragment@15 {
+ target = <&clocks>;
+ __overlay__ {
+ claim-clocks = <BCM2835_PLLD_DSI0 BCM2835_PLLD_DSI1 BCM2835_PLLH_AUX BCM2835_PLLH_PIX>;
+ };
+ };
+- fragment@16 {
++ fragment@15 {
+ target = <&vec>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+- fragment@17 {
++ fragment@16 {
+ target = <&txp>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+- fragment@18 {
++ fragment@17 {
+ target = <&usb>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ dwc2_usb: __overlay__ {
+ compatible = "brcm,bcm2835-usb";
+- reg = <0x7e980000 0x10000>;
+- interrupts = <1 9>;
+ dr_mode = "otg";
+ g-np-tx-fifo-size = <32>;
+ g-rx-fifo-size = <256>;
+@@ -136,25 +122,4 @@
+ status = "okay";
+ };
+ };
+- fragment@19 {
+- target = <&uart1>;
+- __overlay__ {
+- interrupt-parent = <&intc>;
+- interrupts = <0x1 0x1d>;
+- };
+- };
+- fragment@20 {
+- target = <&spi1>;
+- __overlay__ {
+- interrupt-parent = <&intc>;
+- interrupts = <0x1 0x1d>;
+- };
+- };
+- fragment@21 {
+- target = <&spi2>;
+- __overlay__ {
+- interrupt-parent = <&intc>;
+- interrupts = <0x1 0x1d>;
+- };
+- };
+ };
+++ /dev/null
-From 61c44e24ea212b92bf6a420b94070ee6fc715811 Mon Sep 17 00:00:00 2001
-Date: Wed, 8 May 2019 10:08:31 +0100
-Subject: [PATCH] BCM270X_DT: usb: Refactor DTS and overlays
-
-Move the IRQ interrupt declaration in the usb node before the FIQ
-declaration, so that the dwc2 driver will find it. Name the
-interrupts appropriately so that the dwc_otg driver can still find
-them. Then remove the interrupt rewriting from the overlays.
-
----
- arch/arm/boot/dts/bcm270x.dtsi | 6 ++++--
- arch/arm/boot/dts/overlays/dwc-otg-overlay.dts | 6 ------
- arch/arm/boot/dts/overlays/dwc2-overlay.dts | 2 --
- 3 files changed, 4 insertions(+), 10 deletions(-)
-
---- a/arch/arm/boot/dts/bcm270x.dtsi
-+++ b/arch/arm/boot/dts/bcm270x.dtsi
-@@ -131,8 +131,10 @@
- compatible = "brcm,bcm2708-usb";
- reg = <0x7e980000 0x10000>,
- <0x7e006000 0x1000>;
-- interrupts = <2 0>,
-- <1 9>;
-+ interrupt-names = "usb",
-+ "soft";
-+ interrupts = <1 9>,
-+ <2 0>;
- };
-
- v3d@7ec00000 { /* vd3 */
---- a/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dwc-otg-overlay.dts
-@@ -6,14 +6,8 @@
-
- fragment@0 {
- target = <&usb>;
-- #address-cells = <1>;
-- #size-cells = <1>;
- __overlay__ {
- compatible = "brcm,bcm2708-usb";
-- reg = <0x7e980000 0x10000>,
-- <0x7e006000 0x1000>;
-- interrupts = <2 0>,
-- <1 9>;
- status = "okay";
- };
- };
---- a/arch/arm/boot/dts/overlays/dwc2-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts
-@@ -10,8 +10,6 @@
- #size-cells = <1>;
- dwc2_usb: __overlay__ {
- compatible = "brcm,bcm2835-usb";
-- reg = <0x7e980000 0x10000>;
-- interrupts = <1 9>;
- dr_mode = "otg";
- g-np-tx-fifo-size = <32>;
- g-rx-fifo-size = <256>;
--- /dev/null
+From f74fe07cab3e8816c029de25029b71c80004619c Mon Sep 17 00:00:00 2001
+Date: Thu, 16 May 2019 14:39:21 +0200
+Subject: [PATCH] w1: ds2408: Fix typo after 49695ac46861 (reset on
+ output_write retry with readback)
+
+commit 6660a04feb7ef648e50c792e19084d675fa6f3a2 upstream.
+
+Fix a typo in commit:
+49695ac46861 w1: ds2408: reset on output_write retry with readback
+
+Fixes: 49695ac46861 ("w1: ds2408: reset on output_write retry with readback")
+---
+ drivers/w1/slaves/w1_ds2408.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/w1/slaves/w1_ds2408.c
++++ b/drivers/w1/slaves/w1_ds2408.c
+@@ -138,7 +138,7 @@ static ssize_t status_control_read(struc
+ W1_F29_REG_CONTROL_AND_STATUS, buf);
+ }
+
+-#ifdef fCONFIG_W1_SLAVE_DS2408_READBACK
++#ifdef CONFIG_W1_SLAVE_DS2408_READBACK
+ static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)
+ {
+ u8 w1_buf[3];
--- /dev/null
+From 9542646d9211ab4305beb75da97f61cc1968ae6c Mon Sep 17 00:00:00 2001
+Date: Tue, 28 May 2019 16:36:04 +0100
+Subject: [PATCH] BCM270X_DT: Rename Pi Zero W DT files
+
+The downtream Pi Zero W dts file uses the digit 0, whereas upstream
+chose to spell it out - "zero-w". The firmware has, for a long time,
+looked for bcm2708-rpi-zero-w.dtb first before falling back to the
+numerical version. Therefore it is better to follow upstream and
+make the switch to "bcm2708-rpi-zero-w".
+
+At the same time, remove some overrides that duplicate values
+inherited from the shared .dtsi files.
+
+---
+ arch/arm/boot/dts/Makefile | 2 +-
+ .../boot/dts/{bcm2708-rpi-0-w.dts => bcm2708-rpi-zero-w.dts} | 5 -----
+ 2 files changed, 1 insertion(+), 6 deletions(-)
+ rename arch/arm/boot/dts/{bcm2708-rpi-0-w.dts => bcm2708-rpi-zero-w.dts} (97%)
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -4,7 +4,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2708-rpi-b.dtb \
+ bcm2708-rpi-b-plus.dtb \
+ bcm2708-rpi-cm.dtb \
+- bcm2708-rpi-0-w.dtb \
++ bcm2708-rpi-zero-w.dtb \
+ bcm2709-rpi-2-b.dtb \
+ bcm2710-rpi-3-b.dtb \
+ bcm2710-rpi-3-b-plus.dtb \
+--- a/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
++++ /dev/null
+@@ -1,167 +0,0 @@
+-/dts-v1/;
+-
+-#include "bcm2708.dtsi"
+-#include "bcm283x-rpi-csi1-2lane.dtsi"
+-
+-/ {
+- compatible = "raspberrypi,model-zero-w", "brcm,bcm2835";
+- model = "Raspberry Pi Zero W";
+-
+- chosen {
+- bootargs = "coherent_pool=1M 8250.nr_uarts=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>; /* none */
+- };
+-
+- 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>;
+- };
+-};
+-
+-&i2c0 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&i2c0_pins>;
+- clock-frequency = <100000>;
+-};
+-
+-&i2c1 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&i2c1_pins>;
+- clock-frequency = <100000>;
+-};
+-
+-&i2c2 {
+- clock-frequency = <100000>;
+-};
+-
+-&i2s {
+- #sound-dai-cells = <0>;
+- pinctrl-names = "default";
+- pinctrl-0 = <&i2s_pins>;
+-};
+-
+-&random {
+- status = "okay";
+-};
+-
+-&leds {
+- act_led: act {
+- label = "led0";
+- linux,default-trigger = "mmc0";
+- gpios = <&gpio 47 0>;
+- };
+-};
+-
+-&hdmi {
+- hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
+-};
+-
+-&audio {
+- pinctrl-names = "default";
+- pinctrl-0 = <&audio_pins>;
+-};
+-
+-/ {
+- __overrides__ {
+- act_led_gpio = <&act_led>,"gpios:4";
+- act_led_activelow = <&act_led>,"gpios:8";
+- act_led_trigger = <&act_led>,"linux,default-trigger";
+- };
+-};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts
+@@ -0,0 +1,162 @@
++/dts-v1/;
++
++#include "bcm2708.dtsi"
++#include "bcm283x-rpi-csi1-2lane.dtsi"
++
++/ {
++ compatible = "raspberrypi,model-zero-w", "brcm,bcm2835";
++ model = "Raspberry Pi Zero W";
++
++ chosen {
++ bootargs = "coherent_pool=1M 8250.nr_uarts=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>; /* none */
++ };
++
++ 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>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ 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: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&gpio 47 0>;
++ };
++};
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
++
++&audio {
++ pinctrl-names = "default";
++ pinctrl-0 = <&audio_pins>;
++};
++
++/ {
++ __overrides__ {
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++ };
++};
+++ /dev/null
-From 61c487e6a1985e52307d6df5834b610a50219819 Mon Sep 17 00:00:00 2001
-Date: Wed, 22 May 2019 13:29:56 +0100
-Subject: [PATCH] overlays: Update upstream overlay
-
-The recent DT/overlay changes have had a corresponding effect on the
-upstream overlay, which is a composite of the vc4-kms-v3d and dwc2
-overlays.
-
----
- .../boot/dts/overlays/upstream-overlay.dts | 41 ++-----------------
- 1 file changed, 3 insertions(+), 38 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/upstream-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts
-@@ -52,42 +52,36 @@
- fragment@7 {
- target = <&pixelvalve0>;
- __overlay__ {
-- interrupts = <2 13>;
- status = "okay";
- };
- };
- fragment@8 {
- target = <&pixelvalve1>;
- __overlay__ {
-- interrupts = <2 14>;
- status = "okay";
- };
- };
- fragment@9 {
- target = <&pixelvalve2>;
- __overlay__ {
-- interrupts = <2 10>;
- status = "okay";
- };
- };
- fragment@10 {
- target = <&hvs>;
- __overlay__ {
-- interrupts = <2 1>;
- status = "okay";
- };
- };
- fragment@11 {
- target = <&hdmi>;
- __overlay__ {
-- interrupts = <2 8>, <2 9>;
- status = "okay";
- };
- };
- fragment@12 {
- target = <&v3d>;
- __overlay__ {
-- interrupts = <1 10>;
- status = "okay";
- };
- };
-@@ -98,37 +92,29 @@
- };
- };
- fragment@14 {
-- target-path = "/soc/dma";
-- __overlay__ {
-- brcm,dma-channel-mask = <0x7f35>;
-- };
-- };
-- fragment@15 {
- target = <&clocks>;
- __overlay__ {
- claim-clocks = <BCM2835_PLLD_DSI0 BCM2835_PLLD_DSI1 BCM2835_PLLH_AUX BCM2835_PLLH_PIX>;
- };
- };
-- fragment@16 {
-+ fragment@15 {
- target = <&vec>;
- __overlay__ {
- status = "okay";
- };
- };
-- fragment@17 {
-+ fragment@16 {
- target = <&txp>;
- __overlay__ {
- status = "okay";
- };
- };
-- fragment@18 {
-+ fragment@17 {
- target = <&usb>;
- #address-cells = <1>;
- #size-cells = <1>;
- dwc2_usb: __overlay__ {
- compatible = "brcm,bcm2835-usb";
-- reg = <0x7e980000 0x10000>;
-- interrupts = <1 9>;
- dr_mode = "otg";
- g-np-tx-fifo-size = <32>;
- g-rx-fifo-size = <256>;
-@@ -136,25 +122,4 @@
- status = "okay";
- };
- };
-- fragment@19 {
-- target = <&uart1>;
-- __overlay__ {
-- interrupt-parent = <&intc>;
-- interrupts = <0x1 0x1d>;
-- };
-- };
-- fragment@20 {
-- target = <&spi1>;
-- __overlay__ {
-- interrupt-parent = <&intc>;
-- interrupts = <0x1 0x1d>;
-- };
-- };
-- fragment@21 {
-- target = <&spi2>;
-- __overlay__ {
-- interrupt-parent = <&intc>;
-- interrupts = <0x1 0x1d>;
-- };
-- };
- };
--- /dev/null
+From e819b50b0c384f11f4eaf6e1ea76030c320f4511 Mon Sep 17 00:00:00 2001
+Date: Tue, 28 May 2019 16:23:51 +0100
+Subject: [PATCH] BCM270X_DT: Create bcm2708-rpi-zero.dts
+
+The Pi Zero deserves a dedicated .dtb file - sharing the b-plus .dtb
+has been observed to cause an issue with the MAC address of some
+Ethernet dongles.
+
+See: https://github.com/raspberrypi/linux/issues/2990
+
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/bcm2708-rpi-zero.dts | 117 +++++++++++++++++++++++++
+ 2 files changed, 118 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm2708-rpi-zero.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -4,6 +4,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2708-rpi-b.dtb \
+ bcm2708-rpi-b-plus.dtb \
+ bcm2708-rpi-cm.dtb \
++ bcm2708-rpi-zero.dtb \
+ bcm2708-rpi-zero-w.dtb \
+ bcm2709-rpi-2-b.dtb \
+ bcm2710-rpi-3-b.dtb \
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2708-rpi-zero.dts
+@@ -0,0 +1,117 @@
++/dts-v1/;
++
++#include "bcm2708.dtsi"
++#include "bcm283x-rpi-csi1-2lane.dtsi"
++
++/ {
++ compatible = "raspberrypi,model-zero", "brcm,bcm2835";
++ model = "Raspberry Pi Zero";
++
++ chosen {
++ bootargs = "coherent_pool=1M";
++ };
++};
++
++&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 */
++ };
++
++ audio_pins: audio_pins {
++ brcm,pins = <>;
++ brcm,function = <>;
++ };
++};
++
++&uart0 {
++ 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>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ 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: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&gpio 47 0>;
++ };
++};
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
++
++&audio {
++ pinctrl-names = "default";
++ pinctrl-0 = <&audio_pins>;
++};
++
++/ {
++ __overrides__ {
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++ };
++};
+++ /dev/null
-From f74fe07cab3e8816c029de25029b71c80004619c Mon Sep 17 00:00:00 2001
-Date: Thu, 16 May 2019 14:39:21 +0200
-Subject: [PATCH] w1: ds2408: Fix typo after 49695ac46861 (reset on
- output_write retry with readback)
-
-commit 6660a04feb7ef648e50c792e19084d675fa6f3a2 upstream.
-
-Fix a typo in commit:
-49695ac46861 w1: ds2408: reset on output_write retry with readback
-
-Fixes: 49695ac46861 ("w1: ds2408: reset on output_write retry with readback")
----
- drivers/w1/slaves/w1_ds2408.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/w1/slaves/w1_ds2408.c
-+++ b/drivers/w1/slaves/w1_ds2408.c
-@@ -138,7 +138,7 @@ static ssize_t status_control_read(struc
- W1_F29_REG_CONTROL_AND_STATUS, buf);
- }
-
--#ifdef fCONFIG_W1_SLAVE_DS2408_READBACK
-+#ifdef CONFIG_W1_SLAVE_DS2408_READBACK
- static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)
- {
- u8 w1_buf[3];
+++ /dev/null
-From 9542646d9211ab4305beb75da97f61cc1968ae6c Mon Sep 17 00:00:00 2001
-Date: Tue, 28 May 2019 16:36:04 +0100
-Subject: [PATCH] BCM270X_DT: Rename Pi Zero W DT files
-
-The downtream Pi Zero W dts file uses the digit 0, whereas upstream
-chose to spell it out - "zero-w". The firmware has, for a long time,
-looked for bcm2708-rpi-zero-w.dtb first before falling back to the
-numerical version. Therefore it is better to follow upstream and
-make the switch to "bcm2708-rpi-zero-w".
-
-At the same time, remove some overrides that duplicate values
-inherited from the shared .dtsi files.
-
----
- arch/arm/boot/dts/Makefile | 2 +-
- .../boot/dts/{bcm2708-rpi-0-w.dts => bcm2708-rpi-zero-w.dts} | 5 -----
- 2 files changed, 1 insertion(+), 6 deletions(-)
- rename arch/arm/boot/dts/{bcm2708-rpi-0-w.dts => bcm2708-rpi-zero-w.dts} (97%)
-
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -4,7 +4,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
- bcm2708-rpi-b.dtb \
- bcm2708-rpi-b-plus.dtb \
- bcm2708-rpi-cm.dtb \
-- bcm2708-rpi-0-w.dtb \
-+ bcm2708-rpi-zero-w.dtb \
- bcm2709-rpi-2-b.dtb \
- bcm2710-rpi-3-b.dtb \
- bcm2710-rpi-3-b-plus.dtb \
---- a/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
-+++ /dev/null
-@@ -1,167 +0,0 @@
--/dts-v1/;
--
--#include "bcm2708.dtsi"
--#include "bcm283x-rpi-csi1-2lane.dtsi"
--
--/ {
-- compatible = "raspberrypi,model-zero-w", "brcm,bcm2835";
-- model = "Raspberry Pi Zero W";
--
-- chosen {
-- bootargs = "coherent_pool=1M 8250.nr_uarts=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>; /* none */
-- };
--
-- 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>;
-- };
--};
--
--&i2c0 {
-- pinctrl-names = "default";
-- pinctrl-0 = <&i2c0_pins>;
-- clock-frequency = <100000>;
--};
--
--&i2c1 {
-- pinctrl-names = "default";
-- pinctrl-0 = <&i2c1_pins>;
-- clock-frequency = <100000>;
--};
--
--&i2c2 {
-- clock-frequency = <100000>;
--};
--
--&i2s {
-- #sound-dai-cells = <0>;
-- pinctrl-names = "default";
-- pinctrl-0 = <&i2s_pins>;
--};
--
--&random {
-- status = "okay";
--};
--
--&leds {
-- act_led: act {
-- label = "led0";
-- linux,default-trigger = "mmc0";
-- gpios = <&gpio 47 0>;
-- };
--};
--
--&hdmi {
-- hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
--};
--
--&audio {
-- pinctrl-names = "default";
-- pinctrl-0 = <&audio_pins>;
--};
--
--/ {
-- __overrides__ {
-- act_led_gpio = <&act_led>,"gpios:4";
-- act_led_activelow = <&act_led>,"gpios:8";
-- act_led_trigger = <&act_led>,"linux,default-trigger";
-- };
--};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts
-@@ -0,0 +1,162 @@
-+/dts-v1/;
-+
-+#include "bcm2708.dtsi"
-+#include "bcm283x-rpi-csi1-2lane.dtsi"
-+
-+/ {
-+ compatible = "raspberrypi,model-zero-w", "brcm,bcm2835";
-+ model = "Raspberry Pi Zero W";
-+
-+ chosen {
-+ bootargs = "coherent_pool=1M 8250.nr_uarts=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>; /* none */
-+ };
-+
-+ 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>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ 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: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 47 0>;
-+ };
-+};
-+
-+&hdmi {
-+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+};
-+
-+&audio {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&audio_pins>;
-+};
-+
-+/ {
-+ __overrides__ {
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+ };
-+};
--- /dev/null
+From dadcb33e1f4ee70bc77da7fa7054b8571a22d5ea Mon Sep 17 00:00:00 2001
+Date: Thu, 30 May 2019 12:25:29 +0100
+Subject: [PATCH] overlays: Fix mmc-related overlays after refactor
+
+The addition of the mmcnr node to the base dtbs caused some overlays to
+not work as they should. Patch up pi3-disable-wifi, balena-fin and
+sdhost.
+
+---
+ arch/arm/boot/dts/overlays/balena-fin-overlay.dts | 7 ++++---
+ arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts | 7 +++++++
+ arch/arm/boot/dts/overlays/sdhost-overlay.dts | 7 +++++++
+ 3 files changed, 18 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
++++ b/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
+@@ -5,13 +5,12 @@
+ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+- target = <&mmc>;
+- sdio_wifi: __overlay__ {
++ target = <&mmcnr>;
++ __overlay__ {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdio_pins>;
+ bus-width = <4>;
+ brcm,overclock-50 = <35>;
+- non-removable;
+ status = "okay";
+ };
+ };
+@@ -43,6 +42,8 @@
+ compatible = "gpio-poweroff";
+ gpios = <&gpio 40 1>;
+ force;
++ pinctrl-names = "default";
++ pinctrl-0 = <&power_ctrl_pins>;
+ };
+
+ i2c_soft: i2c@0 {
+--- a/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts
+@@ -10,4 +10,11 @@
+ status = "disabled";
+ };
+ };
++
++ fragment@1 {
++ target = <&mmcnr>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
+ };
+--- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts
+@@ -22,6 +22,13 @@
+ };
+ };
+
++ fragment@2 {
++ target = <&mmcnr>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
+ __overrides__ {
+ overclock_50 = <&frag0>,"brcm,overclock-50:0";
+ force_pio = <&frag0>,"brcm,force-pio?";
+++ /dev/null
-From e819b50b0c384f11f4eaf6e1ea76030c320f4511 Mon Sep 17 00:00:00 2001
-Date: Tue, 28 May 2019 16:23:51 +0100
-Subject: [PATCH] BCM270X_DT: Create bcm2708-rpi-zero.dts
-
-The Pi Zero deserves a dedicated .dtb file - sharing the b-plus .dtb
-has been observed to cause an issue with the MAC address of some
-Ethernet dongles.
-
-See: https://github.com/raspberrypi/linux/issues/2990
-
----
- arch/arm/boot/dts/Makefile | 1 +
- arch/arm/boot/dts/bcm2708-rpi-zero.dts | 117 +++++++++++++++++++++++++
- 2 files changed, 118 insertions(+)
- create mode 100644 arch/arm/boot/dts/bcm2708-rpi-zero.dts
-
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -4,6 +4,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
- bcm2708-rpi-b.dtb \
- bcm2708-rpi-b-plus.dtb \
- bcm2708-rpi-cm.dtb \
-+ bcm2708-rpi-zero.dtb \
- bcm2708-rpi-zero-w.dtb \
- bcm2709-rpi-2-b.dtb \
- bcm2710-rpi-3-b.dtb \
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2708-rpi-zero.dts
-@@ -0,0 +1,117 @@
-+/dts-v1/;
-+
-+#include "bcm2708.dtsi"
-+#include "bcm283x-rpi-csi1-2lane.dtsi"
-+
-+/ {
-+ compatible = "raspberrypi,model-zero", "brcm,bcm2835";
-+ model = "Raspberry Pi Zero";
-+
-+ chosen {
-+ bootargs = "coherent_pool=1M";
-+ };
-+};
-+
-+&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 */
-+ };
-+
-+ audio_pins: audio_pins {
-+ brcm,pins = <>;
-+ brcm,function = <>;
-+ };
-+};
-+
-+&uart0 {
-+ 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>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ 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: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 47 0>;
-+ };
-+};
-+
-+&hdmi {
-+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+};
-+
-+&audio {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&audio_pins>;
-+};
-+
-+/ {
-+ __overrides__ {
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+ };
-+};
--- /dev/null
+From 539e2eef7dbfb58ab028a5530430611973dd4c84 Mon Sep 17 00:00:00 2001
+Date: Thu, 6 Jun 2019 10:20:55 +0100
+Subject: [PATCH] Fixed 48k timing issue
+
+---
+ sound/soc/bcm/iqaudio-codec.c | 33 ++++++++++++++++++++++++++++-----
+ 1 file changed, 28 insertions(+), 5 deletions(-)
+
+--- a/sound/soc/bcm/iqaudio-codec.c
++++ b/sound/soc/bcm/iqaudio-codec.c
+@@ -45,11 +45,15 @@ static int snd_rpi_iqaudio_pll_control(s
+ 0);
+ if (ret)
+ dev_err(card->dev, "Failed to bypass PLL: %d\n", ret);
++ /* Allow PLL time to bypass */
++ msleep(100);
+ } else if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0,
+ pll_out);
+ if (ret)
+ dev_err(card->dev, "Failed to enable PLL: %d\n", ret);
++ /* Allow PLL time to lock */
++ msleep(100);
+ }
+
+ return ret;
+@@ -71,6 +75,13 @@ static int snd_rpi_iqaudio_post_dapm_eve
+ return 0;
+ }
+
++static const struct snd_kcontrol_new dapm_controls[] = {
++ SOC_DAPM_PIN_SWITCH("HP Jack"),
++ SOC_DAPM_PIN_SWITCH("MIC Jack"),
++ SOC_DAPM_PIN_SWITCH("Onboard MIC"),
++ SOC_DAPM_PIN_SWITCH("AUX Jack"),
++};
++
+ static const struct snd_soc_dapm_widget dapm_widgets[] = {
+ SND_SOC_DAPM_HP("HP Jack", NULL),
+ SND_SOC_DAPM_MIC("MIC Jack", NULL),
+@@ -87,14 +98,14 @@ static const struct snd_soc_dapm_route a
+ {"HP Jack", NULL, "HPR"},
+ {"HP Jack", NULL, "PLL Control"},
+
+- {"AUX Jack", NULL, "AUXR"},
+- {"AUX Jack", NULL, "AUXL"},
++ {"AUXR", NULL, "AUX Jack"},
++ {"AUXL", NULL, "AUX Jack"},
+ {"AUX Jack", NULL, "PLL Control"},
+
+ /* Assume Mic1 is linked to Headset and Mic2 to on-board mic */
+- {"MIC Jack", NULL, "MIC1"},
++ {"MIC1", NULL, "MIC Jack"},
+ {"MIC Jack", NULL, "PLL Control"},
+- {"Onboard MIC", NULL, "MIC2"},
++ {"MIC2", NULL, "Onboard MIC"},
+ {"Onboard MIC", NULL, "PLL Control"},
+ };
+
+@@ -106,6 +117,16 @@ static int snd_rpi_iqaudio_codec_init(st
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret;
+
++ /*
++ * Disable AUX Jack Pin by default to prevent PLL being enabled at
++ * startup. This avoids holding the PLL to a fixed SR config for
++ * subsequent streams.
++ *
++ * This pin can still be enabled later, as required by user-space.
++ */
++ snd_soc_dapm_disable_pin(&rtd->card->dapm, "AUX Jack");
++ snd_soc_dapm_sync(&rtd->card->dapm);
++
+ /* Set bclk ratio to align with codec's BCLK rate */
+ ret = snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
+ if (ret) {
+@@ -168,6 +189,8 @@ static struct snd_soc_card snd_rpi_iqaud
+ .owner = THIS_MODULE,
+ .dai_link = snd_rpi_iqaudio_codec_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_codec_dai),
++ .controls = dapm_controls,
++ .num_controls = ARRAY_SIZE(dapm_controls),
+ .dapm_widgets = dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
+ .dapm_routes = audio_map,
+@@ -204,7 +227,7 @@ static int snd_rpi_iqaudio_codec_probe(s
+
+ if (of_property_read_string(pdev->dev.of_node,
+ "dai_stream_name", &dai->stream_name))
+- dai->stream_name = "IQaudIO CODEC HiFi v1.1";
++ dai->stream_name = "IQaudIO CODEC HiFi v1.2";
+
+ }
+
+++ /dev/null
-From dadcb33e1f4ee70bc77da7fa7054b8571a22d5ea Mon Sep 17 00:00:00 2001
-Date: Thu, 30 May 2019 12:25:29 +0100
-Subject: [PATCH] overlays: Fix mmc-related overlays after refactor
-
-The addition of the mmcnr node to the base dtbs caused some overlays to
-not work as they should. Patch up pi3-disable-wifi, balena-fin and
-sdhost.
-
----
- arch/arm/boot/dts/overlays/balena-fin-overlay.dts | 7 ++++---
- arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts | 7 +++++++
- arch/arm/boot/dts/overlays/sdhost-overlay.dts | 7 +++++++
- 3 files changed, 18 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
-@@ -5,13 +5,12 @@
- compatible = "brcm,bcm2835";
-
- fragment@0 {
-- target = <&mmc>;
-- sdio_wifi: __overlay__ {
-+ target = <&mmcnr>;
-+ __overlay__ {
- pinctrl-names = "default";
- pinctrl-0 = <&sdio_pins>;
- bus-width = <4>;
- brcm,overclock-50 = <35>;
-- non-removable;
- status = "okay";
- };
- };
-@@ -43,6 +42,8 @@
- compatible = "gpio-poweroff";
- gpios = <&gpio 40 1>;
- force;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&power_ctrl_pins>;
- };
-
- i2c_soft: i2c@0 {
---- a/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts
-@@ -10,4 +10,11 @@
- status = "disabled";
- };
- };
-+
-+ fragment@1 {
-+ target = <&mmcnr>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
- };
---- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts
-@@ -22,6 +22,13 @@
- };
- };
-
-+ fragment@2 {
-+ target = <&mmcnr>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
- __overrides__ {
- overclock_50 = <&frag0>,"brcm,overclock-50:0";
- force_pio = <&frag0>,"brcm,force-pio?";
--- /dev/null
+From 3da653227926705fe0dcb7b6057be1ca811f47b8 Mon Sep 17 00:00:00 2001
+Date: Fri, 10 May 2019 14:11:58 +0100
+Subject: [PATCH] staging: bcm2835-codec: Convert V4L2 nsec timestamps
+ to MMAL usec
+
+V4L2 uses nsecs, whilst MMAL uses usecs, but the code wasn't converting
+between them. This upsets video encode rate control.
+
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -823,7 +823,8 @@ static void op_buffer_cb(struct vchiq_mm
+ vb2->flags |= V4L2_BUF_FLAG_LAST;
+ }
+
+- vb2->vb2_buf.timestamp = mmal_buf->pts;
++ /* vb2 timestamps in nsecs, mmal in usecs */
++ vb2->vb2_buf.timestamp = mmal_buf->pts * 1000;
+
+ vb2_set_plane_payload(&vb2->vb2_buf, 0, mmal_buf->length);
+ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+@@ -847,6 +848,7 @@ static void op_buffer_cb(struct vchiq_mm
+ static void vb2_to_mmal_buffer(struct m2m_mmal_buffer *buf,
+ struct vb2_v4l2_buffer *vb2)
+ {
++ u64 pts;
+ buf->mmal.mmal_flags = 0;
+ if (vb2->flags & V4L2_BUF_FLAG_KEYFRAME)
+ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME;
+@@ -869,7 +871,10 @@ static void vb2_to_mmal_buffer(struct m2
+ if (!buf->mmal.length || vb2->flags & V4L2_BUF_FLAG_LAST)
+ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_EOS;
+
+- buf->mmal.pts = vb2->vb2_buf.timestamp;
++ /* vb2 timestamps in nsecs, mmal in usecs */
++ pts = vb2->vb2_buf.timestamp;
++ do_div(pts, 1000);
++ buf->mmal.pts = pts;
+ buf->mmal.dts = MMAL_TIME_UNKNOWN;
+ }
+
+++ /dev/null
-From 539e2eef7dbfb58ab028a5530430611973dd4c84 Mon Sep 17 00:00:00 2001
-Date: Thu, 6 Jun 2019 10:20:55 +0100
-Subject: [PATCH] Fixed 48k timing issue
-
----
- sound/soc/bcm/iqaudio-codec.c | 33 ++++++++++++++++++++++++++++-----
- 1 file changed, 28 insertions(+), 5 deletions(-)
-
---- a/sound/soc/bcm/iqaudio-codec.c
-+++ b/sound/soc/bcm/iqaudio-codec.c
-@@ -45,11 +45,15 @@ static int snd_rpi_iqaudio_pll_control(s
- 0);
- if (ret)
- dev_err(card->dev, "Failed to bypass PLL: %d\n", ret);
-+ /* Allow PLL time to bypass */
-+ msleep(100);
- } else if (SND_SOC_DAPM_EVENT_ON(event)) {
- ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0,
- pll_out);
- if (ret)
- dev_err(card->dev, "Failed to enable PLL: %d\n", ret);
-+ /* Allow PLL time to lock */
-+ msleep(100);
- }
-
- return ret;
-@@ -71,6 +75,13 @@ static int snd_rpi_iqaudio_post_dapm_eve
- return 0;
- }
-
-+static const struct snd_kcontrol_new dapm_controls[] = {
-+ SOC_DAPM_PIN_SWITCH("HP Jack"),
-+ SOC_DAPM_PIN_SWITCH("MIC Jack"),
-+ SOC_DAPM_PIN_SWITCH("Onboard MIC"),
-+ SOC_DAPM_PIN_SWITCH("AUX Jack"),
-+};
-+
- static const struct snd_soc_dapm_widget dapm_widgets[] = {
- SND_SOC_DAPM_HP("HP Jack", NULL),
- SND_SOC_DAPM_MIC("MIC Jack", NULL),
-@@ -87,14 +98,14 @@ static const struct snd_soc_dapm_route a
- {"HP Jack", NULL, "HPR"},
- {"HP Jack", NULL, "PLL Control"},
-
-- {"AUX Jack", NULL, "AUXR"},
-- {"AUX Jack", NULL, "AUXL"},
-+ {"AUXR", NULL, "AUX Jack"},
-+ {"AUXL", NULL, "AUX Jack"},
- {"AUX Jack", NULL, "PLL Control"},
-
- /* Assume Mic1 is linked to Headset and Mic2 to on-board mic */
-- {"MIC Jack", NULL, "MIC1"},
-+ {"MIC1", NULL, "MIC Jack"},
- {"MIC Jack", NULL, "PLL Control"},
-- {"Onboard MIC", NULL, "MIC2"},
-+ {"MIC2", NULL, "Onboard MIC"},
- {"Onboard MIC", NULL, "PLL Control"},
- };
-
-@@ -106,6 +117,16 @@ static int snd_rpi_iqaudio_codec_init(st
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret;
-
-+ /*
-+ * Disable AUX Jack Pin by default to prevent PLL being enabled at
-+ * startup. This avoids holding the PLL to a fixed SR config for
-+ * subsequent streams.
-+ *
-+ * This pin can still be enabled later, as required by user-space.
-+ */
-+ snd_soc_dapm_disable_pin(&rtd->card->dapm, "AUX Jack");
-+ snd_soc_dapm_sync(&rtd->card->dapm);
-+
- /* Set bclk ratio to align with codec's BCLK rate */
- ret = snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
- if (ret) {
-@@ -168,6 +189,8 @@ static struct snd_soc_card snd_rpi_iqaud
- .owner = THIS_MODULE,
- .dai_link = snd_rpi_iqaudio_codec_dai,
- .num_links = ARRAY_SIZE(snd_rpi_iqaudio_codec_dai),
-+ .controls = dapm_controls,
-+ .num_controls = ARRAY_SIZE(dapm_controls),
- .dapm_widgets = dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
- .dapm_routes = audio_map,
-@@ -204,7 +227,7 @@ static int snd_rpi_iqaudio_codec_probe(s
-
- if (of_property_read_string(pdev->dev.of_node,
- "dai_stream_name", &dai->stream_name))
-- dai->stream_name = "IQaudIO CODEC HiFi v1.1";
-+ dai->stream_name = "IQaudIO CODEC HiFi v1.2";
-
- }
-
--- /dev/null
+From 67c1f9dd0253a1175f77e801b19bd9d923225f9c Mon Sep 17 00:00:00 2001
+Date: Fri, 10 May 2019 14:13:11 +0100
+Subject: [PATCH] staging: bcm2835-codec: Add support for setting
+ S_PARM and G_PARM
+
+Video encode can use the frame rate for rate control calculations,
+therefore plumb it through from V4L2's [S|G]_PARM ioctl.
+
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 52 +++++++++++++++++--
+ 1 file changed, 48 insertions(+), 4 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -447,6 +447,8 @@ struct bcm2835_codec_ctx {
+ /* Source and destination queue data */
+ struct bcm2835_codec_q_data q_data[2];
+ s32 bitrate;
++ unsigned int framerate_num;
++ unsigned int framerate_denom;
+
+ bool aborting;
+ int num_ip_buffers;
+@@ -610,8 +612,8 @@ static void setup_mmal_port_format(struc
+ port->es.video.height = q_data->height;
+ port->es.video.crop.width = q_data->crop_width;
+ port->es.video.crop.height = q_data->crop_height;
+- port->es.video.frame_rate.num = 0;
+- port->es.video.frame_rate.den = 1;
++ port->es.video.frame_rate.num = ctx->framerate_num;
++ port->es.video.frame_rate.den = ctx->framerate_denom;
+ } else {
+ /* Compressed format - leave resolution as 0 for decode */
+ if (ctx->dev->role == DECODE) {
+@@ -625,9 +627,9 @@ static void setup_mmal_port_format(struc
+ port->es.video.crop.width = q_data->crop_width;
+ port->es.video.crop.height = q_data->crop_height;
+ port->format.bitrate = ctx->bitrate;
++ port->es.video.frame_rate.num = ctx->framerate_num;
++ port->es.video.frame_rate.den = ctx->framerate_denom;
+ }
+- port->es.video.frame_rate.num = 0;
+- port->es.video.frame_rate.den = 1;
+ }
+ port->es.video.crop.x = 0;
+ port->es.video.crop.y = 0;
+@@ -1361,6 +1363,41 @@ static int vidioc_s_selection(struct fil
+ return 0;
+ }
+
++static int vidioc_s_parm(struct file *file, void *priv,
++ struct v4l2_streamparm *parm)
++{
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++
++ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ return -EINVAL;
++
++ ctx->framerate_num =
++ parm->parm.output.timeperframe.denominator;
++ ctx->framerate_denom =
++ parm->parm.output.timeperframe.numerator;
++
++ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
++
++ return 0;
++}
++
++static int vidioc_g_parm(struct file *file, void *priv,
++ struct v4l2_streamparm *parm)
++{
++ struct bcm2835_codec_ctx *ctx = file2ctx(file);
++
++ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ return -EINVAL;
++
++ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
++ parm->parm.output.timeperframe.denominator =
++ ctx->framerate_num;
++ parm->parm.output.timeperframe.numerator =
++ ctx->framerate_denom;
++
++ return 0;
++}
++
+ static int vidioc_subscribe_evt(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+ {
+@@ -1725,6 +1762,9 @@ static const struct v4l2_ioctl_ops bcm28
+ .vidioc_g_selection = vidioc_g_selection,
+ .vidioc_s_selection = vidioc_s_selection,
+
++ .vidioc_g_parm = vidioc_g_parm,
++ .vidioc_s_parm = vidioc_s_parm,
++
+ .vidioc_subscribe_event = vidioc_subscribe_evt,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+@@ -2546,6 +2586,8 @@ static int bcm2835_codec_create(struct p
+ case DECODE:
+ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
++ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
++ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
+ video_nr = decode_video_nr;
+ break;
+ case ENCODE:
+@@ -2558,6 +2600,8 @@ static int bcm2835_codec_create(struct p
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
++ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
++ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
+ video_nr = isp_video_nr;
+ break;
+ default:
+++ /dev/null
-From 3da653227926705fe0dcb7b6057be1ca811f47b8 Mon Sep 17 00:00:00 2001
-Date: Fri, 10 May 2019 14:11:58 +0100
-Subject: [PATCH] staging: bcm2835-codec: Convert V4L2 nsec timestamps
- to MMAL usec
-
-V4L2 uses nsecs, whilst MMAL uses usecs, but the code wasn't converting
-between them. This upsets video encode rate control.
-
----
- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 9 +++++++--
- 1 file changed, 7 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -823,7 +823,8 @@ static void op_buffer_cb(struct vchiq_mm
- vb2->flags |= V4L2_BUF_FLAG_LAST;
- }
-
-- vb2->vb2_buf.timestamp = mmal_buf->pts;
-+ /* vb2 timestamps in nsecs, mmal in usecs */
-+ vb2->vb2_buf.timestamp = mmal_buf->pts * 1000;
-
- vb2_set_plane_payload(&vb2->vb2_buf, 0, mmal_buf->length);
- if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
-@@ -847,6 +848,7 @@ static void op_buffer_cb(struct vchiq_mm
- static void vb2_to_mmal_buffer(struct m2m_mmal_buffer *buf,
- struct vb2_v4l2_buffer *vb2)
- {
-+ u64 pts;
- buf->mmal.mmal_flags = 0;
- if (vb2->flags & V4L2_BUF_FLAG_KEYFRAME)
- buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME;
-@@ -869,7 +871,10 @@ static void vb2_to_mmal_buffer(struct m2
- if (!buf->mmal.length || vb2->flags & V4L2_BUF_FLAG_LAST)
- buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_EOS;
-
-- buf->mmal.pts = vb2->vb2_buf.timestamp;
-+ /* vb2 timestamps in nsecs, mmal in usecs */
-+ pts = vb2->vb2_buf.timestamp;
-+ do_div(pts, 1000);
-+ buf->mmal.pts = pts;
- buf->mmal.dts = MMAL_TIME_UNKNOWN;
- }
-
--- /dev/null
+From afea1f84cbda94c47ba4a8f84d16c4330e145a0a Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Jun 2019 17:15:05 +0100
+Subject: [PATCH] w1: w1-gpio: Make GPIO an output for strong pullup
+
+The logic to drive the data line high to implement a strong pullup
+assumed that the pin was already an output - setting a value does
+not change an input.
+
+See: https://github.com/raspberrypi/firmware/issues/1143
+
+---
+ drivers/w1/masters/w1-gpio.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/w1/masters/w1-gpio.c
++++ b/drivers/w1/masters/w1-gpio.c
+@@ -33,7 +33,7 @@ static u8 w1_gpio_set_pullup(void *data,
+ * This will OVERRIDE open drain emulation and force-pull
+ * the line high for some time.
+ */
+- gpiod_set_raw_value(pdata->gpiod, 1);
++ gpiod_direction_output_raw(pdata->gpiod, 1);
+ msleep(pdata->pullup_duration);
+ /*
+ * This will simply set the line as input since we are doing
--- /dev/null
+From 531ae7af75b2be2867814693f069fb51e3155341 Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Jun 2019 17:32:11 +0100
+Subject: [PATCH] overlays: Update w1-gpio and w1-gpio-pullup
+
+The parasitic power (power on data) feature is now enabled by
+default in the w1-gpio driver, so update the README and make the
+"pullup" parameter a no-op.
+
+---
+ arch/arm/boot/dts/overlays/README | 9 ++-------
+ arch/arm/boot/dts/overlays/w1-gpio-overlay.dts | 3 +--
+ arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts | 3 +--
+ 3 files changed, 4 insertions(+), 11 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2261,9 +2261,7 @@ Info: Configures the w1-gpio Onewire i
+ Use this overlay if you *don't* need a GPIO to drive an external pullup.
+ Load: dtoverlay=w1-gpio,<param>=<val>
+ Params: gpiopin GPIO for I/O (default "4")
+-
+- pullup Non-zero, "on", or "y" to enable the parasitic
+- power (2-wire, power-on-data) feature
++ pullup Now enabled by default (ignored)
+
+
+ Name: w1-gpio-pullup
+@@ -2271,11 +2269,8 @@ Info: Configures the w1-gpio Onewire i
+ Use this overlay if you *do* need a GPIO to drive an external pullup.
+ Load: dtoverlay=w1-gpio-pullup,<param>=<val>
+ Params: gpiopin GPIO for I/O (default "4")
+-
+- pullup Non-zero, "on", or "y" to enable the parasitic
+- power (2-wire, power-on-data) feature
+-
+ extpullup GPIO for external pullup (default "5")
++ pullup Now enabled by default (ignored)
+
+
+ Name: wittypi
+--- a/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
+@@ -14,7 +14,6 @@
+ pinctrl-names = "default";
+ pinctrl-0 = <&w1_pins>;
+ gpios = <&gpio 4 0>;
+- rpi,parasitic-power = <0>;
+ status = "okay";
+ };
+ };
+@@ -36,6 +35,6 @@
+ <&w1>,"reg:0",
+ <&w1_pins>,"brcm,pins:0",
+ <&w1_pins>,"reg:0";
+- pullup = <&w1>,"rpi,parasitic-power:0";
++ pullup; // Silently ignore unneeded parameter
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
++++ b/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
+@@ -14,7 +14,6 @@
+ pinctrl-names = "default";
+ pinctrl-0 = <&w1_pins>;
+ gpios = <&gpio 4 0>, <&gpio 5 1>;
+- rpi,parasitic-power = <0>;
+ status = "okay";
+ };
+ };
+@@ -38,6 +37,6 @@
+ <&w1_pins>,"reg:0";
+ extpullup = <&w1>,"gpios:16",
+ <&w1_pins>,"brcm,pins:4";
+- pullup = <&w1>,"rpi,parasitic-power:0";
++ pullup; // Silently ignore unneeded parameter
+ };
+ };
+++ /dev/null
-From 67c1f9dd0253a1175f77e801b19bd9d923225f9c Mon Sep 17 00:00:00 2001
-Date: Fri, 10 May 2019 14:13:11 +0100
-Subject: [PATCH] staging: bcm2835-codec: Add support for setting
- S_PARM and G_PARM
-
-Video encode can use the frame rate for rate control calculations,
-therefore plumb it through from V4L2's [S|G]_PARM ioctl.
-
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 52 +++++++++++++++++--
- 1 file changed, 48 insertions(+), 4 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -447,6 +447,8 @@ struct bcm2835_codec_ctx {
- /* Source and destination queue data */
- struct bcm2835_codec_q_data q_data[2];
- s32 bitrate;
-+ unsigned int framerate_num;
-+ unsigned int framerate_denom;
-
- bool aborting;
- int num_ip_buffers;
-@@ -610,8 +612,8 @@ static void setup_mmal_port_format(struc
- port->es.video.height = q_data->height;
- port->es.video.crop.width = q_data->crop_width;
- port->es.video.crop.height = q_data->crop_height;
-- port->es.video.frame_rate.num = 0;
-- port->es.video.frame_rate.den = 1;
-+ port->es.video.frame_rate.num = ctx->framerate_num;
-+ port->es.video.frame_rate.den = ctx->framerate_denom;
- } else {
- /* Compressed format - leave resolution as 0 for decode */
- if (ctx->dev->role == DECODE) {
-@@ -625,9 +627,9 @@ static void setup_mmal_port_format(struc
- port->es.video.crop.width = q_data->crop_width;
- port->es.video.crop.height = q_data->crop_height;
- port->format.bitrate = ctx->bitrate;
-+ port->es.video.frame_rate.num = ctx->framerate_num;
-+ port->es.video.frame_rate.den = ctx->framerate_denom;
- }
-- port->es.video.frame_rate.num = 0;
-- port->es.video.frame_rate.den = 1;
- }
- port->es.video.crop.x = 0;
- port->es.video.crop.y = 0;
-@@ -1361,6 +1363,41 @@ static int vidioc_s_selection(struct fil
- return 0;
- }
-
-+static int vidioc_s_parm(struct file *file, void *priv,
-+ struct v4l2_streamparm *parm)
-+{
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+
-+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-+ return -EINVAL;
-+
-+ ctx->framerate_num =
-+ parm->parm.output.timeperframe.denominator;
-+ ctx->framerate_denom =
-+ parm->parm.output.timeperframe.numerator;
-+
-+ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
-+
-+ return 0;
-+}
-+
-+static int vidioc_g_parm(struct file *file, void *priv,
-+ struct v4l2_streamparm *parm)
-+{
-+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
-+
-+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-+ return -EINVAL;
-+
-+ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
-+ parm->parm.output.timeperframe.denominator =
-+ ctx->framerate_num;
-+ parm->parm.output.timeperframe.numerator =
-+ ctx->framerate_denom;
-+
-+ return 0;
-+}
-+
- static int vidioc_subscribe_evt(struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub)
- {
-@@ -1725,6 +1762,9 @@ static const struct v4l2_ioctl_ops bcm28
- .vidioc_g_selection = vidioc_g_selection,
- .vidioc_s_selection = vidioc_s_selection,
-
-+ .vidioc_g_parm = vidioc_g_parm,
-+ .vidioc_s_parm = vidioc_s_parm,
-+
- .vidioc_subscribe_event = vidioc_subscribe_evt,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-
-@@ -2546,6 +2586,8 @@ static int bcm2835_codec_create(struct p
- case DECODE:
- v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
-+ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
-+ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
- video_nr = decode_video_nr;
- break;
- case ENCODE:
-@@ -2558,6 +2600,8 @@ static int bcm2835_codec_create(struct p
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
-+ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
-+ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
- video_nr = isp_video_nr;
- break;
- default:
--- /dev/null
+From 73623c76c8bc8c41a4afefc1eee84dfc5979d652 Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Jun 2019 20:45:17 +0100
+Subject: [PATCH] bcm2835-sdhost: Fix DMA channel leak on error/remove
+
+---
+ drivers/mmc/host/bcm2835-sdhost.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -2154,6 +2154,8 @@ static int bcm2835_sdhost_probe(struct p
+
+ err:
+ pr_debug("bcm2835_sdhost_probe -> err %d\n", ret);
++ if (host->dma_chan_rxtx)
++ dma_release_channel(host->dma_chan_rxtx);
+ mmc_free_host(mmc);
+
+ return ret;
+@@ -2174,7 +2176,8 @@ static int bcm2835_sdhost_remove(struct
+ del_timer_sync(&host->timer);
+
+ tasklet_kill(&host->finish_tasklet);
+-
++ if (host->dma_chan_rxtx)
++ dma_release_channel(host->dma_chan_rxtx);
+ mmc_free_host(host->mmc);
+ platform_set_drvdata(pdev, NULL);
+
+++ /dev/null
-From afea1f84cbda94c47ba4a8f84d16c4330e145a0a Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Jun 2019 17:15:05 +0100
-Subject: [PATCH] w1: w1-gpio: Make GPIO an output for strong pullup
-
-The logic to drive the data line high to implement a strong pullup
-assumed that the pin was already an output - setting a value does
-not change an input.
-
-See: https://github.com/raspberrypi/firmware/issues/1143
-
----
- drivers/w1/masters/w1-gpio.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/w1/masters/w1-gpio.c
-+++ b/drivers/w1/masters/w1-gpio.c
-@@ -33,7 +33,7 @@ static u8 w1_gpio_set_pullup(void *data,
- * This will OVERRIDE open drain emulation and force-pull
- * the line high for some time.
- */
-- gpiod_set_raw_value(pdata->gpiod, 1);
-+ gpiod_direction_output_raw(pdata->gpiod, 1);
- msleep(pdata->pullup_duration);
- /*
- * This will simply set the line as input since we are doing
--- /dev/null
+From ffbb6cc14b8fb1876b249048284a5fe30f48c693 Mon Sep 17 00:00:00 2001
+Date: Sat, 8 Jun 2019 10:14:43 -0700
+Subject: [PATCH] i2c: bcm2835: Model Divider in CCF
+
+Commit bebff81fb8b9216eb4fba22cf910553621ae3477 upstream.
+
+Model the I2C bus clock divider as a part of the Core Clock Framework.
+Primarily this removes the clk_get_rate() call from each transfer.
+This call causes problems for slave drivers that themselves have
+internal clock components that are controlled by an I2C interface.
+When the slave's internal clock component is prepared, the prepare
+lock is obtained, and it makes calls to the I2C subsystem to
+command the hardware to activate the clock. In order to perform
+the I2C transfer, this driver sets the divider, which requires
+it to get the parent clock rate, which it does with clk_get_rate().
+Unfortunately, this function will try to take the clock prepare
+lock, which is already held by the slave's internal clock calls
+creating a deadlock.
+
+Modeling the divider in the CCF natively removes this dependency
+and the divider value is only set upon changing the bus clock
+frequency or changes in the parent clock that cascade down to this
+divisor. This obviates the need to set the divider with every
+transfer and avoids the deadlock described above. It also should
+provide better clock debugging and save a few cycles on each
+transfer due to not having to recalcuate the divider value.
+
+---
+ drivers/i2c/busses/i2c-bcm2835.c | 145 ++++++++++++++++++++++++-------
+ 1 file changed, 114 insertions(+), 31 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-bcm2835.c
++++ b/drivers/i2c/busses/i2c-bcm2835.c
+@@ -12,6 +12,8 @@
+ */
+
+ #include <linux/clk.h>
++#include <linux/clkdev.h>
++#include <linux/clk-provider.h>
+ #include <linux/completion.h>
+ #include <linux/err.h>
+ #include <linux/i2c.h>
+@@ -71,9 +73,7 @@ struct bcm2835_debug {
+ struct bcm2835_i2c_dev {
+ struct device *dev;
+ void __iomem *regs;
+- struct clk *clk;
+ int irq;
+- u32 bus_clk_rate;
+ struct i2c_adapter adapter;
+ struct completion completion;
+ struct i2c_msg *curr_msg;
+@@ -164,12 +164,17 @@ static inline u32 bcm2835_i2c_readl(stru
+ return readl(i2c_dev->regs + reg);
+ }
+
+-static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
++#define to_clk_bcm2835_i2c(_hw) container_of(_hw, struct clk_bcm2835_i2c, hw)
++struct clk_bcm2835_i2c {
++ struct clk_hw hw;
++ struct bcm2835_i2c_dev *i2c_dev;
++};
++
++static int clk_bcm2835_i2c_calc_divider(unsigned long rate,
++ unsigned long parent_rate)
+ {
+- u32 divider, redl, fedl;
++ u32 divider = DIV_ROUND_UP(parent_rate, rate);
+
+- divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk),
+- i2c_dev->bus_clk_rate);
+ /*
+ * Per the datasheet, the register is always interpreted as an even
+ * number, by rounding down. In other words, the LSB is ignored. So,
+@@ -178,12 +183,23 @@ static int bcm2835_i2c_set_divider(struc
+ if (divider & 1)
+ divider++;
+ if ((divider < BCM2835_I2C_CDIV_MIN) ||
+- (divider > BCM2835_I2C_CDIV_MAX)) {
+- dev_err_ratelimited(i2c_dev->dev, "Invalid clock-frequency\n");
++ (divider > BCM2835_I2C_CDIV_MAX))
+ return -EINVAL;
+- }
+
+- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
++ return divider;
++}
++
++static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
++ u32 redl, fedl;
++ u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate);
++
++ if (divider == -EINVAL)
++ return -EINVAL;
++
++ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DIV, divider);
+
+ /*
+ * Number of core clocks to wait after falling edge before
+@@ -198,12 +214,62 @@ static int bcm2835_i2c_set_divider(struc
+ */
+ redl = max(divider / 4, 1u);
+
+- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL,
++ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL,
+ (fedl << BCM2835_I2C_FEDL_SHIFT) |
+ (redl << BCM2835_I2C_REDL_SHIFT));
+ return 0;
+ }
+
++static long clk_bcm2835_i2c_round_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long *parent_rate)
++{
++ u32 divider = clk_bcm2835_i2c_calc_divider(rate, *parent_rate);
++
++ return DIV_ROUND_UP(*parent_rate, divider);
++}
++
++static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
++ u32 divider = bcm2835_i2c_readl(div->i2c_dev, BCM2835_I2C_DIV);
++
++ return DIV_ROUND_UP(parent_rate, divider);
++}
++
++static const struct clk_ops clk_bcm2835_i2c_ops = {
++ .set_rate = clk_bcm2835_i2c_set_rate,
++ .round_rate = clk_bcm2835_i2c_round_rate,
++ .recalc_rate = clk_bcm2835_i2c_recalc_rate,
++};
++
++static struct clk *bcm2835_i2c_register_div(struct device *dev,
++ const char *mclk_name,
++ struct bcm2835_i2c_dev *i2c_dev)
++{
++ struct clk_init_data init;
++ struct clk_bcm2835_i2c *priv;
++ char name[32];
++
++ snprintf(name, sizeof(name), "%s_div", dev_name(dev));
++
++ init.ops = &clk_bcm2835_i2c_ops;
++ init.name = name;
++ init.parent_names = (const char* []) { mclk_name };
++ init.num_parents = 1;
++ init.flags = 0;
++
++ priv = devm_kzalloc(dev, sizeof(struct clk_bcm2835_i2c), GFP_KERNEL);
++ if (priv == NULL)
++ return ERR_PTR(-ENOMEM);
++
++ priv->hw.init = &init;
++ priv->i2c_dev = i2c_dev;
++
++ clk_hw_register_clkdev(&priv->hw, "div", dev_name(dev));
++ return devm_clk_register(dev, &priv->hw);
++}
++
+ static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev)
+ {
+ u32 val;
+@@ -363,7 +429,7 @@ static int bcm2835_i2c_xfer(struct i2c_a
+ {
+ struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+ unsigned long time_left;
+- int i, ret;
++ int i;
+
+ if (debug)
+ i2c_dev->debug_num_msgs = num;
+@@ -379,10 +445,6 @@ static int bcm2835_i2c_xfer(struct i2c_a
+ return -EOPNOTSUPP;
+ }
+
+- ret = bcm2835_i2c_set_divider(i2c_dev);
+- if (ret)
+- return ret;
+-
+ i2c_dev->curr_msg = msgs;
+ i2c_dev->num_msgs = num;
+ reinit_completion(&i2c_dev->completion);
+@@ -443,6 +505,9 @@ static int bcm2835_i2c_probe(struct plat
+ struct resource *mem, *irq;
+ int ret;
+ struct i2c_adapter *adap;
++ const char *mclk_name;
++ struct clk *bus_clk;
++ u32 bus_clk_rate;
+
+ i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+ if (!i2c_dev)
+@@ -456,21 +521,6 @@ static int bcm2835_i2c_probe(struct plat
+ if (IS_ERR(i2c_dev->regs))
+ return PTR_ERR(i2c_dev->regs);
+
+- i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
+- if (IS_ERR(i2c_dev->clk)) {
+- if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
+- dev_err(&pdev->dev, "Could not get clock\n");
+- return PTR_ERR(i2c_dev->clk);
+- }
+-
+- ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+- &i2c_dev->bus_clk_rate);
+- if (ret < 0) {
+- dev_warn(&pdev->dev,
+- "Could not read clock-frequency property\n");
+- i2c_dev->bus_clk_rate = 100000;
+- }
+-
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "No IRQ resource\n");
+@@ -485,6 +535,35 @@ static int bcm2835_i2c_probe(struct plat
+ return -ENODEV;
+ }
+
++ mclk_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
++
++ bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk_name, i2c_dev);
++
++ if (IS_ERR(bus_clk)) {
++ dev_err(&pdev->dev, "Could not register clock\n");
++ return PTR_ERR(bus_clk);
++ }
++
++ ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
++ &bus_clk_rate);
++ if (ret < 0) {
++ dev_warn(&pdev->dev,
++ "Could not read clock-frequency property\n");
++ bus_clk_rate = 100000;
++ }
++
++ ret = clk_set_rate_exclusive(bus_clk, bus_clk_rate);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "Could not set clock frequency\n");
++ return ret;
++ }
++
++ ret = clk_prepare_enable(bus_clk);
++ if (ret) {
++ dev_err(&pdev->dev, "Couldn't prepare clock");
++ return ret;
++ }
++
+ adap = &i2c_dev->adapter;
+ i2c_set_adapdata(adap, i2c_dev);
+ adap->owner = THIS_MODULE;
+@@ -507,6 +586,10 @@ static int bcm2835_i2c_probe(struct plat
+ static int bcm2835_i2c_remove(struct platform_device *pdev)
+ {
+ struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
++ struct clk *bus_clk = devm_clk_get(i2c_dev->dev, "div");
++
++ clk_rate_exclusive_put(bus_clk);
++ clk_disable_unprepare(bus_clk);
+
+ free_irq(i2c_dev->irq, i2c_dev);
+ i2c_del_adapter(&i2c_dev->adapter);
+++ /dev/null
-From 531ae7af75b2be2867814693f069fb51e3155341 Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Jun 2019 17:32:11 +0100
-Subject: [PATCH] overlays: Update w1-gpio and w1-gpio-pullup
-
-The parasitic power (power on data) feature is now enabled by
-default in the w1-gpio driver, so update the README and make the
-"pullup" parameter a no-op.
-
----
- arch/arm/boot/dts/overlays/README | 9 ++-------
- arch/arm/boot/dts/overlays/w1-gpio-overlay.dts | 3 +--
- arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts | 3 +--
- 3 files changed, 4 insertions(+), 11 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -2261,9 +2261,7 @@ Info: Configures the w1-gpio Onewire i
- Use this overlay if you *don't* need a GPIO to drive an external pullup.
- Load: dtoverlay=w1-gpio,<param>=<val>
- Params: gpiopin GPIO for I/O (default "4")
--
-- pullup Non-zero, "on", or "y" to enable the parasitic
-- power (2-wire, power-on-data) feature
-+ pullup Now enabled by default (ignored)
-
-
- Name: w1-gpio-pullup
-@@ -2271,11 +2269,8 @@ Info: Configures the w1-gpio Onewire i
- Use this overlay if you *do* need a GPIO to drive an external pullup.
- Load: dtoverlay=w1-gpio-pullup,<param>=<val>
- Params: gpiopin GPIO for I/O (default "4")
--
-- pullup Non-zero, "on", or "y" to enable the parasitic
-- power (2-wire, power-on-data) feature
--
- extpullup GPIO for external pullup (default "5")
-+ pullup Now enabled by default (ignored)
-
-
- Name: wittypi
---- a/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/w1-gpio-overlay.dts
-@@ -14,7 +14,6 @@
- pinctrl-names = "default";
- pinctrl-0 = <&w1_pins>;
- gpios = <&gpio 4 0>;
-- rpi,parasitic-power = <0>;
- status = "okay";
- };
- };
-@@ -36,6 +35,6 @@
- <&w1>,"reg:0",
- <&w1_pins>,"brcm,pins:0",
- <&w1_pins>,"reg:0";
-- pullup = <&w1>,"rpi,parasitic-power:0";
-+ pullup; // Silently ignore unneeded parameter
- };
- };
---- a/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/w1-gpio-pullup-overlay.dts
-@@ -14,7 +14,6 @@
- pinctrl-names = "default";
- pinctrl-0 = <&w1_pins>;
- gpios = <&gpio 4 0>, <&gpio 5 1>;
-- rpi,parasitic-power = <0>;
- status = "okay";
- };
- };
-@@ -38,6 +37,6 @@
- <&w1_pins>,"reg:0";
- extpullup = <&w1>,"gpios:16",
- <&w1_pins>,"brcm,pins:4";
-- pullup = <&w1>,"rpi,parasitic-power:0";
-+ pullup; // Silently ignore unneeded parameter
- };
- };
+++ /dev/null
-From 73623c76c8bc8c41a4afefc1eee84dfc5979d652 Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Jun 2019 20:45:17 +0100
-Subject: [PATCH] bcm2835-sdhost: Fix DMA channel leak on error/remove
-
----
- drivers/mmc/host/bcm2835-sdhost.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
---- a/drivers/mmc/host/bcm2835-sdhost.c
-+++ b/drivers/mmc/host/bcm2835-sdhost.c
-@@ -2154,6 +2154,8 @@ static int bcm2835_sdhost_probe(struct p
-
- err:
- pr_debug("bcm2835_sdhost_probe -> err %d\n", ret);
-+ if (host->dma_chan_rxtx)
-+ dma_release_channel(host->dma_chan_rxtx);
- mmc_free_host(mmc);
-
- return ret;
-@@ -2174,7 +2176,8 @@ static int bcm2835_sdhost_remove(struct
- del_timer_sync(&host->timer);
-
- tasklet_kill(&host->finish_tasklet);
--
-+ if (host->dma_chan_rxtx)
-+ dma_release_channel(host->dma_chan_rxtx);
- mmc_free_host(host->mmc);
- platform_set_drvdata(pdev, NULL);
-
--- /dev/null
+From 63079fbe20c954140f8eb61f858b0774890f301c Mon Sep 17 00:00:00 2001
+Date: Mon, 17 Sep 2018 09:22:21 +0100
+Subject: [PATCH] staging/vc04_services: Use correct cache line size
+
+Use the compatible string in the DTB to select the correct cache line
+size for the SoC - 32 for BCM2835, and 64 for BCM2836 and BCM2837.
+
+---
+ .../interface/vchiq_arm/vchiq_2835_arm.c | 15 ++------
+ .../interface/vchiq_arm/vchiq_arm.c | 35 +++++++++++++------
+ .../interface/vchiq_arm/vchiq_arm.h | 5 +++
+ 3 files changed, 33 insertions(+), 22 deletions(-)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
+@@ -117,7 +117,8 @@ free_pagelist(struct vchiq_pagelist_info
+ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
+ {
+ struct device *dev = &pdev->dev;
+- struct rpi_firmware *fw = platform_get_drvdata(pdev);
++ struct vchiq_drvdata *drvdata = platform_get_drvdata(pdev);
++ struct rpi_firmware *fw = drvdata->fw;
+ VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
+ struct resource *res;
+ void *slot_mem;
+@@ -135,17 +136,7 @@ int vchiq_platform_init(struct platform_
+ if (err < 0)
+ return err;
+
+- /*
+- * The tempting L1_CACHE_BYTES macro doesn't work in the case of
+- * a kernel built with bcm2835_defconfig running on a BCM2836/7
+- * processor, hence the need for a runtime check. The dcache line size
+- * is encoded in one of the coprocessor registers, but there is no
+- * convenient way to access it short of embedded assembler, hence
+- * the use of read_cpuid_id(). The following test evaluates to true
+- * on a BCM2835 showing that it is ARMv6-ish, whereas
+- * cpu_architecture() will indicate that it is an ARMv7.
+- */
+- g_cache_line_size = ((read_cpuid_id() & 0x7f000) == 0x7b000) ? 32 : 64;
++ g_cache_line_size = drvdata->cache_line_size;
+ g_fragments_size = 2 * g_cache_line_size;
+
+ /* Allocate space for the channels in coherent memory */
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -173,6 +173,14 @@ static struct platform_device *bcm2835_c
+ static struct platform_device *bcm2835_codec;
+ static struct platform_device *vcsm_cma;
+
++static struct vchiq_drvdata bcm2835_drvdata = {
++ .cache_line_size = 32,
++};
++
++static struct vchiq_drvdata bcm2836_drvdata = {
++ .cache_line_size = 64,
++};
++
+ static const char *const ioctl_names[] = {
+ "CONNECT",
+ "SHUTDOWN",
+@@ -3607,12 +3615,25 @@ vchiq_register_child(struct platform_dev
+ return new_dev;
+ }
+
++static const struct of_device_id vchiq_of_match[] = {
++ { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata },
++ { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata },
++ {},
++};
++MODULE_DEVICE_TABLE(of, vchiq_of_match);
++
+ static int vchiq_probe(struct platform_device *pdev)
+ {
+ struct device_node *fw_node;
+- struct rpi_firmware *fw;
++ const struct of_device_id *of_id;
++ struct vchiq_drvdata *drvdata;
+ int err;
+
++ of_id = of_match_node(vchiq_of_match, pdev->dev.of_node);
++ drvdata = (struct vchiq_drvdata *)of_id->data;
++ if (!drvdata)
++ return -EINVAL;
++
+ fw_node = of_find_compatible_node(NULL, NULL,
+ "raspberrypi,bcm2835-firmware");
+ if (!fw_node) {
+@@ -3620,12 +3641,12 @@ static int vchiq_probe(struct platform_d
+ return -ENOENT;
+ }
+
+- fw = rpi_firmware_get(fw_node);
++ drvdata->fw = rpi_firmware_get(fw_node);
+ of_node_put(fw_node);
+- if (!fw)
++ if (!drvdata->fw)
+ return -EPROBE_DEFER;
+
+- platform_set_drvdata(pdev, fw);
++ platform_set_drvdata(pdev, drvdata);
+
+ err = vchiq_platform_init(pdev, &g_state);
+ if (err != 0)
+@@ -3703,12 +3724,6 @@ static int vchiq_remove(struct platform_
+ return 0;
+ }
+
+-static const struct of_device_id vchiq_of_match[] = {
+- { .compatible = "brcm,bcm2835-vchiq", },
+- {},
+-};
+-MODULE_DEVICE_TABLE(of, vchiq_of_match);
+-
+ static struct platform_driver vchiq_driver = {
+ .driver = {
+ .name = "bcm2835_vchiq",
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
+@@ -123,6 +123,11 @@ typedef struct vchiq_arm_state_struct {
+
+ } VCHIQ_ARM_STATE_T;
+
++struct vchiq_drvdata {
++ const unsigned int cache_line_size;
++ struct rpi_firmware *fw;
++};
++
+ extern int vchiq_arm_log_level;
+ extern int vchiq_susp_log_level;
+
+++ /dev/null
-From ffbb6cc14b8fb1876b249048284a5fe30f48c693 Mon Sep 17 00:00:00 2001
-Date: Sat, 8 Jun 2019 10:14:43 -0700
-Subject: [PATCH] i2c: bcm2835: Model Divider in CCF
-
-Commit bebff81fb8b9216eb4fba22cf910553621ae3477 upstream.
-
-Model the I2C bus clock divider as a part of the Core Clock Framework.
-Primarily this removes the clk_get_rate() call from each transfer.
-This call causes problems for slave drivers that themselves have
-internal clock components that are controlled by an I2C interface.
-When the slave's internal clock component is prepared, the prepare
-lock is obtained, and it makes calls to the I2C subsystem to
-command the hardware to activate the clock. In order to perform
-the I2C transfer, this driver sets the divider, which requires
-it to get the parent clock rate, which it does with clk_get_rate().
-Unfortunately, this function will try to take the clock prepare
-lock, which is already held by the slave's internal clock calls
-creating a deadlock.
-
-Modeling the divider in the CCF natively removes this dependency
-and the divider value is only set upon changing the bus clock
-frequency or changes in the parent clock that cascade down to this
-divisor. This obviates the need to set the divider with every
-transfer and avoids the deadlock described above. It also should
-provide better clock debugging and save a few cycles on each
-transfer due to not having to recalcuate the divider value.
-
----
- drivers/i2c/busses/i2c-bcm2835.c | 145 ++++++++++++++++++++++++-------
- 1 file changed, 114 insertions(+), 31 deletions(-)
-
---- a/drivers/i2c/busses/i2c-bcm2835.c
-+++ b/drivers/i2c/busses/i2c-bcm2835.c
-@@ -12,6 +12,8 @@
- */
-
- #include <linux/clk.h>
-+#include <linux/clkdev.h>
-+#include <linux/clk-provider.h>
- #include <linux/completion.h>
- #include <linux/err.h>
- #include <linux/i2c.h>
-@@ -71,9 +73,7 @@ struct bcm2835_debug {
- struct bcm2835_i2c_dev {
- struct device *dev;
- void __iomem *regs;
-- struct clk *clk;
- int irq;
-- u32 bus_clk_rate;
- struct i2c_adapter adapter;
- struct completion completion;
- struct i2c_msg *curr_msg;
-@@ -164,12 +164,17 @@ static inline u32 bcm2835_i2c_readl(stru
- return readl(i2c_dev->regs + reg);
- }
-
--static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
-+#define to_clk_bcm2835_i2c(_hw) container_of(_hw, struct clk_bcm2835_i2c, hw)
-+struct clk_bcm2835_i2c {
-+ struct clk_hw hw;
-+ struct bcm2835_i2c_dev *i2c_dev;
-+};
-+
-+static int clk_bcm2835_i2c_calc_divider(unsigned long rate,
-+ unsigned long parent_rate)
- {
-- u32 divider, redl, fedl;
-+ u32 divider = DIV_ROUND_UP(parent_rate, rate);
-
-- divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk),
-- i2c_dev->bus_clk_rate);
- /*
- * Per the datasheet, the register is always interpreted as an even
- * number, by rounding down. In other words, the LSB is ignored. So,
-@@ -178,12 +183,23 @@ static int bcm2835_i2c_set_divider(struc
- if (divider & 1)
- divider++;
- if ((divider < BCM2835_I2C_CDIV_MIN) ||
-- (divider > BCM2835_I2C_CDIV_MAX)) {
-- dev_err_ratelimited(i2c_dev->dev, "Invalid clock-frequency\n");
-+ (divider > BCM2835_I2C_CDIV_MAX))
- return -EINVAL;
-- }
-
-- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
-+ return divider;
-+}
-+
-+static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long parent_rate)
-+{
-+ struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
-+ u32 redl, fedl;
-+ u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate);
-+
-+ if (divider == -EINVAL)
-+ return -EINVAL;
-+
-+ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DIV, divider);
-
- /*
- * Number of core clocks to wait after falling edge before
-@@ -198,12 +214,62 @@ static int bcm2835_i2c_set_divider(struc
- */
- redl = max(divider / 4, 1u);
-
-- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL,
-+ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL,
- (fedl << BCM2835_I2C_FEDL_SHIFT) |
- (redl << BCM2835_I2C_REDL_SHIFT));
- return 0;
- }
-
-+static long clk_bcm2835_i2c_round_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long *parent_rate)
-+{
-+ u32 divider = clk_bcm2835_i2c_calc_divider(rate, *parent_rate);
-+
-+ return DIV_ROUND_UP(*parent_rate, divider);
-+}
-+
-+static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw,
-+ unsigned long parent_rate)
-+{
-+ struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
-+ u32 divider = bcm2835_i2c_readl(div->i2c_dev, BCM2835_I2C_DIV);
-+
-+ return DIV_ROUND_UP(parent_rate, divider);
-+}
-+
-+static const struct clk_ops clk_bcm2835_i2c_ops = {
-+ .set_rate = clk_bcm2835_i2c_set_rate,
-+ .round_rate = clk_bcm2835_i2c_round_rate,
-+ .recalc_rate = clk_bcm2835_i2c_recalc_rate,
-+};
-+
-+static struct clk *bcm2835_i2c_register_div(struct device *dev,
-+ const char *mclk_name,
-+ struct bcm2835_i2c_dev *i2c_dev)
-+{
-+ struct clk_init_data init;
-+ struct clk_bcm2835_i2c *priv;
-+ char name[32];
-+
-+ snprintf(name, sizeof(name), "%s_div", dev_name(dev));
-+
-+ init.ops = &clk_bcm2835_i2c_ops;
-+ init.name = name;
-+ init.parent_names = (const char* []) { mclk_name };
-+ init.num_parents = 1;
-+ init.flags = 0;
-+
-+ priv = devm_kzalloc(dev, sizeof(struct clk_bcm2835_i2c), GFP_KERNEL);
-+ if (priv == NULL)
-+ return ERR_PTR(-ENOMEM);
-+
-+ priv->hw.init = &init;
-+ priv->i2c_dev = i2c_dev;
-+
-+ clk_hw_register_clkdev(&priv->hw, "div", dev_name(dev));
-+ return devm_clk_register(dev, &priv->hw);
-+}
-+
- static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev)
- {
- u32 val;
-@@ -363,7 +429,7 @@ static int bcm2835_i2c_xfer(struct i2c_a
- {
- struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
- unsigned long time_left;
-- int i, ret;
-+ int i;
-
- if (debug)
- i2c_dev->debug_num_msgs = num;
-@@ -379,10 +445,6 @@ static int bcm2835_i2c_xfer(struct i2c_a
- return -EOPNOTSUPP;
- }
-
-- ret = bcm2835_i2c_set_divider(i2c_dev);
-- if (ret)
-- return ret;
--
- i2c_dev->curr_msg = msgs;
- i2c_dev->num_msgs = num;
- reinit_completion(&i2c_dev->completion);
-@@ -443,6 +505,9 @@ static int bcm2835_i2c_probe(struct plat
- struct resource *mem, *irq;
- int ret;
- struct i2c_adapter *adap;
-+ const char *mclk_name;
-+ struct clk *bus_clk;
-+ u32 bus_clk_rate;
-
- i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
- if (!i2c_dev)
-@@ -456,21 +521,6 @@ static int bcm2835_i2c_probe(struct plat
- if (IS_ERR(i2c_dev->regs))
- return PTR_ERR(i2c_dev->regs);
-
-- i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
-- if (IS_ERR(i2c_dev->clk)) {
-- if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
-- dev_err(&pdev->dev, "Could not get clock\n");
-- return PTR_ERR(i2c_dev->clk);
-- }
--
-- ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
-- &i2c_dev->bus_clk_rate);
-- if (ret < 0) {
-- dev_warn(&pdev->dev,
-- "Could not read clock-frequency property\n");
-- i2c_dev->bus_clk_rate = 100000;
-- }
--
- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq) {
- dev_err(&pdev->dev, "No IRQ resource\n");
-@@ -485,6 +535,35 @@ static int bcm2835_i2c_probe(struct plat
- return -ENODEV;
- }
-
-+ mclk_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
-+
-+ bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk_name, i2c_dev);
-+
-+ if (IS_ERR(bus_clk)) {
-+ dev_err(&pdev->dev, "Could not register clock\n");
-+ return PTR_ERR(bus_clk);
-+ }
-+
-+ ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
-+ &bus_clk_rate);
-+ if (ret < 0) {
-+ dev_warn(&pdev->dev,
-+ "Could not read clock-frequency property\n");
-+ bus_clk_rate = 100000;
-+ }
-+
-+ ret = clk_set_rate_exclusive(bus_clk, bus_clk_rate);
-+ if (ret < 0) {
-+ dev_err(&pdev->dev, "Could not set clock frequency\n");
-+ return ret;
-+ }
-+
-+ ret = clk_prepare_enable(bus_clk);
-+ if (ret) {
-+ dev_err(&pdev->dev, "Couldn't prepare clock");
-+ return ret;
-+ }
-+
- adap = &i2c_dev->adapter;
- i2c_set_adapdata(adap, i2c_dev);
- adap->owner = THIS_MODULE;
-@@ -507,6 +586,10 @@ static int bcm2835_i2c_probe(struct plat
- static int bcm2835_i2c_remove(struct platform_device *pdev)
- {
- struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
-+ struct clk *bus_clk = devm_clk_get(i2c_dev->dev, "div");
-+
-+ clk_rate_exclusive_put(bus_clk);
-+ clk_disable_unprepare(bus_clk);
-
- free_irq(i2c_dev->irq, i2c_dev);
- i2c_del_adapter(&i2c_dev->adapter);
--- /dev/null
+From ea75a716955e85ad076dd2861ca9e41def406a1b Mon Sep 17 00:00:00 2001
+Date: Mon, 13 May 2019 20:59:45 +0200
+Subject: [PATCH] tty: amba-pl011: allow shared interrupt
+
+The PL011 register space includes all necessary status bits to
+determine whether a device instance requires handling in response
+to an interrupt. Therefore, multiple instances of the device could
+be serviced by a single shared interrupt, which is the case on BCM7211.
+
+---
+ drivers/tty/serial/amba-pl011.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -1733,7 +1733,8 @@ static int pl011_allocate_irq(struct uar
+ {
+ pl011_write(uap->im, uap, REG_IMSC);
+
+- return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
++ return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011",
++ uap);
+ }
+
+ /*
--- /dev/null
+From 3f6fe9da303fc01fb754a0a639ec3cdb813e8780 Mon Sep 17 00:00:00 2001
+Date: Sun, 19 May 2019 12:20:00 +0200
+Subject: [PATCH] ARM: bcm283x: Reduce register ranges for UART, SPI
+ and I2C
+
+The assigned register ranges for UART, SPI and I2C were too wasteful.
+In order to avoid overlapping with the new functions on BCM2838
+reduce the ranges.
+
+---
+ arch/arm/boot/dts/bcm283x.dtsi | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -387,7 +387,7 @@
+
+ uart0: serial@7e201000 {
+ compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
+- reg = <0x7e201000 0x1000>;
++ reg = <0x7e201000 0x200>;
+ interrupts = <2 25>;
+ clocks = <&clocks BCM2835_CLOCK_UART>,
+ <&clocks BCM2835_CLOCK_VPU>;
+@@ -418,7 +418,7 @@
+
+ spi: spi@7e204000 {
+ compatible = "brcm,bcm2835-spi";
+- reg = <0x7e204000 0x1000>;
++ reg = <0x7e204000 0x200>;
+ interrupts = <2 22>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+ #address-cells = <1>;
+@@ -428,7 +428,7 @@
+
+ i2c0: i2c@7e205000 {
+ compatible = "brcm,bcm2835-i2c";
+- reg = <0x7e205000 0x1000>;
++ reg = <0x7e205000 0x200>;
+ interrupts = <2 21>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+ #address-cells = <1>;
+++ /dev/null
-From 63079fbe20c954140f8eb61f858b0774890f301c Mon Sep 17 00:00:00 2001
-Date: Mon, 17 Sep 2018 09:22:21 +0100
-Subject: [PATCH] staging/vc04_services: Use correct cache line size
-
-Use the compatible string in the DTB to select the correct cache line
-size for the SoC - 32 for BCM2835, and 64 for BCM2836 and BCM2837.
-
----
- .../interface/vchiq_arm/vchiq_2835_arm.c | 15 ++------
- .../interface/vchiq_arm/vchiq_arm.c | 35 +++++++++++++------
- .../interface/vchiq_arm/vchiq_arm.h | 5 +++
- 3 files changed, 33 insertions(+), 22 deletions(-)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
-@@ -117,7 +117,8 @@ free_pagelist(struct vchiq_pagelist_info
- int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
- {
- struct device *dev = &pdev->dev;
-- struct rpi_firmware *fw = platform_get_drvdata(pdev);
-+ struct vchiq_drvdata *drvdata = platform_get_drvdata(pdev);
-+ struct rpi_firmware *fw = drvdata->fw;
- VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
- struct resource *res;
- void *slot_mem;
-@@ -135,17 +136,7 @@ int vchiq_platform_init(struct platform_
- if (err < 0)
- return err;
-
-- /*
-- * The tempting L1_CACHE_BYTES macro doesn't work in the case of
-- * a kernel built with bcm2835_defconfig running on a BCM2836/7
-- * processor, hence the need for a runtime check. The dcache line size
-- * is encoded in one of the coprocessor registers, but there is no
-- * convenient way to access it short of embedded assembler, hence
-- * the use of read_cpuid_id(). The following test evaluates to true
-- * on a BCM2835 showing that it is ARMv6-ish, whereas
-- * cpu_architecture() will indicate that it is an ARMv7.
-- */
-- g_cache_line_size = ((read_cpuid_id() & 0x7f000) == 0x7b000) ? 32 : 64;
-+ g_cache_line_size = drvdata->cache_line_size;
- g_fragments_size = 2 * g_cache_line_size;
-
- /* Allocate space for the channels in coherent memory */
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -173,6 +173,14 @@ static struct platform_device *bcm2835_c
- static struct platform_device *bcm2835_codec;
- static struct platform_device *vcsm_cma;
-
-+static struct vchiq_drvdata bcm2835_drvdata = {
-+ .cache_line_size = 32,
-+};
-+
-+static struct vchiq_drvdata bcm2836_drvdata = {
-+ .cache_line_size = 64,
-+};
-+
- static const char *const ioctl_names[] = {
- "CONNECT",
- "SHUTDOWN",
-@@ -3607,12 +3615,25 @@ vchiq_register_child(struct platform_dev
- return new_dev;
- }
-
-+static const struct of_device_id vchiq_of_match[] = {
-+ { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata },
-+ { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, vchiq_of_match);
-+
- static int vchiq_probe(struct platform_device *pdev)
- {
- struct device_node *fw_node;
-- struct rpi_firmware *fw;
-+ const struct of_device_id *of_id;
-+ struct vchiq_drvdata *drvdata;
- int err;
-
-+ of_id = of_match_node(vchiq_of_match, pdev->dev.of_node);
-+ drvdata = (struct vchiq_drvdata *)of_id->data;
-+ if (!drvdata)
-+ return -EINVAL;
-+
- fw_node = of_find_compatible_node(NULL, NULL,
- "raspberrypi,bcm2835-firmware");
- if (!fw_node) {
-@@ -3620,12 +3641,12 @@ static int vchiq_probe(struct platform_d
- return -ENOENT;
- }
-
-- fw = rpi_firmware_get(fw_node);
-+ drvdata->fw = rpi_firmware_get(fw_node);
- of_node_put(fw_node);
-- if (!fw)
-+ if (!drvdata->fw)
- return -EPROBE_DEFER;
-
-- platform_set_drvdata(pdev, fw);
-+ platform_set_drvdata(pdev, drvdata);
-
- err = vchiq_platform_init(pdev, &g_state);
- if (err != 0)
-@@ -3703,12 +3724,6 @@ static int vchiq_remove(struct platform_
- return 0;
- }
-
--static const struct of_device_id vchiq_of_match[] = {
-- { .compatible = "brcm,bcm2835-vchiq", },
-- {},
--};
--MODULE_DEVICE_TABLE(of, vchiq_of_match);
--
- static struct platform_driver vchiq_driver = {
- .driver = {
- .name = "bcm2835_vchiq",
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
-@@ -123,6 +123,11 @@ typedef struct vchiq_arm_state_struct {
-
- } VCHIQ_ARM_STATE_T;
-
-+struct vchiq_drvdata {
-+ const unsigned int cache_line_size;
-+ struct rpi_firmware *fw;
-+};
-+
- extern int vchiq_arm_log_level;
- extern int vchiq_susp_log_level;
-
--- /dev/null
+From 9f889edf282d1d9a21c921e6cd33cebe22bcc4d4 Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Dec 2018 15:51:49 -0800
+Subject: [PATCH] ARM: bcm283x: Extend the WDT DT node out to cover the
+ whole PM block. (v4)
+
+It was covering part of the PM block's range, up to the WDT regs. To
+support the rest of the PM block's functionality, we need the full
+register range plus the AXI Async Bridge regs for PM sequencing.
+
+This doesn't convert any of the consumers over to the new binding yet,
+since we will need to be careful in coordinating our usage of firmware
+services that might power domains on and off versus the bcm2835-pm
+driver's access of those same domains.
+
+(cherry picked from commit 29abc92c1d93e28a8f4d55e6343eec4faf44025a)
+---
+ arch/arm/boot/dts/bcm283x.dtsi | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -121,8 +121,17 @@
+ };
+
+ watchdog@7e100000 {
+- compatible = "brcm,bcm2835-pm-wdt";
+- reg = <0x7e100000 0x28>;
++ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
++ #power-domain-cells = <1>;
++ #reset-cells = <1>;
++ reg = <0x7e100000 0x114>,
++ <0x7e00a000 0x24>;
++ clocks = <&clocks BCM2835_CLOCK_V3D>,
++ <&clocks BCM2835_CLOCK_PERI_IMAGE>,
++ <&clocks BCM2835_CLOCK_H264>,
++ <&clocks BCM2835_CLOCK_ISP>;
++ clock-names = "v3d", "peri_image", "h264", "isp";
++ system-power-controller;
+ };
+
+ clocks: cprman@7e101000 {
+++ /dev/null
-From ea75a716955e85ad076dd2861ca9e41def406a1b Mon Sep 17 00:00:00 2001
-Date: Mon, 13 May 2019 20:59:45 +0200
-Subject: [PATCH] tty: amba-pl011: allow shared interrupt
-
-The PL011 register space includes all necessary status bits to
-determine whether a device instance requires handling in response
-to an interrupt. Therefore, multiple instances of the device could
-be serviced by a single shared interrupt, which is the case on BCM7211.
-
----
- drivers/tty/serial/amba-pl011.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/tty/serial/amba-pl011.c
-+++ b/drivers/tty/serial/amba-pl011.c
-@@ -1733,7 +1733,8 @@ static int pl011_allocate_irq(struct uar
- {
- pl011_write(uap->im, uap, REG_IMSC);
-
-- return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
-+ return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011",
-+ uap);
- }
-
- /*
+++ /dev/null
-From 3f6fe9da303fc01fb754a0a639ec3cdb813e8780 Mon Sep 17 00:00:00 2001
-Date: Sun, 19 May 2019 12:20:00 +0200
-Subject: [PATCH] ARM: bcm283x: Reduce register ranges for UART, SPI
- and I2C
-
-The assigned register ranges for UART, SPI and I2C were too wasteful.
-In order to avoid overlapping with the new functions on BCM2838
-reduce the ranges.
-
----
- arch/arm/boot/dts/bcm283x.dtsi | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -387,7 +387,7 @@
-
- uart0: serial@7e201000 {
- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
-- reg = <0x7e201000 0x1000>;
-+ reg = <0x7e201000 0x200>;
- interrupts = <2 25>;
- clocks = <&clocks BCM2835_CLOCK_UART>,
- <&clocks BCM2835_CLOCK_VPU>;
-@@ -418,7 +418,7 @@
-
- spi: spi@7e204000 {
- compatible = "brcm,bcm2835-spi";
-- reg = <0x7e204000 0x1000>;
-+ reg = <0x7e204000 0x200>;
- interrupts = <2 22>;
- clocks = <&clocks BCM2835_CLOCK_VPU>;
- #address-cells = <1>;
-@@ -428,7 +428,7 @@
-
- i2c0: i2c@7e205000 {
- compatible = "brcm,bcm2835-i2c";
-- reg = <0x7e205000 0x1000>;
-+ reg = <0x7e205000 0x200>;
- interrupts = <2 21>;
- clocks = <&clocks BCM2835_CLOCK_VPU>;
- #address-cells = <1>;
--- /dev/null
+From 1297aac31942e596e6888d772ba49393a9f59417 Mon Sep 17 00:00:00 2001
+Date: Sat, 4 May 2019 17:06:54 +0200
+Subject: [PATCH] ARM: dts: Add label to bcm2835 RNG
+
+---
+ arch/arm/boot/dts/bcm283x.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -148,7 +148,7 @@
+ <&dsi1 0>, <&dsi1 1>, <&dsi1 2>;
+ };
+
+- rng@7e104000 {
++ rng: rng@7e104000 {
+ compatible = "brcm,bcm2835-rng";
+ reg = <0x7e104000 0x10>;
+ interrupts = <2 29>;
+++ /dev/null
-From 9f889edf282d1d9a21c921e6cd33cebe22bcc4d4 Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Dec 2018 15:51:49 -0800
-Subject: [PATCH] ARM: bcm283x: Extend the WDT DT node out to cover the
- whole PM block. (v4)
-
-It was covering part of the PM block's range, up to the WDT regs. To
-support the rest of the PM block's functionality, we need the full
-register range plus the AXI Async Bridge regs for PM sequencing.
-
-This doesn't convert any of the consumers over to the new binding yet,
-since we will need to be careful in coordinating our usage of firmware
-services that might power domains on and off versus the bcm2835-pm
-driver's access of those same domains.
-
-(cherry picked from commit 29abc92c1d93e28a8f4d55e6343eec4faf44025a)
----
- arch/arm/boot/dts/bcm283x.dtsi | 13 +++++++++++--
- 1 file changed, 11 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -121,8 +121,17 @@
- };
-
- watchdog@7e100000 {
-- compatible = "brcm,bcm2835-pm-wdt";
-- reg = <0x7e100000 0x28>;
-+ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
-+ #power-domain-cells = <1>;
-+ #reset-cells = <1>;
-+ reg = <0x7e100000 0x114>,
-+ <0x7e00a000 0x24>;
-+ clocks = <&clocks BCM2835_CLOCK_V3D>,
-+ <&clocks BCM2835_CLOCK_PERI_IMAGE>,
-+ <&clocks BCM2835_CLOCK_H264>,
-+ <&clocks BCM2835_CLOCK_ISP>;
-+ clock-names = "v3d", "peri_image", "h264", "isp";
-+ system-power-controller;
- };
-
- clocks: cprman@7e101000 {
--- /dev/null
+From 4a09c51bc328b2b83ffa20a6db02ac18139a963d Mon Sep 17 00:00:00 2001
+Date: Thu, 12 Oct 2017 18:11:32 +0100
+Subject: [PATCH] dts: Use fb rather than leds for dpi overlay
+
+---
+ arch/arm/boot/dts/overlays/dpi18-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/dpi24-overlay.dts | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/dpi18-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dpi18-overlay.dts
+@@ -9,7 +9,7 @@
+ // reference on - leds will do
+
+ fragment@0 {
+- target = <&leds>;
++ target = <&fb>;
+ __overlay__ {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dpi18_pins>;
+--- a/arch/arm/boot/dts/overlays/dpi24-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dpi24-overlay.dts
+@@ -9,7 +9,7 @@
+ // reference on - leds will do
+
+ fragment@0 {
+- target = <&leds>;
++ target = <&fb>;
+ __overlay__ {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dpi24_pins>;
+++ /dev/null
-From 1297aac31942e596e6888d772ba49393a9f59417 Mon Sep 17 00:00:00 2001
-Date: Sat, 4 May 2019 17:06:54 +0200
-Subject: [PATCH] ARM: dts: Add label to bcm2835 RNG
-
----
- arch/arm/boot/dts/bcm283x.dtsi | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -148,7 +148,7 @@
- <&dsi1 0>, <&dsi1 1>, <&dsi1 2>;
- };
-
-- rng@7e104000 {
-+ rng: rng@7e104000 {
- compatible = "brcm,bcm2835-rng";
- reg = <0x7e104000 0x10>;
- interrupts = <2 29>;
--- /dev/null
+From 021d54e3ae67e2b02310b9e3e871876a2c3b7eee Mon Sep 17 00:00:00 2001
+Date: Wed, 29 May 2019 15:19:21 +0100
+Subject: [PATCH] BCM270X_DT: Minor tidy up
+
+Move arm_pmu out of soc on bcm2710, and labels aren't aliases.
+
+---
+ arch/arm/boot/dts/bcm270x.dtsi | 14 +++++++-------
+ arch/arm/boot/dts/bcm2710.dtsi | 13 +++++--------
+ 2 files changed, 12 insertions(+), 15 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm270x.dtsi
++++ b/arch/arm/boot/dts/bcm270x.dtsi
+@@ -10,11 +10,11 @@
+ soc: soc {
+
+ watchdog: watchdog@7e100000 {
+- /* Add alias */
++ /* Add label */
+ };
+
+ random: rng@7e104000 {
+- /* Add alias */
++ /* Add label */
+ };
+
+ gpio@7e200000 { /* gpio */
+@@ -40,18 +40,18 @@
+ };
+
+ spi0: spi@7e204000 {
+- /* Add alias */
++ /* Add label */
+ dmas = <&dma 6>, <&dma 7>;
+ dma-names = "tx", "rx";
+ };
+
+ pixelvalve0: pixelvalve@7e206000 {
+- /* Add alias */
++ /* Add label */
+ status = "disabled";
+ };
+
+ pixelvalve1: pixelvalve@7e207000 {
+- /* Add alias */
++ /* Add label */
+ status = "disabled";
+ };
+
+@@ -93,7 +93,7 @@
+ };
+
+ hvs: hvs@7e400000 {
+- /* Add alias */
++ /* Add label */
+ status = "disabled";
+ };
+
+@@ -119,7 +119,7 @@
+ };
+
+ pixelvalve2: pixelvalve@7e807000 {
+- /* Add alias */
++ /* Add label */
+ status = "disabled";
+ };
+
+--- a/arch/arm/boot/dts/bcm2710.dtsi
++++ b/arch/arm/boot/dts/bcm2710.dtsi
+@@ -5,18 +5,15 @@
+ / {
+ compatible = "brcm,bcm2837", "brcm,bcm2836";
+
+- soc {
+-
+- arm-pmu {
++ arm-pmu {
+ #ifdef RPI364
+- compatible = "arm,armv8-pmuv3", "arm,cortex-a7-pmu";
++ compatible = "arm,armv8-pmuv3", "arm,cortex-a7-pmu";
+ #else
+- compatible = "arm,cortex-a7-pmu";
++ compatible = "arm,cortex-a7-pmu";
+ #endif
+- interrupt-parent = <&local_intc>;
+- interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
+- };
++ };
+
++ soc {
+ /delete-node/ timer@7e003000;
+ };
+
--- /dev/null
+From 51d6e1924fd0e9d075bcef61bea5a475a0ad6634 Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Feb 2019 08:49:39 +0000
+Subject: [PATCH] arm: bcm2835: Fix FIQ early ioremap
+
+The ioremapping creates mappings within the vmalloc area. The
+equivalent early function, create_mapping, now checks that the
+requested explicit virtual address is between VMALLOC_START and
+VMALLOC_END. As there is no reason to have any correlation between
+the physical and virtual addresses, put the required mappings at
+VMALLOC_START and above.
+
+---
+ arch/arm/mach-bcm/board_bcm2835.c | 21 +++++++++++++++------
+ 1 file changed, 15 insertions(+), 6 deletions(-)
+
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -14,17 +14,20 @@
+
+ #include <linux/init.h>
+ #include <linux/irqchip.h>
++#include <linux/mm.h>
+ #include <linux/of_address.h>
+ #include <linux/of_fdt.h>
+ #include <asm/system_info.h>
+
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
++#include <asm/memory.h>
++#include <asm/pgtable.h>
+
+ #include "platsmp.h"
+
+-#define BCM2835_USB_VIRT_BASE 0xf0980000
+-#define BCM2835_USB_VIRT_MPHI 0xf0006000
++#define BCM2835_USB_VIRT_BASE (VMALLOC_START)
++#define BCM2835_USB_VIRT_MPHI (VMALLOC_START + 0x10000)
+
+ static void __init bcm2835_init(void)
+ {
+@@ -83,20 +86,26 @@ static int __init bcm2835_map_usb(unsign
+
+ static void __init bcm2835_map_io(void)
+ {
+- const __be32 *ranges;
++ const __be32 *ranges, *address_cells;
++ unsigned long root, addr_cells;
+ int soc, len;
+ unsigned long p2b_offset;
+
+ debug_ll_io_init();
+
++ root = of_get_flat_dt_root();
+ /* Find out how to map bus to physical address first from soc/ranges */
+- soc = of_get_flat_dt_subnode_by_name(of_get_flat_dt_root(), "soc");
++ soc = of_get_flat_dt_subnode_by_name(root, "soc");
+ if (soc < 0)
+ return;
++ address_cells = of_get_flat_dt_prop(root, "#address-cells", &len);
++ if (!address_cells || len < (sizeof(unsigned long)))
++ return;
++ addr_cells = be32_to_cpu(address_cells[0]);
+ ranges = of_get_flat_dt_prop(soc, "ranges", &len);
+- if (!ranges || len < (sizeof(unsigned long) * 3))
++ if (!ranges || len < (sizeof(unsigned long) * (2 + addr_cells)))
+ return;
+- p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[1]);
++ p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[addr_cells]);
+
+ /* Now search for bcm2708-usb node in device tree */
+ of_scan_flat_dt(bcm2835_map_usb, &p2b_offset);
+++ /dev/null
-From 4a09c51bc328b2b83ffa20a6db02ac18139a963d Mon Sep 17 00:00:00 2001
-Date: Thu, 12 Oct 2017 18:11:32 +0100
-Subject: [PATCH] dts: Use fb rather than leds for dpi overlay
-
----
- arch/arm/boot/dts/overlays/dpi18-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/dpi24-overlay.dts | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/dpi18-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dpi18-overlay.dts
-@@ -9,7 +9,7 @@
- // reference on - leds will do
-
- fragment@0 {
-- target = <&leds>;
-+ target = <&fb>;
- __overlay__ {
- pinctrl-names = "default";
- pinctrl-0 = <&dpi18_pins>;
---- a/arch/arm/boot/dts/overlays/dpi24-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dpi24-overlay.dts
-@@ -9,7 +9,7 @@
- // reference on - leds will do
-
- fragment@0 {
-- target = <&leds>;
-+ target = <&fb>;
- __overlay__ {
- pinctrl-names = "default";
- pinctrl-0 = <&dpi24_pins>;
+++ /dev/null
-From 021d54e3ae67e2b02310b9e3e871876a2c3b7eee Mon Sep 17 00:00:00 2001
-Date: Wed, 29 May 2019 15:19:21 +0100
-Subject: [PATCH] BCM270X_DT: Minor tidy up
-
-Move arm_pmu out of soc on bcm2710, and labels aren't aliases.
-
----
- arch/arm/boot/dts/bcm270x.dtsi | 14 +++++++-------
- arch/arm/boot/dts/bcm2710.dtsi | 13 +++++--------
- 2 files changed, 12 insertions(+), 15 deletions(-)
-
---- a/arch/arm/boot/dts/bcm270x.dtsi
-+++ b/arch/arm/boot/dts/bcm270x.dtsi
-@@ -10,11 +10,11 @@
- soc: soc {
-
- watchdog: watchdog@7e100000 {
-- /* Add alias */
-+ /* Add label */
- };
-
- random: rng@7e104000 {
-- /* Add alias */
-+ /* Add label */
- };
-
- gpio@7e200000 { /* gpio */
-@@ -40,18 +40,18 @@
- };
-
- spi0: spi@7e204000 {
-- /* Add alias */
-+ /* Add label */
- dmas = <&dma 6>, <&dma 7>;
- dma-names = "tx", "rx";
- };
-
- pixelvalve0: pixelvalve@7e206000 {
-- /* Add alias */
-+ /* Add label */
- status = "disabled";
- };
-
- pixelvalve1: pixelvalve@7e207000 {
-- /* Add alias */
-+ /* Add label */
- status = "disabled";
- };
-
-@@ -93,7 +93,7 @@
- };
-
- hvs: hvs@7e400000 {
-- /* Add alias */
-+ /* Add label */
- status = "disabled";
- };
-
-@@ -119,7 +119,7 @@
- };
-
- pixelvalve2: pixelvalve@7e807000 {
-- /* Add alias */
-+ /* Add label */
- status = "disabled";
- };
-
---- a/arch/arm/boot/dts/bcm2710.dtsi
-+++ b/arch/arm/boot/dts/bcm2710.dtsi
-@@ -5,18 +5,15 @@
- / {
- compatible = "brcm,bcm2837", "brcm,bcm2836";
-
-- soc {
--
-- arm-pmu {
-+ arm-pmu {
- #ifdef RPI364
-- compatible = "arm,armv8-pmuv3", "arm,cortex-a7-pmu";
-+ compatible = "arm,armv8-pmuv3", "arm,cortex-a7-pmu";
- #else
-- compatible = "arm,cortex-a7-pmu";
-+ compatible = "arm,cortex-a7-pmu";
- #endif
-- interrupt-parent = <&local_intc>;
-- interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
-- };
-+ };
-
-+ soc {
- /delete-node/ timer@7e003000;
- };
-
--- /dev/null
+From ab2695d38f4ffadde05c2275ac68f4aad68ef336 Mon Sep 17 00:00:00 2001
+Date: Thu, 14 Mar 2019 10:16:02 +0000
+Subject: [PATCH] Fix copy_from_user if BCM2835_FAST_MEMCPY=n
+
+The change which introduced CONFIG_BCM2835_FAST_MEMCPY unconditionally
+changed the behaviour of arm_copy_from_user. The page pinning code
+is not safe on ARMv7 if LPAE & high memory is enabled and causes
+crashes which look like PTE corruption.
+
+Make __copy_from_user_memcpy conditional on CONFIG_2835_FAST_MEMCPY=y
+which is really an ARMv6 / Pi1 optimization and not necessary on newer
+ARM processors.
+---
+ arch/arm/lib/uaccess_with_memcpy.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/arch/arm/lib/uaccess_with_memcpy.c
++++ b/arch/arm/lib/uaccess_with_memcpy.c
+@@ -257,6 +257,7 @@ arm_copy_to_user(void __user *to, const
+ unsigned long __must_check
+ arm_copy_from_user(void *to, const void __user *from, unsigned long n)
+ {
++#ifdef CONFIG_BCM2835_FAST_MEMCPY
+ /*
+ * This test is stubbed out of the main function above to keep
+ * the overhead for small copies low by avoiding a large
+@@ -271,6 +272,11 @@ arm_copy_from_user(void *to, const void
+ } else {
+ n = __copy_from_user_memcpy(to, from, n);
+ }
++#else
++ unsigned long ua_flags = uaccess_save_and_enable();
++ n = __copy_from_user_std(to, from, n);
++ uaccess_restore(ua_flags);
++#endif
+ return n;
+ }
+
--- /dev/null
+From ac1212c0f8b611be6df28f252ebbad80b775ee0f Mon Sep 17 00:00:00 2001
+Date: Tue, 19 Feb 2019 22:06:59 +0000
+Subject: [PATCH] PCI: brcmstb: Add Broadcom STB PCIe host controller
+ driver
+
+This commit adds the basic Broadcom STB PCIe controller. Missing is
+the ability to process MSI and also handle dma-ranges for inbound
+memory accesses. These two functionalities are added in subsequent
+commits.
+
+The PCIe block contains an MDIO interface. This is a local interface
+only accessible by the PCIe controller. It cannot be used or shared
+by any other HW. As such, the small amount of code for this
+controller is included in this driver as there is little upside to put
+it elsewhere.
+
+---
+ drivers/pci/controller/Kconfig | 9 +
+ drivers/pci/controller/Makefile | 2 +-
+ drivers/pci/controller/pcie-brcmstb.c | 1097 +++++++++++++++++++++++++
+ include/soc/brcmstb/memory_api.h | 25 +
+ 4 files changed, 1132 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/pci/controller/pcie-brcmstb.c
+ create mode 100644 include/soc/brcmstb/memory_api.h
+
+--- a/drivers/pci/controller/Kconfig
++++ b/drivers/pci/controller/Kconfig
+@@ -278,5 +278,14 @@ config VMD
+ To compile this driver as a module, choose M here: the
+ module will be called vmd.
+
++config PCIE_BRCMSTB
++ tristate "Broadcom Brcmstb PCIe platform host driver"
++ depends on ARCH_BRCMSTB || BMIPS_GENERIC
++ depends on OF
++ depends on SOC_BRCMSTB
++ default ARCH_BRCMSTB || BMIPS_GENERIC
++ help
++ Adds support for Broadcom Settop Box PCIe host controller.
++
+ source "drivers/pci/controller/dwc/Kconfig"
+ endmenu
+--- a/drivers/pci/controller/Makefile
++++ b/drivers/pci/controller/Makefile
+@@ -28,11 +28,11 @@ obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie
+ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
+ obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
+ obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
++obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
+ obj-$(CONFIG_VMD) += vmd.o
+ # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
+ obj-y += dwc/
+
+-
+ # The following drivers are for devices that use the generic ACPI
+ # pci_root.c driver but don't support standard ECAM config access.
+ # They contain MCFG quirks to replace the generic ECAM accessors with
+--- /dev/null
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -0,0 +1,1097 @@
++// SPDX-License-Identifier: GPL-2.0
++/* Copyright (C) 2009 - 2017 Broadcom */
++
++#include <linux/clk.h>
++#include <linux/compiler.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/irqdomain.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/log2.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/of_pci.h>
++#include <linux/of_platform.h>
++#include <linux/pci.h>
++#include <linux/printk.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <soc/brcmstb/memory_api.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include "../pci.h"
++
++/* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */
++#define BRCM_PCIE_CAP_REGS 0x00ac
++
++/*
++ * Broadcom Settop Box PCIe Register Offsets. The names are from
++ * the chip's RDB and we use them here so that a script can correlate
++ * this code and the RDB to prevent discrepancies.
++ */
++#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 0x0188
++#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c
++#define PCIE_RC_DL_MDIO_ADDR 0x1100
++#define PCIE_RC_DL_MDIO_WR_DATA 0x1104
++#define PCIE_RC_DL_MDIO_RD_DATA 0x1108
++#define PCIE_MISC_MISC_CTRL 0x4008
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010
++#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c
++#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034
++#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038
++#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
++#define PCIE_MISC_PCIE_CTRL 0x4064
++#define PCIE_MISC_PCIE_STATUS 0x4068
++#define PCIE_MISC_REVISION 0x406c
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084
++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204
++#define PCIE_INTR2_CPU_BASE 0x4300
++
++/*
++ * Broadcom Settop Box PCIe Register Field shift and mask info. The
++ * names are from the chip's RDB and we use them here so that a script
++ * can correlate this code and the RDB to prevent discrepancies.
++ */
++#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc
++#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_SHIFT 0x2
++#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff
++#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_SHIFT 0x0
++#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000
++#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_SHIFT 0xc
++#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000
++#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_SHIFT 0xd
++#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000
++#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_SHIFT 0x14
++#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK 0xf8000000
++#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_SHIFT 0x1b
++#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_MASK 0x7c00000
++#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_SHIFT 0x16
++#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_MASK 0x1f
++#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_SHIFT 0x0
++#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f
++#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_SHIFT 0x0
++#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f
++#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_SHIFT 0x0
++#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f
++#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_SHIFT 0x0
++#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK 0x4
++#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_SHIFT 0x2
++#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1
++#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_SHIFT 0x0
++#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80
++#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_SHIFT 0x7
++#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20
++#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_SHIFT 0x5
++#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10
++#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_SHIFT 0x4
++#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40
++#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_SHIFT 0x6
++#define PCIE_MISC_REVISION_MAJMIN_MASK 0xffff
++#define PCIE_MISC_REVISION_MAJMIN_SHIFT 0
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_SHIFT 0x14
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_SHIFT 0x4
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_NUM_MASK_BITS 0xc
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK 0xff
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_SHIFT 0x0
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_SHIFT 0x0
++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2
++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_SHIFT 0x1
++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_SHIFT 0x1b
++#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1
++#define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0
++
++#define BRCM_NUM_PCIE_OUT_WINS 0x4
++#define BRCM_MAX_SCB 0x4
++
++#define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL
++#define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL
++
++#define BURST_SIZE_128 0
++#define BURST_SIZE_256 1
++#define BURST_SIZE_512 2
++
++/* Offsets from PCIE_INTR2_CPU_BASE */
++#define STATUS 0x0
++#define SET 0x4
++#define CLR 0x8
++#define MASK_STATUS 0xc
++#define MASK_SET 0x10
++#define MASK_CLR 0x14
++
++#define PCIE_BUSNUM_SHIFT 20
++#define PCIE_SLOT_SHIFT 15
++#define PCIE_FUNC_SHIFT 12
++
++#if defined(__BIG_ENDIAN)
++#define DATA_ENDIAN 2 /* PCIe->DDR inbound traffic */
++#define MMIO_ENDIAN 2 /* CPU->PCIe outbound traffic */
++#else
++#define DATA_ENDIAN 0
++#define MMIO_ENDIAN 0
++#endif
++
++#define MDIO_PORT0 0x0
++#define MDIO_DATA_MASK 0x7fffffff
++#define MDIO_DATA_SHIFT 0x0
++#define MDIO_PORT_MASK 0xf0000
++#define MDIO_PORT_SHIFT 0x16
++#define MDIO_REGAD_MASK 0xffff
++#define MDIO_REGAD_SHIFT 0x0
++#define MDIO_CMD_MASK 0xfff00000
++#define MDIO_CMD_SHIFT 0x14
++#define MDIO_CMD_READ 0x1
++#define MDIO_CMD_WRITE 0x0
++#define MDIO_DATA_DONE_MASK 0x80000000
++#define MDIO_RD_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 1 : 0)
++#define MDIO_WT_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 0 : 1)
++#define SSC_REGS_ADDR 0x1100
++#define SET_ADDR_OFFSET 0x1f
++#define SSC_CNTL_OFFSET 0x2
++#define SSC_CNTL_OVRD_EN_MASK 0x8000
++#define SSC_CNTL_OVRD_EN_SHIFT 0xf
++#define SSC_CNTL_OVRD_VAL_MASK 0x4000
++#define SSC_CNTL_OVRD_VAL_SHIFT 0xe
++#define SSC_STATUS_OFFSET 0x1
++#define SSC_STATUS_SSC_MASK 0x400
++#define SSC_STATUS_SSC_SHIFT 0xa
++#define SSC_STATUS_PLL_LOCK_MASK 0x800
++#define SSC_STATUS_PLL_LOCK_SHIFT 0xb
++
++#define IDX_ADDR(pcie) \
++ ((pcie)->reg_offsets[EXT_CFG_INDEX])
++#define DATA_ADDR(pcie) \
++ ((pcie)->reg_offsets[EXT_CFG_DATA])
++#define PCIE_RGR1_SW_INIT_1(pcie) \
++ ((pcie)->reg_offsets[RGR1_SW_INIT_1])
++
++enum {
++ RGR1_SW_INIT_1,
++ EXT_CFG_INDEX,
++ EXT_CFG_DATA,
++};
++
++enum {
++ RGR1_SW_INIT_1_INIT_MASK,
++ RGR1_SW_INIT_1_INIT_SHIFT,
++ RGR1_SW_INIT_1_PERST_MASK,
++ RGR1_SW_INIT_1_PERST_SHIFT,
++};
++
++enum pcie_type {
++ BCM7425,
++ BCM7435,
++ GENERIC,
++ BCM7278,
++};
++
++struct brcm_window {
++ dma_addr_t pcie_addr;
++ phys_addr_t cpu_addr;
++ dma_addr_t size;
++};
++
++/* Internal PCIe Host Controller Information.*/
++struct brcm_pcie {
++ struct device *dev;
++ void __iomem *base;
++ struct list_head resources;
++ int irq;
++ struct clk *clk;
++ struct pci_bus *root_bus;
++ struct device_node *dn;
++ int id;
++ bool suspended;
++ int num_out_wins;
++ bool ssc;
++ int gen;
++ struct brcm_window out_wins[BRCM_NUM_PCIE_OUT_WINS];
++ unsigned int rev;
++ const int *reg_offsets;
++ const int *reg_field_info;
++ enum pcie_type type;
++};
++
++struct pcie_cfg_data {
++ const int *reg_field_info;
++ const int *offsets;
++ const enum pcie_type type;
++};
++
++static const int pcie_reg_field_info[] = {
++ [RGR1_SW_INIT_1_INIT_MASK] = 0x2,
++ [RGR1_SW_INIT_1_INIT_SHIFT] = 0x1,
++};
++
++static const int pcie_reg_field_info_bcm7278[] = {
++ [RGR1_SW_INIT_1_INIT_MASK] = 0x1,
++ [RGR1_SW_INIT_1_INIT_SHIFT] = 0x0,
++};
++
++static const int pcie_offset_bcm7425[] = {
++ [RGR1_SW_INIT_1] = 0x8010,
++ [EXT_CFG_INDEX] = 0x8300,
++ [EXT_CFG_DATA] = 0x8304,
++};
++
++static const struct pcie_cfg_data bcm7425_cfg = {
++ .reg_field_info = pcie_reg_field_info,
++ .offsets = pcie_offset_bcm7425,
++ .type = BCM7425,
++};
++
++static const int pcie_offsets[] = {
++ [RGR1_SW_INIT_1] = 0x9210,
++ [EXT_CFG_INDEX] = 0x9000,
++ [EXT_CFG_DATA] = 0x9004,
++};
++
++static const struct pcie_cfg_data bcm7435_cfg = {
++ .reg_field_info = pcie_reg_field_info,
++ .offsets = pcie_offsets,
++ .type = BCM7435,
++};
++
++static const struct pcie_cfg_data generic_cfg = {
++ .reg_field_info = pcie_reg_field_info,
++ .offsets = pcie_offsets,
++ .type = GENERIC,
++};
++
++static const int pcie_offset_bcm7278[] = {
++ [RGR1_SW_INIT_1] = 0xc010,
++ [EXT_CFG_INDEX] = 0x9000,
++ [EXT_CFG_DATA] = 0x9004,
++};
++
++static const struct pcie_cfg_data bcm7278_cfg = {
++ .reg_field_info = pcie_reg_field_info_bcm7278,
++ .offsets = pcie_offset_bcm7278,
++ .type = BCM7278,
++};
++
++static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
++ int where);
++
++static struct pci_ops brcm_pcie_ops = {
++ .map_bus = brcm_pcie_map_conf,
++ .read = pci_generic_config_read,
++ .write = pci_generic_config_write,
++};
++
++#if defined(CONFIG_MIPS)
++/* Broadcom MIPs HW implicitly does the swapping if necessary */
++#define bcm_readl(a) __raw_readl(a)
++#define bcm_writel(d, a) __raw_writel(d, a)
++#define bcm_readw(a) __raw_readw(a)
++#define bcm_writew(d, a) __raw_writew(d, a)
++#else
++#define bcm_readl(a) readl(a)
++#define bcm_writel(d, a) writel(d, a)
++#define bcm_readw(a) readw(a)
++#define bcm_writew(d, a) writew(d, a)
++#endif
++
++/* These macros extract/insert fields to host controller's register set. */
++#define RD_FLD(base, reg, field) \
++ rd_fld(base + reg, reg##_##field##_MASK, reg##_##field##_SHIFT)
++#define WR_FLD(base, reg, field, val) \
++ wr_fld(base + reg, reg##_##field##_MASK, reg##_##field##_SHIFT, val)
++#define WR_FLD_RB(base, reg, field, val) \
++ wr_fld_rb(base + reg, reg##_##field##_MASK, reg##_##field##_SHIFT, val)
++#define WR_FLD_WITH_OFFSET(base, off, reg, field, val) \
++ wr_fld(base + reg + off, reg##_##field##_MASK, \
++ reg##_##field##_SHIFT, val)
++#define EXTRACT_FIELD(val, reg, field) \
++ ((val & reg##_##field##_MASK) >> reg##_##field##_SHIFT)
++#define INSERT_FIELD(val, reg, field, field_val) \
++ ((val & ~reg##_##field##_MASK) | \
++ (reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
++
++static phys_addr_t scb_size[BRCM_MAX_SCB];
++static int num_memc;
++static int num_pcie;
++static DEFINE_MUTEX(brcm_pcie_lock);
++
++static u32 rd_fld(void __iomem *p, u32 mask, int shift)
++{
++ return (bcm_readl(p) & mask) >> shift;
++}
++
++static void wr_fld(void __iomem *p, u32 mask, int shift, u32 val)
++{
++ u32 reg = bcm_readl(p);
++
++ reg = (reg & ~mask) | ((val << shift) & mask);
++ bcm_writel(reg, p);
++}
++
++static void wr_fld_rb(void __iomem *p, u32 mask, int shift, u32 val)
++{
++ wr_fld(p, mask, shift, val);
++ (void)bcm_readl(p);
++}
++
++static const char *link_speed_to_str(int s)
++{
++ switch (s) {
++ case 1:
++ return "2.5";
++ case 2:
++ return "5.0";
++ case 3:
++ return "8.0";
++ default:
++ break;
++ }
++ return "???";
++}
++
++/*
++ * The roundup_pow_of_two() from log2.h invokes
++ * __roundup_pow_of_two(unsigned long), but we really need a
++ * such a function to take a native u64 since unsigned long
++ * is 32 bits on some configurations. So we provide this helper
++ * function below.
++ */
++static u64 roundup_pow_of_two_64(u64 n)
++{
++ return 1ULL << fls64(n - 1);
++}
++
++/*
++ * This is to convert the size of the inbound "BAR" region to the
++ * non-linear values of PCIE_X_MISC_RC_BAR[123]_CONFIG_LO.SIZE
++ */
++int encode_ibar_size(u64 size)
++{
++ int log2_in = ilog2(size);
++
++ if (log2_in >= 12 && log2_in <= 15)
++ /* Covers 4KB to 32KB (inclusive) */
++ return (log2_in - 12) + 0x1c;
++ else if (log2_in >= 16 && log2_in <= 37)
++ /* Covers 64KB to 32GB, (inclusive) */
++ return log2_in - 15;
++ /* Something is awry so disable */
++ return 0;
++}
++
++static u32 mdio_form_pkt(int port, int regad, int cmd)
++{
++ u32 pkt = 0;
++
++ pkt |= (port << MDIO_PORT_SHIFT) & MDIO_PORT_MASK;
++ pkt |= (regad << MDIO_REGAD_SHIFT) & MDIO_REGAD_MASK;
++ pkt |= (cmd << MDIO_CMD_SHIFT) & MDIO_CMD_MASK;
++
++ return pkt;
++}
++
++/* negative return value indicates error */
++static int mdio_read(void __iomem *base, u8 port, u8 regad)
++{
++ int tries;
++ u32 data;
++
++ bcm_writel(mdio_form_pkt(port, regad, MDIO_CMD_READ),
++ base + PCIE_RC_DL_MDIO_ADDR);
++ bcm_readl(base + PCIE_RC_DL_MDIO_ADDR);
++
++ data = bcm_readl(base + PCIE_RC_DL_MDIO_RD_DATA);
++ for (tries = 0; !MDIO_RD_DONE(data) && tries < 10; tries++) {
++ udelay(10);
++ data = bcm_readl(base + PCIE_RC_DL_MDIO_RD_DATA);
++ }
++
++ return MDIO_RD_DONE(data)
++ ? (data & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT
++ : -EIO;
++}
++
++/* negative return value indicates error */
++static int mdio_write(void __iomem *base, u8 port, u8 regad, u16 wrdata)
++{
++ int tries;
++ u32 data;
++
++ bcm_writel(mdio_form_pkt(port, regad, MDIO_CMD_WRITE),
++ base + PCIE_RC_DL_MDIO_ADDR);
++ bcm_readl(base + PCIE_RC_DL_MDIO_ADDR);
++ bcm_writel(MDIO_DATA_DONE_MASK | wrdata,
++ base + PCIE_RC_DL_MDIO_WR_DATA);
++
++ data = bcm_readl(base + PCIE_RC_DL_MDIO_WR_DATA);
++ for (tries = 0; !MDIO_WT_DONE(data) && tries < 10; tries++) {
++ udelay(10);
++ data = bcm_readl(base + PCIE_RC_DL_MDIO_WR_DATA);
++ }
++
++ return MDIO_WT_DONE(data) ? 0 : -EIO;
++}
++
++/*
++ * Configures device for Spread Spectrum Clocking (SSC) mode; a negative
++ * return value indicates error.
++ */
++static int set_ssc(void __iomem *base)
++{
++ int tmp;
++ u16 wrdata;
++ int pll, ssc;
++
++ tmp = mdio_write(base, MDIO_PORT0, SET_ADDR_OFFSET, SSC_REGS_ADDR);
++ if (tmp < 0)
++ return tmp;
++
++ tmp = mdio_read(base, MDIO_PORT0, SSC_CNTL_OFFSET);
++ if (tmp < 0)
++ return tmp;
++
++ wrdata = INSERT_FIELD(tmp, SSC_CNTL_OVRD, EN, 1);
++ wrdata = INSERT_FIELD(wrdata, SSC_CNTL_OVRD, VAL, 1);
++ tmp = mdio_write(base, MDIO_PORT0, SSC_CNTL_OFFSET, wrdata);
++ if (tmp < 0)
++ return tmp;
++
++ usleep_range(1000, 2000);
++ tmp = mdio_read(base, MDIO_PORT0, SSC_STATUS_OFFSET);
++ if (tmp < 0)
++ return tmp;
++
++ ssc = EXTRACT_FIELD(tmp, SSC_STATUS, SSC);
++ pll = EXTRACT_FIELD(tmp, SSC_STATUS, PLL_LOCK);
++
++ return (ssc && pll) ? 0 : -EIO;
++}
++
++/* Limits operation to a specific generation (1, 2, or 3) */
++static void set_gen(void __iomem *base, int gen)
++{
++ u32 lnkcap = bcm_readl(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
++ u16 lnkctl2 = bcm_readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
++
++ lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen;
++ bcm_writel(lnkcap, base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
++
++ lnkctl2 = (lnkctl2 & ~0xf) | gen;
++ bcm_writew(lnkctl2, base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
++}
++
++static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie,
++ unsigned int win, phys_addr_t cpu_addr,
++ dma_addr_t pcie_addr, dma_addr_t size)
++{
++ void __iomem *base = pcie->base;
++ phys_addr_t cpu_addr_mb, limit_addr_mb;
++ u32 tmp;
++
++ /* Set the base of the pcie_addr window */
++ bcm_writel(lower_32_bits(pcie_addr) + MMIO_ENDIAN,
++ base + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + (win * 8));
++ bcm_writel(upper_32_bits(pcie_addr),
++ base + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + (win * 8));
++
++ cpu_addr_mb = cpu_addr >> 20;
++ limit_addr_mb = (cpu_addr + size - 1) >> 20;
++
++ /* Write the addr base low register */
++ WR_FLD_WITH_OFFSET(base, (win * 4),
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT,
++ BASE, cpu_addr_mb);
++ /* Write the addr limit low register */
++ WR_FLD_WITH_OFFSET(base, (win * 4),
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT,
++ LIMIT, limit_addr_mb);
++
++ if (pcie->type != BCM7435 && pcie->type != BCM7425) {
++ /* Write the cpu addr high register */
++ tmp = (u32)(cpu_addr_mb >>
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_NUM_MASK_BITS);
++ WR_FLD_WITH_OFFSET(base, (win * 8),
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI,
++ BASE, tmp);
++ /* Write the cpu limit high register */
++ tmp = (u32)(limit_addr_mb >>
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_NUM_MASK_BITS);
++ WR_FLD_WITH_OFFSET(base, (win * 8),
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI,
++ LIMIT, tmp);
++ }
++}
++
++/* Configuration space read/write support */
++static int cfg_index(int busnr, int devfn, int reg)
++{
++ return ((PCI_SLOT(devfn) & 0x1f) << PCIE_SLOT_SHIFT)
++ | ((PCI_FUNC(devfn) & 0x07) << PCIE_FUNC_SHIFT)
++ | (busnr << PCIE_BUSNUM_SHIFT)
++ | (reg & ~3);
++}
++
++/* The controller is capable of serving in both RC and EP roles */
++static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie)
++{
++ void __iomem *base = pcie->base;
++ u32 val = bcm_readl(base + PCIE_MISC_PCIE_STATUS);
++
++ return !!EXTRACT_FIELD(val, PCIE_MISC_PCIE_STATUS, PCIE_PORT);
++}
++
++static bool brcm_pcie_link_up(struct brcm_pcie *pcie)
++{
++ void __iomem *base = pcie->base;
++ u32 val = bcm_readl(base + PCIE_MISC_PCIE_STATUS);
++ u32 dla = EXTRACT_FIELD(val, PCIE_MISC_PCIE_STATUS, PCIE_DL_ACTIVE);
++ u32 plu = EXTRACT_FIELD(val, PCIE_MISC_PCIE_STATUS, PCIE_PHYLINKUP);
++
++ return (dla && plu) ? true : false;
++}
++
++static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
++ int where)
++{
++ struct brcm_pcie *pcie = bus->sysdata;
++ void __iomem *base = pcie->base;
++ int idx;
++
++ /* Accesses to the RC go right to the RC registers if slot==0 */
++ if (pci_is_root_bus(bus))
++ return PCI_SLOT(devfn) ? NULL : base + where;
++
++ /* For devices, write to the config space index register */
++ idx = cfg_index(bus->number, devfn, where);
++ bcm_writel(idx, pcie->base + IDX_ADDR(pcie));
++ return base + DATA_ADDR(pcie) + (where & 0x3);
++}
++
++static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie,
++ unsigned int val)
++{
++ unsigned int shift = pcie->reg_field_info[RGR1_SW_INIT_1_INIT_SHIFT];
++ u32 mask = pcie->reg_field_info[RGR1_SW_INIT_1_INIT_MASK];
++
++ wr_fld_rb(pcie->base + PCIE_RGR1_SW_INIT_1(pcie), mask, shift, val);
++}
++
++static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
++ unsigned int val)
++{
++ if (pcie->type != BCM7278)
++ wr_fld_rb(pcie->base + PCIE_RGR1_SW_INIT_1(pcie),
++ PCIE_RGR1_SW_INIT_1_PERST_MASK,
++ PCIE_RGR1_SW_INIT_1_PERST_SHIFT, val);
++ else
++ /* Assert = 0, de-assert = 1 on 7278 */
++ WR_FLD_RB(pcie->base, PCIE_MISC_PCIE_CTRL, PCIE_PERSTB, !val);
++}
++
++static int brcm_pcie_add_controller(struct brcm_pcie *pcie)
++{
++ int i, ret = 0;
++
++ mutex_lock(&brcm_pcie_lock);
++ if (num_pcie > 0) {
++ num_pcie++;
++ goto done;
++ }
++
++ /* Determine num_memc and their sizes */
++ for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
++ u64 size = brcmstb_memory_memc_size(i);
++
++ if (size == (u64)-1) {
++ dev_err(pcie->dev, "cannot get memc%d size\n", i);
++ ret = -EINVAL;
++ goto done;
++ } else if (size) {
++ scb_size[i] = roundup_pow_of_two_64(size);
++ num_memc++;
++ } else {
++ break;
++ }
++ }
++ if (!ret && num_memc == 0) {
++ ret = -EINVAL;
++ goto done;
++ }
++
++ num_pcie++;
++done:
++ mutex_unlock(&brcm_pcie_lock);
++ return ret;
++}
++
++static void brcm_pcie_remove_controller(struct brcm_pcie *pcie)
++{
++ mutex_lock(&brcm_pcie_lock);
++ if (--num_pcie == 0)
++ num_memc = 0;
++ mutex_unlock(&brcm_pcie_lock);
++}
++
++static int brcm_pcie_parse_request_of_pci_ranges(struct brcm_pcie *pcie)
++{
++ struct resource_entry *win;
++ int ret;
++
++ ret = devm_of_pci_get_host_bridge_resources(pcie->dev, 0, 0xff,
++ &pcie->resources, NULL);
++ if (ret) {
++ dev_err(pcie->dev, "failed to get host resources\n");
++ return ret;
++ }
++
++ resource_list_for_each_entry(win, &pcie->resources) {
++ struct resource *parent, *res = win->res;
++ dma_addr_t offset = (dma_addr_t)win->offset;
++
++ if (resource_type(res) == IORESOURCE_IO) {
++ parent = &ioport_resource;
++ } else if (resource_type(res) == IORESOURCE_MEM) {
++ if (pcie->num_out_wins >= BRCM_NUM_PCIE_OUT_WINS) {
++ dev_err(pcie->dev, "too many outbound wins\n");
++ return -EINVAL;
++ }
++ pcie->out_wins[pcie->num_out_wins].cpu_addr
++ = (phys_addr_t)res->start;
++ pcie->out_wins[pcie->num_out_wins].pcie_addr
++ = (dma_addr_t)(res->start
++ - (phys_addr_t)offset);
++ pcie->out_wins[pcie->num_out_wins].size
++ = (dma_addr_t)(res->end - res->start + 1);
++ pcie->num_out_wins++;
++ parent = &iomem_resource;
++ } else {
++ continue;
++ }
++
++ ret = devm_request_resource(pcie->dev, parent, res);
++ if (ret) {
++ dev_err(pcie->dev, "failed to get res %pR\n", res);
++ return ret;
++ }
++ }
++ return 0;
++}
++
++static int brcm_pcie_setup(struct brcm_pcie *pcie)
++{
++ void __iomem *base = pcie->base;
++ unsigned int scb_size_val;
++ u64 rc_bar2_offset, rc_bar2_size, total_mem_size = 0;
++ u32 tmp, burst;
++ int i, j, ret, limit;
++ u16 nlw, cls, lnksta;
++ bool ssc_good = false;
++ struct device *dev = pcie->dev;
++
++ /* Reset the bridge */
++ brcm_pcie_bridge_sw_init_set(pcie, 1);
++
++ /*
++ * Ensure that the fundamental reset is asserted, except for 7278,
++ * which fails if we do this.
++ */
++ if (pcie->type != BCM7278)
++ brcm_pcie_perst_set(pcie, 1);
++
++ usleep_range(100, 200);
++
++ /* Take the bridge out of reset */
++ brcm_pcie_bridge_sw_init_set(pcie, 0);
++
++ WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, SERDES_IDDQ, 0);
++ /* Wait for SerDes to be stable */
++ usleep_range(100, 200);
++
++ /* Grab the PCIe hw revision number */
++ tmp = bcm_readl(base + PCIE_MISC_REVISION);
++ pcie->rev = EXTRACT_FIELD(tmp, PCIE_MISC_REVISION, MAJMIN);
++
++ /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
++ tmp = INSERT_FIELD(0, PCIE_MISC_MISC_CTRL, SCB_ACCESS_EN, 1);
++ tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, CFG_READ_UR_MODE, 1);
++ burst = (pcie->type == GENERIC || pcie->type == BCM7278)
++ ? BURST_SIZE_512 : BURST_SIZE_256;
++ tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, MAX_BURST_SIZE, burst);
++ bcm_writel(tmp, base + PCIE_MISC_MISC_CTRL);
++
++ /*
++ * Set up inbound memory view for the EP (called RC_BAR2,
++ * not to be confused with the BARs that are advertised by
++ * the EP).
++ */
++ for (i = 0; i < num_memc; i++)
++ total_mem_size += scb_size[i];
++
++ /*
++ * The PCIe host controller by design must set the inbound
++ * viewport to be a contiguous arrangement of all of the
++ * system's memory. In addition, its size mut be a power of
++ * two. To further complicate matters, the viewport must
++ * start on a pcie-address that is aligned on a multiple of its
++ * size. If a portion of the viewport does not represent
++ * system memory -- e.g. 3GB of memory requires a 4GB viewport
++ * -- we can map the outbound memory in or after 3GB and even
++ * though the viewport will overlap the outbound memory the
++ * controller will know to send outbound memory downstream and
++ * everything else upstream.
++ */
++ rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
++
++ /*
++ * Set simple configuration based on memory sizes
++ * only. We always start the viewport at address 0.
++ */
++ rc_bar2_offset = 0;
++
++ tmp = lower_32_bits(rc_bar2_offset);
++ tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
++ encode_ibar_size(rc_bar2_size));
++ bcm_writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO);
++ bcm_writel(upper_32_bits(rc_bar2_offset),
++ base + PCIE_MISC_RC_BAR2_CONFIG_HI);
++
++ scb_size_val = scb_size[0]
++ ? ilog2(scb_size[0]) - 15 : 0xf; /* 0xf is 1GB */
++ WR_FLD(base, PCIE_MISC_MISC_CTRL, SCB0_SIZE, scb_size_val);
++
++ if (num_memc > 1) {
++ scb_size_val = scb_size[1]
++ ? ilog2(scb_size[1]) - 15 : 0xf; /* 0xf is 1GB */
++ WR_FLD(base, PCIE_MISC_MISC_CTRL, SCB1_SIZE, scb_size_val);
++ }
++
++ if (num_memc > 2) {
++ scb_size_val = scb_size[2]
++ ? ilog2(scb_size[2]) - 15 : 0xf; /* 0xf is 1GB */
++ WR_FLD(base, PCIE_MISC_MISC_CTRL, SCB2_SIZE, scb_size_val);
++ }
++
++ /* disable the PCIe->GISB memory window (RC_BAR1) */
++ WR_FLD(base, PCIE_MISC_RC_BAR1_CONFIG_LO, SIZE, 0);
++
++ /* disable the PCIe->SCB memory window (RC_BAR3) */
++ WR_FLD(base, PCIE_MISC_RC_BAR3_CONFIG_LO, SIZE, 0);
++
++ if (!pcie->suspended) {
++ /* clear any interrupts we find on boot */
++ bcm_writel(0xffffffff, base + PCIE_INTR2_CPU_BASE + CLR);
++ (void)bcm_readl(base + PCIE_INTR2_CPU_BASE + CLR);
++ }
++
++ /* Mask all interrupts since we are not handling any yet */
++ bcm_writel(0xffffffff, base + PCIE_INTR2_CPU_BASE + MASK_SET);
++ (void)bcm_readl(base + PCIE_INTR2_CPU_BASE + MASK_SET);
++
++ if (pcie->gen)
++ set_gen(base, pcie->gen);
++
++ /* Unassert the fundamental reset */
++ brcm_pcie_perst_set(pcie, 0);
++
++ /*
++ * Give the RC/EP time to wake up, before trying to configure RC.
++ * Intermittently check status for link-up, up to a total of 100ms
++ * when we don't know if the device is there, and up to 1000ms if
++ * we do know the device is there.
++ */
++ limit = pcie->suspended ? 1000 : 100;
++ for (i = 1, j = 0; j < limit && !brcm_pcie_link_up(pcie);
++ j += i, i = i * 2)
++ msleep(i + j > limit ? limit - j : i);
++
++ if (!brcm_pcie_link_up(pcie)) {
++ dev_info(dev, "link down\n");
++ return -ENODEV;
++ }
++
++ if (!brcm_pcie_rc_mode(pcie)) {
++ dev_err(dev, "PCIe misconfigured; is in EP mode\n");
++ return -EINVAL;
++ }
++
++ for (i = 0; i < pcie->num_out_wins; i++)
++ brcm_pcie_set_outbound_win(pcie, i, pcie->out_wins[i].cpu_addr,
++ pcie->out_wins[i].pcie_addr,
++ pcie->out_wins[i].size);
++
++ /*
++ * For config space accesses on the RC, show the right class for
++ * a PCIe-PCIe bridge (the default setting is to be EP mode).
++ */
++ WR_FLD_RB(base, PCIE_RC_CFG_PRIV1_ID_VAL3, CLASS_CODE, 0x060400);
++
++ if (pcie->ssc) {
++ ret = set_ssc(base);
++ if (ret == 0)
++ ssc_good = true;
++ else
++ dev_err(dev, "failed attempt to enter ssc mode\n");
++ }
++
++ lnksta = bcm_readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA);
++ cls = lnksta & PCI_EXP_LNKSTA_CLS;
++ nlw = (lnksta & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
++ dev_info(dev, "link up, %s Gbps x%u %s\n", link_speed_to_str(cls),
++ nlw, ssc_good ? "(SSC)" : "(!SSC)");
++
++ /* PCIe->SCB endian mode for BAR */
++ /* field ENDIAN_MODE_BAR2 = DATA_ENDIAN */
++ WR_FLD_RB(base, PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1,
++ ENDIAN_MODE_BAR2, DATA_ENDIAN);
++
++ /*
++ * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1
++ * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1.
++ */
++ WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, CLKREQ_DEBUG_ENABLE, 1);
++
++ return 0;
++}
++
++/* L23 is a low-power PCIe link state */
++static void enter_l23(struct brcm_pcie *pcie)
++{
++ void __iomem *base = pcie->base;
++ int tries, l23;
++
++ /* assert request for L23 */
++ WR_FLD_RB(base, PCIE_MISC_PCIE_CTRL, PCIE_L23_REQUEST, 1);
++ /* poll L23 status */
++ for (tries = 0, l23 = 0; tries < 1000 && !l23; tries++)
++ l23 = RD_FLD(base, PCIE_MISC_PCIE_STATUS, PCIE_LINK_IN_L23);
++ if (!l23)
++ dev_err(pcie->dev, "failed to enter L23\n");
++}
++
++static void turn_off(struct brcm_pcie *pcie)
++{
++ void __iomem *base = pcie->base;
++
++ if (brcm_pcie_link_up(pcie))
++ enter_l23(pcie);
++ /* Assert fundamental reset */
++ brcm_pcie_perst_set(pcie, 1);
++ /* Deassert request for L23 in case it was asserted */
++ WR_FLD_RB(base, PCIE_MISC_PCIE_CTRL, PCIE_L23_REQUEST, 0);
++ /* Turn off SerDes */
++ WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, SERDES_IDDQ, 1);
++ /* Shutdown PCIe bridge */
++ brcm_pcie_bridge_sw_init_set(pcie, 1);
++}
++
++static int brcm_pcie_suspend(struct device *dev)
++{
++ struct brcm_pcie *pcie = dev_get_drvdata(dev);
++
++ turn_off(pcie);
++ clk_disable_unprepare(pcie->clk);
++ pcie->suspended = true;
++
++ return 0;
++}
++
++static int brcm_pcie_resume(struct device *dev)
++{
++ struct brcm_pcie *pcie = dev_get_drvdata(dev);
++ void __iomem *base;
++ int ret;
++
++ base = pcie->base;
++ clk_prepare_enable(pcie->clk);
++
++ /* Take bridge out of reset so we can access the SerDes reg */
++ brcm_pcie_bridge_sw_init_set(pcie, 0);
++
++ /* Turn on SerDes */
++ WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, SERDES_IDDQ, 0);
++ /* Wait for SerDes to be stable */
++ usleep_range(100, 200);
++
++ ret = brcm_pcie_setup(pcie);
++ if (ret)
++ return ret;
++
++ pcie->suspended = false;
++
++ return 0;
++}
++
++static void _brcm_pcie_remove(struct brcm_pcie *pcie)
++{
++ turn_off(pcie);
++ clk_disable_unprepare(pcie->clk);
++ clk_put(pcie->clk);
++ brcm_pcie_remove_controller(pcie);
++}
++
++static int brcm_pcie_remove(struct platform_device *pdev)
++{
++ struct brcm_pcie *pcie = platform_get_drvdata(pdev);
++
++ pci_stop_root_bus(pcie->root_bus);
++ pci_remove_root_bus(pcie->root_bus);
++ _brcm_pcie_remove(pcie);
++
++ return 0;
++}
++
++static const struct of_device_id brcm_pcie_match[] = {
++ { .compatible = "brcm,bcm7425-pcie", .data = &bcm7425_cfg },
++ { .compatible = "brcm,bcm7435-pcie", .data = &bcm7435_cfg },
++ { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg },
++ { .compatible = "brcm,bcm7445-pcie", .data = &generic_cfg },
++ {},
++};
++MODULE_DEVICE_TABLE(of, brcm_pcie_match);
++
++static int brcm_pcie_probe(struct platform_device *pdev)
++{
++ struct device_node *dn = pdev->dev.of_node;
++ const struct of_device_id *of_id;
++ const struct pcie_cfg_data *data;
++ int ret;
++ struct brcm_pcie *pcie;
++ struct resource *res;
++ void __iomem *base;
++ u32 tmp;
++ struct pci_host_bridge *bridge;
++ struct pci_bus *child;
++
++ bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
++ if (!bridge)
++ return -ENOMEM;
++
++ pcie = pci_host_bridge_priv(bridge);
++ INIT_LIST_HEAD(&pcie->resources);
++
++ of_id = of_match_node(brcm_pcie_match, dn);
++ if (!of_id) {
++ dev_err(&pdev->dev, "failed to look up compatible string\n");
++ return -EINVAL;
++ }
++
++ if (of_property_read_u32(dn, "dma-ranges", &tmp) == 0) {
++ dev_err(&pdev->dev, "cannot yet handle dma-ranges\n");
++ return -EINVAL;
++ }
++
++ data = of_id->data;
++ pcie->reg_offsets = data->offsets;
++ pcie->reg_field_info = data->reg_field_info;
++ pcie->type = data->type;
++ pcie->dn = dn;
++ pcie->dev = &pdev->dev;
++
++ /* We use the domain number as our controller number */
++ pcie->id = of_get_pci_domain_nr(dn);
++ if (pcie->id < 0)
++ return pcie->id;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res)
++ return -EINVAL;
++
++ base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(base))
++ return PTR_ERR(base);
++
++ pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
++ if (IS_ERR(pcie->clk)) {
++ dev_err(&pdev->dev, "could not get clock\n");
++ pcie->clk = NULL;
++ }
++ pcie->base = base;
++
++ ret = of_pci_get_max_link_speed(dn);
++ pcie->gen = (ret < 0) ? 0 : ret;
++
++ pcie->ssc = of_property_read_bool(dn, "brcm,enable-ssc");
++
++ ret = irq_of_parse_and_map(pdev->dev.of_node, 0);
++ if (ret == 0)
++ /* keep going, as we don't use this intr yet */
++ dev_warn(pcie->dev, "cannot get PCIe interrupt\n");
++ else
++ pcie->irq = ret;
++
++ ret = brcm_pcie_parse_request_of_pci_ranges(pcie);
++ if (ret)
++ return ret;
++
++ ret = clk_prepare_enable(pcie->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "could not enable clock\n");
++ return ret;
++ }
++
++ ret = brcm_pcie_add_controller(pcie);
++ if (ret)
++ return ret;
++
++ ret = brcm_pcie_setup(pcie);
++ if (ret)
++ goto fail;
++
++ list_splice_init(&pcie->resources, &bridge->windows);
++ bridge->dev.parent = &pdev->dev;
++ bridge->busnr = 0;
++ bridge->ops = &brcm_pcie_ops;
++ bridge->sysdata = pcie;
++ bridge->map_irq = of_irq_parse_and_map_pci;
++ bridge->swizzle_irq = pci_common_swizzle;
++
++ ret = pci_scan_root_bus_bridge(bridge);
++ if (ret < 0) {
++ dev_err(pcie->dev, "Scanning root bridge failed\n");
++ goto fail;
++ }
++
++ pci_assign_unassigned_bus_resources(bridge->bus);
++ list_for_each_entry(child, &bridge->bus->children, node)
++ pcie_bus_configure_settings(child);
++ pci_bus_add_devices(bridge->bus);
++ platform_set_drvdata(pdev, pcie);
++ pcie->root_bus = bridge->bus;
++
++ return 0;
++
++fail:
++ _brcm_pcie_remove(pcie);
++ return ret;
++}
++
++static const struct dev_pm_ops brcm_pcie_pm_ops = {
++ .suspend_noirq = brcm_pcie_suspend,
++ .resume_noirq = brcm_pcie_resume,
++};
++
++static struct platform_driver brcm_pcie_driver = {
++ .probe = brcm_pcie_probe,
++ .remove = brcm_pcie_remove,
++ .driver = {
++ .name = "brcm-pcie",
++ .owner = THIS_MODULE,
++ .of_match_table = brcm_pcie_match,
++ .pm = &brcm_pcie_pm_ops,
++ },
++};
++
++module_platform_driver(brcm_pcie_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("Broadcom STB PCIe RC driver");
++MODULE_AUTHOR("Broadcom");
+--- /dev/null
++++ b/include/soc/brcmstb/memory_api.h
+@@ -0,0 +1,25 @@
++#ifndef __MEMORY_API_H
++#define __MEMORY_API_H
++
++/*
++ * Bus Interface Unit control register setup, must happen early during boot,
++ * before SMP is brought up, called by machine entry point.
++ */
++void brcmstb_biuctrl_init(void);
++
++#ifdef CONFIG_SOC_BRCMSTB
++int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa);
++u64 brcmstb_memory_memc_size(int memc);
++#else
++static inline int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa)
++{
++ return -EINVAL;
++}
++
++static inline u64 brcmstb_memory_memc_size(int memc)
++{
++ return -1;
++}
++#endif
++
++#endif /* __MEMORY_API_H */
+++ /dev/null
-From 51d6e1924fd0e9d075bcef61bea5a475a0ad6634 Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Feb 2019 08:49:39 +0000
-Subject: [PATCH] arm: bcm2835: Fix FIQ early ioremap
-
-The ioremapping creates mappings within the vmalloc area. The
-equivalent early function, create_mapping, now checks that the
-requested explicit virtual address is between VMALLOC_START and
-VMALLOC_END. As there is no reason to have any correlation between
-the physical and virtual addresses, put the required mappings at
-VMALLOC_START and above.
-
----
- arch/arm/mach-bcm/board_bcm2835.c | 21 +++++++++++++++------
- 1 file changed, 15 insertions(+), 6 deletions(-)
-
---- a/arch/arm/mach-bcm/board_bcm2835.c
-+++ b/arch/arm/mach-bcm/board_bcm2835.c
-@@ -14,17 +14,20 @@
-
- #include <linux/init.h>
- #include <linux/irqchip.h>
-+#include <linux/mm.h>
- #include <linux/of_address.h>
- #include <linux/of_fdt.h>
- #include <asm/system_info.h>
-
- #include <asm/mach/arch.h>
- #include <asm/mach/map.h>
-+#include <asm/memory.h>
-+#include <asm/pgtable.h>
-
- #include "platsmp.h"
-
--#define BCM2835_USB_VIRT_BASE 0xf0980000
--#define BCM2835_USB_VIRT_MPHI 0xf0006000
-+#define BCM2835_USB_VIRT_BASE (VMALLOC_START)
-+#define BCM2835_USB_VIRT_MPHI (VMALLOC_START + 0x10000)
-
- static void __init bcm2835_init(void)
- {
-@@ -83,20 +86,26 @@ static int __init bcm2835_map_usb(unsign
-
- static void __init bcm2835_map_io(void)
- {
-- const __be32 *ranges;
-+ const __be32 *ranges, *address_cells;
-+ unsigned long root, addr_cells;
- int soc, len;
- unsigned long p2b_offset;
-
- debug_ll_io_init();
-
-+ root = of_get_flat_dt_root();
- /* Find out how to map bus to physical address first from soc/ranges */
-- soc = of_get_flat_dt_subnode_by_name(of_get_flat_dt_root(), "soc");
-+ soc = of_get_flat_dt_subnode_by_name(root, "soc");
- if (soc < 0)
- return;
-+ address_cells = of_get_flat_dt_prop(root, "#address-cells", &len);
-+ if (!address_cells || len < (sizeof(unsigned long)))
-+ return;
-+ addr_cells = be32_to_cpu(address_cells[0]);
- ranges = of_get_flat_dt_prop(soc, "ranges", &len);
-- if (!ranges || len < (sizeof(unsigned long) * 3))
-+ if (!ranges || len < (sizeof(unsigned long) * (2 + addr_cells)))
- return;
-- p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[1]);
-+ p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[addr_cells]);
-
- /* Now search for bcm2708-usb node in device tree */
- of_scan_flat_dt(bcm2835_map_usb, &p2b_offset);
+++ /dev/null
-From ab2695d38f4ffadde05c2275ac68f4aad68ef336 Mon Sep 17 00:00:00 2001
-Date: Thu, 14 Mar 2019 10:16:02 +0000
-Subject: [PATCH] Fix copy_from_user if BCM2835_FAST_MEMCPY=n
-
-The change which introduced CONFIG_BCM2835_FAST_MEMCPY unconditionally
-changed the behaviour of arm_copy_from_user. The page pinning code
-is not safe on ARMv7 if LPAE & high memory is enabled and causes
-crashes which look like PTE corruption.
-
-Make __copy_from_user_memcpy conditional on CONFIG_2835_FAST_MEMCPY=y
-which is really an ARMv6 / Pi1 optimization and not necessary on newer
-ARM processors.
----
- arch/arm/lib/uaccess_with_memcpy.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/arch/arm/lib/uaccess_with_memcpy.c
-+++ b/arch/arm/lib/uaccess_with_memcpy.c
-@@ -257,6 +257,7 @@ arm_copy_to_user(void __user *to, const
- unsigned long __must_check
- arm_copy_from_user(void *to, const void __user *from, unsigned long n)
- {
-+#ifdef CONFIG_BCM2835_FAST_MEMCPY
- /*
- * This test is stubbed out of the main function above to keep
- * the overhead for small copies low by avoiding a large
-@@ -271,6 +272,11 @@ arm_copy_from_user(void *to, const void
- } else {
- n = __copy_from_user_memcpy(to, from, n);
- }
-+#else
-+ unsigned long ua_flags = uaccess_save_and_enable();
-+ n = __copy_from_user_std(to, from, n);
-+ uaccess_restore(ua_flags);
-+#endif
- return n;
- }
-
--- /dev/null
+From d3cc1c713b9436a7dc72788caa1d8de63ac3a01b Mon Sep 17 00:00:00 2001
+Date: Tue, 19 Feb 2019 22:06:59 +0000
+Subject: [PATCH] PCI: brcmstb: Add dma-range mapping for inbound
+ traffic
+
+The Broadcom STB PCIe host controller is intimately related to the
+memory subsystem. This close relationship adds complexity to how cpu
+system memory is mapped to PCIe memory. Ideally, this mapping is an
+identity mapping, or an identity mapping off by a constant. Not so in
+this case.
+
+Consider the Broadcom reference board BCM97445LCC_4X8 which has 6 GB
+of system memory. Here is how the PCIe controller maps the
+system memory to PCIe memory:
+
+ memc0-a@[ 0....3fffffff] <=> pci@[ 0....3fffffff]
+ memc0-b@[100000000...13fffffff] <=> pci@[ 40000000....7fffffff]
+ memc1-a@[ 40000000....7fffffff] <=> pci@[ 80000000....bfffffff]
+ memc1-b@[300000000...33fffffff] <=> pci@[ c0000000....ffffffff]
+ memc2-a@[ 80000000....bfffffff] <=> pci@[100000000...13fffffff]
+ memc2-b@[c00000000...c3fffffff] <=> pci@[140000000...17fffffff]
+
+Although there are some "gaps" that can be added between the
+individual mappings by software, the permutation of memory regions for
+the most part is fixed by HW. The solution of having something close
+to an identity mapping is not possible.
+
+The idea behind this HW design is that the same PCIe module can
+act as an RC or EP, and if it acts as an EP it concatenates all
+of system memory into a BAR so anything can be accessed. Unfortunately,
+when the PCIe block is in the role of an RC it also presents this
+"BAR" to downstream PCIe devices, rather than offering an identity map
+between its system memory and PCIe space.
+
+Suppose that an endpoint driver allocs some DMA memory. Suppose this
+memory is located at 0x6000_0000, which is in the middle of memc1-a.
+The driver wants a dma_addr_t value that it can pass on to the EP to
+use. Without doing any custom mapping, the EP will use this value for
+DMA: the driver will get a dma_addr_t equal to 0x6000_0000. But this
+won't work; the device needs a dma_addr_t that reflects the PCIe space
+address, namely 0xa000_0000.
+
+So, essentially the solution to this problem must modify the
+dma_addr_t returned by the DMA routines routines. There are two
+ways (I know of) of doing this:
+
+(a) overriding/redefining the dma_to_phys() and phys_to_dma() calls
+that are used by the dma_ops routines. This is the approach of
+
+ arch/mips/cavium-octeon/dma-octeon.c
+
+In ARM and ARM64 these two routines are defiend in asm/dma-mapping.h
+as static inline functions.
+
+(b) Subscribe to a notifier that notifies when a device is added to a
+bus. When this happens, set_dma_ops() can be called for the device.
+This method is mentioned in:
+
+ http://lxr.free-electrons.com/source/drivers/of/platform.c?v=3.16#L152
+
+where it says as a comment
+
+ "In case if platform code need to use own special DMA
+ configuration, it can use Platform bus notifier and
+ handle BUS_NOTIFY_ADD_DEVICE event to fix up DMA
+ configuration."
+
+Solution (b) is what this commit does. It uses its own set of
+dma_ops which are wrappers around the arch_dma_ops. The
+wrappers translate the dma addresses before/after invoking
+the arch_dma_ops, as appropriate.
+
+---
+ drivers/pci/controller/pcie-brcmstb.c | 420 +++++++++++++++++++++++++-
+ 1 file changed, 411 insertions(+), 9 deletions(-)
+
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -4,6 +4,7 @@
+ #include <linux/clk.h>
+ #include <linux/compiler.h>
+ #include <linux/delay.h>
++#include <linux/dma-mapping.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+@@ -319,11 +320,307 @@ static struct pci_ops brcm_pcie_ops = {
+ ((val & ~reg##_##field##_MASK) | \
+ (reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
+
++static const struct dma_map_ops *arch_dma_ops;
++static const struct dma_map_ops *brcm_dma_ops_ptr;
++static struct of_pci_range *dma_ranges;
++static int num_dma_ranges;
++
+ static phys_addr_t scb_size[BRCM_MAX_SCB];
+ static int num_memc;
+ static int num_pcie;
+ static DEFINE_MUTEX(brcm_pcie_lock);
+
++static dma_addr_t brcm_to_pci(dma_addr_t addr)
++{
++ struct of_pci_range *p;
++
++ if (!num_dma_ranges)
++ return addr;
++
++ for (p = dma_ranges; p < &dma_ranges[num_dma_ranges]; p++)
++ if (addr >= p->cpu_addr && addr < (p->cpu_addr + p->size))
++ return addr - p->cpu_addr + p->pci_addr;
++
++ return addr;
++}
++
++static dma_addr_t brcm_to_cpu(dma_addr_t addr)
++{
++ struct of_pci_range *p;
++
++ if (!num_dma_ranges)
++ return addr;
++
++ for (p = dma_ranges; p < &dma_ranges[num_dma_ranges]; p++)
++ if (addr >= p->pci_addr && addr < (p->pci_addr + p->size))
++ return addr - p->pci_addr + p->cpu_addr;
++
++ return addr;
++}
++
++static void *brcm_alloc(struct device *dev, size_t size, dma_addr_t *handle,
++ gfp_t gfp, unsigned long attrs)
++{
++ void *ret;
++
++ ret = arch_dma_ops->alloc(dev, size, handle, gfp, attrs);
++ if (ret)
++ *handle = brcm_to_pci(*handle);
++ return ret;
++}
++
++static void brcm_free(struct device *dev, size_t size, void *cpu_addr,
++ dma_addr_t handle, unsigned long attrs)
++{
++ handle = brcm_to_cpu(handle);
++ arch_dma_ops->free(dev, size, cpu_addr, handle, attrs);
++}
++
++static int brcm_mmap(struct device *dev, struct vm_area_struct *vma,
++ void *cpu_addr, dma_addr_t dma_addr, size_t size,
++ unsigned long attrs)
++{
++ dma_addr = brcm_to_cpu(dma_addr);
++ return arch_dma_ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
++}
++
++static int brcm_get_sgtable(struct device *dev, struct sg_table *sgt,
++ void *cpu_addr, dma_addr_t handle, size_t size,
++ unsigned long attrs)
++{
++ handle = brcm_to_cpu(handle);
++ return arch_dma_ops->get_sgtable(dev, sgt, cpu_addr, handle, size,
++ attrs);
++}
++
++static dma_addr_t brcm_map_page(struct device *dev, struct page *page,
++ unsigned long offset, size_t size,
++ enum dma_data_direction dir,
++ unsigned long attrs)
++{
++ return brcm_to_pci(arch_dma_ops->map_page(dev, page, offset, size,
++ dir, attrs));
++}
++
++static void brcm_unmap_page(struct device *dev, dma_addr_t handle,
++ size_t size, enum dma_data_direction dir,
++ unsigned long attrs)
++{
++ handle = brcm_to_cpu(handle);
++ arch_dma_ops->unmap_page(dev, handle, size, dir, attrs);
++}
++
++static int brcm_map_sg(struct device *dev, struct scatterlist *sgl,
++ int nents, enum dma_data_direction dir,
++ unsigned long attrs)
++{
++ int i, j;
++ struct scatterlist *sg;
++
++ for_each_sg(sgl, sg, nents, i) {
++#ifdef CONFIG_NEED_SG_DMA_LENGTH
++ sg->dma_length = sg->length;
++#endif
++ sg->dma_address =
++ brcm_dma_ops_ptr->map_page(dev, sg_page(sg), sg->offset,
++ sg->length, dir, attrs);
++ if (dma_mapping_error(dev, sg->dma_address))
++ goto bad_mapping;
++ }
++ return nents;
++
++bad_mapping:
++ for_each_sg(sgl, sg, i, j)
++ brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
++ sg_dma_len(sg), dir, attrs);
++ return 0;
++}
++
++static void brcm_unmap_sg(struct device *dev,
++ struct scatterlist *sgl, int nents,
++ enum dma_data_direction dir,
++ unsigned long attrs)
++{
++ int i;
++ struct scatterlist *sg;
++
++ for_each_sg(sgl, sg, nents, i)
++ brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
++ sg_dma_len(sg), dir, attrs);
++}
++
++static void brcm_sync_single_for_cpu(struct device *dev,
++ dma_addr_t handle, size_t size,
++ enum dma_data_direction dir)
++{
++ handle = brcm_to_cpu(handle);
++ arch_dma_ops->sync_single_for_cpu(dev, handle, size, dir);
++}
++
++static void brcm_sync_single_for_device(struct device *dev,
++ dma_addr_t handle, size_t size,
++ enum dma_data_direction dir)
++{
++ handle = brcm_to_cpu(handle);
++ arch_dma_ops->sync_single_for_device(dev, handle, size, dir);
++}
++
++static dma_addr_t brcm_map_resource(struct device *dev, phys_addr_t phys,
++ size_t size,
++ enum dma_data_direction dir,
++ unsigned long attrs)
++{
++ if (arch_dma_ops->map_resource)
++ return brcm_to_pci(arch_dma_ops->map_resource
++ (dev, phys, size, dir, attrs));
++ return brcm_to_pci((dma_addr_t)phys);
++}
++
++static void brcm_unmap_resource(struct device *dev, dma_addr_t handle,
++ size_t size, enum dma_data_direction dir,
++ unsigned long attrs)
++{
++ if (arch_dma_ops->unmap_resource)
++ arch_dma_ops->unmap_resource(dev, brcm_to_cpu(handle), size,
++ dir, attrs);
++}
++
++void brcm_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
++ int nents, enum dma_data_direction dir)
++{
++ struct scatterlist *sg;
++ int i;
++
++ for_each_sg(sgl, sg, nents, i)
++ brcm_dma_ops_ptr->sync_single_for_cpu(dev, sg_dma_address(sg),
++ sg->length, dir);
++}
++
++void brcm_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
++ int nents, enum dma_data_direction dir)
++{
++ struct scatterlist *sg;
++ int i;
++
++ for_each_sg(sgl, sg, nents, i)
++ brcm_dma_ops_ptr->sync_single_for_device(dev,
++ sg_dma_address(sg),
++ sg->length, dir);
++}
++
++static int brcm_mapping_error(struct device *dev, dma_addr_t dma_addr)
++{
++ return arch_dma_ops->mapping_error(dev, dma_addr);
++}
++
++static int brcm_dma_supported(struct device *dev, u64 mask)
++{
++ if (num_dma_ranges) {
++ /*
++ * It is our translated addresses that the EP will "see", so
++ * we check all of the ranges for the largest possible value.
++ */
++ int i;
++
++ for (i = 0; i < num_dma_ranges; i++)
++ if (dma_ranges[i].pci_addr + dma_ranges[i].size - 1
++ > mask)
++ return 0;
++ return 1;
++ }
++
++ return arch_dma_ops->dma_supported(dev, mask);
++}
++
++#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
++u64 brcm_get_required_mask)(struct device *dev)
++{
++ return arch_dma_ops->get_required_mask(dev);
++}
++#endif
++
++static const struct dma_map_ops brcm_dma_ops = {
++ .alloc = brcm_alloc,
++ .free = brcm_free,
++ .mmap = brcm_mmap,
++ .get_sgtable = brcm_get_sgtable,
++ .map_page = brcm_map_page,
++ .unmap_page = brcm_unmap_page,
++ .map_sg = brcm_map_sg,
++ .unmap_sg = brcm_unmap_sg,
++ .map_resource = brcm_map_resource,
++ .unmap_resource = brcm_unmap_resource,
++ .sync_single_for_cpu = brcm_sync_single_for_cpu,
++ .sync_single_for_device = brcm_sync_single_for_device,
++ .sync_sg_for_cpu = brcm_sync_sg_for_cpu,
++ .sync_sg_for_device = brcm_sync_sg_for_device,
++ .mapping_error = brcm_mapping_error,
++ .dma_supported = brcm_dma_supported,
++#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
++ .get_required_mask = brcm_get_required_mask,
++#endif
++};
++
++static void brcm_set_dma_ops(struct device *dev)
++{
++ int ret;
++
++ if (IS_ENABLED(CONFIG_ARM64)) {
++ /*
++ * We are going to invoke get_dma_ops(). That
++ * function, at this point in time, invokes
++ * get_arch_dma_ops(), and for ARM64 that function
++ * returns a pointer to dummy_dma_ops. So then we'd
++ * like to call arch_setup_dma_ops(), but that isn't
++ * exported. Instead, we call of_dma_configure(),
++ * which is exported, and this calls
++ * arch_setup_dma_ops(). Once we do this the call to
++ * get_dma_ops() will work properly because
++ * dev->dma_ops will be set.
++ */
++ ret = of_dma_configure(dev, dev->of_node, true);
++ if (ret) {
++ dev_err(dev, "of_dma_configure() failed: %d\n", ret);
++ return;
++ }
++ }
++
++ arch_dma_ops = get_dma_ops(dev);
++ if (!arch_dma_ops) {
++ dev_err(dev, "failed to get arch_dma_ops\n");
++ return;
++ }
++
++ set_dma_ops(dev, &brcm_dma_ops);
++}
++
++static int brcmstb_platform_notifier(struct notifier_block *nb,
++ unsigned long event, void *__dev)
++{
++ struct device *dev = __dev;
++
++ brcm_dma_ops_ptr = &brcm_dma_ops;
++ if (event != BUS_NOTIFY_ADD_DEVICE)
++ return NOTIFY_DONE;
++
++ brcm_set_dma_ops(dev);
++ return NOTIFY_OK;
++}
++
++static struct notifier_block brcmstb_platform_nb = {
++ .notifier_call = brcmstb_platform_notifier,
++};
++
++static int brcm_register_notifier(void)
++{
++ return bus_register_notifier(&pci_bus_type, &brcmstb_platform_nb);
++}
++
++static int brcm_unregister_notifier(void)
++{
++ return bus_unregister_notifier(&pci_bus_type, &brcmstb_platform_nb);
++}
++
+ static u32 rd_fld(void __iomem *p, u32 mask, int shift)
+ {
+ return (bcm_readl(p) & mask) >> shift;
+@@ -597,9 +894,71 @@ static inline void brcm_pcie_perst_set(s
+ WR_FLD_RB(pcie->base, PCIE_MISC_PCIE_CTRL, PCIE_PERSTB, !val);
+ }
+
++static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
++ struct device_node *node)
++{
++ const int na = 3, ns = 2;
++ int rlen;
++
++ parser->node = node;
++ parser->pna = of_n_addr_cells(node);
++ parser->np = parser->pna + na + ns;
++
++ parser->range = of_get_property(node, "dma-ranges", &rlen);
++ if (!parser->range)
++ return -ENOENT;
++
++ parser->end = parser->range + rlen / sizeof(__be32);
++
++ return 0;
++}
++
++static int brcm_pcie_parse_map_dma_ranges(struct brcm_pcie *pcie)
++{
++ int i;
++ struct of_pci_range_parser parser;
++ struct device_node *dn = pcie->dn;
++
++ /*
++ * Parse dma-ranges property if present. If there are multiple
++ * PCIe controllers, we only have to parse from one of them since
++ * the others will have an identical mapping.
++ */
++ if (!pci_dma_range_parser_init(&parser, dn)) {
++ unsigned int max_ranges
++ = (parser.end - parser.range) / parser.np;
++
++ dma_ranges = kcalloc(max_ranges, sizeof(struct of_pci_range),
++ GFP_KERNEL);
++ if (!dma_ranges)
++ return -ENOMEM;
++
++ for (i = 0; of_pci_range_parser_one(&parser, dma_ranges + i);
++ i++)
++ num_dma_ranges++;
++ }
++
++ for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
++ u64 size = brcmstb_memory_memc_size(i);
++
++ if (size == (u64)-1) {
++ dev_err(pcie->dev, "cannot get memc%d size", i);
++ return -EINVAL;
++ } else if (size) {
++ scb_size[i] = roundup_pow_of_two_64(size);
++ num_memc++;
++ } else {
++ break;
++ }
++ }
++
++ return 0;
++}
++
+ static int brcm_pcie_add_controller(struct brcm_pcie *pcie)
+ {
+ int i, ret = 0;
++ struct device *dev = pcie->dev;
+
+ mutex_lock(&brcm_pcie_lock);
+ if (num_pcie > 0) {
+@@ -607,12 +966,21 @@ static int brcm_pcie_add_controller(stru
+ goto done;
+ }
+
++ ret = brcm_register_notifier();
++ if (ret) {
++ dev_err(dev, "failed to register pci bus notifier\n");
++ goto done;
++ }
++ ret = brcm_pcie_parse_map_dma_ranges(pcie);
++ if (ret)
++ goto done;
++
+ /* Determine num_memc and their sizes */
+ for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
+ u64 size = brcmstb_memory_memc_size(i);
+
+ if (size == (u64)-1) {
+- dev_err(pcie->dev, "cannot get memc%d size\n", i);
++ dev_err(dev, "cannot get memc%d size\n", i);
+ ret = -EINVAL;
+ goto done;
+ } else if (size) {
+@@ -636,8 +1004,16 @@ done:
+ static void brcm_pcie_remove_controller(struct brcm_pcie *pcie)
+ {
+ mutex_lock(&brcm_pcie_lock);
+- if (--num_pcie == 0)
+- num_memc = 0;
++ if (--num_pcie > 0)
++ goto out;
++
++ if (brcm_unregister_notifier())
++ dev_err(pcie->dev, "failed to unregister pci bus notifier\n");
++ kfree(dma_ranges);
++ dma_ranges = NULL;
++ num_dma_ranges = 0;
++ num_memc = 0;
++out:
+ mutex_unlock(&brcm_pcie_lock);
+ }
+
+@@ -757,6 +1133,38 @@ static int brcm_pcie_setup(struct brcm_p
+ */
+ rc_bar2_offset = 0;
+
++ if (dma_ranges) {
++ /*
++ * The best-case scenario is to place the inbound
++ * region in the first 4GB of pci-space, as some
++ * legacy devices can only address 32bits.
++ * We would also like to put the MSI under 4GB
++ * as well, since some devices require a 32bit
++ * MSI target address.
++ */
++ if (total_mem_size <= 0xc0000000ULL &&
++ rc_bar2_size <= 0x100000000ULL) {
++ rc_bar2_offset = 0;
++ } else {
++ /*
++ * The system memory is 4GB or larger so we
++ * cannot start the inbound region at location
++ * 0 (since we have to allow some space for
++ * outbound memory @ 3GB). So instead we
++ * start it at the 1x multiple of its size
++ */
++ rc_bar2_offset = rc_bar2_size;
++ }
++
++ } else {
++ /*
++ * Set simple configuration based on memory sizes
++ * only. We always start the viewport at address 0,
++ * and set the MSI target address accordingly.
++ */
++ rc_bar2_offset = 0;
++ }
++
+ tmp = lower_32_bits(rc_bar2_offset);
+ tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
+ encode_ibar_size(rc_bar2_size));
+@@ -967,7 +1375,6 @@ static int brcm_pcie_probe(struct platfo
+ struct brcm_pcie *pcie;
+ struct resource *res;
+ void __iomem *base;
+- u32 tmp;
+ struct pci_host_bridge *bridge;
+ struct pci_bus *child;
+
+@@ -984,11 +1391,6 @@ static int brcm_pcie_probe(struct platfo
+ return -EINVAL;
+ }
+
+- if (of_property_read_u32(dn, "dma-ranges", &tmp) == 0) {
+- dev_err(&pdev->dev, "cannot yet handle dma-ranges\n");
+- return -EINVAL;
+- }
+-
+ data = of_id->data;
+ pcie->reg_offsets = data->offsets;
+ pcie->reg_field_info = data->reg_field_info;
+++ /dev/null
-From ac1212c0f8b611be6df28f252ebbad80b775ee0f Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Feb 2019 22:06:59 +0000
-Subject: [PATCH] PCI: brcmstb: Add Broadcom STB PCIe host controller
- driver
-
-This commit adds the basic Broadcom STB PCIe controller. Missing is
-the ability to process MSI and also handle dma-ranges for inbound
-memory accesses. These two functionalities are added in subsequent
-commits.
-
-The PCIe block contains an MDIO interface. This is a local interface
-only accessible by the PCIe controller. It cannot be used or shared
-by any other HW. As such, the small amount of code for this
-controller is included in this driver as there is little upside to put
-it elsewhere.
-
----
- drivers/pci/controller/Kconfig | 9 +
- drivers/pci/controller/Makefile | 2 +-
- drivers/pci/controller/pcie-brcmstb.c | 1097 +++++++++++++++++++++++++
- include/soc/brcmstb/memory_api.h | 25 +
- 4 files changed, 1132 insertions(+), 1 deletion(-)
- create mode 100644 drivers/pci/controller/pcie-brcmstb.c
- create mode 100644 include/soc/brcmstb/memory_api.h
-
---- a/drivers/pci/controller/Kconfig
-+++ b/drivers/pci/controller/Kconfig
-@@ -278,5 +278,14 @@ config VMD
- To compile this driver as a module, choose M here: the
- module will be called vmd.
-
-+config PCIE_BRCMSTB
-+ tristate "Broadcom Brcmstb PCIe platform host driver"
-+ depends on ARCH_BRCMSTB || BMIPS_GENERIC
-+ depends on OF
-+ depends on SOC_BRCMSTB
-+ default ARCH_BRCMSTB || BMIPS_GENERIC
-+ help
-+ Adds support for Broadcom Settop Box PCIe host controller.
-+
- source "drivers/pci/controller/dwc/Kconfig"
- endmenu
---- a/drivers/pci/controller/Makefile
-+++ b/drivers/pci/controller/Makefile
-@@ -28,11 +28,11 @@ obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie
- obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
- obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
- obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
-+obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
- obj-$(CONFIG_VMD) += vmd.o
- # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
- obj-y += dwc/
-
--
- # The following drivers are for devices that use the generic ACPI
- # pci_root.c driver but don't support standard ECAM config access.
- # They contain MCFG quirks to replace the generic ECAM accessors with
---- /dev/null
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -0,0 +1,1097 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* Copyright (C) 2009 - 2017 Broadcom */
-+
-+#include <linux/clk.h>
-+#include <linux/compiler.h>
-+#include <linux/delay.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <linux/irqdomain.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/log2.h>
-+#include <linux/module.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+#include <linux/of_pci.h>
-+#include <linux/of_platform.h>
-+#include <linux/pci.h>
-+#include <linux/printk.h>
-+#include <linux/sizes.h>
-+#include <linux/slab.h>
-+#include <soc/brcmstb/memory_api.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include "../pci.h"
-+
-+/* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */
-+#define BRCM_PCIE_CAP_REGS 0x00ac
-+
-+/*
-+ * Broadcom Settop Box PCIe Register Offsets. The names are from
-+ * the chip's RDB and we use them here so that a script can correlate
-+ * this code and the RDB to prevent discrepancies.
-+ */
-+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 0x0188
-+#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c
-+#define PCIE_RC_DL_MDIO_ADDR 0x1100
-+#define PCIE_RC_DL_MDIO_WR_DATA 0x1104
-+#define PCIE_RC_DL_MDIO_RD_DATA 0x1108
-+#define PCIE_MISC_MISC_CTRL 0x4008
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010
-+#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c
-+#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034
-+#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038
-+#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
-+#define PCIE_MISC_PCIE_CTRL 0x4064
-+#define PCIE_MISC_PCIE_STATUS 0x4068
-+#define PCIE_MISC_REVISION 0x406c
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204
-+#define PCIE_INTR2_CPU_BASE 0x4300
-+
-+/*
-+ * Broadcom Settop Box PCIe Register Field shift and mask info. The
-+ * names are from the chip's RDB and we use them here so that a script
-+ * can correlate this code and the RDB to prevent discrepancies.
-+ */
-+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc
-+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_SHIFT 0x2
-+#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff
-+#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_SHIFT 0x0
-+#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000
-+#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_SHIFT 0xc
-+#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000
-+#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_SHIFT 0xd
-+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000
-+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_SHIFT 0x14
-+#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK 0xf8000000
-+#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_SHIFT 0x1b
-+#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_MASK 0x7c00000
-+#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_SHIFT 0x16
-+#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_MASK 0x1f
-+#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_SHIFT 0x0
-+#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f
-+#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_SHIFT 0x0
-+#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f
-+#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_SHIFT 0x0
-+#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f
-+#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_SHIFT 0x0
-+#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK 0x4
-+#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_SHIFT 0x2
-+#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1
-+#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_SHIFT 0x0
-+#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80
-+#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_SHIFT 0x7
-+#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20
-+#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_SHIFT 0x5
-+#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10
-+#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_SHIFT 0x4
-+#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40
-+#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_SHIFT 0x6
-+#define PCIE_MISC_REVISION_MAJMIN_MASK 0xffff
-+#define PCIE_MISC_REVISION_MAJMIN_SHIFT 0
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_SHIFT 0x14
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_SHIFT 0x4
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_NUM_MASK_BITS 0xc
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK 0xff
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_SHIFT 0x0
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_SHIFT 0x0
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_SHIFT 0x1
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_SHIFT 0x1b
-+#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1
-+#define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0
-+
-+#define BRCM_NUM_PCIE_OUT_WINS 0x4
-+#define BRCM_MAX_SCB 0x4
-+
-+#define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL
-+#define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL
-+
-+#define BURST_SIZE_128 0
-+#define BURST_SIZE_256 1
-+#define BURST_SIZE_512 2
-+
-+/* Offsets from PCIE_INTR2_CPU_BASE */
-+#define STATUS 0x0
-+#define SET 0x4
-+#define CLR 0x8
-+#define MASK_STATUS 0xc
-+#define MASK_SET 0x10
-+#define MASK_CLR 0x14
-+
-+#define PCIE_BUSNUM_SHIFT 20
-+#define PCIE_SLOT_SHIFT 15
-+#define PCIE_FUNC_SHIFT 12
-+
-+#if defined(__BIG_ENDIAN)
-+#define DATA_ENDIAN 2 /* PCIe->DDR inbound traffic */
-+#define MMIO_ENDIAN 2 /* CPU->PCIe outbound traffic */
-+#else
-+#define DATA_ENDIAN 0
-+#define MMIO_ENDIAN 0
-+#endif
-+
-+#define MDIO_PORT0 0x0
-+#define MDIO_DATA_MASK 0x7fffffff
-+#define MDIO_DATA_SHIFT 0x0
-+#define MDIO_PORT_MASK 0xf0000
-+#define MDIO_PORT_SHIFT 0x16
-+#define MDIO_REGAD_MASK 0xffff
-+#define MDIO_REGAD_SHIFT 0x0
-+#define MDIO_CMD_MASK 0xfff00000
-+#define MDIO_CMD_SHIFT 0x14
-+#define MDIO_CMD_READ 0x1
-+#define MDIO_CMD_WRITE 0x0
-+#define MDIO_DATA_DONE_MASK 0x80000000
-+#define MDIO_RD_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 1 : 0)
-+#define MDIO_WT_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 0 : 1)
-+#define SSC_REGS_ADDR 0x1100
-+#define SET_ADDR_OFFSET 0x1f
-+#define SSC_CNTL_OFFSET 0x2
-+#define SSC_CNTL_OVRD_EN_MASK 0x8000
-+#define SSC_CNTL_OVRD_EN_SHIFT 0xf
-+#define SSC_CNTL_OVRD_VAL_MASK 0x4000
-+#define SSC_CNTL_OVRD_VAL_SHIFT 0xe
-+#define SSC_STATUS_OFFSET 0x1
-+#define SSC_STATUS_SSC_MASK 0x400
-+#define SSC_STATUS_SSC_SHIFT 0xa
-+#define SSC_STATUS_PLL_LOCK_MASK 0x800
-+#define SSC_STATUS_PLL_LOCK_SHIFT 0xb
-+
-+#define IDX_ADDR(pcie) \
-+ ((pcie)->reg_offsets[EXT_CFG_INDEX])
-+#define DATA_ADDR(pcie) \
-+ ((pcie)->reg_offsets[EXT_CFG_DATA])
-+#define PCIE_RGR1_SW_INIT_1(pcie) \
-+ ((pcie)->reg_offsets[RGR1_SW_INIT_1])
-+
-+enum {
-+ RGR1_SW_INIT_1,
-+ EXT_CFG_INDEX,
-+ EXT_CFG_DATA,
-+};
-+
-+enum {
-+ RGR1_SW_INIT_1_INIT_MASK,
-+ RGR1_SW_INIT_1_INIT_SHIFT,
-+ RGR1_SW_INIT_1_PERST_MASK,
-+ RGR1_SW_INIT_1_PERST_SHIFT,
-+};
-+
-+enum pcie_type {
-+ BCM7425,
-+ BCM7435,
-+ GENERIC,
-+ BCM7278,
-+};
-+
-+struct brcm_window {
-+ dma_addr_t pcie_addr;
-+ phys_addr_t cpu_addr;
-+ dma_addr_t size;
-+};
-+
-+/* Internal PCIe Host Controller Information.*/
-+struct brcm_pcie {
-+ struct device *dev;
-+ void __iomem *base;
-+ struct list_head resources;
-+ int irq;
-+ struct clk *clk;
-+ struct pci_bus *root_bus;
-+ struct device_node *dn;
-+ int id;
-+ bool suspended;
-+ int num_out_wins;
-+ bool ssc;
-+ int gen;
-+ struct brcm_window out_wins[BRCM_NUM_PCIE_OUT_WINS];
-+ unsigned int rev;
-+ const int *reg_offsets;
-+ const int *reg_field_info;
-+ enum pcie_type type;
-+};
-+
-+struct pcie_cfg_data {
-+ const int *reg_field_info;
-+ const int *offsets;
-+ const enum pcie_type type;
-+};
-+
-+static const int pcie_reg_field_info[] = {
-+ [RGR1_SW_INIT_1_INIT_MASK] = 0x2,
-+ [RGR1_SW_INIT_1_INIT_SHIFT] = 0x1,
-+};
-+
-+static const int pcie_reg_field_info_bcm7278[] = {
-+ [RGR1_SW_INIT_1_INIT_MASK] = 0x1,
-+ [RGR1_SW_INIT_1_INIT_SHIFT] = 0x0,
-+};
-+
-+static const int pcie_offset_bcm7425[] = {
-+ [RGR1_SW_INIT_1] = 0x8010,
-+ [EXT_CFG_INDEX] = 0x8300,
-+ [EXT_CFG_DATA] = 0x8304,
-+};
-+
-+static const struct pcie_cfg_data bcm7425_cfg = {
-+ .reg_field_info = pcie_reg_field_info,
-+ .offsets = pcie_offset_bcm7425,
-+ .type = BCM7425,
-+};
-+
-+static const int pcie_offsets[] = {
-+ [RGR1_SW_INIT_1] = 0x9210,
-+ [EXT_CFG_INDEX] = 0x9000,
-+ [EXT_CFG_DATA] = 0x9004,
-+};
-+
-+static const struct pcie_cfg_data bcm7435_cfg = {
-+ .reg_field_info = pcie_reg_field_info,
-+ .offsets = pcie_offsets,
-+ .type = BCM7435,
-+};
-+
-+static const struct pcie_cfg_data generic_cfg = {
-+ .reg_field_info = pcie_reg_field_info,
-+ .offsets = pcie_offsets,
-+ .type = GENERIC,
-+};
-+
-+static const int pcie_offset_bcm7278[] = {
-+ [RGR1_SW_INIT_1] = 0xc010,
-+ [EXT_CFG_INDEX] = 0x9000,
-+ [EXT_CFG_DATA] = 0x9004,
-+};
-+
-+static const struct pcie_cfg_data bcm7278_cfg = {
-+ .reg_field_info = pcie_reg_field_info_bcm7278,
-+ .offsets = pcie_offset_bcm7278,
-+ .type = BCM7278,
-+};
-+
-+static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
-+ int where);
-+
-+static struct pci_ops brcm_pcie_ops = {
-+ .map_bus = brcm_pcie_map_conf,
-+ .read = pci_generic_config_read,
-+ .write = pci_generic_config_write,
-+};
-+
-+#if defined(CONFIG_MIPS)
-+/* Broadcom MIPs HW implicitly does the swapping if necessary */
-+#define bcm_readl(a) __raw_readl(a)
-+#define bcm_writel(d, a) __raw_writel(d, a)
-+#define bcm_readw(a) __raw_readw(a)
-+#define bcm_writew(d, a) __raw_writew(d, a)
-+#else
-+#define bcm_readl(a) readl(a)
-+#define bcm_writel(d, a) writel(d, a)
-+#define bcm_readw(a) readw(a)
-+#define bcm_writew(d, a) writew(d, a)
-+#endif
-+
-+/* These macros extract/insert fields to host controller's register set. */
-+#define RD_FLD(base, reg, field) \
-+ rd_fld(base + reg, reg##_##field##_MASK, reg##_##field##_SHIFT)
-+#define WR_FLD(base, reg, field, val) \
-+ wr_fld(base + reg, reg##_##field##_MASK, reg##_##field##_SHIFT, val)
-+#define WR_FLD_RB(base, reg, field, val) \
-+ wr_fld_rb(base + reg, reg##_##field##_MASK, reg##_##field##_SHIFT, val)
-+#define WR_FLD_WITH_OFFSET(base, off, reg, field, val) \
-+ wr_fld(base + reg + off, reg##_##field##_MASK, \
-+ reg##_##field##_SHIFT, val)
-+#define EXTRACT_FIELD(val, reg, field) \
-+ ((val & reg##_##field##_MASK) >> reg##_##field##_SHIFT)
-+#define INSERT_FIELD(val, reg, field, field_val) \
-+ ((val & ~reg##_##field##_MASK) | \
-+ (reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
-+
-+static phys_addr_t scb_size[BRCM_MAX_SCB];
-+static int num_memc;
-+static int num_pcie;
-+static DEFINE_MUTEX(brcm_pcie_lock);
-+
-+static u32 rd_fld(void __iomem *p, u32 mask, int shift)
-+{
-+ return (bcm_readl(p) & mask) >> shift;
-+}
-+
-+static void wr_fld(void __iomem *p, u32 mask, int shift, u32 val)
-+{
-+ u32 reg = bcm_readl(p);
-+
-+ reg = (reg & ~mask) | ((val << shift) & mask);
-+ bcm_writel(reg, p);
-+}
-+
-+static void wr_fld_rb(void __iomem *p, u32 mask, int shift, u32 val)
-+{
-+ wr_fld(p, mask, shift, val);
-+ (void)bcm_readl(p);
-+}
-+
-+static const char *link_speed_to_str(int s)
-+{
-+ switch (s) {
-+ case 1:
-+ return "2.5";
-+ case 2:
-+ return "5.0";
-+ case 3:
-+ return "8.0";
-+ default:
-+ break;
-+ }
-+ return "???";
-+}
-+
-+/*
-+ * The roundup_pow_of_two() from log2.h invokes
-+ * __roundup_pow_of_two(unsigned long), but we really need a
-+ * such a function to take a native u64 since unsigned long
-+ * is 32 bits on some configurations. So we provide this helper
-+ * function below.
-+ */
-+static u64 roundup_pow_of_two_64(u64 n)
-+{
-+ return 1ULL << fls64(n - 1);
-+}
-+
-+/*
-+ * This is to convert the size of the inbound "BAR" region to the
-+ * non-linear values of PCIE_X_MISC_RC_BAR[123]_CONFIG_LO.SIZE
-+ */
-+int encode_ibar_size(u64 size)
-+{
-+ int log2_in = ilog2(size);
-+
-+ if (log2_in >= 12 && log2_in <= 15)
-+ /* Covers 4KB to 32KB (inclusive) */
-+ return (log2_in - 12) + 0x1c;
-+ else if (log2_in >= 16 && log2_in <= 37)
-+ /* Covers 64KB to 32GB, (inclusive) */
-+ return log2_in - 15;
-+ /* Something is awry so disable */
-+ return 0;
-+}
-+
-+static u32 mdio_form_pkt(int port, int regad, int cmd)
-+{
-+ u32 pkt = 0;
-+
-+ pkt |= (port << MDIO_PORT_SHIFT) & MDIO_PORT_MASK;
-+ pkt |= (regad << MDIO_REGAD_SHIFT) & MDIO_REGAD_MASK;
-+ pkt |= (cmd << MDIO_CMD_SHIFT) & MDIO_CMD_MASK;
-+
-+ return pkt;
-+}
-+
-+/* negative return value indicates error */
-+static int mdio_read(void __iomem *base, u8 port, u8 regad)
-+{
-+ int tries;
-+ u32 data;
-+
-+ bcm_writel(mdio_form_pkt(port, regad, MDIO_CMD_READ),
-+ base + PCIE_RC_DL_MDIO_ADDR);
-+ bcm_readl(base + PCIE_RC_DL_MDIO_ADDR);
-+
-+ data = bcm_readl(base + PCIE_RC_DL_MDIO_RD_DATA);
-+ for (tries = 0; !MDIO_RD_DONE(data) && tries < 10; tries++) {
-+ udelay(10);
-+ data = bcm_readl(base + PCIE_RC_DL_MDIO_RD_DATA);
-+ }
-+
-+ return MDIO_RD_DONE(data)
-+ ? (data & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT
-+ : -EIO;
-+}
-+
-+/* negative return value indicates error */
-+static int mdio_write(void __iomem *base, u8 port, u8 regad, u16 wrdata)
-+{
-+ int tries;
-+ u32 data;
-+
-+ bcm_writel(mdio_form_pkt(port, regad, MDIO_CMD_WRITE),
-+ base + PCIE_RC_DL_MDIO_ADDR);
-+ bcm_readl(base + PCIE_RC_DL_MDIO_ADDR);
-+ bcm_writel(MDIO_DATA_DONE_MASK | wrdata,
-+ base + PCIE_RC_DL_MDIO_WR_DATA);
-+
-+ data = bcm_readl(base + PCIE_RC_DL_MDIO_WR_DATA);
-+ for (tries = 0; !MDIO_WT_DONE(data) && tries < 10; tries++) {
-+ udelay(10);
-+ data = bcm_readl(base + PCIE_RC_DL_MDIO_WR_DATA);
-+ }
-+
-+ return MDIO_WT_DONE(data) ? 0 : -EIO;
-+}
-+
-+/*
-+ * Configures device for Spread Spectrum Clocking (SSC) mode; a negative
-+ * return value indicates error.
-+ */
-+static int set_ssc(void __iomem *base)
-+{
-+ int tmp;
-+ u16 wrdata;
-+ int pll, ssc;
-+
-+ tmp = mdio_write(base, MDIO_PORT0, SET_ADDR_OFFSET, SSC_REGS_ADDR);
-+ if (tmp < 0)
-+ return tmp;
-+
-+ tmp = mdio_read(base, MDIO_PORT0, SSC_CNTL_OFFSET);
-+ if (tmp < 0)
-+ return tmp;
-+
-+ wrdata = INSERT_FIELD(tmp, SSC_CNTL_OVRD, EN, 1);
-+ wrdata = INSERT_FIELD(wrdata, SSC_CNTL_OVRD, VAL, 1);
-+ tmp = mdio_write(base, MDIO_PORT0, SSC_CNTL_OFFSET, wrdata);
-+ if (tmp < 0)
-+ return tmp;
-+
-+ usleep_range(1000, 2000);
-+ tmp = mdio_read(base, MDIO_PORT0, SSC_STATUS_OFFSET);
-+ if (tmp < 0)
-+ return tmp;
-+
-+ ssc = EXTRACT_FIELD(tmp, SSC_STATUS, SSC);
-+ pll = EXTRACT_FIELD(tmp, SSC_STATUS, PLL_LOCK);
-+
-+ return (ssc && pll) ? 0 : -EIO;
-+}
-+
-+/* Limits operation to a specific generation (1, 2, or 3) */
-+static void set_gen(void __iomem *base, int gen)
-+{
-+ u32 lnkcap = bcm_readl(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
-+ u16 lnkctl2 = bcm_readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
-+
-+ lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen;
-+ bcm_writel(lnkcap, base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
-+
-+ lnkctl2 = (lnkctl2 & ~0xf) | gen;
-+ bcm_writew(lnkctl2, base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
-+}
-+
-+static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie,
-+ unsigned int win, phys_addr_t cpu_addr,
-+ dma_addr_t pcie_addr, dma_addr_t size)
-+{
-+ void __iomem *base = pcie->base;
-+ phys_addr_t cpu_addr_mb, limit_addr_mb;
-+ u32 tmp;
-+
-+ /* Set the base of the pcie_addr window */
-+ bcm_writel(lower_32_bits(pcie_addr) + MMIO_ENDIAN,
-+ base + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + (win * 8));
-+ bcm_writel(upper_32_bits(pcie_addr),
-+ base + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + (win * 8));
-+
-+ cpu_addr_mb = cpu_addr >> 20;
-+ limit_addr_mb = (cpu_addr + size - 1) >> 20;
-+
-+ /* Write the addr base low register */
-+ WR_FLD_WITH_OFFSET(base, (win * 4),
-+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT,
-+ BASE, cpu_addr_mb);
-+ /* Write the addr limit low register */
-+ WR_FLD_WITH_OFFSET(base, (win * 4),
-+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT,
-+ LIMIT, limit_addr_mb);
-+
-+ if (pcie->type != BCM7435 && pcie->type != BCM7425) {
-+ /* Write the cpu addr high register */
-+ tmp = (u32)(cpu_addr_mb >>
-+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_NUM_MASK_BITS);
-+ WR_FLD_WITH_OFFSET(base, (win * 8),
-+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI,
-+ BASE, tmp);
-+ /* Write the cpu limit high register */
-+ tmp = (u32)(limit_addr_mb >>
-+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_NUM_MASK_BITS);
-+ WR_FLD_WITH_OFFSET(base, (win * 8),
-+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI,
-+ LIMIT, tmp);
-+ }
-+}
-+
-+/* Configuration space read/write support */
-+static int cfg_index(int busnr, int devfn, int reg)
-+{
-+ return ((PCI_SLOT(devfn) & 0x1f) << PCIE_SLOT_SHIFT)
-+ | ((PCI_FUNC(devfn) & 0x07) << PCIE_FUNC_SHIFT)
-+ | (busnr << PCIE_BUSNUM_SHIFT)
-+ | (reg & ~3);
-+}
-+
-+/* The controller is capable of serving in both RC and EP roles */
-+static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie)
-+{
-+ void __iomem *base = pcie->base;
-+ u32 val = bcm_readl(base + PCIE_MISC_PCIE_STATUS);
-+
-+ return !!EXTRACT_FIELD(val, PCIE_MISC_PCIE_STATUS, PCIE_PORT);
-+}
-+
-+static bool brcm_pcie_link_up(struct brcm_pcie *pcie)
-+{
-+ void __iomem *base = pcie->base;
-+ u32 val = bcm_readl(base + PCIE_MISC_PCIE_STATUS);
-+ u32 dla = EXTRACT_FIELD(val, PCIE_MISC_PCIE_STATUS, PCIE_DL_ACTIVE);
-+ u32 plu = EXTRACT_FIELD(val, PCIE_MISC_PCIE_STATUS, PCIE_PHYLINKUP);
-+
-+ return (dla && plu) ? true : false;
-+}
-+
-+static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
-+ int where)
-+{
-+ struct brcm_pcie *pcie = bus->sysdata;
-+ void __iomem *base = pcie->base;
-+ int idx;
-+
-+ /* Accesses to the RC go right to the RC registers if slot==0 */
-+ if (pci_is_root_bus(bus))
-+ return PCI_SLOT(devfn) ? NULL : base + where;
-+
-+ /* For devices, write to the config space index register */
-+ idx = cfg_index(bus->number, devfn, where);
-+ bcm_writel(idx, pcie->base + IDX_ADDR(pcie));
-+ return base + DATA_ADDR(pcie) + (where & 0x3);
-+}
-+
-+static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie,
-+ unsigned int val)
-+{
-+ unsigned int shift = pcie->reg_field_info[RGR1_SW_INIT_1_INIT_SHIFT];
-+ u32 mask = pcie->reg_field_info[RGR1_SW_INIT_1_INIT_MASK];
-+
-+ wr_fld_rb(pcie->base + PCIE_RGR1_SW_INIT_1(pcie), mask, shift, val);
-+}
-+
-+static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
-+ unsigned int val)
-+{
-+ if (pcie->type != BCM7278)
-+ wr_fld_rb(pcie->base + PCIE_RGR1_SW_INIT_1(pcie),
-+ PCIE_RGR1_SW_INIT_1_PERST_MASK,
-+ PCIE_RGR1_SW_INIT_1_PERST_SHIFT, val);
-+ else
-+ /* Assert = 0, de-assert = 1 on 7278 */
-+ WR_FLD_RB(pcie->base, PCIE_MISC_PCIE_CTRL, PCIE_PERSTB, !val);
-+}
-+
-+static int brcm_pcie_add_controller(struct brcm_pcie *pcie)
-+{
-+ int i, ret = 0;
-+
-+ mutex_lock(&brcm_pcie_lock);
-+ if (num_pcie > 0) {
-+ num_pcie++;
-+ goto done;
-+ }
-+
-+ /* Determine num_memc and their sizes */
-+ for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-+ u64 size = brcmstb_memory_memc_size(i);
-+
-+ if (size == (u64)-1) {
-+ dev_err(pcie->dev, "cannot get memc%d size\n", i);
-+ ret = -EINVAL;
-+ goto done;
-+ } else if (size) {
-+ scb_size[i] = roundup_pow_of_two_64(size);
-+ num_memc++;
-+ } else {
-+ break;
-+ }
-+ }
-+ if (!ret && num_memc == 0) {
-+ ret = -EINVAL;
-+ goto done;
-+ }
-+
-+ num_pcie++;
-+done:
-+ mutex_unlock(&brcm_pcie_lock);
-+ return ret;
-+}
-+
-+static void brcm_pcie_remove_controller(struct brcm_pcie *pcie)
-+{
-+ mutex_lock(&brcm_pcie_lock);
-+ if (--num_pcie == 0)
-+ num_memc = 0;
-+ mutex_unlock(&brcm_pcie_lock);
-+}
-+
-+static int brcm_pcie_parse_request_of_pci_ranges(struct brcm_pcie *pcie)
-+{
-+ struct resource_entry *win;
-+ int ret;
-+
-+ ret = devm_of_pci_get_host_bridge_resources(pcie->dev, 0, 0xff,
-+ &pcie->resources, NULL);
-+ if (ret) {
-+ dev_err(pcie->dev, "failed to get host resources\n");
-+ return ret;
-+ }
-+
-+ resource_list_for_each_entry(win, &pcie->resources) {
-+ struct resource *parent, *res = win->res;
-+ dma_addr_t offset = (dma_addr_t)win->offset;
-+
-+ if (resource_type(res) == IORESOURCE_IO) {
-+ parent = &ioport_resource;
-+ } else if (resource_type(res) == IORESOURCE_MEM) {
-+ if (pcie->num_out_wins >= BRCM_NUM_PCIE_OUT_WINS) {
-+ dev_err(pcie->dev, "too many outbound wins\n");
-+ return -EINVAL;
-+ }
-+ pcie->out_wins[pcie->num_out_wins].cpu_addr
-+ = (phys_addr_t)res->start;
-+ pcie->out_wins[pcie->num_out_wins].pcie_addr
-+ = (dma_addr_t)(res->start
-+ - (phys_addr_t)offset);
-+ pcie->out_wins[pcie->num_out_wins].size
-+ = (dma_addr_t)(res->end - res->start + 1);
-+ pcie->num_out_wins++;
-+ parent = &iomem_resource;
-+ } else {
-+ continue;
-+ }
-+
-+ ret = devm_request_resource(pcie->dev, parent, res);
-+ if (ret) {
-+ dev_err(pcie->dev, "failed to get res %pR\n", res);
-+ return ret;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int brcm_pcie_setup(struct brcm_pcie *pcie)
-+{
-+ void __iomem *base = pcie->base;
-+ unsigned int scb_size_val;
-+ u64 rc_bar2_offset, rc_bar2_size, total_mem_size = 0;
-+ u32 tmp, burst;
-+ int i, j, ret, limit;
-+ u16 nlw, cls, lnksta;
-+ bool ssc_good = false;
-+ struct device *dev = pcie->dev;
-+
-+ /* Reset the bridge */
-+ brcm_pcie_bridge_sw_init_set(pcie, 1);
-+
-+ /*
-+ * Ensure that the fundamental reset is asserted, except for 7278,
-+ * which fails if we do this.
-+ */
-+ if (pcie->type != BCM7278)
-+ brcm_pcie_perst_set(pcie, 1);
-+
-+ usleep_range(100, 200);
-+
-+ /* Take the bridge out of reset */
-+ brcm_pcie_bridge_sw_init_set(pcie, 0);
-+
-+ WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, SERDES_IDDQ, 0);
-+ /* Wait for SerDes to be stable */
-+ usleep_range(100, 200);
-+
-+ /* Grab the PCIe hw revision number */
-+ tmp = bcm_readl(base + PCIE_MISC_REVISION);
-+ pcie->rev = EXTRACT_FIELD(tmp, PCIE_MISC_REVISION, MAJMIN);
-+
-+ /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
-+ tmp = INSERT_FIELD(0, PCIE_MISC_MISC_CTRL, SCB_ACCESS_EN, 1);
-+ tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, CFG_READ_UR_MODE, 1);
-+ burst = (pcie->type == GENERIC || pcie->type == BCM7278)
-+ ? BURST_SIZE_512 : BURST_SIZE_256;
-+ tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, MAX_BURST_SIZE, burst);
-+ bcm_writel(tmp, base + PCIE_MISC_MISC_CTRL);
-+
-+ /*
-+ * Set up inbound memory view for the EP (called RC_BAR2,
-+ * not to be confused with the BARs that are advertised by
-+ * the EP).
-+ */
-+ for (i = 0; i < num_memc; i++)
-+ total_mem_size += scb_size[i];
-+
-+ /*
-+ * The PCIe host controller by design must set the inbound
-+ * viewport to be a contiguous arrangement of all of the
-+ * system's memory. In addition, its size mut be a power of
-+ * two. To further complicate matters, the viewport must
-+ * start on a pcie-address that is aligned on a multiple of its
-+ * size. If a portion of the viewport does not represent
-+ * system memory -- e.g. 3GB of memory requires a 4GB viewport
-+ * -- we can map the outbound memory in or after 3GB and even
-+ * though the viewport will overlap the outbound memory the
-+ * controller will know to send outbound memory downstream and
-+ * everything else upstream.
-+ */
-+ rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
-+
-+ /*
-+ * Set simple configuration based on memory sizes
-+ * only. We always start the viewport at address 0.
-+ */
-+ rc_bar2_offset = 0;
-+
-+ tmp = lower_32_bits(rc_bar2_offset);
-+ tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
-+ encode_ibar_size(rc_bar2_size));
-+ bcm_writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO);
-+ bcm_writel(upper_32_bits(rc_bar2_offset),
-+ base + PCIE_MISC_RC_BAR2_CONFIG_HI);
-+
-+ scb_size_val = scb_size[0]
-+ ? ilog2(scb_size[0]) - 15 : 0xf; /* 0xf is 1GB */
-+ WR_FLD(base, PCIE_MISC_MISC_CTRL, SCB0_SIZE, scb_size_val);
-+
-+ if (num_memc > 1) {
-+ scb_size_val = scb_size[1]
-+ ? ilog2(scb_size[1]) - 15 : 0xf; /* 0xf is 1GB */
-+ WR_FLD(base, PCIE_MISC_MISC_CTRL, SCB1_SIZE, scb_size_val);
-+ }
-+
-+ if (num_memc > 2) {
-+ scb_size_val = scb_size[2]
-+ ? ilog2(scb_size[2]) - 15 : 0xf; /* 0xf is 1GB */
-+ WR_FLD(base, PCIE_MISC_MISC_CTRL, SCB2_SIZE, scb_size_val);
-+ }
-+
-+ /* disable the PCIe->GISB memory window (RC_BAR1) */
-+ WR_FLD(base, PCIE_MISC_RC_BAR1_CONFIG_LO, SIZE, 0);
-+
-+ /* disable the PCIe->SCB memory window (RC_BAR3) */
-+ WR_FLD(base, PCIE_MISC_RC_BAR3_CONFIG_LO, SIZE, 0);
-+
-+ if (!pcie->suspended) {
-+ /* clear any interrupts we find on boot */
-+ bcm_writel(0xffffffff, base + PCIE_INTR2_CPU_BASE + CLR);
-+ (void)bcm_readl(base + PCIE_INTR2_CPU_BASE + CLR);
-+ }
-+
-+ /* Mask all interrupts since we are not handling any yet */
-+ bcm_writel(0xffffffff, base + PCIE_INTR2_CPU_BASE + MASK_SET);
-+ (void)bcm_readl(base + PCIE_INTR2_CPU_BASE + MASK_SET);
-+
-+ if (pcie->gen)
-+ set_gen(base, pcie->gen);
-+
-+ /* Unassert the fundamental reset */
-+ brcm_pcie_perst_set(pcie, 0);
-+
-+ /*
-+ * Give the RC/EP time to wake up, before trying to configure RC.
-+ * Intermittently check status for link-up, up to a total of 100ms
-+ * when we don't know if the device is there, and up to 1000ms if
-+ * we do know the device is there.
-+ */
-+ limit = pcie->suspended ? 1000 : 100;
-+ for (i = 1, j = 0; j < limit && !brcm_pcie_link_up(pcie);
-+ j += i, i = i * 2)
-+ msleep(i + j > limit ? limit - j : i);
-+
-+ if (!brcm_pcie_link_up(pcie)) {
-+ dev_info(dev, "link down\n");
-+ return -ENODEV;
-+ }
-+
-+ if (!brcm_pcie_rc_mode(pcie)) {
-+ dev_err(dev, "PCIe misconfigured; is in EP mode\n");
-+ return -EINVAL;
-+ }
-+
-+ for (i = 0; i < pcie->num_out_wins; i++)
-+ brcm_pcie_set_outbound_win(pcie, i, pcie->out_wins[i].cpu_addr,
-+ pcie->out_wins[i].pcie_addr,
-+ pcie->out_wins[i].size);
-+
-+ /*
-+ * For config space accesses on the RC, show the right class for
-+ * a PCIe-PCIe bridge (the default setting is to be EP mode).
-+ */
-+ WR_FLD_RB(base, PCIE_RC_CFG_PRIV1_ID_VAL3, CLASS_CODE, 0x060400);
-+
-+ if (pcie->ssc) {
-+ ret = set_ssc(base);
-+ if (ret == 0)
-+ ssc_good = true;
-+ else
-+ dev_err(dev, "failed attempt to enter ssc mode\n");
-+ }
-+
-+ lnksta = bcm_readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA);
-+ cls = lnksta & PCI_EXP_LNKSTA_CLS;
-+ nlw = (lnksta & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
-+ dev_info(dev, "link up, %s Gbps x%u %s\n", link_speed_to_str(cls),
-+ nlw, ssc_good ? "(SSC)" : "(!SSC)");
-+
-+ /* PCIe->SCB endian mode for BAR */
-+ /* field ENDIAN_MODE_BAR2 = DATA_ENDIAN */
-+ WR_FLD_RB(base, PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1,
-+ ENDIAN_MODE_BAR2, DATA_ENDIAN);
-+
-+ /*
-+ * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1
-+ * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1.
-+ */
-+ WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, CLKREQ_DEBUG_ENABLE, 1);
-+
-+ return 0;
-+}
-+
-+/* L23 is a low-power PCIe link state */
-+static void enter_l23(struct brcm_pcie *pcie)
-+{
-+ void __iomem *base = pcie->base;
-+ int tries, l23;
-+
-+ /* assert request for L23 */
-+ WR_FLD_RB(base, PCIE_MISC_PCIE_CTRL, PCIE_L23_REQUEST, 1);
-+ /* poll L23 status */
-+ for (tries = 0, l23 = 0; tries < 1000 && !l23; tries++)
-+ l23 = RD_FLD(base, PCIE_MISC_PCIE_STATUS, PCIE_LINK_IN_L23);
-+ if (!l23)
-+ dev_err(pcie->dev, "failed to enter L23\n");
-+}
-+
-+static void turn_off(struct brcm_pcie *pcie)
-+{
-+ void __iomem *base = pcie->base;
-+
-+ if (brcm_pcie_link_up(pcie))
-+ enter_l23(pcie);
-+ /* Assert fundamental reset */
-+ brcm_pcie_perst_set(pcie, 1);
-+ /* Deassert request for L23 in case it was asserted */
-+ WR_FLD_RB(base, PCIE_MISC_PCIE_CTRL, PCIE_L23_REQUEST, 0);
-+ /* Turn off SerDes */
-+ WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, SERDES_IDDQ, 1);
-+ /* Shutdown PCIe bridge */
-+ brcm_pcie_bridge_sw_init_set(pcie, 1);
-+}
-+
-+static int brcm_pcie_suspend(struct device *dev)
-+{
-+ struct brcm_pcie *pcie = dev_get_drvdata(dev);
-+
-+ turn_off(pcie);
-+ clk_disable_unprepare(pcie->clk);
-+ pcie->suspended = true;
-+
-+ return 0;
-+}
-+
-+static int brcm_pcie_resume(struct device *dev)
-+{
-+ struct brcm_pcie *pcie = dev_get_drvdata(dev);
-+ void __iomem *base;
-+ int ret;
-+
-+ base = pcie->base;
-+ clk_prepare_enable(pcie->clk);
-+
-+ /* Take bridge out of reset so we can access the SerDes reg */
-+ brcm_pcie_bridge_sw_init_set(pcie, 0);
-+
-+ /* Turn on SerDes */
-+ WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, SERDES_IDDQ, 0);
-+ /* Wait for SerDes to be stable */
-+ usleep_range(100, 200);
-+
-+ ret = brcm_pcie_setup(pcie);
-+ if (ret)
-+ return ret;
-+
-+ pcie->suspended = false;
-+
-+ return 0;
-+}
-+
-+static void _brcm_pcie_remove(struct brcm_pcie *pcie)
-+{
-+ turn_off(pcie);
-+ clk_disable_unprepare(pcie->clk);
-+ clk_put(pcie->clk);
-+ brcm_pcie_remove_controller(pcie);
-+}
-+
-+static int brcm_pcie_remove(struct platform_device *pdev)
-+{
-+ struct brcm_pcie *pcie = platform_get_drvdata(pdev);
-+
-+ pci_stop_root_bus(pcie->root_bus);
-+ pci_remove_root_bus(pcie->root_bus);
-+ _brcm_pcie_remove(pcie);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id brcm_pcie_match[] = {
-+ { .compatible = "brcm,bcm7425-pcie", .data = &bcm7425_cfg },
-+ { .compatible = "brcm,bcm7435-pcie", .data = &bcm7435_cfg },
-+ { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg },
-+ { .compatible = "brcm,bcm7445-pcie", .data = &generic_cfg },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, brcm_pcie_match);
-+
-+static int brcm_pcie_probe(struct platform_device *pdev)
-+{
-+ struct device_node *dn = pdev->dev.of_node;
-+ const struct of_device_id *of_id;
-+ const struct pcie_cfg_data *data;
-+ int ret;
-+ struct brcm_pcie *pcie;
-+ struct resource *res;
-+ void __iomem *base;
-+ u32 tmp;
-+ struct pci_host_bridge *bridge;
-+ struct pci_bus *child;
-+
-+ bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
-+ if (!bridge)
-+ return -ENOMEM;
-+
-+ pcie = pci_host_bridge_priv(bridge);
-+ INIT_LIST_HEAD(&pcie->resources);
-+
-+ of_id = of_match_node(brcm_pcie_match, dn);
-+ if (!of_id) {
-+ dev_err(&pdev->dev, "failed to look up compatible string\n");
-+ return -EINVAL;
-+ }
-+
-+ if (of_property_read_u32(dn, "dma-ranges", &tmp) == 0) {
-+ dev_err(&pdev->dev, "cannot yet handle dma-ranges\n");
-+ return -EINVAL;
-+ }
-+
-+ data = of_id->data;
-+ pcie->reg_offsets = data->offsets;
-+ pcie->reg_field_info = data->reg_field_info;
-+ pcie->type = data->type;
-+ pcie->dn = dn;
-+ pcie->dev = &pdev->dev;
-+
-+ /* We use the domain number as our controller number */
-+ pcie->id = of_get_pci_domain_nr(dn);
-+ if (pcie->id < 0)
-+ return pcie->id;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!res)
-+ return -EINVAL;
-+
-+ base = devm_ioremap_resource(&pdev->dev, res);
-+ if (IS_ERR(base))
-+ return PTR_ERR(base);
-+
-+ pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
-+ if (IS_ERR(pcie->clk)) {
-+ dev_err(&pdev->dev, "could not get clock\n");
-+ pcie->clk = NULL;
-+ }
-+ pcie->base = base;
-+
-+ ret = of_pci_get_max_link_speed(dn);
-+ pcie->gen = (ret < 0) ? 0 : ret;
-+
-+ pcie->ssc = of_property_read_bool(dn, "brcm,enable-ssc");
-+
-+ ret = irq_of_parse_and_map(pdev->dev.of_node, 0);
-+ if (ret == 0)
-+ /* keep going, as we don't use this intr yet */
-+ dev_warn(pcie->dev, "cannot get PCIe interrupt\n");
-+ else
-+ pcie->irq = ret;
-+
-+ ret = brcm_pcie_parse_request_of_pci_ranges(pcie);
-+ if (ret)
-+ return ret;
-+
-+ ret = clk_prepare_enable(pcie->clk);
-+ if (ret) {
-+ dev_err(&pdev->dev, "could not enable clock\n");
-+ return ret;
-+ }
-+
-+ ret = brcm_pcie_add_controller(pcie);
-+ if (ret)
-+ return ret;
-+
-+ ret = brcm_pcie_setup(pcie);
-+ if (ret)
-+ goto fail;
-+
-+ list_splice_init(&pcie->resources, &bridge->windows);
-+ bridge->dev.parent = &pdev->dev;
-+ bridge->busnr = 0;
-+ bridge->ops = &brcm_pcie_ops;
-+ bridge->sysdata = pcie;
-+ bridge->map_irq = of_irq_parse_and_map_pci;
-+ bridge->swizzle_irq = pci_common_swizzle;
-+
-+ ret = pci_scan_root_bus_bridge(bridge);
-+ if (ret < 0) {
-+ dev_err(pcie->dev, "Scanning root bridge failed\n");
-+ goto fail;
-+ }
-+
-+ pci_assign_unassigned_bus_resources(bridge->bus);
-+ list_for_each_entry(child, &bridge->bus->children, node)
-+ pcie_bus_configure_settings(child);
-+ pci_bus_add_devices(bridge->bus);
-+ platform_set_drvdata(pdev, pcie);
-+ pcie->root_bus = bridge->bus;
-+
-+ return 0;
-+
-+fail:
-+ _brcm_pcie_remove(pcie);
-+ return ret;
-+}
-+
-+static const struct dev_pm_ops brcm_pcie_pm_ops = {
-+ .suspend_noirq = brcm_pcie_suspend,
-+ .resume_noirq = brcm_pcie_resume,
-+};
-+
-+static struct platform_driver brcm_pcie_driver = {
-+ .probe = brcm_pcie_probe,
-+ .remove = brcm_pcie_remove,
-+ .driver = {
-+ .name = "brcm-pcie",
-+ .owner = THIS_MODULE,
-+ .of_match_table = brcm_pcie_match,
-+ .pm = &brcm_pcie_pm_ops,
-+ },
-+};
-+
-+module_platform_driver(brcm_pcie_driver);
-+
-+MODULE_LICENSE("GPL v2");
-+MODULE_DESCRIPTION("Broadcom STB PCIe RC driver");
-+MODULE_AUTHOR("Broadcom");
---- /dev/null
-+++ b/include/soc/brcmstb/memory_api.h
-@@ -0,0 +1,25 @@
-+#ifndef __MEMORY_API_H
-+#define __MEMORY_API_H
-+
-+/*
-+ * Bus Interface Unit control register setup, must happen early during boot,
-+ * before SMP is brought up, called by machine entry point.
-+ */
-+void brcmstb_biuctrl_init(void);
-+
-+#ifdef CONFIG_SOC_BRCMSTB
-+int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa);
-+u64 brcmstb_memory_memc_size(int memc);
-+#else
-+static inline int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa)
-+{
-+ return -EINVAL;
-+}
-+
-+static inline u64 brcmstb_memory_memc_size(int memc)
-+{
-+ return -1;
-+}
-+#endif
-+
-+#endif /* __MEMORY_API_H */
--- /dev/null
+From cd3af4fa73ab25353f0865ebe8e0d2af1fd2a50b Mon Sep 17 00:00:00 2001
+Date: Tue, 19 Feb 2019 22:06:59 +0000
+Subject: [PATCH] PCI: brcmstb: Add MSI capability
+
+This commit adds MSI to the Broadcom STB PCIe host controller. It does
+not add MSIX since that functionality is not in the HW. The MSI
+controller is physically located within the PCIe block, however, there
+is no reason why the MSI controller could not be moved elsewhere in
+the future.
+
+Since the internal Brcmstb MSI controller is intertwined with the PCIe
+controller, it is not its own platform device but rather part of the
+PCIe platform device.
+
+---
+ drivers/pci/controller/pcie-brcmstb.c | 374 ++++++++++++++++++++++++--
+ 1 file changed, 353 insertions(+), 21 deletions(-)
+
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -1,6 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /* Copyright (C) 2009 - 2017 Broadcom */
+
++#include <linux/bitops.h>
+ #include <linux/clk.h>
+ #include <linux/compiler.h>
+ #include <linux/delay.h>
+@@ -9,11 +10,13 @@
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+ #include <linux/ioport.h>
++#include <linux/irqchip/chained_irq.h>
+ #include <linux/irqdomain.h>
+ #include <linux/kernel.h>
+ #include <linux/list.h>
+ #include <linux/log2.h>
+ #include <linux/module.h>
++#include <linux/msi.h>
+ #include <linux/of_address.h>
+ #include <linux/of_irq.h>
+ #include <linux/of_pci.h>
+@@ -47,6 +50,9 @@
+ #define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034
+ #define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038
+ #define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
++#define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044
++#define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048
++#define PCIE_MISC_MSI_DATA_CONFIG 0x404c
+ #define PCIE_MISC_PCIE_CTRL 0x4064
+ #define PCIE_MISC_PCIE_STATUS 0x4068
+ #define PCIE_MISC_REVISION 0x406c
+@@ -55,6 +61,7 @@
+ #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084
+ #define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204
+ #define PCIE_INTR2_CPU_BASE 0x4300
++#define PCIE_MSI_INTR2_BASE 0x4500
+
+ /*
+ * Broadcom Settop Box PCIe Register Field shift and mask info. The
+@@ -115,6 +122,8 @@
+
+ #define BRCM_NUM_PCIE_OUT_WINS 0x4
+ #define BRCM_MAX_SCB 0x4
++#define BRCM_INT_PCI_MSI_NR 32
++#define BRCM_PCIE_HW_REV_33 0x0303
+
+ #define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL
+ #define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL
+@@ -203,6 +212,33 @@ struct brcm_window {
+ dma_addr_t size;
+ };
+
++struct brcm_msi {
++ struct device *dev;
++ void __iomem *base;
++ struct device_node *dn;
++ struct irq_domain *msi_domain;
++ struct irq_domain *inner_domain;
++ struct mutex lock; /* guards the alloc/free operations */
++ u64 target_addr;
++ int irq;
++
++ /* intr_base is the base pointer for interrupt status/set/clr regs */
++ void __iomem *intr_base;
++
++ /* intr_legacy_mask indicates how many bits are MSI interrupts */
++ u32 intr_legacy_mask;
++
++ /*
++ * intr_legacy_offset indicates bit position of MSI_01. It is
++ * to map the register bit position to a hwirq that starts at 0.
++ */
++ u32 intr_legacy_offset;
++
++ /* used indicates which MSI interrupts have been alloc'd */
++ unsigned long used;
++ unsigned int rev;
++};
++
+ /* Internal PCIe Host Controller Information.*/
+ struct brcm_pcie {
+ struct device *dev;
+@@ -217,7 +253,10 @@ struct brcm_pcie {
+ int num_out_wins;
+ bool ssc;
+ int gen;
++ u64 msi_target_addr;
+ struct brcm_window out_wins[BRCM_NUM_PCIE_OUT_WINS];
++ struct brcm_msi *msi;
++ bool msi_internal;
+ unsigned int rev;
+ const int *reg_offsets;
+ const int *reg_field_info;
+@@ -225,9 +264,9 @@ struct brcm_pcie {
+ };
+
+ struct pcie_cfg_data {
+- const int *reg_field_info;
+- const int *offsets;
+- const enum pcie_type type;
++ const int *reg_field_info;
++ const int *offsets;
++ const enum pcie_type type;
+ };
+
+ static const int pcie_reg_field_info[] = {
+@@ -828,6 +867,267 @@ static void brcm_pcie_set_outbound_win(s
+ }
+ }
+
++static struct irq_chip brcm_msi_irq_chip = {
++ .name = "Brcm_MSI",
++ .irq_mask = pci_msi_mask_irq,
++ .irq_unmask = pci_msi_unmask_irq,
++};
++
++static struct msi_domain_info brcm_msi_domain_info = {
++ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
++ MSI_FLAG_PCI_MSIX),
++ .chip = &brcm_msi_irq_chip,
++};
++
++static void brcm_pcie_msi_isr(struct irq_desc *desc)
++{
++ struct irq_chip *chip = irq_desc_get_chip(desc);
++ struct brcm_msi *msi;
++ unsigned long status, virq;
++ u32 mask, bit, hwirq;
++ struct device *dev;
++
++ chained_irq_enter(chip, desc);
++ msi = irq_desc_get_handler_data(desc);
++ mask = msi->intr_legacy_mask;
++ dev = msi->dev;
++
++ while ((status = bcm_readl(msi->intr_base + STATUS) & mask)) {
++ for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) {
++ /* clear the interrupt */
++ bcm_writel(1 << bit, msi->intr_base + CLR);
++
++ /* Account for legacy interrupt offset */
++ hwirq = bit - msi->intr_legacy_offset;
++
++ virq = irq_find_mapping(msi->inner_domain, hwirq);
++ if (virq) {
++ if (msi->used & (1 << hwirq))
++ generic_handle_irq(virq);
++ else
++ dev_info(dev, "unhandled MSI %d\n",
++ hwirq);
++ } else {
++ /* Unknown MSI, just clear it */
++ dev_dbg(dev, "unexpected MSI\n");
++ }
++ }
++ }
++ chained_irq_exit(chip, desc);
++}
++
++static void brcm_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
++{
++ struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
++ u32 temp;
++
++ msg->address_lo = lower_32_bits(msi->target_addr);
++ msg->address_hi = upper_32_bits(msi->target_addr);
++ temp = bcm_readl(msi->base + PCIE_MISC_MSI_DATA_CONFIG);
++ msg->data = ((temp >> 16) & (temp & 0xffff)) | data->hwirq;
++}
++
++static int brcm_msi_set_affinity(struct irq_data *irq_data,
++ const struct cpumask *mask, bool force)
++{
++ return -EINVAL;
++}
++
++static struct irq_chip brcm_msi_bottom_irq_chip = {
++ .name = "Brcm_MSI",
++ .irq_compose_msi_msg = brcm_compose_msi_msg,
++ .irq_set_affinity = brcm_msi_set_affinity,
++};
++
++static int brcm_msi_alloc(struct brcm_msi *msi)
++{
++ int bit, hwirq;
++
++ mutex_lock(&msi->lock);
++ bit = ~msi->used ? ffz(msi->used) : -1;
++
++ if (bit >= 0 && bit < BRCM_INT_PCI_MSI_NR) {
++ msi->used |= (1 << bit);
++ hwirq = bit - msi->intr_legacy_offset;
++ } else {
++ hwirq = -ENOSPC;
++ }
++
++ mutex_unlock(&msi->lock);
++ return hwirq;
++}
++
++static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq)
++{
++ mutex_lock(&msi->lock);
++ msi->used &= ~(1 << (hwirq + msi->intr_legacy_offset));
++ mutex_unlock(&msi->lock);
++}
++
++static int brcm_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
++ unsigned int nr_irqs, void *args)
++{
++ struct brcm_msi *msi = domain->host_data;
++ int hwirq;
++
++ hwirq = brcm_msi_alloc(msi);
++
++ if (hwirq < 0)
++ return hwirq;
++
++ irq_domain_set_info(domain, virq, (irq_hw_number_t)hwirq,
++ &brcm_msi_bottom_irq_chip, domain->host_data,
++ handle_simple_irq, NULL, NULL);
++ return 0;
++}
++
++static void brcm_irq_domain_free(struct irq_domain *domain,
++ unsigned int virq, unsigned int nr_irqs)
++{
++ struct irq_data *d = irq_domain_get_irq_data(domain, virq);
++ struct brcm_msi *msi = irq_data_get_irq_chip_data(d);
++
++ brcm_msi_free(msi, d->hwirq);
++}
++
++static void brcm_msi_set_regs(struct brcm_msi *msi)
++{
++ u32 data_val, msi_lo, msi_hi;
++
++ if (msi->rev >= BRCM_PCIE_HW_REV_33) {
++ /*
++ * ffe0 -- least sig 5 bits are 0 indicating 32 msgs
++ * 6540 -- this is our arbitrary unique data value
++ */
++ data_val = 0xffe06540;
++ } else {
++ /*
++ * fff8 -- least sig 3 bits are 0 indicating 8 msgs
++ * 6540 -- this is our arbitrary unique data value
++ */
++ data_val = 0xfff86540;
++ }
++
++ /*
++ * Make sure we are not masking MSIs. Note that MSIs can be masked,
++ * but that occurs on the PCIe EP device
++ */
++ bcm_writel(0xffffffff & msi->intr_legacy_mask,
++ msi->intr_base + MASK_CLR);
++
++ msi_lo = lower_32_bits(msi->target_addr);
++ msi_hi = upper_32_bits(msi->target_addr);
++ /*
++ * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI
++ * enable, which we set to 1.
++ */
++ bcm_writel(msi_lo | 1, msi->base + PCIE_MISC_MSI_BAR_CONFIG_LO);
++ bcm_writel(msi_hi, msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI);
++ bcm_writel(data_val, msi->base + PCIE_MISC_MSI_DATA_CONFIG);
++}
++
++static const struct irq_domain_ops msi_domain_ops = {
++ .alloc = brcm_irq_domain_alloc,
++ .free = brcm_irq_domain_free,
++};
++
++static int brcm_allocate_domains(struct brcm_msi *msi)
++{
++ struct fwnode_handle *fwnode = of_node_to_fwnode(msi->dn);
++ struct device *dev = msi->dev;
++
++ msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR,
++ &msi_domain_ops, msi);
++ if (!msi->inner_domain) {
++ dev_err(dev, "failed to create IRQ domain\n");
++ return -ENOMEM;
++ }
++
++ msi->msi_domain = pci_msi_create_irq_domain(fwnode,
++ &brcm_msi_domain_info,
++ msi->inner_domain);
++ if (!msi->msi_domain) {
++ dev_err(dev, "failed to create MSI domain\n");
++ irq_domain_remove(msi->inner_domain);
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++static void brcm_free_domains(struct brcm_msi *msi)
++{
++ irq_domain_remove(msi->msi_domain);
++ irq_domain_remove(msi->inner_domain);
++}
++
++static void brcm_msi_remove(struct brcm_pcie *pcie)
++{
++ struct brcm_msi *msi = pcie->msi;
++
++ if (!msi)
++ return;
++ irq_set_chained_handler(msi->irq, NULL);
++ irq_set_handler_data(msi->irq, NULL);
++ brcm_free_domains(msi);
++}
++
++static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)
++{
++ struct brcm_msi *msi;
++ int irq, ret;
++ struct device *dev = pcie->dev;
++
++ irq = irq_of_parse_and_map(dev->of_node, 1);
++ if (irq <= 0) {
++ dev_err(dev, "cannot map msi intr\n");
++ return -ENODEV;
++ }
++
++ msi = devm_kzalloc(dev, sizeof(struct brcm_msi), GFP_KERNEL);
++ if (!msi)
++ return -ENOMEM;
++
++ msi->dev = dev;
++ msi->base = pcie->base;
++ msi->rev = pcie->rev;
++ msi->dn = pcie->dn;
++ msi->target_addr = pcie->msi_target_addr;
++ msi->irq = irq;
++
++ ret = brcm_allocate_domains(msi);
++ if (ret)
++ return ret;
++
++ irq_set_chained_handler_and_data(msi->irq, brcm_pcie_msi_isr, msi);
++
++ if (msi->rev >= BRCM_PCIE_HW_REV_33) {
++ msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE;
++ /*
++ * This version of PCIe hw has only 32 intr bits
++ * starting at bit position 0.
++ */
++ msi->intr_legacy_mask = 0xffffffff;
++ msi->intr_legacy_offset = 0x0;
++ msi->used = 0x0;
++
++ } else {
++ msi->intr_base = msi->base + PCIE_INTR2_CPU_BASE;
++ /*
++ * This version of PCIe hw has only 8 intr bits starting
++ * at bit position 24.
++ */
++ msi->intr_legacy_mask = 0xff000000;
++ msi->intr_legacy_offset = 24;
++ msi->used = 0x00ffffff;
++ }
++
++ brcm_msi_set_regs(msi);
++ pcie->msi = msi;
++
++ return 0;
++}
++
+ /* Configuration space read/write support */
+ static int cfg_index(int busnr, int devfn, int reg)
+ {
+@@ -1072,6 +1372,7 @@ static int brcm_pcie_setup(struct brcm_p
+ u16 nlw, cls, lnksta;
+ bool ssc_good = false;
+ struct device *dev = pcie->dev;
++ u64 msi_target_addr;
+
+ /* Reset the bridge */
+ brcm_pcie_bridge_sw_init_set(pcie, 1);
+@@ -1116,27 +1417,24 @@ static int brcm_pcie_setup(struct brcm_p
+ * The PCIe host controller by design must set the inbound
+ * viewport to be a contiguous arrangement of all of the
+ * system's memory. In addition, its size mut be a power of
+- * two. To further complicate matters, the viewport must
+- * start on a pcie-address that is aligned on a multiple of its
+- * size. If a portion of the viewport does not represent
+- * system memory -- e.g. 3GB of memory requires a 4GB viewport
+- * -- we can map the outbound memory in or after 3GB and even
+- * though the viewport will overlap the outbound memory the
+- * controller will know to send outbound memory downstream and
+- * everything else upstream.
++ * two. Further, the MSI target address must NOT be placed
++ * inside this region, as the decoding logic will consider its
++ * address to be inbound memory traffic. To further
++ * complicate matters, the viewport must start on a
++ * pcie-address that is aligned on a multiple of its size.
++ * If a portion of the viewport does not represent system
++ * memory -- e.g. 3GB of memory requires a 4GB viewport --
++ * we can map the outbound memory in or after 3GB and even
++ * though the viewport will overlap the outbound memory
++ * the controller will know to send outbound memory downstream
++ * and everything else upstream.
+ */
+ rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
+
+- /*
+- * Set simple configuration based on memory sizes
+- * only. We always start the viewport at address 0.
+- */
+- rc_bar2_offset = 0;
+-
+ if (dma_ranges) {
+ /*
+ * The best-case scenario is to place the inbound
+- * region in the first 4GB of pci-space, as some
++ * region in the first 4GB of pcie-space, as some
+ * legacy devices can only address 32bits.
+ * We would also like to put the MSI under 4GB
+ * as well, since some devices require a 32bit
+@@ -1145,6 +1443,14 @@ static int brcm_pcie_setup(struct brcm_p
+ if (total_mem_size <= 0xc0000000ULL &&
+ rc_bar2_size <= 0x100000000ULL) {
+ rc_bar2_offset = 0;
++ /* If the viewport is less then 4GB we can fit
++ * the MSI target address under 4GB. Otherwise
++ * put it right below 64GB.
++ */
++ msi_target_addr =
++ (rc_bar2_size == 0x100000000ULL)
++ ? BRCM_MSI_TARGET_ADDR_GT_4GB
++ : BRCM_MSI_TARGET_ADDR_LT_4GB;
+ } else {
+ /*
+ * The system memory is 4GB or larger so we
+@@ -1154,8 +1460,12 @@ static int brcm_pcie_setup(struct brcm_p
+ * start it at the 1x multiple of its size
+ */
+ rc_bar2_offset = rc_bar2_size;
+- }
+
++ /* Since we are starting the viewport at 4GB or
++ * higher, put the MSI target address below 4GB
++ */
++ msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
++ }
+ } else {
+ /*
+ * Set simple configuration based on memory sizes
+@@ -1163,7 +1473,12 @@ static int brcm_pcie_setup(struct brcm_p
+ * and set the MSI target address accordingly.
+ */
+ rc_bar2_offset = 0;
++
++ msi_target_addr = (rc_bar2_size >= 0x100000000ULL)
++ ? BRCM_MSI_TARGET_ADDR_GT_4GB
++ : BRCM_MSI_TARGET_ADDR_LT_4GB;
+ }
++ pcie->msi_target_addr = msi_target_addr;
+
+ tmp = lower_32_bits(rc_bar2_offset);
+ tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
+@@ -1333,6 +1648,9 @@ static int brcm_pcie_resume(struct devic
+ if (ret)
+ return ret;
+
++ if (pcie->msi && pcie->msi_internal)
++ brcm_msi_set_regs(pcie->msi);
++
+ pcie->suspended = false;
+
+ return 0;
+@@ -1340,6 +1658,7 @@ static int brcm_pcie_resume(struct devic
+
+ static void _brcm_pcie_remove(struct brcm_pcie *pcie)
+ {
++ brcm_msi_remove(pcie);
+ turn_off(pcie);
+ clk_disable_unprepare(pcie->clk);
+ clk_put(pcie->clk);
+@@ -1368,7 +1687,7 @@ MODULE_DEVICE_TABLE(of, brcm_pcie_match)
+
+ static int brcm_pcie_probe(struct platform_device *pdev)
+ {
+- struct device_node *dn = pdev->dev.of_node;
++ struct device_node *dn = pdev->dev.of_node, *msi_dn;
+ const struct of_device_id *of_id;
+ const struct pcie_cfg_data *data;
+ int ret;
+@@ -1448,6 +1767,20 @@ static int brcm_pcie_probe(struct platfo
+ if (ret)
+ goto fail;
+
++ msi_dn = of_parse_phandle(pcie->dn, "msi-parent", 0);
++ /* Use the internal MSI if no msi-parent property */
++ if (!msi_dn)
++ msi_dn = pcie->dn;
++
++ if (pci_msi_enabled() && msi_dn == pcie->dn) {
++ ret = brcm_pcie_enable_msi(pcie);
++ if (ret)
++ dev_err(pcie->dev,
++ "probe of internal MSI failed: %d)", ret);
++ else
++ pcie->msi_internal = true;
++ }
++
+ list_splice_init(&pcie->resources, &bridge->windows);
+ bridge->dev.parent = &pdev->dev;
+ bridge->busnr = 0;
+@@ -1470,7 +1803,6 @@ static int brcm_pcie_probe(struct platfo
+ pcie->root_bus = bridge->bus;
+
+ return 0;
+-
+ fail:
+ _brcm_pcie_remove(pcie);
+ return ret;
+++ /dev/null
-From d3cc1c713b9436a7dc72788caa1d8de63ac3a01b Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Feb 2019 22:06:59 +0000
-Subject: [PATCH] PCI: brcmstb: Add dma-range mapping for inbound
- traffic
-
-The Broadcom STB PCIe host controller is intimately related to the
-memory subsystem. This close relationship adds complexity to how cpu
-system memory is mapped to PCIe memory. Ideally, this mapping is an
-identity mapping, or an identity mapping off by a constant. Not so in
-this case.
-
-Consider the Broadcom reference board BCM97445LCC_4X8 which has 6 GB
-of system memory. Here is how the PCIe controller maps the
-system memory to PCIe memory:
-
- memc0-a@[ 0....3fffffff] <=> pci@[ 0....3fffffff]
- memc0-b@[100000000...13fffffff] <=> pci@[ 40000000....7fffffff]
- memc1-a@[ 40000000....7fffffff] <=> pci@[ 80000000....bfffffff]
- memc1-b@[300000000...33fffffff] <=> pci@[ c0000000....ffffffff]
- memc2-a@[ 80000000....bfffffff] <=> pci@[100000000...13fffffff]
- memc2-b@[c00000000...c3fffffff] <=> pci@[140000000...17fffffff]
-
-Although there are some "gaps" that can be added between the
-individual mappings by software, the permutation of memory regions for
-the most part is fixed by HW. The solution of having something close
-to an identity mapping is not possible.
-
-The idea behind this HW design is that the same PCIe module can
-act as an RC or EP, and if it acts as an EP it concatenates all
-of system memory into a BAR so anything can be accessed. Unfortunately,
-when the PCIe block is in the role of an RC it also presents this
-"BAR" to downstream PCIe devices, rather than offering an identity map
-between its system memory and PCIe space.
-
-Suppose that an endpoint driver allocs some DMA memory. Suppose this
-memory is located at 0x6000_0000, which is in the middle of memc1-a.
-The driver wants a dma_addr_t value that it can pass on to the EP to
-use. Without doing any custom mapping, the EP will use this value for
-DMA: the driver will get a dma_addr_t equal to 0x6000_0000. But this
-won't work; the device needs a dma_addr_t that reflects the PCIe space
-address, namely 0xa000_0000.
-
-So, essentially the solution to this problem must modify the
-dma_addr_t returned by the DMA routines routines. There are two
-ways (I know of) of doing this:
-
-(a) overriding/redefining the dma_to_phys() and phys_to_dma() calls
-that are used by the dma_ops routines. This is the approach of
-
- arch/mips/cavium-octeon/dma-octeon.c
-
-In ARM and ARM64 these two routines are defiend in asm/dma-mapping.h
-as static inline functions.
-
-(b) Subscribe to a notifier that notifies when a device is added to a
-bus. When this happens, set_dma_ops() can be called for the device.
-This method is mentioned in:
-
- http://lxr.free-electrons.com/source/drivers/of/platform.c?v=3.16#L152
-
-where it says as a comment
-
- "In case if platform code need to use own special DMA
- configuration, it can use Platform bus notifier and
- handle BUS_NOTIFY_ADD_DEVICE event to fix up DMA
- configuration."
-
-Solution (b) is what this commit does. It uses its own set of
-dma_ops which are wrappers around the arch_dma_ops. The
-wrappers translate the dma addresses before/after invoking
-the arch_dma_ops, as appropriate.
-
----
- drivers/pci/controller/pcie-brcmstb.c | 420 +++++++++++++++++++++++++-
- 1 file changed, 411 insertions(+), 9 deletions(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -4,6 +4,7 @@
- #include <linux/clk.h>
- #include <linux/compiler.h>
- #include <linux/delay.h>
-+#include <linux/dma-mapping.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/io.h>
-@@ -319,11 +320,307 @@ static struct pci_ops brcm_pcie_ops = {
- ((val & ~reg##_##field##_MASK) | \
- (reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
-
-+static const struct dma_map_ops *arch_dma_ops;
-+static const struct dma_map_ops *brcm_dma_ops_ptr;
-+static struct of_pci_range *dma_ranges;
-+static int num_dma_ranges;
-+
- static phys_addr_t scb_size[BRCM_MAX_SCB];
- static int num_memc;
- static int num_pcie;
- static DEFINE_MUTEX(brcm_pcie_lock);
-
-+static dma_addr_t brcm_to_pci(dma_addr_t addr)
-+{
-+ struct of_pci_range *p;
-+
-+ if (!num_dma_ranges)
-+ return addr;
-+
-+ for (p = dma_ranges; p < &dma_ranges[num_dma_ranges]; p++)
-+ if (addr >= p->cpu_addr && addr < (p->cpu_addr + p->size))
-+ return addr - p->cpu_addr + p->pci_addr;
-+
-+ return addr;
-+}
-+
-+static dma_addr_t brcm_to_cpu(dma_addr_t addr)
-+{
-+ struct of_pci_range *p;
-+
-+ if (!num_dma_ranges)
-+ return addr;
-+
-+ for (p = dma_ranges; p < &dma_ranges[num_dma_ranges]; p++)
-+ if (addr >= p->pci_addr && addr < (p->pci_addr + p->size))
-+ return addr - p->pci_addr + p->cpu_addr;
-+
-+ return addr;
-+}
-+
-+static void *brcm_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-+ gfp_t gfp, unsigned long attrs)
-+{
-+ void *ret;
-+
-+ ret = arch_dma_ops->alloc(dev, size, handle, gfp, attrs);
-+ if (ret)
-+ *handle = brcm_to_pci(*handle);
-+ return ret;
-+}
-+
-+static void brcm_free(struct device *dev, size_t size, void *cpu_addr,
-+ dma_addr_t handle, unsigned long attrs)
-+{
-+ handle = brcm_to_cpu(handle);
-+ arch_dma_ops->free(dev, size, cpu_addr, handle, attrs);
-+}
-+
-+static int brcm_mmap(struct device *dev, struct vm_area_struct *vma,
-+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
-+ unsigned long attrs)
-+{
-+ dma_addr = brcm_to_cpu(dma_addr);
-+ return arch_dma_ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
-+}
-+
-+static int brcm_get_sgtable(struct device *dev, struct sg_table *sgt,
-+ void *cpu_addr, dma_addr_t handle, size_t size,
-+ unsigned long attrs)
-+{
-+ handle = brcm_to_cpu(handle);
-+ return arch_dma_ops->get_sgtable(dev, sgt, cpu_addr, handle, size,
-+ attrs);
-+}
-+
-+static dma_addr_t brcm_map_page(struct device *dev, struct page *page,
-+ unsigned long offset, size_t size,
-+ enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ return brcm_to_pci(arch_dma_ops->map_page(dev, page, offset, size,
-+ dir, attrs));
-+}
-+
-+static void brcm_unmap_page(struct device *dev, dma_addr_t handle,
-+ size_t size, enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ handle = brcm_to_cpu(handle);
-+ arch_dma_ops->unmap_page(dev, handle, size, dir, attrs);
-+}
-+
-+static int brcm_map_sg(struct device *dev, struct scatterlist *sgl,
-+ int nents, enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ int i, j;
-+ struct scatterlist *sg;
-+
-+ for_each_sg(sgl, sg, nents, i) {
-+#ifdef CONFIG_NEED_SG_DMA_LENGTH
-+ sg->dma_length = sg->length;
-+#endif
-+ sg->dma_address =
-+ brcm_dma_ops_ptr->map_page(dev, sg_page(sg), sg->offset,
-+ sg->length, dir, attrs);
-+ if (dma_mapping_error(dev, sg->dma_address))
-+ goto bad_mapping;
-+ }
-+ return nents;
-+
-+bad_mapping:
-+ for_each_sg(sgl, sg, i, j)
-+ brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
-+ sg_dma_len(sg), dir, attrs);
-+ return 0;
-+}
-+
-+static void brcm_unmap_sg(struct device *dev,
-+ struct scatterlist *sgl, int nents,
-+ enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ int i;
-+ struct scatterlist *sg;
-+
-+ for_each_sg(sgl, sg, nents, i)
-+ brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
-+ sg_dma_len(sg), dir, attrs);
-+}
-+
-+static void brcm_sync_single_for_cpu(struct device *dev,
-+ dma_addr_t handle, size_t size,
-+ enum dma_data_direction dir)
-+{
-+ handle = brcm_to_cpu(handle);
-+ arch_dma_ops->sync_single_for_cpu(dev, handle, size, dir);
-+}
-+
-+static void brcm_sync_single_for_device(struct device *dev,
-+ dma_addr_t handle, size_t size,
-+ enum dma_data_direction dir)
-+{
-+ handle = brcm_to_cpu(handle);
-+ arch_dma_ops->sync_single_for_device(dev, handle, size, dir);
-+}
-+
-+static dma_addr_t brcm_map_resource(struct device *dev, phys_addr_t phys,
-+ size_t size,
-+ enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ if (arch_dma_ops->map_resource)
-+ return brcm_to_pci(arch_dma_ops->map_resource
-+ (dev, phys, size, dir, attrs));
-+ return brcm_to_pci((dma_addr_t)phys);
-+}
-+
-+static void brcm_unmap_resource(struct device *dev, dma_addr_t handle,
-+ size_t size, enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ if (arch_dma_ops->unmap_resource)
-+ arch_dma_ops->unmap_resource(dev, brcm_to_cpu(handle), size,
-+ dir, attrs);
-+}
-+
-+void brcm_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
-+ int nents, enum dma_data_direction dir)
-+{
-+ struct scatterlist *sg;
-+ int i;
-+
-+ for_each_sg(sgl, sg, nents, i)
-+ brcm_dma_ops_ptr->sync_single_for_cpu(dev, sg_dma_address(sg),
-+ sg->length, dir);
-+}
-+
-+void brcm_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
-+ int nents, enum dma_data_direction dir)
-+{
-+ struct scatterlist *sg;
-+ int i;
-+
-+ for_each_sg(sgl, sg, nents, i)
-+ brcm_dma_ops_ptr->sync_single_for_device(dev,
-+ sg_dma_address(sg),
-+ sg->length, dir);
-+}
-+
-+static int brcm_mapping_error(struct device *dev, dma_addr_t dma_addr)
-+{
-+ return arch_dma_ops->mapping_error(dev, dma_addr);
-+}
-+
-+static int brcm_dma_supported(struct device *dev, u64 mask)
-+{
-+ if (num_dma_ranges) {
-+ /*
-+ * It is our translated addresses that the EP will "see", so
-+ * we check all of the ranges for the largest possible value.
-+ */
-+ int i;
-+
-+ for (i = 0; i < num_dma_ranges; i++)
-+ if (dma_ranges[i].pci_addr + dma_ranges[i].size - 1
-+ > mask)
-+ return 0;
-+ return 1;
-+ }
-+
-+ return arch_dma_ops->dma_supported(dev, mask);
-+}
-+
-+#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
-+u64 brcm_get_required_mask)(struct device *dev)
-+{
-+ return arch_dma_ops->get_required_mask(dev);
-+}
-+#endif
-+
-+static const struct dma_map_ops brcm_dma_ops = {
-+ .alloc = brcm_alloc,
-+ .free = brcm_free,
-+ .mmap = brcm_mmap,
-+ .get_sgtable = brcm_get_sgtable,
-+ .map_page = brcm_map_page,
-+ .unmap_page = brcm_unmap_page,
-+ .map_sg = brcm_map_sg,
-+ .unmap_sg = brcm_unmap_sg,
-+ .map_resource = brcm_map_resource,
-+ .unmap_resource = brcm_unmap_resource,
-+ .sync_single_for_cpu = brcm_sync_single_for_cpu,
-+ .sync_single_for_device = brcm_sync_single_for_device,
-+ .sync_sg_for_cpu = brcm_sync_sg_for_cpu,
-+ .sync_sg_for_device = brcm_sync_sg_for_device,
-+ .mapping_error = brcm_mapping_error,
-+ .dma_supported = brcm_dma_supported,
-+#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
-+ .get_required_mask = brcm_get_required_mask,
-+#endif
-+};
-+
-+static void brcm_set_dma_ops(struct device *dev)
-+{
-+ int ret;
-+
-+ if (IS_ENABLED(CONFIG_ARM64)) {
-+ /*
-+ * We are going to invoke get_dma_ops(). That
-+ * function, at this point in time, invokes
-+ * get_arch_dma_ops(), and for ARM64 that function
-+ * returns a pointer to dummy_dma_ops. So then we'd
-+ * like to call arch_setup_dma_ops(), but that isn't
-+ * exported. Instead, we call of_dma_configure(),
-+ * which is exported, and this calls
-+ * arch_setup_dma_ops(). Once we do this the call to
-+ * get_dma_ops() will work properly because
-+ * dev->dma_ops will be set.
-+ */
-+ ret = of_dma_configure(dev, dev->of_node, true);
-+ if (ret) {
-+ dev_err(dev, "of_dma_configure() failed: %d\n", ret);
-+ return;
-+ }
-+ }
-+
-+ arch_dma_ops = get_dma_ops(dev);
-+ if (!arch_dma_ops) {
-+ dev_err(dev, "failed to get arch_dma_ops\n");
-+ return;
-+ }
-+
-+ set_dma_ops(dev, &brcm_dma_ops);
-+}
-+
-+static int brcmstb_platform_notifier(struct notifier_block *nb,
-+ unsigned long event, void *__dev)
-+{
-+ struct device *dev = __dev;
-+
-+ brcm_dma_ops_ptr = &brcm_dma_ops;
-+ if (event != BUS_NOTIFY_ADD_DEVICE)
-+ return NOTIFY_DONE;
-+
-+ brcm_set_dma_ops(dev);
-+ return NOTIFY_OK;
-+}
-+
-+static struct notifier_block brcmstb_platform_nb = {
-+ .notifier_call = brcmstb_platform_notifier,
-+};
-+
-+static int brcm_register_notifier(void)
-+{
-+ return bus_register_notifier(&pci_bus_type, &brcmstb_platform_nb);
-+}
-+
-+static int brcm_unregister_notifier(void)
-+{
-+ return bus_unregister_notifier(&pci_bus_type, &brcmstb_platform_nb);
-+}
-+
- static u32 rd_fld(void __iomem *p, u32 mask, int shift)
- {
- return (bcm_readl(p) & mask) >> shift;
-@@ -597,9 +894,71 @@ static inline void brcm_pcie_perst_set(s
- WR_FLD_RB(pcie->base, PCIE_MISC_PCIE_CTRL, PCIE_PERSTB, !val);
- }
-
-+static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
-+ struct device_node *node)
-+{
-+ const int na = 3, ns = 2;
-+ int rlen;
-+
-+ parser->node = node;
-+ parser->pna = of_n_addr_cells(node);
-+ parser->np = parser->pna + na + ns;
-+
-+ parser->range = of_get_property(node, "dma-ranges", &rlen);
-+ if (!parser->range)
-+ return -ENOENT;
-+
-+ parser->end = parser->range + rlen / sizeof(__be32);
-+
-+ return 0;
-+}
-+
-+static int brcm_pcie_parse_map_dma_ranges(struct brcm_pcie *pcie)
-+{
-+ int i;
-+ struct of_pci_range_parser parser;
-+ struct device_node *dn = pcie->dn;
-+
-+ /*
-+ * Parse dma-ranges property if present. If there are multiple
-+ * PCIe controllers, we only have to parse from one of them since
-+ * the others will have an identical mapping.
-+ */
-+ if (!pci_dma_range_parser_init(&parser, dn)) {
-+ unsigned int max_ranges
-+ = (parser.end - parser.range) / parser.np;
-+
-+ dma_ranges = kcalloc(max_ranges, sizeof(struct of_pci_range),
-+ GFP_KERNEL);
-+ if (!dma_ranges)
-+ return -ENOMEM;
-+
-+ for (i = 0; of_pci_range_parser_one(&parser, dma_ranges + i);
-+ i++)
-+ num_dma_ranges++;
-+ }
-+
-+ for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-+ u64 size = brcmstb_memory_memc_size(i);
-+
-+ if (size == (u64)-1) {
-+ dev_err(pcie->dev, "cannot get memc%d size", i);
-+ return -EINVAL;
-+ } else if (size) {
-+ scb_size[i] = roundup_pow_of_two_64(size);
-+ num_memc++;
-+ } else {
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
- static int brcm_pcie_add_controller(struct brcm_pcie *pcie)
- {
- int i, ret = 0;
-+ struct device *dev = pcie->dev;
-
- mutex_lock(&brcm_pcie_lock);
- if (num_pcie > 0) {
-@@ -607,12 +966,21 @@ static int brcm_pcie_add_controller(stru
- goto done;
- }
-
-+ ret = brcm_register_notifier();
-+ if (ret) {
-+ dev_err(dev, "failed to register pci bus notifier\n");
-+ goto done;
-+ }
-+ ret = brcm_pcie_parse_map_dma_ranges(pcie);
-+ if (ret)
-+ goto done;
-+
- /* Determine num_memc and their sizes */
- for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
- u64 size = brcmstb_memory_memc_size(i);
-
- if (size == (u64)-1) {
-- dev_err(pcie->dev, "cannot get memc%d size\n", i);
-+ dev_err(dev, "cannot get memc%d size\n", i);
- ret = -EINVAL;
- goto done;
- } else if (size) {
-@@ -636,8 +1004,16 @@ done:
- static void brcm_pcie_remove_controller(struct brcm_pcie *pcie)
- {
- mutex_lock(&brcm_pcie_lock);
-- if (--num_pcie == 0)
-- num_memc = 0;
-+ if (--num_pcie > 0)
-+ goto out;
-+
-+ if (brcm_unregister_notifier())
-+ dev_err(pcie->dev, "failed to unregister pci bus notifier\n");
-+ kfree(dma_ranges);
-+ dma_ranges = NULL;
-+ num_dma_ranges = 0;
-+ num_memc = 0;
-+out:
- mutex_unlock(&brcm_pcie_lock);
- }
-
-@@ -757,6 +1133,38 @@ static int brcm_pcie_setup(struct brcm_p
- */
- rc_bar2_offset = 0;
-
-+ if (dma_ranges) {
-+ /*
-+ * The best-case scenario is to place the inbound
-+ * region in the first 4GB of pci-space, as some
-+ * legacy devices can only address 32bits.
-+ * We would also like to put the MSI under 4GB
-+ * as well, since some devices require a 32bit
-+ * MSI target address.
-+ */
-+ if (total_mem_size <= 0xc0000000ULL &&
-+ rc_bar2_size <= 0x100000000ULL) {
-+ rc_bar2_offset = 0;
-+ } else {
-+ /*
-+ * The system memory is 4GB or larger so we
-+ * cannot start the inbound region at location
-+ * 0 (since we have to allow some space for
-+ * outbound memory @ 3GB). So instead we
-+ * start it at the 1x multiple of its size
-+ */
-+ rc_bar2_offset = rc_bar2_size;
-+ }
-+
-+ } else {
-+ /*
-+ * Set simple configuration based on memory sizes
-+ * only. We always start the viewport at address 0,
-+ * and set the MSI target address accordingly.
-+ */
-+ rc_bar2_offset = 0;
-+ }
-+
- tmp = lower_32_bits(rc_bar2_offset);
- tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
- encode_ibar_size(rc_bar2_size));
-@@ -967,7 +1375,6 @@ static int brcm_pcie_probe(struct platfo
- struct brcm_pcie *pcie;
- struct resource *res;
- void __iomem *base;
-- u32 tmp;
- struct pci_host_bridge *bridge;
- struct pci_bus *child;
-
-@@ -984,11 +1391,6 @@ static int brcm_pcie_probe(struct platfo
- return -EINVAL;
- }
-
-- if (of_property_read_u32(dn, "dma-ranges", &tmp) == 0) {
-- dev_err(&pdev->dev, "cannot yet handle dma-ranges\n");
-- return -EINVAL;
-- }
--
- data = of_id->data;
- pcie->reg_offsets = data->offsets;
- pcie->reg_field_info = data->reg_field_info;
--- /dev/null
+From cb1acabb459677efbf95c54ce1dc5252be30a018 Mon Sep 17 00:00:00 2001
+Date: Mon, 15 Jan 2018 18:28:39 -0500
+Subject: [PATCH] dt-bindings: pci: Add DT docs for Brcmstb PCIe device
+
+The DT bindings description of the Brcmstb PCIe device is described. This
+node can be used by almost all Broadcom settop box chips, using
+ARM, ARM64, or MIPS CPU architectures.
+
+---
+ .../devicetree/bindings/pci/brcmstb-pcie.txt | 59 +++++++++++++++++++
+ 1 file changed, 59 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/pci/brcmstb-pcie.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt
+@@ -0,0 +1,59 @@
++Brcmstb PCIe Host Controller Device Tree Bindings
++
++Required Properties:
++- compatible
++ "brcm,bcm7425-pcie" -- for 7425 family MIPS-based SOCs.
++ "brcm,bcm7435-pcie" -- for 7435 family MIPS-based SOCs.
++ "brcm,bcm7445-pcie" -- for 7445 and later ARM based SOCs (not including
++ the 7278).
++ "brcm,bcm7278-pcie" -- for 7278 family ARM-based SOCs.
++
++- reg -- the register start address and length for the PCIe reg block.
++- interrupts -- two interrupts are specified; the first interrupt is for
++ the PCI host controller and the second is for MSI if the built-in
++ MSI controller is to be used.
++- interrupt-names -- names of the interrupts (above): "pcie" and "msi".
++- #address-cells -- set to <3>.
++- #size-cells -- set to <2>.
++- #interrupt-cells: set to <1>.
++- interrupt-map-mask and interrupt-map, standard PCI properties to define the
++ mapping of the PCIe interface to interrupt numbers.
++- ranges: ranges for the PCI memory and I/O regions.
++- linux,pci-domain -- should be unique per host controller.
++
++Optional Properties:
++- clocks -- phandle of pcie clock.
++- clock-names -- set to "sw_pcie" if clocks is used.
++- dma-ranges -- Specifies the inbound memory mapping regions when
++ an "identity map" is not possible.
++- msi-controller -- this property is typically specified to have the
++ PCIe controller use its internal MSI controller.
++- msi-parent -- set to use an external MSI interrupt controller.
++- brcm,enable-ssc -- (boolean) indicates usage of spread-spectrum clocking.
++- max-link-speed -- (integer) indicates desired generation of link:
++ 1 => 2.5 Gbps (gen1), 2 => 5.0 Gbps (gen2), 3 => 8.0 Gbps (gen3).
++
++Example Node:
++
++pcie0: pcie@f0460000 {
++ reg = <0x0 0xf0460000 0x0 0x9310>;
++ interrupts = <0x0 0x0 0x4>;
++ compatible = "brcm,bcm7445-pcie";
++ #address-cells = <3>;
++ #size-cells = <2>;
++ ranges = <0x02000000 0x00000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x08000000
++ 0x02000000 0x00000000 0x08000000 0x00000000 0xc8000000 0x00000000 0x08000000>;
++ #interrupt-cells = <1>;
++ interrupt-map-mask = <0 0 0 7>;
++ interrupt-map = <0 0 0 1 &intc 0 47 3
++ 0 0 0 2 &intc 0 48 3
++ 0 0 0 3 &intc 0 49 3
++ 0 0 0 4 &intc 0 50 3>;
++ clocks = <&sw_pcie0>;
++ clock-names = "sw_pcie";
++ msi-parent = <&pcie0>; /* use PCIe's internal MSI controller */
++ msi-controller; /* use PCIe's internal MSI controller */
++ brcm,ssc;
++ max-link-speed = <1>;
++ linux,pci-domain = <0>;
++ };
+++ /dev/null
-From cd3af4fa73ab25353f0865ebe8e0d2af1fd2a50b Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Feb 2019 22:06:59 +0000
-Subject: [PATCH] PCI: brcmstb: Add MSI capability
-
-This commit adds MSI to the Broadcom STB PCIe host controller. It does
-not add MSIX since that functionality is not in the HW. The MSI
-controller is physically located within the PCIe block, however, there
-is no reason why the MSI controller could not be moved elsewhere in
-the future.
-
-Since the internal Brcmstb MSI controller is intertwined with the PCIe
-controller, it is not its own platform device but rather part of the
-PCIe platform device.
-
----
- drivers/pci/controller/pcie-brcmstb.c | 374 ++++++++++++++++++++++++--
- 1 file changed, 353 insertions(+), 21 deletions(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -1,6 +1,7 @@
- // SPDX-License-Identifier: GPL-2.0
- /* Copyright (C) 2009 - 2017 Broadcom */
-
-+#include <linux/bitops.h>
- #include <linux/clk.h>
- #include <linux/compiler.h>
- #include <linux/delay.h>
-@@ -9,11 +10,13 @@
- #include <linux/interrupt.h>
- #include <linux/io.h>
- #include <linux/ioport.h>
-+#include <linux/irqchip/chained_irq.h>
- #include <linux/irqdomain.h>
- #include <linux/kernel.h>
- #include <linux/list.h>
- #include <linux/log2.h>
- #include <linux/module.h>
-+#include <linux/msi.h>
- #include <linux/of_address.h>
- #include <linux/of_irq.h>
- #include <linux/of_pci.h>
-@@ -47,6 +50,9 @@
- #define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034
- #define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038
- #define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
-+#define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044
-+#define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048
-+#define PCIE_MISC_MSI_DATA_CONFIG 0x404c
- #define PCIE_MISC_PCIE_CTRL 0x4064
- #define PCIE_MISC_PCIE_STATUS 0x4068
- #define PCIE_MISC_REVISION 0x406c
-@@ -55,6 +61,7 @@
- #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084
- #define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204
- #define PCIE_INTR2_CPU_BASE 0x4300
-+#define PCIE_MSI_INTR2_BASE 0x4500
-
- /*
- * Broadcom Settop Box PCIe Register Field shift and mask info. The
-@@ -115,6 +122,8 @@
-
- #define BRCM_NUM_PCIE_OUT_WINS 0x4
- #define BRCM_MAX_SCB 0x4
-+#define BRCM_INT_PCI_MSI_NR 32
-+#define BRCM_PCIE_HW_REV_33 0x0303
-
- #define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL
- #define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL
-@@ -203,6 +212,33 @@ struct brcm_window {
- dma_addr_t size;
- };
-
-+struct brcm_msi {
-+ struct device *dev;
-+ void __iomem *base;
-+ struct device_node *dn;
-+ struct irq_domain *msi_domain;
-+ struct irq_domain *inner_domain;
-+ struct mutex lock; /* guards the alloc/free operations */
-+ u64 target_addr;
-+ int irq;
-+
-+ /* intr_base is the base pointer for interrupt status/set/clr regs */
-+ void __iomem *intr_base;
-+
-+ /* intr_legacy_mask indicates how many bits are MSI interrupts */
-+ u32 intr_legacy_mask;
-+
-+ /*
-+ * intr_legacy_offset indicates bit position of MSI_01. It is
-+ * to map the register bit position to a hwirq that starts at 0.
-+ */
-+ u32 intr_legacy_offset;
-+
-+ /* used indicates which MSI interrupts have been alloc'd */
-+ unsigned long used;
-+ unsigned int rev;
-+};
-+
- /* Internal PCIe Host Controller Information.*/
- struct brcm_pcie {
- struct device *dev;
-@@ -217,7 +253,10 @@ struct brcm_pcie {
- int num_out_wins;
- bool ssc;
- int gen;
-+ u64 msi_target_addr;
- struct brcm_window out_wins[BRCM_NUM_PCIE_OUT_WINS];
-+ struct brcm_msi *msi;
-+ bool msi_internal;
- unsigned int rev;
- const int *reg_offsets;
- const int *reg_field_info;
-@@ -225,9 +264,9 @@ struct brcm_pcie {
- };
-
- struct pcie_cfg_data {
-- const int *reg_field_info;
-- const int *offsets;
-- const enum pcie_type type;
-+ const int *reg_field_info;
-+ const int *offsets;
-+ const enum pcie_type type;
- };
-
- static const int pcie_reg_field_info[] = {
-@@ -828,6 +867,267 @@ static void brcm_pcie_set_outbound_win(s
- }
- }
-
-+static struct irq_chip brcm_msi_irq_chip = {
-+ .name = "Brcm_MSI",
-+ .irq_mask = pci_msi_mask_irq,
-+ .irq_unmask = pci_msi_unmask_irq,
-+};
-+
-+static struct msi_domain_info brcm_msi_domain_info = {
-+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-+ MSI_FLAG_PCI_MSIX),
-+ .chip = &brcm_msi_irq_chip,
-+};
-+
-+static void brcm_pcie_msi_isr(struct irq_desc *desc)
-+{
-+ struct irq_chip *chip = irq_desc_get_chip(desc);
-+ struct brcm_msi *msi;
-+ unsigned long status, virq;
-+ u32 mask, bit, hwirq;
-+ struct device *dev;
-+
-+ chained_irq_enter(chip, desc);
-+ msi = irq_desc_get_handler_data(desc);
-+ mask = msi->intr_legacy_mask;
-+ dev = msi->dev;
-+
-+ while ((status = bcm_readl(msi->intr_base + STATUS) & mask)) {
-+ for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) {
-+ /* clear the interrupt */
-+ bcm_writel(1 << bit, msi->intr_base + CLR);
-+
-+ /* Account for legacy interrupt offset */
-+ hwirq = bit - msi->intr_legacy_offset;
-+
-+ virq = irq_find_mapping(msi->inner_domain, hwirq);
-+ if (virq) {
-+ if (msi->used & (1 << hwirq))
-+ generic_handle_irq(virq);
-+ else
-+ dev_info(dev, "unhandled MSI %d\n",
-+ hwirq);
-+ } else {
-+ /* Unknown MSI, just clear it */
-+ dev_dbg(dev, "unexpected MSI\n");
-+ }
-+ }
-+ }
-+ chained_irq_exit(chip, desc);
-+}
-+
-+static void brcm_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
-+{
-+ struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
-+ u32 temp;
-+
-+ msg->address_lo = lower_32_bits(msi->target_addr);
-+ msg->address_hi = upper_32_bits(msi->target_addr);
-+ temp = bcm_readl(msi->base + PCIE_MISC_MSI_DATA_CONFIG);
-+ msg->data = ((temp >> 16) & (temp & 0xffff)) | data->hwirq;
-+}
-+
-+static int brcm_msi_set_affinity(struct irq_data *irq_data,
-+ const struct cpumask *mask, bool force)
-+{
-+ return -EINVAL;
-+}
-+
-+static struct irq_chip brcm_msi_bottom_irq_chip = {
-+ .name = "Brcm_MSI",
-+ .irq_compose_msi_msg = brcm_compose_msi_msg,
-+ .irq_set_affinity = brcm_msi_set_affinity,
-+};
-+
-+static int brcm_msi_alloc(struct brcm_msi *msi)
-+{
-+ int bit, hwirq;
-+
-+ mutex_lock(&msi->lock);
-+ bit = ~msi->used ? ffz(msi->used) : -1;
-+
-+ if (bit >= 0 && bit < BRCM_INT_PCI_MSI_NR) {
-+ msi->used |= (1 << bit);
-+ hwirq = bit - msi->intr_legacy_offset;
-+ } else {
-+ hwirq = -ENOSPC;
-+ }
-+
-+ mutex_unlock(&msi->lock);
-+ return hwirq;
-+}
-+
-+static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq)
-+{
-+ mutex_lock(&msi->lock);
-+ msi->used &= ~(1 << (hwirq + msi->intr_legacy_offset));
-+ mutex_unlock(&msi->lock);
-+}
-+
-+static int brcm_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
-+ unsigned int nr_irqs, void *args)
-+{
-+ struct brcm_msi *msi = domain->host_data;
-+ int hwirq;
-+
-+ hwirq = brcm_msi_alloc(msi);
-+
-+ if (hwirq < 0)
-+ return hwirq;
-+
-+ irq_domain_set_info(domain, virq, (irq_hw_number_t)hwirq,
-+ &brcm_msi_bottom_irq_chip, domain->host_data,
-+ handle_simple_irq, NULL, NULL);
-+ return 0;
-+}
-+
-+static void brcm_irq_domain_free(struct irq_domain *domain,
-+ unsigned int virq, unsigned int nr_irqs)
-+{
-+ struct irq_data *d = irq_domain_get_irq_data(domain, virq);
-+ struct brcm_msi *msi = irq_data_get_irq_chip_data(d);
-+
-+ brcm_msi_free(msi, d->hwirq);
-+}
-+
-+static void brcm_msi_set_regs(struct brcm_msi *msi)
-+{
-+ u32 data_val, msi_lo, msi_hi;
-+
-+ if (msi->rev >= BRCM_PCIE_HW_REV_33) {
-+ /*
-+ * ffe0 -- least sig 5 bits are 0 indicating 32 msgs
-+ * 6540 -- this is our arbitrary unique data value
-+ */
-+ data_val = 0xffe06540;
-+ } else {
-+ /*
-+ * fff8 -- least sig 3 bits are 0 indicating 8 msgs
-+ * 6540 -- this is our arbitrary unique data value
-+ */
-+ data_val = 0xfff86540;
-+ }
-+
-+ /*
-+ * Make sure we are not masking MSIs. Note that MSIs can be masked,
-+ * but that occurs on the PCIe EP device
-+ */
-+ bcm_writel(0xffffffff & msi->intr_legacy_mask,
-+ msi->intr_base + MASK_CLR);
-+
-+ msi_lo = lower_32_bits(msi->target_addr);
-+ msi_hi = upper_32_bits(msi->target_addr);
-+ /*
-+ * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI
-+ * enable, which we set to 1.
-+ */
-+ bcm_writel(msi_lo | 1, msi->base + PCIE_MISC_MSI_BAR_CONFIG_LO);
-+ bcm_writel(msi_hi, msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI);
-+ bcm_writel(data_val, msi->base + PCIE_MISC_MSI_DATA_CONFIG);
-+}
-+
-+static const struct irq_domain_ops msi_domain_ops = {
-+ .alloc = brcm_irq_domain_alloc,
-+ .free = brcm_irq_domain_free,
-+};
-+
-+static int brcm_allocate_domains(struct brcm_msi *msi)
-+{
-+ struct fwnode_handle *fwnode = of_node_to_fwnode(msi->dn);
-+ struct device *dev = msi->dev;
-+
-+ msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR,
-+ &msi_domain_ops, msi);
-+ if (!msi->inner_domain) {
-+ dev_err(dev, "failed to create IRQ domain\n");
-+ return -ENOMEM;
-+ }
-+
-+ msi->msi_domain = pci_msi_create_irq_domain(fwnode,
-+ &brcm_msi_domain_info,
-+ msi->inner_domain);
-+ if (!msi->msi_domain) {
-+ dev_err(dev, "failed to create MSI domain\n");
-+ irq_domain_remove(msi->inner_domain);
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+
-+static void brcm_free_domains(struct brcm_msi *msi)
-+{
-+ irq_domain_remove(msi->msi_domain);
-+ irq_domain_remove(msi->inner_domain);
-+}
-+
-+static void brcm_msi_remove(struct brcm_pcie *pcie)
-+{
-+ struct brcm_msi *msi = pcie->msi;
-+
-+ if (!msi)
-+ return;
-+ irq_set_chained_handler(msi->irq, NULL);
-+ irq_set_handler_data(msi->irq, NULL);
-+ brcm_free_domains(msi);
-+}
-+
-+static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)
-+{
-+ struct brcm_msi *msi;
-+ int irq, ret;
-+ struct device *dev = pcie->dev;
-+
-+ irq = irq_of_parse_and_map(dev->of_node, 1);
-+ if (irq <= 0) {
-+ dev_err(dev, "cannot map msi intr\n");
-+ return -ENODEV;
-+ }
-+
-+ msi = devm_kzalloc(dev, sizeof(struct brcm_msi), GFP_KERNEL);
-+ if (!msi)
-+ return -ENOMEM;
-+
-+ msi->dev = dev;
-+ msi->base = pcie->base;
-+ msi->rev = pcie->rev;
-+ msi->dn = pcie->dn;
-+ msi->target_addr = pcie->msi_target_addr;
-+ msi->irq = irq;
-+
-+ ret = brcm_allocate_domains(msi);
-+ if (ret)
-+ return ret;
-+
-+ irq_set_chained_handler_and_data(msi->irq, brcm_pcie_msi_isr, msi);
-+
-+ if (msi->rev >= BRCM_PCIE_HW_REV_33) {
-+ msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE;
-+ /*
-+ * This version of PCIe hw has only 32 intr bits
-+ * starting at bit position 0.
-+ */
-+ msi->intr_legacy_mask = 0xffffffff;
-+ msi->intr_legacy_offset = 0x0;
-+ msi->used = 0x0;
-+
-+ } else {
-+ msi->intr_base = msi->base + PCIE_INTR2_CPU_BASE;
-+ /*
-+ * This version of PCIe hw has only 8 intr bits starting
-+ * at bit position 24.
-+ */
-+ msi->intr_legacy_mask = 0xff000000;
-+ msi->intr_legacy_offset = 24;
-+ msi->used = 0x00ffffff;
-+ }
-+
-+ brcm_msi_set_regs(msi);
-+ pcie->msi = msi;
-+
-+ return 0;
-+}
-+
- /* Configuration space read/write support */
- static int cfg_index(int busnr, int devfn, int reg)
- {
-@@ -1072,6 +1372,7 @@ static int brcm_pcie_setup(struct brcm_p
- u16 nlw, cls, lnksta;
- bool ssc_good = false;
- struct device *dev = pcie->dev;
-+ u64 msi_target_addr;
-
- /* Reset the bridge */
- brcm_pcie_bridge_sw_init_set(pcie, 1);
-@@ -1116,27 +1417,24 @@ static int brcm_pcie_setup(struct brcm_p
- * The PCIe host controller by design must set the inbound
- * viewport to be a contiguous arrangement of all of the
- * system's memory. In addition, its size mut be a power of
-- * two. To further complicate matters, the viewport must
-- * start on a pcie-address that is aligned on a multiple of its
-- * size. If a portion of the viewport does not represent
-- * system memory -- e.g. 3GB of memory requires a 4GB viewport
-- * -- we can map the outbound memory in or after 3GB and even
-- * though the viewport will overlap the outbound memory the
-- * controller will know to send outbound memory downstream and
-- * everything else upstream.
-+ * two. Further, the MSI target address must NOT be placed
-+ * inside this region, as the decoding logic will consider its
-+ * address to be inbound memory traffic. To further
-+ * complicate matters, the viewport must start on a
-+ * pcie-address that is aligned on a multiple of its size.
-+ * If a portion of the viewport does not represent system
-+ * memory -- e.g. 3GB of memory requires a 4GB viewport --
-+ * we can map the outbound memory in or after 3GB and even
-+ * though the viewport will overlap the outbound memory
-+ * the controller will know to send outbound memory downstream
-+ * and everything else upstream.
- */
- rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
-
-- /*
-- * Set simple configuration based on memory sizes
-- * only. We always start the viewport at address 0.
-- */
-- rc_bar2_offset = 0;
--
- if (dma_ranges) {
- /*
- * The best-case scenario is to place the inbound
-- * region in the first 4GB of pci-space, as some
-+ * region in the first 4GB of pcie-space, as some
- * legacy devices can only address 32bits.
- * We would also like to put the MSI under 4GB
- * as well, since some devices require a 32bit
-@@ -1145,6 +1443,14 @@ static int brcm_pcie_setup(struct brcm_p
- if (total_mem_size <= 0xc0000000ULL &&
- rc_bar2_size <= 0x100000000ULL) {
- rc_bar2_offset = 0;
-+ /* If the viewport is less then 4GB we can fit
-+ * the MSI target address under 4GB. Otherwise
-+ * put it right below 64GB.
-+ */
-+ msi_target_addr =
-+ (rc_bar2_size == 0x100000000ULL)
-+ ? BRCM_MSI_TARGET_ADDR_GT_4GB
-+ : BRCM_MSI_TARGET_ADDR_LT_4GB;
- } else {
- /*
- * The system memory is 4GB or larger so we
-@@ -1154,8 +1460,12 @@ static int brcm_pcie_setup(struct brcm_p
- * start it at the 1x multiple of its size
- */
- rc_bar2_offset = rc_bar2_size;
-- }
-
-+ /* Since we are starting the viewport at 4GB or
-+ * higher, put the MSI target address below 4GB
-+ */
-+ msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
-+ }
- } else {
- /*
- * Set simple configuration based on memory sizes
-@@ -1163,7 +1473,12 @@ static int brcm_pcie_setup(struct brcm_p
- * and set the MSI target address accordingly.
- */
- rc_bar2_offset = 0;
-+
-+ msi_target_addr = (rc_bar2_size >= 0x100000000ULL)
-+ ? BRCM_MSI_TARGET_ADDR_GT_4GB
-+ : BRCM_MSI_TARGET_ADDR_LT_4GB;
- }
-+ pcie->msi_target_addr = msi_target_addr;
-
- tmp = lower_32_bits(rc_bar2_offset);
- tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
-@@ -1333,6 +1648,9 @@ static int brcm_pcie_resume(struct devic
- if (ret)
- return ret;
-
-+ if (pcie->msi && pcie->msi_internal)
-+ brcm_msi_set_regs(pcie->msi);
-+
- pcie->suspended = false;
-
- return 0;
-@@ -1340,6 +1658,7 @@ static int brcm_pcie_resume(struct devic
-
- static void _brcm_pcie_remove(struct brcm_pcie *pcie)
- {
-+ brcm_msi_remove(pcie);
- turn_off(pcie);
- clk_disable_unprepare(pcie->clk);
- clk_put(pcie->clk);
-@@ -1368,7 +1687,7 @@ MODULE_DEVICE_TABLE(of, brcm_pcie_match)
-
- static int brcm_pcie_probe(struct platform_device *pdev)
- {
-- struct device_node *dn = pdev->dev.of_node;
-+ struct device_node *dn = pdev->dev.of_node, *msi_dn;
- const struct of_device_id *of_id;
- const struct pcie_cfg_data *data;
- int ret;
-@@ -1448,6 +1767,20 @@ static int brcm_pcie_probe(struct platfo
- if (ret)
- goto fail;
-
-+ msi_dn = of_parse_phandle(pcie->dn, "msi-parent", 0);
-+ /* Use the internal MSI if no msi-parent property */
-+ if (!msi_dn)
-+ msi_dn = pcie->dn;
-+
-+ if (pci_msi_enabled() && msi_dn == pcie->dn) {
-+ ret = brcm_pcie_enable_msi(pcie);
-+ if (ret)
-+ dev_err(pcie->dev,
-+ "probe of internal MSI failed: %d)", ret);
-+ else
-+ pcie->msi_internal = true;
-+ }
-+
- list_splice_init(&pcie->resources, &bridge->windows);
- bridge->dev.parent = &pdev->dev;
- bridge->busnr = 0;
-@@ -1470,7 +1803,6 @@ static int brcm_pcie_probe(struct platfo
- pcie->root_bus = bridge->bus;
-
- return 0;
--
- fail:
- _brcm_pcie_remove(pcie);
- return ret;
--- /dev/null
+From 545951be6cabac8b1df85771c44335a0eaaa3c5d Mon Sep 17 00:00:00 2001
+Date: Tue, 19 Feb 2019 22:06:59 +0000
+Subject: [PATCH] pcie-brcmstb: Changes for BCM2711
+
+The initial brcmstb PCIe driver - originally taken from the V3(?)
+patch set - has been modified significantly for the BCM2711.
+
+---
+ drivers/dma/bcm2835-dma.c | 107 ++++
+ drivers/pci/controller/Makefile | 4 +
+ drivers/pci/controller/pcie-brcmstb-bounce.c | 564 +++++++++++++++++++
+ drivers/pci/controller/pcie-brcmstb-bounce.h | 32 ++
+ drivers/pci/controller/pcie-brcmstb.c | 237 ++++----
+ drivers/soc/bcm/brcmstb/Makefile | 2 +-
+ drivers/soc/bcm/brcmstb/memory.c | 158 ++++++
+ 7 files changed, 996 insertions(+), 108 deletions(-)
+ create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce.c
+ create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce.h
+ create mode 100644 drivers/soc/bcm/brcmstb/memory.c
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -68,6 +68,17 @@ struct bcm2835_dma_cb {
+ uint32_t pad[2];
+ };
+
++struct bcm2838_dma40_scb {
++ uint32_t ti;
++ uint32_t src;
++ uint32_t srci;
++ uint32_t dst;
++ uint32_t dsti;
++ uint32_t len;
++ uint32_t next_cb;
++ uint32_t rsvd;
++};
++
+ struct bcm2835_cb_entry {
+ struct bcm2835_dma_cb *cb;
+ dma_addr_t paddr;
+@@ -185,6 +196,45 @@ struct bcm2835_desc {
+ #define MAX_DMA_LEN SZ_1G
+ #define MAX_LITE_DMA_LEN (SZ_64K - 4)
+
++/* 40-bit DMA support */
++#define BCM2838_DMA40_CS 0x00
++#define BCM2838_DMA40_CB 0x04
++#define BCM2838_DMA40_DEBUG 0x0c
++#define BCM2858_DMA40_TI 0x10
++#define BCM2838_DMA40_SRC 0x14
++#define BCM2838_DMA40_SRCI 0x18
++#define BCM2838_DMA40_DEST 0x1c
++#define BCM2838_DMA40_DESTI 0x20
++#define BCM2838_DMA40_LEN 0x24
++#define BCM2838_DMA40_NEXT_CB 0x28
++#define BCM2838_DMA40_DEBUG2 0x2c
++
++#define BCM2838_DMA40_CS_ACTIVE BIT(0)
++#define BCM2838_DMA40_CS_END BIT(1)
++
++#define BCM2838_DMA40_CS_QOS(x) (((x) & 0x1f) << 16)
++#define BCM2838_DMA40_CS_PANIC_QOS(x) (((x) & 0x1f) << 20)
++#define BCM2838_DMA40_CS_WRITE_WAIT BIT(28)
++
++#define BCM2838_DMA40_BURST_LEN(x) ((((x) - 1) & 0xf) << 8)
++#define BCM2838_DMA40_INC BIT(12)
++#define BCM2838_DMA40_SIZE_128 (2 << 13)
++
++#define BCM2838_DMA40_MEMCPY_QOS \
++ (BCM2838_DMA40_CS_QOS(0x0) | \
++ BCM2838_DMA40_CS_PANIC_QOS(0x0) | \
++ BCM2838_DMA40_CS_WRITE_WAIT)
++
++#define BCM2838_DMA40_MEMCPY_XFER_INFO \
++ (BCM2838_DMA40_SIZE_128 | \
++ BCM2838_DMA40_INC | \
++ BCM2838_DMA40_BURST_LEN(16))
++
++static void __iomem *memcpy_chan;
++static struct bcm2838_dma40_scb *memcpy_scb;
++static dma_addr_t memcpy_scb_dma;
++DEFINE_SPINLOCK(memcpy_lock);
++
+ static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
+ {
+ /* lite and normal channels have different max frame length */
+@@ -868,6 +918,56 @@ static void bcm2835_dma_free(struct bcm2
+ }
+ }
+
++int bcm2838_dma40_memcpy_init(struct device *dev)
++{
++ if (memcpy_scb)
++ return 0;
++
++ memcpy_scb = dma_alloc_coherent(dev, sizeof(*memcpy_scb),
++ &memcpy_scb_dma, GFP_KERNEL);
++
++ if (!memcpy_scb) {
++ pr_err("bcm2838_dma40_memcpy_init failed!\n");
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(bcm2838_dma40_memcpy_init);
++
++void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size)
++{
++ struct bcm2838_dma40_scb *scb = memcpy_scb;
++ unsigned long flags;
++
++ if (!scb) {
++ pr_err("bcm2838_dma40_memcpy not initialised!\n");
++ return;
++ }
++
++ spin_lock_irqsave(&memcpy_lock, flags);
++
++ scb->ti = 0;
++ scb->src = lower_32_bits(src);
++ scb->srci = upper_32_bits(src) | BCM2838_DMA40_MEMCPY_XFER_INFO;
++ scb->dst = lower_32_bits(dst);
++ scb->dsti = upper_32_bits(dst) | BCM2838_DMA40_MEMCPY_XFER_INFO;
++ scb->len = size;
++ scb->next_cb = 0;
++
++ writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2838_DMA40_CB);
++ writel(BCM2838_DMA40_MEMCPY_QOS + BCM2838_DMA40_CS_ACTIVE,
++ memcpy_chan + BCM2838_DMA40_CS);
++ /* Poll for completion */
++ while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_CS_END))
++ cpu_relax();
++
++ writel(BCM2838_DMA40_CS_END, memcpy_chan + BCM2838_DMA40_CS);
++
++ spin_unlock_irqrestore(&memcpy_lock, flags);
++}
++EXPORT_SYMBOL(bcm2838_dma40_memcpy);
++
+ static const struct of_device_id bcm2835_dma_of_match[] = {
+ { .compatible = "brcm,bcm2835-dma", },
+ {},
+@@ -966,6 +1066,13 @@ static int bcm2835_dma_probe(struct plat
+ /* Channel 0 is used by the legacy API */
+ chans_available &= ~BCM2835_DMA_BULK_MASK;
+
++ /* We can't use channels 11-13 yet */
++ chans_available &= ~(BIT(11) | BIT(12) | BIT(13));
++
++ /* Grab channel 14 for the 40-bit DMA memcpy */
++ chans_available &= ~BIT(14);
++ memcpy_chan = BCM2835_DMA_CHANIO(base, 14);
++
+ /* get irqs for each channel that we support */
+ for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
+ /* skip masked out channels */
+--- a/drivers/pci/controller/Makefile
++++ b/drivers/pci/controller/Makefile
+@@ -29,6 +29,10 @@ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-medi
+ obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
+ obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
+ obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
++ifdef CONFIG_ARM
++obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce.o
++endif
++
+ obj-$(CONFIG_VMD) += vmd.o
+ # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
+ obj-y += dwc/
+--- /dev/null
++++ b/drivers/pci/controller/pcie-brcmstb-bounce.c
+@@ -0,0 +1,564 @@
++/*
++ * This code started out as a version of arch/arm/common/dmabounce.c,
++ * modified to cope with highmem pages. Now it has been changed heavily -
++ * it now preallocates a large block (currently 4MB) and carves it up
++ * sequentially in ring fashion, and DMA is used to copy the data - to the
++ * point where very little of the original remains.
++ *
++ * Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
++ *
++ *
++ * Copyright (C) 2002 Hewlett Packard Company.
++ * Copyright (C) 2004 MontaVista Software, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/page-flags.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmapool.h>
++#include <linux/list.h>
++#include <linux/scatterlist.h>
++#include <linux/bitmap.h>
++
++#include <asm/cacheflush.h>
++#include <asm/dma-iommu.h>
++
++#define STATS
++
++#ifdef STATS
++#define DO_STATS(X) do { X ; } while (0)
++#else
++#define DO_STATS(X) do { } while (0)
++#endif
++
++/* ************************************************** */
++
++struct safe_buffer {
++ struct list_head node;
++
++ /* original request */
++ size_t size;
++ int direction;
++
++ struct dmabounce_pool *pool;
++ void *safe;
++ dma_addr_t unsafe_dma_addr;
++ dma_addr_t safe_dma_addr;
++};
++
++struct dmabounce_pool {
++ unsigned long pages;
++ void *virt_addr;
++ dma_addr_t dma_addr;
++ unsigned long *alloc_map;
++ unsigned long alloc_pos;
++ spinlock_t lock;
++ struct device *dev;
++ unsigned long num_pages;
++#ifdef STATS
++ size_t max_size;
++ unsigned long num_bufs;
++ unsigned long max_bufs;
++ unsigned long max_pages;
++#endif
++};
++
++struct dmabounce_device_info {
++ struct device *dev;
++ dma_addr_t threshold;
++ struct list_head safe_buffers;
++ struct dmabounce_pool pool;
++ rwlock_t lock;
++#ifdef STATS
++ unsigned long map_count;
++ unsigned long unmap_count;
++ unsigned long sync_dev_count;
++ unsigned long sync_cpu_count;
++ unsigned long fail_count;
++ int attr_res;
++#endif
++};
++
++static struct dmabounce_device_info *g_dmabounce_device_info;
++
++extern int bcm2838_dma40_memcpy_init(struct device *dev);
++extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
++
++#ifdef STATS
++static ssize_t
++bounce_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
++ return sprintf(buf, "m:%lu/%lu s:%lu/%lu f:%lu s:%zu b:%lu/%lu a:%lu/%lu\n",
++ device_info->map_count,
++ device_info->unmap_count,
++ device_info->sync_dev_count,
++ device_info->sync_cpu_count,
++ device_info->fail_count,
++ device_info->pool.max_size,
++ device_info->pool.num_bufs,
++ device_info->pool.max_bufs,
++ device_info->pool.num_pages * PAGE_SIZE,
++ device_info->pool.max_pages * PAGE_SIZE);
++}
++
++static DEVICE_ATTR(dmabounce_stats, 0444, bounce_show, NULL);
++#endif
++
++static int bounce_create(struct dmabounce_pool *pool, struct device *dev,
++ unsigned long buffer_size)
++{
++ int ret = -ENOMEM;
++ pool->pages = (buffer_size + PAGE_SIZE - 1)/PAGE_SIZE;
++ pool->alloc_map = bitmap_zalloc(pool->pages, GFP_KERNEL);
++ if (!pool->alloc_map)
++ goto err_bitmap;
++ pool->virt_addr = dma_alloc_coherent(dev, pool->pages * PAGE_SIZE,
++ &pool->dma_addr, GFP_KERNEL);
++ if (!pool->virt_addr)
++ goto err_dmabuf;
++
++ pool->alloc_pos = 0;
++ spin_lock_init(&pool->lock);
++ pool->dev = dev;
++ pool->num_pages = 0;
++
++ DO_STATS(pool->max_size = 0);
++ DO_STATS(pool->num_bufs = 0);
++ DO_STATS(pool->max_bufs = 0);
++ DO_STATS(pool->max_pages = 0);
++
++ return 0;
++
++err_dmabuf:
++ bitmap_free(pool->alloc_map);
++err_bitmap:
++ return ret;
++}
++
++static void bounce_destroy(struct dmabounce_pool *pool)
++{
++ dma_free_coherent(pool->dev, pool->pages * PAGE_SIZE, pool->virt_addr,
++ pool->dma_addr);
++
++ bitmap_free(pool->alloc_map);
++}
++
++static void *bounce_alloc(struct dmabounce_pool *pool, size_t size,
++ dma_addr_t *dmaaddrp)
++{
++ unsigned long pages;
++ unsigned long flags;
++ unsigned long pos;
++
++ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
++
++ DO_STATS(pool->max_size = max(size, pool->max_size));
++
++ spin_lock_irqsave(&pool->lock, flags);
++ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
++ pool->alloc_pos, pages, 0);
++ /* If not found, try from the start */
++ if (pos >= pool->pages && pool->alloc_pos)
++ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
++ 0, pages, 0);
++
++ if (pos >= pool->pages) {
++ spin_unlock_irqrestore(&pool->lock, flags);
++ return NULL;
++ }
++
++ bitmap_set(pool->alloc_map, pos, pages);
++ pool->alloc_pos = (pos + pages) % pool->pages;
++ pool->num_pages += pages;
++
++ DO_STATS(pool->num_bufs++);
++ DO_STATS(pool->max_bufs = max(pool->num_bufs, pool->max_bufs));
++ DO_STATS(pool->max_pages = max(pool->num_pages, pool->max_pages));
++
++ spin_unlock_irqrestore(&pool->lock, flags);
++
++ *dmaaddrp = pool->dma_addr + pos * PAGE_SIZE;
++
++ return pool->virt_addr + pos * PAGE_SIZE;
++}
++
++static void
++bounce_free(struct dmabounce_pool *pool, void *buf, size_t size)
++{
++ unsigned long pages;
++ unsigned long flags;
++ unsigned long pos;
++
++ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
++ pos = (buf - pool->virt_addr)/PAGE_SIZE;
++
++ BUG_ON((buf - pool->virt_addr) & (PAGE_SIZE - 1));
++
++ spin_lock_irqsave(&pool->lock, flags);
++ bitmap_clear(pool->alloc_map, pos, pages);
++ pool->num_pages -= pages;
++ if (pool->num_pages == 0)
++ pool->alloc_pos = 0;
++ DO_STATS(pool->num_bufs--);
++ spin_unlock_irqrestore(&pool->lock, flags);
++}
++
++/* allocate a 'safe' buffer and keep track of it */
++static struct safe_buffer *
++alloc_safe_buffer(struct dmabounce_device_info *device_info,
++ dma_addr_t dma_addr, size_t size, enum dma_data_direction dir)
++{
++ struct safe_buffer *buf;
++ struct dmabounce_pool *pool = &device_info->pool;
++ struct device *dev = device_info->dev;
++ unsigned long flags;
++
++ /*
++ * Although one might expect this to be called in thread context,
++ * using GFP_KERNEL here leads to hard-to-debug lockups. in_atomic()
++ * was previously used to select the appropriate allocation mode,
++ * but this is unsafe.
++ */
++ buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
++ if (!buf) {
++ dev_warn(dev, "%s: kmalloc failed\n", __func__);
++ return NULL;
++ }
++
++ buf->unsafe_dma_addr = dma_addr;
++ buf->size = size;
++ buf->direction = dir;
++ buf->pool = pool;
++
++ buf->safe = bounce_alloc(pool, size, &buf->safe_dma_addr);
++
++ if (!buf->safe) {
++ dev_warn(dev,
++ "%s: could not alloc dma memory (size=%d)\n",
++ __func__, size);
++ kfree(buf);
++ return NULL;
++ }
++
++ write_lock_irqsave(&device_info->lock, flags);
++ list_add(&buf->node, &device_info->safe_buffers);
++ write_unlock_irqrestore(&device_info->lock, flags);
++
++ return buf;
++}
++
++/* determine if a buffer is from our "safe" pool */
++static struct safe_buffer *
++find_safe_buffer(struct dmabounce_device_info *device_info,
++ dma_addr_t safe_dma_addr)
++{
++ struct safe_buffer *b, *rb = NULL;
++ unsigned long flags;
++
++ read_lock_irqsave(&device_info->lock, flags);
++
++ list_for_each_entry(b, &device_info->safe_buffers, node)
++ if (b->safe_dma_addr <= safe_dma_addr &&
++ b->safe_dma_addr + b->size > safe_dma_addr) {
++ rb = b;
++ break;
++ }
++
++ read_unlock_irqrestore(&device_info->lock, flags);
++ return rb;
++}
++
++static void
++free_safe_buffer(struct dmabounce_device_info *device_info,
++ struct safe_buffer *buf)
++{
++ unsigned long flags;
++
++ write_lock_irqsave(&device_info->lock, flags);
++ list_del(&buf->node);
++ write_unlock_irqrestore(&device_info->lock, flags);
++
++ bounce_free(buf->pool, buf->safe, buf->size);
++
++ kfree(buf);
++}
++
++/* ************************************************** */
++
++static struct safe_buffer *
++find_safe_buffer_dev(struct device *dev, dma_addr_t dma_addr, const char *where)
++{
++ if (!dev || !g_dmabounce_device_info)
++ return NULL;
++ if (dma_mapping_error(dev, dma_addr)) {
++ dev_err(dev, "Trying to %s invalid mapping\n", where);
++ return NULL;
++ }
++ return find_safe_buffer(g_dmabounce_device_info, dma_addr);
++}
++
++static dma_addr_t
++map_single(struct device *dev, struct safe_buffer *buf, size_t size,
++ enum dma_data_direction dir, unsigned long attrs)
++{
++ BUG_ON(buf->size != size);
++ BUG_ON(buf->direction != dir);
++
++ dev_dbg(dev, "map: %llx->%llx\n", (u64)buf->unsafe_dma_addr,
++ (u64)buf->safe_dma_addr);
++
++ if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
++ !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
++ bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
++ size);
++
++ return buf->safe_dma_addr;
++}
++
++static dma_addr_t
++unmap_single(struct device *dev, struct safe_buffer *buf, size_t size,
++ enum dma_data_direction dir, unsigned long attrs)
++{
++ BUG_ON(buf->size != size);
++ BUG_ON(buf->direction != dir);
++
++ if ((dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) &&
++ !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
++ dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
++ (u64)buf->unsafe_dma_addr);
++
++ bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
++ size);
++ }
++ return buf->unsafe_dma_addr;
++}
++
++/* ************************************************** */
++
++/*
++ * see if a buffer address is in an 'unsafe' range. if it is
++ * allocate a 'safe' buffer and copy the unsafe buffer into it.
++ * substitute the safe buffer for the unsafe one.
++ * (basically move the buffer from an unsafe area to a safe one)
++ */
++static dma_addr_t
++dmabounce_map_page(struct device *dev, struct page *page, unsigned long offset,
++ size_t size, enum dma_data_direction dir,
++ unsigned long attrs)
++{
++ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
++ dma_addr_t dma_addr;
++
++ dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset;
++
++ arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
++
++ if (device_info && (dma_addr + size) > device_info->threshold) {
++ struct safe_buffer *buf;
++
++ buf = alloc_safe_buffer(device_info, dma_addr, size, dir);
++ if (!buf) {
++ DO_STATS(device_info->fail_count++);
++ return ARM_MAPPING_ERROR;
++ }
++
++ DO_STATS(device_info->map_count++);
++
++ dma_addr = map_single(dev, buf, size, dir, attrs);
++ }
++
++ return dma_addr;
++}
++
++/*
++ * see if a mapped address was really a "safe" buffer and if so, copy
++ * the data from the safe buffer back to the unsafe buffer and free up
++ * the safe buffer. (basically return things back to the way they
++ * should be)
++ */
++static void
++dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
++ enum dma_data_direction dir, unsigned long attrs)
++{
++ struct safe_buffer *buf;
++
++ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
++ if (buf) {
++ DO_STATS(g_dmabounce_device_info->unmap_count++);
++ dma_addr = unmap_single(dev, buf, size, dir, attrs);
++ free_safe_buffer(g_dmabounce_device_info, buf);
++ }
++
++ arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
++}
++
++/*
++ * A version of dmabounce_map_page that assumes the mapping has already
++ * been created - intended for streaming operation.
++ */
++static void
++dmabounce_sync_for_device(struct device *dev, dma_addr_t dma_addr, size_t size,
++ enum dma_data_direction dir)
++{
++ struct safe_buffer *buf;
++
++ arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
++
++ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
++ if (buf) {
++ DO_STATS(g_dmabounce_device_info->sync_dev_count++);
++ map_single(dev, buf, size, dir, 0);
++ }
++}
++
++/*
++ * A version of dmabounce_unmap_page that doesn't destroy the mapping -
++ * intended for streaming operation.
++ */
++static void
++dmabounce_sync_for_cpu(struct device *dev, dma_addr_t dma_addr,
++ size_t size, enum dma_data_direction dir)
++{
++ struct safe_buffer *buf;
++
++ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
++ if (buf) {
++ DO_STATS(g_dmabounce_device_info->sync_cpu_count++);
++ dma_addr = unmap_single(dev, buf, size, dir, 0);
++ }
++
++ arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
++}
++
++static int dmabounce_dma_supported(struct device *dev, u64 dma_mask)
++{
++ if (g_dmabounce_device_info)
++ return 0;
++
++ return arm_dma_ops.dma_supported(dev, dma_mask);
++}
++
++static int dmabounce_mapping_error(struct device *dev, dma_addr_t dma_addr)
++{
++ return arm_dma_ops.mapping_error(dev, dma_addr);
++}
++
++static const struct dma_map_ops dmabounce_ops = {
++ .alloc = arm_dma_alloc,
++ .free = arm_dma_free,
++ .mmap = arm_dma_mmap,
++ .get_sgtable = arm_dma_get_sgtable,
++ .map_page = dmabounce_map_page,
++ .unmap_page = dmabounce_unmap_page,
++ .sync_single_for_cpu = dmabounce_sync_for_cpu,
++ .sync_single_for_device = dmabounce_sync_for_device,
++ .map_sg = arm_dma_map_sg,
++ .unmap_sg = arm_dma_unmap_sg,
++ .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
++ .sync_sg_for_device = arm_dma_sync_sg_for_device,
++ .dma_supported = dmabounce_dma_supported,
++ .mapping_error = dmabounce_mapping_error,
++};
++
++int brcm_pcie_bounce_register_dev(struct device *dev,
++ unsigned long buffer_size,
++ dma_addr_t threshold)
++{
++ struct dmabounce_device_info *device_info;
++ int ret;
++
++ /* Only support a single client */
++ if (g_dmabounce_device_info)
++ return -EBUSY;
++
++ ret = bcm2838_dma40_memcpy_init(dev);
++ if (ret)
++ return ret;
++
++ device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
++ if (!device_info) {
++ dev_err(dev,
++ "Could not allocated dmabounce_device_info\n");
++ return -ENOMEM;
++ }
++
++ ret = bounce_create(&device_info->pool, dev, buffer_size);
++ if (ret) {
++ dev_err(dev,
++ "dmabounce: could not allocate %ld byte DMA pool\n",
++ buffer_size);
++ goto err_bounce;
++ }
++
++ device_info->dev = dev;
++ device_info->threshold = threshold;
++ INIT_LIST_HEAD(&device_info->safe_buffers);
++ rwlock_init(&device_info->lock);
++
++ DO_STATS(device_info->map_count = 0);
++ DO_STATS(device_info->unmap_count = 0);
++ DO_STATS(device_info->sync_dev_count = 0);
++ DO_STATS(device_info->sync_cpu_count = 0);
++ DO_STATS(device_info->fail_count = 0);
++ DO_STATS(device_info->attr_res =
++ device_create_file(dev, &dev_attr_dmabounce_stats));
++
++ g_dmabounce_device_info = device_info;
++ set_dma_ops(dev, &dmabounce_ops);
++
++ dev_info(dev, "dmabounce: registered device - %ld kB, threshold %pad\n",
++ buffer_size / 1024, &threshold);
++
++ return 0;
++
++ err_bounce:
++ kfree(device_info);
++ return ret;
++}
++EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
++
++void brcm_pcie_bounce_unregister_dev(struct device *dev)
++{
++ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
++
++ g_dmabounce_device_info = NULL;
++ set_dma_ops(dev, NULL);
++
++ if (!device_info) {
++ dev_warn(dev,
++ "Never registered with dmabounce but attempting"
++ "to unregister!\n");
++ return;
++ }
++
++ if (!list_empty(&device_info->safe_buffers)) {
++ dev_err(dev,
++ "Removing from dmabounce with pending buffers!\n");
++ BUG();
++ }
++
++ bounce_destroy(&device_info->pool);
++
++ DO_STATS(if (device_info->attr_res == 0)
++ device_remove_file(dev, &dev_attr_dmabounce_stats));
++
++ kfree(device_info);
++
++ dev_info(dev, "dmabounce: device unregistered\n");
++}
++EXPORT_SYMBOL(brcm_pcie_bounce_unregister_dev);
++
++MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
+@@ -0,0 +1,32 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
++ */
++
++#ifndef _PCIE_BRCMSTB_BOUNCE_H
++#define _PCIE_BRCMSTB_BOUNCE_H
++
++#ifdef CONFIG_ARM
++
++int brcm_pcie_bounce_register_dev(struct device *dev, unsigned long buffer_size,
++ dma_addr_t threshold);
++
++int brcm_pcie_bounce_unregister_dev(struct device *dev);
++
++#else
++
++static inline int brcm_pcie_bounce_register_dev(struct device *dev,
++ unsigned long buffer_size,
++ dma_addr_t threshold)
++{
++ return 0;
++}
++
++static inline int brcm_pcie_bounce_unregister_dev(struct device *dev)
++{
++ return 0;
++}
++
++#endif
++
++#endif /* _PCIE_BRCMSTB_BOUNCE_H */
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -29,6 +29,7 @@
+ #include <linux/string.h>
+ #include <linux/types.h>
+ #include "../pci.h"
++#include "pcie-brcmstb-bounce.h"
+
+ /* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */
+ #define BRCM_PCIE_CAP_REGS 0x00ac
+@@ -53,6 +54,7 @@
+ #define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044
+ #define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048
+ #define PCIE_MISC_MSI_DATA_CONFIG 0x404c
++#define PCIE_MISC_EOI_CTRL 0x4060
+ #define PCIE_MISC_PCIE_CTRL 0x4064
+ #define PCIE_MISC_PCIE_STATUS 0x4068
+ #define PCIE_MISC_REVISION 0x406c
+@@ -260,12 +262,14 @@ struct brcm_pcie {
+ unsigned int rev;
+ const int *reg_offsets;
+ const int *reg_field_info;
++ u32 max_burst_size;
+ enum pcie_type type;
+ };
+
+ struct pcie_cfg_data {
+ const int *reg_field_info;
+ const int *offsets;
++ const u32 max_burst_size;
+ const enum pcie_type type;
+ };
+
+@@ -288,24 +292,27 @@ static const int pcie_offset_bcm7425[] =
+ static const struct pcie_cfg_data bcm7425_cfg = {
+ .reg_field_info = pcie_reg_field_info,
+ .offsets = pcie_offset_bcm7425,
++ .max_burst_size = BURST_SIZE_256,
+ .type = BCM7425,
+ };
+
+ static const int pcie_offsets[] = {
+ [RGR1_SW_INIT_1] = 0x9210,
+ [EXT_CFG_INDEX] = 0x9000,
+- [EXT_CFG_DATA] = 0x9004,
++ [EXT_CFG_DATA] = 0x8000,
+ };
+
+ static const struct pcie_cfg_data bcm7435_cfg = {
+ .reg_field_info = pcie_reg_field_info,
+ .offsets = pcie_offsets,
++ .max_burst_size = BURST_SIZE_256,
+ .type = BCM7435,
+ };
+
+ static const struct pcie_cfg_data generic_cfg = {
+ .reg_field_info = pcie_reg_field_info,
+ .offsets = pcie_offsets,
++ .max_burst_size = BURST_SIZE_128, // before BURST_SIZE_512
+ .type = GENERIC,
+ };
+
+@@ -318,6 +325,7 @@ static const int pcie_offset_bcm7278[] =
+ static const struct pcie_cfg_data bcm7278_cfg = {
+ .reg_field_info = pcie_reg_field_info_bcm7278,
+ .offsets = pcie_offset_bcm7278,
++ .max_burst_size = BURST_SIZE_512,
+ .type = BCM7278,
+ };
+
+@@ -360,7 +368,6 @@ static struct pci_ops brcm_pcie_ops = {
+ (reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
+
+ static const struct dma_map_ops *arch_dma_ops;
+-static const struct dma_map_ops *brcm_dma_ops_ptr;
+ static struct of_pci_range *dma_ranges;
+ static int num_dma_ranges;
+
+@@ -369,6 +376,16 @@ static int num_memc;
+ static int num_pcie;
+ static DEFINE_MUTEX(brcm_pcie_lock);
+
++static unsigned int bounce_buffer = 32*1024*1024;
++module_param(bounce_buffer, uint, 0644);
++MODULE_PARM_DESC(bounce_buffer, "Size of bounce buffer");
++
++static unsigned int bounce_threshold = 0xc0000000;
++module_param(bounce_threshold, uint, 0644);
++MODULE_PARM_DESC(bounce_threshold, "Bounce threshold");
++
++static struct brcm_pcie *g_pcie;
++
+ static dma_addr_t brcm_to_pci(dma_addr_t addr)
+ {
+ struct of_pci_range *p;
+@@ -457,12 +474,10 @@ static int brcm_map_sg(struct device *de
+ struct scatterlist *sg;
+
+ for_each_sg(sgl, sg, nents, i) {
+-#ifdef CONFIG_NEED_SG_DMA_LENGTH
+- sg->dma_length = sg->length;
+-#endif
++ sg_dma_len(sg) = sg->length;
+ sg->dma_address =
+- brcm_dma_ops_ptr->map_page(dev, sg_page(sg), sg->offset,
+- sg->length, dir, attrs);
++ brcm_map_page(dev, sg_page(sg), sg->offset,
++ sg->length, dir, attrs);
+ if (dma_mapping_error(dev, sg->dma_address))
+ goto bad_mapping;
+ }
+@@ -470,8 +485,8 @@ static int brcm_map_sg(struct device *de
+
+ bad_mapping:
+ for_each_sg(sgl, sg, i, j)
+- brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
+- sg_dma_len(sg), dir, attrs);
++ brcm_unmap_page(dev, sg_dma_address(sg),
++ sg_dma_len(sg), dir, attrs);
+ return 0;
+ }
+
+@@ -484,8 +499,8 @@ static void brcm_unmap_sg(struct device
+ struct scatterlist *sg;
+
+ for_each_sg(sgl, sg, nents, i)
+- brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
+- sg_dma_len(sg), dir, attrs);
++ brcm_unmap_page(dev, sg_dma_address(sg),
++ sg_dma_len(sg), dir, attrs);
+ }
+
+ static void brcm_sync_single_for_cpu(struct device *dev,
+@@ -531,8 +546,8 @@ void brcm_sync_sg_for_cpu(struct device
+ int i;
+
+ for_each_sg(sgl, sg, nents, i)
+- brcm_dma_ops_ptr->sync_single_for_cpu(dev, sg_dma_address(sg),
+- sg->length, dir);
++ brcm_sync_single_for_cpu(dev, sg_dma_address(sg),
++ sg->length, dir);
+ }
+
+ void brcm_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
+@@ -542,9 +557,9 @@ void brcm_sync_sg_for_device(struct devi
+ int i;
+
+ for_each_sg(sgl, sg, nents, i)
+- brcm_dma_ops_ptr->sync_single_for_device(dev,
+- sg_dma_address(sg),
+- sg->length, dir);
++ brcm_sync_single_for_device(dev,
++ sg_dma_address(sg),
++ sg->length, dir);
+ }
+
+ static int brcm_mapping_error(struct device *dev, dma_addr_t dma_addr)
+@@ -633,17 +648,47 @@ static void brcm_set_dma_ops(struct devi
+ set_dma_ops(dev, &brcm_dma_ops);
+ }
+
++static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
++ unsigned int val);
+ static int brcmstb_platform_notifier(struct notifier_block *nb,
+ unsigned long event, void *__dev)
+ {
++ extern unsigned long max_pfn;
+ struct device *dev = __dev;
++ const char *rc_name = "0000:00:00.0";
+
+- brcm_dma_ops_ptr = &brcm_dma_ops;
+- if (event != BUS_NOTIFY_ADD_DEVICE)
+- return NOTIFY_DONE;
++ switch (event) {
++ case BUS_NOTIFY_ADD_DEVICE:
++ if (max_pfn > (bounce_threshold/PAGE_SIZE) &&
++ strcmp(dev->kobj.name, rc_name)) {
++ int ret;
++
++ ret = brcm_pcie_bounce_register_dev(dev, bounce_buffer,
++ (dma_addr_t)bounce_threshold);
++ if (ret) {
++ dev_err(dev,
++ "brcm_pcie_bounce_register_dev() failed: %d\n",
++ ret);
++ return ret;
++ }
++ }
++ brcm_set_dma_ops(dev);
++ return NOTIFY_OK;
++
++ case BUS_NOTIFY_DEL_DEVICE:
++ if (!strcmp(dev->kobj.name, rc_name) && g_pcie) {
++ /* Force a bus reset */
++ brcm_pcie_perst_set(g_pcie, 1);
++ msleep(100);
++ brcm_pcie_perst_set(g_pcie, 0);
++ } else if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
++ brcm_pcie_bounce_unregister_dev(dev);
++ }
++ return NOTIFY_OK;
+
+- brcm_set_dma_ops(dev);
+- return NOTIFY_OK;
++ default:
++ return NOTIFY_DONE;
++ }
+ }
+
+ static struct notifier_block brcmstb_platform_nb = {
+@@ -914,6 +959,7 @@ static void brcm_pcie_msi_isr(struct irq
+ }
+ }
+ chained_irq_exit(chip, desc);
++ bcm_writel(1, msi->base + PCIE_MISC_EOI_CTRL);
+ }
+
+ static void brcm_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+@@ -930,7 +976,8 @@ static void brcm_compose_msi_msg(struct
+ static int brcm_msi_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *mask, bool force)
+ {
+- return -EINVAL;
++ struct brcm_msi *msi = irq_data_get_irq_chip_data(irq_data);
++ return __irq_set_affinity(msi->irq, mask, force);
+ }
+
+ static struct irq_chip brcm_msi_bottom_irq_chip = {
+@@ -1168,9 +1215,9 @@ static void __iomem *brcm_pcie_map_conf(
+ return PCI_SLOT(devfn) ? NULL : base + where;
+
+ /* For devices, write to the config space index register */
+- idx = cfg_index(bus->number, devfn, where);
++ idx = cfg_index(bus->number, devfn, 0);
+ bcm_writel(idx, pcie->base + IDX_ADDR(pcie));
+- return base + DATA_ADDR(pcie) + (where & 0x3);
++ return base + DATA_ADDR(pcie) + where;
+ }
+
+ static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie,
+@@ -1238,20 +1285,6 @@ static int brcm_pcie_parse_map_dma_range
+ num_dma_ranges++;
+ }
+
+- for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
+- u64 size = brcmstb_memory_memc_size(i);
+-
+- if (size == (u64)-1) {
+- dev_err(pcie->dev, "cannot get memc%d size", i);
+- return -EINVAL;
+- } else if (size) {
+- scb_size[i] = roundup_pow_of_two_64(size);
+- num_memc++;
+- } else {
+- break;
+- }
+- }
+-
+ return 0;
+ }
+
+@@ -1275,26 +1308,25 @@ static int brcm_pcie_add_controller(stru
+ if (ret)
+ goto done;
+
+- /* Determine num_memc and their sizes */
+- for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
+- u64 size = brcmstb_memory_memc_size(i);
+-
+- if (size == (u64)-1) {
+- dev_err(dev, "cannot get memc%d size\n", i);
+- ret = -EINVAL;
+- goto done;
+- } else if (size) {
+- scb_size[i] = roundup_pow_of_two_64(size);
+- num_memc++;
+- } else {
+- break;
++ if (!num_dma_ranges) {
++ /* Determine num_memc and their sizes by other means */
++ for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
++ u64 size = brcmstb_memory_memc_size(i);
++
++ if (size == (u64)-1) {
++ dev_err(dev, "cannot get memc%d size\n", i);
++ ret = -EINVAL;
++ goto done;
++ } else if (size) {
++ scb_size[i] = roundup_pow_of_two_64(size);
++ } else {
++ break;
++ }
+ }
+- }
+- if (!ret && num_memc == 0) {
+- ret = -EINVAL;
+- goto done;
++ num_memc = i;
+ }
+
++ g_pcie = pcie;
+ num_pcie++;
+ done:
+ mutex_unlock(&brcm_pcie_lock);
+@@ -1307,6 +1339,7 @@ static void brcm_pcie_remove_controller(
+ if (--num_pcie > 0)
+ goto out;
+
++ g_pcie = NULL;
+ if (brcm_unregister_notifier())
+ dev_err(pcie->dev, "failed to unregister pci bus notifier\n");
+ kfree(dma_ranges);
+@@ -1367,7 +1400,7 @@ static int brcm_pcie_setup(struct brcm_p
+ void __iomem *base = pcie->base;
+ unsigned int scb_size_val;
+ u64 rc_bar2_offset, rc_bar2_size, total_mem_size = 0;
+- u32 tmp, burst;
++ u32 tmp;
+ int i, j, ret, limit;
+ u16 nlw, cls, lnksta;
+ bool ssc_good = false;
+@@ -1400,20 +1433,15 @@ static int brcm_pcie_setup(struct brcm_p
+ /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
+ tmp = INSERT_FIELD(0, PCIE_MISC_MISC_CTRL, SCB_ACCESS_EN, 1);
+ tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, CFG_READ_UR_MODE, 1);
+- burst = (pcie->type == GENERIC || pcie->type == BCM7278)
+- ? BURST_SIZE_512 : BURST_SIZE_256;
+- tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, MAX_BURST_SIZE, burst);
++ tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, MAX_BURST_SIZE,
++ pcie->max_burst_size);
+ bcm_writel(tmp, base + PCIE_MISC_MISC_CTRL);
+
+ /*
+ * Set up inbound memory view for the EP (called RC_BAR2,
+ * not to be confused with the BARs that are advertised by
+ * the EP).
+- */
+- for (i = 0; i < num_memc; i++)
+- total_mem_size += scb_size[i];
+-
+- /*
++ *
+ * The PCIe host controller by design must set the inbound
+ * viewport to be a contiguous arrangement of all of the
+ * system's memory. In addition, its size mut be a power of
+@@ -1429,55 +1457,49 @@ static int brcm_pcie_setup(struct brcm_p
+ * the controller will know to send outbound memory downstream
+ * and everything else upstream.
+ */
+- rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
+
+- if (dma_ranges) {
++ if (num_dma_ranges) {
+ /*
+- * The best-case scenario is to place the inbound
+- * region in the first 4GB of pcie-space, as some
+- * legacy devices can only address 32bits.
+- * We would also like to put the MSI under 4GB
+- * as well, since some devices require a 32bit
+- * MSI target address.
++ * Use the base address and size(s) provided in the dma-ranges
++ * property.
+ */
+- if (total_mem_size <= 0xc0000000ULL &&
+- rc_bar2_size <= 0x100000000ULL) {
+- rc_bar2_offset = 0;
+- /* If the viewport is less then 4GB we can fit
+- * the MSI target address under 4GB. Otherwise
+- * put it right below 64GB.
+- */
+- msi_target_addr =
+- (rc_bar2_size == 0x100000000ULL)
+- ? BRCM_MSI_TARGET_ADDR_GT_4GB
+- : BRCM_MSI_TARGET_ADDR_LT_4GB;
+- } else {
+- /*
+- * The system memory is 4GB or larger so we
+- * cannot start the inbound region at location
+- * 0 (since we have to allow some space for
+- * outbound memory @ 3GB). So instead we
+- * start it at the 1x multiple of its size
+- */
+- rc_bar2_offset = rc_bar2_size;
+-
+- /* Since we are starting the viewport at 4GB or
+- * higher, put the MSI target address below 4GB
+- */
+- msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
+- }
+- } else {
++ for (i = 0; i < num_dma_ranges; i++)
++ scb_size[i] = roundup_pow_of_two_64(dma_ranges[i].size);
++
++ num_memc = num_dma_ranges;
++ rc_bar2_offset = dma_ranges[0].pci_addr;
++ } else if (num_memc) {
+ /*
+ * Set simple configuration based on memory sizes
+- * only. We always start the viewport at address 0,
+- * and set the MSI target address accordingly.
++ * only. We always start the viewport at address 0.
+ */
+ rc_bar2_offset = 0;
++ } else {
++ return -EINVAL;
++ }
++
++ for (i = 0; i < num_memc; i++)
++ total_mem_size += scb_size[i];
++
++ rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
+
+- msi_target_addr = (rc_bar2_size >= 0x100000000ULL)
+- ? BRCM_MSI_TARGET_ADDR_GT_4GB
+- : BRCM_MSI_TARGET_ADDR_LT_4GB;
++ /* Verify the alignment is correct */
++ if (rc_bar2_offset & (rc_bar2_size - 1)) {
++ dev_err(dev, "inbound window is misaligned\n");
++ return -EINVAL;
+ }
++
++ /*
++ * Position the MSI target low if possible.
++ *
++ * TO DO: Consider outbound window when choosing MSI target and
++ * verifying configuration.
++ */
++ msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
++ if (rc_bar2_offset <= msi_target_addr &&
++ rc_bar2_offset + rc_bar2_size > msi_target_addr)
++ msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB;
++
+ pcie->msi_target_addr = msi_target_addr;
+
+ tmp = lower_32_bits(rc_bar2_offset);
+@@ -1713,6 +1735,7 @@ static int brcm_pcie_probe(struct platfo
+ data = of_id->data;
+ pcie->reg_offsets = data->offsets;
+ pcie->reg_field_info = data->reg_field_info;
++ pcie->max_burst_size = data->max_burst_size;
+ pcie->type = data->type;
+ pcie->dn = dn;
+ pcie->dev = &pdev->dev;
+@@ -1732,7 +1755,7 @@ static int brcm_pcie_probe(struct platfo
+
+ pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
+ if (IS_ERR(pcie->clk)) {
+- dev_err(&pdev->dev, "could not get clock\n");
++ dev_warn(&pdev->dev, "could not get clock\n");
+ pcie->clk = NULL;
+ }
+ pcie->base = base;
+@@ -1755,7 +1778,8 @@ static int brcm_pcie_probe(struct platfo
+
+ ret = clk_prepare_enable(pcie->clk);
+ if (ret) {
+- dev_err(&pdev->dev, "could not enable clock\n");
++ if (ret != -EPROBE_DEFER)
++ dev_err(&pdev->dev, "could not enable clock\n");
+ return ret;
+ }
+
+@@ -1818,7 +1842,6 @@ static struct platform_driver brcm_pcie_
+ .remove = brcm_pcie_remove,
+ .driver = {
+ .name = "brcm-pcie",
+- .owner = THIS_MODULE,
+ .of_match_table = brcm_pcie_match,
+ .pm = &brcm_pcie_pm_ops,
+ },
+--- a/drivers/soc/bcm/brcmstb/Makefile
++++ b/drivers/soc/bcm/brcmstb/Makefile
+@@ -1,2 +1,2 @@
+-obj-y += common.o biuctrl.o
++obj-y += common.o biuctrl.o memory.o
+ obj-$(CONFIG_BRCMSTB_PM) += pm/
+--- /dev/null
++++ b/drivers/soc/bcm/brcmstb/memory.c
+@@ -0,0 +1,158 @@
++// SPDX-License-Identifier: GPL-2.0
++/* Copyright © 2015-2017 Broadcom */
++
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/libfdt.h>
++#include <linux/of_address.h>
++#include <linux/of_fdt.h>
++#include <linux/sizes.h>
++#include <soc/brcmstb/memory_api.h>
++
++/* Macro to help extract property data */
++#define DT_PROP_DATA_TO_U32(b, offs) (fdt32_to_cpu(*(u32 *)(b + offs)))
++
++/* Constants used when retrieving memc info */
++#define NUM_BUS_RANGES 10
++#define BUS_RANGE_ULIMIT_SHIFT 4
++#define BUS_RANGE_LLIMIT_SHIFT 4
++#define BUS_RANGE_PA_SHIFT 12
++
++enum {
++ BUSNUM_MCP0 = 0x4,
++ BUSNUM_MCP1 = 0x5,
++ BUSNUM_MCP2 = 0x6,
++};
++
++/*
++ * If the DT nodes are handy, determine which MEMC holds the specified
++ * physical address.
++ */
++#ifdef CONFIG_ARCH_BRCMSTB
++int __brcmstb_memory_phys_addr_to_memc(phys_addr_t pa, void __iomem *base)
++{
++ int memc = -1;
++ int i;
++
++ for (i = 0; i < NUM_BUS_RANGES; i++, base += 8) {
++ const u64 ulimit_raw = readl(base);
++ const u64 llimit_raw = readl(base + 4);
++ const u64 ulimit =
++ ((ulimit_raw >> BUS_RANGE_ULIMIT_SHIFT)
++ << BUS_RANGE_PA_SHIFT) | 0xfff;
++ const u64 llimit = (llimit_raw >> BUS_RANGE_LLIMIT_SHIFT)
++ << BUS_RANGE_PA_SHIFT;
++ const u32 busnum = (u32)(ulimit_raw & 0xf);
++
++ if (pa >= llimit && pa <= ulimit) {
++ if (busnum >= BUSNUM_MCP0 && busnum <= BUSNUM_MCP2) {
++ memc = busnum - BUSNUM_MCP0;
++ break;
++ }
++ }
++ }
++
++ return memc;
++}
++
++int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa)
++{
++ int memc = -1;
++ struct device_node *np;
++ void __iomem *cpubiuctrl;
++
++ np = of_find_compatible_node(NULL, NULL, "brcm,brcmstb-cpu-biu-ctrl");
++ if (!np)
++ return memc;
++
++ cpubiuctrl = of_iomap(np, 0);
++ if (!cpubiuctrl)
++ goto cleanup;
++
++ memc = __brcmstb_memory_phys_addr_to_memc(pa, cpubiuctrl);
++ iounmap(cpubiuctrl);
++
++cleanup:
++ of_node_put(np);
++
++ return memc;
++}
++
++#elif defined(CONFIG_MIPS)
++int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa)
++{
++ /* The logic here is fairly simple and hardcoded: if pa <= 0x5000_0000,
++ * then this is MEMC0, else MEMC1.
++ *
++ * For systems with 2GB on MEMC0, MEMC1 starts at 9000_0000, with 1GB
++ * on MEMC0, MEMC1 starts at 6000_0000.
++ */
++ if (pa >= 0x50000000ULL)
++ return 1;
++ else
++ return 0;
++}
++#endif
++
++u64 brcmstb_memory_memc_size(int memc)
++{
++ const void *fdt = initial_boot_params;
++ const int mem_offset = fdt_path_offset(fdt, "/memory");
++ int addr_cells = 1, size_cells = 1;
++ const struct fdt_property *prop;
++ int proplen, cellslen;
++ u64 memc_size = 0;
++ int i;
++
++ /* Get root size and address cells if specified */
++ prop = fdt_get_property(fdt, 0, "#size-cells", &proplen);
++ if (prop)
++ size_cells = DT_PROP_DATA_TO_U32(prop->data, 0);
++
++ prop = fdt_get_property(fdt, 0, "#address-cells", &proplen);
++ if (prop)
++ addr_cells = DT_PROP_DATA_TO_U32(prop->data, 0);
++
++ if (mem_offset < 0)
++ return -1;
++
++ prop = fdt_get_property(fdt, mem_offset, "reg", &proplen);
++ cellslen = (int)sizeof(u32) * (addr_cells + size_cells);
++ if ((proplen % cellslen) != 0)
++ return -1;
++
++ for (i = 0; i < proplen / cellslen; ++i) {
++ u64 addr = 0;
++ u64 size = 0;
++ int memc_idx;
++ int j;
++
++ for (j = 0; j < addr_cells; ++j) {
++ int offset = (cellslen * i) + (sizeof(u32) * j);
++
++ addr |= (u64)DT_PROP_DATA_TO_U32(prop->data, offset) <<
++ ((addr_cells - j - 1) * 32);
++ }
++ for (j = 0; j < size_cells; ++j) {
++ int offset = (cellslen * i) +
++ (sizeof(u32) * (j + addr_cells));
++
++ size |= (u64)DT_PROP_DATA_TO_U32(prop->data, offset) <<
++ ((size_cells - j - 1) * 32);
++ }
++
++ if ((phys_addr_t)addr != addr) {
++ pr_err("phys_addr_t is smaller than provided address 0x%llx!\n",
++ addr);
++ return -1;
++ }
++
++ memc_idx = brcmstb_memory_phys_addr_to_memc((phys_addr_t)addr);
++ if (memc_idx == memc)
++ memc_size += size;
++ }
++
++ return memc_size;
++}
++EXPORT_SYMBOL_GPL(brcmstb_memory_memc_size);
++
--- /dev/null
+From 9334afe7293b3a78b7e070a70880b2db7aa98365 Mon Sep 17 00:00:00 2001
+Date: Wed, 29 May 2019 15:47:42 +0100
+Subject: [PATCH] arm: bcm2835: DMA can only address 1GB
+
+The legacy peripherals can only address the first gigabyte of RAM, so
+ensure that DMA allocations are restricted to that region.
+
+---
+ arch/arm/mach-bcm/board_bcm2835.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -123,6 +123,9 @@ static const char * const bcm2835_compat
+ };
+
+ DT_MACHINE_START(BCM2835, "BCM2835")
++#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
++ .dma_zone_size = SZ_1G,
++#endif
+ .map_io = bcm2835_map_io,
+ .init_machine = bcm2835_init,
+ .dt_compat = bcm2835_compat,
+++ /dev/null
-From cb1acabb459677efbf95c54ce1dc5252be30a018 Mon Sep 17 00:00:00 2001
-Date: Mon, 15 Jan 2018 18:28:39 -0500
-Subject: [PATCH] dt-bindings: pci: Add DT docs for Brcmstb PCIe device
-
-The DT bindings description of the Brcmstb PCIe device is described. This
-node can be used by almost all Broadcom settop box chips, using
-ARM, ARM64, or MIPS CPU architectures.
-
----
- .../devicetree/bindings/pci/brcmstb-pcie.txt | 59 +++++++++++++++++++
- 1 file changed, 59 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/pci/brcmstb-pcie.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt
-@@ -0,0 +1,59 @@
-+Brcmstb PCIe Host Controller Device Tree Bindings
-+
-+Required Properties:
-+- compatible
-+ "brcm,bcm7425-pcie" -- for 7425 family MIPS-based SOCs.
-+ "brcm,bcm7435-pcie" -- for 7435 family MIPS-based SOCs.
-+ "brcm,bcm7445-pcie" -- for 7445 and later ARM based SOCs (not including
-+ the 7278).
-+ "brcm,bcm7278-pcie" -- for 7278 family ARM-based SOCs.
-+
-+- reg -- the register start address and length for the PCIe reg block.
-+- interrupts -- two interrupts are specified; the first interrupt is for
-+ the PCI host controller and the second is for MSI if the built-in
-+ MSI controller is to be used.
-+- interrupt-names -- names of the interrupts (above): "pcie" and "msi".
-+- #address-cells -- set to <3>.
-+- #size-cells -- set to <2>.
-+- #interrupt-cells: set to <1>.
-+- interrupt-map-mask and interrupt-map, standard PCI properties to define the
-+ mapping of the PCIe interface to interrupt numbers.
-+- ranges: ranges for the PCI memory and I/O regions.
-+- linux,pci-domain -- should be unique per host controller.
-+
-+Optional Properties:
-+- clocks -- phandle of pcie clock.
-+- clock-names -- set to "sw_pcie" if clocks is used.
-+- dma-ranges -- Specifies the inbound memory mapping regions when
-+ an "identity map" is not possible.
-+- msi-controller -- this property is typically specified to have the
-+ PCIe controller use its internal MSI controller.
-+- msi-parent -- set to use an external MSI interrupt controller.
-+- brcm,enable-ssc -- (boolean) indicates usage of spread-spectrum clocking.
-+- max-link-speed -- (integer) indicates desired generation of link:
-+ 1 => 2.5 Gbps (gen1), 2 => 5.0 Gbps (gen2), 3 => 8.0 Gbps (gen3).
-+
-+Example Node:
-+
-+pcie0: pcie@f0460000 {
-+ reg = <0x0 0xf0460000 0x0 0x9310>;
-+ interrupts = <0x0 0x0 0x4>;
-+ compatible = "brcm,bcm7445-pcie";
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+ ranges = <0x02000000 0x00000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x08000000
-+ 0x02000000 0x00000000 0x08000000 0x00000000 0xc8000000 0x00000000 0x08000000>;
-+ #interrupt-cells = <1>;
-+ interrupt-map-mask = <0 0 0 7>;
-+ interrupt-map = <0 0 0 1 &intc 0 47 3
-+ 0 0 0 2 &intc 0 48 3
-+ 0 0 0 3 &intc 0 49 3
-+ 0 0 0 4 &intc 0 50 3>;
-+ clocks = <&sw_pcie0>;
-+ clock-names = "sw_pcie";
-+ msi-parent = <&pcie0>; /* use PCIe's internal MSI controller */
-+ msi-controller; /* use PCIe's internal MSI controller */
-+ brcm,ssc;
-+ max-link-speed = <1>;
-+ linux,pci-domain = <0>;
-+ };
--- /dev/null
+From 8a58288d710a817b5dc7747f0bec1fb167368e7e Mon Sep 17 00:00:00 2001
+Date: Wed, 29 Aug 2018 09:05:15 +0100
+Subject: [PATCH] mmc: bcm2835-sdhost: Support 64-bit physical
+ addresses
+
+---
+ drivers/mmc/host/bcm2835-sdhost.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -148,7 +148,7 @@ struct bcm2835_host {
+ spinlock_t lock;
+
+ void __iomem *ioaddr;
+- u32 bus_addr;
++ phys_addr_t bus_addr;
+
+ struct mmc_host *mmc;
+
+@@ -246,8 +246,8 @@ static void log_init(struct device *dev,
+ sdhost_log_buf = dma_zalloc_coherent(dev, LOG_SIZE, &sdhost_log_addr,
+ GFP_KERNEL);
+ if (sdhost_log_buf) {
+- pr_info("sdhost: log_buf @ %p (%x)\n",
+- sdhost_log_buf, (u32)sdhost_log_addr);
++ pr_info("sdhost: log_buf @ %p (%llx)\n",
++ sdhost_log_buf, (u64)sdhost_log_addr);
+ timer_base = ioremap_nocache(bus_to_phys + 0x7e003000, SZ_4K);
+ if (!timer_base)
+ pr_err("sdhost: failed to remap timer\n");
+@@ -2024,6 +2024,7 @@ static int bcm2835_sdhost_probe(struct p
+ struct mmc_host *mmc;
+ const __be32 *addr;
+ u32 msg[3];
++ int na;
+ int ret;
+
+ pr_debug("bcm2835_sdhost_probe\n");
+@@ -2047,12 +2048,13 @@ static int bcm2835_sdhost_probe(struct p
+ goto err;
+ }
+
++ na = of_n_addr_cells(node);
+ addr = of_get_address(node, 0, NULL, NULL);
+ if (!addr) {
+ dev_err(dev, "could not get DMA-register address\n");
+ return -ENODEV;
+ }
+- host->bus_addr = be32_to_cpup(addr);
++ host->bus_addr = (phys_addr_t)of_read_number(addr, na);
+ pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
+ (unsigned long)host->ioaddr,
+ (unsigned long)iomem->start,
+++ /dev/null
-From 545951be6cabac8b1df85771c44335a0eaaa3c5d Mon Sep 17 00:00:00 2001
-Date: Tue, 19 Feb 2019 22:06:59 +0000
-Subject: [PATCH] pcie-brcmstb: Changes for BCM2711
-
-The initial brcmstb PCIe driver - originally taken from the V3(?)
-patch set - has been modified significantly for the BCM2711.
-
----
- drivers/dma/bcm2835-dma.c | 107 ++++
- drivers/pci/controller/Makefile | 4 +
- drivers/pci/controller/pcie-brcmstb-bounce.c | 564 +++++++++++++++++++
- drivers/pci/controller/pcie-brcmstb-bounce.h | 32 ++
- drivers/pci/controller/pcie-brcmstb.c | 237 ++++----
- drivers/soc/bcm/brcmstb/Makefile | 2 +-
- drivers/soc/bcm/brcmstb/memory.c | 158 ++++++
- 7 files changed, 996 insertions(+), 108 deletions(-)
- create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce.c
- create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce.h
- create mode 100644 drivers/soc/bcm/brcmstb/memory.c
-
---- a/drivers/dma/bcm2835-dma.c
-+++ b/drivers/dma/bcm2835-dma.c
-@@ -68,6 +68,17 @@ struct bcm2835_dma_cb {
- uint32_t pad[2];
- };
-
-+struct bcm2838_dma40_scb {
-+ uint32_t ti;
-+ uint32_t src;
-+ uint32_t srci;
-+ uint32_t dst;
-+ uint32_t dsti;
-+ uint32_t len;
-+ uint32_t next_cb;
-+ uint32_t rsvd;
-+};
-+
- struct bcm2835_cb_entry {
- struct bcm2835_dma_cb *cb;
- dma_addr_t paddr;
-@@ -185,6 +196,45 @@ struct bcm2835_desc {
- #define MAX_DMA_LEN SZ_1G
- #define MAX_LITE_DMA_LEN (SZ_64K - 4)
-
-+/* 40-bit DMA support */
-+#define BCM2838_DMA40_CS 0x00
-+#define BCM2838_DMA40_CB 0x04
-+#define BCM2838_DMA40_DEBUG 0x0c
-+#define BCM2858_DMA40_TI 0x10
-+#define BCM2838_DMA40_SRC 0x14
-+#define BCM2838_DMA40_SRCI 0x18
-+#define BCM2838_DMA40_DEST 0x1c
-+#define BCM2838_DMA40_DESTI 0x20
-+#define BCM2838_DMA40_LEN 0x24
-+#define BCM2838_DMA40_NEXT_CB 0x28
-+#define BCM2838_DMA40_DEBUG2 0x2c
-+
-+#define BCM2838_DMA40_CS_ACTIVE BIT(0)
-+#define BCM2838_DMA40_CS_END BIT(1)
-+
-+#define BCM2838_DMA40_CS_QOS(x) (((x) & 0x1f) << 16)
-+#define BCM2838_DMA40_CS_PANIC_QOS(x) (((x) & 0x1f) << 20)
-+#define BCM2838_DMA40_CS_WRITE_WAIT BIT(28)
-+
-+#define BCM2838_DMA40_BURST_LEN(x) ((((x) - 1) & 0xf) << 8)
-+#define BCM2838_DMA40_INC BIT(12)
-+#define BCM2838_DMA40_SIZE_128 (2 << 13)
-+
-+#define BCM2838_DMA40_MEMCPY_QOS \
-+ (BCM2838_DMA40_CS_QOS(0x0) | \
-+ BCM2838_DMA40_CS_PANIC_QOS(0x0) | \
-+ BCM2838_DMA40_CS_WRITE_WAIT)
-+
-+#define BCM2838_DMA40_MEMCPY_XFER_INFO \
-+ (BCM2838_DMA40_SIZE_128 | \
-+ BCM2838_DMA40_INC | \
-+ BCM2838_DMA40_BURST_LEN(16))
-+
-+static void __iomem *memcpy_chan;
-+static struct bcm2838_dma40_scb *memcpy_scb;
-+static dma_addr_t memcpy_scb_dma;
-+DEFINE_SPINLOCK(memcpy_lock);
-+
- static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
- {
- /* lite and normal channels have different max frame length */
-@@ -868,6 +918,56 @@ static void bcm2835_dma_free(struct bcm2
- }
- }
-
-+int bcm2838_dma40_memcpy_init(struct device *dev)
-+{
-+ if (memcpy_scb)
-+ return 0;
-+
-+ memcpy_scb = dma_alloc_coherent(dev, sizeof(*memcpy_scb),
-+ &memcpy_scb_dma, GFP_KERNEL);
-+
-+ if (!memcpy_scb) {
-+ pr_err("bcm2838_dma40_memcpy_init failed!\n");
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(bcm2838_dma40_memcpy_init);
-+
-+void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size)
-+{
-+ struct bcm2838_dma40_scb *scb = memcpy_scb;
-+ unsigned long flags;
-+
-+ if (!scb) {
-+ pr_err("bcm2838_dma40_memcpy not initialised!\n");
-+ return;
-+ }
-+
-+ spin_lock_irqsave(&memcpy_lock, flags);
-+
-+ scb->ti = 0;
-+ scb->src = lower_32_bits(src);
-+ scb->srci = upper_32_bits(src) | BCM2838_DMA40_MEMCPY_XFER_INFO;
-+ scb->dst = lower_32_bits(dst);
-+ scb->dsti = upper_32_bits(dst) | BCM2838_DMA40_MEMCPY_XFER_INFO;
-+ scb->len = size;
-+ scb->next_cb = 0;
-+
-+ writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2838_DMA40_CB);
-+ writel(BCM2838_DMA40_MEMCPY_QOS + BCM2838_DMA40_CS_ACTIVE,
-+ memcpy_chan + BCM2838_DMA40_CS);
-+ /* Poll for completion */
-+ while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_CS_END))
-+ cpu_relax();
-+
-+ writel(BCM2838_DMA40_CS_END, memcpy_chan + BCM2838_DMA40_CS);
-+
-+ spin_unlock_irqrestore(&memcpy_lock, flags);
-+}
-+EXPORT_SYMBOL(bcm2838_dma40_memcpy);
-+
- static const struct of_device_id bcm2835_dma_of_match[] = {
- { .compatible = "brcm,bcm2835-dma", },
- {},
-@@ -966,6 +1066,13 @@ static int bcm2835_dma_probe(struct plat
- /* Channel 0 is used by the legacy API */
- chans_available &= ~BCM2835_DMA_BULK_MASK;
-
-+ /* We can't use channels 11-13 yet */
-+ chans_available &= ~(BIT(11) | BIT(12) | BIT(13));
-+
-+ /* Grab channel 14 for the 40-bit DMA memcpy */
-+ chans_available &= ~BIT(14);
-+ memcpy_chan = BCM2835_DMA_CHANIO(base, 14);
-+
- /* get irqs for each channel that we support */
- for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
- /* skip masked out channels */
---- a/drivers/pci/controller/Makefile
-+++ b/drivers/pci/controller/Makefile
-@@ -29,6 +29,10 @@ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-medi
- obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
- obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
- obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
-+ifdef CONFIG_ARM
-+obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce.o
-+endif
-+
- obj-$(CONFIG_VMD) += vmd.o
- # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
- obj-y += dwc/
---- /dev/null
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.c
-@@ -0,0 +1,564 @@
-+/*
-+ * This code started out as a version of arch/arm/common/dmabounce.c,
-+ * modified to cope with highmem pages. Now it has been changed heavily -
-+ * it now preallocates a large block (currently 4MB) and carves it up
-+ * sequentially in ring fashion, and DMA is used to copy the data - to the
-+ * point where very little of the original remains.
-+ *
-+ * Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
-+ *
-+ *
-+ * Copyright (C) 2002 Hewlett Packard Company.
-+ * Copyright (C) 2004 MontaVista Software, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/page-flags.h>
-+#include <linux/device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dmapool.h>
-+#include <linux/list.h>
-+#include <linux/scatterlist.h>
-+#include <linux/bitmap.h>
-+
-+#include <asm/cacheflush.h>
-+#include <asm/dma-iommu.h>
-+
-+#define STATS
-+
-+#ifdef STATS
-+#define DO_STATS(X) do { X ; } while (0)
-+#else
-+#define DO_STATS(X) do { } while (0)
-+#endif
-+
-+/* ************************************************** */
-+
-+struct safe_buffer {
-+ struct list_head node;
-+
-+ /* original request */
-+ size_t size;
-+ int direction;
-+
-+ struct dmabounce_pool *pool;
-+ void *safe;
-+ dma_addr_t unsafe_dma_addr;
-+ dma_addr_t safe_dma_addr;
-+};
-+
-+struct dmabounce_pool {
-+ unsigned long pages;
-+ void *virt_addr;
-+ dma_addr_t dma_addr;
-+ unsigned long *alloc_map;
-+ unsigned long alloc_pos;
-+ spinlock_t lock;
-+ struct device *dev;
-+ unsigned long num_pages;
-+#ifdef STATS
-+ size_t max_size;
-+ unsigned long num_bufs;
-+ unsigned long max_bufs;
-+ unsigned long max_pages;
-+#endif
-+};
-+
-+struct dmabounce_device_info {
-+ struct device *dev;
-+ dma_addr_t threshold;
-+ struct list_head safe_buffers;
-+ struct dmabounce_pool pool;
-+ rwlock_t lock;
-+#ifdef STATS
-+ unsigned long map_count;
-+ unsigned long unmap_count;
-+ unsigned long sync_dev_count;
-+ unsigned long sync_cpu_count;
-+ unsigned long fail_count;
-+ int attr_res;
-+#endif
-+};
-+
-+static struct dmabounce_device_info *g_dmabounce_device_info;
-+
-+extern int bcm2838_dma40_memcpy_init(struct device *dev);
-+extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-+
-+#ifdef STATS
-+static ssize_t
-+bounce_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+ return sprintf(buf, "m:%lu/%lu s:%lu/%lu f:%lu s:%zu b:%lu/%lu a:%lu/%lu\n",
-+ device_info->map_count,
-+ device_info->unmap_count,
-+ device_info->sync_dev_count,
-+ device_info->sync_cpu_count,
-+ device_info->fail_count,
-+ device_info->pool.max_size,
-+ device_info->pool.num_bufs,
-+ device_info->pool.max_bufs,
-+ device_info->pool.num_pages * PAGE_SIZE,
-+ device_info->pool.max_pages * PAGE_SIZE);
-+}
-+
-+static DEVICE_ATTR(dmabounce_stats, 0444, bounce_show, NULL);
-+#endif
-+
-+static int bounce_create(struct dmabounce_pool *pool, struct device *dev,
-+ unsigned long buffer_size)
-+{
-+ int ret = -ENOMEM;
-+ pool->pages = (buffer_size + PAGE_SIZE - 1)/PAGE_SIZE;
-+ pool->alloc_map = bitmap_zalloc(pool->pages, GFP_KERNEL);
-+ if (!pool->alloc_map)
-+ goto err_bitmap;
-+ pool->virt_addr = dma_alloc_coherent(dev, pool->pages * PAGE_SIZE,
-+ &pool->dma_addr, GFP_KERNEL);
-+ if (!pool->virt_addr)
-+ goto err_dmabuf;
-+
-+ pool->alloc_pos = 0;
-+ spin_lock_init(&pool->lock);
-+ pool->dev = dev;
-+ pool->num_pages = 0;
-+
-+ DO_STATS(pool->max_size = 0);
-+ DO_STATS(pool->num_bufs = 0);
-+ DO_STATS(pool->max_bufs = 0);
-+ DO_STATS(pool->max_pages = 0);
-+
-+ return 0;
-+
-+err_dmabuf:
-+ bitmap_free(pool->alloc_map);
-+err_bitmap:
-+ return ret;
-+}
-+
-+static void bounce_destroy(struct dmabounce_pool *pool)
-+{
-+ dma_free_coherent(pool->dev, pool->pages * PAGE_SIZE, pool->virt_addr,
-+ pool->dma_addr);
-+
-+ bitmap_free(pool->alloc_map);
-+}
-+
-+static void *bounce_alloc(struct dmabounce_pool *pool, size_t size,
-+ dma_addr_t *dmaaddrp)
-+{
-+ unsigned long pages;
-+ unsigned long flags;
-+ unsigned long pos;
-+
-+ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
-+
-+ DO_STATS(pool->max_size = max(size, pool->max_size));
-+
-+ spin_lock_irqsave(&pool->lock, flags);
-+ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
-+ pool->alloc_pos, pages, 0);
-+ /* If not found, try from the start */
-+ if (pos >= pool->pages && pool->alloc_pos)
-+ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
-+ 0, pages, 0);
-+
-+ if (pos >= pool->pages) {
-+ spin_unlock_irqrestore(&pool->lock, flags);
-+ return NULL;
-+ }
-+
-+ bitmap_set(pool->alloc_map, pos, pages);
-+ pool->alloc_pos = (pos + pages) % pool->pages;
-+ pool->num_pages += pages;
-+
-+ DO_STATS(pool->num_bufs++);
-+ DO_STATS(pool->max_bufs = max(pool->num_bufs, pool->max_bufs));
-+ DO_STATS(pool->max_pages = max(pool->num_pages, pool->max_pages));
-+
-+ spin_unlock_irqrestore(&pool->lock, flags);
-+
-+ *dmaaddrp = pool->dma_addr + pos * PAGE_SIZE;
-+
-+ return pool->virt_addr + pos * PAGE_SIZE;
-+}
-+
-+static void
-+bounce_free(struct dmabounce_pool *pool, void *buf, size_t size)
-+{
-+ unsigned long pages;
-+ unsigned long flags;
-+ unsigned long pos;
-+
-+ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
-+ pos = (buf - pool->virt_addr)/PAGE_SIZE;
-+
-+ BUG_ON((buf - pool->virt_addr) & (PAGE_SIZE - 1));
-+
-+ spin_lock_irqsave(&pool->lock, flags);
-+ bitmap_clear(pool->alloc_map, pos, pages);
-+ pool->num_pages -= pages;
-+ if (pool->num_pages == 0)
-+ pool->alloc_pos = 0;
-+ DO_STATS(pool->num_bufs--);
-+ spin_unlock_irqrestore(&pool->lock, flags);
-+}
-+
-+/* allocate a 'safe' buffer and keep track of it */
-+static struct safe_buffer *
-+alloc_safe_buffer(struct dmabounce_device_info *device_info,
-+ dma_addr_t dma_addr, size_t size, enum dma_data_direction dir)
-+{
-+ struct safe_buffer *buf;
-+ struct dmabounce_pool *pool = &device_info->pool;
-+ struct device *dev = device_info->dev;
-+ unsigned long flags;
-+
-+ /*
-+ * Although one might expect this to be called in thread context,
-+ * using GFP_KERNEL here leads to hard-to-debug lockups. in_atomic()
-+ * was previously used to select the appropriate allocation mode,
-+ * but this is unsafe.
-+ */
-+ buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
-+ if (!buf) {
-+ dev_warn(dev, "%s: kmalloc failed\n", __func__);
-+ return NULL;
-+ }
-+
-+ buf->unsafe_dma_addr = dma_addr;
-+ buf->size = size;
-+ buf->direction = dir;
-+ buf->pool = pool;
-+
-+ buf->safe = bounce_alloc(pool, size, &buf->safe_dma_addr);
-+
-+ if (!buf->safe) {
-+ dev_warn(dev,
-+ "%s: could not alloc dma memory (size=%d)\n",
-+ __func__, size);
-+ kfree(buf);
-+ return NULL;
-+ }
-+
-+ write_lock_irqsave(&device_info->lock, flags);
-+ list_add(&buf->node, &device_info->safe_buffers);
-+ write_unlock_irqrestore(&device_info->lock, flags);
-+
-+ return buf;
-+}
-+
-+/* determine if a buffer is from our "safe" pool */
-+static struct safe_buffer *
-+find_safe_buffer(struct dmabounce_device_info *device_info,
-+ dma_addr_t safe_dma_addr)
-+{
-+ struct safe_buffer *b, *rb = NULL;
-+ unsigned long flags;
-+
-+ read_lock_irqsave(&device_info->lock, flags);
-+
-+ list_for_each_entry(b, &device_info->safe_buffers, node)
-+ if (b->safe_dma_addr <= safe_dma_addr &&
-+ b->safe_dma_addr + b->size > safe_dma_addr) {
-+ rb = b;
-+ break;
-+ }
-+
-+ read_unlock_irqrestore(&device_info->lock, flags);
-+ return rb;
-+}
-+
-+static void
-+free_safe_buffer(struct dmabounce_device_info *device_info,
-+ struct safe_buffer *buf)
-+{
-+ unsigned long flags;
-+
-+ write_lock_irqsave(&device_info->lock, flags);
-+ list_del(&buf->node);
-+ write_unlock_irqrestore(&device_info->lock, flags);
-+
-+ bounce_free(buf->pool, buf->safe, buf->size);
-+
-+ kfree(buf);
-+}
-+
-+/* ************************************************** */
-+
-+static struct safe_buffer *
-+find_safe_buffer_dev(struct device *dev, dma_addr_t dma_addr, const char *where)
-+{
-+ if (!dev || !g_dmabounce_device_info)
-+ return NULL;
-+ if (dma_mapping_error(dev, dma_addr)) {
-+ dev_err(dev, "Trying to %s invalid mapping\n", where);
-+ return NULL;
-+ }
-+ return find_safe_buffer(g_dmabounce_device_info, dma_addr);
-+}
-+
-+static dma_addr_t
-+map_single(struct device *dev, struct safe_buffer *buf, size_t size,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ BUG_ON(buf->size != size);
-+ BUG_ON(buf->direction != dir);
-+
-+ dev_dbg(dev, "map: %llx->%llx\n", (u64)buf->unsafe_dma_addr,
-+ (u64)buf->safe_dma_addr);
-+
-+ if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-+ !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-+ bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
-+ size);
-+
-+ return buf->safe_dma_addr;
-+}
-+
-+static dma_addr_t
-+unmap_single(struct device *dev, struct safe_buffer *buf, size_t size,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ BUG_ON(buf->size != size);
-+ BUG_ON(buf->direction != dir);
-+
-+ if ((dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-+ !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
-+ dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
-+ (u64)buf->unsafe_dma_addr);
-+
-+ bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
-+ size);
-+ }
-+ return buf->unsafe_dma_addr;
-+}
-+
-+/* ************************************************** */
-+
-+/*
-+ * see if a buffer address is in an 'unsafe' range. if it is
-+ * allocate a 'safe' buffer and copy the unsafe buffer into it.
-+ * substitute the safe buffer for the unsafe one.
-+ * (basically move the buffer from an unsafe area to a safe one)
-+ */
-+static dma_addr_t
-+dmabounce_map_page(struct device *dev, struct page *page, unsigned long offset,
-+ size_t size, enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+ dma_addr_t dma_addr;
-+
-+ dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset;
-+
-+ arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
-+
-+ if (device_info && (dma_addr + size) > device_info->threshold) {
-+ struct safe_buffer *buf;
-+
-+ buf = alloc_safe_buffer(device_info, dma_addr, size, dir);
-+ if (!buf) {
-+ DO_STATS(device_info->fail_count++);
-+ return ARM_MAPPING_ERROR;
-+ }
-+
-+ DO_STATS(device_info->map_count++);
-+
-+ dma_addr = map_single(dev, buf, size, dir, attrs);
-+ }
-+
-+ return dma_addr;
-+}
-+
-+/*
-+ * see if a mapped address was really a "safe" buffer and if so, copy
-+ * the data from the safe buffer back to the unsafe buffer and free up
-+ * the safe buffer. (basically return things back to the way they
-+ * should be)
-+ */
-+static void
-+dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ struct safe_buffer *buf;
-+
-+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+ if (buf) {
-+ DO_STATS(g_dmabounce_device_info->unmap_count++);
-+ dma_addr = unmap_single(dev, buf, size, dir, attrs);
-+ free_safe_buffer(g_dmabounce_device_info, buf);
-+ }
-+
-+ arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
-+}
-+
-+/*
-+ * A version of dmabounce_map_page that assumes the mapping has already
-+ * been created - intended for streaming operation.
-+ */
-+static void
-+dmabounce_sync_for_device(struct device *dev, dma_addr_t dma_addr, size_t size,
-+ enum dma_data_direction dir)
-+{
-+ struct safe_buffer *buf;
-+
-+ arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
-+
-+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+ if (buf) {
-+ DO_STATS(g_dmabounce_device_info->sync_dev_count++);
-+ map_single(dev, buf, size, dir, 0);
-+ }
-+}
-+
-+/*
-+ * A version of dmabounce_unmap_page that doesn't destroy the mapping -
-+ * intended for streaming operation.
-+ */
-+static void
-+dmabounce_sync_for_cpu(struct device *dev, dma_addr_t dma_addr,
-+ size_t size, enum dma_data_direction dir)
-+{
-+ struct safe_buffer *buf;
-+
-+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+ if (buf) {
-+ DO_STATS(g_dmabounce_device_info->sync_cpu_count++);
-+ dma_addr = unmap_single(dev, buf, size, dir, 0);
-+ }
-+
-+ arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
-+}
-+
-+static int dmabounce_dma_supported(struct device *dev, u64 dma_mask)
-+{
-+ if (g_dmabounce_device_info)
-+ return 0;
-+
-+ return arm_dma_ops.dma_supported(dev, dma_mask);
-+}
-+
-+static int dmabounce_mapping_error(struct device *dev, dma_addr_t dma_addr)
-+{
-+ return arm_dma_ops.mapping_error(dev, dma_addr);
-+}
-+
-+static const struct dma_map_ops dmabounce_ops = {
-+ .alloc = arm_dma_alloc,
-+ .free = arm_dma_free,
-+ .mmap = arm_dma_mmap,
-+ .get_sgtable = arm_dma_get_sgtable,
-+ .map_page = dmabounce_map_page,
-+ .unmap_page = dmabounce_unmap_page,
-+ .sync_single_for_cpu = dmabounce_sync_for_cpu,
-+ .sync_single_for_device = dmabounce_sync_for_device,
-+ .map_sg = arm_dma_map_sg,
-+ .unmap_sg = arm_dma_unmap_sg,
-+ .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
-+ .sync_sg_for_device = arm_dma_sync_sg_for_device,
-+ .dma_supported = dmabounce_dma_supported,
-+ .mapping_error = dmabounce_mapping_error,
-+};
-+
-+int brcm_pcie_bounce_register_dev(struct device *dev,
-+ unsigned long buffer_size,
-+ dma_addr_t threshold)
-+{
-+ struct dmabounce_device_info *device_info;
-+ int ret;
-+
-+ /* Only support a single client */
-+ if (g_dmabounce_device_info)
-+ return -EBUSY;
-+
-+ ret = bcm2838_dma40_memcpy_init(dev);
-+ if (ret)
-+ return ret;
-+
-+ device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
-+ if (!device_info) {
-+ dev_err(dev,
-+ "Could not allocated dmabounce_device_info\n");
-+ return -ENOMEM;
-+ }
-+
-+ ret = bounce_create(&device_info->pool, dev, buffer_size);
-+ if (ret) {
-+ dev_err(dev,
-+ "dmabounce: could not allocate %ld byte DMA pool\n",
-+ buffer_size);
-+ goto err_bounce;
-+ }
-+
-+ device_info->dev = dev;
-+ device_info->threshold = threshold;
-+ INIT_LIST_HEAD(&device_info->safe_buffers);
-+ rwlock_init(&device_info->lock);
-+
-+ DO_STATS(device_info->map_count = 0);
-+ DO_STATS(device_info->unmap_count = 0);
-+ DO_STATS(device_info->sync_dev_count = 0);
-+ DO_STATS(device_info->sync_cpu_count = 0);
-+ DO_STATS(device_info->fail_count = 0);
-+ DO_STATS(device_info->attr_res =
-+ device_create_file(dev, &dev_attr_dmabounce_stats));
-+
-+ g_dmabounce_device_info = device_info;
-+ set_dma_ops(dev, &dmabounce_ops);
-+
-+ dev_info(dev, "dmabounce: registered device - %ld kB, threshold %pad\n",
-+ buffer_size / 1024, &threshold);
-+
-+ return 0;
-+
-+ err_bounce:
-+ kfree(device_info);
-+ return ret;
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
-+
-+void brcm_pcie_bounce_unregister_dev(struct device *dev)
-+{
-+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+
-+ g_dmabounce_device_info = NULL;
-+ set_dma_ops(dev, NULL);
-+
-+ if (!device_info) {
-+ dev_warn(dev,
-+ "Never registered with dmabounce but attempting"
-+ "to unregister!\n");
-+ return;
-+ }
-+
-+ if (!list_empty(&device_info->safe_buffers)) {
-+ dev_err(dev,
-+ "Removing from dmabounce with pending buffers!\n");
-+ BUG();
-+ }
-+
-+ bounce_destroy(&device_info->pool);
-+
-+ DO_STATS(if (device_info->attr_res == 0)
-+ device_remove_file(dev, &dev_attr_dmabounce_stats));
-+
-+ kfree(device_info);
-+
-+ dev_info(dev, "dmabounce: device unregistered\n");
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_unregister_dev);
-+
-+MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
-+ */
-+
-+#ifndef _PCIE_BRCMSTB_BOUNCE_H
-+#define _PCIE_BRCMSTB_BOUNCE_H
-+
-+#ifdef CONFIG_ARM
-+
-+int brcm_pcie_bounce_register_dev(struct device *dev, unsigned long buffer_size,
-+ dma_addr_t threshold);
-+
-+int brcm_pcie_bounce_unregister_dev(struct device *dev);
-+
-+#else
-+
-+static inline int brcm_pcie_bounce_register_dev(struct device *dev,
-+ unsigned long buffer_size,
-+ dma_addr_t threshold)
-+{
-+ return 0;
-+}
-+
-+static inline int brcm_pcie_bounce_unregister_dev(struct device *dev)
-+{
-+ return 0;
-+}
-+
-+#endif
-+
-+#endif /* _PCIE_BRCMSTB_BOUNCE_H */
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -29,6 +29,7 @@
- #include <linux/string.h>
- #include <linux/types.h>
- #include "../pci.h"
-+#include "pcie-brcmstb-bounce.h"
-
- /* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */
- #define BRCM_PCIE_CAP_REGS 0x00ac
-@@ -53,6 +54,7 @@
- #define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044
- #define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048
- #define PCIE_MISC_MSI_DATA_CONFIG 0x404c
-+#define PCIE_MISC_EOI_CTRL 0x4060
- #define PCIE_MISC_PCIE_CTRL 0x4064
- #define PCIE_MISC_PCIE_STATUS 0x4068
- #define PCIE_MISC_REVISION 0x406c
-@@ -260,12 +262,14 @@ struct brcm_pcie {
- unsigned int rev;
- const int *reg_offsets;
- const int *reg_field_info;
-+ u32 max_burst_size;
- enum pcie_type type;
- };
-
- struct pcie_cfg_data {
- const int *reg_field_info;
- const int *offsets;
-+ const u32 max_burst_size;
- const enum pcie_type type;
- };
-
-@@ -288,24 +292,27 @@ static const int pcie_offset_bcm7425[] =
- static const struct pcie_cfg_data bcm7425_cfg = {
- .reg_field_info = pcie_reg_field_info,
- .offsets = pcie_offset_bcm7425,
-+ .max_burst_size = BURST_SIZE_256,
- .type = BCM7425,
- };
-
- static const int pcie_offsets[] = {
- [RGR1_SW_INIT_1] = 0x9210,
- [EXT_CFG_INDEX] = 0x9000,
-- [EXT_CFG_DATA] = 0x9004,
-+ [EXT_CFG_DATA] = 0x8000,
- };
-
- static const struct pcie_cfg_data bcm7435_cfg = {
- .reg_field_info = pcie_reg_field_info,
- .offsets = pcie_offsets,
-+ .max_burst_size = BURST_SIZE_256,
- .type = BCM7435,
- };
-
- static const struct pcie_cfg_data generic_cfg = {
- .reg_field_info = pcie_reg_field_info,
- .offsets = pcie_offsets,
-+ .max_burst_size = BURST_SIZE_128, // before BURST_SIZE_512
- .type = GENERIC,
- };
-
-@@ -318,6 +325,7 @@ static const int pcie_offset_bcm7278[] =
- static const struct pcie_cfg_data bcm7278_cfg = {
- .reg_field_info = pcie_reg_field_info_bcm7278,
- .offsets = pcie_offset_bcm7278,
-+ .max_burst_size = BURST_SIZE_512,
- .type = BCM7278,
- };
-
-@@ -360,7 +368,6 @@ static struct pci_ops brcm_pcie_ops = {
- (reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
-
- static const struct dma_map_ops *arch_dma_ops;
--static const struct dma_map_ops *brcm_dma_ops_ptr;
- static struct of_pci_range *dma_ranges;
- static int num_dma_ranges;
-
-@@ -369,6 +376,16 @@ static int num_memc;
- static int num_pcie;
- static DEFINE_MUTEX(brcm_pcie_lock);
-
-+static unsigned int bounce_buffer = 32*1024*1024;
-+module_param(bounce_buffer, uint, 0644);
-+MODULE_PARM_DESC(bounce_buffer, "Size of bounce buffer");
-+
-+static unsigned int bounce_threshold = 0xc0000000;
-+module_param(bounce_threshold, uint, 0644);
-+MODULE_PARM_DESC(bounce_threshold, "Bounce threshold");
-+
-+static struct brcm_pcie *g_pcie;
-+
- static dma_addr_t brcm_to_pci(dma_addr_t addr)
- {
- struct of_pci_range *p;
-@@ -457,12 +474,10 @@ static int brcm_map_sg(struct device *de
- struct scatterlist *sg;
-
- for_each_sg(sgl, sg, nents, i) {
--#ifdef CONFIG_NEED_SG_DMA_LENGTH
-- sg->dma_length = sg->length;
--#endif
-+ sg_dma_len(sg) = sg->length;
- sg->dma_address =
-- brcm_dma_ops_ptr->map_page(dev, sg_page(sg), sg->offset,
-- sg->length, dir, attrs);
-+ brcm_map_page(dev, sg_page(sg), sg->offset,
-+ sg->length, dir, attrs);
- if (dma_mapping_error(dev, sg->dma_address))
- goto bad_mapping;
- }
-@@ -470,8 +485,8 @@ static int brcm_map_sg(struct device *de
-
- bad_mapping:
- for_each_sg(sgl, sg, i, j)
-- brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
-- sg_dma_len(sg), dir, attrs);
-+ brcm_unmap_page(dev, sg_dma_address(sg),
-+ sg_dma_len(sg), dir, attrs);
- return 0;
- }
-
-@@ -484,8 +499,8 @@ static void brcm_unmap_sg(struct device
- struct scatterlist *sg;
-
- for_each_sg(sgl, sg, nents, i)
-- brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
-- sg_dma_len(sg), dir, attrs);
-+ brcm_unmap_page(dev, sg_dma_address(sg),
-+ sg_dma_len(sg), dir, attrs);
- }
-
- static void brcm_sync_single_for_cpu(struct device *dev,
-@@ -531,8 +546,8 @@ void brcm_sync_sg_for_cpu(struct device
- int i;
-
- for_each_sg(sgl, sg, nents, i)
-- brcm_dma_ops_ptr->sync_single_for_cpu(dev, sg_dma_address(sg),
-- sg->length, dir);
-+ brcm_sync_single_for_cpu(dev, sg_dma_address(sg),
-+ sg->length, dir);
- }
-
- void brcm_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
-@@ -542,9 +557,9 @@ void brcm_sync_sg_for_device(struct devi
- int i;
-
- for_each_sg(sgl, sg, nents, i)
-- brcm_dma_ops_ptr->sync_single_for_device(dev,
-- sg_dma_address(sg),
-- sg->length, dir);
-+ brcm_sync_single_for_device(dev,
-+ sg_dma_address(sg),
-+ sg->length, dir);
- }
-
- static int brcm_mapping_error(struct device *dev, dma_addr_t dma_addr)
-@@ -633,17 +648,47 @@ static void brcm_set_dma_ops(struct devi
- set_dma_ops(dev, &brcm_dma_ops);
- }
-
-+static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
-+ unsigned int val);
- static int brcmstb_platform_notifier(struct notifier_block *nb,
- unsigned long event, void *__dev)
- {
-+ extern unsigned long max_pfn;
- struct device *dev = __dev;
-+ const char *rc_name = "0000:00:00.0";
-
-- brcm_dma_ops_ptr = &brcm_dma_ops;
-- if (event != BUS_NOTIFY_ADD_DEVICE)
-- return NOTIFY_DONE;
-+ switch (event) {
-+ case BUS_NOTIFY_ADD_DEVICE:
-+ if (max_pfn > (bounce_threshold/PAGE_SIZE) &&
-+ strcmp(dev->kobj.name, rc_name)) {
-+ int ret;
-+
-+ ret = brcm_pcie_bounce_register_dev(dev, bounce_buffer,
-+ (dma_addr_t)bounce_threshold);
-+ if (ret) {
-+ dev_err(dev,
-+ "brcm_pcie_bounce_register_dev() failed: %d\n",
-+ ret);
-+ return ret;
-+ }
-+ }
-+ brcm_set_dma_ops(dev);
-+ return NOTIFY_OK;
-+
-+ case BUS_NOTIFY_DEL_DEVICE:
-+ if (!strcmp(dev->kobj.name, rc_name) && g_pcie) {
-+ /* Force a bus reset */
-+ brcm_pcie_perst_set(g_pcie, 1);
-+ msleep(100);
-+ brcm_pcie_perst_set(g_pcie, 0);
-+ } else if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-+ brcm_pcie_bounce_unregister_dev(dev);
-+ }
-+ return NOTIFY_OK;
-
-- brcm_set_dma_ops(dev);
-- return NOTIFY_OK;
-+ default:
-+ return NOTIFY_DONE;
-+ }
- }
-
- static struct notifier_block brcmstb_platform_nb = {
-@@ -914,6 +959,7 @@ static void brcm_pcie_msi_isr(struct irq
- }
- }
- chained_irq_exit(chip, desc);
-+ bcm_writel(1, msi->base + PCIE_MISC_EOI_CTRL);
- }
-
- static void brcm_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
-@@ -930,7 +976,8 @@ static void brcm_compose_msi_msg(struct
- static int brcm_msi_set_affinity(struct irq_data *irq_data,
- const struct cpumask *mask, bool force)
- {
-- return -EINVAL;
-+ struct brcm_msi *msi = irq_data_get_irq_chip_data(irq_data);
-+ return __irq_set_affinity(msi->irq, mask, force);
- }
-
- static struct irq_chip brcm_msi_bottom_irq_chip = {
-@@ -1168,9 +1215,9 @@ static void __iomem *brcm_pcie_map_conf(
- return PCI_SLOT(devfn) ? NULL : base + where;
-
- /* For devices, write to the config space index register */
-- idx = cfg_index(bus->number, devfn, where);
-+ idx = cfg_index(bus->number, devfn, 0);
- bcm_writel(idx, pcie->base + IDX_ADDR(pcie));
-- return base + DATA_ADDR(pcie) + (where & 0x3);
-+ return base + DATA_ADDR(pcie) + where;
- }
-
- static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie,
-@@ -1238,20 +1285,6 @@ static int brcm_pcie_parse_map_dma_range
- num_dma_ranges++;
- }
-
-- for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-- u64 size = brcmstb_memory_memc_size(i);
--
-- if (size == (u64)-1) {
-- dev_err(pcie->dev, "cannot get memc%d size", i);
-- return -EINVAL;
-- } else if (size) {
-- scb_size[i] = roundup_pow_of_two_64(size);
-- num_memc++;
-- } else {
-- break;
-- }
-- }
--
- return 0;
- }
-
-@@ -1275,26 +1308,25 @@ static int brcm_pcie_add_controller(stru
- if (ret)
- goto done;
-
-- /* Determine num_memc and their sizes */
-- for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-- u64 size = brcmstb_memory_memc_size(i);
--
-- if (size == (u64)-1) {
-- dev_err(dev, "cannot get memc%d size\n", i);
-- ret = -EINVAL;
-- goto done;
-- } else if (size) {
-- scb_size[i] = roundup_pow_of_two_64(size);
-- num_memc++;
-- } else {
-- break;
-+ if (!num_dma_ranges) {
-+ /* Determine num_memc and their sizes by other means */
-+ for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-+ u64 size = brcmstb_memory_memc_size(i);
-+
-+ if (size == (u64)-1) {
-+ dev_err(dev, "cannot get memc%d size\n", i);
-+ ret = -EINVAL;
-+ goto done;
-+ } else if (size) {
-+ scb_size[i] = roundup_pow_of_two_64(size);
-+ } else {
-+ break;
-+ }
- }
-- }
-- if (!ret && num_memc == 0) {
-- ret = -EINVAL;
-- goto done;
-+ num_memc = i;
- }
-
-+ g_pcie = pcie;
- num_pcie++;
- done:
- mutex_unlock(&brcm_pcie_lock);
-@@ -1307,6 +1339,7 @@ static void brcm_pcie_remove_controller(
- if (--num_pcie > 0)
- goto out;
-
-+ g_pcie = NULL;
- if (brcm_unregister_notifier())
- dev_err(pcie->dev, "failed to unregister pci bus notifier\n");
- kfree(dma_ranges);
-@@ -1367,7 +1400,7 @@ static int brcm_pcie_setup(struct brcm_p
- void __iomem *base = pcie->base;
- unsigned int scb_size_val;
- u64 rc_bar2_offset, rc_bar2_size, total_mem_size = 0;
-- u32 tmp, burst;
-+ u32 tmp;
- int i, j, ret, limit;
- u16 nlw, cls, lnksta;
- bool ssc_good = false;
-@@ -1400,20 +1433,15 @@ static int brcm_pcie_setup(struct brcm_p
- /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
- tmp = INSERT_FIELD(0, PCIE_MISC_MISC_CTRL, SCB_ACCESS_EN, 1);
- tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, CFG_READ_UR_MODE, 1);
-- burst = (pcie->type == GENERIC || pcie->type == BCM7278)
-- ? BURST_SIZE_512 : BURST_SIZE_256;
-- tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, MAX_BURST_SIZE, burst);
-+ tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, MAX_BURST_SIZE,
-+ pcie->max_burst_size);
- bcm_writel(tmp, base + PCIE_MISC_MISC_CTRL);
-
- /*
- * Set up inbound memory view for the EP (called RC_BAR2,
- * not to be confused with the BARs that are advertised by
- * the EP).
-- */
-- for (i = 0; i < num_memc; i++)
-- total_mem_size += scb_size[i];
--
-- /*
-+ *
- * The PCIe host controller by design must set the inbound
- * viewport to be a contiguous arrangement of all of the
- * system's memory. In addition, its size mut be a power of
-@@ -1429,55 +1457,49 @@ static int brcm_pcie_setup(struct brcm_p
- * the controller will know to send outbound memory downstream
- * and everything else upstream.
- */
-- rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
-
-- if (dma_ranges) {
-+ if (num_dma_ranges) {
- /*
-- * The best-case scenario is to place the inbound
-- * region in the first 4GB of pcie-space, as some
-- * legacy devices can only address 32bits.
-- * We would also like to put the MSI under 4GB
-- * as well, since some devices require a 32bit
-- * MSI target address.
-+ * Use the base address and size(s) provided in the dma-ranges
-+ * property.
- */
-- if (total_mem_size <= 0xc0000000ULL &&
-- rc_bar2_size <= 0x100000000ULL) {
-- rc_bar2_offset = 0;
-- /* If the viewport is less then 4GB we can fit
-- * the MSI target address under 4GB. Otherwise
-- * put it right below 64GB.
-- */
-- msi_target_addr =
-- (rc_bar2_size == 0x100000000ULL)
-- ? BRCM_MSI_TARGET_ADDR_GT_4GB
-- : BRCM_MSI_TARGET_ADDR_LT_4GB;
-- } else {
-- /*
-- * The system memory is 4GB or larger so we
-- * cannot start the inbound region at location
-- * 0 (since we have to allow some space for
-- * outbound memory @ 3GB). So instead we
-- * start it at the 1x multiple of its size
-- */
-- rc_bar2_offset = rc_bar2_size;
--
-- /* Since we are starting the viewport at 4GB or
-- * higher, put the MSI target address below 4GB
-- */
-- msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
-- }
-- } else {
-+ for (i = 0; i < num_dma_ranges; i++)
-+ scb_size[i] = roundup_pow_of_two_64(dma_ranges[i].size);
-+
-+ num_memc = num_dma_ranges;
-+ rc_bar2_offset = dma_ranges[0].pci_addr;
-+ } else if (num_memc) {
- /*
- * Set simple configuration based on memory sizes
-- * only. We always start the viewport at address 0,
-- * and set the MSI target address accordingly.
-+ * only. We always start the viewport at address 0.
- */
- rc_bar2_offset = 0;
-+ } else {
-+ return -EINVAL;
-+ }
-+
-+ for (i = 0; i < num_memc; i++)
-+ total_mem_size += scb_size[i];
-+
-+ rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
-
-- msi_target_addr = (rc_bar2_size >= 0x100000000ULL)
-- ? BRCM_MSI_TARGET_ADDR_GT_4GB
-- : BRCM_MSI_TARGET_ADDR_LT_4GB;
-+ /* Verify the alignment is correct */
-+ if (rc_bar2_offset & (rc_bar2_size - 1)) {
-+ dev_err(dev, "inbound window is misaligned\n");
-+ return -EINVAL;
- }
-+
-+ /*
-+ * Position the MSI target low if possible.
-+ *
-+ * TO DO: Consider outbound window when choosing MSI target and
-+ * verifying configuration.
-+ */
-+ msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
-+ if (rc_bar2_offset <= msi_target_addr &&
-+ rc_bar2_offset + rc_bar2_size > msi_target_addr)
-+ msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB;
-+
- pcie->msi_target_addr = msi_target_addr;
-
- tmp = lower_32_bits(rc_bar2_offset);
-@@ -1713,6 +1735,7 @@ static int brcm_pcie_probe(struct platfo
- data = of_id->data;
- pcie->reg_offsets = data->offsets;
- pcie->reg_field_info = data->reg_field_info;
-+ pcie->max_burst_size = data->max_burst_size;
- pcie->type = data->type;
- pcie->dn = dn;
- pcie->dev = &pdev->dev;
-@@ -1732,7 +1755,7 @@ static int brcm_pcie_probe(struct platfo
-
- pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
- if (IS_ERR(pcie->clk)) {
-- dev_err(&pdev->dev, "could not get clock\n");
-+ dev_warn(&pdev->dev, "could not get clock\n");
- pcie->clk = NULL;
- }
- pcie->base = base;
-@@ -1755,7 +1778,8 @@ static int brcm_pcie_probe(struct platfo
-
- ret = clk_prepare_enable(pcie->clk);
- if (ret) {
-- dev_err(&pdev->dev, "could not enable clock\n");
-+ if (ret != -EPROBE_DEFER)
-+ dev_err(&pdev->dev, "could not enable clock\n");
- return ret;
- }
-
-@@ -1818,7 +1842,6 @@ static struct platform_driver brcm_pcie_
- .remove = brcm_pcie_remove,
- .driver = {
- .name = "brcm-pcie",
-- .owner = THIS_MODULE,
- .of_match_table = brcm_pcie_match,
- .pm = &brcm_pcie_pm_ops,
- },
---- a/drivers/soc/bcm/brcmstb/Makefile
-+++ b/drivers/soc/bcm/brcmstb/Makefile
-@@ -1,2 +1,2 @@
--obj-y += common.o biuctrl.o
-+obj-y += common.o biuctrl.o memory.o
- obj-$(CONFIG_BRCMSTB_PM) += pm/
---- /dev/null
-+++ b/drivers/soc/bcm/brcmstb/memory.c
-@@ -0,0 +1,158 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* Copyright © 2015-2017 Broadcom */
-+
-+#include <linux/device.h>
-+#include <linux/io.h>
-+#include <linux/libfdt.h>
-+#include <linux/of_address.h>
-+#include <linux/of_fdt.h>
-+#include <linux/sizes.h>
-+#include <soc/brcmstb/memory_api.h>
-+
-+/* Macro to help extract property data */
-+#define DT_PROP_DATA_TO_U32(b, offs) (fdt32_to_cpu(*(u32 *)(b + offs)))
-+
-+/* Constants used when retrieving memc info */
-+#define NUM_BUS_RANGES 10
-+#define BUS_RANGE_ULIMIT_SHIFT 4
-+#define BUS_RANGE_LLIMIT_SHIFT 4
-+#define BUS_RANGE_PA_SHIFT 12
-+
-+enum {
-+ BUSNUM_MCP0 = 0x4,
-+ BUSNUM_MCP1 = 0x5,
-+ BUSNUM_MCP2 = 0x6,
-+};
-+
-+/*
-+ * If the DT nodes are handy, determine which MEMC holds the specified
-+ * physical address.
-+ */
-+#ifdef CONFIG_ARCH_BRCMSTB
-+int __brcmstb_memory_phys_addr_to_memc(phys_addr_t pa, void __iomem *base)
-+{
-+ int memc = -1;
-+ int i;
-+
-+ for (i = 0; i < NUM_BUS_RANGES; i++, base += 8) {
-+ const u64 ulimit_raw = readl(base);
-+ const u64 llimit_raw = readl(base + 4);
-+ const u64 ulimit =
-+ ((ulimit_raw >> BUS_RANGE_ULIMIT_SHIFT)
-+ << BUS_RANGE_PA_SHIFT) | 0xfff;
-+ const u64 llimit = (llimit_raw >> BUS_RANGE_LLIMIT_SHIFT)
-+ << BUS_RANGE_PA_SHIFT;
-+ const u32 busnum = (u32)(ulimit_raw & 0xf);
-+
-+ if (pa >= llimit && pa <= ulimit) {
-+ if (busnum >= BUSNUM_MCP0 && busnum <= BUSNUM_MCP2) {
-+ memc = busnum - BUSNUM_MCP0;
-+ break;
-+ }
-+ }
-+ }
-+
-+ return memc;
-+}
-+
-+int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa)
-+{
-+ int memc = -1;
-+ struct device_node *np;
-+ void __iomem *cpubiuctrl;
-+
-+ np = of_find_compatible_node(NULL, NULL, "brcm,brcmstb-cpu-biu-ctrl");
-+ if (!np)
-+ return memc;
-+
-+ cpubiuctrl = of_iomap(np, 0);
-+ if (!cpubiuctrl)
-+ goto cleanup;
-+
-+ memc = __brcmstb_memory_phys_addr_to_memc(pa, cpubiuctrl);
-+ iounmap(cpubiuctrl);
-+
-+cleanup:
-+ of_node_put(np);
-+
-+ return memc;
-+}
-+
-+#elif defined(CONFIG_MIPS)
-+int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa)
-+{
-+ /* The logic here is fairly simple and hardcoded: if pa <= 0x5000_0000,
-+ * then this is MEMC0, else MEMC1.
-+ *
-+ * For systems with 2GB on MEMC0, MEMC1 starts at 9000_0000, with 1GB
-+ * on MEMC0, MEMC1 starts at 6000_0000.
-+ */
-+ if (pa >= 0x50000000ULL)
-+ return 1;
-+ else
-+ return 0;
-+}
-+#endif
-+
-+u64 brcmstb_memory_memc_size(int memc)
-+{
-+ const void *fdt = initial_boot_params;
-+ const int mem_offset = fdt_path_offset(fdt, "/memory");
-+ int addr_cells = 1, size_cells = 1;
-+ const struct fdt_property *prop;
-+ int proplen, cellslen;
-+ u64 memc_size = 0;
-+ int i;
-+
-+ /* Get root size and address cells if specified */
-+ prop = fdt_get_property(fdt, 0, "#size-cells", &proplen);
-+ if (prop)
-+ size_cells = DT_PROP_DATA_TO_U32(prop->data, 0);
-+
-+ prop = fdt_get_property(fdt, 0, "#address-cells", &proplen);
-+ if (prop)
-+ addr_cells = DT_PROP_DATA_TO_U32(prop->data, 0);
-+
-+ if (mem_offset < 0)
-+ return -1;
-+
-+ prop = fdt_get_property(fdt, mem_offset, "reg", &proplen);
-+ cellslen = (int)sizeof(u32) * (addr_cells + size_cells);
-+ if ((proplen % cellslen) != 0)
-+ return -1;
-+
-+ for (i = 0; i < proplen / cellslen; ++i) {
-+ u64 addr = 0;
-+ u64 size = 0;
-+ int memc_idx;
-+ int j;
-+
-+ for (j = 0; j < addr_cells; ++j) {
-+ int offset = (cellslen * i) + (sizeof(u32) * j);
-+
-+ addr |= (u64)DT_PROP_DATA_TO_U32(prop->data, offset) <<
-+ ((addr_cells - j - 1) * 32);
-+ }
-+ for (j = 0; j < size_cells; ++j) {
-+ int offset = (cellslen * i) +
-+ (sizeof(u32) * (j + addr_cells));
-+
-+ size |= (u64)DT_PROP_DATA_TO_U32(prop->data, offset) <<
-+ ((size_cells - j - 1) * 32);
-+ }
-+
-+ if ((phys_addr_t)addr != addr) {
-+ pr_err("phys_addr_t is smaller than provided address 0x%llx!\n",
-+ addr);
-+ return -1;
-+ }
-+
-+ memc_idx = brcmstb_memory_phys_addr_to_memc((phys_addr_t)addr);
-+ if (memc_idx == memc)
-+ memc_size += size;
-+ }
-+
-+ return memc_size;
-+}
-+EXPORT_SYMBOL_GPL(brcmstb_memory_memc_size);
-+
+++ /dev/null
-From 9334afe7293b3a78b7e070a70880b2db7aa98365 Mon Sep 17 00:00:00 2001
-Date: Wed, 29 May 2019 15:47:42 +0100
-Subject: [PATCH] arm: bcm2835: DMA can only address 1GB
-
-The legacy peripherals can only address the first gigabyte of RAM, so
-ensure that DMA allocations are restricted to that region.
-
----
- arch/arm/mach-bcm/board_bcm2835.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/arch/arm/mach-bcm/board_bcm2835.c
-+++ b/arch/arm/mach-bcm/board_bcm2835.c
-@@ -123,6 +123,9 @@ static const char * const bcm2835_compat
- };
-
- DT_MACHINE_START(BCM2835, "BCM2835")
-+#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
-+ .dma_zone_size = SZ_1G,
-+#endif
- .map_io = bcm2835_map_io,
- .init_machine = bcm2835_init,
- .dt_compat = bcm2835_compat,
--- /dev/null
+From be309b7db77215610d5ac15bf0aacd47ea5b3433 Mon Sep 17 00:00:00 2001
+Date: Fri, 28 Sep 2018 16:24:05 +0100
+Subject: [PATCH] mmc: sdhci: Mask "spurious" interrupts
+
+Add a filter for "spurious" Transfer Complete interrupts, attempting
+to make it as specific as possible:
+* INT_DATA_END (transfer complete) is set
+* There is a stop command in progress
+* There is no data transfer in progress
+
+---
+ drivers/mmc/host/sdhci.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/mmc/host/sdhci.c
++++ b/drivers/mmc/host/sdhci.c
+@@ -2935,6 +2935,10 @@ static irqreturn_t sdhci_irq(int irq, vo
+ result = IRQ_WAKE_THREAD;
+ }
+
++ if ((intmask & SDHCI_INT_DATA_END) && !host->data &&
++ host->cmd && (host->cmd == host->cmd->mrq->stop))
++ intmask &= ~SDHCI_INT_DATA_END;
++
+ if (intmask & SDHCI_INT_CMD_MASK)
+ sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK, &intmask);
+
+++ /dev/null
-From 8a58288d710a817b5dc7747f0bec1fb167368e7e Mon Sep 17 00:00:00 2001
-Date: Wed, 29 Aug 2018 09:05:15 +0100
-Subject: [PATCH] mmc: bcm2835-sdhost: Support 64-bit physical
- addresses
-
----
- drivers/mmc/host/bcm2835-sdhost.c | 10 ++++++----
- 1 file changed, 6 insertions(+), 4 deletions(-)
-
---- a/drivers/mmc/host/bcm2835-sdhost.c
-+++ b/drivers/mmc/host/bcm2835-sdhost.c
-@@ -148,7 +148,7 @@ struct bcm2835_host {
- spinlock_t lock;
-
- void __iomem *ioaddr;
-- u32 bus_addr;
-+ phys_addr_t bus_addr;
-
- struct mmc_host *mmc;
-
-@@ -246,8 +246,8 @@ static void log_init(struct device *dev,
- sdhost_log_buf = dma_zalloc_coherent(dev, LOG_SIZE, &sdhost_log_addr,
- GFP_KERNEL);
- if (sdhost_log_buf) {
-- pr_info("sdhost: log_buf @ %p (%x)\n",
-- sdhost_log_buf, (u32)sdhost_log_addr);
-+ pr_info("sdhost: log_buf @ %p (%llx)\n",
-+ sdhost_log_buf, (u64)sdhost_log_addr);
- timer_base = ioremap_nocache(bus_to_phys + 0x7e003000, SZ_4K);
- if (!timer_base)
- pr_err("sdhost: failed to remap timer\n");
-@@ -2024,6 +2024,7 @@ static int bcm2835_sdhost_probe(struct p
- struct mmc_host *mmc;
- const __be32 *addr;
- u32 msg[3];
-+ int na;
- int ret;
-
- pr_debug("bcm2835_sdhost_probe\n");
-@@ -2047,12 +2048,13 @@ static int bcm2835_sdhost_probe(struct p
- goto err;
- }
-
-+ na = of_n_addr_cells(node);
- addr = of_get_address(node, 0, NULL, NULL);
- if (!addr) {
- dev_err(dev, "could not get DMA-register address\n");
- return -ENODEV;
- }
-- host->bus_addr = be32_to_cpup(addr);
-+ host->bus_addr = (phys_addr_t)of_read_number(addr, na);
- pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
- (unsigned long)host->ioaddr,
- (unsigned long)iomem->start,
--- /dev/null
+From 0a1c3ff378e60f2a59153cfc1c7529bfe05eb115 Mon Sep 17 00:00:00 2001
+Date: Sat, 27 Apr 2019 12:33:57 +0200
+Subject: [PATCH] mmc: sdhci-iproc: Add support for emmc2 of the
+ BCM2838
+
+The emmc2 interface of the BCM2838 should be integrated in sdhci-iproc
+to avoid code redundancy. Except 32 bit only access no other quirks are
+known yet. Add an additional compatible string for upstream proposal.
+
+---
+ drivers/mmc/host/sdhci-iproc.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/mmc/host/sdhci-iproc.c
++++ b/drivers/mmc/host/sdhci-iproc.c
+@@ -250,8 +250,18 @@ static const struct sdhci_iproc_data bcm
+ .mmc_caps = 0x00000000,
+ };
+
++static const struct sdhci_pltfm_data sdhci_bcm2838_pltfm_data = {
++ .ops = &sdhci_iproc_32only_ops,
++};
++
++static const struct sdhci_iproc_data bcm2838_data = {
++ .pdata = &sdhci_bcm2838_pltfm_data,
++};
++
+ static const struct of_device_id sdhci_iproc_of_match[] = {
+ { .compatible = "brcm,bcm2835-sdhci", .data = &bcm2835_data },
++ { .compatible = "brcm,bcm2838-sdhci", .data = &bcm2838_data },
++ { .compatible = "brcm,bcm2711-emmc2", .data = &bcm2838_data },
+ { .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_cygnus_data},
+ { .compatible = "brcm,sdhci-iproc", .data = &iproc_data },
+ { }
--- /dev/null
+From e9c0fd87b6169baf5bd10293a85675d505086191 Mon Sep 17 00:00:00 2001
+Date: Sat, 4 May 2019 17:06:15 +0200
+Subject: [PATCH] hwrng: iproc-rng200: Add BCM2838 support
+
+The HWRNG on the BCM2838 is compatible to iproc-rng200, so add the
+support to this driver instead of bcm2835-rng.
+
+---
+ drivers/char/hw_random/Kconfig | 4 +-
+ drivers/char/hw_random/iproc-rng200.c | 81 +++++++++++++++++++++++++--
+ 2 files changed, 79 insertions(+), 6 deletions(-)
+
+--- a/drivers/char/hw_random/Kconfig
++++ b/drivers/char/hw_random/Kconfig
+@@ -89,11 +89,11 @@ config HW_RANDOM_BCM2835
+
+ config HW_RANDOM_IPROC_RNG200
+ tristate "Broadcom iProc/STB RNG200 support"
+- depends on ARCH_BCM_IPROC || ARCH_BRCMSTB
++ depends on ARCH_BCM_IPROC || ARCH_BCM2835 || ARCH_BRCMSTB
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the RNG200
+- hardware found on the Broadcom iProc and STB SoCs.
++ hardware found on the Broadcom iProc, BCM2838 and STB SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called iproc-rng200
+--- a/drivers/char/hw_random/iproc-rng200.c
++++ b/drivers/char/hw_random/iproc-rng200.c
+@@ -29,6 +29,7 @@
+ #define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF
+ #define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001
+ #define RNG_CTRL_RNG_RBGEN_DISABLE 0x00000000
++#define RNG_CTRL_RNG_DIV_CTRL_SHIFT 13
+
+ #define RNG_SOFT_RESET_OFFSET 0x04
+ #define RNG_SOFT_RESET 0x00000001
+@@ -36,16 +37,23 @@
+ #define RBG_SOFT_RESET_OFFSET 0x08
+ #define RBG_SOFT_RESET 0x00000001
+
++#define RNG_TOTAL_BIT_COUNT_OFFSET 0x0C
++
++#define RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET 0x10
++
+ #define RNG_INT_STATUS_OFFSET 0x18
+ #define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000
+ #define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK 0x00020000
+ #define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020
+ #define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK 0x00000001
+
++#define RNG_INT_ENABLE_OFFSET 0x1C
++
+ #define RNG_FIFO_DATA_OFFSET 0x20
+
+ #define RNG_FIFO_COUNT_OFFSET 0x24
+ #define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF
++#define RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT 8
+
+ struct iproc_rng200_dev {
+ struct hwrng rng;
+@@ -166,6 +174,64 @@ static int iproc_rng200_init(struct hwrn
+ return 0;
+ }
+
++static int bcm2838_rng200_read(struct hwrng *rng, void *buf, size_t max,
++ bool wait)
++{
++ struct iproc_rng200_dev *priv = to_rng_priv(rng);
++ u32 max_words = max / sizeof(u32);
++ u32 num_words, count, val;
++
++ /* ensure warm up period has elapsed */
++ while (1) {
++ val = ioread32(priv->base + RNG_TOTAL_BIT_COUNT_OFFSET);
++ if (val > 16)
++ break;
++ cpu_relax();
++ }
++
++ /* ensure fifo is not empty */
++ while (1) {
++ num_words = ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) &
++ RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK;
++ if (num_words)
++ break;
++ if (!wait)
++ return 0;
++ cpu_relax();
++ }
++
++ if (num_words > max_words)
++ num_words = max_words;
++
++ for (count = 0; count < num_words; count++) {
++ ((u32 *)buf)[count] = ioread32(priv->base +
++ RNG_FIFO_DATA_OFFSET);
++ }
++
++ return num_words * sizeof(u32);
++}
++
++static int bcm2838_rng200_init(struct hwrng *rng)
++{
++ struct iproc_rng200_dev *priv = to_rng_priv(rng);
++ uint32_t val;
++
++ if (ioread32(priv->base + RNG_CTRL_OFFSET) & RNG_CTRL_RNG_RBGEN_MASK)
++ return 0;
++
++ /* initial numbers generated are "less random" so will be discarded */
++ val = 0x40000;
++ iowrite32(val, priv->base + RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET);
++ /* min fifo count to generate full interrupt */
++ val = 2 << RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT;
++ iowrite32(val, priv->base + RNG_FIFO_COUNT_OFFSET);
++ /* enable the rng - 1Mhz sample rate */
++ val = (0x3 << RNG_CTRL_RNG_DIV_CTRL_SHIFT) | RNG_CTRL_RNG_RBGEN_MASK;
++ iowrite32(val, priv->base + RNG_CTRL_OFFSET);
++
++ return 0;
++}
++
+ static void iproc_rng200_cleanup(struct hwrng *rng)
+ {
+ struct iproc_rng200_dev *priv = to_rng_priv(rng);
+@@ -202,10 +268,16 @@ static int iproc_rng200_probe(struct pla
+ return PTR_ERR(priv->base);
+ }
+
+- priv->rng.name = "iproc-rng200",
+- priv->rng.read = iproc_rng200_read,
+- priv->rng.init = iproc_rng200_init,
+- priv->rng.cleanup = iproc_rng200_cleanup,
++ priv->rng.name = pdev->name;
++ priv->rng.cleanup = iproc_rng200_cleanup;
++
++ if (of_device_is_compatible(dev->of_node, "brcm,bcm2838-rng200")) {
++ priv->rng.init = bcm2838_rng200_init;
++ priv->rng.read = bcm2838_rng200_read;
++ } else {
++ priv->rng.init = iproc_rng200_init;
++ priv->rng.read = iproc_rng200_read;
++ }
+
+ /* Register driver */
+ ret = devm_hwrng_register(dev, &priv->rng);
+@@ -222,6 +294,7 @@ static int iproc_rng200_probe(struct pla
+ static const struct of_device_id iproc_rng200_of_match[] = {
+ { .compatible = "brcm,bcm7278-rng200", },
+ { .compatible = "brcm,iproc-rng200", },
++ { .compatible = "brcm,bcm2838-rng200"},
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, iproc_rng200_of_match);
+++ /dev/null
-From be309b7db77215610d5ac15bf0aacd47ea5b3433 Mon Sep 17 00:00:00 2001
-Date: Fri, 28 Sep 2018 16:24:05 +0100
-Subject: [PATCH] mmc: sdhci: Mask "spurious" interrupts
-
-Add a filter for "spurious" Transfer Complete interrupts, attempting
-to make it as specific as possible:
-* INT_DATA_END (transfer complete) is set
-* There is a stop command in progress
-* There is no data transfer in progress
-
----
- drivers/mmc/host/sdhci.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/mmc/host/sdhci.c
-+++ b/drivers/mmc/host/sdhci.c
-@@ -2935,6 +2935,10 @@ static irqreturn_t sdhci_irq(int irq, vo
- result = IRQ_WAKE_THREAD;
- }
-
-+ if ((intmask & SDHCI_INT_DATA_END) && !host->data &&
-+ host->cmd && (host->cmd == host->cmd->mrq->stop))
-+ intmask &= ~SDHCI_INT_DATA_END;
-+
- if (intmask & SDHCI_INT_CMD_MASK)
- sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK, &intmask);
-
+++ /dev/null
-From 0a1c3ff378e60f2a59153cfc1c7529bfe05eb115 Mon Sep 17 00:00:00 2001
-Date: Sat, 27 Apr 2019 12:33:57 +0200
-Subject: [PATCH] mmc: sdhci-iproc: Add support for emmc2 of the
- BCM2838
-
-The emmc2 interface of the BCM2838 should be integrated in sdhci-iproc
-to avoid code redundancy. Except 32 bit only access no other quirks are
-known yet. Add an additional compatible string for upstream proposal.
-
----
- drivers/mmc/host/sdhci-iproc.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/mmc/host/sdhci-iproc.c
-+++ b/drivers/mmc/host/sdhci-iproc.c
-@@ -250,8 +250,18 @@ static const struct sdhci_iproc_data bcm
- .mmc_caps = 0x00000000,
- };
-
-+static const struct sdhci_pltfm_data sdhci_bcm2838_pltfm_data = {
-+ .ops = &sdhci_iproc_32only_ops,
-+};
-+
-+static const struct sdhci_iproc_data bcm2838_data = {
-+ .pdata = &sdhci_bcm2838_pltfm_data,
-+};
-+
- static const struct of_device_id sdhci_iproc_of_match[] = {
- { .compatible = "brcm,bcm2835-sdhci", .data = &bcm2835_data },
-+ { .compatible = "brcm,bcm2838-sdhci", .data = &bcm2838_data },
-+ { .compatible = "brcm,bcm2711-emmc2", .data = &bcm2838_data },
- { .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_cygnus_data},
- { .compatible = "brcm,sdhci-iproc", .data = &iproc_data },
- { }
--- /dev/null
+From d49649e2dcf0d5775e92677d37e229e0387fe82a Mon Sep 17 00:00:00 2001
+Date: Sat, 18 May 2019 12:26:11 +0200
+Subject: [PATCH] thermal: brcmstb_thermal: Add BCM2838 support
+
+The BCM2838 has an AVS TMON hardware block. This adds the necessary
+support to the brcmstb_thermal driver ( no trip handling ).
+
+---
+ drivers/thermal/broadcom/Kconfig | 2 +-
+ drivers/thermal/broadcom/brcmstb_thermal.c | 65 +++++++++++++++++++---
+ 2 files changed, 58 insertions(+), 9 deletions(-)
+
+--- a/drivers/thermal/broadcom/Kconfig
++++ b/drivers/thermal/broadcom/Kconfig
+@@ -8,7 +8,7 @@ config BCM2835_THERMAL
+
+ config BRCMSTB_THERMAL
+ tristate "Broadcom STB AVS TMON thermal driver"
+- depends on ARCH_BRCMSTB || COMPILE_TEST
++ depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
+ help
+ Enable this driver if you have a Broadcom STB SoC and would like
+ thermal framework support.
+--- a/drivers/thermal/broadcom/brcmstb_thermal.c
++++ b/drivers/thermal/broadcom/brcmstb_thermal.c
+@@ -19,6 +19,7 @@
+ #define pr_fmt(fmt) DRV_NAME ": " fmt
+
+ #include <linux/bitops.h>
++#include <linux/clk.h>
+ #include <linux/device.h>
+ #include <linux/err.h>
+ #include <linux/io.h>
+@@ -31,9 +32,6 @@
+ #include <linux/thermal.h>
+
+ #define AVS_TMON_STATUS 0x00
+- #define AVS_TMON_STATUS_valid_msk BIT(11)
+- #define AVS_TMON_STATUS_data_msk GENMASK(10, 1)
+- #define AVS_TMON_STATUS_data_shift 1
+
+ #define AVS_TMON_EN_OVERTEMP_RESET 0x04
+ #define AVS_TMON_EN_OVERTEMP_RESET_msk BIT(0)
+@@ -111,10 +109,19 @@ static struct avs_tmon_trip avs_tmon_tri
+ },
+ };
+
++struct brcmstb_thermal_of_data {
++ const struct thermal_zone_of_device_ops *of_ops;
++ u32 status_valid_mask;
++ u32 status_data_mask;
++ u32 status_data_shift;
++};
++
+ struct brcmstb_thermal_priv {
+ void __iomem *tmon_base;
+ struct device *dev;
+ struct thermal_zone_device *thermal;
++ struct clk *clk;
++ const struct brcmstb_thermal_of_data *socdata;
+ };
+
+ static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int *slope,
+@@ -164,17 +171,18 @@ static inline u32 avs_tmon_temp_to_code(
+ static int brcmstb_get_temp(void *data, int *temp)
+ {
+ struct brcmstb_thermal_priv *priv = data;
++ const struct brcmstb_thermal_of_data *socdata = priv->socdata;
+ u32 val;
+ long t;
+
+ val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
+
+- if (!(val & AVS_TMON_STATUS_valid_msk)) {
++ if (!(val & socdata->status_valid_mask)) {
+ dev_err(priv->dev, "reading not valid\n");
+ return -EIO;
+ }
+
+- val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
++ val = (val & socdata->status_data_mask) >> socdata->status_data_shift;
+
+ t = avs_tmon_code_to_temp(priv->thermal, val);
+ if (t < 0)
+@@ -299,13 +307,34 @@ static int brcmstb_set_trips(void *data,
+ return 0;
+ }
+
+-static struct thermal_zone_of_device_ops of_ops = {
++static const struct thermal_zone_of_device_ops bcm7445_thermal_of_ops = {
+ .get_temp = brcmstb_get_temp,
+ .set_trips = brcmstb_set_trips,
+ };
+
++static const struct thermal_zone_of_device_ops bcm2838_thermal_of_ops = {
++ .get_temp = brcmstb_get_temp,
++};
++
++static const struct brcmstb_thermal_of_data bcm7445_thermal_of_data = {
++ .of_ops = &bcm7445_thermal_of_ops,
++ .status_valid_mask = BIT(11),
++ .status_data_mask = GENMASK(10, 1),
++ .status_data_shift = 1,
++};
++
++static const struct brcmstb_thermal_of_data bcm2838_thermal_of_data = {
++ .of_ops = &bcm2838_thermal_of_ops,
++ .status_valid_mask = BIT(10),
++ .status_data_mask = GENMASK(9, 0),
++ .status_data_shift = 0,
++};
++
+ static const struct of_device_id brcmstb_thermal_id_table[] = {
+- { .compatible = "brcm,avs-tmon" },
++ { .compatible = "brcm,avs-tmon",
++ .data = &bcm7445_thermal_of_data },
++ { .compatible = "brcm,avs-tmon-bcm2838",
++ .data = &bcm2838_thermal_of_data },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
+@@ -326,10 +355,27 @@ static int brcmstb_thermal_probe(struct
+ if (IS_ERR(priv->tmon_base))
+ return PTR_ERR(priv->tmon_base);
+
++ priv->socdata = of_device_get_match_data(&pdev->dev);
++ if (!priv->socdata) {
++ dev_err(&pdev->dev, "no device match found\n");
++ return -ENODEV;
++ }
++
++ priv->clk = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
++
++ if (!IS_ERR(priv->clk)) {
++ ret = clk_prepare_enable(priv->clk);
++ if (ret)
++ return ret;
++ }
++
+ priv->dev = &pdev->dev;
+ platform_set_drvdata(pdev, priv);
+
+- thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &of_ops);
++ thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv,
++ priv->socdata->of_ops);
+ if (IS_ERR(thermal)) {
+ ret = PTR_ERR(thermal);
+ dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
+@@ -369,6 +415,9 @@ static int brcmstb_thermal_exit(struct p
+ if (thermal)
+ thermal_zone_of_sensor_unregister(&pdev->dev, priv->thermal);
+
++ if (!IS_ERR(priv->clk))
++ clk_disable_unprepare(priv->clk);
++
+ return 0;
+ }
+
+++ /dev/null
-From e9c0fd87b6169baf5bd10293a85675d505086191 Mon Sep 17 00:00:00 2001
-Date: Sat, 4 May 2019 17:06:15 +0200
-Subject: [PATCH] hwrng: iproc-rng200: Add BCM2838 support
-
-The HWRNG on the BCM2838 is compatible to iproc-rng200, so add the
-support to this driver instead of bcm2835-rng.
-
----
- drivers/char/hw_random/Kconfig | 4 +-
- drivers/char/hw_random/iproc-rng200.c | 81 +++++++++++++++++++++++++--
- 2 files changed, 79 insertions(+), 6 deletions(-)
-
---- a/drivers/char/hw_random/Kconfig
-+++ b/drivers/char/hw_random/Kconfig
-@@ -89,11 +89,11 @@ config HW_RANDOM_BCM2835
-
- config HW_RANDOM_IPROC_RNG200
- tristate "Broadcom iProc/STB RNG200 support"
-- depends on ARCH_BCM_IPROC || ARCH_BRCMSTB
-+ depends on ARCH_BCM_IPROC || ARCH_BCM2835 || ARCH_BRCMSTB
- default HW_RANDOM
- ---help---
- This driver provides kernel-side support for the RNG200
-- hardware found on the Broadcom iProc and STB SoCs.
-+ hardware found on the Broadcom iProc, BCM2838 and STB SoCs.
-
- To compile this driver as a module, choose M here: the
- module will be called iproc-rng200
---- a/drivers/char/hw_random/iproc-rng200.c
-+++ b/drivers/char/hw_random/iproc-rng200.c
-@@ -29,6 +29,7 @@
- #define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF
- #define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001
- #define RNG_CTRL_RNG_RBGEN_DISABLE 0x00000000
-+#define RNG_CTRL_RNG_DIV_CTRL_SHIFT 13
-
- #define RNG_SOFT_RESET_OFFSET 0x04
- #define RNG_SOFT_RESET 0x00000001
-@@ -36,16 +37,23 @@
- #define RBG_SOFT_RESET_OFFSET 0x08
- #define RBG_SOFT_RESET 0x00000001
-
-+#define RNG_TOTAL_BIT_COUNT_OFFSET 0x0C
-+
-+#define RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET 0x10
-+
- #define RNG_INT_STATUS_OFFSET 0x18
- #define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000
- #define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK 0x00020000
- #define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020
- #define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK 0x00000001
-
-+#define RNG_INT_ENABLE_OFFSET 0x1C
-+
- #define RNG_FIFO_DATA_OFFSET 0x20
-
- #define RNG_FIFO_COUNT_OFFSET 0x24
- #define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF
-+#define RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT 8
-
- struct iproc_rng200_dev {
- struct hwrng rng;
-@@ -166,6 +174,64 @@ static int iproc_rng200_init(struct hwrn
- return 0;
- }
-
-+static int bcm2838_rng200_read(struct hwrng *rng, void *buf, size_t max,
-+ bool wait)
-+{
-+ struct iproc_rng200_dev *priv = to_rng_priv(rng);
-+ u32 max_words = max / sizeof(u32);
-+ u32 num_words, count, val;
-+
-+ /* ensure warm up period has elapsed */
-+ while (1) {
-+ val = ioread32(priv->base + RNG_TOTAL_BIT_COUNT_OFFSET);
-+ if (val > 16)
-+ break;
-+ cpu_relax();
-+ }
-+
-+ /* ensure fifo is not empty */
-+ while (1) {
-+ num_words = ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) &
-+ RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK;
-+ if (num_words)
-+ break;
-+ if (!wait)
-+ return 0;
-+ cpu_relax();
-+ }
-+
-+ if (num_words > max_words)
-+ num_words = max_words;
-+
-+ for (count = 0; count < num_words; count++) {
-+ ((u32 *)buf)[count] = ioread32(priv->base +
-+ RNG_FIFO_DATA_OFFSET);
-+ }
-+
-+ return num_words * sizeof(u32);
-+}
-+
-+static int bcm2838_rng200_init(struct hwrng *rng)
-+{
-+ struct iproc_rng200_dev *priv = to_rng_priv(rng);
-+ uint32_t val;
-+
-+ if (ioread32(priv->base + RNG_CTRL_OFFSET) & RNG_CTRL_RNG_RBGEN_MASK)
-+ return 0;
-+
-+ /* initial numbers generated are "less random" so will be discarded */
-+ val = 0x40000;
-+ iowrite32(val, priv->base + RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET);
-+ /* min fifo count to generate full interrupt */
-+ val = 2 << RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT;
-+ iowrite32(val, priv->base + RNG_FIFO_COUNT_OFFSET);
-+ /* enable the rng - 1Mhz sample rate */
-+ val = (0x3 << RNG_CTRL_RNG_DIV_CTRL_SHIFT) | RNG_CTRL_RNG_RBGEN_MASK;
-+ iowrite32(val, priv->base + RNG_CTRL_OFFSET);
-+
-+ return 0;
-+}
-+
- static void iproc_rng200_cleanup(struct hwrng *rng)
- {
- struct iproc_rng200_dev *priv = to_rng_priv(rng);
-@@ -202,10 +268,16 @@ static int iproc_rng200_probe(struct pla
- return PTR_ERR(priv->base);
- }
-
-- priv->rng.name = "iproc-rng200",
-- priv->rng.read = iproc_rng200_read,
-- priv->rng.init = iproc_rng200_init,
-- priv->rng.cleanup = iproc_rng200_cleanup,
-+ priv->rng.name = pdev->name;
-+ priv->rng.cleanup = iproc_rng200_cleanup;
-+
-+ if (of_device_is_compatible(dev->of_node, "brcm,bcm2838-rng200")) {
-+ priv->rng.init = bcm2838_rng200_init;
-+ priv->rng.read = bcm2838_rng200_read;
-+ } else {
-+ priv->rng.init = iproc_rng200_init;
-+ priv->rng.read = iproc_rng200_read;
-+ }
-
- /* Register driver */
- ret = devm_hwrng_register(dev, &priv->rng);
-@@ -222,6 +294,7 @@ static int iproc_rng200_probe(struct pla
- static const struct of_device_id iproc_rng200_of_match[] = {
- { .compatible = "brcm,bcm7278-rng200", },
- { .compatible = "brcm,iproc-rng200", },
-+ { .compatible = "brcm,bcm2838-rng200"},
- {},
- };
- MODULE_DEVICE_TABLE(of, iproc_rng200_of_match);
--- /dev/null
+From d5c6191cc94b358de183cc8c88a5722a79445202 Mon Sep 17 00:00:00 2001
+Date: Thu, 1 Nov 2018 17:31:37 +0000
+Subject: [PATCH] vchiq: Add 36-bit address support
+
+Conditional on a new compatible string, change the pagelist encoding
+such that the top 24 bits are the pfn, leaving 8 bits for run length
+(-1).
+
+---
+ .../interface/vchiq_arm/vchiq_2835_arm.c | 90 ++++++++++++++-----
+ .../interface/vchiq_arm/vchiq_arm.c | 6 ++
+ .../interface/vchiq_arm/vchiq_arm.h | 1 +
+ 3 files changed, 75 insertions(+), 22 deletions(-)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
+@@ -47,6 +47,8 @@
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
+ #define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
++#define VC_SAFE(x) (g_use_36bit_addrs ? ((u32)(x) | 0xc0000000) : (u32)(x))
++#define IS_VC_SAFE(x) (g_use_36bit_addrs ? !((x) & ~0x3fffffffull) : 1)
+
+ #include "vchiq_arm.h"
+ #include "vchiq_connected.h"
+@@ -96,6 +98,7 @@ static void __iomem *g_regs;
+ */
+ static unsigned int g_cache_line_size;
+ static struct dma_pool *g_dma_pool;
++static unsigned int g_use_36bit_addrs = 0;
+ static unsigned int g_fragments_size;
+ static char *g_fragments_base;
+ static char *g_free_fragments;
+@@ -139,6 +142,8 @@ int vchiq_platform_init(struct platform_
+ g_cache_line_size = drvdata->cache_line_size;
+ g_fragments_size = 2 * g_cache_line_size;
+
++ g_use_36bit_addrs = (dev->dma_pfn_offset == 0);
++
+ /* Allocate space for the channels in coherent memory */
+ slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
+ frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS);
+@@ -150,14 +155,21 @@ int vchiq_platform_init(struct platform_
+ return -ENOMEM;
+ }
+
++ if (!IS_VC_SAFE(slot_phys)) {
++ dev_err(dev, "allocated DMA memory %pad is not VC-safe\n",
++ &slot_phys);
++ return -ENOMEM;
++ }
++
+ WARN_ON(((unsigned long)slot_mem & (PAGE_SIZE - 1)) != 0);
++ channelbase = VC_SAFE(slot_phys);
+
+ vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size);
+ if (!vchiq_slot_zero)
+ return -EINVAL;
+
+ vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] =
+- (int)slot_phys + slot_mem_size;
++ channelbase + slot_mem_size;
+ vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
+ MAX_FRAGMENTS;
+
+@@ -193,7 +205,6 @@ int vchiq_platform_init(struct platform_
+ }
+
+ /* Send the base address of the slots to VideoCore */
+- channelbase = slot_phys;
+ err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT,
+ &channelbase, sizeof(channelbase));
+ if (err || channelbase) {
+@@ -282,7 +293,7 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu
+ return VCHIQ_ERROR;
+
+ bulk->handle = memhandle;
+- bulk->data = (void *)(unsigned long)pagelistinfo->dma_addr;
++ bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr);
+
+ /*
+ * Store the pagelistinfo address in remote_data,
+@@ -570,25 +581,60 @@ create_pagelist(char __user *buf, size_t
+
+ /* Combine adjacent blocks for performance */
+ k = 0;
+- for_each_sg(scatterlist, sg, dma_buffers, i) {
+- u32 len = sg_dma_len(sg);
+- u32 addr = sg_dma_address(sg);
+-
+- /* Note: addrs is the address + page_count - 1
+- * The firmware expects blocks after the first to be page-
+- * aligned and a multiple of the page size
+- */
+- WARN_ON(len == 0);
+- WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
+- WARN_ON(i && (addr & ~PAGE_MASK));
+- if (k > 0 &&
+- ((addrs[k - 1] & PAGE_MASK) +
+- (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT))
+- == (addr & PAGE_MASK))
+- addrs[k - 1] += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT);
+- else
+- addrs[k++] = (addr & PAGE_MASK) |
+- (((len + PAGE_SIZE - 1) >> PAGE_SHIFT) - 1);
++ if (g_use_36bit_addrs) {
++ for_each_sg(scatterlist, sg, dma_buffers, i) {
++ u32 len = sg_dma_len(sg);
++ u64 addr = sg_dma_address(sg);
++ u32 page_id = (u32)((addr >> 4) & ~0xff);
++ u32 sg_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
++
++ /* Note: addrs is the address + page_count - 1
++ * The firmware expects blocks after the first to be page-
++ * aligned and a multiple of the page size
++ */
++ WARN_ON(len == 0);
++ WARN_ON(i &&
++ (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
++ WARN_ON(i && (addr & ~PAGE_MASK));
++ WARN_ON(upper_32_bits(addr) > 0xf);
++ if (k > 0 &&
++ ((addrs[k - 1] & ~0xff) +
++ (((addrs[k - 1] & 0xff) + 1) << 8)
++ == page_id)) {
++ u32 inc_pages = min(sg_pages,
++ 0xff - (addrs[k - 1] & 0xff));
++ addrs[k - 1] += inc_pages;
++ page_id += inc_pages << 8;
++ sg_pages -= inc_pages;
++ }
++ while (sg_pages) {
++ u32 inc_pages = min(sg_pages, 0x100u);
++ addrs[k++] = page_id | (inc_pages - 1);
++ page_id += inc_pages << 8;
++ sg_pages -= inc_pages;
++ }
++ }
++ } else {
++ for_each_sg(scatterlist, sg, dma_buffers, i) {
++ u32 len = sg_dma_len(sg);
++ u32 addr = VC_SAFE(sg_dma_address(sg));
++ u32 new_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
++
++ /* Note: addrs is the address + page_count - 1
++ * The firmware expects blocks after the first to be page-
++ * aligned and a multiple of the page size
++ */
++ WARN_ON(len == 0);
++ WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
++ WARN_ON(i && (addr & ~PAGE_MASK));
++ if (k > 0 &&
++ ((addrs[k - 1] & PAGE_MASK) +
++ (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT))
++ == (addr & PAGE_MASK))
++ addrs[k - 1] += new_pages;
++ else
++ addrs[k++] = (addr & PAGE_MASK) | (new_pages - 1);
++ }
+ }
+
+ /* Partial cache lines (fragments) require special measures */
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -181,6 +181,11 @@ static struct vchiq_drvdata bcm2836_drvd
+ .cache_line_size = 64,
+ };
+
++static struct vchiq_drvdata bcm2838_drvdata = {
++ .cache_line_size = 64,
++ .use_36bit_addrs = true,
++};
++
+ static const char *const ioctl_names[] = {
+ "CONNECT",
+ "SHUTDOWN",
+@@ -3618,6 +3623,7 @@ vchiq_register_child(struct platform_dev
+ static const struct of_device_id vchiq_of_match[] = {
+ { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata },
+ { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata },
++ { .compatible = "brcm,bcm2838-vchiq", .data = &bcm2838_drvdata },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, vchiq_of_match);
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
+@@ -125,6 +125,7 @@ typedef struct vchiq_arm_state_struct {
+
+ struct vchiq_drvdata {
+ const unsigned int cache_line_size;
++ const bool use_36bit_addrs;
+ struct rpi_firmware *fw;
+ };
+
--- /dev/null
+From 69d7e7d0f958186a0f7667ebeefdb50d1c5c3bd3 Mon Sep 17 00:00:00 2001
+Date: Tue, 30 Apr 2019 19:15:30 +0100
+Subject: [PATCH] bcm2835-pcm.c: Support multichannel audio
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -14,9 +14,9 @@ static const struct snd_pcm_hardware snd
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
++ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
+ .rate_min = 8000,
+- .rate_max = 48000,
++ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+@@ -31,15 +31,16 @@ static const struct snd_pcm_hardware snd
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
+- SNDRV_PCM_RATE_48000,
++ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
++ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
++ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+ .rate_min = 44100,
+- .rate_max = 48000,
++ .rate_max = 192000,
+ .channels_min = 2,
+- .channels_max = 2,
+- .buffer_bytes_max = 128 * 1024,
++ .channels_max = 8,
++ .buffer_bytes_max = 512 * 1024,
+ .period_bytes_min = 1 * 1024,
+- .period_bytes_max = 128 * 1024,
++ .period_bytes_max = 512 * 1024,
+ .periods_min = 1,
+ .periods_max = 128,
+ };
+++ /dev/null
-From d49649e2dcf0d5775e92677d37e229e0387fe82a Mon Sep 17 00:00:00 2001
-Date: Sat, 18 May 2019 12:26:11 +0200
-Subject: [PATCH] thermal: brcmstb_thermal: Add BCM2838 support
-
-The BCM2838 has an AVS TMON hardware block. This adds the necessary
-support to the brcmstb_thermal driver ( no trip handling ).
-
----
- drivers/thermal/broadcom/Kconfig | 2 +-
- drivers/thermal/broadcom/brcmstb_thermal.c | 65 +++++++++++++++++++---
- 2 files changed, 58 insertions(+), 9 deletions(-)
-
---- a/drivers/thermal/broadcom/Kconfig
-+++ b/drivers/thermal/broadcom/Kconfig
-@@ -8,7 +8,7 @@ config BCM2835_THERMAL
-
- config BRCMSTB_THERMAL
- tristate "Broadcom STB AVS TMON thermal driver"
-- depends on ARCH_BRCMSTB || COMPILE_TEST
-+ depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
- help
- Enable this driver if you have a Broadcom STB SoC and would like
- thermal framework support.
---- a/drivers/thermal/broadcom/brcmstb_thermal.c
-+++ b/drivers/thermal/broadcom/brcmstb_thermal.c
-@@ -19,6 +19,7 @@
- #define pr_fmt(fmt) DRV_NAME ": " fmt
-
- #include <linux/bitops.h>
-+#include <linux/clk.h>
- #include <linux/device.h>
- #include <linux/err.h>
- #include <linux/io.h>
-@@ -31,9 +32,6 @@
- #include <linux/thermal.h>
-
- #define AVS_TMON_STATUS 0x00
-- #define AVS_TMON_STATUS_valid_msk BIT(11)
-- #define AVS_TMON_STATUS_data_msk GENMASK(10, 1)
-- #define AVS_TMON_STATUS_data_shift 1
-
- #define AVS_TMON_EN_OVERTEMP_RESET 0x04
- #define AVS_TMON_EN_OVERTEMP_RESET_msk BIT(0)
-@@ -111,10 +109,19 @@ static struct avs_tmon_trip avs_tmon_tri
- },
- };
-
-+struct brcmstb_thermal_of_data {
-+ const struct thermal_zone_of_device_ops *of_ops;
-+ u32 status_valid_mask;
-+ u32 status_data_mask;
-+ u32 status_data_shift;
-+};
-+
- struct brcmstb_thermal_priv {
- void __iomem *tmon_base;
- struct device *dev;
- struct thermal_zone_device *thermal;
-+ struct clk *clk;
-+ const struct brcmstb_thermal_of_data *socdata;
- };
-
- static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int *slope,
-@@ -164,17 +171,18 @@ static inline u32 avs_tmon_temp_to_code(
- static int brcmstb_get_temp(void *data, int *temp)
- {
- struct brcmstb_thermal_priv *priv = data;
-+ const struct brcmstb_thermal_of_data *socdata = priv->socdata;
- u32 val;
- long t;
-
- val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
-
-- if (!(val & AVS_TMON_STATUS_valid_msk)) {
-+ if (!(val & socdata->status_valid_mask)) {
- dev_err(priv->dev, "reading not valid\n");
- return -EIO;
- }
-
-- val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
-+ val = (val & socdata->status_data_mask) >> socdata->status_data_shift;
-
- t = avs_tmon_code_to_temp(priv->thermal, val);
- if (t < 0)
-@@ -299,13 +307,34 @@ static int brcmstb_set_trips(void *data,
- return 0;
- }
-
--static struct thermal_zone_of_device_ops of_ops = {
-+static const struct thermal_zone_of_device_ops bcm7445_thermal_of_ops = {
- .get_temp = brcmstb_get_temp,
- .set_trips = brcmstb_set_trips,
- };
-
-+static const struct thermal_zone_of_device_ops bcm2838_thermal_of_ops = {
-+ .get_temp = brcmstb_get_temp,
-+};
-+
-+static const struct brcmstb_thermal_of_data bcm7445_thermal_of_data = {
-+ .of_ops = &bcm7445_thermal_of_ops,
-+ .status_valid_mask = BIT(11),
-+ .status_data_mask = GENMASK(10, 1),
-+ .status_data_shift = 1,
-+};
-+
-+static const struct brcmstb_thermal_of_data bcm2838_thermal_of_data = {
-+ .of_ops = &bcm2838_thermal_of_ops,
-+ .status_valid_mask = BIT(10),
-+ .status_data_mask = GENMASK(9, 0),
-+ .status_data_shift = 0,
-+};
-+
- static const struct of_device_id brcmstb_thermal_id_table[] = {
-- { .compatible = "brcm,avs-tmon" },
-+ { .compatible = "brcm,avs-tmon",
-+ .data = &bcm7445_thermal_of_data },
-+ { .compatible = "brcm,avs-tmon-bcm2838",
-+ .data = &bcm2838_thermal_of_data },
- {},
- };
- MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
-@@ -326,10 +355,27 @@ static int brcmstb_thermal_probe(struct
- if (IS_ERR(priv->tmon_base))
- return PTR_ERR(priv->tmon_base);
-
-+ priv->socdata = of_device_get_match_data(&pdev->dev);
-+ if (!priv->socdata) {
-+ dev_err(&pdev->dev, "no device match found\n");
-+ return -ENODEV;
-+ }
-+
-+ priv->clk = devm_clk_get(&pdev->dev, NULL);
-+ if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER)
-+ return -EPROBE_DEFER;
-+
-+ if (!IS_ERR(priv->clk)) {
-+ ret = clk_prepare_enable(priv->clk);
-+ if (ret)
-+ return ret;
-+ }
-+
- priv->dev = &pdev->dev;
- platform_set_drvdata(pdev, priv);
-
-- thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &of_ops);
-+ thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv,
-+ priv->socdata->of_ops);
- if (IS_ERR(thermal)) {
- ret = PTR_ERR(thermal);
- dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
-@@ -369,6 +415,9 @@ static int brcmstb_thermal_exit(struct p
- if (thermal)
- thermal_zone_of_sensor_unregister(&pdev->dev, priv->thermal);
-
-+ if (!IS_ERR(priv->clk))
-+ clk_disable_unprepare(priv->clk);
-+
- return 0;
- }
-
--- /dev/null
+From 12865021c91e21ca7189c6a84688459d400de204 Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Sep 2018 14:44:53 +0100
+Subject: [PATCH] bcmgenet: constrain max DMA burst length
+
+---
+ drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+@@ -31,7 +31,7 @@
+ #define ENET_PAD 8
+ #define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \
+ ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD)
+-#define DMA_MAX_BURST_LENGTH 0x10
++#define DMA_MAX_BURST_LENGTH 0x08
+
+ /* misc. configuration */
+ #define CLEAR_ALL_HFB 0xFF
+++ /dev/null
-From d5c6191cc94b358de183cc8c88a5722a79445202 Mon Sep 17 00:00:00 2001
-Date: Thu, 1 Nov 2018 17:31:37 +0000
-Subject: [PATCH] vchiq: Add 36-bit address support
-
-Conditional on a new compatible string, change the pagelist encoding
-such that the top 24 bits are the pfn, leaving 8 bits for run length
-(-1).
-
----
- .../interface/vchiq_arm/vchiq_2835_arm.c | 90 ++++++++++++++-----
- .../interface/vchiq_arm/vchiq_arm.c | 6 ++
- .../interface/vchiq_arm/vchiq_arm.h | 1 +
- 3 files changed, 75 insertions(+), 22 deletions(-)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
-@@ -47,6 +47,8 @@
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
- #define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
-+#define VC_SAFE(x) (g_use_36bit_addrs ? ((u32)(x) | 0xc0000000) : (u32)(x))
-+#define IS_VC_SAFE(x) (g_use_36bit_addrs ? !((x) & ~0x3fffffffull) : 1)
-
- #include "vchiq_arm.h"
- #include "vchiq_connected.h"
-@@ -96,6 +98,7 @@ static void __iomem *g_regs;
- */
- static unsigned int g_cache_line_size;
- static struct dma_pool *g_dma_pool;
-+static unsigned int g_use_36bit_addrs = 0;
- static unsigned int g_fragments_size;
- static char *g_fragments_base;
- static char *g_free_fragments;
-@@ -139,6 +142,8 @@ int vchiq_platform_init(struct platform_
- g_cache_line_size = drvdata->cache_line_size;
- g_fragments_size = 2 * g_cache_line_size;
-
-+ g_use_36bit_addrs = (dev->dma_pfn_offset == 0);
-+
- /* Allocate space for the channels in coherent memory */
- slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
- frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS);
-@@ -150,14 +155,21 @@ int vchiq_platform_init(struct platform_
- return -ENOMEM;
- }
-
-+ if (!IS_VC_SAFE(slot_phys)) {
-+ dev_err(dev, "allocated DMA memory %pad is not VC-safe\n",
-+ &slot_phys);
-+ return -ENOMEM;
-+ }
-+
- WARN_ON(((unsigned long)slot_mem & (PAGE_SIZE - 1)) != 0);
-+ channelbase = VC_SAFE(slot_phys);
-
- vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size);
- if (!vchiq_slot_zero)
- return -EINVAL;
-
- vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] =
-- (int)slot_phys + slot_mem_size;
-+ channelbase + slot_mem_size;
- vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
- MAX_FRAGMENTS;
-
-@@ -193,7 +205,6 @@ int vchiq_platform_init(struct platform_
- }
-
- /* Send the base address of the slots to VideoCore */
-- channelbase = slot_phys;
- err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT,
- &channelbase, sizeof(channelbase));
- if (err || channelbase) {
-@@ -282,7 +293,7 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu
- return VCHIQ_ERROR;
-
- bulk->handle = memhandle;
-- bulk->data = (void *)(unsigned long)pagelistinfo->dma_addr;
-+ bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr);
-
- /*
- * Store the pagelistinfo address in remote_data,
-@@ -570,25 +581,60 @@ create_pagelist(char __user *buf, size_t
-
- /* Combine adjacent blocks for performance */
- k = 0;
-- for_each_sg(scatterlist, sg, dma_buffers, i) {
-- u32 len = sg_dma_len(sg);
-- u32 addr = sg_dma_address(sg);
--
-- /* Note: addrs is the address + page_count - 1
-- * The firmware expects blocks after the first to be page-
-- * aligned and a multiple of the page size
-- */
-- WARN_ON(len == 0);
-- WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
-- WARN_ON(i && (addr & ~PAGE_MASK));
-- if (k > 0 &&
-- ((addrs[k - 1] & PAGE_MASK) +
-- (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT))
-- == (addr & PAGE_MASK))
-- addrs[k - 1] += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT);
-- else
-- addrs[k++] = (addr & PAGE_MASK) |
-- (((len + PAGE_SIZE - 1) >> PAGE_SHIFT) - 1);
-+ if (g_use_36bit_addrs) {
-+ for_each_sg(scatterlist, sg, dma_buffers, i) {
-+ u32 len = sg_dma_len(sg);
-+ u64 addr = sg_dma_address(sg);
-+ u32 page_id = (u32)((addr >> 4) & ~0xff);
-+ u32 sg_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-+
-+ /* Note: addrs is the address + page_count - 1
-+ * The firmware expects blocks after the first to be page-
-+ * aligned and a multiple of the page size
-+ */
-+ WARN_ON(len == 0);
-+ WARN_ON(i &&
-+ (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
-+ WARN_ON(i && (addr & ~PAGE_MASK));
-+ WARN_ON(upper_32_bits(addr) > 0xf);
-+ if (k > 0 &&
-+ ((addrs[k - 1] & ~0xff) +
-+ (((addrs[k - 1] & 0xff) + 1) << 8)
-+ == page_id)) {
-+ u32 inc_pages = min(sg_pages,
-+ 0xff - (addrs[k - 1] & 0xff));
-+ addrs[k - 1] += inc_pages;
-+ page_id += inc_pages << 8;
-+ sg_pages -= inc_pages;
-+ }
-+ while (sg_pages) {
-+ u32 inc_pages = min(sg_pages, 0x100u);
-+ addrs[k++] = page_id | (inc_pages - 1);
-+ page_id += inc_pages << 8;
-+ sg_pages -= inc_pages;
-+ }
-+ }
-+ } else {
-+ for_each_sg(scatterlist, sg, dma_buffers, i) {
-+ u32 len = sg_dma_len(sg);
-+ u32 addr = VC_SAFE(sg_dma_address(sg));
-+ u32 new_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-+
-+ /* Note: addrs is the address + page_count - 1
-+ * The firmware expects blocks after the first to be page-
-+ * aligned and a multiple of the page size
-+ */
-+ WARN_ON(len == 0);
-+ WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
-+ WARN_ON(i && (addr & ~PAGE_MASK));
-+ if (k > 0 &&
-+ ((addrs[k - 1] & PAGE_MASK) +
-+ (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT))
-+ == (addr & PAGE_MASK))
-+ addrs[k - 1] += new_pages;
-+ else
-+ addrs[k++] = (addr & PAGE_MASK) | (new_pages - 1);
-+ }
- }
-
- /* Partial cache lines (fragments) require special measures */
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -181,6 +181,11 @@ static struct vchiq_drvdata bcm2836_drvd
- .cache_line_size = 64,
- };
-
-+static struct vchiq_drvdata bcm2838_drvdata = {
-+ .cache_line_size = 64,
-+ .use_36bit_addrs = true,
-+};
-+
- static const char *const ioctl_names[] = {
- "CONNECT",
- "SHUTDOWN",
-@@ -3618,6 +3623,7 @@ vchiq_register_child(struct platform_dev
- static const struct of_device_id vchiq_of_match[] = {
- { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata },
- { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata },
-+ { .compatible = "brcm,bcm2838-vchiq", .data = &bcm2838_drvdata },
- {},
- };
- MODULE_DEVICE_TABLE(of, vchiq_of_match);
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
-@@ -125,6 +125,7 @@ typedef struct vchiq_arm_state_struct {
-
- struct vchiq_drvdata {
- const unsigned int cache_line_size;
-+ const bool use_36bit_addrs;
- struct rpi_firmware *fw;
- };
-
+++ /dev/null
-From 69d7e7d0f958186a0f7667ebeefdb50d1c5c3bd3 Mon Sep 17 00:00:00 2001
-Date: Tue, 30 Apr 2019 19:15:30 +0100
-Subject: [PATCH] bcm2835-pcm.c: Support multichannel audio
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 17 +++++++++--------
- 1 file changed, 9 insertions(+), 8 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -14,9 +14,9 @@ static const struct snd_pcm_hardware snd
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
- .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
-- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
-+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
- .rate_min = 8000,
-- .rate_max = 48000,
-+ .rate_max = 192000,
- .channels_min = 1,
- .channels_max = 2,
- .buffer_bytes_max = 128 * 1024,
-@@ -31,15 +31,16 @@ static const struct snd_pcm_hardware snd
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
-- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
-- SNDRV_PCM_RATE_48000,
-+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
-+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
-+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
- .rate_min = 44100,
-- .rate_max = 48000,
-+ .rate_max = 192000,
- .channels_min = 2,
-- .channels_max = 2,
-- .buffer_bytes_max = 128 * 1024,
-+ .channels_max = 8,
-+ .buffer_bytes_max = 512 * 1024,
- .period_bytes_min = 1 * 1024,
-- .period_bytes_max = 128 * 1024,
-+ .period_bytes_max = 512 * 1024,
- .periods_min = 1,
- .periods_max = 128,
- };
--- /dev/null
+From bb3075a2edb5c55d0ea7470da8bb44cc9f36aa02 Mon Sep 17 00:00:00 2001
+Date: Wed, 27 Mar 2019 13:45:46 +0000
+Subject: [PATCH] bcmgenet: Better coalescing parameter defaults
+
+Set defaults for TX and RX packet coalescing to be equivalent to:
+
+ # ethtool -C eth0 tx-frames 10
+ # ethtool -C eth0 rx-usecs 50
+
+This may be something we want to set via DT parameters in the
+future.
+
+---
+ drivers/net/ethernet/broadcom/genet/bcmgenet.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+@@ -2147,7 +2147,7 @@ static void bcmgenet_init_tx_ring(struct
+
+ bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);
+ bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);
+- bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH);
++ bcmgenet_tdma_ring_writel(priv, index, 10, DMA_MBUF_DONE_THRESH);
+ /* Disable rate control for now */
+ bcmgenet_tdma_ring_writel(priv, index, flow_period_val,
+ TDMA_FLOW_PERIOD);
+@@ -3576,9 +3576,12 @@ static int bcmgenet_probe(struct platfor
+ netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1);
+
+ /* Set default coalescing parameters */
+- for (i = 0; i < priv->hw_params->rx_queues; i++)
++ for (i = 0; i < priv->hw_params->rx_queues; i++) {
+ priv->rx_rings[i].rx_max_coalesced_frames = 1;
++ priv->rx_rings[i].rx_coalesce_usecs = 50;
++ }
+ priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1;
++ priv->rx_rings[DESC_INDEX].rx_coalesce_usecs = 50;
+
+ /* libphy will determine the link state */
+ netif_carrier_off(dev);
+++ /dev/null
-From 12865021c91e21ca7189c6a84688459d400de204 Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Sep 2018 14:44:53 +0100
-Subject: [PATCH] bcmgenet: constrain max DMA burst length
-
----
- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
-+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
-@@ -31,7 +31,7 @@
- #define ENET_PAD 8
- #define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \
- ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD)
--#define DMA_MAX_BURST_LENGTH 0x10
-+#define DMA_MAX_BURST_LENGTH 0x08
-
- /* misc. configuration */
- #define CLEAR_ALL_HFB 0xFF
--- /dev/null
+From d8b59e9245f8b2a231eeaa35b4a42f30cdbd5304 Mon Sep 17 00:00:00 2001
+Date: Tue, 14 May 2019 17:17:59 +0100
+Subject: [PATCH] net: genet: enable link energy detect powerdown for
+ external PHYs
+
+There are several warts surrounding bcmgenet_mii_probe() as this
+function is called from ndo_open, but it's calling registration-type
+functions. The probe should be called at probe time and refactored
+such that the PHY device data can be extracted to limit the scope
+of this flag to Broadcom PHYs.
+
+For now, pass this flag in as it puts our attached PHY into a low-power
+state when disconnected.
+
+---
+ drivers/net/ethernet/broadcom/genet/bcmmii.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
++++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
+@@ -318,6 +318,8 @@ int bcmgenet_mii_probe(struct net_device
+ /* Communicate the integrated PHY revision */
+ if (priv->internal_phy)
+ phy_flags = priv->gphy_rev;
++ else
++ phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE;
+
+ /* Initialize link state variables that bcmgenet_mii_setup() uses */
+ priv->old_link = -1;
+++ /dev/null
-From bb3075a2edb5c55d0ea7470da8bb44cc9f36aa02 Mon Sep 17 00:00:00 2001
-Date: Wed, 27 Mar 2019 13:45:46 +0000
-Subject: [PATCH] bcmgenet: Better coalescing parameter defaults
-
-Set defaults for TX and RX packet coalescing to be equivalent to:
-
- # ethtool -C eth0 tx-frames 10
- # ethtool -C eth0 rx-usecs 50
-
-This may be something we want to set via DT parameters in the
-future.
-
----
- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 7 +++++--
- 1 file changed, 5 insertions(+), 2 deletions(-)
-
---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-@@ -2147,7 +2147,7 @@ static void bcmgenet_init_tx_ring(struct
-
- bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);
- bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);
-- bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH);
-+ bcmgenet_tdma_ring_writel(priv, index, 10, DMA_MBUF_DONE_THRESH);
- /* Disable rate control for now */
- bcmgenet_tdma_ring_writel(priv, index, flow_period_val,
- TDMA_FLOW_PERIOD);
-@@ -3576,9 +3576,12 @@ static int bcmgenet_probe(struct platfor
- netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1);
-
- /* Set default coalescing parameters */
-- for (i = 0; i < priv->hw_params->rx_queues; i++)
-+ for (i = 0; i < priv->hw_params->rx_queues; i++) {
- priv->rx_rings[i].rx_max_coalesced_frames = 1;
-+ priv->rx_rings[i].rx_coalesce_usecs = 50;
-+ }
- priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1;
-+ priv->rx_rings[DESC_INDEX].rx_coalesce_usecs = 50;
-
- /* libphy will determine the link state */
- netif_carrier_off(dev);
--- /dev/null
+From 8eb54bbd5e6ebb929d390432163589f4c3dc0c14 Mon Sep 17 00:00:00 2001
+Date: Tue, 14 May 2019 17:00:41 +0100
+Subject: [PATCH] phy: broadcom: split out the BCM54213PE from the
+ BCM54210E IDs
+
+The last nibble is a revision ID, and the 54213pe is a later rev
+than the 54210e. Running the 54210e setup code on a 54213pe results
+in a broken RGMII interface.
+
+---
+ drivers/net/phy/broadcom.c | 17 ++++++++++++++---
+ include/linux/brcmphy.h | 1 +
+ 2 files changed, 15 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/phy/broadcom.c
++++ b/drivers/net/phy/broadcom.c
+@@ -222,7 +222,8 @@ static void bcm54xx_adjust_rxrefclk(stru
+ /* Abort if we are using an untested phy. */
+ if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
+ BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
+- BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
++ BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M &&
++ BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54213PE)
+ return;
+
+ val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
+@@ -604,7 +605,7 @@ static struct phy_driver broadcom_driver
+ .config_intr = bcm_phy_config_intr,
+ }, {
+ .phy_id = PHY_ID_BCM54210E,
+- .phy_id_mask = 0xfffffff0,
++ .phy_id_mask = 0xffffffff,
+ .name = "Broadcom BCM54210E",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+@@ -612,6 +613,15 @@ static struct phy_driver broadcom_driver
+ .ack_interrupt = bcm_phy_ack_intr,
+ .config_intr = bcm_phy_config_intr,
+ }, {
++ .phy_id = PHY_ID_BCM54213PE,
++ .phy_id_mask = 0xffffffff,
++ .name = "Broadcom BCM54213PE",
++ .features = PHY_GBIT_FEATURES,
++ .flags = PHY_HAS_INTERRUPT,
++ .config_init = bcm54xx_config_init,
++ .ack_interrupt = bcm_phy_ack_intr,
++ .config_intr = bcm_phy_config_intr,
++}, {
+ .phy_id = PHY_ID_BCM5461,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Broadcom BCM5461",
+@@ -748,7 +758,8 @@ module_phy_driver(broadcom_drivers);
+ static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
+ { PHY_ID_BCM5411, 0xfffffff0 },
+ { PHY_ID_BCM5421, 0xfffffff0 },
+- { PHY_ID_BCM54210E, 0xfffffff0 },
++ { PHY_ID_BCM54210E, 0xffffffff },
++ { PHY_ID_BCM54213PE, 0xffffffff },
+ { PHY_ID_BCM5461, 0xfffffff0 },
+ { PHY_ID_BCM54612E, 0xfffffff0 },
+ { PHY_ID_BCM54616S, 0xfffffff0 },
+--- a/include/linux/brcmphy.h
++++ b/include/linux/brcmphy.h
+@@ -20,6 +20,7 @@
+ #define PHY_ID_BCM5411 0x00206070
+ #define PHY_ID_BCM5421 0x002060e0
+ #define PHY_ID_BCM54210E 0x600d84a0
++#define PHY_ID_BCM54213PE 0x600d84a2
+ #define PHY_ID_BCM5464 0x002060b0
+ #define PHY_ID_BCM5461 0x002060c0
+ #define PHY_ID_BCM54612E 0x03625e60
+++ /dev/null
-From d8b59e9245f8b2a231eeaa35b4a42f30cdbd5304 Mon Sep 17 00:00:00 2001
-Date: Tue, 14 May 2019 17:17:59 +0100
-Subject: [PATCH] net: genet: enable link energy detect powerdown for
- external PHYs
-
-There are several warts surrounding bcmgenet_mii_probe() as this
-function is called from ndo_open, but it's calling registration-type
-functions. The probe should be called at probe time and refactored
-such that the PHY device data can be extracted to limit the scope
-of this flag to Broadcom PHYs.
-
-For now, pass this flag in as it puts our attached PHY into a low-power
-state when disconnected.
-
----
- drivers/net/ethernet/broadcom/genet/bcmmii.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
-+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
-@@ -318,6 +318,8 @@ int bcmgenet_mii_probe(struct net_device
- /* Communicate the integrated PHY revision */
- if (priv->internal_phy)
- phy_flags = priv->gphy_rev;
-+ else
-+ phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE;
-
- /* Initialize link state variables that bcmgenet_mii_setup() uses */
- priv->old_link = -1;
--- /dev/null
+From dc2550fdfd0a46c3ec67e5003b3d69c29141406b Mon Sep 17 00:00:00 2001
+Date: Fri, 17 May 2019 13:31:21 +0100
+Subject: [PATCH] phy: bcm54213pe: configure the LED outputs to be more
+ user-friendly
+
+The default state was both LEDs indicating link speed.
+
+Change the default configuration to
+- Amber: 1000/100 link speed indication
+- Green: link present + activity indication
+
+---
+ drivers/net/phy/broadcom.c | 17 +++++++++++++++++
+ include/linux/brcmphy.h | 4 ++++
+ 2 files changed, 21 insertions(+)
+
+--- a/drivers/net/phy/broadcom.c
++++ b/drivers/net/phy/broadcom.c
+@@ -52,6 +52,21 @@ static int bcm54210e_config_init(struct
+ return 0;
+ }
+
++static void bcm54213pe_config_init(struct phy_device *phydev)
++{
++ u16 val;
++
++ /* Enable ACT+LINK indication on ACTIVITY trigger */
++ val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_LEDCTL);
++ val |= BCM54XX_SHD_LEDCTL_ACTLINK_EN;
++ bcm_phy_write_shadow(phydev, BCM54XX_SHD_LEDCTL, val);
++
++ /* Set ACTIVITY on LED "1" output, LINKSPD[1] on LED "3" output */
++ val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
++ BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD1);
++ bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
++}
++
+ static int bcm54612e_config_init(struct phy_device *phydev)
+ {
+ int reg;
+@@ -310,6 +325,8 @@ static int bcm54xx_config_init(struct ph
+ err = bcm54210e_config_init(phydev);
+ if (err)
+ return err;
++ } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54213PE) {
++ bcm54213pe_config_init(phydev);
+ } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) {
+ err = bcm54612e_config_init(phydev);
+ if (err)
+--- a/include/linux/brcmphy.h
++++ b/include/linux/brcmphy.h
+@@ -168,6 +168,10 @@
+ #define BCM54XX_SHD_SCR3_DLLAPD_DIS 0x0002
+ #define BCM54XX_SHD_SCR3_TRDDAPD 0x0004
+
++/* 01001: Additional LED trigger options */
++#define BCM54XX_SHD_LEDCTL 0x09
++#define BCM54XX_SHD_LEDCTL_ACTLINK_EN 0x0010
++
+ /* 01010: Auto Power-Down */
+ #define BCM54XX_SHD_APD 0x0a
+ #define BCM_APD_CLR_MASK 0xFE9F /* clear bits 5, 6 & 8 */
--- /dev/null
+From 856c8fdf68e589c89ed0518aab727c54fdff5afa Mon Sep 17 00:00:00 2001
+Date: Tue, 21 May 2019 13:36:52 +0100
+Subject: [PATCH] dwc_otg: Choose appropriate IRQ handover strategy
+
+2711 has no MPHI peripheral, but the ARM Control block can fake
+interrupts. Use the size of the DTB "mphi" reg block to determine
+which is required.
+
+---
+ drivers/usb/host/dwc_otg/dwc_otg_driver.c | 9 +++--
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 21 ++++++----
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 2 +
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 12 ++++--
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 41 +++++++++++++-------
+ drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 3 ++
+ 6 files changed, 60 insertions(+), 28 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
+@@ -806,14 +806,15 @@ static int dwc_otg_driver_probe(
+ if (!request_mem_region(_dev->resource[1].start,
+ _dev->resource[1].end - _dev->resource[1].start + 1,
+ "dwc_otg")) {
+- dev_dbg(&_dev->dev, "error reserving mapped memory\n");
+- retval = -EFAULT;
+- goto fail;
+- }
++ dev_dbg(&_dev->dev, "error reserving mapped memory\n");
++ retval = -EFAULT;
++ goto fail;
++ }
+
+ dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start,
+ _dev->resource[1].end -
+ _dev->resource[1].start + 1);
++ dwc_otg_device->os_dep.use_swirq = (_dev->resource[1].end - _dev->resource[1].start) == 0x200;
+ }
+
+ #else
+--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
+@@ -1347,8 +1347,12 @@ void notrace dwc_otg_fiq_fsm(struct fiq_
+ /* We got an interrupt, didn't handle it. */
+ if (kick_irq) {
+ state->mphi_int_count++;
+- FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
+- FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
++ if (state->mphi_regs.swirq_set) {
++ FIQ_WRITE(state->mphi_regs.swirq_set, 1);
++ } else {
++ FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
++ FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
++ }
+
+ }
+ state->fiq_done++;
+@@ -1406,11 +1410,14 @@ void notrace dwc_otg_fiq_nop(struct fiq_
+ state->mphi_int_count++;
+ gintmsk.d32 &= state->gintmsk_saved.d32;
+ FIQ_WRITE(state->dwc_regs_base + GINTMSK, gintmsk.d32);
+- /* Force a clear before another dummy send */
+- FIQ_WRITE(state->mphi_regs.intstat, (1<<29));
+- FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
+- FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
+-
++ if (state->mphi_regs.swirq_set) {
++ FIQ_WRITE(state->mphi_regs.swirq_set, 1);
++ } else {
++ /* Force a clear before another dummy send */
++ FIQ_WRITE(state->mphi_regs.intstat, (1<<29));
++ FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
++ FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
++ }
+ }
+ state->fiq_done++;
+ mb();
+--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
+@@ -118,6 +118,8 @@ typedef struct {
+ volatile void* outdda;
+ volatile void* outddb;
+ volatile void* intstat;
++ volatile void* swirq_set;
++ volatile void* swirq_clr;
+ } mphi_regs_t;
+
+ enum fiq_debug_level {
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
+@@ -220,16 +220,20 @@ exit_handler_routine:
+
+ /* The FIQ could have sneaked another interrupt in. If so, don't clear MPHI */
+ if ((gintmsk_new.d32 == ~0) && (haintmsk_new.d32 == 0x0000FFFF)) {
++ if (dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr) {
++ DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr, 1);
++ } else {
+ DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.intstat, (1<<16));
+- if (dwc_otg_hcd->fiq_state->mphi_int_count >= 50) {
+- fiq_print(FIQDBG_INT, dwc_otg_hcd->fiq_state, "MPHI CLR");
++ }
++ if (dwc_otg_hcd->fiq_state->mphi_int_count >= 50) {
++ fiq_print(FIQDBG_INT, dwc_otg_hcd->fiq_state, "MPHI CLR");
+ DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, ((1<<31) + (1<<16)));
+ while (!(DWC_READ_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & (1 << 17)))
+ ;
+ DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, (1<<31));
+ dwc_otg_hcd->fiq_state->mphi_int_count = 0;
+- }
+- int_done++;
++ }
++ int_done++;
+ }
+ haintmsk.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
+ /* Re-enable interrupts that the FIQ masked (first time round) */
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
+@@ -474,22 +474,37 @@ static void hcd_init_fiq(void *cookie)
+ set_fiq_regs(®s);
+ #endif
+
+- //Set the mphi periph to the required registers
+- dwc_otg_hcd->fiq_state->mphi_regs.base = otg_dev->os_dep.mphi_base;
+- dwc_otg_hcd->fiq_state->mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c;
+- dwc_otg_hcd->fiq_state->mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28;
+- dwc_otg_hcd->fiq_state->mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c;
+- dwc_otg_hcd->fiq_state->mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50;
+ dwc_otg_hcd->fiq_state->dwc_regs_base = otg_dev->os_dep.base;
+- DWC_WARN("MPHI regs_base at %px", dwc_otg_hcd->fiq_state->mphi_regs.base);
+- //Enable mphi peripheral
+- writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl);
++ //Set the mphi periph to the required registers
++ dwc_otg_hcd->fiq_state->mphi_regs.base = otg_dev->os_dep.mphi_base;
++ if (otg_dev->os_dep.use_swirq) {
++ dwc_otg_hcd->fiq_state->mphi_regs.swirq_set =
++ otg_dev->os_dep.mphi_base + 0x1f0;
++ dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr =
++ otg_dev->os_dep.mphi_base + 0x1f4;
++ DWC_WARN("Fake MPHI regs_base at 0x%08x",
++ (int)dwc_otg_hcd->fiq_state->mphi_regs.base);
++ } else {
++ dwc_otg_hcd->fiq_state->mphi_regs.ctrl =
++ otg_dev->os_dep.mphi_base + 0x4c;
++ dwc_otg_hcd->fiq_state->mphi_regs.outdda
++ = otg_dev->os_dep.mphi_base + 0x28;
++ dwc_otg_hcd->fiq_state->mphi_regs.outddb
++ = otg_dev->os_dep.mphi_base + 0x2c;
++ dwc_otg_hcd->fiq_state->mphi_regs.intstat
++ = otg_dev->os_dep.mphi_base + 0x50;
++ DWC_WARN("MPHI regs_base at %px",
++ dwc_otg_hcd->fiq_state->mphi_regs.base);
++
++ //Enable mphi peripheral
++ writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl);
+ #ifdef DEBUG
+- if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000)
+- DWC_WARN("MPHI periph has been enabled");
+- else
+- DWC_WARN("MPHI periph has NOT been enabled");
++ if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000)
++ DWC_WARN("MPHI periph has been enabled");
++ else
++ DWC_WARN("MPHI periph has NOT been enabled");
+ #endif
++ }
+ // Enable FIQ interrupt from USB peripheral
+ #ifdef CONFIG_ARM64
+ irq = otg_dev->os_dep.fiq_num;
+--- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
++++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
+@@ -102,6 +102,9 @@ typedef struct os_dependent {
+ /** Base address for MPHI peripheral */
+ void *mphi_base;
+
++ /** mphi_base actually points to the SWIRQ block */
++ bool use_swirq;
++
+ /** IRQ number (<0 if not valid) */
+ int irq_num;
+
+++ /dev/null
-From 8eb54bbd5e6ebb929d390432163589f4c3dc0c14 Mon Sep 17 00:00:00 2001
-Date: Tue, 14 May 2019 17:00:41 +0100
-Subject: [PATCH] phy: broadcom: split out the BCM54213PE from the
- BCM54210E IDs
-
-The last nibble is a revision ID, and the 54213pe is a later rev
-than the 54210e. Running the 54210e setup code on a 54213pe results
-in a broken RGMII interface.
-
----
- drivers/net/phy/broadcom.c | 17 ++++++++++++++---
- include/linux/brcmphy.h | 1 +
- 2 files changed, 15 insertions(+), 3 deletions(-)
-
---- a/drivers/net/phy/broadcom.c
-+++ b/drivers/net/phy/broadcom.c
-@@ -222,7 +222,8 @@ static void bcm54xx_adjust_rxrefclk(stru
- /* Abort if we are using an untested phy. */
- if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
- BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
-- BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
-+ BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M &&
-+ BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54213PE)
- return;
-
- val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
-@@ -604,7 +605,7 @@ static struct phy_driver broadcom_driver
- .config_intr = bcm_phy_config_intr,
- }, {
- .phy_id = PHY_ID_BCM54210E,
-- .phy_id_mask = 0xfffffff0,
-+ .phy_id_mask = 0xffffffff,
- .name = "Broadcom BCM54210E",
- .features = PHY_GBIT_FEATURES,
- .flags = PHY_HAS_INTERRUPT,
-@@ -612,6 +613,15 @@ static struct phy_driver broadcom_driver
- .ack_interrupt = bcm_phy_ack_intr,
- .config_intr = bcm_phy_config_intr,
- }, {
-+ .phy_id = PHY_ID_BCM54213PE,
-+ .phy_id_mask = 0xffffffff,
-+ .name = "Broadcom BCM54213PE",
-+ .features = PHY_GBIT_FEATURES,
-+ .flags = PHY_HAS_INTERRUPT,
-+ .config_init = bcm54xx_config_init,
-+ .ack_interrupt = bcm_phy_ack_intr,
-+ .config_intr = bcm_phy_config_intr,
-+}, {
- .phy_id = PHY_ID_BCM5461,
- .phy_id_mask = 0xfffffff0,
- .name = "Broadcom BCM5461",
-@@ -748,7 +758,8 @@ module_phy_driver(broadcom_drivers);
- static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
- { PHY_ID_BCM5411, 0xfffffff0 },
- { PHY_ID_BCM5421, 0xfffffff0 },
-- { PHY_ID_BCM54210E, 0xfffffff0 },
-+ { PHY_ID_BCM54210E, 0xffffffff },
-+ { PHY_ID_BCM54213PE, 0xffffffff },
- { PHY_ID_BCM5461, 0xfffffff0 },
- { PHY_ID_BCM54612E, 0xfffffff0 },
- { PHY_ID_BCM54616S, 0xfffffff0 },
---- a/include/linux/brcmphy.h
-+++ b/include/linux/brcmphy.h
-@@ -20,6 +20,7 @@
- #define PHY_ID_BCM5411 0x00206070
- #define PHY_ID_BCM5421 0x002060e0
- #define PHY_ID_BCM54210E 0x600d84a0
-+#define PHY_ID_BCM54213PE 0x600d84a2
- #define PHY_ID_BCM5464 0x002060b0
- #define PHY_ID_BCM5461 0x002060c0
- #define PHY_ID_BCM54612E 0x03625e60
+++ /dev/null
-From dc2550fdfd0a46c3ec67e5003b3d69c29141406b Mon Sep 17 00:00:00 2001
-Date: Fri, 17 May 2019 13:31:21 +0100
-Subject: [PATCH] phy: bcm54213pe: configure the LED outputs to be more
- user-friendly
-
-The default state was both LEDs indicating link speed.
-
-Change the default configuration to
-- Amber: 1000/100 link speed indication
-- Green: link present + activity indication
-
----
- drivers/net/phy/broadcom.c | 17 +++++++++++++++++
- include/linux/brcmphy.h | 4 ++++
- 2 files changed, 21 insertions(+)
-
---- a/drivers/net/phy/broadcom.c
-+++ b/drivers/net/phy/broadcom.c
-@@ -52,6 +52,21 @@ static int bcm54210e_config_init(struct
- return 0;
- }
-
-+static void bcm54213pe_config_init(struct phy_device *phydev)
-+{
-+ u16 val;
-+
-+ /* Enable ACT+LINK indication on ACTIVITY trigger */
-+ val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_LEDCTL);
-+ val |= BCM54XX_SHD_LEDCTL_ACTLINK_EN;
-+ bcm_phy_write_shadow(phydev, BCM54XX_SHD_LEDCTL, val);
-+
-+ /* Set ACTIVITY on LED "1" output, LINKSPD[1] on LED "3" output */
-+ val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
-+ BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD1);
-+ bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
-+}
-+
- static int bcm54612e_config_init(struct phy_device *phydev)
- {
- int reg;
-@@ -310,6 +325,8 @@ static int bcm54xx_config_init(struct ph
- err = bcm54210e_config_init(phydev);
- if (err)
- return err;
-+ } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54213PE) {
-+ bcm54213pe_config_init(phydev);
- } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) {
- err = bcm54612e_config_init(phydev);
- if (err)
---- a/include/linux/brcmphy.h
-+++ b/include/linux/brcmphy.h
-@@ -168,6 +168,10 @@
- #define BCM54XX_SHD_SCR3_DLLAPD_DIS 0x0002
- #define BCM54XX_SHD_SCR3_TRDDAPD 0x0004
-
-+/* 01001: Additional LED trigger options */
-+#define BCM54XX_SHD_LEDCTL 0x09
-+#define BCM54XX_SHD_LEDCTL_ACTLINK_EN 0x0010
-+
- /* 01010: Auto Power-Down */
- #define BCM54XX_SHD_APD 0x0a
- #define BCM_APD_CLR_MASK 0xFE9F /* clear bits 5, 6 & 8 */
--- /dev/null
+From ff7222c0771a5e28666335663571058e560ad32b Mon Sep 17 00:00:00 2001
+Date: Fri, 22 Mar 2019 09:47:14 +0000
+Subject: [PATCH] usb: xhci: Disable the XHCI 5 second timeout
+
+If the VL805 EEPROM has not been programmed then boot will hang for five
+seconds. The timeout seems to be arbitrary and is an unecessary
+delay on the first boot. Remove the timeout.
+
+This is common code and probably can't be upstreamed unless the timeout
+can be configurable somehow or perhaps the XHCI driver can be skipped
+on the first boot.
+---
+ drivers/usb/host/xhci.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -196,8 +196,9 @@ int xhci_reset(struct xhci_hcd *xhci)
+ if (xhci->quirks & XHCI_INTEL_HOST)
+ udelay(1000);
+
++ // Hack: reduce handshake timeout from 10s 0.5s due to unprogrammed vl805
+ ret = xhci_handshake(&xhci->op_regs->command,
+- CMD_RESET, 0, 10 * 1000 * 1000);
++ CMD_RESET, 0, 500 * 1000);
+ if (ret)
+ return ret;
+
+++ /dev/null
-From 856c8fdf68e589c89ed0518aab727c54fdff5afa Mon Sep 17 00:00:00 2001
-Date: Tue, 21 May 2019 13:36:52 +0100
-Subject: [PATCH] dwc_otg: Choose appropriate IRQ handover strategy
-
-2711 has no MPHI peripheral, but the ARM Control block can fake
-interrupts. Use the size of the DTB "mphi" reg block to determine
-which is required.
-
----
- drivers/usb/host/dwc_otg/dwc_otg_driver.c | 9 +++--
- drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 21 ++++++----
- drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 2 +
- drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 12 ++++--
- drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 41 +++++++++++++-------
- drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 3 ++
- 6 files changed, 60 insertions(+), 28 deletions(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
-@@ -806,14 +806,15 @@ static int dwc_otg_driver_probe(
- if (!request_mem_region(_dev->resource[1].start,
- _dev->resource[1].end - _dev->resource[1].start + 1,
- "dwc_otg")) {
-- dev_dbg(&_dev->dev, "error reserving mapped memory\n");
-- retval = -EFAULT;
-- goto fail;
-- }
-+ dev_dbg(&_dev->dev, "error reserving mapped memory\n");
-+ retval = -EFAULT;
-+ goto fail;
-+ }
-
- dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start,
- _dev->resource[1].end -
- _dev->resource[1].start + 1);
-+ dwc_otg_device->os_dep.use_swirq = (_dev->resource[1].end - _dev->resource[1].start) == 0x200;
- }
-
- #else
---- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
-@@ -1347,8 +1347,12 @@ void notrace dwc_otg_fiq_fsm(struct fiq_
- /* We got an interrupt, didn't handle it. */
- if (kick_irq) {
- state->mphi_int_count++;
-- FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
-- FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
-+ if (state->mphi_regs.swirq_set) {
-+ FIQ_WRITE(state->mphi_regs.swirq_set, 1);
-+ } else {
-+ FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
-+ FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
-+ }
-
- }
- state->fiq_done++;
-@@ -1406,11 +1410,14 @@ void notrace dwc_otg_fiq_nop(struct fiq_
- state->mphi_int_count++;
- gintmsk.d32 &= state->gintmsk_saved.d32;
- FIQ_WRITE(state->dwc_regs_base + GINTMSK, gintmsk.d32);
-- /* Force a clear before another dummy send */
-- FIQ_WRITE(state->mphi_regs.intstat, (1<<29));
-- FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
-- FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
--
-+ if (state->mphi_regs.swirq_set) {
-+ FIQ_WRITE(state->mphi_regs.swirq_set, 1);
-+ } else {
-+ /* Force a clear before another dummy send */
-+ FIQ_WRITE(state->mphi_regs.intstat, (1<<29));
-+ FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
-+ FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
-+ }
- }
- state->fiq_done++;
- mb();
---- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
-@@ -118,6 +118,8 @@ typedef struct {
- volatile void* outdda;
- volatile void* outddb;
- volatile void* intstat;
-+ volatile void* swirq_set;
-+ volatile void* swirq_clr;
- } mphi_regs_t;
-
- enum fiq_debug_level {
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
-@@ -220,16 +220,20 @@ exit_handler_routine:
-
- /* The FIQ could have sneaked another interrupt in. If so, don't clear MPHI */
- if ((gintmsk_new.d32 == ~0) && (haintmsk_new.d32 == 0x0000FFFF)) {
-+ if (dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr) {
-+ DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr, 1);
-+ } else {
- DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.intstat, (1<<16));
-- if (dwc_otg_hcd->fiq_state->mphi_int_count >= 50) {
-- fiq_print(FIQDBG_INT, dwc_otg_hcd->fiq_state, "MPHI CLR");
-+ }
-+ if (dwc_otg_hcd->fiq_state->mphi_int_count >= 50) {
-+ fiq_print(FIQDBG_INT, dwc_otg_hcd->fiq_state, "MPHI CLR");
- DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, ((1<<31) + (1<<16)));
- while (!(DWC_READ_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & (1 << 17)))
- ;
- DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, (1<<31));
- dwc_otg_hcd->fiq_state->mphi_int_count = 0;
-- }
-- int_done++;
-+ }
-+ int_done++;
- }
- haintmsk.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
- /* Re-enable interrupts that the FIQ masked (first time round) */
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-@@ -474,22 +474,37 @@ static void hcd_init_fiq(void *cookie)
- set_fiq_regs(®s);
- #endif
-
-- //Set the mphi periph to the required registers
-- dwc_otg_hcd->fiq_state->mphi_regs.base = otg_dev->os_dep.mphi_base;
-- dwc_otg_hcd->fiq_state->mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c;
-- dwc_otg_hcd->fiq_state->mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28;
-- dwc_otg_hcd->fiq_state->mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c;
-- dwc_otg_hcd->fiq_state->mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50;
- dwc_otg_hcd->fiq_state->dwc_regs_base = otg_dev->os_dep.base;
-- DWC_WARN("MPHI regs_base at %px", dwc_otg_hcd->fiq_state->mphi_regs.base);
-- //Enable mphi peripheral
-- writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl);
-+ //Set the mphi periph to the required registers
-+ dwc_otg_hcd->fiq_state->mphi_regs.base = otg_dev->os_dep.mphi_base;
-+ if (otg_dev->os_dep.use_swirq) {
-+ dwc_otg_hcd->fiq_state->mphi_regs.swirq_set =
-+ otg_dev->os_dep.mphi_base + 0x1f0;
-+ dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr =
-+ otg_dev->os_dep.mphi_base + 0x1f4;
-+ DWC_WARN("Fake MPHI regs_base at 0x%08x",
-+ (int)dwc_otg_hcd->fiq_state->mphi_regs.base);
-+ } else {
-+ dwc_otg_hcd->fiq_state->mphi_regs.ctrl =
-+ otg_dev->os_dep.mphi_base + 0x4c;
-+ dwc_otg_hcd->fiq_state->mphi_regs.outdda
-+ = otg_dev->os_dep.mphi_base + 0x28;
-+ dwc_otg_hcd->fiq_state->mphi_regs.outddb
-+ = otg_dev->os_dep.mphi_base + 0x2c;
-+ dwc_otg_hcd->fiq_state->mphi_regs.intstat
-+ = otg_dev->os_dep.mphi_base + 0x50;
-+ DWC_WARN("MPHI regs_base at %px",
-+ dwc_otg_hcd->fiq_state->mphi_regs.base);
-+
-+ //Enable mphi peripheral
-+ writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl);
- #ifdef DEBUG
-- if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000)
-- DWC_WARN("MPHI periph has been enabled");
-- else
-- DWC_WARN("MPHI periph has NOT been enabled");
-+ if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000)
-+ DWC_WARN("MPHI periph has been enabled");
-+ else
-+ DWC_WARN("MPHI periph has NOT been enabled");
- #endif
-+ }
- // Enable FIQ interrupt from USB peripheral
- #ifdef CONFIG_ARM64
- irq = otg_dev->os_dep.fiq_num;
---- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
-@@ -102,6 +102,9 @@ typedef struct os_dependent {
- /** Base address for MPHI peripheral */
- void *mphi_base;
-
-+ /** mphi_base actually points to the SWIRQ block */
-+ bool use_swirq;
-+
- /** IRQ number (<0 if not valid) */
- int irq_num;
-
--- /dev/null
+From 94a960e8933fb94b979f88c319aa54c304004b35 Mon Sep 17 00:00:00 2001
+Date: Thu, 23 May 2019 15:08:30 +0100
+Subject: [PATCH] usb: xhci: Show that the VIA VL805 supports LPM
+
+---
+ drivers/usb/host/xhci-pci.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -222,6 +222,10 @@ static void xhci_pci_quirks(struct devic
+ pdev->device == 0x3432)
+ xhci->quirks |= XHCI_BROKEN_STREAMS;
+
++ if (pdev->vendor == PCI_VENDOR_ID_VIA &&
++ pdev->device == 0x3483)
++ xhci->quirks |= XHCI_LPM_SUPPORT;
++
+ if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+ pdev->device == 0x1042)
+ xhci->quirks |= XHCI_BROKEN_STREAMS;
--- /dev/null
+From 21dd7cd6dc231287b92a8c8b9ecf9d0844c2d325 Mon Sep 17 00:00:00 2001
+Date: Mon, 13 May 2019 11:05:27 +0000
+Subject: [PATCH] spi: bcm2835: enable shared interrupt support
+
+Add shared interrupt support for this driver.
+
+---
+ drivers/spi/spi-bcm2835.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-bcm2835.c
++++ b/drivers/spi/spi-bcm2835.c
+@@ -150,6 +150,10 @@ static irqreturn_t bcm2835_spi_interrupt
+ struct spi_master *master = dev_id;
+ struct bcm2835_spi *bs = spi_master_get_devdata(master);
+
++ /* check if we got interrupt enabled */
++ if (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_INTR))
++ return IRQ_NONE;
++
+ /* Read as many bytes as possible from FIFO */
+ bcm2835_rd_fifo(bs);
+ /* Write as many bytes as possible to FIFO */
+@@ -756,7 +760,8 @@ static int bcm2835_spi_probe(struct plat
+ bcm2835_wr(bs, BCM2835_SPI_CS,
+ BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
+
+- err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
++ err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt,
++ IRQF_SHARED,
+ dev_name(&pdev->dev), master);
+ if (err) {
+ dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
+++ /dev/null
-From ff7222c0771a5e28666335663571058e560ad32b Mon Sep 17 00:00:00 2001
-Date: Fri, 22 Mar 2019 09:47:14 +0000
-Subject: [PATCH] usb: xhci: Disable the XHCI 5 second timeout
-
-If the VL805 EEPROM has not been programmed then boot will hang for five
-seconds. The timeout seems to be arbitrary and is an unecessary
-delay on the first boot. Remove the timeout.
-
-This is common code and probably can't be upstreamed unless the timeout
-can be configurable somehow or perhaps the XHCI driver can be skipped
-on the first boot.
----
- drivers/usb/host/xhci.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/usb/host/xhci.c
-+++ b/drivers/usb/host/xhci.c
-@@ -196,8 +196,9 @@ int xhci_reset(struct xhci_hcd *xhci)
- if (xhci->quirks & XHCI_INTEL_HOST)
- udelay(1000);
-
-+ // Hack: reduce handshake timeout from 10s 0.5s due to unprogrammed vl805
- ret = xhci_handshake(&xhci->op_regs->command,
-- CMD_RESET, 0, 10 * 1000 * 1000);
-+ CMD_RESET, 0, 500 * 1000);
- if (ret)
- return ret;
-
--- /dev/null
+From 0be0d6439128366a8d2ac0afaf88f19209171e51 Mon Sep 17 00:00:00 2001
+Date: Thu, 9 May 2019 14:30:37 +0100
+Subject: [PATCH] drivers: char: add chardev for mmap'ing Argon control
+ registers
+
+Based on the gpiomem driver, allow mapping of the decoder register
+spaces such that userspace can access control/status registers.
+This driver is intended for use with a custom ffmpeg backend accelerator
+prior to a v4l2 driver being written.
+
+---
+ drivers/char/broadcom/Kconfig | 8 +
+ drivers/char/broadcom/Makefile | 1 +
+ drivers/char/broadcom/argon-mem.c | 277 ++++++++++++++++++++++++++++++
+ 3 files changed, 286 insertions(+)
+ create mode 100644 drivers/char/broadcom/argon-mem.c
+
+--- a/drivers/char/broadcom/Kconfig
++++ b/drivers/char/broadcom/Kconfig
+@@ -49,3 +49,11 @@ config BCM2835_SMI_DEV
+ This driver provides a character device interface (ioctl + read/write) to
+ Broadcom's Secondary Memory interface. The low-level functionality is provided
+ by the SMI driver itself.
++
++config ARGON_MEM
++ tristate "Character device driver for the Argon decoder hardware"
++ default n
++ help
++ This driver provides a character device interface for memory-map operations
++ so userspace tools can access the control and status registers of the Argon
++ video decoder hardware.
+--- a/drivers/char/broadcom/Makefile
++++ b/drivers/char/broadcom/Makefile
+@@ -4,3 +4,4 @@ obj-$(CONFIG_BCM_VC_SM) += vc_sm
+
+ obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
+ obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o
++obj-$(CONFIG_ARGON_MEM) += argon-mem.o
+--- /dev/null
++++ b/drivers/char/broadcom/argon-mem.c
+@@ -0,0 +1,277 @@
++/**
++ * argon-mem.c - character device access to the Argon decoder registers
++ *
++ * Based on bcm2835-gpiomem.c. Provides IO memory access to the decoder
++ * register blocks such that ffmpeg plugins can access the hardware.
++ *
++ * Copyright (c) 2019, Raspberry Pi (Trading) Ltd.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/cdev.h>
++#include <linux/pagemap.h>
++#include <linux/io.h>
++
++#define DRIVER_NAME "argon-mem"
++#define DEVICE_MINOR 0
++
++struct argon_mem_priv {
++ dev_t devid;
++ struct class *class;
++ struct cdev argon_mem_cdev;
++ unsigned long regs_phys;
++ unsigned long mem_window_len;
++ struct device *dev;
++ const char *name;
++};
++
++static int argon_mem_open(struct inode *inode, struct file *file)
++{
++ int dev = iminor(inode);
++ int ret = 0;
++ struct argon_mem_priv *priv;
++ if (dev != DEVICE_MINOR)
++ ret = -ENXIO;
++
++ priv = container_of(inode->i_cdev, struct argon_mem_priv,
++ argon_mem_cdev);
++ if (!priv)
++ return -EINVAL;
++ file->private_data = priv;
++ return ret;
++}
++
++static int argon_mem_release(struct inode *inode, struct file *file)
++{
++ int dev = iminor(inode);
++ int ret = 0;
++
++ if (dev != DEVICE_MINOR)
++ ret = -ENXIO;
++
++ return ret;
++}
++
++static const struct vm_operations_struct argon_mem_vm_ops = {
++#ifdef CONFIG_HAVE_IOREMAP_PROT
++ .access = generic_access_phys
++#endif
++};
++
++static int argon_mem_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ struct argon_mem_priv *priv;
++ unsigned long pages;
++
++ priv = file->private_data;
++ pages = priv->regs_phys >> PAGE_SHIFT;
++ /*
++ * The address decode is far larger than the actual number of registers.
++ * Just map the whole lot in.
++ */
++ vma->vm_page_prot = phys_mem_access_prot(file, pages,
++ priv->mem_window_len,
++ vma->vm_page_prot);
++ vma->vm_ops = &argon_mem_vm_ops;
++ if (remap_pfn_range(vma, vma->vm_start,
++ pages,
++ priv->mem_window_len,
++ vma->vm_page_prot)) {
++ return -EAGAIN;
++ }
++ return 0;
++}
++
++static const struct file_operations
++argon_mem_fops = {
++ .owner = THIS_MODULE,
++ .open = argon_mem_open,
++ .release = argon_mem_release,
++ .mmap = argon_mem_mmap,
++};
++
++static const struct of_device_id argon_mem_of_match[];
++static int argon_mem_probe(struct platform_device *pdev)
++{
++ int err;
++ void *ptr_err;
++ const struct of_device_id *id;
++ struct device *dev = &pdev->dev;
++ struct device *argon_mem_dev;
++ struct resource *ioresource;
++ struct argon_mem_priv *priv;
++
++
++ /* Allocate buffers and instance data */
++
++ priv = kzalloc(sizeof(struct argon_mem_priv), GFP_KERNEL);
++
++ if (!priv) {
++ err = -ENOMEM;
++ goto failed_inst_alloc;
++ }
++ platform_set_drvdata(pdev, priv);
++
++ priv->dev = dev;
++ id = of_match_device(argon_mem_of_match, dev);
++ if (!id)
++ return -EINVAL;
++ priv->name = id->data;
++
++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (ioresource) {
++ priv->regs_phys = ioresource->start;
++ priv->mem_window_len = ioresource->end - ioresource->start;
++ } else {
++ dev_err(priv->dev, "failed to get IO resource");
++ err = -ENOENT;
++ goto failed_get_resource;
++ }
++
++ /* Create character device entries */
++
++ err = alloc_chrdev_region(&priv->devid,
++ DEVICE_MINOR, 1, priv->name);
++ if (err != 0) {
++ dev_err(priv->dev, "unable to allocate device number");
++ goto failed_alloc_chrdev;
++ }
++ cdev_init(&priv->argon_mem_cdev, &argon_mem_fops);
++ priv->argon_mem_cdev.owner = THIS_MODULE;
++ err = cdev_add(&priv->argon_mem_cdev, priv->devid, 1);
++ if (err != 0) {
++ dev_err(priv->dev, "unable to register device");
++ goto failed_cdev_add;
++ }
++
++ /* Create sysfs entries */
++
++ priv->class = class_create(THIS_MODULE, priv->name);
++ ptr_err = priv->class;
++ if (IS_ERR(ptr_err))
++ goto failed_class_create;
++
++ argon_mem_dev = device_create(priv->class, NULL,
++ priv->devid, NULL,
++ priv->name);
++ ptr_err = argon_mem_dev;
++ if (IS_ERR(ptr_err))
++ goto failed_device_create;
++
++ dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
++ priv->name, priv->regs_phys, priv->mem_window_len);
++
++ return 0;
++
++failed_device_create:
++ class_destroy(priv->class);
++failed_class_create:
++ cdev_del(&priv->argon_mem_cdev);
++ err = PTR_ERR(ptr_err);
++failed_cdev_add:
++ unregister_chrdev_region(priv->devid, 1);
++failed_alloc_chrdev:
++failed_get_resource:
++ kfree(priv);
++failed_inst_alloc:
++ dev_err(priv->dev, "could not load argon_mem");
++ return err;
++}
++
++static int argon_mem_remove(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct argon_mem_priv *priv = platform_get_drvdata(pdev);
++
++ device_destroy(priv->class, priv->devid);
++ class_destroy(priv->class);
++ cdev_del(&priv->argon_mem_cdev);
++ unregister_chrdev_region(priv->devid, 1);
++ kfree(priv);
++
++ dev_info(dev, "%s driver removed - OK", priv->name);
++ return 0;
++}
++
++static const char argon_hevc_name[] = "argon-hevcmem";
++static const char argon_h264_name[] = "argon-h264mem";
++static const char argon_vp9_name[] = "argon-vp9mem";
++static const char argon_intc_name[] = "argon-intcmem";
++
++static const struct of_device_id argon_mem_of_match[] = {
++ {
++ .compatible = "raspberrypi,argon-hevc-decoder",
++ .data = &argon_hevc_name,
++ },
++ {
++ .compatible = "raspberrypi,argon-h264-decoder",
++ .data = &argon_h264_name,
++ },
++ {
++ .compatible = "raspberrypi,argon-vp9-decoder",
++ .data = &argon_vp9_name,
++ },
++ /* The "intc" is included as this block of hardware contains the
++ * "frame done" status flags.
++ */
++ {
++ .compatible = "raspberrypi,argon-local-intc",
++ .data = &argon_intc_name,
++ },
++ { /* sentinel */ },
++};
++
++MODULE_DEVICE_TABLE(of, argon_mem_of_match);
++
++static struct platform_driver argon_mem_driver = {
++ .probe = argon_mem_probe,
++ .remove = argon_mem_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = argon_mem_of_match,
++ },
++};
++
++module_platform_driver(argon_mem_driver);
++
++MODULE_ALIAS("platform:argon-mem");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Driver for accessing Argon decoder registers from userspace");
+++ /dev/null
-From 94a960e8933fb94b979f88c319aa54c304004b35 Mon Sep 17 00:00:00 2001
-Date: Thu, 23 May 2019 15:08:30 +0100
-Subject: [PATCH] usb: xhci: Show that the VIA VL805 supports LPM
-
----
- drivers/usb/host/xhci-pci.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/usb/host/xhci-pci.c
-+++ b/drivers/usb/host/xhci-pci.c
-@@ -222,6 +222,10 @@ static void xhci_pci_quirks(struct devic
- pdev->device == 0x3432)
- xhci->quirks |= XHCI_BROKEN_STREAMS;
-
-+ if (pdev->vendor == PCI_VENDOR_ID_VIA &&
-+ pdev->device == 0x3483)
-+ xhci->quirks |= XHCI_LPM_SUPPORT;
-+
- if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
- pdev->device == 0x1042)
- xhci->quirks |= XHCI_BROKEN_STREAMS;
--- /dev/null
+From 3924edc9bd3c55d48c383c1046d75e163ce3cddb Mon Sep 17 00:00:00 2001
+Date: Wed, 23 Jan 2019 16:11:50 +0000
+Subject: [PATCH] clk-bcm2835: Don't wait for pllh lock
+
+---
+ drivers/clk/bcm/clk-bcm2835.c | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -627,15 +627,17 @@ static int bcm2835_pll_on(struct clk_hw
+ spin_unlock(&cprman->regs_lock);
+
+ /* Wait for the PLL to lock. */
+- timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
+- while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) {
+- if (ktime_after(ktime_get(), timeout)) {
+- dev_err(cprman->dev, "%s: couldn't lock PLL\n",
+- clk_hw_get_name(hw));
+- return -ETIMEDOUT;
+- }
++ if (strcmp(data->name, "pllh")) {
++ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
++ while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) {
++ if (ktime_after(ktime_get(), timeout)) {
++ dev_err(cprman->dev, "%s: couldn't lock PLL\n",
++ clk_hw_get_name(hw));
++ return -ETIMEDOUT;
++ }
+
+- cpu_relax();
++ cpu_relax();
++ }
+ }
+
+ cprman_write(cprman, data->a2w_ctrl_reg,
+++ /dev/null
-From 21dd7cd6dc231287b92a8c8b9ecf9d0844c2d325 Mon Sep 17 00:00:00 2001
-Date: Mon, 13 May 2019 11:05:27 +0000
-Subject: [PATCH] spi: bcm2835: enable shared interrupt support
-
-Add shared interrupt support for this driver.
-
----
- drivers/spi/spi-bcm2835.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
---- a/drivers/spi/spi-bcm2835.c
-+++ b/drivers/spi/spi-bcm2835.c
-@@ -150,6 +150,10 @@ static irqreturn_t bcm2835_spi_interrupt
- struct spi_master *master = dev_id;
- struct bcm2835_spi *bs = spi_master_get_devdata(master);
-
-+ /* check if we got interrupt enabled */
-+ if (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_INTR))
-+ return IRQ_NONE;
-+
- /* Read as many bytes as possible from FIFO */
- bcm2835_rd_fifo(bs);
- /* Write as many bytes as possible to FIFO */
-@@ -756,7 +760,8 @@ static int bcm2835_spi_probe(struct plat
- bcm2835_wr(bs, BCM2835_SPI_CS,
- BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
-
-- err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
-+ err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt,
-+ IRQF_SHARED,
- dev_name(&pdev->dev), master);
- if (err) {
- dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
--- /dev/null
+From 90964ab2d00546a59086ffd08964da3d2a5cefc9 Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Dec 2018 15:51:47 -0800
+Subject: [PATCH] bcm2835-pm: Move bcm2835-watchdog's DT probe to an
+ MFD.
+
+The PM block that the wdt driver was binding to actually has multiple
+features we want to expose (power domains, reset, watchdog). Move the
+DT attachment to a MFD driver and make WDT probe against MFD.
+
+(cherry picked from commit 5e6acc3e678ed3db746ab4fb53a980861cd711b6)
+---
+ drivers/mfd/Makefile | 1 +
+ drivers/mfd/bcm2835-pm.c | 64 ++++++++++++++++++++++++++++++++++
+ drivers/watchdog/bcm2835_wdt.c | 26 +++++---------
+ include/linux/mfd/bcm2835-pm.h | 13 +++++++
+ 4 files changed, 87 insertions(+), 17 deletions(-)
+ create mode 100644 drivers/mfd/bcm2835-pm.c
+ create mode 100644 include/linux/mfd/bcm2835-pm.h
+
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -10,6 +10,7 @@ obj-$(CONFIG_MFD_88PM805) += 88pm805.o 8
+ obj-$(CONFIG_MFD_ACT8945A) += act8945a.o
+ obj-$(CONFIG_MFD_SM501) += sm501.o
+ obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
++obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o
+ obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
+ obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o
+ cros_ec_core-objs := cros_ec.o
+--- /dev/null
++++ b/drivers/mfd/bcm2835-pm.c
+@@ -0,0 +1,64 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * PM MFD driver for Broadcom BCM2835
++ *
++ * This driver binds to the PM block and creates the MFD device for
++ * the WDT driver.
++ */
++
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/mfd/bcm2835-pm.h>
++#include <linux/mfd/core.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/types.h>
++#include <linux/watchdog.h>
++
++static const struct mfd_cell bcm2835_pm_devs[] = {
++ { .name = "bcm2835-wdt" },
++};
++
++static int bcm2835_pm_probe(struct platform_device *pdev)
++{
++ struct resource *res;
++ struct device *dev = &pdev->dev;
++ struct bcm2835_pm *pm;
++
++ pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL);
++ if (!pm)
++ return -ENOMEM;
++ platform_set_drvdata(pdev, pm);
++
++ pm->dev = dev;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ pm->base = devm_ioremap_resource(dev, res);
++ if (IS_ERR(pm->base))
++ return PTR_ERR(pm->base);
++
++ return devm_mfd_add_devices(dev, -1,
++ bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
++ NULL, 0, NULL);
++}
++
++static const struct of_device_id bcm2835_pm_of_match[] = {
++ { .compatible = "brcm,bcm2835-pm-wdt", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
++
++static struct platform_driver bcm2835_pm_driver = {
++ .probe = bcm2835_pm_probe,
++ .driver = {
++ .name = "bcm2835-pm",
++ .of_match_table = bcm2835_pm_of_match,
++ },
++};
++module_platform_driver(bcm2835_pm_driver);
++
++MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM MFD");
++MODULE_LICENSE("GPL");
+--- a/drivers/watchdog/bcm2835_wdt.c
++++ b/drivers/watchdog/bcm2835_wdt.c
+@@ -12,6 +12,7 @@
+
+ #include <linux/delay.h>
+ #include <linux/types.h>
++#include <linux/mfd/bcm2835-pm.h>
+ #include <linux/module.h>
+ #include <linux/io.h>
+ #include <linux/watchdog.h>
+@@ -41,6 +42,8 @@ struct bcm2835_wdt {
+ spinlock_t lock;
+ };
+
++static struct bcm2835_wdt *bcm2835_power_off_wdt;
++
+ static unsigned int heartbeat;
+ static bool nowayout = WATCHDOG_NOWAYOUT;
+
+@@ -163,10 +166,7 @@ static struct watchdog_device bcm2835_wd
+ */
+ static void bcm2835_power_off(void)
+ {
+- struct device_node *np =
+- of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt");
+- struct platform_device *pdev = of_find_device_by_node(np);
+- struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
++ struct bcm2835_wdt *wdt = bcm2835_power_off_wdt;
+
+ /* Partition 63 tells the firmware that this is a halt */
+ __bcm2835_restart(wdt, 63);
+@@ -174,7 +174,7 @@ static void bcm2835_power_off(void)
+
+ static int bcm2835_wdt_probe(struct platform_device *pdev)
+ {
+- struct resource *res;
++ struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct bcm2835_wdt *wdt;
+ int err;
+@@ -186,10 +186,7 @@ static int bcm2835_wdt_probe(struct plat
+
+ spin_lock_init(&wdt->lock);
+
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- wdt->base = devm_ioremap_resource(dev, res);
+- if (IS_ERR(wdt->base))
+- return PTR_ERR(wdt->base);
++ wdt->base = pm->base;
+
+ watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt);
+ watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev);
+@@ -216,8 +213,10 @@ static int bcm2835_wdt_probe(struct plat
+ return err;
+ }
+
+- if (pm_power_off == NULL)
++ if (pm_power_off == NULL) {
+ pm_power_off = bcm2835_power_off;
++ bcm2835_power_off_wdt = wdt;
++ }
+
+ dev_info(dev, "Broadcom BCM2835 watchdog timer");
+ return 0;
+@@ -231,18 +230,11 @@ static int bcm2835_wdt_remove(struct pla
+ return 0;
+ }
+
+-static const struct of_device_id bcm2835_wdt_of_match[] = {
+- { .compatible = "brcm,bcm2835-pm-wdt", },
+- {},
+-};
+-MODULE_DEVICE_TABLE(of, bcm2835_wdt_of_match);
+-
+ static struct platform_driver bcm2835_wdt_driver = {
+ .probe = bcm2835_wdt_probe,
+ .remove = bcm2835_wdt_remove,
+ .driver = {
+ .name = "bcm2835-wdt",
+- .of_match_table = bcm2835_wdt_of_match,
+ },
+ };
+ module_platform_driver(bcm2835_wdt_driver);
+--- /dev/null
++++ b/include/linux/mfd/bcm2835-pm.h
+@@ -0,0 +1,13 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++
++#ifndef BCM2835_MFD_PM_H
++#define BCM2835_MFD_PM_H
++
++#include <linux/regmap.h>
++
++struct bcm2835_pm {
++ struct device *dev;
++ void __iomem *base;
++};
++
++#endif /* BCM2835_MFD_PM_H */
+++ /dev/null
-From 0be0d6439128366a8d2ac0afaf88f19209171e51 Mon Sep 17 00:00:00 2001
-Date: Thu, 9 May 2019 14:30:37 +0100
-Subject: [PATCH] drivers: char: add chardev for mmap'ing Argon control
- registers
-
-Based on the gpiomem driver, allow mapping of the decoder register
-spaces such that userspace can access control/status registers.
-This driver is intended for use with a custom ffmpeg backend accelerator
-prior to a v4l2 driver being written.
-
----
- drivers/char/broadcom/Kconfig | 8 +
- drivers/char/broadcom/Makefile | 1 +
- drivers/char/broadcom/argon-mem.c | 277 ++++++++++++++++++++++++++++++
- 3 files changed, 286 insertions(+)
- create mode 100644 drivers/char/broadcom/argon-mem.c
-
---- a/drivers/char/broadcom/Kconfig
-+++ b/drivers/char/broadcom/Kconfig
-@@ -49,3 +49,11 @@ config BCM2835_SMI_DEV
- This driver provides a character device interface (ioctl + read/write) to
- Broadcom's Secondary Memory interface. The low-level functionality is provided
- by the SMI driver itself.
-+
-+config ARGON_MEM
-+ tristate "Character device driver for the Argon decoder hardware"
-+ default n
-+ help
-+ This driver provides a character device interface for memory-map operations
-+ so userspace tools can access the control and status registers of the Argon
-+ video decoder hardware.
---- a/drivers/char/broadcom/Makefile
-+++ b/drivers/char/broadcom/Makefile
-@@ -4,3 +4,4 @@ obj-$(CONFIG_BCM_VC_SM) += vc_sm
-
- obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
- obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o
-+obj-$(CONFIG_ARGON_MEM) += argon-mem.o
---- /dev/null
-+++ b/drivers/char/broadcom/argon-mem.c
-@@ -0,0 +1,277 @@
-+/**
-+ * argon-mem.c - character device access to the Argon decoder registers
-+ *
-+ * Based on bcm2835-gpiomem.c. Provides IO memory access to the decoder
-+ * register blocks such that ffmpeg plugins can access the hardware.
-+ *
-+ * Copyright (c) 2019, Raspberry Pi (Trading) Ltd.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/cdev.h>
-+#include <linux/pagemap.h>
-+#include <linux/io.h>
-+
-+#define DRIVER_NAME "argon-mem"
-+#define DEVICE_MINOR 0
-+
-+struct argon_mem_priv {
-+ dev_t devid;
-+ struct class *class;
-+ struct cdev argon_mem_cdev;
-+ unsigned long regs_phys;
-+ unsigned long mem_window_len;
-+ struct device *dev;
-+ const char *name;
-+};
-+
-+static int argon_mem_open(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode);
-+ int ret = 0;
-+ struct argon_mem_priv *priv;
-+ if (dev != DEVICE_MINOR)
-+ ret = -ENXIO;
-+
-+ priv = container_of(inode->i_cdev, struct argon_mem_priv,
-+ argon_mem_cdev);
-+ if (!priv)
-+ return -EINVAL;
-+ file->private_data = priv;
-+ return ret;
-+}
-+
-+static int argon_mem_release(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode);
-+ int ret = 0;
-+
-+ if (dev != DEVICE_MINOR)
-+ ret = -ENXIO;
-+
-+ return ret;
-+}
-+
-+static const struct vm_operations_struct argon_mem_vm_ops = {
-+#ifdef CONFIG_HAVE_IOREMAP_PROT
-+ .access = generic_access_phys
-+#endif
-+};
-+
-+static int argon_mem_mmap(struct file *file, struct vm_area_struct *vma)
-+{
-+ struct argon_mem_priv *priv;
-+ unsigned long pages;
-+
-+ priv = file->private_data;
-+ pages = priv->regs_phys >> PAGE_SHIFT;
-+ /*
-+ * The address decode is far larger than the actual number of registers.
-+ * Just map the whole lot in.
-+ */
-+ vma->vm_page_prot = phys_mem_access_prot(file, pages,
-+ priv->mem_window_len,
-+ vma->vm_page_prot);
-+ vma->vm_ops = &argon_mem_vm_ops;
-+ if (remap_pfn_range(vma, vma->vm_start,
-+ pages,
-+ priv->mem_window_len,
-+ vma->vm_page_prot)) {
-+ return -EAGAIN;
-+ }
-+ return 0;
-+}
-+
-+static const struct file_operations
-+argon_mem_fops = {
-+ .owner = THIS_MODULE,
-+ .open = argon_mem_open,
-+ .release = argon_mem_release,
-+ .mmap = argon_mem_mmap,
-+};
-+
-+static const struct of_device_id argon_mem_of_match[];
-+static int argon_mem_probe(struct platform_device *pdev)
-+{
-+ int err;
-+ void *ptr_err;
-+ const struct of_device_id *id;
-+ struct device *dev = &pdev->dev;
-+ struct device *argon_mem_dev;
-+ struct resource *ioresource;
-+ struct argon_mem_priv *priv;
-+
-+
-+ /* Allocate buffers and instance data */
-+
-+ priv = kzalloc(sizeof(struct argon_mem_priv), GFP_KERNEL);
-+
-+ if (!priv) {
-+ err = -ENOMEM;
-+ goto failed_inst_alloc;
-+ }
-+ platform_set_drvdata(pdev, priv);
-+
-+ priv->dev = dev;
-+ id = of_match_device(argon_mem_of_match, dev);
-+ if (!id)
-+ return -EINVAL;
-+ priv->name = id->data;
-+
-+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (ioresource) {
-+ priv->regs_phys = ioresource->start;
-+ priv->mem_window_len = ioresource->end - ioresource->start;
-+ } else {
-+ dev_err(priv->dev, "failed to get IO resource");
-+ err = -ENOENT;
-+ goto failed_get_resource;
-+ }
-+
-+ /* Create character device entries */
-+
-+ err = alloc_chrdev_region(&priv->devid,
-+ DEVICE_MINOR, 1, priv->name);
-+ if (err != 0) {
-+ dev_err(priv->dev, "unable to allocate device number");
-+ goto failed_alloc_chrdev;
-+ }
-+ cdev_init(&priv->argon_mem_cdev, &argon_mem_fops);
-+ priv->argon_mem_cdev.owner = THIS_MODULE;
-+ err = cdev_add(&priv->argon_mem_cdev, priv->devid, 1);
-+ if (err != 0) {
-+ dev_err(priv->dev, "unable to register device");
-+ goto failed_cdev_add;
-+ }
-+
-+ /* Create sysfs entries */
-+
-+ priv->class = class_create(THIS_MODULE, priv->name);
-+ ptr_err = priv->class;
-+ if (IS_ERR(ptr_err))
-+ goto failed_class_create;
-+
-+ argon_mem_dev = device_create(priv->class, NULL,
-+ priv->devid, NULL,
-+ priv->name);
-+ ptr_err = argon_mem_dev;
-+ if (IS_ERR(ptr_err))
-+ goto failed_device_create;
-+
-+ dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
-+ priv->name, priv->regs_phys, priv->mem_window_len);
-+
-+ return 0;
-+
-+failed_device_create:
-+ class_destroy(priv->class);
-+failed_class_create:
-+ cdev_del(&priv->argon_mem_cdev);
-+ err = PTR_ERR(ptr_err);
-+failed_cdev_add:
-+ unregister_chrdev_region(priv->devid, 1);
-+failed_alloc_chrdev:
-+failed_get_resource:
-+ kfree(priv);
-+failed_inst_alloc:
-+ dev_err(priv->dev, "could not load argon_mem");
-+ return err;
-+}
-+
-+static int argon_mem_remove(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct argon_mem_priv *priv = platform_get_drvdata(pdev);
-+
-+ device_destroy(priv->class, priv->devid);
-+ class_destroy(priv->class);
-+ cdev_del(&priv->argon_mem_cdev);
-+ unregister_chrdev_region(priv->devid, 1);
-+ kfree(priv);
-+
-+ dev_info(dev, "%s driver removed - OK", priv->name);
-+ return 0;
-+}
-+
-+static const char argon_hevc_name[] = "argon-hevcmem";
-+static const char argon_h264_name[] = "argon-h264mem";
-+static const char argon_vp9_name[] = "argon-vp9mem";
-+static const char argon_intc_name[] = "argon-intcmem";
-+
-+static const struct of_device_id argon_mem_of_match[] = {
-+ {
-+ .compatible = "raspberrypi,argon-hevc-decoder",
-+ .data = &argon_hevc_name,
-+ },
-+ {
-+ .compatible = "raspberrypi,argon-h264-decoder",
-+ .data = &argon_h264_name,
-+ },
-+ {
-+ .compatible = "raspberrypi,argon-vp9-decoder",
-+ .data = &argon_vp9_name,
-+ },
-+ /* The "intc" is included as this block of hardware contains the
-+ * "frame done" status flags.
-+ */
-+ {
-+ .compatible = "raspberrypi,argon-local-intc",
-+ .data = &argon_intc_name,
-+ },
-+ { /* sentinel */ },
-+};
-+
-+MODULE_DEVICE_TABLE(of, argon_mem_of_match);
-+
-+static struct platform_driver argon_mem_driver = {
-+ .probe = argon_mem_probe,
-+ .remove = argon_mem_remove,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = argon_mem_of_match,
-+ },
-+};
-+
-+module_platform_driver(argon_mem_driver);
-+
-+MODULE_ALIAS("platform:argon-mem");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Driver for accessing Argon decoder registers from userspace");
+++ /dev/null
-From 3924edc9bd3c55d48c383c1046d75e163ce3cddb Mon Sep 17 00:00:00 2001
-Date: Wed, 23 Jan 2019 16:11:50 +0000
-Subject: [PATCH] clk-bcm2835: Don't wait for pllh lock
-
----
- drivers/clk/bcm/clk-bcm2835.c | 18 ++++++++++--------
- 1 file changed, 10 insertions(+), 8 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -627,15 +627,17 @@ static int bcm2835_pll_on(struct clk_hw
- spin_unlock(&cprman->regs_lock);
-
- /* Wait for the PLL to lock. */
-- timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
-- while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) {
-- if (ktime_after(ktime_get(), timeout)) {
-- dev_err(cprman->dev, "%s: couldn't lock PLL\n",
-- clk_hw_get_name(hw));
-- return -ETIMEDOUT;
-- }
-+ if (strcmp(data->name, "pllh")) {
-+ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
-+ while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) {
-+ if (ktime_after(ktime_get(), timeout)) {
-+ dev_err(cprman->dev, "%s: couldn't lock PLL\n",
-+ clk_hw_get_name(hw));
-+ return -ETIMEDOUT;
-+ }
-
-- cpu_relax();
-+ cpu_relax();
-+ }
- }
-
- cprman_write(cprman, data->a2w_ctrl_reg,
--- /dev/null
+From fd8ca458728baabe9cae37836088a33c8642d420 Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Dec 2018 15:51:48 -0800
+Subject: [PATCH] soc: bcm: bcm2835-pm: Add support for power domains
+ under a new binding.
+
+This provides a free software alternative to raspberrypi-power.c's
+firmware calls to manage power domains. It also exposes a reset line,
+where previously the vc4 driver had to try to force power off the
+domain in order to trigger a reset.
+
+(cherry picked from commit 670c672608a1ffcbc7ac0f872734843593bb8b15)
+---
+ drivers/mfd/bcm2835-pm.c | 36 +-
+ drivers/soc/bcm/Kconfig | 11 +
+ drivers/soc/bcm/Makefile | 1 +
+ drivers/soc/bcm/bcm2835-power.c | 661 +++++++++++++++++++++++++++
+ include/dt-bindings/soc/bcm2835-pm.h | 28 ++
+ include/linux/mfd/bcm2835-pm.h | 1 +
+ 6 files changed, 734 insertions(+), 4 deletions(-)
+ create mode 100644 drivers/soc/bcm/bcm2835-power.c
+ create mode 100644 include/dt-bindings/soc/bcm2835-pm.h
+
+--- a/drivers/mfd/bcm2835-pm.c
++++ b/drivers/mfd/bcm2835-pm.c
+@@ -3,7 +3,7 @@
+ * PM MFD driver for Broadcom BCM2835
+ *
+ * This driver binds to the PM block and creates the MFD device for
+- * the WDT driver.
++ * the WDT and power drivers.
+ */
+
+ #include <linux/delay.h>
+@@ -21,11 +21,16 @@ static const struct mfd_cell bcm2835_pm_
+ { .name = "bcm2835-wdt" },
+ };
+
++static const struct mfd_cell bcm2835_power_devs[] = {
++ { .name = "bcm2835-power" },
++};
++
+ static int bcm2835_pm_probe(struct platform_device *pdev)
+ {
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct bcm2835_pm *pm;
++ int ret;
+
+ pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL);
+ if (!pm)
+@@ -39,13 +44,36 @@ static int bcm2835_pm_probe(struct platf
+ if (IS_ERR(pm->base))
+ return PTR_ERR(pm->base);
+
+- return devm_mfd_add_devices(dev, -1,
+- bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
+- NULL, 0, NULL);
++ ret = devm_mfd_add_devices(dev, -1,
++ bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
++ NULL, 0, NULL);
++ if (ret)
++ return ret;
++
++ /* We'll use the presence of the AXI ASB regs in the
++ * bcm2835-pm binding as the key for whether we can reference
++ * the full PM register range and support power domains.
++ */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (res) {
++ pm->asb = devm_ioremap_resource(dev, res);
++ if (IS_ERR(pm->asb))
++ return PTR_ERR(pm->asb);
++
++ ret = devm_mfd_add_devices(dev, -1,
++ bcm2835_power_devs,
++ ARRAY_SIZE(bcm2835_power_devs),
++ NULL, 0, NULL);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
+ }
+
+ static const struct of_device_id bcm2835_pm_of_match[] = {
+ { .compatible = "brcm,bcm2835-pm-wdt", },
++ { .compatible = "brcm,bcm2835-pm", },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
+--- a/drivers/soc/bcm/Kconfig
++++ b/drivers/soc/bcm/Kconfig
+@@ -1,5 +1,16 @@
+ menu "Broadcom SoC drivers"
+
++config BCM2835_POWER
++ bool "BCM2835 power domain driver"
++ depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
++ select PM_GENERIC_DOMAINS if PM
++ select RESET_CONTROLLER
++ help
++ This enables support for the BCM2835 power domains and reset
++ controller. Any usage of power domains by the Raspberry Pi
++ firmware means that Linux usage of the same power domain
++ must be accessed using the RASPBERRYPI_POWER driver
++
+ config RASPBERRYPI_POWER
+ bool "Raspberry Pi power domain driver"
+ depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
+--- a/drivers/soc/bcm/Makefile
++++ b/drivers/soc/bcm/Makefile
+@@ -1,2 +1,3 @@
++obj-$(CONFIG_BCM2835_POWER) += bcm2835-power.o
+ obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
+ obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
+--- /dev/null
++++ b/drivers/soc/bcm/bcm2835-power.c
+@@ -0,0 +1,661 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Power domain driver for Broadcom BCM2835
++ *
++ * Copyright (C) 2018 Broadcom
++ */
++
++#include <dt-bindings/soc/bcm2835-pm.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/mfd/bcm2835-pm.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/pm_domain.h>
++#include <linux/reset-controller.h>
++#include <linux/types.h>
++
++#define PM_GNRIC 0x00
++#define PM_AUDIO 0x04
++#define PM_STATUS 0x18
++#define PM_RSTC 0x1c
++#define PM_RSTS 0x20
++#define PM_WDOG 0x24
++#define PM_PADS0 0x28
++#define PM_PADS2 0x2c
++#define PM_PADS3 0x30
++#define PM_PADS4 0x34
++#define PM_PADS5 0x38
++#define PM_PADS6 0x3c
++#define PM_CAM0 0x44
++#define PM_CAM0_LDOHPEN BIT(2)
++#define PM_CAM0_LDOLPEN BIT(1)
++#define PM_CAM0_CTRLEN BIT(0)
++
++#define PM_CAM1 0x48
++#define PM_CAM1_LDOHPEN BIT(2)
++#define PM_CAM1_LDOLPEN BIT(1)
++#define PM_CAM1_CTRLEN BIT(0)
++
++#define PM_CCP2TX 0x4c
++#define PM_CCP2TX_LDOEN BIT(1)
++#define PM_CCP2TX_CTRLEN BIT(0)
++
++#define PM_DSI0 0x50
++#define PM_DSI0_LDOHPEN BIT(2)
++#define PM_DSI0_LDOLPEN BIT(1)
++#define PM_DSI0_CTRLEN BIT(0)
++
++#define PM_DSI1 0x54
++#define PM_DSI1_LDOHPEN BIT(2)
++#define PM_DSI1_LDOLPEN BIT(1)
++#define PM_DSI1_CTRLEN BIT(0)
++
++#define PM_HDMI 0x58
++#define PM_HDMI_RSTDR BIT(19)
++#define PM_HDMI_LDOPD BIT(1)
++#define PM_HDMI_CTRLEN BIT(0)
++
++#define PM_USB 0x5c
++/* The power gates must be enabled with this bit before enabling the LDO in the
++ * USB block.
++ */
++#define PM_USB_CTRLEN BIT(0)
++
++#define PM_PXLDO 0x60
++#define PM_PXBG 0x64
++#define PM_DFT 0x68
++#define PM_SMPS 0x6c
++#define PM_XOSC 0x70
++#define PM_SPAREW 0x74
++#define PM_SPARER 0x78
++#define PM_AVS_RSTDR 0x7c
++#define PM_AVS_STAT 0x80
++#define PM_AVS_EVENT 0x84
++#define PM_AVS_INTEN 0x88
++#define PM_DUMMY 0xfc
++
++#define PM_IMAGE 0x108
++#define PM_GRAFX 0x10c
++#define PM_PROC 0x110
++#define PM_ENAB BIT(12)
++#define PM_ISPRSTN BIT(8)
++#define PM_H264RSTN BIT(7)
++#define PM_PERIRSTN BIT(6)
++#define PM_V3DRSTN BIT(6)
++#define PM_ISFUNC BIT(5)
++#define PM_MRDONE BIT(4)
++#define PM_MEMREP BIT(3)
++#define PM_ISPOW BIT(2)
++#define PM_POWOK BIT(1)
++#define PM_POWUP BIT(0)
++#define PM_INRUSH_SHIFT 13
++#define PM_INRUSH_3_5_MA 0
++#define PM_INRUSH_5_MA 1
++#define PM_INRUSH_10_MA 2
++#define PM_INRUSH_20_MA 3
++#define PM_INRUSH_MASK (3 << PM_INRUSH_SHIFT)
++
++#define PM_PASSWORD 0x5a000000
++
++#define PM_WDOG_TIME_SET 0x000fffff
++#define PM_RSTC_WRCFG_CLR 0xffffffcf
++#define PM_RSTS_HADWRH_SET 0x00000040
++#define PM_RSTC_WRCFG_SET 0x00000030
++#define PM_RSTC_WRCFG_FULL_RESET 0x00000020
++#define PM_RSTC_RESET 0x00000102
++
++#define PM_READ(reg) readl(power->base + (reg))
++#define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg))
++
++#define ASB_BRDG_VERSION 0x00
++#define ASB_CPR_CTRL 0x04
++
++#define ASB_V3D_S_CTRL 0x08
++#define ASB_V3D_M_CTRL 0x0c
++#define ASB_ISP_S_CTRL 0x10
++#define ASB_ISP_M_CTRL 0x14
++#define ASB_H264_S_CTRL 0x18
++#define ASB_H264_M_CTRL 0x1c
++
++#define ASB_REQ_STOP BIT(0)
++#define ASB_ACK BIT(1)
++#define ASB_EMPTY BIT(2)
++#define ASB_FULL BIT(3)
++
++#define ASB_AXI_BRDG_ID 0x20
++
++#define ASB_READ(reg) readl(power->asb + (reg))
++#define ASB_WRITE(reg, val) writel(PM_PASSWORD | (val), power->asb + (reg))
++
++struct bcm2835_power_domain {
++ struct generic_pm_domain base;
++ struct bcm2835_power *power;
++ u32 domain;
++ struct clk *clk;
++};
++
++struct bcm2835_power {
++ struct device *dev;
++ /* PM registers. */
++ void __iomem *base;
++ /* AXI Async bridge registers. */
++ void __iomem *asb;
++
++ struct genpd_onecell_data pd_xlate;
++ struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
++ struct reset_controller_dev reset;
++};
++
++static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
++{
++ u64 start = ktime_get_ns();
++
++ /* Enable the module's async AXI bridges. */
++ ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP);
++ while (ASB_READ(reg) & ASB_ACK) {
++ cpu_relax();
++ if (ktime_get_ns() - start >= 1000)
++ return -ETIMEDOUT;
++ }
++
++ return 0;
++}
++
++static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
++{
++ u64 start = ktime_get_ns();
++
++ /* Enable the module's async AXI bridges. */
++ ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP);
++ while (!(ASB_READ(reg) & ASB_ACK)) {
++ cpu_relax();
++ if (ktime_get_ns() - start >= 1000)
++ return -ETIMEDOUT;
++ }
++
++ return 0;
++}
++
++static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)
++{
++ struct bcm2835_power *power = pd->power;
++
++ /* Enable functional isolation */
++ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
++
++ /* Enable electrical isolation */
++ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
++
++ /* Open the power switches. */
++ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP);
++
++ return 0;
++}
++
++static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg)
++{
++ struct bcm2835_power *power = pd->power;
++ struct device *dev = power->dev;
++ u64 start;
++ int ret;
++ int inrush;
++ bool powok;
++
++ /* If it was already powered on by the fw, leave it that way. */
++ if (PM_READ(pm_reg) & PM_POWUP)
++ return 0;
++
++ /* Enable power. Allowing too much current at once may result
++ * in POWOK never getting set, so start low and ramp it up as
++ * necessary to succeed.
++ */
++ powok = false;
++ for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; inrush++) {
++ PM_WRITE(pm_reg,
++ (PM_READ(pm_reg) & ~PM_INRUSH_MASK) |
++ (inrush << PM_INRUSH_SHIFT) |
++ PM_POWUP);
++
++ start = ktime_get_ns();
++ while (!(powok = !!(PM_READ(pm_reg) & PM_POWOK))) {
++ cpu_relax();
++ if (ktime_get_ns() - start >= 3000)
++ break;
++ }
++ }
++ if (!powok) {
++ dev_err(dev, "Timeout waiting for %s power OK\n",
++ pd->base.name);
++ ret = -ETIMEDOUT;
++ goto err_disable_powup;
++ }
++
++ /* Disable electrical isolation */
++ PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW);
++
++ /* Repair memory */
++ PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP);
++ start = ktime_get_ns();
++ while (!(PM_READ(pm_reg) & PM_MRDONE)) {
++ cpu_relax();
++ if (ktime_get_ns() - start >= 1000) {
++ dev_err(dev, "Timeout waiting for %s memory repair\n",
++ pd->base.name);
++ ret = -ETIMEDOUT;
++ goto err_disable_ispow;
++ }
++ }
++
++ /* Disable functional isolation */
++ PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC);
++
++ return 0;
++
++err_disable_ispow:
++ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
++err_disable_powup:
++ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK));
++ return ret;
++}
++
++static int bcm2835_asb_power_on(struct bcm2835_power_domain *pd,
++ u32 pm_reg,
++ u32 asb_m_reg,
++ u32 asb_s_reg,
++ u32 reset_flags)
++{
++ struct bcm2835_power *power = pd->power;
++ int ret;
++
++ ret = clk_prepare_enable(pd->clk);
++ if (ret) {
++ dev_err(power->dev, "Failed to enable clock for %s\n",
++ pd->base.name);
++ return ret;
++ }
++
++ /* Wait 32 clocks for reset to propagate, 1 us will be enough */
++ udelay(1);
++
++ clk_disable_unprepare(pd->clk);
++
++ /* Deassert the resets. */
++ PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags);
++
++ ret = clk_prepare_enable(pd->clk);
++ if (ret) {
++ dev_err(power->dev, "Failed to enable clock for %s\n",
++ pd->base.name);
++ goto err_enable_resets;
++ }
++
++ ret = bcm2835_asb_enable(power, asb_m_reg);
++ if (ret) {
++ dev_err(power->dev, "Failed to enable ASB master for %s\n",
++ pd->base.name);
++ goto err_disable_clk;
++ }
++ ret = bcm2835_asb_enable(power, asb_s_reg);
++ if (ret) {
++ dev_err(power->dev, "Failed to enable ASB slave for %s\n",
++ pd->base.name);
++ goto err_disable_asb_master;
++ }
++
++ return 0;
++
++err_disable_asb_master:
++ bcm2835_asb_disable(power, asb_m_reg);
++err_disable_clk:
++ clk_disable_unprepare(pd->clk);
++err_enable_resets:
++ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
++ return ret;
++}
++
++static int bcm2835_asb_power_off(struct bcm2835_power_domain *pd,
++ u32 pm_reg,
++ u32 asb_m_reg,
++ u32 asb_s_reg,
++ u32 reset_flags)
++{
++ struct bcm2835_power *power = pd->power;
++ int ret;
++
++ ret = bcm2835_asb_disable(power, asb_s_reg);
++ if (ret) {
++ dev_warn(power->dev, "Failed to disable ASB slave for %s\n",
++ pd->base.name);
++ return ret;
++ }
++ ret = bcm2835_asb_disable(power, asb_m_reg);
++ if (ret) {
++ dev_warn(power->dev, "Failed to disable ASB master for %s\n",
++ pd->base.name);
++ bcm2835_asb_enable(power, asb_s_reg);
++ return ret;
++ }
++
++ clk_disable_unprepare(pd->clk);
++
++ /* Assert the resets. */
++ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
++
++ return 0;
++}
++
++static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain)
++{
++ struct bcm2835_power_domain *pd =
++ container_of(domain, struct bcm2835_power_domain, base);
++ struct bcm2835_power *power = pd->power;
++
++ switch (pd->domain) {
++ case BCM2835_POWER_DOMAIN_GRAFX:
++ return bcm2835_power_power_on(pd, PM_GRAFX);
++
++ case BCM2835_POWER_DOMAIN_GRAFX_V3D:
++ return bcm2835_asb_power_on(pd, PM_GRAFX,
++ ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
++ PM_V3DRSTN);
++
++ case BCM2835_POWER_DOMAIN_IMAGE:
++ return bcm2835_power_power_on(pd, PM_IMAGE);
++
++ case BCM2835_POWER_DOMAIN_IMAGE_PERI:
++ return bcm2835_asb_power_on(pd, PM_IMAGE,
++ 0, 0,
++ PM_PERIRSTN);
++
++ case BCM2835_POWER_DOMAIN_IMAGE_ISP:
++ return bcm2835_asb_power_on(pd, PM_IMAGE,
++ ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
++ PM_ISPRSTN);
++
++ case BCM2835_POWER_DOMAIN_IMAGE_H264:
++ return bcm2835_asb_power_on(pd, PM_IMAGE,
++ ASB_H264_M_CTRL, ASB_H264_S_CTRL,
++ PM_H264RSTN);
++
++ case BCM2835_POWER_DOMAIN_USB:
++ PM_WRITE(PM_USB, PM_USB_CTRLEN);
++ return 0;
++
++ case BCM2835_POWER_DOMAIN_DSI0:
++ PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
++ PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN);
++ return 0;
++
++ case BCM2835_POWER_DOMAIN_DSI1:
++ PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
++ PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN);
++ return 0;
++
++ case BCM2835_POWER_DOMAIN_CCP2TX:
++ PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
++ PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN);
++ return 0;
++
++ case BCM2835_POWER_DOMAIN_HDMI:
++ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR);
++ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN);
++ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD);
++ usleep_range(100, 200);
++ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR);
++ return 0;
++
++ default:
++ dev_err(power->dev, "Invalid domain %d\n", pd->domain);
++ return -EINVAL;
++ }
++}
++
++static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain)
++{
++ struct bcm2835_power_domain *pd =
++ container_of(domain, struct bcm2835_power_domain, base);
++ struct bcm2835_power *power = pd->power;
++
++ switch (pd->domain) {
++ case BCM2835_POWER_DOMAIN_GRAFX:
++ return bcm2835_power_power_off(pd, PM_GRAFX);
++
++ case BCM2835_POWER_DOMAIN_GRAFX_V3D:
++ return bcm2835_asb_power_off(pd, PM_GRAFX,
++ ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
++ PM_V3DRSTN);
++
++ case BCM2835_POWER_DOMAIN_IMAGE:
++ return bcm2835_power_power_off(pd, PM_IMAGE);
++
++ case BCM2835_POWER_DOMAIN_IMAGE_PERI:
++ return bcm2835_asb_power_off(pd, PM_IMAGE,
++ 0, 0,
++ PM_PERIRSTN);
++
++ case BCM2835_POWER_DOMAIN_IMAGE_ISP:
++ return bcm2835_asb_power_off(pd, PM_IMAGE,
++ ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
++ PM_ISPRSTN);
++
++ case BCM2835_POWER_DOMAIN_IMAGE_H264:
++ return bcm2835_asb_power_off(pd, PM_IMAGE,
++ ASB_H264_M_CTRL, ASB_H264_S_CTRL,
++ PM_H264RSTN);
++
++ case BCM2835_POWER_DOMAIN_USB:
++ PM_WRITE(PM_USB, 0);
++ return 0;
++
++ case BCM2835_POWER_DOMAIN_DSI0:
++ PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
++ PM_WRITE(PM_DSI0, 0);
++ return 0;
++
++ case BCM2835_POWER_DOMAIN_DSI1:
++ PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
++ PM_WRITE(PM_DSI1, 0);
++ return 0;
++
++ case BCM2835_POWER_DOMAIN_CCP2TX:
++ PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
++ PM_WRITE(PM_CCP2TX, 0);
++ return 0;
++
++ case BCM2835_POWER_DOMAIN_HDMI:
++ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD);
++ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN);
++ return 0;
++
++ default:
++ dev_err(power->dev, "Invalid domain %d\n", pd->domain);
++ return -EINVAL;
++ }
++}
++
++static void
++bcm2835_init_power_domain(struct bcm2835_power *power,
++ int pd_xlate_index, const char *name)
++{
++ struct device *dev = power->dev;
++ struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
++
++ dom->clk = devm_clk_get(dev->parent, name);
++
++ dom->base.name = name;
++ dom->base.power_on = bcm2835_power_pd_power_on;
++ dom->base.power_off = bcm2835_power_pd_power_off;
++
++ dom->domain = pd_xlate_index;
++ dom->power = power;
++
++ /* XXX: on/off at boot? */
++ pm_genpd_init(&dom->base, NULL, true);
++
++ power->pd_xlate.domains[pd_xlate_index] = &dom->base;
++}
++
++/** bcm2835_reset_reset - Resets a block that has a reset line in the
++ * PM block.
++ *
++ * The consumer of the reset controller must have the power domain up
++ * -- there's no reset ability with the power domain down. To reset
++ * the sub-block, we just disable its access to memory through the
++ * ASB, reset, and re-enable.
++ */
++static int bcm2835_reset_reset(struct reset_controller_dev *rcdev,
++ unsigned long id)
++{
++ struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
++ reset);
++ struct bcm2835_power_domain *pd;
++ int ret;
++
++ switch (id) {
++ case BCM2835_RESET_V3D:
++ pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D];
++ break;
++ case BCM2835_RESET_H264:
++ pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264];
++ break;
++ case BCM2835_RESET_ISP:
++ pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP];
++ break;
++ default:
++ dev_err(power->dev, "Bad reset id %ld\n", id);
++ return -EINVAL;
++ }
++
++ ret = bcm2835_power_pd_power_off(&pd->base);
++ if (ret)
++ return ret;
++
++ return bcm2835_power_pd_power_on(&pd->base);
++}
++
++static int bcm2835_reset_status(struct reset_controller_dev *rcdev,
++ unsigned long id)
++{
++ struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
++ reset);
++
++ switch (id) {
++ case BCM2835_RESET_V3D:
++ return !PM_READ(PM_GRAFX & PM_V3DRSTN);
++ case BCM2835_RESET_H264:
++ return !PM_READ(PM_IMAGE & PM_H264RSTN);
++ case BCM2835_RESET_ISP:
++ return !PM_READ(PM_IMAGE & PM_ISPRSTN);
++ default:
++ return -EINVAL;
++ }
++}
++
++const struct reset_control_ops bcm2835_reset_ops = {
++ .reset = bcm2835_reset_reset,
++ .status = bcm2835_reset_status,
++};
++
++static const char *const power_domain_names[] = {
++ [BCM2835_POWER_DOMAIN_GRAFX] = "grafx",
++ [BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d",
++
++ [BCM2835_POWER_DOMAIN_IMAGE] = "image",
++ [BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image",
++ [BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264",
++ [BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp",
++
++ [BCM2835_POWER_DOMAIN_USB] = "usb",
++ [BCM2835_POWER_DOMAIN_DSI0] = "dsi0",
++ [BCM2835_POWER_DOMAIN_DSI1] = "dsi1",
++ [BCM2835_POWER_DOMAIN_CAM0] = "cam0",
++ [BCM2835_POWER_DOMAIN_CAM1] = "cam1",
++ [BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx",
++ [BCM2835_POWER_DOMAIN_HDMI] = "hdmi",
++};
++
++static int bcm2835_power_probe(struct platform_device *pdev)
++{
++ struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);
++ struct device *dev = &pdev->dev;
++ struct bcm2835_power *power;
++ static const struct {
++ int parent, child;
++ } domain_deps[] = {
++ { BCM2835_POWER_DOMAIN_GRAFX, BCM2835_POWER_DOMAIN_GRAFX_V3D },
++ { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_PERI },
++ { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_H264 },
++ { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_ISP },
++ { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_USB },
++ { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },
++ { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },
++ };
++ int ret, i;
++ u32 id;
++
++ power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
++ if (!power)
++ return -ENOMEM;
++ platform_set_drvdata(pdev, power);
++
++ power->dev = dev;
++ power->base = pm->base;
++ power->asb = pm->asb;
++
++ id = ASB_READ(ASB_AXI_BRDG_ID);
++ if (id != 0x62726467 /* "BRDG" */) {
++ dev_err(dev, "ASB register ID returned 0x%08x\n", id);
++ return -ENODEV;
++ }
++
++ power->pd_xlate.domains = devm_kcalloc(dev,
++ ARRAY_SIZE(power_domain_names),
++ sizeof(*power->pd_xlate.domains),
++ GFP_KERNEL);
++ if (!power->pd_xlate.domains)
++ return -ENOMEM;
++
++ power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);
++
++ for (i = 0; i < ARRAY_SIZE(power_domain_names); i++)
++ bcm2835_init_power_domain(power, i, power_domain_names[i]);
++
++ for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {
++ pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,
++ &power->domains[domain_deps[i].child].base);
++ }
++
++ power->reset.owner = THIS_MODULE;
++ power->reset.nr_resets = BCM2835_RESET_COUNT;
++ power->reset.ops = &bcm2835_reset_ops;
++ power->reset.of_node = dev->parent->of_node;
++
++ ret = devm_reset_controller_register(dev, &power->reset);
++ if (ret)
++ return ret;
++
++ of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
++
++ dev_info(dev, "Broadcom BCM2835 power domains driver");
++ return 0;
++}
++
++static int bcm2835_power_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++
++static struct platform_driver bcm2835_power_driver = {
++ .probe = bcm2835_power_probe,
++ .remove = bcm2835_power_remove,
++ .driver = {
++ .name = "bcm2835-power",
++ },
++};
++module_platform_driver(bcm2835_power_driver);
++
++MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/include/dt-bindings/soc/bcm2835-pm.h
+@@ -0,0 +1,28 @@
++/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
++
++#ifndef _DT_BINDINGS_ARM_BCM2835_PM_H
++#define _DT_BINDINGS_ARM_BCM2835_PM_H
++
++#define BCM2835_POWER_DOMAIN_GRAFX 0
++#define BCM2835_POWER_DOMAIN_GRAFX_V3D 1
++#define BCM2835_POWER_DOMAIN_IMAGE 2
++#define BCM2835_POWER_DOMAIN_IMAGE_PERI 3
++#define BCM2835_POWER_DOMAIN_IMAGE_ISP 4
++#define BCM2835_POWER_DOMAIN_IMAGE_H264 5
++#define BCM2835_POWER_DOMAIN_USB 6
++#define BCM2835_POWER_DOMAIN_DSI0 7
++#define BCM2835_POWER_DOMAIN_DSI1 8
++#define BCM2835_POWER_DOMAIN_CAM0 9
++#define BCM2835_POWER_DOMAIN_CAM1 10
++#define BCM2835_POWER_DOMAIN_CCP2TX 11
++#define BCM2835_POWER_DOMAIN_HDMI 12
++
++#define BCM2835_POWER_DOMAIN_COUNT 13
++
++#define BCM2835_RESET_V3D 0
++#define BCM2835_RESET_ISP 1
++#define BCM2835_RESET_H264 2
++
++#define BCM2835_RESET_COUNT 3
++
++#endif /* _DT_BINDINGS_ARM_BCM2835_PM_H */
+--- a/include/linux/mfd/bcm2835-pm.h
++++ b/include/linux/mfd/bcm2835-pm.h
+@@ -8,6 +8,7 @@
+ struct bcm2835_pm {
+ struct device *dev;
+ void __iomem *base;
++ void __iomem *asb;
+ };
+
+ #endif /* BCM2835_MFD_PM_H */
+++ /dev/null
-From 90964ab2d00546a59086ffd08964da3d2a5cefc9 Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Dec 2018 15:51:47 -0800
-Subject: [PATCH] bcm2835-pm: Move bcm2835-watchdog's DT probe to an
- MFD.
-
-The PM block that the wdt driver was binding to actually has multiple
-features we want to expose (power domains, reset, watchdog). Move the
-DT attachment to a MFD driver and make WDT probe against MFD.
-
-(cherry picked from commit 5e6acc3e678ed3db746ab4fb53a980861cd711b6)
----
- drivers/mfd/Makefile | 1 +
- drivers/mfd/bcm2835-pm.c | 64 ++++++++++++++++++++++++++++++++++
- drivers/watchdog/bcm2835_wdt.c | 26 +++++---------
- include/linux/mfd/bcm2835-pm.h | 13 +++++++
- 4 files changed, 87 insertions(+), 17 deletions(-)
- create mode 100644 drivers/mfd/bcm2835-pm.c
- create mode 100644 include/linux/mfd/bcm2835-pm.h
-
---- a/drivers/mfd/Makefile
-+++ b/drivers/mfd/Makefile
-@@ -10,6 +10,7 @@ obj-$(CONFIG_MFD_88PM805) += 88pm805.o 8
- obj-$(CONFIG_MFD_ACT8945A) += act8945a.o
- obj-$(CONFIG_MFD_SM501) += sm501.o
- obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
-+obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o
- obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
- obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o
- cros_ec_core-objs := cros_ec.o
---- /dev/null
-+++ b/drivers/mfd/bcm2835-pm.c
-@@ -0,0 +1,64 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * PM MFD driver for Broadcom BCM2835
-+ *
-+ * This driver binds to the PM block and creates the MFD device for
-+ * the WDT driver.
-+ */
-+
-+#include <linux/delay.h>
-+#include <linux/io.h>
-+#include <linux/mfd/bcm2835-pm.h>
-+#include <linux/mfd/core.h>
-+#include <linux/module.h>
-+#include <linux/of_address.h>
-+#include <linux/of_platform.h>
-+#include <linux/platform_device.h>
-+#include <linux/types.h>
-+#include <linux/watchdog.h>
-+
-+static const struct mfd_cell bcm2835_pm_devs[] = {
-+ { .name = "bcm2835-wdt" },
-+};
-+
-+static int bcm2835_pm_probe(struct platform_device *pdev)
-+{
-+ struct resource *res;
-+ struct device *dev = &pdev->dev;
-+ struct bcm2835_pm *pm;
-+
-+ pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL);
-+ if (!pm)
-+ return -ENOMEM;
-+ platform_set_drvdata(pdev, pm);
-+
-+ pm->dev = dev;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ pm->base = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(pm->base))
-+ return PTR_ERR(pm->base);
-+
-+ return devm_mfd_add_devices(dev, -1,
-+ bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
-+ NULL, 0, NULL);
-+}
-+
-+static const struct of_device_id bcm2835_pm_of_match[] = {
-+ { .compatible = "brcm,bcm2835-pm-wdt", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
-+
-+static struct platform_driver bcm2835_pm_driver = {
-+ .probe = bcm2835_pm_probe,
-+ .driver = {
-+ .name = "bcm2835-pm",
-+ .of_match_table = bcm2835_pm_of_match,
-+ },
-+};
-+module_platform_driver(bcm2835_pm_driver);
-+
-+MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM MFD");
-+MODULE_LICENSE("GPL");
---- a/drivers/watchdog/bcm2835_wdt.c
-+++ b/drivers/watchdog/bcm2835_wdt.c
-@@ -12,6 +12,7 @@
-
- #include <linux/delay.h>
- #include <linux/types.h>
-+#include <linux/mfd/bcm2835-pm.h>
- #include <linux/module.h>
- #include <linux/io.h>
- #include <linux/watchdog.h>
-@@ -41,6 +42,8 @@ struct bcm2835_wdt {
- spinlock_t lock;
- };
-
-+static struct bcm2835_wdt *bcm2835_power_off_wdt;
-+
- static unsigned int heartbeat;
- static bool nowayout = WATCHDOG_NOWAYOUT;
-
-@@ -163,10 +166,7 @@ static struct watchdog_device bcm2835_wd
- */
- static void bcm2835_power_off(void)
- {
-- struct device_node *np =
-- of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt");
-- struct platform_device *pdev = of_find_device_by_node(np);
-- struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
-+ struct bcm2835_wdt *wdt = bcm2835_power_off_wdt;
-
- /* Partition 63 tells the firmware that this is a halt */
- __bcm2835_restart(wdt, 63);
-@@ -174,7 +174,7 @@ static void bcm2835_power_off(void)
-
- static int bcm2835_wdt_probe(struct platform_device *pdev)
- {
-- struct resource *res;
-+ struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);
- struct device *dev = &pdev->dev;
- struct bcm2835_wdt *wdt;
- int err;
-@@ -186,10 +186,7 @@ static int bcm2835_wdt_probe(struct plat
-
- spin_lock_init(&wdt->lock);
-
-- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-- wdt->base = devm_ioremap_resource(dev, res);
-- if (IS_ERR(wdt->base))
-- return PTR_ERR(wdt->base);
-+ wdt->base = pm->base;
-
- watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt);
- watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev);
-@@ -216,8 +213,10 @@ static int bcm2835_wdt_probe(struct plat
- return err;
- }
-
-- if (pm_power_off == NULL)
-+ if (pm_power_off == NULL) {
- pm_power_off = bcm2835_power_off;
-+ bcm2835_power_off_wdt = wdt;
-+ }
-
- dev_info(dev, "Broadcom BCM2835 watchdog timer");
- return 0;
-@@ -231,18 +230,11 @@ static int bcm2835_wdt_remove(struct pla
- return 0;
- }
-
--static const struct of_device_id bcm2835_wdt_of_match[] = {
-- { .compatible = "brcm,bcm2835-pm-wdt", },
-- {},
--};
--MODULE_DEVICE_TABLE(of, bcm2835_wdt_of_match);
--
- static struct platform_driver bcm2835_wdt_driver = {
- .probe = bcm2835_wdt_probe,
- .remove = bcm2835_wdt_remove,
- .driver = {
- .name = "bcm2835-wdt",
-- .of_match_table = bcm2835_wdt_of_match,
- },
- };
- module_platform_driver(bcm2835_wdt_driver);
---- /dev/null
-+++ b/include/linux/mfd/bcm2835-pm.h
-@@ -0,0 +1,13 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+
-+#ifndef BCM2835_MFD_PM_H
-+#define BCM2835_MFD_PM_H
-+
-+#include <linux/regmap.h>
-+
-+struct bcm2835_pm {
-+ struct device *dev;
-+ void __iomem *base;
-+};
-+
-+#endif /* BCM2835_MFD_PM_H */
--- /dev/null
+From ea44a81b7daf511788aecaee7575feff359c5d19 Mon Sep 17 00:00:00 2001
+Date: Fri, 11 Jan 2019 17:29:10 -0800
+Subject: [PATCH] soc: bcm: bcm2835-pm: Fix PM_IMAGE_PERI power domain
+ support.
+
+We don't have ASB master/slave regs for this domain, so just skip that
+step.
+
+Fixes: 670c672608a1 ("soc: bcm: bcm2835-pm: Add support for power domains under a new binding.")
+---
+ drivers/soc/bcm/bcm2835-power.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+--- a/drivers/soc/bcm/bcm2835-power.c
++++ b/drivers/soc/bcm/bcm2835-power.c
+@@ -150,7 +150,12 @@ struct bcm2835_power {
+
+ static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
+ {
+- u64 start = ktime_get_ns();
++ u64 start;
++
++ if (!reg)
++ return 0;
++
++ start = ktime_get_ns();
+
+ /* Enable the module's async AXI bridges. */
+ ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP);
+@@ -165,7 +170,12 @@ static int bcm2835_asb_enable(struct bcm
+
+ static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
+ {
+- u64 start = ktime_get_ns();
++ u64 start;
++
++ if (!reg)
++ return 0;
++
++ start = ktime_get_ns();
+
+ /* Enable the module's async AXI bridges. */
+ ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP);
+++ /dev/null
-From fd8ca458728baabe9cae37836088a33c8642d420 Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Dec 2018 15:51:48 -0800
-Subject: [PATCH] soc: bcm: bcm2835-pm: Add support for power domains
- under a new binding.
-
-This provides a free software alternative to raspberrypi-power.c's
-firmware calls to manage power domains. It also exposes a reset line,
-where previously the vc4 driver had to try to force power off the
-domain in order to trigger a reset.
-
-(cherry picked from commit 670c672608a1ffcbc7ac0f872734843593bb8b15)
----
- drivers/mfd/bcm2835-pm.c | 36 +-
- drivers/soc/bcm/Kconfig | 11 +
- drivers/soc/bcm/Makefile | 1 +
- drivers/soc/bcm/bcm2835-power.c | 661 +++++++++++++++++++++++++++
- include/dt-bindings/soc/bcm2835-pm.h | 28 ++
- include/linux/mfd/bcm2835-pm.h | 1 +
- 6 files changed, 734 insertions(+), 4 deletions(-)
- create mode 100644 drivers/soc/bcm/bcm2835-power.c
- create mode 100644 include/dt-bindings/soc/bcm2835-pm.h
-
---- a/drivers/mfd/bcm2835-pm.c
-+++ b/drivers/mfd/bcm2835-pm.c
-@@ -3,7 +3,7 @@
- * PM MFD driver for Broadcom BCM2835
- *
- * This driver binds to the PM block and creates the MFD device for
-- * the WDT driver.
-+ * the WDT and power drivers.
- */
-
- #include <linux/delay.h>
-@@ -21,11 +21,16 @@ static const struct mfd_cell bcm2835_pm_
- { .name = "bcm2835-wdt" },
- };
-
-+static const struct mfd_cell bcm2835_power_devs[] = {
-+ { .name = "bcm2835-power" },
-+};
-+
- static int bcm2835_pm_probe(struct platform_device *pdev)
- {
- struct resource *res;
- struct device *dev = &pdev->dev;
- struct bcm2835_pm *pm;
-+ int ret;
-
- pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL);
- if (!pm)
-@@ -39,13 +44,36 @@ static int bcm2835_pm_probe(struct platf
- if (IS_ERR(pm->base))
- return PTR_ERR(pm->base);
-
-- return devm_mfd_add_devices(dev, -1,
-- bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
-- NULL, 0, NULL);
-+ ret = devm_mfd_add_devices(dev, -1,
-+ bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
-+ NULL, 0, NULL);
-+ if (ret)
-+ return ret;
-+
-+ /* We'll use the presence of the AXI ASB regs in the
-+ * bcm2835-pm binding as the key for whether we can reference
-+ * the full PM register range and support power domains.
-+ */
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ if (res) {
-+ pm->asb = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(pm->asb))
-+ return PTR_ERR(pm->asb);
-+
-+ ret = devm_mfd_add_devices(dev, -1,
-+ bcm2835_power_devs,
-+ ARRAY_SIZE(bcm2835_power_devs),
-+ NULL, 0, NULL);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return 0;
- }
-
- static const struct of_device_id bcm2835_pm_of_match[] = {
- { .compatible = "brcm,bcm2835-pm-wdt", },
-+ { .compatible = "brcm,bcm2835-pm", },
- {},
- };
- MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
---- a/drivers/soc/bcm/Kconfig
-+++ b/drivers/soc/bcm/Kconfig
-@@ -1,5 +1,16 @@
- menu "Broadcom SoC drivers"
-
-+config BCM2835_POWER
-+ bool "BCM2835 power domain driver"
-+ depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
-+ select PM_GENERIC_DOMAINS if PM
-+ select RESET_CONTROLLER
-+ help
-+ This enables support for the BCM2835 power domains and reset
-+ controller. Any usage of power domains by the Raspberry Pi
-+ firmware means that Linux usage of the same power domain
-+ must be accessed using the RASPBERRYPI_POWER driver
-+
- config RASPBERRYPI_POWER
- bool "Raspberry Pi power domain driver"
- depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
---- a/drivers/soc/bcm/Makefile
-+++ b/drivers/soc/bcm/Makefile
-@@ -1,2 +1,3 @@
-+obj-$(CONFIG_BCM2835_POWER) += bcm2835-power.o
- obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
- obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
---- /dev/null
-+++ b/drivers/soc/bcm/bcm2835-power.c
-@@ -0,0 +1,661 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Power domain driver for Broadcom BCM2835
-+ *
-+ * Copyright (C) 2018 Broadcom
-+ */
-+
-+#include <dt-bindings/soc/bcm2835-pm.h>
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/io.h>
-+#include <linux/mfd/bcm2835-pm.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_domain.h>
-+#include <linux/reset-controller.h>
-+#include <linux/types.h>
-+
-+#define PM_GNRIC 0x00
-+#define PM_AUDIO 0x04
-+#define PM_STATUS 0x18
-+#define PM_RSTC 0x1c
-+#define PM_RSTS 0x20
-+#define PM_WDOG 0x24
-+#define PM_PADS0 0x28
-+#define PM_PADS2 0x2c
-+#define PM_PADS3 0x30
-+#define PM_PADS4 0x34
-+#define PM_PADS5 0x38
-+#define PM_PADS6 0x3c
-+#define PM_CAM0 0x44
-+#define PM_CAM0_LDOHPEN BIT(2)
-+#define PM_CAM0_LDOLPEN BIT(1)
-+#define PM_CAM0_CTRLEN BIT(0)
-+
-+#define PM_CAM1 0x48
-+#define PM_CAM1_LDOHPEN BIT(2)
-+#define PM_CAM1_LDOLPEN BIT(1)
-+#define PM_CAM1_CTRLEN BIT(0)
-+
-+#define PM_CCP2TX 0x4c
-+#define PM_CCP2TX_LDOEN BIT(1)
-+#define PM_CCP2TX_CTRLEN BIT(0)
-+
-+#define PM_DSI0 0x50
-+#define PM_DSI0_LDOHPEN BIT(2)
-+#define PM_DSI0_LDOLPEN BIT(1)
-+#define PM_DSI0_CTRLEN BIT(0)
-+
-+#define PM_DSI1 0x54
-+#define PM_DSI1_LDOHPEN BIT(2)
-+#define PM_DSI1_LDOLPEN BIT(1)
-+#define PM_DSI1_CTRLEN BIT(0)
-+
-+#define PM_HDMI 0x58
-+#define PM_HDMI_RSTDR BIT(19)
-+#define PM_HDMI_LDOPD BIT(1)
-+#define PM_HDMI_CTRLEN BIT(0)
-+
-+#define PM_USB 0x5c
-+/* The power gates must be enabled with this bit before enabling the LDO in the
-+ * USB block.
-+ */
-+#define PM_USB_CTRLEN BIT(0)
-+
-+#define PM_PXLDO 0x60
-+#define PM_PXBG 0x64
-+#define PM_DFT 0x68
-+#define PM_SMPS 0x6c
-+#define PM_XOSC 0x70
-+#define PM_SPAREW 0x74
-+#define PM_SPARER 0x78
-+#define PM_AVS_RSTDR 0x7c
-+#define PM_AVS_STAT 0x80
-+#define PM_AVS_EVENT 0x84
-+#define PM_AVS_INTEN 0x88
-+#define PM_DUMMY 0xfc
-+
-+#define PM_IMAGE 0x108
-+#define PM_GRAFX 0x10c
-+#define PM_PROC 0x110
-+#define PM_ENAB BIT(12)
-+#define PM_ISPRSTN BIT(8)
-+#define PM_H264RSTN BIT(7)
-+#define PM_PERIRSTN BIT(6)
-+#define PM_V3DRSTN BIT(6)
-+#define PM_ISFUNC BIT(5)
-+#define PM_MRDONE BIT(4)
-+#define PM_MEMREP BIT(3)
-+#define PM_ISPOW BIT(2)
-+#define PM_POWOK BIT(1)
-+#define PM_POWUP BIT(0)
-+#define PM_INRUSH_SHIFT 13
-+#define PM_INRUSH_3_5_MA 0
-+#define PM_INRUSH_5_MA 1
-+#define PM_INRUSH_10_MA 2
-+#define PM_INRUSH_20_MA 3
-+#define PM_INRUSH_MASK (3 << PM_INRUSH_SHIFT)
-+
-+#define PM_PASSWORD 0x5a000000
-+
-+#define PM_WDOG_TIME_SET 0x000fffff
-+#define PM_RSTC_WRCFG_CLR 0xffffffcf
-+#define PM_RSTS_HADWRH_SET 0x00000040
-+#define PM_RSTC_WRCFG_SET 0x00000030
-+#define PM_RSTC_WRCFG_FULL_RESET 0x00000020
-+#define PM_RSTC_RESET 0x00000102
-+
-+#define PM_READ(reg) readl(power->base + (reg))
-+#define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg))
-+
-+#define ASB_BRDG_VERSION 0x00
-+#define ASB_CPR_CTRL 0x04
-+
-+#define ASB_V3D_S_CTRL 0x08
-+#define ASB_V3D_M_CTRL 0x0c
-+#define ASB_ISP_S_CTRL 0x10
-+#define ASB_ISP_M_CTRL 0x14
-+#define ASB_H264_S_CTRL 0x18
-+#define ASB_H264_M_CTRL 0x1c
-+
-+#define ASB_REQ_STOP BIT(0)
-+#define ASB_ACK BIT(1)
-+#define ASB_EMPTY BIT(2)
-+#define ASB_FULL BIT(3)
-+
-+#define ASB_AXI_BRDG_ID 0x20
-+
-+#define ASB_READ(reg) readl(power->asb + (reg))
-+#define ASB_WRITE(reg, val) writel(PM_PASSWORD | (val), power->asb + (reg))
-+
-+struct bcm2835_power_domain {
-+ struct generic_pm_domain base;
-+ struct bcm2835_power *power;
-+ u32 domain;
-+ struct clk *clk;
-+};
-+
-+struct bcm2835_power {
-+ struct device *dev;
-+ /* PM registers. */
-+ void __iomem *base;
-+ /* AXI Async bridge registers. */
-+ void __iomem *asb;
-+
-+ struct genpd_onecell_data pd_xlate;
-+ struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
-+ struct reset_controller_dev reset;
-+};
-+
-+static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
-+{
-+ u64 start = ktime_get_ns();
-+
-+ /* Enable the module's async AXI bridges. */
-+ ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP);
-+ while (ASB_READ(reg) & ASB_ACK) {
-+ cpu_relax();
-+ if (ktime_get_ns() - start >= 1000)
-+ return -ETIMEDOUT;
-+ }
-+
-+ return 0;
-+}
-+
-+static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
-+{
-+ u64 start = ktime_get_ns();
-+
-+ /* Enable the module's async AXI bridges. */
-+ ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP);
-+ while (!(ASB_READ(reg) & ASB_ACK)) {
-+ cpu_relax();
-+ if (ktime_get_ns() - start >= 1000)
-+ return -ETIMEDOUT;
-+ }
-+
-+ return 0;
-+}
-+
-+static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)
-+{
-+ struct bcm2835_power *power = pd->power;
-+
-+ /* Enable functional isolation */
-+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
-+
-+ /* Enable electrical isolation */
-+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
-+
-+ /* Open the power switches. */
-+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP);
-+
-+ return 0;
-+}
-+
-+static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg)
-+{
-+ struct bcm2835_power *power = pd->power;
-+ struct device *dev = power->dev;
-+ u64 start;
-+ int ret;
-+ int inrush;
-+ bool powok;
-+
-+ /* If it was already powered on by the fw, leave it that way. */
-+ if (PM_READ(pm_reg) & PM_POWUP)
-+ return 0;
-+
-+ /* Enable power. Allowing too much current at once may result
-+ * in POWOK never getting set, so start low and ramp it up as
-+ * necessary to succeed.
-+ */
-+ powok = false;
-+ for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; inrush++) {
-+ PM_WRITE(pm_reg,
-+ (PM_READ(pm_reg) & ~PM_INRUSH_MASK) |
-+ (inrush << PM_INRUSH_SHIFT) |
-+ PM_POWUP);
-+
-+ start = ktime_get_ns();
-+ while (!(powok = !!(PM_READ(pm_reg) & PM_POWOK))) {
-+ cpu_relax();
-+ if (ktime_get_ns() - start >= 3000)
-+ break;
-+ }
-+ }
-+ if (!powok) {
-+ dev_err(dev, "Timeout waiting for %s power OK\n",
-+ pd->base.name);
-+ ret = -ETIMEDOUT;
-+ goto err_disable_powup;
-+ }
-+
-+ /* Disable electrical isolation */
-+ PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW);
-+
-+ /* Repair memory */
-+ PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP);
-+ start = ktime_get_ns();
-+ while (!(PM_READ(pm_reg) & PM_MRDONE)) {
-+ cpu_relax();
-+ if (ktime_get_ns() - start >= 1000) {
-+ dev_err(dev, "Timeout waiting for %s memory repair\n",
-+ pd->base.name);
-+ ret = -ETIMEDOUT;
-+ goto err_disable_ispow;
-+ }
-+ }
-+
-+ /* Disable functional isolation */
-+ PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC);
-+
-+ return 0;
-+
-+err_disable_ispow:
-+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
-+err_disable_powup:
-+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK));
-+ return ret;
-+}
-+
-+static int bcm2835_asb_power_on(struct bcm2835_power_domain *pd,
-+ u32 pm_reg,
-+ u32 asb_m_reg,
-+ u32 asb_s_reg,
-+ u32 reset_flags)
-+{
-+ struct bcm2835_power *power = pd->power;
-+ int ret;
-+
-+ ret = clk_prepare_enable(pd->clk);
-+ if (ret) {
-+ dev_err(power->dev, "Failed to enable clock for %s\n",
-+ pd->base.name);
-+ return ret;
-+ }
-+
-+ /* Wait 32 clocks for reset to propagate, 1 us will be enough */
-+ udelay(1);
-+
-+ clk_disable_unprepare(pd->clk);
-+
-+ /* Deassert the resets. */
-+ PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags);
-+
-+ ret = clk_prepare_enable(pd->clk);
-+ if (ret) {
-+ dev_err(power->dev, "Failed to enable clock for %s\n",
-+ pd->base.name);
-+ goto err_enable_resets;
-+ }
-+
-+ ret = bcm2835_asb_enable(power, asb_m_reg);
-+ if (ret) {
-+ dev_err(power->dev, "Failed to enable ASB master for %s\n",
-+ pd->base.name);
-+ goto err_disable_clk;
-+ }
-+ ret = bcm2835_asb_enable(power, asb_s_reg);
-+ if (ret) {
-+ dev_err(power->dev, "Failed to enable ASB slave for %s\n",
-+ pd->base.name);
-+ goto err_disable_asb_master;
-+ }
-+
-+ return 0;
-+
-+err_disable_asb_master:
-+ bcm2835_asb_disable(power, asb_m_reg);
-+err_disable_clk:
-+ clk_disable_unprepare(pd->clk);
-+err_enable_resets:
-+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
-+ return ret;
-+}
-+
-+static int bcm2835_asb_power_off(struct bcm2835_power_domain *pd,
-+ u32 pm_reg,
-+ u32 asb_m_reg,
-+ u32 asb_s_reg,
-+ u32 reset_flags)
-+{
-+ struct bcm2835_power *power = pd->power;
-+ int ret;
-+
-+ ret = bcm2835_asb_disable(power, asb_s_reg);
-+ if (ret) {
-+ dev_warn(power->dev, "Failed to disable ASB slave for %s\n",
-+ pd->base.name);
-+ return ret;
-+ }
-+ ret = bcm2835_asb_disable(power, asb_m_reg);
-+ if (ret) {
-+ dev_warn(power->dev, "Failed to disable ASB master for %s\n",
-+ pd->base.name);
-+ bcm2835_asb_enable(power, asb_s_reg);
-+ return ret;
-+ }
-+
-+ clk_disable_unprepare(pd->clk);
-+
-+ /* Assert the resets. */
-+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
-+
-+ return 0;
-+}
-+
-+static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain)
-+{
-+ struct bcm2835_power_domain *pd =
-+ container_of(domain, struct bcm2835_power_domain, base);
-+ struct bcm2835_power *power = pd->power;
-+
-+ switch (pd->domain) {
-+ case BCM2835_POWER_DOMAIN_GRAFX:
-+ return bcm2835_power_power_on(pd, PM_GRAFX);
-+
-+ case BCM2835_POWER_DOMAIN_GRAFX_V3D:
-+ return bcm2835_asb_power_on(pd, PM_GRAFX,
-+ ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
-+ PM_V3DRSTN);
-+
-+ case BCM2835_POWER_DOMAIN_IMAGE:
-+ return bcm2835_power_power_on(pd, PM_IMAGE);
-+
-+ case BCM2835_POWER_DOMAIN_IMAGE_PERI:
-+ return bcm2835_asb_power_on(pd, PM_IMAGE,
-+ 0, 0,
-+ PM_PERIRSTN);
-+
-+ case BCM2835_POWER_DOMAIN_IMAGE_ISP:
-+ return bcm2835_asb_power_on(pd, PM_IMAGE,
-+ ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
-+ PM_ISPRSTN);
-+
-+ case BCM2835_POWER_DOMAIN_IMAGE_H264:
-+ return bcm2835_asb_power_on(pd, PM_IMAGE,
-+ ASB_H264_M_CTRL, ASB_H264_S_CTRL,
-+ PM_H264RSTN);
-+
-+ case BCM2835_POWER_DOMAIN_USB:
-+ PM_WRITE(PM_USB, PM_USB_CTRLEN);
-+ return 0;
-+
-+ case BCM2835_POWER_DOMAIN_DSI0:
-+ PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
-+ PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN);
-+ return 0;
-+
-+ case BCM2835_POWER_DOMAIN_DSI1:
-+ PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
-+ PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN);
-+ return 0;
-+
-+ case BCM2835_POWER_DOMAIN_CCP2TX:
-+ PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
-+ PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN);
-+ return 0;
-+
-+ case BCM2835_POWER_DOMAIN_HDMI:
-+ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR);
-+ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN);
-+ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD);
-+ usleep_range(100, 200);
-+ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR);
-+ return 0;
-+
-+ default:
-+ dev_err(power->dev, "Invalid domain %d\n", pd->domain);
-+ return -EINVAL;
-+ }
-+}
-+
-+static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain)
-+{
-+ struct bcm2835_power_domain *pd =
-+ container_of(domain, struct bcm2835_power_domain, base);
-+ struct bcm2835_power *power = pd->power;
-+
-+ switch (pd->domain) {
-+ case BCM2835_POWER_DOMAIN_GRAFX:
-+ return bcm2835_power_power_off(pd, PM_GRAFX);
-+
-+ case BCM2835_POWER_DOMAIN_GRAFX_V3D:
-+ return bcm2835_asb_power_off(pd, PM_GRAFX,
-+ ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
-+ PM_V3DRSTN);
-+
-+ case BCM2835_POWER_DOMAIN_IMAGE:
-+ return bcm2835_power_power_off(pd, PM_IMAGE);
-+
-+ case BCM2835_POWER_DOMAIN_IMAGE_PERI:
-+ return bcm2835_asb_power_off(pd, PM_IMAGE,
-+ 0, 0,
-+ PM_PERIRSTN);
-+
-+ case BCM2835_POWER_DOMAIN_IMAGE_ISP:
-+ return bcm2835_asb_power_off(pd, PM_IMAGE,
-+ ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
-+ PM_ISPRSTN);
-+
-+ case BCM2835_POWER_DOMAIN_IMAGE_H264:
-+ return bcm2835_asb_power_off(pd, PM_IMAGE,
-+ ASB_H264_M_CTRL, ASB_H264_S_CTRL,
-+ PM_H264RSTN);
-+
-+ case BCM2835_POWER_DOMAIN_USB:
-+ PM_WRITE(PM_USB, 0);
-+ return 0;
-+
-+ case BCM2835_POWER_DOMAIN_DSI0:
-+ PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
-+ PM_WRITE(PM_DSI0, 0);
-+ return 0;
-+
-+ case BCM2835_POWER_DOMAIN_DSI1:
-+ PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
-+ PM_WRITE(PM_DSI1, 0);
-+ return 0;
-+
-+ case BCM2835_POWER_DOMAIN_CCP2TX:
-+ PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
-+ PM_WRITE(PM_CCP2TX, 0);
-+ return 0;
-+
-+ case BCM2835_POWER_DOMAIN_HDMI:
-+ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD);
-+ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN);
-+ return 0;
-+
-+ default:
-+ dev_err(power->dev, "Invalid domain %d\n", pd->domain);
-+ return -EINVAL;
-+ }
-+}
-+
-+static void
-+bcm2835_init_power_domain(struct bcm2835_power *power,
-+ int pd_xlate_index, const char *name)
-+{
-+ struct device *dev = power->dev;
-+ struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
-+
-+ dom->clk = devm_clk_get(dev->parent, name);
-+
-+ dom->base.name = name;
-+ dom->base.power_on = bcm2835_power_pd_power_on;
-+ dom->base.power_off = bcm2835_power_pd_power_off;
-+
-+ dom->domain = pd_xlate_index;
-+ dom->power = power;
-+
-+ /* XXX: on/off at boot? */
-+ pm_genpd_init(&dom->base, NULL, true);
-+
-+ power->pd_xlate.domains[pd_xlate_index] = &dom->base;
-+}
-+
-+/** bcm2835_reset_reset - Resets a block that has a reset line in the
-+ * PM block.
-+ *
-+ * The consumer of the reset controller must have the power domain up
-+ * -- there's no reset ability with the power domain down. To reset
-+ * the sub-block, we just disable its access to memory through the
-+ * ASB, reset, and re-enable.
-+ */
-+static int bcm2835_reset_reset(struct reset_controller_dev *rcdev,
-+ unsigned long id)
-+{
-+ struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
-+ reset);
-+ struct bcm2835_power_domain *pd;
-+ int ret;
-+
-+ switch (id) {
-+ case BCM2835_RESET_V3D:
-+ pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D];
-+ break;
-+ case BCM2835_RESET_H264:
-+ pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264];
-+ break;
-+ case BCM2835_RESET_ISP:
-+ pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP];
-+ break;
-+ default:
-+ dev_err(power->dev, "Bad reset id %ld\n", id);
-+ return -EINVAL;
-+ }
-+
-+ ret = bcm2835_power_pd_power_off(&pd->base);
-+ if (ret)
-+ return ret;
-+
-+ return bcm2835_power_pd_power_on(&pd->base);
-+}
-+
-+static int bcm2835_reset_status(struct reset_controller_dev *rcdev,
-+ unsigned long id)
-+{
-+ struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
-+ reset);
-+
-+ switch (id) {
-+ case BCM2835_RESET_V3D:
-+ return !PM_READ(PM_GRAFX & PM_V3DRSTN);
-+ case BCM2835_RESET_H264:
-+ return !PM_READ(PM_IMAGE & PM_H264RSTN);
-+ case BCM2835_RESET_ISP:
-+ return !PM_READ(PM_IMAGE & PM_ISPRSTN);
-+ default:
-+ return -EINVAL;
-+ }
-+}
-+
-+const struct reset_control_ops bcm2835_reset_ops = {
-+ .reset = bcm2835_reset_reset,
-+ .status = bcm2835_reset_status,
-+};
-+
-+static const char *const power_domain_names[] = {
-+ [BCM2835_POWER_DOMAIN_GRAFX] = "grafx",
-+ [BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d",
-+
-+ [BCM2835_POWER_DOMAIN_IMAGE] = "image",
-+ [BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image",
-+ [BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264",
-+ [BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp",
-+
-+ [BCM2835_POWER_DOMAIN_USB] = "usb",
-+ [BCM2835_POWER_DOMAIN_DSI0] = "dsi0",
-+ [BCM2835_POWER_DOMAIN_DSI1] = "dsi1",
-+ [BCM2835_POWER_DOMAIN_CAM0] = "cam0",
-+ [BCM2835_POWER_DOMAIN_CAM1] = "cam1",
-+ [BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx",
-+ [BCM2835_POWER_DOMAIN_HDMI] = "hdmi",
-+};
-+
-+static int bcm2835_power_probe(struct platform_device *pdev)
-+{
-+ struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);
-+ struct device *dev = &pdev->dev;
-+ struct bcm2835_power *power;
-+ static const struct {
-+ int parent, child;
-+ } domain_deps[] = {
-+ { BCM2835_POWER_DOMAIN_GRAFX, BCM2835_POWER_DOMAIN_GRAFX_V3D },
-+ { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_PERI },
-+ { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_H264 },
-+ { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_ISP },
-+ { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_USB },
-+ { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },
-+ { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },
-+ };
-+ int ret, i;
-+ u32 id;
-+
-+ power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
-+ if (!power)
-+ return -ENOMEM;
-+ platform_set_drvdata(pdev, power);
-+
-+ power->dev = dev;
-+ power->base = pm->base;
-+ power->asb = pm->asb;
-+
-+ id = ASB_READ(ASB_AXI_BRDG_ID);
-+ if (id != 0x62726467 /* "BRDG" */) {
-+ dev_err(dev, "ASB register ID returned 0x%08x\n", id);
-+ return -ENODEV;
-+ }
-+
-+ power->pd_xlate.domains = devm_kcalloc(dev,
-+ ARRAY_SIZE(power_domain_names),
-+ sizeof(*power->pd_xlate.domains),
-+ GFP_KERNEL);
-+ if (!power->pd_xlate.domains)
-+ return -ENOMEM;
-+
-+ power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);
-+
-+ for (i = 0; i < ARRAY_SIZE(power_domain_names); i++)
-+ bcm2835_init_power_domain(power, i, power_domain_names[i]);
-+
-+ for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {
-+ pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,
-+ &power->domains[domain_deps[i].child].base);
-+ }
-+
-+ power->reset.owner = THIS_MODULE;
-+ power->reset.nr_resets = BCM2835_RESET_COUNT;
-+ power->reset.ops = &bcm2835_reset_ops;
-+ power->reset.of_node = dev->parent->of_node;
-+
-+ ret = devm_reset_controller_register(dev, &power->reset);
-+ if (ret)
-+ return ret;
-+
-+ of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
-+
-+ dev_info(dev, "Broadcom BCM2835 power domains driver");
-+ return 0;
-+}
-+
-+static int bcm2835_power_remove(struct platform_device *pdev)
-+{
-+ return 0;
-+}
-+
-+static struct platform_driver bcm2835_power_driver = {
-+ .probe = bcm2835_power_probe,
-+ .remove = bcm2835_power_remove,
-+ .driver = {
-+ .name = "bcm2835-power",
-+ },
-+};
-+module_platform_driver(bcm2835_power_driver);
-+
-+MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/include/dt-bindings/soc/bcm2835-pm.h
-@@ -0,0 +1,28 @@
-+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
-+
-+#ifndef _DT_BINDINGS_ARM_BCM2835_PM_H
-+#define _DT_BINDINGS_ARM_BCM2835_PM_H
-+
-+#define BCM2835_POWER_DOMAIN_GRAFX 0
-+#define BCM2835_POWER_DOMAIN_GRAFX_V3D 1
-+#define BCM2835_POWER_DOMAIN_IMAGE 2
-+#define BCM2835_POWER_DOMAIN_IMAGE_PERI 3
-+#define BCM2835_POWER_DOMAIN_IMAGE_ISP 4
-+#define BCM2835_POWER_DOMAIN_IMAGE_H264 5
-+#define BCM2835_POWER_DOMAIN_USB 6
-+#define BCM2835_POWER_DOMAIN_DSI0 7
-+#define BCM2835_POWER_DOMAIN_DSI1 8
-+#define BCM2835_POWER_DOMAIN_CAM0 9
-+#define BCM2835_POWER_DOMAIN_CAM1 10
-+#define BCM2835_POWER_DOMAIN_CCP2TX 11
-+#define BCM2835_POWER_DOMAIN_HDMI 12
-+
-+#define BCM2835_POWER_DOMAIN_COUNT 13
-+
-+#define BCM2835_RESET_V3D 0
-+#define BCM2835_RESET_ISP 1
-+#define BCM2835_RESET_H264 2
-+
-+#define BCM2835_RESET_COUNT 3
-+
-+#endif /* _DT_BINDINGS_ARM_BCM2835_PM_H */
---- a/include/linux/mfd/bcm2835-pm.h
-+++ b/include/linux/mfd/bcm2835-pm.h
-@@ -8,6 +8,7 @@
- struct bcm2835_pm {
- struct device *dev;
- void __iomem *base;
-+ void __iomem *asb;
- };
-
- #endif /* BCM2835_MFD_PM_H */
--- /dev/null
+From 8d9f3526529d857376c661c21820a0049c2e62de Mon Sep 17 00:00:00 2001
+Date: Sat, 12 Jan 2019 08:07:43 -0800
+Subject: [PATCH] soc: bcm: bcm2835-pm: Fix error paths of
+ initialization.
+
+The clock driver may probe after ours and so we need to pass the
+-EPROBE_DEFER out. Fix the other error path while we're here.
+
+v2: Use dom->name instead of dom->gov as the flag for initialized
+ domains, since we aren't setting up a governor. Make sure to
+ clear ->clk when no clk is present in the DT.
+
+Fixes: 670c672608a1 ("soc: bcm: bcm2835-pm: Add support for power domains under a new binding.")
+---
+ drivers/soc/bcm/bcm2835-power.c | 35 ++++++++++++++++++++++++++++-----
+ 1 file changed, 30 insertions(+), 5 deletions(-)
+
+--- a/drivers/soc/bcm/bcm2835-power.c
++++ b/drivers/soc/bcm/bcm2835-power.c
+@@ -485,7 +485,7 @@ static int bcm2835_power_pd_power_off(st
+ }
+ }
+
+-static void
++static int
+ bcm2835_init_power_domain(struct bcm2835_power *power,
+ int pd_xlate_index, const char *name)
+ {
+@@ -493,6 +493,17 @@ bcm2835_init_power_domain(struct bcm2835
+ struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
+
+ dom->clk = devm_clk_get(dev->parent, name);
++ if (IS_ERR(dom->clk)) {
++ int ret = PTR_ERR(dom->clk);
++
++ if (ret == -EPROBE_DEFER)
++ return ret;
++
++ /* Some domains don't have a clk, so make sure that we
++ * don't deref an error pointer later.
++ */
++ dom->clk = NULL;
++ }
+
+ dom->base.name = name;
+ dom->base.power_on = bcm2835_power_pd_power_on;
+@@ -505,6 +516,8 @@ bcm2835_init_power_domain(struct bcm2835
+ pm_genpd_init(&dom->base, NULL, true);
+
+ power->pd_xlate.domains[pd_xlate_index] = &dom->base;
++
++ return 0;
+ }
+
+ /** bcm2835_reset_reset - Resets a block that has a reset line in the
+@@ -602,7 +615,7 @@ static int bcm2835_power_probe(struct pl
+ { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },
+ { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },
+ };
+- int ret, i;
++ int ret = 0, i;
+ u32 id;
+
+ power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
+@@ -629,8 +642,11 @@ static int bcm2835_power_probe(struct pl
+
+ power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);
+
+- for (i = 0; i < ARRAY_SIZE(power_domain_names); i++)
+- bcm2835_init_power_domain(power, i, power_domain_names[i]);
++ for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
++ ret = bcm2835_init_power_domain(power, i, power_domain_names[i]);
++ if (ret)
++ goto fail;
++ }
+
+ for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {
+ pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,
+@@ -644,12 +660,21 @@ static int bcm2835_power_probe(struct pl
+
+ ret = devm_reset_controller_register(dev, &power->reset);
+ if (ret)
+- return ret;
++ goto fail;
+
+ of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
+
+ dev_info(dev, "Broadcom BCM2835 power domains driver");
+ return 0;
++
++fail:
++ for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
++ struct generic_pm_domain *dom = &power->domains[i].base;
++
++ if (dom->name)
++ pm_genpd_remove(dom);
++ }
++ return ret;
+ }
+
+ static int bcm2835_power_remove(struct platform_device *pdev)
--- /dev/null
+From f3470769d4e64084fc7f3060d634aff8fdf8f75d Mon Sep 17 00:00:00 2001
+Date: Fri, 11 Jan 2019 17:31:07 -0800
+Subject: [PATCH] soc: bcm: bcm2835-pm: Add support for 2711.
+
+Without the actual power management part any more, there's a lot less
+to set up for V3D. We just need to clear the RSTN field for the power
+domain, and expose the reset controller for toggling it again.
+
+This is definitely incomplete -- the old ISP and H264 is in the old
+bridge, but since we have no consumers of it I've just done the
+minimum to get V3D working.
+
+---
+ drivers/mfd/bcm2835-pm.c | 11 +++++++++++
+ drivers/soc/bcm/bcm2835-power.c | 22 ++++++++++++++++++++++
+ include/linux/mfd/bcm2835-pm.h | 1 +
+ 3 files changed, 34 insertions(+)
+
+--- a/drivers/mfd/bcm2835-pm.c
++++ b/drivers/mfd/bcm2835-pm.c
+@@ -50,6 +50,17 @@ static int bcm2835_pm_probe(struct platf
+ if (ret)
+ return ret;
+
++ /* Map the ARGON ASB regs if present. */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
++ if (res) {
++ pm->arg_asb = devm_ioremap_resource(dev, res);
++ if (IS_ERR(pm->arg_asb)) {
++ dev_err(dev, "Failed to map ARGON ASB: %ld\n",
++ PTR_ERR(pm->arg_asb));
++ return PTR_ERR(pm->arg_asb);
++ }
++ }
++
+ /* We'll use the presence of the AXI ASB regs in the
+ * bcm2835-pm binding as the key for whether we can reference
+ * the full PM register range and support power domains.
+--- a/drivers/soc/bcm/bcm2835-power.c
++++ b/drivers/soc/bcm/bcm2835-power.c
+@@ -143,6 +143,8 @@ struct bcm2835_power {
+ /* AXI Async bridge registers. */
+ void __iomem *asb;
+
++ bool is_2711;
++
+ struct genpd_onecell_data pd_xlate;
+ struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
+ struct reset_controller_dev reset;
+@@ -192,6 +194,10 @@ static int bcm2835_power_power_off(struc
+ {
+ struct bcm2835_power *power = pd->power;
+
++ /* 2711 has no power domains above the reset controller. */
++ if (power->is_2711)
++ return 0;
++
+ /* Enable functional isolation */
+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
+
+@@ -213,6 +219,10 @@ static int bcm2835_power_power_on(struct
+ int inrush;
+ bool powok;
+
++ /* 2711 has no power domains above the reset controller. */
++ if (power->is_2711)
++ return 0;
++
+ /* If it was already powered on by the fw, leave it that way. */
+ if (PM_READ(pm_reg) & PM_POWUP)
+ return 0;
+@@ -627,6 +637,18 @@ static int bcm2835_power_probe(struct pl
+ power->base = pm->base;
+ power->asb = pm->asb;
+
++ /* 2711 hack: the new ARGON ASB took over V3D, which is our
++ * only consumer of this driver so far. The old ASB seems to
++ * still be present with ISP and H264 bits but no V3D, but I
++ * don't know if that's real or not. The V3D is in the same
++ * place in the new ASB as the old one, so just poke the new
++ * one for now.
++ */
++ if (pm->arg_asb) {
++ power->asb = pm->arg_asb;
++ power->is_2711 = true;
++ }
++
+ id = ASB_READ(ASB_AXI_BRDG_ID);
+ if (id != 0x62726467 /* "BRDG" */) {
+ dev_err(dev, "ASB register ID returned 0x%08x\n", id);
+--- a/include/linux/mfd/bcm2835-pm.h
++++ b/include/linux/mfd/bcm2835-pm.h
+@@ -9,6 +9,7 @@ struct bcm2835_pm {
+ struct device *dev;
+ void __iomem *base;
+ void __iomem *asb;
++ void __iomem *arg_asb;
+ };
+
+ #endif /* BCM2835_MFD_PM_H */
+++ /dev/null
-From ea44a81b7daf511788aecaee7575feff359c5d19 Mon Sep 17 00:00:00 2001
-Date: Fri, 11 Jan 2019 17:29:10 -0800
-Subject: [PATCH] soc: bcm: bcm2835-pm: Fix PM_IMAGE_PERI power domain
- support.
-
-We don't have ASB master/slave regs for this domain, so just skip that
-step.
-
-Fixes: 670c672608a1 ("soc: bcm: bcm2835-pm: Add support for power domains under a new binding.")
----
- drivers/soc/bcm/bcm2835-power.c | 14 ++++++++++++--
- 1 file changed, 12 insertions(+), 2 deletions(-)
-
---- a/drivers/soc/bcm/bcm2835-power.c
-+++ b/drivers/soc/bcm/bcm2835-power.c
-@@ -150,7 +150,12 @@ struct bcm2835_power {
-
- static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
- {
-- u64 start = ktime_get_ns();
-+ u64 start;
-+
-+ if (!reg)
-+ return 0;
-+
-+ start = ktime_get_ns();
-
- /* Enable the module's async AXI bridges. */
- ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP);
-@@ -165,7 +170,12 @@ static int bcm2835_asb_enable(struct bcm
-
- static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
- {
-- u64 start = ktime_get_ns();
-+ u64 start;
-+
-+ if (!reg)
-+ return 0;
-+
-+ start = ktime_get_ns();
-
- /* Enable the module's async AXI bridges. */
- ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP);
--- /dev/null
+From 7e891cb1f9f57c87706b1292f186d65e1640e0e7 Mon Sep 17 00:00:00 2001
+Date: Thu, 30 Aug 2018 14:48:29 +0800
+Subject: [PATCH] drm: expand drm_syncobj_find_fence to support
+ timeline point v2
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+we can fetch timeline point fence after expanded.
+v2: The parameter fence is the result of the function and should come last.
+
+Link: https://patchwork.freedesktop.org/patch/246541/
+(cherry picked from commit 0a6730ea27b68c7ac4171c29a816c29d26a9637a)
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +-
+ drivers/gpu/drm/drm_syncobj.c | 5 +++--
+ drivers/gpu/drm/v3d/v3d_gem.c | 4 ++--
+ drivers/gpu/drm/vc4/vc4_gem.c | 2 +-
+ include/drm/drm_syncobj.h | 2 +-
+ 5 files changed, 8 insertions(+), 7 deletions(-)
+
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+@@ -1105,7 +1105,7 @@ static int amdgpu_syncobj_lookup_and_add
+ {
+ int r;
+ struct dma_fence *fence;
+- r = drm_syncobj_find_fence(p->filp, handle, &fence);
++ r = drm_syncobj_find_fence(p->filp, handle, 0, &fence);
+ if (r)
+ return r;
+
+--- a/drivers/gpu/drm/drm_syncobj.c
++++ b/drivers/gpu/drm/drm_syncobj.c
+@@ -235,6 +235,7 @@ static int drm_syncobj_assign_null_handl
+ * drm_syncobj_find_fence - lookup and reference the fence in a sync object
+ * @file_private: drm file private pointer
+ * @handle: sync object handle to lookup.
++ * @point: timeline point
+ * @fence: out parameter for the fence
+ *
+ * This is just a convenience function that combines drm_syncobj_find() and
+@@ -245,7 +246,7 @@ static int drm_syncobj_assign_null_handl
+ * dma_fence_put().
+ */
+ int drm_syncobj_find_fence(struct drm_file *file_private,
+- u32 handle,
++ u32 handle, u64 point,
+ struct dma_fence **fence)
+ {
+ struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
+@@ -516,7 +517,7 @@ static int drm_syncobj_export_sync_file(
+ if (fd < 0)
+ return fd;
+
+- ret = drm_syncobj_find_fence(file_private, handle, &fence);
++ ret = drm_syncobj_find_fence(file_private, handle, 0, &fence);
+ if (ret)
+ goto err_put_fd;
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -521,12 +521,12 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ kref_init(&exec->refcount);
+
+ ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
+- &exec->bin.in_fence);
++ 0, &exec->bin.in_fence);
+ if (ret == -EINVAL)
+ goto fail;
+
+ ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl,
+- &exec->render.in_fence);
++ 0, &exec->render.in_fence);
+ if (ret == -EINVAL)
+ goto fail;
+
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -1173,7 +1173,7 @@ vc4_submit_cl_ioctl(struct drm_device *d
+
+ if (args->in_sync) {
+ ret = drm_syncobj_find_fence(file_priv, args->in_sync,
+- &in_fence);
++ 0, &in_fence);
+ if (ret)
+ goto fail;
+
+--- a/include/drm/drm_syncobj.h
++++ b/include/drm/drm_syncobj.h
+@@ -139,7 +139,7 @@ void drm_syncobj_remove_callback(struct
+ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
+ struct dma_fence *fence);
+ int drm_syncobj_find_fence(struct drm_file *file_private,
+- u32 handle,
++ u32 handle, u64 point,
+ struct dma_fence **fence);
+ void drm_syncobj_free(struct kref *kref);
+ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
+++ /dev/null
-From 8d9f3526529d857376c661c21820a0049c2e62de Mon Sep 17 00:00:00 2001
-Date: Sat, 12 Jan 2019 08:07:43 -0800
-Subject: [PATCH] soc: bcm: bcm2835-pm: Fix error paths of
- initialization.
-
-The clock driver may probe after ours and so we need to pass the
--EPROBE_DEFER out. Fix the other error path while we're here.
-
-v2: Use dom->name instead of dom->gov as the flag for initialized
- domains, since we aren't setting up a governor. Make sure to
- clear ->clk when no clk is present in the DT.
-
-Fixes: 670c672608a1 ("soc: bcm: bcm2835-pm: Add support for power domains under a new binding.")
----
- drivers/soc/bcm/bcm2835-power.c | 35 ++++++++++++++++++++++++++++-----
- 1 file changed, 30 insertions(+), 5 deletions(-)
-
---- a/drivers/soc/bcm/bcm2835-power.c
-+++ b/drivers/soc/bcm/bcm2835-power.c
-@@ -485,7 +485,7 @@ static int bcm2835_power_pd_power_off(st
- }
- }
-
--static void
-+static int
- bcm2835_init_power_domain(struct bcm2835_power *power,
- int pd_xlate_index, const char *name)
- {
-@@ -493,6 +493,17 @@ bcm2835_init_power_domain(struct bcm2835
- struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
-
- dom->clk = devm_clk_get(dev->parent, name);
-+ if (IS_ERR(dom->clk)) {
-+ int ret = PTR_ERR(dom->clk);
-+
-+ if (ret == -EPROBE_DEFER)
-+ return ret;
-+
-+ /* Some domains don't have a clk, so make sure that we
-+ * don't deref an error pointer later.
-+ */
-+ dom->clk = NULL;
-+ }
-
- dom->base.name = name;
- dom->base.power_on = bcm2835_power_pd_power_on;
-@@ -505,6 +516,8 @@ bcm2835_init_power_domain(struct bcm2835
- pm_genpd_init(&dom->base, NULL, true);
-
- power->pd_xlate.domains[pd_xlate_index] = &dom->base;
-+
-+ return 0;
- }
-
- /** bcm2835_reset_reset - Resets a block that has a reset line in the
-@@ -602,7 +615,7 @@ static int bcm2835_power_probe(struct pl
- { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },
- { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },
- };
-- int ret, i;
-+ int ret = 0, i;
- u32 id;
-
- power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
-@@ -629,8 +642,11 @@ static int bcm2835_power_probe(struct pl
-
- power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);
-
-- for (i = 0; i < ARRAY_SIZE(power_domain_names); i++)
-- bcm2835_init_power_domain(power, i, power_domain_names[i]);
-+ for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
-+ ret = bcm2835_init_power_domain(power, i, power_domain_names[i]);
-+ if (ret)
-+ goto fail;
-+ }
-
- for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {
- pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,
-@@ -644,12 +660,21 @@ static int bcm2835_power_probe(struct pl
-
- ret = devm_reset_controller_register(dev, &power->reset);
- if (ret)
-- return ret;
-+ goto fail;
-
- of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
-
- dev_info(dev, "Broadcom BCM2835 power domains driver");
- return 0;
-+
-+fail:
-+ for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
-+ struct generic_pm_domain *dom = &power->domains[i].base;
-+
-+ if (dom->name)
-+ pm_genpd_remove(dom);
-+ }
-+ return ret;
- }
-
- static int bcm2835_power_remove(struct platform_device *pdev)
--- /dev/null
+From f5f3df2b1746a9ba9420ae11988fc37a7b93691d Mon Sep 17 00:00:00 2001
+Date: Fri, 28 Sep 2018 16:21:23 -0700
+Subject: [PATCH] drm/v3d: Fix a use-after-free race accessing the
+ scheduler's fences.
+
+Once we push the job, the scheduler could run it and free it. So, if
+we want to reference their fences, we need to grab them before then.
+I haven't seen this happen in many days of conformance test runtime,
+but let's still close the race.
+
+Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+")
+Link: https://patchwork.freedesktop.org/patch/254119/
+(cherry picked from commit 34c2c4f632f232ed2fdb66d4e42cc72d322273fe)
+---
+ drivers/gpu/drm/v3d/v3d_drv.h | 5 +++++
+ drivers/gpu/drm/v3d/v3d_gem.c | 8 ++++++--
+ 2 files changed, 11 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.h
++++ b/drivers/gpu/drm/v3d/v3d_drv.h
+@@ -198,6 +198,11 @@ struct v3d_exec_info {
+ */
+ struct dma_fence *bin_done_fence;
+
++ /* Fence for when the scheduler considers the render to be
++ * done, for when the BOs reservations should be complete.
++ */
++ struct dma_fence *render_done_fence;
++
+ struct kref refcount;
+
+ /* This is the array of BOs that were looked up at the start of exec. */
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -209,7 +209,7 @@ v3d_flush_caches(struct v3d_dev *v3d)
+ static void
+ v3d_attach_object_fences(struct v3d_exec_info *exec)
+ {
+- struct dma_fence *out_fence = &exec->render.base.s_fence->finished;
++ struct dma_fence *out_fence = exec->render_done_fence;
+ struct v3d_bo *bo;
+ int i;
+
+@@ -409,6 +409,7 @@ v3d_exec_cleanup(struct kref *ref)
+ dma_fence_put(exec->render.done_fence);
+
+ dma_fence_put(exec->bin_done_fence);
++ dma_fence_put(exec->render_done_fence);
+
+ for (i = 0; i < exec->bo_count; i++)
+ drm_gem_object_put_unlocked(&exec->bo[i]->base);
+@@ -572,6 +573,9 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ if (ret)
+ goto fail_unreserve;
+
++ exec->render_done_fence =
++ dma_fence_get(&exec->render.base.s_fence->finished);
++
+ kref_get(&exec->refcount); /* put by scheduler job completion */
+ drm_sched_entity_push_job(&exec->render.base,
+ &v3d_priv->sched_entity[V3D_RENDER]);
+@@ -585,7 +589,7 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ sync_out = drm_syncobj_find(file_priv, args->out_sync);
+ if (sync_out) {
+ drm_syncobj_replace_fence(sync_out,
+- &exec->render.base.s_fence->finished);
++ exec->render_done_fence);
+ drm_syncobj_put(sync_out);
+ }
+
+++ /dev/null
-From f3470769d4e64084fc7f3060d634aff8fdf8f75d Mon Sep 17 00:00:00 2001
-Date: Fri, 11 Jan 2019 17:31:07 -0800
-Subject: [PATCH] soc: bcm: bcm2835-pm: Add support for 2711.
-
-Without the actual power management part any more, there's a lot less
-to set up for V3D. We just need to clear the RSTN field for the power
-domain, and expose the reset controller for toggling it again.
-
-This is definitely incomplete -- the old ISP and H264 is in the old
-bridge, but since we have no consumers of it I've just done the
-minimum to get V3D working.
-
----
- drivers/mfd/bcm2835-pm.c | 11 +++++++++++
- drivers/soc/bcm/bcm2835-power.c | 22 ++++++++++++++++++++++
- include/linux/mfd/bcm2835-pm.h | 1 +
- 3 files changed, 34 insertions(+)
-
---- a/drivers/mfd/bcm2835-pm.c
-+++ b/drivers/mfd/bcm2835-pm.c
-@@ -50,6 +50,17 @@ static int bcm2835_pm_probe(struct platf
- if (ret)
- return ret;
-
-+ /* Map the ARGON ASB regs if present. */
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-+ if (res) {
-+ pm->arg_asb = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(pm->arg_asb)) {
-+ dev_err(dev, "Failed to map ARGON ASB: %ld\n",
-+ PTR_ERR(pm->arg_asb));
-+ return PTR_ERR(pm->arg_asb);
-+ }
-+ }
-+
- /* We'll use the presence of the AXI ASB regs in the
- * bcm2835-pm binding as the key for whether we can reference
- * the full PM register range and support power domains.
---- a/drivers/soc/bcm/bcm2835-power.c
-+++ b/drivers/soc/bcm/bcm2835-power.c
-@@ -143,6 +143,8 @@ struct bcm2835_power {
- /* AXI Async bridge registers. */
- void __iomem *asb;
-
-+ bool is_2711;
-+
- struct genpd_onecell_data pd_xlate;
- struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
- struct reset_controller_dev reset;
-@@ -192,6 +194,10 @@ static int bcm2835_power_power_off(struc
- {
- struct bcm2835_power *power = pd->power;
-
-+ /* 2711 has no power domains above the reset controller. */
-+ if (power->is_2711)
-+ return 0;
-+
- /* Enable functional isolation */
- PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
-
-@@ -213,6 +219,10 @@ static int bcm2835_power_power_on(struct
- int inrush;
- bool powok;
-
-+ /* 2711 has no power domains above the reset controller. */
-+ if (power->is_2711)
-+ return 0;
-+
- /* If it was already powered on by the fw, leave it that way. */
- if (PM_READ(pm_reg) & PM_POWUP)
- return 0;
-@@ -627,6 +637,18 @@ static int bcm2835_power_probe(struct pl
- power->base = pm->base;
- power->asb = pm->asb;
-
-+ /* 2711 hack: the new ARGON ASB took over V3D, which is our
-+ * only consumer of this driver so far. The old ASB seems to
-+ * still be present with ISP and H264 bits but no V3D, but I
-+ * don't know if that's real or not. The V3D is in the same
-+ * place in the new ASB as the old one, so just poke the new
-+ * one for now.
-+ */
-+ if (pm->arg_asb) {
-+ power->asb = pm->arg_asb;
-+ power->is_2711 = true;
-+ }
-+
- id = ASB_READ(ASB_AXI_BRDG_ID);
- if (id != 0x62726467 /* "BRDG" */) {
- dev_err(dev, "ASB register ID returned 0x%08x\n", id);
---- a/include/linux/mfd/bcm2835-pm.h
-+++ b/include/linux/mfd/bcm2835-pm.h
-@@ -9,6 +9,7 @@ struct bcm2835_pm {
- struct device *dev;
- void __iomem *base;
- void __iomem *asb;
-+ void __iomem *arg_asb;
- };
-
- #endif /* BCM2835_MFD_PM_H */
+++ /dev/null
-From 7e891cb1f9f57c87706b1292f186d65e1640e0e7 Mon Sep 17 00:00:00 2001
-Date: Thu, 30 Aug 2018 14:48:29 +0800
-Subject: [PATCH] drm: expand drm_syncobj_find_fence to support
- timeline point v2
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-we can fetch timeline point fence after expanded.
-v2: The parameter fence is the result of the function and should come last.
-
-Link: https://patchwork.freedesktop.org/patch/246541/
-(cherry picked from commit 0a6730ea27b68c7ac4171c29a816c29d26a9637a)
----
- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +-
- drivers/gpu/drm/drm_syncobj.c | 5 +++--
- drivers/gpu/drm/v3d/v3d_gem.c | 4 ++--
- drivers/gpu/drm/vc4/vc4_gem.c | 2 +-
- include/drm/drm_syncobj.h | 2 +-
- 5 files changed, 8 insertions(+), 7 deletions(-)
-
---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
-+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
-@@ -1105,7 +1105,7 @@ static int amdgpu_syncobj_lookup_and_add
- {
- int r;
- struct dma_fence *fence;
-- r = drm_syncobj_find_fence(p->filp, handle, &fence);
-+ r = drm_syncobj_find_fence(p->filp, handle, 0, &fence);
- if (r)
- return r;
-
---- a/drivers/gpu/drm/drm_syncobj.c
-+++ b/drivers/gpu/drm/drm_syncobj.c
-@@ -235,6 +235,7 @@ static int drm_syncobj_assign_null_handl
- * drm_syncobj_find_fence - lookup and reference the fence in a sync object
- * @file_private: drm file private pointer
- * @handle: sync object handle to lookup.
-+ * @point: timeline point
- * @fence: out parameter for the fence
- *
- * This is just a convenience function that combines drm_syncobj_find() and
-@@ -245,7 +246,7 @@ static int drm_syncobj_assign_null_handl
- * dma_fence_put().
- */
- int drm_syncobj_find_fence(struct drm_file *file_private,
-- u32 handle,
-+ u32 handle, u64 point,
- struct dma_fence **fence)
- {
- struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
-@@ -516,7 +517,7 @@ static int drm_syncobj_export_sync_file(
- if (fd < 0)
- return fd;
-
-- ret = drm_syncobj_find_fence(file_private, handle, &fence);
-+ ret = drm_syncobj_find_fence(file_private, handle, 0, &fence);
- if (ret)
- goto err_put_fd;
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -521,12 +521,12 @@ v3d_submit_cl_ioctl(struct drm_device *d
- kref_init(&exec->refcount);
-
- ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
-- &exec->bin.in_fence);
-+ 0, &exec->bin.in_fence);
- if (ret == -EINVAL)
- goto fail;
-
- ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl,
-- &exec->render.in_fence);
-+ 0, &exec->render.in_fence);
- if (ret == -EINVAL)
- goto fail;
-
---- a/drivers/gpu/drm/vc4/vc4_gem.c
-+++ b/drivers/gpu/drm/vc4/vc4_gem.c
-@@ -1173,7 +1173,7 @@ vc4_submit_cl_ioctl(struct drm_device *d
-
- if (args->in_sync) {
- ret = drm_syncobj_find_fence(file_priv, args->in_sync,
-- &in_fence);
-+ 0, &in_fence);
- if (ret)
- goto fail;
-
---- a/include/drm/drm_syncobj.h
-+++ b/include/drm/drm_syncobj.h
-@@ -139,7 +139,7 @@ void drm_syncobj_remove_callback(struct
- void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
- struct dma_fence *fence);
- int drm_syncobj_find_fence(struct drm_file *file_private,
-- u32 handle,
-+ u32 handle, u64 point,
- struct dma_fence **fence);
- void drm_syncobj_free(struct kref *kref);
- int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
--- /dev/null
+From 18f93916e42ea25fc77cab20d1e038620e33d741 Mon Sep 17 00:00:00 2001
+Date: Fri, 28 Sep 2018 16:21:24 -0700
+Subject: [PATCH] drm/v3d: Add a little debugfs entry for measuring the
+ core clock.
+
+This adds just enough performance counter support to measure the
+clock. We don't have linux kernel drivers for the clock driving the
+HW, and this was useful for determining that the V3D HW is running on
+a slow clock, not that the driver was slow.
+
+(cherry picked from commit 6915c9a525e575732429c22b28eb11871a29374b)
+---
+ drivers/gpu/drm/v3d/v3d_debugfs.c | 35 +++++++++++++++++++++++++++++++
+ drivers/gpu/drm/v3d/v3d_regs.h | 30 ++++++++++++++++++++++++++
+ 2 files changed, 65 insertions(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
++++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
+@@ -179,9 +179,44 @@ static int v3d_debugfs_bo_stats(struct s
+ return 0;
+ }
+
++static int v3d_measure_clock(struct seq_file *m, void *unused)
++{
++ struct drm_info_node *node = (struct drm_info_node *)m->private;
++ struct drm_device *dev = node->minor->dev;
++ struct v3d_dev *v3d = to_v3d_dev(dev);
++ uint32_t cycles;
++ int core = 0;
++ int measure_ms = 1000;
++
++ if (v3d->ver >= 40) {
++ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
++ V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT,
++ V3D_PCTR_S0));
++ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1);
++ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1);
++ } else {
++ V3D_CORE_WRITE(core, V3D_V3_PCTR_0_PCTRS0,
++ V3D_PCTR_CYCLE_COUNT);
++ V3D_CORE_WRITE(core, V3D_V3_PCTR_0_CLR, 1);
++ V3D_CORE_WRITE(core, V3D_V3_PCTR_0_EN,
++ V3D_V3_PCTR_0_EN_ENABLE |
++ 1);
++ }
++ msleep(measure_ms);
++ cycles = V3D_CORE_READ(core, V3D_PCTR_0_PCTR0);
++
++ seq_printf(m, "cycles: %d (%d.%d Mhz)\n",
++ cycles,
++ cycles / (measure_ms * 1000),
++ (cycles / (measure_ms * 100)) % 10);
++
++ return 0;
++}
++
+ static const struct drm_info_list v3d_debugfs_list[] = {
+ {"v3d_ident", v3d_v3d_debugfs_ident, 0},
+ {"v3d_regs", v3d_v3d_debugfs_regs, 0},
++ {"measure_clock", v3d_measure_clock, 0},
+ {"bo_stats", v3d_debugfs_bo_stats, 0},
+ };
+
+--- a/drivers/gpu/drm/v3d/v3d_regs.h
++++ b/drivers/gpu/drm/v3d/v3d_regs.h
+@@ -267,6 +267,36 @@
+ # define V3D_PTB_BXCF_RWORDERDISA BIT(1)
+ # define V3D_PTB_BXCF_CLIPDISA BIT(0)
+
++#define V3D_V3_PCTR_0_EN 0x00674
++#define V3D_V3_PCTR_0_EN_ENABLE BIT(31)
++#define V3D_V4_PCTR_0_EN 0x00650
++/* When a bit is set, resets the counter to 0. */
++#define V3D_V3_PCTR_0_CLR 0x00670
++#define V3D_V4_PCTR_0_CLR 0x00654
++#define V3D_PCTR_0_OVERFLOW 0x00658
++
++#define V3D_V3_PCTR_0_PCTRS0 0x00684
++#define V3D_V3_PCTR_0_PCTRS15 0x00660
++#define V3D_V3_PCTR_0_PCTRSX(x) (V3D_V3_PCTR_0_PCTRS0 + \
++ 4 * (x))
++/* Each src reg muxes four counters each. */
++#define V3D_V4_PCTR_0_SRC_0_3 0x00660
++#define V3D_V4_PCTR_0_SRC_28_31 0x0067c
++# define V3D_PCTR_S0_MASK V3D_MASK(6, 0)
++# define V3D_PCTR_S0_SHIFT 0
++# define V3D_PCTR_S1_MASK V3D_MASK(14, 8)
++# define V3D_PCTR_S1_SHIFT 8
++# define V3D_PCTR_S2_MASK V3D_MASK(22, 16)
++# define V3D_PCTR_S2_SHIFT 16
++# define V3D_PCTR_S3_MASK V3D_MASK(30, 24)
++# define V3D_PCTR_S3_SHIFT 24
++# define V3D_PCTR_CYCLE_COUNT 32
++
++/* Output values of the counters. */
++#define V3D_PCTR_0_PCTR0 0x00680
++#define V3D_PCTR_0_PCTR31 0x006fc
++#define V3D_PCTR_0_PCTRX(x) (V3D_PCTR_0_PCTR0 + \
++ 4 * (x))
+ #define V3D_GMP_STATUS 0x00800
+ # define V3D_GMP_STATUS_GMPRST BIT(31)
+ # define V3D_GMP_STATUS_WR_COUNT_MASK V3D_MASK(30, 24)
+++ /dev/null
-From f5f3df2b1746a9ba9420ae11988fc37a7b93691d Mon Sep 17 00:00:00 2001
-Date: Fri, 28 Sep 2018 16:21:23 -0700
-Subject: [PATCH] drm/v3d: Fix a use-after-free race accessing the
- scheduler's fences.
-
-Once we push the job, the scheduler could run it and free it. So, if
-we want to reference their fences, we need to grab them before then.
-I haven't seen this happen in many days of conformance test runtime,
-but let's still close the race.
-
-Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+")
-Link: https://patchwork.freedesktop.org/patch/254119/
-(cherry picked from commit 34c2c4f632f232ed2fdb66d4e42cc72d322273fe)
----
- drivers/gpu/drm/v3d/v3d_drv.h | 5 +++++
- drivers/gpu/drm/v3d/v3d_gem.c | 8 ++++++--
- 2 files changed, 11 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.h
-+++ b/drivers/gpu/drm/v3d/v3d_drv.h
-@@ -198,6 +198,11 @@ struct v3d_exec_info {
- */
- struct dma_fence *bin_done_fence;
-
-+ /* Fence for when the scheduler considers the render to be
-+ * done, for when the BOs reservations should be complete.
-+ */
-+ struct dma_fence *render_done_fence;
-+
- struct kref refcount;
-
- /* This is the array of BOs that were looked up at the start of exec. */
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -209,7 +209,7 @@ v3d_flush_caches(struct v3d_dev *v3d)
- static void
- v3d_attach_object_fences(struct v3d_exec_info *exec)
- {
-- struct dma_fence *out_fence = &exec->render.base.s_fence->finished;
-+ struct dma_fence *out_fence = exec->render_done_fence;
- struct v3d_bo *bo;
- int i;
-
-@@ -409,6 +409,7 @@ v3d_exec_cleanup(struct kref *ref)
- dma_fence_put(exec->render.done_fence);
-
- dma_fence_put(exec->bin_done_fence);
-+ dma_fence_put(exec->render_done_fence);
-
- for (i = 0; i < exec->bo_count; i++)
- drm_gem_object_put_unlocked(&exec->bo[i]->base);
-@@ -572,6 +573,9 @@ v3d_submit_cl_ioctl(struct drm_device *d
- if (ret)
- goto fail_unreserve;
-
-+ exec->render_done_fence =
-+ dma_fence_get(&exec->render.base.s_fence->finished);
-+
- kref_get(&exec->refcount); /* put by scheduler job completion */
- drm_sched_entity_push_job(&exec->render.base,
- &v3d_priv->sched_entity[V3D_RENDER]);
-@@ -585,7 +589,7 @@ v3d_submit_cl_ioctl(struct drm_device *d
- sync_out = drm_syncobj_find(file_priv, args->out_sync);
- if (sync_out) {
- drm_syncobj_replace_fence(sync_out,
-- &exec->render.base.s_fence->finished);
-+ exec->render_done_fence);
- drm_syncobj_put(sync_out);
- }
-
--- /dev/null
+From 6351d93a0f1a18c45c4407c472195d957da5d3d0 Mon Sep 17 00:00:00 2001
+Date: Thu, 8 Nov 2018 08:16:52 -0800
+Subject: [PATCH] drm/v3d: Update a comment about what uses
+ v3d_job_dependency().
+
+I merged bin and render's paths in a late refactoring.
+
+(cherry picked from commit e90e45f6bd45cc494a6f4cd1853c5e7cd4be7f68)
+---
+ drivers/gpu/drm/v3d/v3d_sched.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_sched.c
++++ b/drivers/gpu/drm/v3d/v3d_sched.c
+@@ -39,7 +39,7 @@ v3d_job_free(struct drm_sched_job *sched
+ }
+
+ /**
+- * Returns the fences that the bin job depends on, one by one.
++ * Returns the fences that the bin or render job depends on, one by one.
+ * v3d_job_run() won't be called until all of them have been signaled.
+ */
+ static struct dma_fence *
+++ /dev/null
-From 18f93916e42ea25fc77cab20d1e038620e33d741 Mon Sep 17 00:00:00 2001
-Date: Fri, 28 Sep 2018 16:21:24 -0700
-Subject: [PATCH] drm/v3d: Add a little debugfs entry for measuring the
- core clock.
-
-This adds just enough performance counter support to measure the
-clock. We don't have linux kernel drivers for the clock driving the
-HW, and this was useful for determining that the V3D HW is running on
-a slow clock, not that the driver was slow.
-
-(cherry picked from commit 6915c9a525e575732429c22b28eb11871a29374b)
----
- drivers/gpu/drm/v3d/v3d_debugfs.c | 35 +++++++++++++++++++++++++++++++
- drivers/gpu/drm/v3d/v3d_regs.h | 30 ++++++++++++++++++++++++++
- 2 files changed, 65 insertions(+)
-
---- a/drivers/gpu/drm/v3d/v3d_debugfs.c
-+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
-@@ -179,9 +179,44 @@ static int v3d_debugfs_bo_stats(struct s
- return 0;
- }
-
-+static int v3d_measure_clock(struct seq_file *m, void *unused)
-+{
-+ struct drm_info_node *node = (struct drm_info_node *)m->private;
-+ struct drm_device *dev = node->minor->dev;
-+ struct v3d_dev *v3d = to_v3d_dev(dev);
-+ uint32_t cycles;
-+ int core = 0;
-+ int measure_ms = 1000;
-+
-+ if (v3d->ver >= 40) {
-+ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
-+ V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT,
-+ V3D_PCTR_S0));
-+ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1);
-+ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1);
-+ } else {
-+ V3D_CORE_WRITE(core, V3D_V3_PCTR_0_PCTRS0,
-+ V3D_PCTR_CYCLE_COUNT);
-+ V3D_CORE_WRITE(core, V3D_V3_PCTR_0_CLR, 1);
-+ V3D_CORE_WRITE(core, V3D_V3_PCTR_0_EN,
-+ V3D_V3_PCTR_0_EN_ENABLE |
-+ 1);
-+ }
-+ msleep(measure_ms);
-+ cycles = V3D_CORE_READ(core, V3D_PCTR_0_PCTR0);
-+
-+ seq_printf(m, "cycles: %d (%d.%d Mhz)\n",
-+ cycles,
-+ cycles / (measure_ms * 1000),
-+ (cycles / (measure_ms * 100)) % 10);
-+
-+ return 0;
-+}
-+
- static const struct drm_info_list v3d_debugfs_list[] = {
- {"v3d_ident", v3d_v3d_debugfs_ident, 0},
- {"v3d_regs", v3d_v3d_debugfs_regs, 0},
-+ {"measure_clock", v3d_measure_clock, 0},
- {"bo_stats", v3d_debugfs_bo_stats, 0},
- };
-
---- a/drivers/gpu/drm/v3d/v3d_regs.h
-+++ b/drivers/gpu/drm/v3d/v3d_regs.h
-@@ -267,6 +267,36 @@
- # define V3D_PTB_BXCF_RWORDERDISA BIT(1)
- # define V3D_PTB_BXCF_CLIPDISA BIT(0)
-
-+#define V3D_V3_PCTR_0_EN 0x00674
-+#define V3D_V3_PCTR_0_EN_ENABLE BIT(31)
-+#define V3D_V4_PCTR_0_EN 0x00650
-+/* When a bit is set, resets the counter to 0. */
-+#define V3D_V3_PCTR_0_CLR 0x00670
-+#define V3D_V4_PCTR_0_CLR 0x00654
-+#define V3D_PCTR_0_OVERFLOW 0x00658
-+
-+#define V3D_V3_PCTR_0_PCTRS0 0x00684
-+#define V3D_V3_PCTR_0_PCTRS15 0x00660
-+#define V3D_V3_PCTR_0_PCTRSX(x) (V3D_V3_PCTR_0_PCTRS0 + \
-+ 4 * (x))
-+/* Each src reg muxes four counters each. */
-+#define V3D_V4_PCTR_0_SRC_0_3 0x00660
-+#define V3D_V4_PCTR_0_SRC_28_31 0x0067c
-+# define V3D_PCTR_S0_MASK V3D_MASK(6, 0)
-+# define V3D_PCTR_S0_SHIFT 0
-+# define V3D_PCTR_S1_MASK V3D_MASK(14, 8)
-+# define V3D_PCTR_S1_SHIFT 8
-+# define V3D_PCTR_S2_MASK V3D_MASK(22, 16)
-+# define V3D_PCTR_S2_SHIFT 16
-+# define V3D_PCTR_S3_MASK V3D_MASK(30, 24)
-+# define V3D_PCTR_S3_SHIFT 24
-+# define V3D_PCTR_CYCLE_COUNT 32
-+
-+/* Output values of the counters. */
-+#define V3D_PCTR_0_PCTR0 0x00680
-+#define V3D_PCTR_0_PCTR31 0x006fc
-+#define V3D_PCTR_0_PCTRX(x) (V3D_PCTR_0_PCTR0 + \
-+ 4 * (x))
- #define V3D_GMP_STATUS 0x00800
- # define V3D_GMP_STATUS_GMPRST BIT(31)
- # define V3D_GMP_STATUS_WR_COUNT_MASK V3D_MASK(30, 24)
--- /dev/null
+From 5ca5bd799b4f4a065b969461fa7852415bfb8c6f Mon Sep 17 00:00:00 2001
+Date: Thu, 8 Nov 2018 08:16:53 -0800
+Subject: [PATCH] drm/v3d: Clean up the reservation object setup.
+
+The extra to_v3d_bo() calls came from copying this from the vc4
+driver, which stored the cma gem object in the structs.
+
+v2: Fix an unused var warning
+
+(cherry picked from commit 8f1cd826641d677d0f7494253ecfc3335f0bcd4e)
+---
+ drivers/gpu/drm/v3d/v3d_gem.c | 33 +++++++++++----------------------
+ 1 file changed, 11 insertions(+), 22 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -210,14 +210,11 @@ static void
+ v3d_attach_object_fences(struct v3d_exec_info *exec)
+ {
+ struct dma_fence *out_fence = exec->render_done_fence;
+- struct v3d_bo *bo;
+ int i;
+
+ for (i = 0; i < exec->bo_count; i++) {
+- bo = to_v3d_bo(&exec->bo[i]->base);
+-
+ /* XXX: Use shared fences for read-only objects. */
+- reservation_object_add_excl_fence(bo->resv, out_fence);
++ reservation_object_add_excl_fence(exec->bo[i]->resv, out_fence);
+ }
+ }
+
+@@ -228,11 +225,8 @@ v3d_unlock_bo_reservations(struct drm_de
+ {
+ int i;
+
+- for (i = 0; i < exec->bo_count; i++) {
+- struct v3d_bo *bo = to_v3d_bo(&exec->bo[i]->base);
+-
+- ww_mutex_unlock(&bo->resv->lock);
+- }
++ for (i = 0; i < exec->bo_count; i++)
++ ww_mutex_unlock(&exec->bo[i]->resv->lock);
+
+ ww_acquire_fini(acquire_ctx);
+ }
+@@ -251,13 +245,13 @@ v3d_lock_bo_reservations(struct drm_devi
+ {
+ int contended_lock = -1;
+ int i, ret;
+- struct v3d_bo *bo;
+
+ ww_acquire_init(acquire_ctx, &reservation_ww_class);
+
+ retry:
+ if (contended_lock != -1) {
+- bo = to_v3d_bo(&exec->bo[contended_lock]->base);
++ struct v3d_bo *bo = exec->bo[contended_lock];
++
+ ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,
+ acquire_ctx);
+ if (ret) {
+@@ -270,19 +264,16 @@ retry:
+ if (i == contended_lock)
+ continue;
+
+- bo = to_v3d_bo(&exec->bo[i]->base);
+-
+- ret = ww_mutex_lock_interruptible(&bo->resv->lock, acquire_ctx);
++ ret = ww_mutex_lock_interruptible(&exec->bo[i]->resv->lock,
++ acquire_ctx);
+ if (ret) {
+ int j;
+
+- for (j = 0; j < i; j++) {
+- bo = to_v3d_bo(&exec->bo[j]->base);
+- ww_mutex_unlock(&bo->resv->lock);
+- }
++ for (j = 0; j < i; j++)
++ ww_mutex_unlock(&exec->bo[j]->resv->lock);
+
+ if (contended_lock != -1 && contended_lock >= i) {
+- bo = to_v3d_bo(&exec->bo[contended_lock]->base);
++ struct v3d_bo *bo = exec->bo[contended_lock];
+
+ ww_mutex_unlock(&bo->resv->lock);
+ }
+@@ -303,9 +294,7 @@ retry:
+ * before we commit the CL to the hardware.
+ */
+ for (i = 0; i < exec->bo_count; i++) {
+- bo = to_v3d_bo(&exec->bo[i]->base);
+-
+- ret = reservation_object_reserve_shared(bo->resv);
++ ret = reservation_object_reserve_shared(exec->bo[i]->resv);
+ if (ret) {
+ v3d_unlock_bo_reservations(dev, exec, acquire_ctx);
+ return ret;
--- /dev/null
+From ba1e90b6c3b3bf0e88ab01c824c4f8fde582e878 Mon Sep 17 00:00:00 2001
+Date: Wed, 28 Nov 2018 15:09:25 -0800
+Subject: [PATCH] drm/v3d: Add support for submitting jobs to the TFU.
+
+The TFU can copy from raster, UIF, and SAND input images to UIF output
+images, with optional mipmap generation. This will certainly be
+useful for media EGL image input, but is also useful immediately for
+mipmap generation without bogging the V3D core down.
+
+For now we only run the queue 1 job deep, and don't have any hang
+recovery (though I don't think we should need it, with TFU). Queuing
+multiple jobs in the HW will require synchronizing the YUV coefficient
+regs updates since they don't get FIFOed with the job.
+
+v2: Change the ioctl to IOW instead of IOWR, always set COEF0, explain
+ why TFU is AUTH, clarify the syncing docs, drop the unused TFU
+ interrupt regs (you're expected to use the hub's), don't take
+ &bo->base for NULL bos.
+v3: Fix a little whitespace alignment (noticed by checkpatch), rebase
+ on drm_sched_job_cleanup() changes.
+
+Link: https://patchwork.freedesktop.org/patch/264607/
+(cherry picked from commit 1584f16ca96ef124aad79efa3303cff5f3530e2c)
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 15 ++-
+ drivers/gpu/drm/v3d/v3d_drv.h | 32 +++++-
+ drivers/gpu/drm/v3d/v3d_gem.c | 178 ++++++++++++++++++++++++++++----
+ drivers/gpu/drm/v3d/v3d_irq.c | 12 ++-
+ drivers/gpu/drm/v3d/v3d_regs.h | 49 +++++++++
+ drivers/gpu/drm/v3d/v3d_sched.c | 148 ++++++++++++++++++++++----
+ drivers/gpu/drm/v3d/v3d_trace.h | 20 ++++
+ include/uapi/drm/v3d_drm.h | 25 +++++
+ 8 files changed, 426 insertions(+), 53 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -112,10 +112,15 @@ static int v3d_get_param_ioctl(struct dr
+ return 0;
+ }
+
+- /* Any params that aren't just register reads would go here. */
+
+- DRM_DEBUG("Unknown parameter %d\n", args->param);
+- return -EINVAL;
++ switch (args->param) {
++ case DRM_V3D_PARAM_SUPPORTS_TFU:
++ args->value = 1;
++ return 0;
++ default:
++ DRM_DEBUG("Unknown parameter %d\n", args->param);
++ return -EINVAL;
++ }
+ }
+
+ static int
+@@ -170,7 +175,8 @@ static const struct file_operations v3d_
+ /* DRM_AUTH is required on SUBMIT_CL for now, while we don't have GMP
+ * protection between clients. Note that render nodes would be be
+ * able to submit CLs that could access BOs from clients authenticated
+- * with the master node.
++ * with the master node. The TFU doesn't use the GMP, so it would
++ * need to stay DRM_AUTH until we do buffer size/offset validation.
+ */
+ static const struct drm_ioctl_desc v3d_drm_ioctls[] = {
+ DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CL, v3d_submit_cl_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
+@@ -179,6 +185,7 @@ static const struct drm_ioctl_desc v3d_d
+ DRM_IOCTL_DEF_DRV(V3D_MMAP_BO, v3d_mmap_bo_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(V3D_GET_PARAM, v3d_get_param_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(V3D_GET_BO_OFFSET, v3d_get_bo_offset_ioctl, DRM_RENDER_ALLOW),
++ DRM_IOCTL_DEF_DRV(V3D_SUBMIT_TFU, v3d_submit_tfu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
+ };
+
+ static const struct vm_operations_struct v3d_vm_ops = {
+--- a/drivers/gpu/drm/v3d/v3d_drv.h
++++ b/drivers/gpu/drm/v3d/v3d_drv.h
+@@ -7,19 +7,18 @@
+ #include <drm/drm_encoder.h>
+ #include <drm/drm_gem.h>
+ #include <drm/gpu_scheduler.h>
++#include "uapi/drm/v3d_drm.h"
+
+ #define GMP_GRANULARITY (128 * 1024)
+
+-/* Enum for each of the V3D queues. We maintain various queue
+- * tracking as an array because at some point we'll want to support
+- * the TFU (texture formatting unit) as another queue.
+- */
++/* Enum for each of the V3D queues. */
+ enum v3d_queue {
+ V3D_BIN,
+ V3D_RENDER,
++ V3D_TFU,
+ };
+
+-#define V3D_MAX_QUEUES (V3D_RENDER + 1)
++#define V3D_MAX_QUEUES (V3D_TFU + 1)
+
+ struct v3d_queue_state {
+ struct drm_gpu_scheduler sched;
+@@ -68,6 +67,7 @@ struct v3d_dev {
+
+ struct v3d_exec_info *bin_job;
+ struct v3d_exec_info *render_job;
++ struct v3d_tfu_job *tfu_job;
+
+ struct v3d_queue_state queue[V3D_MAX_QUEUES];
+
+@@ -218,6 +218,25 @@ struct v3d_exec_info {
+ u32 qma, qms, qts;
+ };
+
++struct v3d_tfu_job {
++ struct drm_sched_job base;
++
++ struct drm_v3d_submit_tfu args;
++
++ /* An optional fence userspace can pass in for the job to depend on. */
++ struct dma_fence *in_fence;
++
++ /* v3d fence to be signaled by IRQ handler when the job is complete. */
++ struct dma_fence *done_fence;
++
++ struct v3d_dev *v3d;
++
++ struct kref refcount;
++
++ /* This is the array of BOs that were looked up at the start of exec. */
++ struct v3d_bo *bo[4];
++};
++
+ /**
+ * _wait_for - magic (register) wait macro
+ *
+@@ -281,9 +300,12 @@ int v3d_gem_init(struct drm_device *dev)
+ void v3d_gem_destroy(struct drm_device *dev);
+ int v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
++int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv);
+ int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+ void v3d_exec_put(struct v3d_exec_info *exec);
++void v3d_tfu_job_put(struct v3d_tfu_job *exec);
+ void v3d_reset(struct v3d_dev *v3d);
+ void v3d_invalidate_caches(struct v3d_dev *v3d);
+ void v3d_flush_caches(struct v3d_dev *v3d);
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -207,26 +207,27 @@ v3d_flush_caches(struct v3d_dev *v3d)
+ }
+
+ static void
+-v3d_attach_object_fences(struct v3d_exec_info *exec)
++v3d_attach_object_fences(struct v3d_bo **bos, int bo_count,
++ struct dma_fence *fence)
+ {
+- struct dma_fence *out_fence = exec->render_done_fence;
+ int i;
+
+- for (i = 0; i < exec->bo_count; i++) {
++ for (i = 0; i < bo_count; i++) {
+ /* XXX: Use shared fences for read-only objects. */
+- reservation_object_add_excl_fence(exec->bo[i]->resv, out_fence);
++ reservation_object_add_excl_fence(bos[i]->resv, fence);
+ }
+ }
+
+ static void
+ v3d_unlock_bo_reservations(struct drm_device *dev,
+- struct v3d_exec_info *exec,
++ struct v3d_bo **bos,
++ int bo_count,
+ struct ww_acquire_ctx *acquire_ctx)
+ {
+ int i;
+
+- for (i = 0; i < exec->bo_count; i++)
+- ww_mutex_unlock(&exec->bo[i]->resv->lock);
++ for (i = 0; i < bo_count; i++)
++ ww_mutex_unlock(&bos[i]->resv->lock);
+
+ ww_acquire_fini(acquire_ctx);
+ }
+@@ -240,7 +241,8 @@ v3d_unlock_bo_reservations(struct drm_de
+ */
+ static int
+ v3d_lock_bo_reservations(struct drm_device *dev,
+- struct v3d_exec_info *exec,
++ struct v3d_bo **bos,
++ int bo_count,
+ struct ww_acquire_ctx *acquire_ctx)
+ {
+ int contended_lock = -1;
+@@ -250,7 +252,7 @@ v3d_lock_bo_reservations(struct drm_devi
+
+ retry:
+ if (contended_lock != -1) {
+- struct v3d_bo *bo = exec->bo[contended_lock];
++ struct v3d_bo *bo = bos[contended_lock];
+
+ ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,
+ acquire_ctx);
+@@ -260,20 +262,20 @@ retry:
+ }
+ }
+
+- for (i = 0; i < exec->bo_count; i++) {
++ for (i = 0; i < bo_count; i++) {
+ if (i == contended_lock)
+ continue;
+
+- ret = ww_mutex_lock_interruptible(&exec->bo[i]->resv->lock,
++ ret = ww_mutex_lock_interruptible(&bos[i]->resv->lock,
+ acquire_ctx);
+ if (ret) {
+ int j;
+
+ for (j = 0; j < i; j++)
+- ww_mutex_unlock(&exec->bo[j]->resv->lock);
++ ww_mutex_unlock(&bos[j]->resv->lock);
+
+ if (contended_lock != -1 && contended_lock >= i) {
+- struct v3d_bo *bo = exec->bo[contended_lock];
++ struct v3d_bo *bo = bos[contended_lock];
+
+ ww_mutex_unlock(&bo->resv->lock);
+ }
+@@ -293,10 +295,11 @@ retry:
+ /* Reserve space for our shared (read-only) fence references,
+ * before we commit the CL to the hardware.
+ */
+- for (i = 0; i < exec->bo_count; i++) {
+- ret = reservation_object_reserve_shared(exec->bo[i]->resv);
++ for (i = 0; i < bo_count; i++) {
++ ret = reservation_object_reserve_shared(bos[i]->resv);
+ if (ret) {
+- v3d_unlock_bo_reservations(dev, exec, acquire_ctx);
++ v3d_unlock_bo_reservations(dev, bos, bo_count,
++ acquire_ctx);
+ return ret;
+ }
+ }
+@@ -419,6 +422,33 @@ void v3d_exec_put(struct v3d_exec_info *
+ kref_put(&exec->refcount, v3d_exec_cleanup);
+ }
+
++static void
++v3d_tfu_job_cleanup(struct kref *ref)
++{
++ struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job,
++ refcount);
++ struct v3d_dev *v3d = job->v3d;
++ unsigned int i;
++
++ dma_fence_put(job->in_fence);
++ dma_fence_put(job->done_fence);
++
++ for (i = 0; i < ARRAY_SIZE(job->bo); i++) {
++ if (job->bo[i])
++ drm_gem_object_put_unlocked(&job->bo[i]->base);
++ }
++
++ pm_runtime_mark_last_busy(v3d->dev);
++ pm_runtime_put_autosuspend(v3d->dev);
++
++ kfree(job);
++}
++
++void v3d_tfu_job_put(struct v3d_tfu_job *job)
++{
++ kref_put(&job->refcount, v3d_tfu_job_cleanup);
++}
++
+ int
+ v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+@@ -536,7 +566,8 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ if (ret)
+ goto fail;
+
+- ret = v3d_lock_bo_reservations(dev, exec, &acquire_ctx);
++ ret = v3d_lock_bo_reservations(dev, exec->bo, exec->bo_count,
++ &acquire_ctx);
+ if (ret)
+ goto fail;
+
+@@ -570,9 +601,10 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ &v3d_priv->sched_entity[V3D_RENDER]);
+ mutex_unlock(&v3d->sched_lock);
+
+- v3d_attach_object_fences(exec);
++ v3d_attach_object_fences(exec->bo, exec->bo_count,
++ exec->render_done_fence);
+
+- v3d_unlock_bo_reservations(dev, exec, &acquire_ctx);
++ v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx);
+
+ /* Update the return sync object for the */
+ sync_out = drm_syncobj_find(file_priv, args->out_sync);
+@@ -588,12 +620,118 @@ v3d_submit_cl_ioctl(struct drm_device *d
+
+ fail_unreserve:
+ mutex_unlock(&v3d->sched_lock);
+- v3d_unlock_bo_reservations(dev, exec, &acquire_ctx);
++ v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx);
+ fail:
+ v3d_exec_put(exec);
+
+ return ret;
+ }
++
++/**
++ * v3d_submit_tfu_ioctl() - Submits a TFU (texture formatting) job to the V3D.
++ * @dev: DRM device
++ * @data: ioctl argument
++ * @file_priv: DRM file for this fd
++ *
++ * Userspace provides the register setup for the TFU, which we don't
++ * need to validate since the TFU is behind the MMU.
++ */
++int
++v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ struct v3d_dev *v3d = to_v3d_dev(dev);
++ struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
++ struct drm_v3d_submit_tfu *args = data;
++ struct v3d_tfu_job *job;
++ struct ww_acquire_ctx acquire_ctx;
++ struct drm_syncobj *sync_out;
++ struct dma_fence *sched_done_fence;
++ int ret = 0;
++ int bo_count;
++
++ job = kcalloc(1, sizeof(*job), GFP_KERNEL);
++ if (!job)
++ return -ENOMEM;
++
++ ret = pm_runtime_get_sync(v3d->dev);
++ if (ret < 0) {
++ kfree(job);
++ return ret;
++ }
++
++ kref_init(&job->refcount);
++
++ ret = drm_syncobj_find_fence(file_priv, args->in_sync,
++ 0, &job->in_fence);
++ if (ret == -EINVAL)
++ goto fail;
++
++ job->args = *args;
++ job->v3d = v3d;
++
++ spin_lock(&file_priv->table_lock);
++ for (bo_count = 0; bo_count < ARRAY_SIZE(job->bo); bo_count++) {
++ struct drm_gem_object *bo;
++
++ if (!args->bo_handles[bo_count])
++ break;
++
++ bo = idr_find(&file_priv->object_idr,
++ args->bo_handles[bo_count]);
++ if (!bo) {
++ DRM_DEBUG("Failed to look up GEM BO %d: %d\n",
++ bo_count, args->bo_handles[bo_count]);
++ ret = -ENOENT;
++ spin_unlock(&file_priv->table_lock);
++ goto fail;
++ }
++ drm_gem_object_get(bo);
++ job->bo[bo_count] = to_v3d_bo(bo);
++ }
++ spin_unlock(&file_priv->table_lock);
++
++ ret = v3d_lock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
++ if (ret)
++ goto fail;
++
++ mutex_lock(&v3d->sched_lock);
++ ret = drm_sched_job_init(&job->base,
++ &v3d_priv->sched_entity[V3D_TFU],
++ v3d_priv);
++ if (ret)
++ goto fail_unreserve;
++
++ sched_done_fence = dma_fence_get(&job->base.s_fence->finished);
++
++ kref_get(&job->refcount); /* put by scheduler job completion */
++ drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[V3D_TFU]);
++ mutex_unlock(&v3d->sched_lock);
++
++ v3d_attach_object_fences(job->bo, bo_count, sched_done_fence);
++
++ v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
++
++ /* Update the return sync object */
++ sync_out = drm_syncobj_find(file_priv, args->out_sync);
++ if (sync_out) {
++ drm_syncobj_replace_fence(sync_out, sched_done_fence);
++ drm_syncobj_put(sync_out);
++ }
++ dma_fence_put(sched_done_fence);
++
++ v3d_tfu_job_put(job);
++
++ return 0;
++
++fail_unreserve:
++ mutex_unlock(&v3d->sched_lock);
++ v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
++fail:
++ v3d_tfu_job_put(job);
++
++ return ret;
++}
+
+ int
+ v3d_gem_init(struct drm_device *dev)
+--- a/drivers/gpu/drm/v3d/v3d_irq.c
++++ b/drivers/gpu/drm/v3d/v3d_irq.c
+@@ -4,8 +4,8 @@
+ /**
+ * DOC: Interrupt management for the V3D engine
+ *
+- * When we take a binning or rendering flush done interrupt, we need
+- * to signal the fence for that job so that the scheduler can queue up
++ * When we take a bin, render, or TFU done interrupt, we need to
++ * signal the fence for that job so that the scheduler can queue up
+ * the next one and unblock any waiters.
+ *
+ * When we take the binner out of memory interrupt, we need to
+@@ -23,7 +23,8 @@
+
+ #define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \
+ V3D_HUB_INT_MMU_PTI | \
+- V3D_HUB_INT_MMU_CAP))
++ V3D_HUB_INT_MMU_CAP | \
++ V3D_HUB_INT_TFUC))
+
+ static void
+ v3d_overflow_mem_work(struct work_struct *work)
+@@ -117,6 +118,11 @@ v3d_hub_irq(int irq, void *arg)
+ /* Acknowledge the interrupts we're handling here. */
+ V3D_WRITE(V3D_HUB_INT_CLR, intsts);
+
++ if (intsts & V3D_HUB_INT_TFUC) {
++ dma_fence_signal(v3d->tfu_job->done_fence);
++ status = IRQ_HANDLED;
++ }
++
+ if (intsts & (V3D_HUB_INT_MMU_WRV |
+ V3D_HUB_INT_MMU_PTI |
+ V3D_HUB_INT_MMU_CAP)) {
+--- a/drivers/gpu/drm/v3d/v3d_regs.h
++++ b/drivers/gpu/drm/v3d/v3d_regs.h
+@@ -86,6 +86,55 @@
+ # define V3D_TOP_GR_BRIDGE_SW_INIT_1 0x0000c
+ # define V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT BIT(0)
+
++#define V3D_TFU_CS 0x00400
++/* Stops current job, empties input fifo. */
++# define V3D_TFU_CS_TFURST BIT(31)
++# define V3D_TFU_CS_CVTCT_MASK V3D_MASK(23, 16)
++# define V3D_TFU_CS_CVTCT_SHIFT 16
++# define V3D_TFU_CS_NFREE_MASK V3D_MASK(13, 8)
++# define V3D_TFU_CS_NFREE_SHIFT 8
++# define V3D_TFU_CS_BUSY BIT(0)
++
++#define V3D_TFU_SU 0x00404
++/* Interrupt when FINTTHR input slots are free (0 = disabled) */
++# define V3D_TFU_SU_FINTTHR_MASK V3D_MASK(13, 8)
++# define V3D_TFU_SU_FINTTHR_SHIFT 8
++/* Skips resetting the CRC at the start of CRC generation. */
++# define V3D_TFU_SU_CRCCHAIN BIT(4)
++/* skips writes, computes CRC of the image. miplevels must be 0. */
++# define V3D_TFU_SU_CRC BIT(3)
++# define V3D_TFU_SU_THROTTLE_MASK V3D_MASK(1, 0)
++# define V3D_TFU_SU_THROTTLE_SHIFT 0
++
++#define V3D_TFU_ICFG 0x00408
++/* Interrupt when the conversion is complete. */
++# define V3D_TFU_ICFG_IOC BIT(0)
++
++/* Input Image Address */
++#define V3D_TFU_IIA 0x0040c
++/* Input Chroma Address */
++#define V3D_TFU_ICA 0x00410
++/* Input Image Stride */
++#define V3D_TFU_IIS 0x00414
++/* Input Image U-Plane Address */
++#define V3D_TFU_IUA 0x00418
++/* Output Image Address */
++#define V3D_TFU_IOA 0x0041c
++/* Image Output Size */
++#define V3D_TFU_IOS 0x00420
++/* TFU YUV Coefficient 0 */
++#define V3D_TFU_COEF0 0x00424
++/* Use these regs instead of the defaults. */
++# define V3D_TFU_COEF0_USECOEF BIT(31)
++/* TFU YUV Coefficient 1 */
++#define V3D_TFU_COEF1 0x00428
++/* TFU YUV Coefficient 2 */
++#define V3D_TFU_COEF2 0x0042c
++/* TFU YUV Coefficient 3 */
++#define V3D_TFU_COEF3 0x00430
++
++#define V3D_TFU_CRC 0x00434
++
+ /* Per-MMU registers. */
+
+ #define V3D_MMUC_CONTROL 0x01000
+--- a/drivers/gpu/drm/v3d/v3d_sched.c
++++ b/drivers/gpu/drm/v3d/v3d_sched.c
+@@ -30,6 +30,12 @@ to_v3d_job(struct drm_sched_job *sched_j
+ return container_of(sched_job, struct v3d_job, base);
+ }
+
++static struct v3d_tfu_job *
++to_tfu_job(struct drm_sched_job *sched_job)
++{
++ return container_of(sched_job, struct v3d_tfu_job, base);
++}
++
+ static void
+ v3d_job_free(struct drm_sched_job *sched_job)
+ {
+@@ -38,6 +44,14 @@ v3d_job_free(struct drm_sched_job *sched
+ v3d_exec_put(job->exec);
+ }
+
++static void
++v3d_tfu_job_free(struct drm_sched_job *sched_job)
++{
++ struct v3d_tfu_job *job = to_tfu_job(sched_job);
++
++ v3d_tfu_job_put(job);
++}
++
+ /**
+ * Returns the fences that the bin or render job depends on, one by one.
+ * v3d_job_run() won't be called until all of them have been signaled.
+@@ -76,6 +90,27 @@ v3d_job_dependency(struct drm_sched_job
+ return fence;
+ }
+
++/**
++ * Returns the fences that the TFU job depends on, one by one.
++ * v3d_tfu_job_run() won't be called until all of them have been
++ * signaled.
++ */
++static struct dma_fence *
++v3d_tfu_job_dependency(struct drm_sched_job *sched_job,
++ struct drm_sched_entity *s_entity)
++{
++ struct v3d_tfu_job *job = to_tfu_job(sched_job);
++ struct dma_fence *fence;
++
++ fence = job->in_fence;
++ if (fence) {
++ job->in_fence = NULL;
++ return fence;
++ }
++
++ return NULL;
++}
++
+ static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job)
+ {
+ struct v3d_job *job = to_v3d_job(sched_job);
+@@ -147,31 +182,47 @@ static struct dma_fence *v3d_job_run(str
+ return fence;
+ }
+
+-static void
+-v3d_job_timedout(struct drm_sched_job *sched_job)
++static struct dma_fence *
++v3d_tfu_job_run(struct drm_sched_job *sched_job)
+ {
+- struct v3d_job *job = to_v3d_job(sched_job);
+- struct v3d_exec_info *exec = job->exec;
+- struct v3d_dev *v3d = exec->v3d;
+- enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
+- enum v3d_queue q;
+- u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q));
+- u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q));
++ struct v3d_tfu_job *job = to_tfu_job(sched_job);
++ struct v3d_dev *v3d = job->v3d;
++ struct drm_device *dev = &v3d->drm;
++ struct dma_fence *fence;
+
+- /* If the current address or return address have changed, then
+- * the GPU has probably made progress and we should delay the
+- * reset. This could fail if the GPU got in an infinite loop
+- * in the CL, but that is pretty unlikely outside of an i-g-t
+- * testcase.
+- */
+- if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) {
+- job->timedout_ctca = ctca;
+- job->timedout_ctra = ctra;
++ fence = v3d_fence_create(v3d, V3D_TFU);
++ if (IS_ERR(fence))
++ return NULL;
+
+- schedule_delayed_work(&job->base.work_tdr,
+- job->base.sched->timeout);
+- return;
++ v3d->tfu_job = job;
++ if (job->done_fence)
++ dma_fence_put(job->done_fence);
++ job->done_fence = dma_fence_get(fence);
++
++ trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);
++
++ V3D_WRITE(V3D_TFU_IIA, job->args.iia);
++ V3D_WRITE(V3D_TFU_IIS, job->args.iis);
++ V3D_WRITE(V3D_TFU_ICA, job->args.ica);
++ V3D_WRITE(V3D_TFU_IUA, job->args.iua);
++ V3D_WRITE(V3D_TFU_IOA, job->args.ioa);
++ V3D_WRITE(V3D_TFU_IOS, job->args.ios);
++ V3D_WRITE(V3D_TFU_COEF0, job->args.coef[0]);
++ if (job->args.coef[0] & V3D_TFU_COEF0_USECOEF) {
++ V3D_WRITE(V3D_TFU_COEF1, job->args.coef[1]);
++ V3D_WRITE(V3D_TFU_COEF2, job->args.coef[2]);
++ V3D_WRITE(V3D_TFU_COEF3, job->args.coef[3]);
+ }
++ /* ICFG kicks off the job. */
++ V3D_WRITE(V3D_TFU_ICFG, job->args.icfg | V3D_TFU_ICFG_IOC);
++
++ return fence;
++}
++
++static void
++v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job)
++{
++ enum v3d_queue q;
+
+ mutex_lock(&v3d->reset_lock);
+
+@@ -196,6 +247,41 @@ v3d_job_timedout(struct drm_sched_job *s
+ mutex_unlock(&v3d->reset_lock);
+ }
+
++static void
++v3d_job_timedout(struct drm_sched_job *sched_job)
++{
++ struct v3d_job *job = to_v3d_job(sched_job);
++ struct v3d_exec_info *exec = job->exec;
++ struct v3d_dev *v3d = exec->v3d;
++ enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
++ u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q));
++ u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q));
++
++ /* If the current address or return address have changed, then
++ * the GPU has probably made progress and we should delay the
++ * reset. This could fail if the GPU got in an infinite loop
++ * in the CL, but that is pretty unlikely outside of an i-g-t
++ * testcase.
++ */
++ if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) {
++ job->timedout_ctca = ctca;
++ job->timedout_ctra = ctra;
++ schedule_delayed_work(&job->base.work_tdr,
++ job->base.sched->timeout);
++ return;
++ }
++
++ v3d_gpu_reset_for_timeout(v3d, sched_job);
++}
++
++static void
++v3d_tfu_job_timedout(struct drm_sched_job *sched_job)
++{
++ struct v3d_tfu_job *job = to_tfu_job(sched_job);
++
++ v3d_gpu_reset_for_timeout(job->v3d, sched_job);
++}
++
+ static const struct drm_sched_backend_ops v3d_sched_ops = {
+ .dependency = v3d_job_dependency,
+ .run_job = v3d_job_run,
+@@ -203,6 +289,13 @@ static const struct drm_sched_backend_op
+ .free_job = v3d_job_free
+ };
+
++static const struct drm_sched_backend_ops v3d_tfu_sched_ops = {
++ .dependency = v3d_tfu_job_dependency,
++ .run_job = v3d_tfu_job_run,
++ .timedout_job = v3d_tfu_job_timedout,
++ .free_job = v3d_tfu_job_free
++};
++
+ int
+ v3d_sched_init(struct v3d_dev *v3d)
+ {
+@@ -232,6 +325,19 @@ v3d_sched_init(struct v3d_dev *v3d)
+ drm_sched_fini(&v3d->queue[V3D_BIN].sched);
+ return ret;
+ }
++
++ ret = drm_sched_init(&v3d->queue[V3D_TFU].sched,
++ &v3d_tfu_sched_ops,
++ hw_jobs_limit, job_hang_limit,
++ msecs_to_jiffies(hang_limit_ms),
++ "v3d_tfu");
++ if (ret) {
++ dev_err(v3d->dev, "Failed to create TFU scheduler: %d.",
++ ret);
++ drm_sched_fini(&v3d->queue[V3D_RENDER].sched);
++ drm_sched_fini(&v3d->queue[V3D_BIN].sched);
++ return ret;
++ }
+
+ return 0;
+ }
+--- a/drivers/gpu/drm/v3d/v3d_trace.h
++++ b/drivers/gpu/drm/v3d/v3d_trace.h
+@@ -42,6 +42,26 @@ TRACE_EVENT(v3d_submit_cl,
+ __entry->ctnqea)
+ );
+
++TRACE_EVENT(v3d_submit_tfu,
++ TP_PROTO(struct drm_device *dev,
++ uint64_t seqno),
++ TP_ARGS(dev, seqno),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ __field(u64, seqno)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ __entry->seqno = seqno;
++ ),
++
++ TP_printk("dev=%u, seqno=%llu",
++ __entry->dev,
++ __entry->seqno)
++);
++
+ TRACE_EVENT(v3d_reset_begin,
+ TP_PROTO(struct drm_device *dev),
+ TP_ARGS(dev),
+--- a/include/uapi/drm/v3d_drm.h
++++ b/include/uapi/drm/v3d_drm.h
+@@ -36,6 +36,7 @@ extern "C" {
+ #define DRM_V3D_MMAP_BO 0x03
+ #define DRM_V3D_GET_PARAM 0x04
+ #define DRM_V3D_GET_BO_OFFSET 0x05
++#define DRM_V3D_SUBMIT_TFU 0x06
+
+ #define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl)
+ #define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo)
+@@ -43,6 +44,7 @@ extern "C" {
+ #define DRM_IOCTL_V3D_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_MMAP_BO, struct drm_v3d_mmap_bo)
+ #define DRM_IOCTL_V3D_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_PARAM, struct drm_v3d_get_param)
+ #define DRM_IOCTL_V3D_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_BO_OFFSET, struct drm_v3d_get_bo_offset)
++#define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu)
+
+ /**
+ * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D
+@@ -169,6 +171,7 @@ enum drm_v3d_param {
+ DRM_V3D_PARAM_V3D_CORE0_IDENT0,
+ DRM_V3D_PARAM_V3D_CORE0_IDENT1,
+ DRM_V3D_PARAM_V3D_CORE0_IDENT2,
++ DRM_V3D_PARAM_SUPPORTS_TFU,
+ };
+
+ struct drm_v3d_get_param {
+@@ -187,6 +190,28 @@ struct drm_v3d_get_bo_offset {
+ __u32 offset;
+ };
+
++struct drm_v3d_submit_tfu {
++ __u32 icfg;
++ __u32 iia;
++ __u32 iis;
++ __u32 ica;
++ __u32 iua;
++ __u32 ioa;
++ __u32 ios;
++ __u32 coef[4];
++ /* First handle is the output BO, following are other inputs.
++ * 0 for unused.
++ */
++ __u32 bo_handles[4];
++ /* sync object to block on before running the TFU job. Each TFU
++ * job will execute in the order submitted to its FD. Synchronization
++ * against rendering jobs requires using sync objects.
++ */
++ __u32 in_sync;
++ /* Sync object to signal when the TFU job is done. */
++ __u32 out_sync;
++};
++
+ #if defined(__cplusplus)
+ }
+ #endif
+++ /dev/null
-From 6351d93a0f1a18c45c4407c472195d957da5d3d0 Mon Sep 17 00:00:00 2001
-Date: Thu, 8 Nov 2018 08:16:52 -0800
-Subject: [PATCH] drm/v3d: Update a comment about what uses
- v3d_job_dependency().
-
-I merged bin and render's paths in a late refactoring.
-
-(cherry picked from commit e90e45f6bd45cc494a6f4cd1853c5e7cd4be7f68)
----
- drivers/gpu/drm/v3d/v3d_sched.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/v3d/v3d_sched.c
-+++ b/drivers/gpu/drm/v3d/v3d_sched.c
-@@ -39,7 +39,7 @@ v3d_job_free(struct drm_sched_job *sched
- }
-
- /**
-- * Returns the fences that the bin job depends on, one by one.
-+ * Returns the fences that the bin or render job depends on, one by one.
- * v3d_job_run() won't be called until all of them have been signaled.
- */
- static struct dma_fence *
+++ /dev/null
-From 5ca5bd799b4f4a065b969461fa7852415bfb8c6f Mon Sep 17 00:00:00 2001
-Date: Thu, 8 Nov 2018 08:16:53 -0800
-Subject: [PATCH] drm/v3d: Clean up the reservation object setup.
-
-The extra to_v3d_bo() calls came from copying this from the vc4
-driver, which stored the cma gem object in the structs.
-
-v2: Fix an unused var warning
-
-(cherry picked from commit 8f1cd826641d677d0f7494253ecfc3335f0bcd4e)
----
- drivers/gpu/drm/v3d/v3d_gem.c | 33 +++++++++++----------------------
- 1 file changed, 11 insertions(+), 22 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -210,14 +210,11 @@ static void
- v3d_attach_object_fences(struct v3d_exec_info *exec)
- {
- struct dma_fence *out_fence = exec->render_done_fence;
-- struct v3d_bo *bo;
- int i;
-
- for (i = 0; i < exec->bo_count; i++) {
-- bo = to_v3d_bo(&exec->bo[i]->base);
--
- /* XXX: Use shared fences for read-only objects. */
-- reservation_object_add_excl_fence(bo->resv, out_fence);
-+ reservation_object_add_excl_fence(exec->bo[i]->resv, out_fence);
- }
- }
-
-@@ -228,11 +225,8 @@ v3d_unlock_bo_reservations(struct drm_de
- {
- int i;
-
-- for (i = 0; i < exec->bo_count; i++) {
-- struct v3d_bo *bo = to_v3d_bo(&exec->bo[i]->base);
--
-- ww_mutex_unlock(&bo->resv->lock);
-- }
-+ for (i = 0; i < exec->bo_count; i++)
-+ ww_mutex_unlock(&exec->bo[i]->resv->lock);
-
- ww_acquire_fini(acquire_ctx);
- }
-@@ -251,13 +245,13 @@ v3d_lock_bo_reservations(struct drm_devi
- {
- int contended_lock = -1;
- int i, ret;
-- struct v3d_bo *bo;
-
- ww_acquire_init(acquire_ctx, &reservation_ww_class);
-
- retry:
- if (contended_lock != -1) {
-- bo = to_v3d_bo(&exec->bo[contended_lock]->base);
-+ struct v3d_bo *bo = exec->bo[contended_lock];
-+
- ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,
- acquire_ctx);
- if (ret) {
-@@ -270,19 +264,16 @@ retry:
- if (i == contended_lock)
- continue;
-
-- bo = to_v3d_bo(&exec->bo[i]->base);
--
-- ret = ww_mutex_lock_interruptible(&bo->resv->lock, acquire_ctx);
-+ ret = ww_mutex_lock_interruptible(&exec->bo[i]->resv->lock,
-+ acquire_ctx);
- if (ret) {
- int j;
-
-- for (j = 0; j < i; j++) {
-- bo = to_v3d_bo(&exec->bo[j]->base);
-- ww_mutex_unlock(&bo->resv->lock);
-- }
-+ for (j = 0; j < i; j++)
-+ ww_mutex_unlock(&exec->bo[j]->resv->lock);
-
- if (contended_lock != -1 && contended_lock >= i) {
-- bo = to_v3d_bo(&exec->bo[contended_lock]->base);
-+ struct v3d_bo *bo = exec->bo[contended_lock];
-
- ww_mutex_unlock(&bo->resv->lock);
- }
-@@ -303,9 +294,7 @@ retry:
- * before we commit the CL to the hardware.
- */
- for (i = 0; i < exec->bo_count; i++) {
-- bo = to_v3d_bo(&exec->bo[i]->base);
--
-- ret = reservation_object_reserve_shared(bo->resv);
-+ ret = reservation_object_reserve_shared(exec->bo[i]->resv);
- if (ret) {
- v3d_unlock_bo_reservations(dev, exec, acquire_ctx);
- return ret;
--- /dev/null
+From c95a4208ef87c56349d35480e68304562c7612bd Mon Sep 17 00:00:00 2001
+Date: Wed, 28 Nov 2018 15:09:26 -0800
+Subject: [PATCH] drm/v3d: Drop the "dev" argument to lock/unlock of BO
+ reservations.
+
+They were unused, as Dave Emett noticed in TFU review.
+
+(cherry picked from commit e14a07fc4b961a75f6c275d6bd670ba54fbdae14)
+---
+ drivers/gpu/drm/v3d/v3d_gem.c | 20 +++++++++-----------
+ 1 file changed, 9 insertions(+), 11 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -219,8 +219,7 @@ v3d_attach_object_fences(struct v3d_bo *
+ }
+
+ static void
+-v3d_unlock_bo_reservations(struct drm_device *dev,
+- struct v3d_bo **bos,
++v3d_unlock_bo_reservations(struct v3d_bo **bos,
+ int bo_count,
+ struct ww_acquire_ctx *acquire_ctx)
+ {
+@@ -240,8 +239,7 @@ v3d_unlock_bo_reservations(struct drm_de
+ * to v3d, so we don't attach dma-buf fences to them.
+ */
+ static int
+-v3d_lock_bo_reservations(struct drm_device *dev,
+- struct v3d_bo **bos,
++v3d_lock_bo_reservations(struct v3d_bo **bos,
+ int bo_count,
+ struct ww_acquire_ctx *acquire_ctx)
+ {
+@@ -298,7 +296,7 @@ retry:
+ for (i = 0; i < bo_count; i++) {
+ ret = reservation_object_reserve_shared(bos[i]->resv);
+ if (ret) {
+- v3d_unlock_bo_reservations(dev, bos, bo_count,
++ v3d_unlock_bo_reservations(bos, bo_count,
+ acquire_ctx);
+ return ret;
+ }
+@@ -566,7 +564,7 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ if (ret)
+ goto fail;
+
+- ret = v3d_lock_bo_reservations(dev, exec->bo, exec->bo_count,
++ ret = v3d_lock_bo_reservations(exec->bo, exec->bo_count,
+ &acquire_ctx);
+ if (ret)
+ goto fail;
+@@ -604,7 +602,7 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ v3d_attach_object_fences(exec->bo, exec->bo_count,
+ exec->render_done_fence);
+
+- v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx);
++ v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx);
+
+ /* Update the return sync object for the */
+ sync_out = drm_syncobj_find(file_priv, args->out_sync);
+@@ -620,7 +618,7 @@ v3d_submit_cl_ioctl(struct drm_device *d
+
+ fail_unreserve:
+ mutex_unlock(&v3d->sched_lock);
+- v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx);
++ v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx);
+ fail:
+ v3d_exec_put(exec);
+
+@@ -691,7 +689,7 @@ v3d_submit_tfu_ioctl(struct drm_device *
+ }
+ spin_unlock(&file_priv->table_lock);
+
+- ret = v3d_lock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
++ ret = v3d_lock_bo_reservations(job->bo, bo_count, &acquire_ctx);
+ if (ret)
+ goto fail;
+
+@@ -710,7 +708,7 @@ v3d_submit_tfu_ioctl(struct drm_device *
+
+ v3d_attach_object_fences(job->bo, bo_count, sched_done_fence);
+
+- v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
++ v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx);
+
+ /* Update the return sync object */
+ sync_out = drm_syncobj_find(file_priv, args->out_sync);
+@@ -726,7 +724,7 @@ v3d_submit_tfu_ioctl(struct drm_device *
+
+ fail_unreserve:
+ mutex_unlock(&v3d->sched_lock);
+- v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
++ v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx);
+ fail:
+ v3d_tfu_job_put(job);
+
--- /dev/null
+From 49281ec9b6f3c7bda94c798133dd35d50eb69649 Mon Sep 17 00:00:00 2001
+Date: Fri, 30 Nov 2018 16:57:59 -0800
+Subject: [PATCH] drm/v3d: Add missing fence timeline name for TFU.
+
+We shouldn't be returning v3d-render for our new queue.
+
+Fixes: 83d5139982db ("drm/v3d: Add support for submitting jobs to the TFU.")
+(cherry picked from commit db176f6ba1da39ad0016c77b9775a6bb3d0ce88a)
+---
+ drivers/gpu/drm/v3d/v3d_fence.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_fence.c
++++ b/drivers/gpu/drm/v3d/v3d_fence.c
+@@ -29,10 +29,16 @@ static const char *v3d_fence_get_timelin
+ {
+ struct v3d_fence *f = to_v3d_fence(fence);
+
+- if (f->queue == V3D_BIN)
++ switch (f->queue) {
++ case V3D_BIN:
+ return "v3d-bin";
+- else
++ case V3D_RENDER:
+ return "v3d-render";
++ case V3D_TFU:
++ return "v3d-tfu";
++ default:
++ return NULL;
++ }
+ }
+
+ const struct dma_fence_ops v3d_fence_ops = {
+++ /dev/null
-From ba1e90b6c3b3bf0e88ab01c824c4f8fde582e878 Mon Sep 17 00:00:00 2001
-Date: Wed, 28 Nov 2018 15:09:25 -0800
-Subject: [PATCH] drm/v3d: Add support for submitting jobs to the TFU.
-
-The TFU can copy from raster, UIF, and SAND input images to UIF output
-images, with optional mipmap generation. This will certainly be
-useful for media EGL image input, but is also useful immediately for
-mipmap generation without bogging the V3D core down.
-
-For now we only run the queue 1 job deep, and don't have any hang
-recovery (though I don't think we should need it, with TFU). Queuing
-multiple jobs in the HW will require synchronizing the YUV coefficient
-regs updates since they don't get FIFOed with the job.
-
-v2: Change the ioctl to IOW instead of IOWR, always set COEF0, explain
- why TFU is AUTH, clarify the syncing docs, drop the unused TFU
- interrupt regs (you're expected to use the hub's), don't take
- &bo->base for NULL bos.
-v3: Fix a little whitespace alignment (noticed by checkpatch), rebase
- on drm_sched_job_cleanup() changes.
-
-Link: https://patchwork.freedesktop.org/patch/264607/
-(cherry picked from commit 1584f16ca96ef124aad79efa3303cff5f3530e2c)
----
- drivers/gpu/drm/v3d/v3d_drv.c | 15 ++-
- drivers/gpu/drm/v3d/v3d_drv.h | 32 +++++-
- drivers/gpu/drm/v3d/v3d_gem.c | 178 ++++++++++++++++++++++++++++----
- drivers/gpu/drm/v3d/v3d_irq.c | 12 ++-
- drivers/gpu/drm/v3d/v3d_regs.h | 49 +++++++++
- drivers/gpu/drm/v3d/v3d_sched.c | 148 ++++++++++++++++++++++----
- drivers/gpu/drm/v3d/v3d_trace.h | 20 ++++
- include/uapi/drm/v3d_drm.h | 25 +++++
- 8 files changed, 426 insertions(+), 53 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -112,10 +112,15 @@ static int v3d_get_param_ioctl(struct dr
- return 0;
- }
-
-- /* Any params that aren't just register reads would go here. */
-
-- DRM_DEBUG("Unknown parameter %d\n", args->param);
-- return -EINVAL;
-+ switch (args->param) {
-+ case DRM_V3D_PARAM_SUPPORTS_TFU:
-+ args->value = 1;
-+ return 0;
-+ default:
-+ DRM_DEBUG("Unknown parameter %d\n", args->param);
-+ return -EINVAL;
-+ }
- }
-
- static int
-@@ -170,7 +175,8 @@ static const struct file_operations v3d_
- /* DRM_AUTH is required on SUBMIT_CL for now, while we don't have GMP
- * protection between clients. Note that render nodes would be be
- * able to submit CLs that could access BOs from clients authenticated
-- * with the master node.
-+ * with the master node. The TFU doesn't use the GMP, so it would
-+ * need to stay DRM_AUTH until we do buffer size/offset validation.
- */
- static const struct drm_ioctl_desc v3d_drm_ioctls[] = {
- DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CL, v3d_submit_cl_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
-@@ -179,6 +185,7 @@ static const struct drm_ioctl_desc v3d_d
- DRM_IOCTL_DEF_DRV(V3D_MMAP_BO, v3d_mmap_bo_ioctl, DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(V3D_GET_PARAM, v3d_get_param_ioctl, DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(V3D_GET_BO_OFFSET, v3d_get_bo_offset_ioctl, DRM_RENDER_ALLOW),
-+ DRM_IOCTL_DEF_DRV(V3D_SUBMIT_TFU, v3d_submit_tfu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
- };
-
- static const struct vm_operations_struct v3d_vm_ops = {
---- a/drivers/gpu/drm/v3d/v3d_drv.h
-+++ b/drivers/gpu/drm/v3d/v3d_drv.h
-@@ -7,19 +7,18 @@
- #include <drm/drm_encoder.h>
- #include <drm/drm_gem.h>
- #include <drm/gpu_scheduler.h>
-+#include "uapi/drm/v3d_drm.h"
-
- #define GMP_GRANULARITY (128 * 1024)
-
--/* Enum for each of the V3D queues. We maintain various queue
-- * tracking as an array because at some point we'll want to support
-- * the TFU (texture formatting unit) as another queue.
-- */
-+/* Enum for each of the V3D queues. */
- enum v3d_queue {
- V3D_BIN,
- V3D_RENDER,
-+ V3D_TFU,
- };
-
--#define V3D_MAX_QUEUES (V3D_RENDER + 1)
-+#define V3D_MAX_QUEUES (V3D_TFU + 1)
-
- struct v3d_queue_state {
- struct drm_gpu_scheduler sched;
-@@ -68,6 +67,7 @@ struct v3d_dev {
-
- struct v3d_exec_info *bin_job;
- struct v3d_exec_info *render_job;
-+ struct v3d_tfu_job *tfu_job;
-
- struct v3d_queue_state queue[V3D_MAX_QUEUES];
-
-@@ -218,6 +218,25 @@ struct v3d_exec_info {
- u32 qma, qms, qts;
- };
-
-+struct v3d_tfu_job {
-+ struct drm_sched_job base;
-+
-+ struct drm_v3d_submit_tfu args;
-+
-+ /* An optional fence userspace can pass in for the job to depend on. */
-+ struct dma_fence *in_fence;
-+
-+ /* v3d fence to be signaled by IRQ handler when the job is complete. */
-+ struct dma_fence *done_fence;
-+
-+ struct v3d_dev *v3d;
-+
-+ struct kref refcount;
-+
-+ /* This is the array of BOs that were looked up at the start of exec. */
-+ struct v3d_bo *bo[4];
-+};
-+
- /**
- * _wait_for - magic (register) wait macro
- *
-@@ -281,9 +300,12 @@ int v3d_gem_init(struct drm_device *dev)
- void v3d_gem_destroy(struct drm_device *dev);
- int v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-+int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv);
- int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
- void v3d_exec_put(struct v3d_exec_info *exec);
-+void v3d_tfu_job_put(struct v3d_tfu_job *exec);
- void v3d_reset(struct v3d_dev *v3d);
- void v3d_invalidate_caches(struct v3d_dev *v3d);
- void v3d_flush_caches(struct v3d_dev *v3d);
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -207,26 +207,27 @@ v3d_flush_caches(struct v3d_dev *v3d)
- }
-
- static void
--v3d_attach_object_fences(struct v3d_exec_info *exec)
-+v3d_attach_object_fences(struct v3d_bo **bos, int bo_count,
-+ struct dma_fence *fence)
- {
-- struct dma_fence *out_fence = exec->render_done_fence;
- int i;
-
-- for (i = 0; i < exec->bo_count; i++) {
-+ for (i = 0; i < bo_count; i++) {
- /* XXX: Use shared fences for read-only objects. */
-- reservation_object_add_excl_fence(exec->bo[i]->resv, out_fence);
-+ reservation_object_add_excl_fence(bos[i]->resv, fence);
- }
- }
-
- static void
- v3d_unlock_bo_reservations(struct drm_device *dev,
-- struct v3d_exec_info *exec,
-+ struct v3d_bo **bos,
-+ int bo_count,
- struct ww_acquire_ctx *acquire_ctx)
- {
- int i;
-
-- for (i = 0; i < exec->bo_count; i++)
-- ww_mutex_unlock(&exec->bo[i]->resv->lock);
-+ for (i = 0; i < bo_count; i++)
-+ ww_mutex_unlock(&bos[i]->resv->lock);
-
- ww_acquire_fini(acquire_ctx);
- }
-@@ -240,7 +241,8 @@ v3d_unlock_bo_reservations(struct drm_de
- */
- static int
- v3d_lock_bo_reservations(struct drm_device *dev,
-- struct v3d_exec_info *exec,
-+ struct v3d_bo **bos,
-+ int bo_count,
- struct ww_acquire_ctx *acquire_ctx)
- {
- int contended_lock = -1;
-@@ -250,7 +252,7 @@ v3d_lock_bo_reservations(struct drm_devi
-
- retry:
- if (contended_lock != -1) {
-- struct v3d_bo *bo = exec->bo[contended_lock];
-+ struct v3d_bo *bo = bos[contended_lock];
-
- ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,
- acquire_ctx);
-@@ -260,20 +262,20 @@ retry:
- }
- }
-
-- for (i = 0; i < exec->bo_count; i++) {
-+ for (i = 0; i < bo_count; i++) {
- if (i == contended_lock)
- continue;
-
-- ret = ww_mutex_lock_interruptible(&exec->bo[i]->resv->lock,
-+ ret = ww_mutex_lock_interruptible(&bos[i]->resv->lock,
- acquire_ctx);
- if (ret) {
- int j;
-
- for (j = 0; j < i; j++)
-- ww_mutex_unlock(&exec->bo[j]->resv->lock);
-+ ww_mutex_unlock(&bos[j]->resv->lock);
-
- if (contended_lock != -1 && contended_lock >= i) {
-- struct v3d_bo *bo = exec->bo[contended_lock];
-+ struct v3d_bo *bo = bos[contended_lock];
-
- ww_mutex_unlock(&bo->resv->lock);
- }
-@@ -293,10 +295,11 @@ retry:
- /* Reserve space for our shared (read-only) fence references,
- * before we commit the CL to the hardware.
- */
-- for (i = 0; i < exec->bo_count; i++) {
-- ret = reservation_object_reserve_shared(exec->bo[i]->resv);
-+ for (i = 0; i < bo_count; i++) {
-+ ret = reservation_object_reserve_shared(bos[i]->resv);
- if (ret) {
-- v3d_unlock_bo_reservations(dev, exec, acquire_ctx);
-+ v3d_unlock_bo_reservations(dev, bos, bo_count,
-+ acquire_ctx);
- return ret;
- }
- }
-@@ -419,6 +422,33 @@ void v3d_exec_put(struct v3d_exec_info *
- kref_put(&exec->refcount, v3d_exec_cleanup);
- }
-
-+static void
-+v3d_tfu_job_cleanup(struct kref *ref)
-+{
-+ struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job,
-+ refcount);
-+ struct v3d_dev *v3d = job->v3d;
-+ unsigned int i;
-+
-+ dma_fence_put(job->in_fence);
-+ dma_fence_put(job->done_fence);
-+
-+ for (i = 0; i < ARRAY_SIZE(job->bo); i++) {
-+ if (job->bo[i])
-+ drm_gem_object_put_unlocked(&job->bo[i]->base);
-+ }
-+
-+ pm_runtime_mark_last_busy(v3d->dev);
-+ pm_runtime_put_autosuspend(v3d->dev);
-+
-+ kfree(job);
-+}
-+
-+void v3d_tfu_job_put(struct v3d_tfu_job *job)
-+{
-+ kref_put(&job->refcount, v3d_tfu_job_cleanup);
-+}
-+
- int
- v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-@@ -536,7 +566,8 @@ v3d_submit_cl_ioctl(struct drm_device *d
- if (ret)
- goto fail;
-
-- ret = v3d_lock_bo_reservations(dev, exec, &acquire_ctx);
-+ ret = v3d_lock_bo_reservations(dev, exec->bo, exec->bo_count,
-+ &acquire_ctx);
- if (ret)
- goto fail;
-
-@@ -570,9 +601,10 @@ v3d_submit_cl_ioctl(struct drm_device *d
- &v3d_priv->sched_entity[V3D_RENDER]);
- mutex_unlock(&v3d->sched_lock);
-
-- v3d_attach_object_fences(exec);
-+ v3d_attach_object_fences(exec->bo, exec->bo_count,
-+ exec->render_done_fence);
-
-- v3d_unlock_bo_reservations(dev, exec, &acquire_ctx);
-+ v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx);
-
- /* Update the return sync object for the */
- sync_out = drm_syncobj_find(file_priv, args->out_sync);
-@@ -588,12 +620,118 @@ v3d_submit_cl_ioctl(struct drm_device *d
-
- fail_unreserve:
- mutex_unlock(&v3d->sched_lock);
-- v3d_unlock_bo_reservations(dev, exec, &acquire_ctx);
-+ v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx);
- fail:
- v3d_exec_put(exec);
-
- return ret;
- }
-+
-+/**
-+ * v3d_submit_tfu_ioctl() - Submits a TFU (texture formatting) job to the V3D.
-+ * @dev: DRM device
-+ * @data: ioctl argument
-+ * @file_priv: DRM file for this fd
-+ *
-+ * Userspace provides the register setup for the TFU, which we don't
-+ * need to validate since the TFU is behind the MMU.
-+ */
-+int
-+v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv)
-+{
-+ struct v3d_dev *v3d = to_v3d_dev(dev);
-+ struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
-+ struct drm_v3d_submit_tfu *args = data;
-+ struct v3d_tfu_job *job;
-+ struct ww_acquire_ctx acquire_ctx;
-+ struct drm_syncobj *sync_out;
-+ struct dma_fence *sched_done_fence;
-+ int ret = 0;
-+ int bo_count;
-+
-+ job = kcalloc(1, sizeof(*job), GFP_KERNEL);
-+ if (!job)
-+ return -ENOMEM;
-+
-+ ret = pm_runtime_get_sync(v3d->dev);
-+ if (ret < 0) {
-+ kfree(job);
-+ return ret;
-+ }
-+
-+ kref_init(&job->refcount);
-+
-+ ret = drm_syncobj_find_fence(file_priv, args->in_sync,
-+ 0, &job->in_fence);
-+ if (ret == -EINVAL)
-+ goto fail;
-+
-+ job->args = *args;
-+ job->v3d = v3d;
-+
-+ spin_lock(&file_priv->table_lock);
-+ for (bo_count = 0; bo_count < ARRAY_SIZE(job->bo); bo_count++) {
-+ struct drm_gem_object *bo;
-+
-+ if (!args->bo_handles[bo_count])
-+ break;
-+
-+ bo = idr_find(&file_priv->object_idr,
-+ args->bo_handles[bo_count]);
-+ if (!bo) {
-+ DRM_DEBUG("Failed to look up GEM BO %d: %d\n",
-+ bo_count, args->bo_handles[bo_count]);
-+ ret = -ENOENT;
-+ spin_unlock(&file_priv->table_lock);
-+ goto fail;
-+ }
-+ drm_gem_object_get(bo);
-+ job->bo[bo_count] = to_v3d_bo(bo);
-+ }
-+ spin_unlock(&file_priv->table_lock);
-+
-+ ret = v3d_lock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
-+ if (ret)
-+ goto fail;
-+
-+ mutex_lock(&v3d->sched_lock);
-+ ret = drm_sched_job_init(&job->base,
-+ &v3d_priv->sched_entity[V3D_TFU],
-+ v3d_priv);
-+ if (ret)
-+ goto fail_unreserve;
-+
-+ sched_done_fence = dma_fence_get(&job->base.s_fence->finished);
-+
-+ kref_get(&job->refcount); /* put by scheduler job completion */
-+ drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[V3D_TFU]);
-+ mutex_unlock(&v3d->sched_lock);
-+
-+ v3d_attach_object_fences(job->bo, bo_count, sched_done_fence);
-+
-+ v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
-+
-+ /* Update the return sync object */
-+ sync_out = drm_syncobj_find(file_priv, args->out_sync);
-+ if (sync_out) {
-+ drm_syncobj_replace_fence(sync_out, sched_done_fence);
-+ drm_syncobj_put(sync_out);
-+ }
-+ dma_fence_put(sched_done_fence);
-+
-+ v3d_tfu_job_put(job);
-+
-+ return 0;
-+
-+fail_unreserve:
-+ mutex_unlock(&v3d->sched_lock);
-+ v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
-+fail:
-+ v3d_tfu_job_put(job);
-+
-+ return ret;
-+}
-
- int
- v3d_gem_init(struct drm_device *dev)
---- a/drivers/gpu/drm/v3d/v3d_irq.c
-+++ b/drivers/gpu/drm/v3d/v3d_irq.c
-@@ -4,8 +4,8 @@
- /**
- * DOC: Interrupt management for the V3D engine
- *
-- * When we take a binning or rendering flush done interrupt, we need
-- * to signal the fence for that job so that the scheduler can queue up
-+ * When we take a bin, render, or TFU done interrupt, we need to
-+ * signal the fence for that job so that the scheduler can queue up
- * the next one and unblock any waiters.
- *
- * When we take the binner out of memory interrupt, we need to
-@@ -23,7 +23,8 @@
-
- #define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \
- V3D_HUB_INT_MMU_PTI | \
-- V3D_HUB_INT_MMU_CAP))
-+ V3D_HUB_INT_MMU_CAP | \
-+ V3D_HUB_INT_TFUC))
-
- static void
- v3d_overflow_mem_work(struct work_struct *work)
-@@ -117,6 +118,11 @@ v3d_hub_irq(int irq, void *arg)
- /* Acknowledge the interrupts we're handling here. */
- V3D_WRITE(V3D_HUB_INT_CLR, intsts);
-
-+ if (intsts & V3D_HUB_INT_TFUC) {
-+ dma_fence_signal(v3d->tfu_job->done_fence);
-+ status = IRQ_HANDLED;
-+ }
-+
- if (intsts & (V3D_HUB_INT_MMU_WRV |
- V3D_HUB_INT_MMU_PTI |
- V3D_HUB_INT_MMU_CAP)) {
---- a/drivers/gpu/drm/v3d/v3d_regs.h
-+++ b/drivers/gpu/drm/v3d/v3d_regs.h
-@@ -86,6 +86,55 @@
- # define V3D_TOP_GR_BRIDGE_SW_INIT_1 0x0000c
- # define V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT BIT(0)
-
-+#define V3D_TFU_CS 0x00400
-+/* Stops current job, empties input fifo. */
-+# define V3D_TFU_CS_TFURST BIT(31)
-+# define V3D_TFU_CS_CVTCT_MASK V3D_MASK(23, 16)
-+# define V3D_TFU_CS_CVTCT_SHIFT 16
-+# define V3D_TFU_CS_NFREE_MASK V3D_MASK(13, 8)
-+# define V3D_TFU_CS_NFREE_SHIFT 8
-+# define V3D_TFU_CS_BUSY BIT(0)
-+
-+#define V3D_TFU_SU 0x00404
-+/* Interrupt when FINTTHR input slots are free (0 = disabled) */
-+# define V3D_TFU_SU_FINTTHR_MASK V3D_MASK(13, 8)
-+# define V3D_TFU_SU_FINTTHR_SHIFT 8
-+/* Skips resetting the CRC at the start of CRC generation. */
-+# define V3D_TFU_SU_CRCCHAIN BIT(4)
-+/* skips writes, computes CRC of the image. miplevels must be 0. */
-+# define V3D_TFU_SU_CRC BIT(3)
-+# define V3D_TFU_SU_THROTTLE_MASK V3D_MASK(1, 0)
-+# define V3D_TFU_SU_THROTTLE_SHIFT 0
-+
-+#define V3D_TFU_ICFG 0x00408
-+/* Interrupt when the conversion is complete. */
-+# define V3D_TFU_ICFG_IOC BIT(0)
-+
-+/* Input Image Address */
-+#define V3D_TFU_IIA 0x0040c
-+/* Input Chroma Address */
-+#define V3D_TFU_ICA 0x00410
-+/* Input Image Stride */
-+#define V3D_TFU_IIS 0x00414
-+/* Input Image U-Plane Address */
-+#define V3D_TFU_IUA 0x00418
-+/* Output Image Address */
-+#define V3D_TFU_IOA 0x0041c
-+/* Image Output Size */
-+#define V3D_TFU_IOS 0x00420
-+/* TFU YUV Coefficient 0 */
-+#define V3D_TFU_COEF0 0x00424
-+/* Use these regs instead of the defaults. */
-+# define V3D_TFU_COEF0_USECOEF BIT(31)
-+/* TFU YUV Coefficient 1 */
-+#define V3D_TFU_COEF1 0x00428
-+/* TFU YUV Coefficient 2 */
-+#define V3D_TFU_COEF2 0x0042c
-+/* TFU YUV Coefficient 3 */
-+#define V3D_TFU_COEF3 0x00430
-+
-+#define V3D_TFU_CRC 0x00434
-+
- /* Per-MMU registers. */
-
- #define V3D_MMUC_CONTROL 0x01000
---- a/drivers/gpu/drm/v3d/v3d_sched.c
-+++ b/drivers/gpu/drm/v3d/v3d_sched.c
-@@ -30,6 +30,12 @@ to_v3d_job(struct drm_sched_job *sched_j
- return container_of(sched_job, struct v3d_job, base);
- }
-
-+static struct v3d_tfu_job *
-+to_tfu_job(struct drm_sched_job *sched_job)
-+{
-+ return container_of(sched_job, struct v3d_tfu_job, base);
-+}
-+
- static void
- v3d_job_free(struct drm_sched_job *sched_job)
- {
-@@ -38,6 +44,14 @@ v3d_job_free(struct drm_sched_job *sched
- v3d_exec_put(job->exec);
- }
-
-+static void
-+v3d_tfu_job_free(struct drm_sched_job *sched_job)
-+{
-+ struct v3d_tfu_job *job = to_tfu_job(sched_job);
-+
-+ v3d_tfu_job_put(job);
-+}
-+
- /**
- * Returns the fences that the bin or render job depends on, one by one.
- * v3d_job_run() won't be called until all of them have been signaled.
-@@ -76,6 +90,27 @@ v3d_job_dependency(struct drm_sched_job
- return fence;
- }
-
-+/**
-+ * Returns the fences that the TFU job depends on, one by one.
-+ * v3d_tfu_job_run() won't be called until all of them have been
-+ * signaled.
-+ */
-+static struct dma_fence *
-+v3d_tfu_job_dependency(struct drm_sched_job *sched_job,
-+ struct drm_sched_entity *s_entity)
-+{
-+ struct v3d_tfu_job *job = to_tfu_job(sched_job);
-+ struct dma_fence *fence;
-+
-+ fence = job->in_fence;
-+ if (fence) {
-+ job->in_fence = NULL;
-+ return fence;
-+ }
-+
-+ return NULL;
-+}
-+
- static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job)
- {
- struct v3d_job *job = to_v3d_job(sched_job);
-@@ -147,31 +182,47 @@ static struct dma_fence *v3d_job_run(str
- return fence;
- }
-
--static void
--v3d_job_timedout(struct drm_sched_job *sched_job)
-+static struct dma_fence *
-+v3d_tfu_job_run(struct drm_sched_job *sched_job)
- {
-- struct v3d_job *job = to_v3d_job(sched_job);
-- struct v3d_exec_info *exec = job->exec;
-- struct v3d_dev *v3d = exec->v3d;
-- enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
-- enum v3d_queue q;
-- u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q));
-- u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q));
-+ struct v3d_tfu_job *job = to_tfu_job(sched_job);
-+ struct v3d_dev *v3d = job->v3d;
-+ struct drm_device *dev = &v3d->drm;
-+ struct dma_fence *fence;
-
-- /* If the current address or return address have changed, then
-- * the GPU has probably made progress and we should delay the
-- * reset. This could fail if the GPU got in an infinite loop
-- * in the CL, but that is pretty unlikely outside of an i-g-t
-- * testcase.
-- */
-- if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) {
-- job->timedout_ctca = ctca;
-- job->timedout_ctra = ctra;
-+ fence = v3d_fence_create(v3d, V3D_TFU);
-+ if (IS_ERR(fence))
-+ return NULL;
-
-- schedule_delayed_work(&job->base.work_tdr,
-- job->base.sched->timeout);
-- return;
-+ v3d->tfu_job = job;
-+ if (job->done_fence)
-+ dma_fence_put(job->done_fence);
-+ job->done_fence = dma_fence_get(fence);
-+
-+ trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);
-+
-+ V3D_WRITE(V3D_TFU_IIA, job->args.iia);
-+ V3D_WRITE(V3D_TFU_IIS, job->args.iis);
-+ V3D_WRITE(V3D_TFU_ICA, job->args.ica);
-+ V3D_WRITE(V3D_TFU_IUA, job->args.iua);
-+ V3D_WRITE(V3D_TFU_IOA, job->args.ioa);
-+ V3D_WRITE(V3D_TFU_IOS, job->args.ios);
-+ V3D_WRITE(V3D_TFU_COEF0, job->args.coef[0]);
-+ if (job->args.coef[0] & V3D_TFU_COEF0_USECOEF) {
-+ V3D_WRITE(V3D_TFU_COEF1, job->args.coef[1]);
-+ V3D_WRITE(V3D_TFU_COEF2, job->args.coef[2]);
-+ V3D_WRITE(V3D_TFU_COEF3, job->args.coef[3]);
- }
-+ /* ICFG kicks off the job. */
-+ V3D_WRITE(V3D_TFU_ICFG, job->args.icfg | V3D_TFU_ICFG_IOC);
-+
-+ return fence;
-+}
-+
-+static void
-+v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job)
-+{
-+ enum v3d_queue q;
-
- mutex_lock(&v3d->reset_lock);
-
-@@ -196,6 +247,41 @@ v3d_job_timedout(struct drm_sched_job *s
- mutex_unlock(&v3d->reset_lock);
- }
-
-+static void
-+v3d_job_timedout(struct drm_sched_job *sched_job)
-+{
-+ struct v3d_job *job = to_v3d_job(sched_job);
-+ struct v3d_exec_info *exec = job->exec;
-+ struct v3d_dev *v3d = exec->v3d;
-+ enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
-+ u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q));
-+ u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q));
-+
-+ /* If the current address or return address have changed, then
-+ * the GPU has probably made progress and we should delay the
-+ * reset. This could fail if the GPU got in an infinite loop
-+ * in the CL, but that is pretty unlikely outside of an i-g-t
-+ * testcase.
-+ */
-+ if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) {
-+ job->timedout_ctca = ctca;
-+ job->timedout_ctra = ctra;
-+ schedule_delayed_work(&job->base.work_tdr,
-+ job->base.sched->timeout);
-+ return;
-+ }
-+
-+ v3d_gpu_reset_for_timeout(v3d, sched_job);
-+}
-+
-+static void
-+v3d_tfu_job_timedout(struct drm_sched_job *sched_job)
-+{
-+ struct v3d_tfu_job *job = to_tfu_job(sched_job);
-+
-+ v3d_gpu_reset_for_timeout(job->v3d, sched_job);
-+}
-+
- static const struct drm_sched_backend_ops v3d_sched_ops = {
- .dependency = v3d_job_dependency,
- .run_job = v3d_job_run,
-@@ -203,6 +289,13 @@ static const struct drm_sched_backend_op
- .free_job = v3d_job_free
- };
-
-+static const struct drm_sched_backend_ops v3d_tfu_sched_ops = {
-+ .dependency = v3d_tfu_job_dependency,
-+ .run_job = v3d_tfu_job_run,
-+ .timedout_job = v3d_tfu_job_timedout,
-+ .free_job = v3d_tfu_job_free
-+};
-+
- int
- v3d_sched_init(struct v3d_dev *v3d)
- {
-@@ -232,6 +325,19 @@ v3d_sched_init(struct v3d_dev *v3d)
- drm_sched_fini(&v3d->queue[V3D_BIN].sched);
- return ret;
- }
-+
-+ ret = drm_sched_init(&v3d->queue[V3D_TFU].sched,
-+ &v3d_tfu_sched_ops,
-+ hw_jobs_limit, job_hang_limit,
-+ msecs_to_jiffies(hang_limit_ms),
-+ "v3d_tfu");
-+ if (ret) {
-+ dev_err(v3d->dev, "Failed to create TFU scheduler: %d.",
-+ ret);
-+ drm_sched_fini(&v3d->queue[V3D_RENDER].sched);
-+ drm_sched_fini(&v3d->queue[V3D_BIN].sched);
-+ return ret;
-+ }
-
- return 0;
- }
---- a/drivers/gpu/drm/v3d/v3d_trace.h
-+++ b/drivers/gpu/drm/v3d/v3d_trace.h
-@@ -42,6 +42,26 @@ TRACE_EVENT(v3d_submit_cl,
- __entry->ctnqea)
- );
-
-+TRACE_EVENT(v3d_submit_tfu,
-+ TP_PROTO(struct drm_device *dev,
-+ uint64_t seqno),
-+ TP_ARGS(dev, seqno),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ __field(u64, seqno)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ __entry->seqno = seqno;
-+ ),
-+
-+ TP_printk("dev=%u, seqno=%llu",
-+ __entry->dev,
-+ __entry->seqno)
-+);
-+
- TRACE_EVENT(v3d_reset_begin,
- TP_PROTO(struct drm_device *dev),
- TP_ARGS(dev),
---- a/include/uapi/drm/v3d_drm.h
-+++ b/include/uapi/drm/v3d_drm.h
-@@ -36,6 +36,7 @@ extern "C" {
- #define DRM_V3D_MMAP_BO 0x03
- #define DRM_V3D_GET_PARAM 0x04
- #define DRM_V3D_GET_BO_OFFSET 0x05
-+#define DRM_V3D_SUBMIT_TFU 0x06
-
- #define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl)
- #define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo)
-@@ -43,6 +44,7 @@ extern "C" {
- #define DRM_IOCTL_V3D_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_MMAP_BO, struct drm_v3d_mmap_bo)
- #define DRM_IOCTL_V3D_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_PARAM, struct drm_v3d_get_param)
- #define DRM_IOCTL_V3D_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_BO_OFFSET, struct drm_v3d_get_bo_offset)
-+#define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu)
-
- /**
- * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D
-@@ -169,6 +171,7 @@ enum drm_v3d_param {
- DRM_V3D_PARAM_V3D_CORE0_IDENT0,
- DRM_V3D_PARAM_V3D_CORE0_IDENT1,
- DRM_V3D_PARAM_V3D_CORE0_IDENT2,
-+ DRM_V3D_PARAM_SUPPORTS_TFU,
- };
-
- struct drm_v3d_get_param {
-@@ -187,6 +190,28 @@ struct drm_v3d_get_bo_offset {
- __u32 offset;
- };
-
-+struct drm_v3d_submit_tfu {
-+ __u32 icfg;
-+ __u32 iia;
-+ __u32 iis;
-+ __u32 ica;
-+ __u32 iua;
-+ __u32 ioa;
-+ __u32 ios;
-+ __u32 coef[4];
-+ /* First handle is the output BO, following are other inputs.
-+ * 0 for unused.
-+ */
-+ __u32 bo_handles[4];
-+ /* sync object to block on before running the TFU job. Each TFU
-+ * job will execute in the order submitted to its FD. Synchronization
-+ * against rendering jobs requires using sync objects.
-+ */
-+ __u32 in_sync;
-+ /* Sync object to signal when the TFU job is done. */
-+ __u32 out_sync;
-+};
-+
- #if defined(__cplusplus)
- }
- #endif
--- /dev/null
+From 128adbc39c9826ca137ca3627cff17644e786fdb Mon Sep 17 00:00:00 2001
+Date: Fri, 30 Nov 2018 16:57:58 -0800
+Subject: [PATCH] drm/v3d: Add more tracepoints for V3D GPU rendering.
+
+The core scheduler tells us when the job is pushed to the scheduler's
+queue, and I had the job_run functions saying when they actually queue
+the job to the hardware. By adding tracepoints for the very top of
+the ioctls and the IRQs signaling job completion, "perf record -a -e
+v3d:.\* -e gpu_scheduler:.\* <job>; perf script" gets you a pretty
+decent timeline.
+
+(cherry picked from commit 55a9b74846ed5e6219c7d81a8e1bf96f25d8ad5e)
+---
+ drivers/gpu/drm/v3d/v3d_gem.c | 4 ++
+ drivers/gpu/drm/v3d/v3d_irq.c | 19 +++++-
+ drivers/gpu/drm/v3d/v3d_trace.h | 101 ++++++++++++++++++++++++++++++++
+ 3 files changed, 121 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -521,6 +521,8 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ struct drm_syncobj *sync_out;
+ int ret = 0;
+
++ trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end);
++
+ if (args->pad != 0) {
+ DRM_INFO("pad must be zero: %d\n", args->pad);
+ return -EINVAL;
+@@ -648,6 +650,8 @@ v3d_submit_tfu_ioctl(struct drm_device *
+ int ret = 0;
+ int bo_count;
+
++ trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia);
++
+ job = kcalloc(1, sizeof(*job), GFP_KERNEL);
+ if (!job)
+ return -ENOMEM;
+--- a/drivers/gpu/drm/v3d/v3d_irq.c
++++ b/drivers/gpu/drm/v3d/v3d_irq.c
+@@ -15,6 +15,7 @@
+
+ #include "v3d_drv.h"
+ #include "v3d_regs.h"
++#include "v3d_trace.h"
+
+ #define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \
+ V3D_INT_FLDONE | \
+@@ -88,12 +89,20 @@ v3d_irq(int irq, void *arg)
+ }
+
+ if (intsts & V3D_INT_FLDONE) {
+- dma_fence_signal(v3d->bin_job->bin.done_fence);
++ struct v3d_fence *fence =
++ to_v3d_fence(v3d->bin_job->bin.done_fence);
++
++ trace_v3d_bcl_irq(&v3d->drm, fence->seqno);
++ dma_fence_signal(&fence->base);
+ status = IRQ_HANDLED;
+ }
+
+ if (intsts & V3D_INT_FRDONE) {
+- dma_fence_signal(v3d->render_job->render.done_fence);
++ struct v3d_fence *fence =
++ to_v3d_fence(v3d->render_job->render.done_fence);
++
++ trace_v3d_rcl_irq(&v3d->drm, fence->seqno);
++ dma_fence_signal(&fence->base);
+ status = IRQ_HANDLED;
+ }
+
+@@ -119,7 +128,11 @@ v3d_hub_irq(int irq, void *arg)
+ V3D_WRITE(V3D_HUB_INT_CLR, intsts);
+
+ if (intsts & V3D_HUB_INT_TFUC) {
+- dma_fence_signal(v3d->tfu_job->done_fence);
++ struct v3d_fence *fence =
++ to_v3d_fence(v3d->tfu_job->done_fence);
++
++ trace_v3d_tfu_irq(&v3d->drm, fence->seqno);
++ dma_fence_signal(&fence->base);
+ status = IRQ_HANDLED;
+ }
+
+--- a/drivers/gpu/drm/v3d/v3d_trace.h
++++ b/drivers/gpu/drm/v3d/v3d_trace.h
+@@ -12,6 +12,28 @@
+ #define TRACE_SYSTEM v3d
+ #define TRACE_INCLUDE_FILE v3d_trace
+
++TRACE_EVENT(v3d_submit_cl_ioctl,
++ TP_PROTO(struct drm_device *dev, u32 ct1qba, u32 ct1qea),
++ TP_ARGS(dev, ct1qba, ct1qea),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ __field(u32, ct1qba)
++ __field(u32, ct1qea)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ __entry->ct1qba = ct1qba;
++ __entry->ct1qea = ct1qea;
++ ),
++
++ TP_printk("dev=%u, RCL 0x%08x..0x%08x",
++ __entry->dev,
++ __entry->ct1qba,
++ __entry->ct1qea)
++);
++
+ TRACE_EVENT(v3d_submit_cl,
+ TP_PROTO(struct drm_device *dev, bool is_render,
+ uint64_t seqno,
+@@ -42,6 +64,85 @@ TRACE_EVENT(v3d_submit_cl,
+ __entry->ctnqea)
+ );
+
++TRACE_EVENT(v3d_bcl_irq,
++ TP_PROTO(struct drm_device *dev,
++ uint64_t seqno),
++ TP_ARGS(dev, seqno),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ __field(u64, seqno)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ __entry->seqno = seqno;
++ ),
++
++ TP_printk("dev=%u, seqno=%llu",
++ __entry->dev,
++ __entry->seqno)
++);
++
++TRACE_EVENT(v3d_rcl_irq,
++ TP_PROTO(struct drm_device *dev,
++ uint64_t seqno),
++ TP_ARGS(dev, seqno),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ __field(u64, seqno)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ __entry->seqno = seqno;
++ ),
++
++ TP_printk("dev=%u, seqno=%llu",
++ __entry->dev,
++ __entry->seqno)
++);
++
++TRACE_EVENT(v3d_tfu_irq,
++ TP_PROTO(struct drm_device *dev,
++ uint64_t seqno),
++ TP_ARGS(dev, seqno),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ __field(u64, seqno)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ __entry->seqno = seqno;
++ ),
++
++ TP_printk("dev=%u, seqno=%llu",
++ __entry->dev,
++ __entry->seqno)
++);
++
++TRACE_EVENT(v3d_submit_tfu_ioctl,
++ TP_PROTO(struct drm_device *dev, u32 iia),
++ TP_ARGS(dev, iia),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ __field(u32, iia)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ __entry->iia = iia;
++ ),
++
++ TP_printk("dev=%u, IIA 0x%08x",
++ __entry->dev,
++ __entry->iia)
++);
++
+ TRACE_EVENT(v3d_submit_tfu,
+ TP_PROTO(struct drm_device *dev,
+ uint64_t seqno),
+++ /dev/null
-From c95a4208ef87c56349d35480e68304562c7612bd Mon Sep 17 00:00:00 2001
-Date: Wed, 28 Nov 2018 15:09:26 -0800
-Subject: [PATCH] drm/v3d: Drop the "dev" argument to lock/unlock of BO
- reservations.
-
-They were unused, as Dave Emett noticed in TFU review.
-
-(cherry picked from commit e14a07fc4b961a75f6c275d6bd670ba54fbdae14)
----
- drivers/gpu/drm/v3d/v3d_gem.c | 20 +++++++++-----------
- 1 file changed, 9 insertions(+), 11 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -219,8 +219,7 @@ v3d_attach_object_fences(struct v3d_bo *
- }
-
- static void
--v3d_unlock_bo_reservations(struct drm_device *dev,
-- struct v3d_bo **bos,
-+v3d_unlock_bo_reservations(struct v3d_bo **bos,
- int bo_count,
- struct ww_acquire_ctx *acquire_ctx)
- {
-@@ -240,8 +239,7 @@ v3d_unlock_bo_reservations(struct drm_de
- * to v3d, so we don't attach dma-buf fences to them.
- */
- static int
--v3d_lock_bo_reservations(struct drm_device *dev,
-- struct v3d_bo **bos,
-+v3d_lock_bo_reservations(struct v3d_bo **bos,
- int bo_count,
- struct ww_acquire_ctx *acquire_ctx)
- {
-@@ -298,7 +296,7 @@ retry:
- for (i = 0; i < bo_count; i++) {
- ret = reservation_object_reserve_shared(bos[i]->resv);
- if (ret) {
-- v3d_unlock_bo_reservations(dev, bos, bo_count,
-+ v3d_unlock_bo_reservations(bos, bo_count,
- acquire_ctx);
- return ret;
- }
-@@ -566,7 +564,7 @@ v3d_submit_cl_ioctl(struct drm_device *d
- if (ret)
- goto fail;
-
-- ret = v3d_lock_bo_reservations(dev, exec->bo, exec->bo_count,
-+ ret = v3d_lock_bo_reservations(exec->bo, exec->bo_count,
- &acquire_ctx);
- if (ret)
- goto fail;
-@@ -604,7 +602,7 @@ v3d_submit_cl_ioctl(struct drm_device *d
- v3d_attach_object_fences(exec->bo, exec->bo_count,
- exec->render_done_fence);
-
-- v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx);
-+ v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx);
-
- /* Update the return sync object for the */
- sync_out = drm_syncobj_find(file_priv, args->out_sync);
-@@ -620,7 +618,7 @@ v3d_submit_cl_ioctl(struct drm_device *d
-
- fail_unreserve:
- mutex_unlock(&v3d->sched_lock);
-- v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx);
-+ v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx);
- fail:
- v3d_exec_put(exec);
-
-@@ -691,7 +689,7 @@ v3d_submit_tfu_ioctl(struct drm_device *
- }
- spin_unlock(&file_priv->table_lock);
-
-- ret = v3d_lock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
-+ ret = v3d_lock_bo_reservations(job->bo, bo_count, &acquire_ctx);
- if (ret)
- goto fail;
-
-@@ -710,7 +708,7 @@ v3d_submit_tfu_ioctl(struct drm_device *
-
- v3d_attach_object_fences(job->bo, bo_count, sched_done_fence);
-
-- v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
-+ v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx);
-
- /* Update the return sync object */
- sync_out = drm_syncobj_find(file_priv, args->out_sync);
-@@ -726,7 +724,7 @@ v3d_submit_tfu_ioctl(struct drm_device *
-
- fail_unreserve:
- mutex_unlock(&v3d->sched_lock);
-- v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
-+ v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx);
- fail:
- v3d_tfu_job_put(job);
-
+++ /dev/null
-From 49281ec9b6f3c7bda94c798133dd35d50eb69649 Mon Sep 17 00:00:00 2001
-Date: Fri, 30 Nov 2018 16:57:59 -0800
-Subject: [PATCH] drm/v3d: Add missing fence timeline name for TFU.
-
-We shouldn't be returning v3d-render for our new queue.
-
-Fixes: 83d5139982db ("drm/v3d: Add support for submitting jobs to the TFU.")
-(cherry picked from commit db176f6ba1da39ad0016c77b9775a6bb3d0ce88a)
----
- drivers/gpu/drm/v3d/v3d_fence.c | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_fence.c
-+++ b/drivers/gpu/drm/v3d/v3d_fence.c
-@@ -29,10 +29,16 @@ static const char *v3d_fence_get_timelin
- {
- struct v3d_fence *f = to_v3d_fence(fence);
-
-- if (f->queue == V3D_BIN)
-+ switch (f->queue) {
-+ case V3D_BIN:
- return "v3d-bin";
-- else
-+ case V3D_RENDER:
- return "v3d-render";
-+ case V3D_TFU:
-+ return "v3d-tfu";
-+ default:
-+ return NULL;
-+ }
- }
-
- const struct dma_fence_ops v3d_fence_ops = {
--- /dev/null
+From 065c8947cb7c40bfb3e76dcbb9d901b5e8fe0ea4 Mon Sep 17 00:00:00 2001
+Date: Mon, 3 Dec 2018 14:24:34 -0800
+Subject: [PATCH] drm/v3d: Drop unused v3d_flush_caches().
+
+Now that I've specified how the end-of-pipeline flushing should work,
+we're never going to use this function.
+
+(cherry picked from commit 2aa34fd5c7754824cf5488b61ac644f30d3c5c85)
+---
+ drivers/gpu/drm/v3d/v3d_drv.h | 1 -
+ drivers/gpu/drm/v3d/v3d_gem.c | 21 ---------------------
+ 2 files changed, 22 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.h
++++ b/drivers/gpu/drm/v3d/v3d_drv.h
+@@ -308,7 +308,6 @@ void v3d_exec_put(struct v3d_exec_info *
+ void v3d_tfu_job_put(struct v3d_tfu_job *exec);
+ void v3d_reset(struct v3d_dev *v3d);
+ void v3d_invalidate_caches(struct v3d_dev *v3d);
+-void v3d_flush_caches(struct v3d_dev *v3d);
+
+ /* v3d_irq.c */
+ int v3d_irq_init(struct v3d_dev *v3d);
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -175,20 +175,6 @@ v3d_invalidate_slices(struct v3d_dev *v3
+ V3D_SET_FIELD(0xf, V3D_SLCACTL_ICC));
+ }
+
+-/* Invalidates texture L2 cachelines */
+-static void
+-v3d_invalidate_l2t(struct v3d_dev *v3d, int core)
+-{
+- V3D_CORE_WRITE(core,
+- V3D_CTL_L2TCACTL,
+- V3D_L2TCACTL_L2TFLS |
+- V3D_SET_FIELD(V3D_L2TCACTL_FLM_CLEAR, V3D_L2TCACTL_FLM));
+- if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
+- V3D_L2TCACTL_L2TFLS), 100)) {
+- DRM_ERROR("Timeout waiting for L2T invalidate\n");
+- }
+-}
+-
+ void
+ v3d_invalidate_caches(struct v3d_dev *v3d)
+ {
+@@ -199,13 +185,6 @@ v3d_invalidate_caches(struct v3d_dev *v3
+ v3d_flush_l2t(v3d, 0);
+ }
+
+-void
+-v3d_flush_caches(struct v3d_dev *v3d)
+-{
+- v3d_invalidate_l1td(v3d, 0);
+- v3d_invalidate_l2t(v3d, 0);
+-}
+-
+ static void
+ v3d_attach_object_fences(struct v3d_bo **bos, int bo_count,
+ struct dma_fence *fence)
+++ /dev/null
-From 128adbc39c9826ca137ca3627cff17644e786fdb Mon Sep 17 00:00:00 2001
-Date: Fri, 30 Nov 2018 16:57:58 -0800
-Subject: [PATCH] drm/v3d: Add more tracepoints for V3D GPU rendering.
-
-The core scheduler tells us when the job is pushed to the scheduler's
-queue, and I had the job_run functions saying when they actually queue
-the job to the hardware. By adding tracepoints for the very top of
-the ioctls and the IRQs signaling job completion, "perf record -a -e
-v3d:.\* -e gpu_scheduler:.\* <job>; perf script" gets you a pretty
-decent timeline.
-
-(cherry picked from commit 55a9b74846ed5e6219c7d81a8e1bf96f25d8ad5e)
----
- drivers/gpu/drm/v3d/v3d_gem.c | 4 ++
- drivers/gpu/drm/v3d/v3d_irq.c | 19 +++++-
- drivers/gpu/drm/v3d/v3d_trace.h | 101 ++++++++++++++++++++++++++++++++
- 3 files changed, 121 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -521,6 +521,8 @@ v3d_submit_cl_ioctl(struct drm_device *d
- struct drm_syncobj *sync_out;
- int ret = 0;
-
-+ trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end);
-+
- if (args->pad != 0) {
- DRM_INFO("pad must be zero: %d\n", args->pad);
- return -EINVAL;
-@@ -648,6 +650,8 @@ v3d_submit_tfu_ioctl(struct drm_device *
- int ret = 0;
- int bo_count;
-
-+ trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia);
-+
- job = kcalloc(1, sizeof(*job), GFP_KERNEL);
- if (!job)
- return -ENOMEM;
---- a/drivers/gpu/drm/v3d/v3d_irq.c
-+++ b/drivers/gpu/drm/v3d/v3d_irq.c
-@@ -15,6 +15,7 @@
-
- #include "v3d_drv.h"
- #include "v3d_regs.h"
-+#include "v3d_trace.h"
-
- #define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \
- V3D_INT_FLDONE | \
-@@ -88,12 +89,20 @@ v3d_irq(int irq, void *arg)
- }
-
- if (intsts & V3D_INT_FLDONE) {
-- dma_fence_signal(v3d->bin_job->bin.done_fence);
-+ struct v3d_fence *fence =
-+ to_v3d_fence(v3d->bin_job->bin.done_fence);
-+
-+ trace_v3d_bcl_irq(&v3d->drm, fence->seqno);
-+ dma_fence_signal(&fence->base);
- status = IRQ_HANDLED;
- }
-
- if (intsts & V3D_INT_FRDONE) {
-- dma_fence_signal(v3d->render_job->render.done_fence);
-+ struct v3d_fence *fence =
-+ to_v3d_fence(v3d->render_job->render.done_fence);
-+
-+ trace_v3d_rcl_irq(&v3d->drm, fence->seqno);
-+ dma_fence_signal(&fence->base);
- status = IRQ_HANDLED;
- }
-
-@@ -119,7 +128,11 @@ v3d_hub_irq(int irq, void *arg)
- V3D_WRITE(V3D_HUB_INT_CLR, intsts);
-
- if (intsts & V3D_HUB_INT_TFUC) {
-- dma_fence_signal(v3d->tfu_job->done_fence);
-+ struct v3d_fence *fence =
-+ to_v3d_fence(v3d->tfu_job->done_fence);
-+
-+ trace_v3d_tfu_irq(&v3d->drm, fence->seqno);
-+ dma_fence_signal(&fence->base);
- status = IRQ_HANDLED;
- }
-
---- a/drivers/gpu/drm/v3d/v3d_trace.h
-+++ b/drivers/gpu/drm/v3d/v3d_trace.h
-@@ -12,6 +12,28 @@
- #define TRACE_SYSTEM v3d
- #define TRACE_INCLUDE_FILE v3d_trace
-
-+TRACE_EVENT(v3d_submit_cl_ioctl,
-+ TP_PROTO(struct drm_device *dev, u32 ct1qba, u32 ct1qea),
-+ TP_ARGS(dev, ct1qba, ct1qea),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ __field(u32, ct1qba)
-+ __field(u32, ct1qea)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ __entry->ct1qba = ct1qba;
-+ __entry->ct1qea = ct1qea;
-+ ),
-+
-+ TP_printk("dev=%u, RCL 0x%08x..0x%08x",
-+ __entry->dev,
-+ __entry->ct1qba,
-+ __entry->ct1qea)
-+);
-+
- TRACE_EVENT(v3d_submit_cl,
- TP_PROTO(struct drm_device *dev, bool is_render,
- uint64_t seqno,
-@@ -42,6 +64,85 @@ TRACE_EVENT(v3d_submit_cl,
- __entry->ctnqea)
- );
-
-+TRACE_EVENT(v3d_bcl_irq,
-+ TP_PROTO(struct drm_device *dev,
-+ uint64_t seqno),
-+ TP_ARGS(dev, seqno),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ __field(u64, seqno)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ __entry->seqno = seqno;
-+ ),
-+
-+ TP_printk("dev=%u, seqno=%llu",
-+ __entry->dev,
-+ __entry->seqno)
-+);
-+
-+TRACE_EVENT(v3d_rcl_irq,
-+ TP_PROTO(struct drm_device *dev,
-+ uint64_t seqno),
-+ TP_ARGS(dev, seqno),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ __field(u64, seqno)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ __entry->seqno = seqno;
-+ ),
-+
-+ TP_printk("dev=%u, seqno=%llu",
-+ __entry->dev,
-+ __entry->seqno)
-+);
-+
-+TRACE_EVENT(v3d_tfu_irq,
-+ TP_PROTO(struct drm_device *dev,
-+ uint64_t seqno),
-+ TP_ARGS(dev, seqno),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ __field(u64, seqno)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ __entry->seqno = seqno;
-+ ),
-+
-+ TP_printk("dev=%u, seqno=%llu",
-+ __entry->dev,
-+ __entry->seqno)
-+);
-+
-+TRACE_EVENT(v3d_submit_tfu_ioctl,
-+ TP_PROTO(struct drm_device *dev, u32 iia),
-+ TP_ARGS(dev, iia),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ __field(u32, iia)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ __entry->iia = iia;
-+ ),
-+
-+ TP_printk("dev=%u, IIA 0x%08x",
-+ __entry->dev,
-+ __entry->iia)
-+);
-+
- TRACE_EVENT(v3d_submit_tfu,
- TP_PROTO(struct drm_device *dev,
- uint64_t seqno),
--- /dev/null
+From 4a6410a53059d6505680b70fc438b7cfbf8939ca Mon Sep 17 00:00:00 2001
+Date: Mon, 3 Dec 2018 14:24:35 -0800
+Subject: [PATCH] drm/v3d: Don't bother flushing L1TD at job start.
+
+This is the write combiner for TMU writes. You're supposed to flush
+that at job end if you had dirtied any cachelines. Flushing it at job
+start then doesn't make any sense.
+
+Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+")
+(cherry picked from commit 2e6dc3bd80478212e84addf1cafd6ec60674b884)
+---
+ drivers/gpu/drm/v3d/v3d_gem.c | 12 ------------
+ 1 file changed, 12 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -139,22 +139,10 @@ v3d_invalidate_l2(struct v3d_dev *v3d, i
+ V3D_L2CACTL_L2CENA);
+ }
+
+-static void
+-v3d_invalidate_l1td(struct v3d_dev *v3d, int core)
+-{
+- V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, V3D_L2TCACTL_TMUWCF);
+- if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
+- V3D_L2TCACTL_L2TFLS), 100)) {
+- DRM_ERROR("Timeout waiting for L1T write combiner flush\n");
+- }
+-}
+-
+ /* Invalidates texture L2 cachelines */
+ static void
+ v3d_flush_l2t(struct v3d_dev *v3d, int core)
+ {
+- v3d_invalidate_l1td(v3d, core);
+-
+ V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL,
+ V3D_L2TCACTL_L2TFLS |
+ V3D_SET_FIELD(V3D_L2TCACTL_FLM_FLUSH, V3D_L2TCACTL_FLM));
--- /dev/null
+From 9d8fa62500ae52348d36766e70b49c7508addaf3 Mon Sep 17 00:00:00 2001
+Date: Mon, 3 Dec 2018 14:24:36 -0800
+Subject: [PATCH] drm/v3d: Drop the wait for L2T flush to complete.
+
+According to Dave, once you've started an L2T flush, all L2T accesses
+will be blocked until the flush completes. This fixes a consistent
+3-4ms stall between the ioctl and running the job, and 3DMMES Taiji
+goes from 27fps to 110fps.
+
+v2: Leave a note about why we don't need to wait for completion.
+
+Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+")
+(cherry picked from commit 51c1b6f9eb3dbdec91b0e3c89f623e634c996bbb)
+---
+ drivers/gpu/drm/v3d/v3d_gem.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -143,13 +143,13 @@ v3d_invalidate_l2(struct v3d_dev *v3d, i
+ static void
+ v3d_flush_l2t(struct v3d_dev *v3d, int core)
+ {
++ /* While there is a busy bit (V3D_L2TCACTL_L2TFLS), we don't
++ * need to wait for completion before dispatching the job --
++ * L2T accesses will be stalled until the flush has completed.
++ */
+ V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL,
+ V3D_L2TCACTL_L2TFLS |
+ V3D_SET_FIELD(V3D_L2TCACTL_FLM_FLUSH, V3D_L2TCACTL_FLM));
+- if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
+- V3D_L2TCACTL_L2TFLS), 100)) {
+- DRM_ERROR("Timeout waiting for L2T flush\n");
+- }
+ }
+
+ /* Invalidates the slice caches. These are read-only caches. */
+++ /dev/null
-From 065c8947cb7c40bfb3e76dcbb9d901b5e8fe0ea4 Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Dec 2018 14:24:34 -0800
-Subject: [PATCH] drm/v3d: Drop unused v3d_flush_caches().
-
-Now that I've specified how the end-of-pipeline flushing should work,
-we're never going to use this function.
-
-(cherry picked from commit 2aa34fd5c7754824cf5488b61ac644f30d3c5c85)
----
- drivers/gpu/drm/v3d/v3d_drv.h | 1 -
- drivers/gpu/drm/v3d/v3d_gem.c | 21 ---------------------
- 2 files changed, 22 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.h
-+++ b/drivers/gpu/drm/v3d/v3d_drv.h
-@@ -308,7 +308,6 @@ void v3d_exec_put(struct v3d_exec_info *
- void v3d_tfu_job_put(struct v3d_tfu_job *exec);
- void v3d_reset(struct v3d_dev *v3d);
- void v3d_invalidate_caches(struct v3d_dev *v3d);
--void v3d_flush_caches(struct v3d_dev *v3d);
-
- /* v3d_irq.c */
- int v3d_irq_init(struct v3d_dev *v3d);
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -175,20 +175,6 @@ v3d_invalidate_slices(struct v3d_dev *v3
- V3D_SET_FIELD(0xf, V3D_SLCACTL_ICC));
- }
-
--/* Invalidates texture L2 cachelines */
--static void
--v3d_invalidate_l2t(struct v3d_dev *v3d, int core)
--{
-- V3D_CORE_WRITE(core,
-- V3D_CTL_L2TCACTL,
-- V3D_L2TCACTL_L2TFLS |
-- V3D_SET_FIELD(V3D_L2TCACTL_FLM_CLEAR, V3D_L2TCACTL_FLM));
-- if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
-- V3D_L2TCACTL_L2TFLS), 100)) {
-- DRM_ERROR("Timeout waiting for L2T invalidate\n");
-- }
--}
--
- void
- v3d_invalidate_caches(struct v3d_dev *v3d)
- {
-@@ -199,13 +185,6 @@ v3d_invalidate_caches(struct v3d_dev *v3
- v3d_flush_l2t(v3d, 0);
- }
-
--void
--v3d_flush_caches(struct v3d_dev *v3d)
--{
-- v3d_invalidate_l1td(v3d, 0);
-- v3d_invalidate_l2t(v3d, 0);
--}
--
- static void
- v3d_attach_object_fences(struct v3d_bo **bos, int bo_count,
- struct dma_fence *fence)
+++ /dev/null
-From 4a6410a53059d6505680b70fc438b7cfbf8939ca Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Dec 2018 14:24:35 -0800
-Subject: [PATCH] drm/v3d: Don't bother flushing L1TD at job start.
-
-This is the write combiner for TMU writes. You're supposed to flush
-that at job end if you had dirtied any cachelines. Flushing it at job
-start then doesn't make any sense.
-
-Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+")
-(cherry picked from commit 2e6dc3bd80478212e84addf1cafd6ec60674b884)
----
- drivers/gpu/drm/v3d/v3d_gem.c | 12 ------------
- 1 file changed, 12 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -139,22 +139,10 @@ v3d_invalidate_l2(struct v3d_dev *v3d, i
- V3D_L2CACTL_L2CENA);
- }
-
--static void
--v3d_invalidate_l1td(struct v3d_dev *v3d, int core)
--{
-- V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, V3D_L2TCACTL_TMUWCF);
-- if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
-- V3D_L2TCACTL_L2TFLS), 100)) {
-- DRM_ERROR("Timeout waiting for L1T write combiner flush\n");
-- }
--}
--
- /* Invalidates texture L2 cachelines */
- static void
- v3d_flush_l2t(struct v3d_dev *v3d, int core)
- {
-- v3d_invalidate_l1td(v3d, core);
--
- V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL,
- V3D_L2TCACTL_L2TFLS |
- V3D_SET_FIELD(V3D_L2TCACTL_FLM_FLUSH, V3D_L2TCACTL_FLM));
--- /dev/null
+From abee30ca29ec11b62842934de04b5a0033bff21b Mon Sep 17 00:00:00 2001
+Date: Mon, 3 Dec 2018 14:24:37 -0800
+Subject: [PATCH] drm/v3d: Stop trying to flush L2C on V3D 3.3+
+
+This cache was replaced with the slice accessing the L2T in the newer
+generations. Noted by Dave during review.
+
+(cherry picked from commit 7b9d2fe4350a9c12f66ad8cc78c1098226f6c3c2)
+---
+ drivers/gpu/drm/v3d/v3d_gem.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -130,10 +130,15 @@ v3d_flush_l3(struct v3d_dev *v3d)
+ }
+ }
+
+-/* Invalidates the (read-only) L2 cache. */
++/* Invalidates the (read-only) L2C cache. This was the L2 cache for
++ * uniforms and instructions on V3D 3.2.
++ */
+ static void
+-v3d_invalidate_l2(struct v3d_dev *v3d, int core)
++v3d_invalidate_l2c(struct v3d_dev *v3d, int core)
+ {
++ if (v3d->ver > 32)
++ return;
++
+ V3D_CORE_WRITE(core, V3D_CTL_L2CACTL,
+ V3D_L2CACTL_L2CCLR |
+ V3D_L2CACTL_L2CENA);
+@@ -168,7 +173,7 @@ v3d_invalidate_caches(struct v3d_dev *v3
+ {
+ v3d_flush_l3(v3d);
+
+- v3d_invalidate_l2(v3d, 0);
++ v3d_invalidate_l2c(v3d, 0);
+ v3d_invalidate_slices(v3d, 0);
+ v3d_flush_l2t(v3d, 0);
+ }
+++ /dev/null
-From 9d8fa62500ae52348d36766e70b49c7508addaf3 Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Dec 2018 14:24:36 -0800
-Subject: [PATCH] drm/v3d: Drop the wait for L2T flush to complete.
-
-According to Dave, once you've started an L2T flush, all L2T accesses
-will be blocked until the flush completes. This fixes a consistent
-3-4ms stall between the ioctl and running the job, and 3DMMES Taiji
-goes from 27fps to 110fps.
-
-v2: Leave a note about why we don't need to wait for completion.
-
-Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+")
-(cherry picked from commit 51c1b6f9eb3dbdec91b0e3c89f623e634c996bbb)
----
- drivers/gpu/drm/v3d/v3d_gem.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -143,13 +143,13 @@ v3d_invalidate_l2(struct v3d_dev *v3d, i
- static void
- v3d_flush_l2t(struct v3d_dev *v3d, int core)
- {
-+ /* While there is a busy bit (V3D_L2TCACTL_L2TFLS), we don't
-+ * need to wait for completion before dispatching the job --
-+ * L2T accesses will be stalled until the flush has completed.
-+ */
- V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL,
- V3D_L2TCACTL_L2TFLS |
- V3D_SET_FIELD(V3D_L2TCACTL_FLM_FLUSH, V3D_L2TCACTL_FLM));
-- if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
-- V3D_L2TCACTL_L2TFLS), 100)) {
-- DRM_ERROR("Timeout waiting for L2T flush\n");
-- }
- }
-
- /* Invalidates the slice caches. These are read-only caches. */
--- /dev/null
+From 514653cd51ff6bc14268dc0f98ebb37daa8f0e88 Mon Sep 17 00:00:00 2001
+Date: Mon, 3 Dec 2018 14:24:38 -0800
+Subject: [PATCH] drm/v3d: Invalidate the caches from the outside in.
+
+This would be a fairly obscure race, but let's make sure we don't ever
+lose it.
+
+(cherry picked from commit aa5beec32e8b78bfcf621e3c3daebfb1644b6365)
+---
+ drivers/gpu/drm/v3d/v3d_gem.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -171,11 +171,15 @@ v3d_invalidate_slices(struct v3d_dev *v3
+ void
+ v3d_invalidate_caches(struct v3d_dev *v3d)
+ {
++ /* Invalidate the caches from the outside in. That way if
++ * another CL's concurrent use of nearby memory were to pull
++ * an invalidated cacheline back in, we wouldn't leave stale
++ * data in the inner cache.
++ */
+ v3d_flush_l3(v3d);
+-
+ v3d_invalidate_l2c(v3d, 0);
+- v3d_invalidate_slices(v3d, 0);
+ v3d_flush_l2t(v3d, 0);
++ v3d_invalidate_slices(v3d, 0);
+ }
+
+ static void
--- /dev/null
+From f91d0382b735a3d7711f6b160d80627cd4be54af Mon Sep 17 00:00:00 2001
+Date: Thu, 7 Feb 2019 15:26:13 -0800
+Subject: [PATCH] drm/v3d: Fix BO stats accounting for dma-buf-imported
+ buffers.
+
+We always decrement at GEM free, so make sure we increment at GEM
+creation for dma-bufs.
+
+(cherry picked from commit cc3f60cfd4f2752f1bad7eaa3839855c15347abc)
+---
+ drivers/gpu/drm/v3d/v3d_bo.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_bo.c
++++ b/drivers/gpu/drm/v3d/v3d_bo.c
+@@ -282,6 +282,7 @@ v3d_prime_import_sg_table(struct drm_dev
+ struct dma_buf_attachment *attach,
+ struct sg_table *sgt)
+ {
++ struct v3d_dev *v3d = to_v3d_dev(dev);
+ struct drm_gem_object *obj;
+ struct v3d_bo *bo;
+
+@@ -296,6 +297,11 @@ v3d_prime_import_sg_table(struct drm_dev
+ obj->import_attach = attach;
+ v3d_bo_get_pages(bo);
+
++ mutex_lock(&v3d->bo_lock);
++ v3d->bo_stats.num_allocated++;
++ v3d->bo_stats.pages_allocated += obj->size >> PAGE_SHIFT;
++ mutex_unlock(&v3d->bo_lock);
++
+ v3d_mmu_insert_ptes(bo);
+
+ return obj;
+++ /dev/null
-From abee30ca29ec11b62842934de04b5a0033bff21b Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Dec 2018 14:24:37 -0800
-Subject: [PATCH] drm/v3d: Stop trying to flush L2C on V3D 3.3+
-
-This cache was replaced with the slice accessing the L2T in the newer
-generations. Noted by Dave during review.
-
-(cherry picked from commit 7b9d2fe4350a9c12f66ad8cc78c1098226f6c3c2)
----
- drivers/gpu/drm/v3d/v3d_gem.c | 11 ++++++++---
- 1 file changed, 8 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -130,10 +130,15 @@ v3d_flush_l3(struct v3d_dev *v3d)
- }
- }
-
--/* Invalidates the (read-only) L2 cache. */
-+/* Invalidates the (read-only) L2C cache. This was the L2 cache for
-+ * uniforms and instructions on V3D 3.2.
-+ */
- static void
--v3d_invalidate_l2(struct v3d_dev *v3d, int core)
-+v3d_invalidate_l2c(struct v3d_dev *v3d, int core)
- {
-+ if (v3d->ver > 32)
-+ return;
-+
- V3D_CORE_WRITE(core, V3D_CTL_L2CACTL,
- V3D_L2CACTL_L2CCLR |
- V3D_L2CACTL_L2CENA);
-@@ -168,7 +173,7 @@ v3d_invalidate_caches(struct v3d_dev *v3
- {
- v3d_flush_l3(v3d);
-
-- v3d_invalidate_l2(v3d, 0);
-+ v3d_invalidate_l2c(v3d, 0);
- v3d_invalidate_slices(v3d, 0);
- v3d_flush_l2t(v3d, 0);
- }
+++ /dev/null
-From 514653cd51ff6bc14268dc0f98ebb37daa8f0e88 Mon Sep 17 00:00:00 2001
-Date: Mon, 3 Dec 2018 14:24:38 -0800
-Subject: [PATCH] drm/v3d: Invalidate the caches from the outside in.
-
-This would be a fairly obscure race, but let's make sure we don't ever
-lose it.
-
-(cherry picked from commit aa5beec32e8b78bfcf621e3c3daebfb1644b6365)
----
- drivers/gpu/drm/v3d/v3d_gem.c | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -171,11 +171,15 @@ v3d_invalidate_slices(struct v3d_dev *v3
- void
- v3d_invalidate_caches(struct v3d_dev *v3d)
- {
-+ /* Invalidate the caches from the outside in. That way if
-+ * another CL's concurrent use of nearby memory were to pull
-+ * an invalidated cacheline back in, we wouldn't leave stale
-+ * data in the inner cache.
-+ */
- v3d_flush_l3(v3d);
--
- v3d_invalidate_l2c(v3d, 0);
-- v3d_invalidate_slices(v3d, 0);
- v3d_flush_l2t(v3d, 0);
-+ v3d_invalidate_slices(v3d, 0);
- }
-
- static void
--- /dev/null
+From 752f66d4482db75db81e5255f5071de1e47ac121 Mon Sep 17 00:00:00 2001
+Date: Thu, 7 Feb 2019 12:09:58 -0800
+Subject: [PATCH] drm/v3d: Update top-level kerneldoc for the addition
+ of TFU.
+
+(cherry picked from commit fd347df16d4ed2eef565344b8f16a1134bddf185)
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -7,9 +7,9 @@
+ * This driver supports the Broadcom V3D 3.3 and 4.1 OpenGL ES GPUs.
+ * For V3D 2.x support, see the VC4 driver.
+ *
+- * Currently only single-core rendering using the binner and renderer
+- * is supported. The TFU (texture formatting unit) and V3D 4.x's CSD
+- * (compute shader dispatch) are not yet supported.
++ * Currently only single-core rendering using the binner and renderer,
++ * along with TFU (texture formatting unit) rendering is supported.
++ * V3D 4.x's CSD (compute shader dispatch) is not yet supported.
+ */
+
+ #include <linux/clk.h>
+++ /dev/null
-From f91d0382b735a3d7711f6b160d80627cd4be54af Mon Sep 17 00:00:00 2001
-Date: Thu, 7 Feb 2019 15:26:13 -0800
-Subject: [PATCH] drm/v3d: Fix BO stats accounting for dma-buf-imported
- buffers.
-
-We always decrement at GEM free, so make sure we increment at GEM
-creation for dma-bufs.
-
-(cherry picked from commit cc3f60cfd4f2752f1bad7eaa3839855c15347abc)
----
- drivers/gpu/drm/v3d/v3d_bo.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/drivers/gpu/drm/v3d/v3d_bo.c
-+++ b/drivers/gpu/drm/v3d/v3d_bo.c
-@@ -282,6 +282,7 @@ v3d_prime_import_sg_table(struct drm_dev
- struct dma_buf_attachment *attach,
- struct sg_table *sgt)
- {
-+ struct v3d_dev *v3d = to_v3d_dev(dev);
- struct drm_gem_object *obj;
- struct v3d_bo *bo;
-
-@@ -296,6 +297,11 @@ v3d_prime_import_sg_table(struct drm_dev
- obj->import_attach = attach;
- v3d_bo_get_pages(bo);
-
-+ mutex_lock(&v3d->bo_lock);
-+ v3d->bo_stats.num_allocated++;
-+ v3d->bo_stats.pages_allocated += obj->size >> PAGE_SHIFT;
-+ mutex_unlock(&v3d->bo_lock);
-+
- v3d_mmu_insert_ptes(bo);
-
- return obj;
--- /dev/null
+From ec551e663ddd1be9140cc23f1eff33b8d270ed60 Mon Sep 17 00:00:00 2001
+Date: Mon, 4 Mar 2019 11:59:34 -0800
+Subject: [PATCH] drm/vc4: Fix oops at boot with firmwarekms on 4.19.
+
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -107,6 +107,9 @@ vc4_ctm_commit(struct vc4_dev *vc4, stru
+ struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state);
+ struct drm_color_ctm *ctm = ctm_state->ctm;
+
++ if (vc4->firmware_kms)
++ return;
++
+ if (ctm_state->fifo) {
+ HVS_WRITE(SCALER_OLEDCOEF2,
+ VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]),
--- /dev/null
+From b0e7b8814e74be0559e07f737ef18cc3709d4ac4 Mon Sep 17 00:00:00 2001
+Date: Thu, 4 Oct 2018 17:22:43 -0700
+Subject: [PATCH] drm/v3d: Add support for V3D v4.2.
+
+No compatible string for it yet, just the version-dependent changes.
+They've now tied the hub and the core interrupt lines into a single
+interrupt line coming out of the block. It also turns out I made a
+mistake in modeling the V3D v3.3 and v4.1 bridge as a part of V3D
+itself -- the bridge is going away in favor of an external reset
+controller in a larger HW module.
+
+v2: Use consistent checks for whether we're on 4.2, and fix a leak in
+ an error path.
+v3: Use more general means of determining if the current 4.2 changes
+ are in place, as apparently other platforms may switch back (noted
+ by Dave). Update the binding doc.
+
+---
+ .../devicetree/bindings/gpu/brcm,bcm-v3d.txt | 11 ++++--
+ drivers/gpu/drm/v3d/v3d_drv.c | 21 +++++++++---
+ drivers/gpu/drm/v3d/v3d_drv.h | 2 ++
+ drivers/gpu/drm/v3d/v3d_gem.c | 12 ++++++-
+ drivers/gpu/drm/v3d/v3d_irq.c | 34 ++++++++++++++-----
+ 5 files changed, 63 insertions(+), 17 deletions(-)
+
+--- a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.txt
++++ b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.txt
+@@ -6,15 +6,20 @@ For V3D 2.x, see brcm,bcm-vc4.txt.
+ Required properties:
+ - compatible: Should be "brcm,7268-v3d" or "brcm,7278-v3d"
+ - reg: Physical base addresses and lengths of the register areas
+-- reg-names: Names for the register areas. The "hub", "bridge", and "core0"
++- reg-names: Names for the register areas. The "hub" and "core0"
+ register areas are always required. The "gca" register area
+- is required if the GCA cache controller is present.
++ is required if the GCA cache controller is present. The
++ "bridge" register area is required if an external reset
++ controller is not present.
+ - interrupts: The interrupt numbers. The first interrupt is for the hub,
+- while the following interrupts are for the cores.
++ while the following interrupts are separate interrupt lines
++ for the cores (if they don't share the hub's interrupt).
+ See bindings/interrupt-controller/interrupts.txt
+
+ Optional properties:
+ - clocks: The core clock the unit runs on
++- resets: The reset line for v3d, if not using a mapping of the bridge
++ See bindings/reset/reset.txt
+
+ v3d {
+ compatible = "brcm,7268-v3d";
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -19,6 +19,7 @@
+ #include <linux/of_platform.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_runtime.h>
++#include <linux/reset.h>
+ #include <drm/drm_fb_cma_helper.h>
+ #include <drm/drm_fb_helper.h>
+
+@@ -265,10 +266,6 @@ static int v3d_platform_drm_probe(struct
+ v3d->pdev = pdev;
+ drm = &v3d->drm;
+
+- ret = map_regs(v3d, &v3d->bridge_regs, "bridge");
+- if (ret)
+- goto dev_free;
+-
+ ret = map_regs(v3d, &v3d->hub_regs, "hub");
+ if (ret)
+ goto dev_free;
+@@ -283,6 +280,22 @@ static int v3d_platform_drm_probe(struct
+ v3d->cores = V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_NCORES);
+ WARN_ON(v3d->cores > 1); /* multicore not yet implemented */
+
++ v3d->reset = devm_reset_control_get_exclusive(dev, NULL);
++ if (IS_ERR(v3d->reset)) {
++ ret = PTR_ERR(v3d->reset);
++
++ if (ret == -EPROBE_DEFER)
++ goto dev_free;
++
++ v3d->reset = NULL;
++ ret = map_regs(v3d, &v3d->bridge_regs, "bridge");
++ if (ret) {
++ dev_err(dev,
++ "Failed to get reset control or bridge regs\n");
++ goto dev_free;
++ }
++ }
++
+ if (v3d->ver < 41) {
+ ret = map_regs(v3d, &v3d->gca_regs, "gca");
+ if (ret)
+--- a/drivers/gpu/drm/v3d/v3d_drv.h
++++ b/drivers/gpu/drm/v3d/v3d_drv.h
+@@ -34,6 +34,7 @@ struct v3d_dev {
+ * and revision.
+ */
+ int ver;
++ bool single_irq_line;
+
+ struct device *dev;
+ struct platform_device *pdev;
+@@ -42,6 +43,7 @@ struct v3d_dev {
+ void __iomem *bridge_regs;
+ void __iomem *gca_regs;
+ struct clk *clk;
++ struct reset_control *reset;
+
+ /* Virtual and DMA addresses of the single shared page table. */
+ volatile u32 *pt;
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -6,6 +6,7 @@
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_runtime.h>
++#include <linux/reset.h>
+ #include <linux/device.h>
+ #include <linux/io.h>
+ #include <linux/sched/signal.h>
+@@ -69,7 +70,7 @@ v3d_idle_gca(struct v3d_dev *v3d)
+ }
+
+ static void
+-v3d_reset_v3d(struct v3d_dev *v3d)
++v3d_reset_by_bridge(struct v3d_dev *v3d)
+ {
+ int version = V3D_BRIDGE_READ(V3D_TOP_GR_BRIDGE_REVISION);
+
+@@ -89,6 +90,15 @@ v3d_reset_v3d(struct v3d_dev *v3d)
+ V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT);
+ V3D_BRIDGE_WRITE(V3D_TOP_GR_BRIDGE_SW_INIT_1, 0);
+ }
++}
++
++static void
++v3d_reset_v3d(struct v3d_dev *v3d)
++{
++ if (v3d->reset)
++ reset_control_reset(v3d->reset);
++ else
++ v3d_reset_by_bridge(v3d);
+
+ v3d_init_hw_state(v3d);
+ }
+--- a/drivers/gpu/drm/v3d/v3d_irq.c
++++ b/drivers/gpu/drm/v3d/v3d_irq.c
+@@ -27,6 +27,9 @@
+ V3D_HUB_INT_MMU_CAP | \
+ V3D_HUB_INT_TFUC))
+
++static irqreturn_t
++v3d_hub_irq(int irq, void *arg);
++
+ static void
+ v3d_overflow_mem_work(struct work_struct *work)
+ {
+@@ -112,6 +115,12 @@ v3d_irq(int irq, void *arg)
+ if (intsts & V3D_INT_GMPV)
+ dev_err(v3d->dev, "GMP violation\n");
+
++ /* V3D 4.2 wires the hub and core IRQs together, so if we &
++ * didn't see the common one then check hub for MMU IRQs.
++ */
++ if (v3d->single_irq_line && status == IRQ_NONE)
++ return v3d_hub_irq(irq, arg);
++
+ return status;
+ }
+
+@@ -170,15 +179,22 @@ v3d_irq_init(struct v3d_dev *v3d)
+ V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS);
+ V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS);
+
+- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
+- v3d_hub_irq, IRQF_SHARED,
+- "v3d_hub", v3d);
+- if (ret)
+- goto fail;
+-
+- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 1),
+- v3d_irq, IRQF_SHARED,
+- "v3d_core0", v3d);
++ if (platform_get_irq(v3d->pdev, 1) < 0) {
++ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
++ v3d_irq, IRQF_SHARED,
++ "v3d", v3d);
++ v3d->single_irq_line = true;
++ } else {
++ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
++ v3d_hub_irq, IRQF_SHARED,
++ "v3d_hub", v3d);
++ if (ret)
++ goto fail;
++
++ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 1),
++ v3d_irq, IRQF_SHARED,
++ "v3d_core0", v3d);
++ }
+ if (ret)
+ goto fail;
+
+++ /dev/null
-From 752f66d4482db75db81e5255f5071de1e47ac121 Mon Sep 17 00:00:00 2001
-Date: Thu, 7 Feb 2019 12:09:58 -0800
-Subject: [PATCH] drm/v3d: Update top-level kerneldoc for the addition
- of TFU.
-
-(cherry picked from commit fd347df16d4ed2eef565344b8f16a1134bddf185)
----
- drivers/gpu/drm/v3d/v3d_drv.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -7,9 +7,9 @@
- * This driver supports the Broadcom V3D 3.3 and 4.1 OpenGL ES GPUs.
- * For V3D 2.x support, see the VC4 driver.
- *
-- * Currently only single-core rendering using the binner and renderer
-- * is supported. The TFU (texture formatting unit) and V3D 4.x's CSD
-- * (compute shader dispatch) are not yet supported.
-+ * Currently only single-core rendering using the binner and renderer,
-+ * along with TFU (texture formatting unit) rendering is supported.
-+ * V3D 4.x's CSD (compute shader dispatch) is not yet supported.
- */
-
- #include <linux/clk.h>
--- /dev/null
+From 8011a92f6eabd682e62e268bcd80b45ce3f06af4 Mon Sep 17 00:00:00 2001
+Date: Tue, 16 Oct 2018 10:13:41 -0700
+Subject: [PATCH] drm/v3d: Don't try to set OVRTMUOUT on V3D 4.x.
+
+The old field is gone and the register now has a different field,
+QRMAXCNT for how many TMU requests get serviced before thread switch.
+We were accidentally reducing it from its default of 0x3 (4 requests)
+to 0x0 (1).
+
+v2: Skip setting the reg at all on 4.x, instead of trying to update
+ only the old field.
+
+---
+ drivers/gpu/drm/v3d/v3d_gem.c | 3 ++-
+ drivers/gpu/drm/v3d/v3d_regs.h | 2 ++
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -25,7 +25,8 @@ v3d_init_core(struct v3d_dev *v3d, int c
+ * type. If you want the default behavior, you can still put
+ * "2" in the indirect texture state's output_type field.
+ */
+- V3D_CORE_WRITE(core, V3D_CTL_MISCCFG, V3D_MISCCFG_OVRTMUOUT);
++ if (v3d->ver < 40)
++ V3D_CORE_WRITE(core, V3D_CTL_MISCCFG, V3D_MISCCFG_OVRTMUOUT);
+
+ /* Whenever we flush the L2T cache, we always want to flush
+ * the whole thing.
+--- a/drivers/gpu/drm/v3d/v3d_regs.h
++++ b/drivers/gpu/drm/v3d/v3d_regs.h
+@@ -216,6 +216,8 @@
+ # define V3D_IDENT2_BCG_INT BIT(28)
+
+ #define V3D_CTL_MISCCFG 0x00018
++# define V3D_CTL_MISCCFG_QRMAXCNT_MASK V3D_MASK(3, 1)
++# define V3D_CTL_MISCCFG_QRMAXCNT_SHIFT 1
+ # define V3D_MISCCFG_OVRTMUOUT BIT(0)
+
+ #define V3D_CTL_L2CACTL 0x00020
+++ /dev/null
-From ec551e663ddd1be9140cc23f1eff33b8d270ed60 Mon Sep 17 00:00:00 2001
-Date: Mon, 4 Mar 2019 11:59:34 -0800
-Subject: [PATCH] drm/vc4: Fix oops at boot with firmwarekms on 4.19.
-
----
- drivers/gpu/drm/vc4/vc4_kms.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -107,6 +107,9 @@ vc4_ctm_commit(struct vc4_dev *vc4, stru
- struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state);
- struct drm_color_ctm *ctm = ctm_state->ctm;
-
-+ if (vc4->firmware_kms)
-+ return;
-+
- if (ctm_state->fifo) {
- HVS_WRITE(SCALER_OLEDCOEF2,
- VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]),
+++ /dev/null
-From b0e7b8814e74be0559e07f737ef18cc3709d4ac4 Mon Sep 17 00:00:00 2001
-Date: Thu, 4 Oct 2018 17:22:43 -0700
-Subject: [PATCH] drm/v3d: Add support for V3D v4.2.
-
-No compatible string for it yet, just the version-dependent changes.
-They've now tied the hub and the core interrupt lines into a single
-interrupt line coming out of the block. It also turns out I made a
-mistake in modeling the V3D v3.3 and v4.1 bridge as a part of V3D
-itself -- the bridge is going away in favor of an external reset
-controller in a larger HW module.
-
-v2: Use consistent checks for whether we're on 4.2, and fix a leak in
- an error path.
-v3: Use more general means of determining if the current 4.2 changes
- are in place, as apparently other platforms may switch back (noted
- by Dave). Update the binding doc.
-
----
- .../devicetree/bindings/gpu/brcm,bcm-v3d.txt | 11 ++++--
- drivers/gpu/drm/v3d/v3d_drv.c | 21 +++++++++---
- drivers/gpu/drm/v3d/v3d_drv.h | 2 ++
- drivers/gpu/drm/v3d/v3d_gem.c | 12 ++++++-
- drivers/gpu/drm/v3d/v3d_irq.c | 34 ++++++++++++++-----
- 5 files changed, 63 insertions(+), 17 deletions(-)
-
---- a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.txt
-+++ b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.txt
-@@ -6,15 +6,20 @@ For V3D 2.x, see brcm,bcm-vc4.txt.
- Required properties:
- - compatible: Should be "brcm,7268-v3d" or "brcm,7278-v3d"
- - reg: Physical base addresses and lengths of the register areas
--- reg-names: Names for the register areas. The "hub", "bridge", and "core0"
-+- reg-names: Names for the register areas. The "hub" and "core0"
- register areas are always required. The "gca" register area
-- is required if the GCA cache controller is present.
-+ is required if the GCA cache controller is present. The
-+ "bridge" register area is required if an external reset
-+ controller is not present.
- - interrupts: The interrupt numbers. The first interrupt is for the hub,
-- while the following interrupts are for the cores.
-+ while the following interrupts are separate interrupt lines
-+ for the cores (if they don't share the hub's interrupt).
- See bindings/interrupt-controller/interrupts.txt
-
- Optional properties:
- - clocks: The core clock the unit runs on
-+- resets: The reset line for v3d, if not using a mapping of the bridge
-+ See bindings/reset/reset.txt
-
- v3d {
- compatible = "brcm,7268-v3d";
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -19,6 +19,7 @@
- #include <linux/of_platform.h>
- #include <linux/platform_device.h>
- #include <linux/pm_runtime.h>
-+#include <linux/reset.h>
- #include <drm/drm_fb_cma_helper.h>
- #include <drm/drm_fb_helper.h>
-
-@@ -265,10 +266,6 @@ static int v3d_platform_drm_probe(struct
- v3d->pdev = pdev;
- drm = &v3d->drm;
-
-- ret = map_regs(v3d, &v3d->bridge_regs, "bridge");
-- if (ret)
-- goto dev_free;
--
- ret = map_regs(v3d, &v3d->hub_regs, "hub");
- if (ret)
- goto dev_free;
-@@ -283,6 +280,22 @@ static int v3d_platform_drm_probe(struct
- v3d->cores = V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_NCORES);
- WARN_ON(v3d->cores > 1); /* multicore not yet implemented */
-
-+ v3d->reset = devm_reset_control_get_exclusive(dev, NULL);
-+ if (IS_ERR(v3d->reset)) {
-+ ret = PTR_ERR(v3d->reset);
-+
-+ if (ret == -EPROBE_DEFER)
-+ goto dev_free;
-+
-+ v3d->reset = NULL;
-+ ret = map_regs(v3d, &v3d->bridge_regs, "bridge");
-+ if (ret) {
-+ dev_err(dev,
-+ "Failed to get reset control or bridge regs\n");
-+ goto dev_free;
-+ }
-+ }
-+
- if (v3d->ver < 41) {
- ret = map_regs(v3d, &v3d->gca_regs, "gca");
- if (ret)
---- a/drivers/gpu/drm/v3d/v3d_drv.h
-+++ b/drivers/gpu/drm/v3d/v3d_drv.h
-@@ -34,6 +34,7 @@ struct v3d_dev {
- * and revision.
- */
- int ver;
-+ bool single_irq_line;
-
- struct device *dev;
- struct platform_device *pdev;
-@@ -42,6 +43,7 @@ struct v3d_dev {
- void __iomem *bridge_regs;
- void __iomem *gca_regs;
- struct clk *clk;
-+ struct reset_control *reset;
-
- /* Virtual and DMA addresses of the single shared page table. */
- volatile u32 *pt;
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -6,6 +6,7 @@
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/pm_runtime.h>
-+#include <linux/reset.h>
- #include <linux/device.h>
- #include <linux/io.h>
- #include <linux/sched/signal.h>
-@@ -69,7 +70,7 @@ v3d_idle_gca(struct v3d_dev *v3d)
- }
-
- static void
--v3d_reset_v3d(struct v3d_dev *v3d)
-+v3d_reset_by_bridge(struct v3d_dev *v3d)
- {
- int version = V3D_BRIDGE_READ(V3D_TOP_GR_BRIDGE_REVISION);
-
-@@ -89,6 +90,15 @@ v3d_reset_v3d(struct v3d_dev *v3d)
- V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT);
- V3D_BRIDGE_WRITE(V3D_TOP_GR_BRIDGE_SW_INIT_1, 0);
- }
-+}
-+
-+static void
-+v3d_reset_v3d(struct v3d_dev *v3d)
-+{
-+ if (v3d->reset)
-+ reset_control_reset(v3d->reset);
-+ else
-+ v3d_reset_by_bridge(v3d);
-
- v3d_init_hw_state(v3d);
- }
---- a/drivers/gpu/drm/v3d/v3d_irq.c
-+++ b/drivers/gpu/drm/v3d/v3d_irq.c
-@@ -27,6 +27,9 @@
- V3D_HUB_INT_MMU_CAP | \
- V3D_HUB_INT_TFUC))
-
-+static irqreturn_t
-+v3d_hub_irq(int irq, void *arg);
-+
- static void
- v3d_overflow_mem_work(struct work_struct *work)
- {
-@@ -112,6 +115,12 @@ v3d_irq(int irq, void *arg)
- if (intsts & V3D_INT_GMPV)
- dev_err(v3d->dev, "GMP violation\n");
-
-+ /* V3D 4.2 wires the hub and core IRQs together, so if we &
-+ * didn't see the common one then check hub for MMU IRQs.
-+ */
-+ if (v3d->single_irq_line && status == IRQ_NONE)
-+ return v3d_hub_irq(irq, arg);
-+
- return status;
- }
-
-@@ -170,15 +179,22 @@ v3d_irq_init(struct v3d_dev *v3d)
- V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS);
- V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS);
-
-- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
-- v3d_hub_irq, IRQF_SHARED,
-- "v3d_hub", v3d);
-- if (ret)
-- goto fail;
--
-- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 1),
-- v3d_irq, IRQF_SHARED,
-- "v3d_core0", v3d);
-+ if (platform_get_irq(v3d->pdev, 1) < 0) {
-+ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
-+ v3d_irq, IRQF_SHARED,
-+ "v3d", v3d);
-+ v3d->single_irq_line = true;
-+ } else {
-+ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
-+ v3d_hub_irq, IRQF_SHARED,
-+ "v3d_hub", v3d);
-+ if (ret)
-+ goto fail;
-+
-+ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 1),
-+ v3d_irq, IRQF_SHARED,
-+ "v3d_core0", v3d);
-+ }
- if (ret)
- goto fail;
-
--- /dev/null
+From 19846d53c32be7c9d8d46b369910374c5ea9b9d5 Mon Sep 17 00:00:00 2001
+Date: Mon, 14 Jan 2019 17:26:04 -0800
+Subject: [PATCH] drm/v3d: Make sure the GPU is on when measuring
+ clocks.
+
+You'll get garbage measurements if the registers always read back
+0xdeadbeef
+
+---
+ drivers/gpu/drm/v3d/v3d_debugfs.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
++++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
+@@ -187,6 +187,11 @@ static int v3d_measure_clock(struct seq_
+ uint32_t cycles;
+ int core = 0;
+ int measure_ms = 1000;
++ int ret;
++
++ ret = pm_runtime_get_sync(v3d->dev);
++ if (ret < 0)
++ return ret;
+
+ if (v3d->ver >= 40) {
+ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
+@@ -210,6 +215,9 @@ static int v3d_measure_clock(struct seq_
+ cycles / (measure_ms * 1000),
+ (cycles / (measure_ms * 100)) % 10);
+
++ pm_runtime_mark_last_busy(v3d->dev);
++ pm_runtime_put_autosuspend(v3d->dev);
++
+ return 0;
+ }
+
--- /dev/null
+From ffd9543f2d74e9215996ce6500fc34dcf7976462 Mon Sep 17 00:00:00 2001
+Date: Thu, 4 Oct 2018 17:22:43 -0700
+Subject: [PATCH] drm/v3d: Add support for 2711.
+
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -235,6 +235,7 @@ static struct drm_driver v3d_drm_driver
+ static const struct of_device_id v3d_of_match[] = {
+ { .compatible = "brcm,7268-v3d" },
+ { .compatible = "brcm,7278-v3d" },
++ { .compatible = "brcm,2711-v3d" },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, v3d_of_match);
+++ /dev/null
-From 8011a92f6eabd682e62e268bcd80b45ce3f06af4 Mon Sep 17 00:00:00 2001
-Date: Tue, 16 Oct 2018 10:13:41 -0700
-Subject: [PATCH] drm/v3d: Don't try to set OVRTMUOUT on V3D 4.x.
-
-The old field is gone and the register now has a different field,
-QRMAXCNT for how many TMU requests get serviced before thread switch.
-We were accidentally reducing it from its default of 0x3 (4 requests)
-to 0x0 (1).
-
-v2: Skip setting the reg at all on 4.x, instead of trying to update
- only the old field.
-
----
- drivers/gpu/drm/v3d/v3d_gem.c | 3 ++-
- drivers/gpu/drm/v3d/v3d_regs.h | 2 ++
- 2 files changed, 4 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -25,7 +25,8 @@ v3d_init_core(struct v3d_dev *v3d, int c
- * type. If you want the default behavior, you can still put
- * "2" in the indirect texture state's output_type field.
- */
-- V3D_CORE_WRITE(core, V3D_CTL_MISCCFG, V3D_MISCCFG_OVRTMUOUT);
-+ if (v3d->ver < 40)
-+ V3D_CORE_WRITE(core, V3D_CTL_MISCCFG, V3D_MISCCFG_OVRTMUOUT);
-
- /* Whenever we flush the L2T cache, we always want to flush
- * the whole thing.
---- a/drivers/gpu/drm/v3d/v3d_regs.h
-+++ b/drivers/gpu/drm/v3d/v3d_regs.h
-@@ -216,6 +216,8 @@
- # define V3D_IDENT2_BCG_INT BIT(28)
-
- #define V3D_CTL_MISCCFG 0x00018
-+# define V3D_CTL_MISCCFG_QRMAXCNT_MASK V3D_MASK(3, 1)
-+# define V3D_CTL_MISCCFG_QRMAXCNT_SHIFT 1
- # define V3D_MISCCFG_OVRTMUOUT BIT(0)
-
- #define V3D_CTL_L2CACTL 0x00020
+++ /dev/null
-From 19846d53c32be7c9d8d46b369910374c5ea9b9d5 Mon Sep 17 00:00:00 2001
-Date: Mon, 14 Jan 2019 17:26:04 -0800
-Subject: [PATCH] drm/v3d: Make sure the GPU is on when measuring
- clocks.
-
-You'll get garbage measurements if the registers always read back
-0xdeadbeef
-
----
- drivers/gpu/drm/v3d/v3d_debugfs.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/drivers/gpu/drm/v3d/v3d_debugfs.c
-+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
-@@ -187,6 +187,11 @@ static int v3d_measure_clock(struct seq_
- uint32_t cycles;
- int core = 0;
- int measure_ms = 1000;
-+ int ret;
-+
-+ ret = pm_runtime_get_sync(v3d->dev);
-+ if (ret < 0)
-+ return ret;
-
- if (v3d->ver >= 40) {
- V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
-@@ -210,6 +215,9 @@ static int v3d_measure_clock(struct seq_
- cycles / (measure_ms * 1000),
- (cycles / (measure_ms * 100)) % 10);
-
-+ pm_runtime_mark_last_busy(v3d->dev);
-+ pm_runtime_put_autosuspend(v3d->dev);
-+
- return 0;
- }
-
--- /dev/null
+From f389abea861f9bd3165f98a8d3a1f3407e9fc01a Mon Sep 17 00:00:00 2001
+Date: Mon, 14 Jan 2019 12:35:43 -0800
+Subject: [PATCH] drm/v3d: Skip MMU flush if the device is currently
+ off.
+
+If it's off, we know it will be reset on poweron, so the MMU won't
+have any TLB cached from before this point. Avoids failed waits for
+MMU flush to reply.
+
+(cherry picked from commit 3ee4e2e0a9e9587eacbb69b067bbc72ab2cdc47b)
+---
+ drivers/gpu/drm/v3d/v3d_mmu.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_mmu.c
++++ b/drivers/gpu/drm/v3d/v3d_mmu.c
+@@ -18,6 +18,8 @@
+ * each client. This is not yet implemented.
+ */
+
++#include <linux/pm_runtime.h>
++
+ #include "v3d_drv.h"
+ #include "v3d_regs.h"
+
+@@ -34,6 +36,14 @@ static int v3d_mmu_flush_all(struct v3d_
+ {
+ int ret;
+
++ /* Keep power on the device on until we're done with this
++ * call, but skip the flush if the device is off and will be
++ * reset when powered back on.
++ */
++ ret = pm_runtime_get_if_in_use(v3d->dev);
++ if (ret == 0)
++ return 0;
++
+ /* Make sure that another flush isn't already running when we
+ * start this one.
+ */
+@@ -61,6 +71,9 @@ static int v3d_mmu_flush_all(struct v3d_
+ if (ret)
+ dev_err(v3d->dev, "MMUC flush wait idle failed\n");
+
++ pm_runtime_mark_last_busy(v3d->dev);
++ pm_runtime_put_autosuspend(v3d->dev);
++
+ return ret;
+ }
+
+++ /dev/null
-From ffd9543f2d74e9215996ce6500fc34dcf7976462 Mon Sep 17 00:00:00 2001
-Date: Thu, 4 Oct 2018 17:22:43 -0700
-Subject: [PATCH] drm/v3d: Add support for 2711.
-
----
- drivers/gpu/drm/v3d/v3d_drv.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -235,6 +235,7 @@ static struct drm_driver v3d_drm_driver
- static const struct of_device_id v3d_of_match[] = {
- { .compatible = "brcm,7268-v3d" },
- { .compatible = "brcm,7278-v3d" },
-+ { .compatible = "brcm,2711-v3d" },
- {},
- };
- MODULE_DEVICE_TABLE(of, v3d_of_match);
--- /dev/null
+From 30dd82d785715b2ed52a5079595ffcd2ec1f728d Mon Sep 17 00:00:00 2001
+Date: Mon, 14 Jan 2019 14:47:57 -0800
+Subject: [PATCH] drm/v3d: Hook up the runtime PM ops.
+
+In translating the runtime PM code from vc4, I missed the ".pm"
+assignment to actually connect them up. Fixes missing MMU setup if
+runtime PM resets V3D.
+
+(cherry picked from commit ca197699af29baa8236c74c53d4904ca8957ee06)
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -66,7 +66,7 @@ static int v3d_runtime_resume(struct dev
+ }
+ #endif
+
+-static const struct dev_pm_ops v3d_v3d_pm_ops = {
++static const struct dev_pm_ops v3d_pm_ops = {
+ SET_RUNTIME_PM_OPS(v3d_runtime_suspend, v3d_runtime_resume, NULL)
+ };
+
+@@ -371,6 +371,7 @@ static struct platform_driver v3d_platfo
+ .driver = {
+ .name = "v3d",
+ .of_match_table = v3d_of_match,
++ .pm = &v3d_pm_ops,
+ },
+ };
+
--- /dev/null
+From 2d4f38abdc2a919d8002fbec7bc0be7c1312786a Mon Sep 17 00:00:00 2001
+Date: Mon, 14 Jan 2019 15:13:17 -0800
+Subject: [PATCH] drm/v3d: HACK: gut runtime pm for now.
+
+Something is still unstable -- on starting a new glxgears from an idle
+X11, I get an MMU violation in high addresses. The CTS also failed
+quite quickly. With this, CTS progresses for an hour before OOMing
+(allocating some big buffers when my board only has 600MB available to
+Linux)
+
+---
+ drivers/gpu/drm/v3d/v3d_debugfs.c | 16 +---------------
+ drivers/gpu/drm/v3d/v3d_drv.c | 7 -------
+ drivers/gpu/drm/v3d/v3d_gem.c | 20 --------------------
+ 3 files changed, 1 insertion(+), 42 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
++++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
+@@ -4,7 +4,6 @@
+ #include <linux/circ_buf.h>
+ #include <linux/ctype.h>
+ #include <linux/debugfs.h>
+-#include <linux/pm_runtime.h>
+ #include <linux/seq_file.h>
+ #include <drm/drmP.h>
+
+@@ -100,11 +99,8 @@ static int v3d_v3d_debugfs_ident(struct
+ struct drm_device *dev = node->minor->dev;
+ struct v3d_dev *v3d = to_v3d_dev(dev);
+ u32 ident0, ident1, ident2, ident3, cores;
+- int ret, core;
++ int core;
+
+- ret = pm_runtime_get_sync(v3d->dev);
+- if (ret < 0)
+- return ret;
+
+ ident0 = V3D_READ(V3D_HUB_IDENT0);
+ ident1 = V3D_READ(V3D_HUB_IDENT1);
+@@ -157,9 +153,6 @@ static int v3d_v3d_debugfs_ident(struct
+ (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0);
+ }
+
+- pm_runtime_mark_last_busy(v3d->dev);
+- pm_runtime_put_autosuspend(v3d->dev);
+-
+ return 0;
+ }
+
+@@ -187,11 +180,6 @@ static int v3d_measure_clock(struct seq_
+ uint32_t cycles;
+ int core = 0;
+ int measure_ms = 1000;
+- int ret;
+-
+- ret = pm_runtime_get_sync(v3d->dev);
+- if (ret < 0)
+- return ret;
+
+ if (v3d->ver >= 40) {
+ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
+@@ -215,8 +203,6 @@ static int v3d_measure_clock(struct seq_
+ cycles / (measure_ms * 1000),
+ (cycles / (measure_ms * 100)) % 10);
+
+- pm_runtime_mark_last_busy(v3d->dev);
+- pm_runtime_put_autosuspend(v3d->dev);
+
+ return 0;
+ }
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -75,7 +75,6 @@ static int v3d_get_param_ioctl(struct dr
+ {
+ struct v3d_dev *v3d = to_v3d_dev(dev);
+ struct drm_v3d_get_param *args = data;
+- int ret;
+ static const u32 reg_map[] = {
+ [DRM_V3D_PARAM_V3D_UIFCFG] = V3D_HUB_UIFCFG,
+ [DRM_V3D_PARAM_V3D_HUB_IDENT1] = V3D_HUB_IDENT1,
+@@ -101,15 +100,12 @@ static int v3d_get_param_ioctl(struct dr
+ if (args->value != 0)
+ return -EINVAL;
+
+- ret = pm_runtime_get_sync(v3d->dev);
+ if (args->param >= DRM_V3D_PARAM_V3D_CORE0_IDENT0 &&
+ args->param <= DRM_V3D_PARAM_V3D_CORE0_IDENT2) {
+ args->value = V3D_CORE_READ(0, offset);
+ } else {
+ args->value = V3D_READ(offset);
+ }
+- pm_runtime_mark_last_busy(v3d->dev);
+- pm_runtime_put_autosuspend(v3d->dev);
+ return 0;
+ }
+
+@@ -311,9 +307,6 @@ static int v3d_platform_drm_probe(struct
+ goto dev_free;
+ }
+
+- pm_runtime_use_autosuspend(dev);
+- pm_runtime_set_autosuspend_delay(dev, 50);
+- pm_runtime_enable(dev);
+
+ ret = drm_dev_init(&v3d->drm, &v3d_drm_driver, dev);
+ if (ret)
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -375,7 +375,6 @@ v3d_exec_cleanup(struct kref *ref)
+ {
+ struct v3d_exec_info *exec = container_of(ref, struct v3d_exec_info,
+ refcount);
+- struct v3d_dev *v3d = exec->v3d;
+ unsigned int i;
+ struct v3d_bo *bo, *save;
+
+@@ -396,9 +395,6 @@ v3d_exec_cleanup(struct kref *ref)
+ drm_gem_object_put_unlocked(&bo->base);
+ }
+
+- pm_runtime_mark_last_busy(v3d->dev);
+- pm_runtime_put_autosuspend(v3d->dev);
+-
+ kfree(exec);
+ }
+
+@@ -412,7 +408,6 @@ v3d_tfu_job_cleanup(struct kref *ref)
+ {
+ struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job,
+ refcount);
+- struct v3d_dev *v3d = job->v3d;
+ unsigned int i;
+
+ dma_fence_put(job->in_fence);
+@@ -423,9 +418,6 @@ v3d_tfu_job_cleanup(struct kref *ref)
+ drm_gem_object_put_unlocked(&job->bo[i]->base);
+ }
+
+- pm_runtime_mark_last_busy(v3d->dev);
+- pm_runtime_put_autosuspend(v3d->dev);
+-
+ kfree(job);
+ }
+
+@@ -519,12 +511,6 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ if (!exec)
+ return -ENOMEM;
+
+- ret = pm_runtime_get_sync(v3d->dev);
+- if (ret < 0) {
+- kfree(exec);
+- return ret;
+- }
+-
+ kref_init(&exec->refcount);
+
+ ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
+@@ -643,12 +629,6 @@ v3d_submit_tfu_ioctl(struct drm_device *
+ if (!job)
+ return -ENOMEM;
+
+- ret = pm_runtime_get_sync(v3d->dev);
+- if (ret < 0) {
+- kfree(job);
+- return ret;
+- }
+-
+ kref_init(&job->refcount);
+
+ ret = drm_syncobj_find_fence(file_priv, args->in_sync,
+++ /dev/null
-From f389abea861f9bd3165f98a8d3a1f3407e9fc01a Mon Sep 17 00:00:00 2001
-Date: Mon, 14 Jan 2019 12:35:43 -0800
-Subject: [PATCH] drm/v3d: Skip MMU flush if the device is currently
- off.
-
-If it's off, we know it will be reset on poweron, so the MMU won't
-have any TLB cached from before this point. Avoids failed waits for
-MMU flush to reply.
-
-(cherry picked from commit 3ee4e2e0a9e9587eacbb69b067bbc72ab2cdc47b)
----
- drivers/gpu/drm/v3d/v3d_mmu.c | 13 +++++++++++++
- 1 file changed, 13 insertions(+)
-
---- a/drivers/gpu/drm/v3d/v3d_mmu.c
-+++ b/drivers/gpu/drm/v3d/v3d_mmu.c
-@@ -18,6 +18,8 @@
- * each client. This is not yet implemented.
- */
-
-+#include <linux/pm_runtime.h>
-+
- #include "v3d_drv.h"
- #include "v3d_regs.h"
-
-@@ -34,6 +36,14 @@ static int v3d_mmu_flush_all(struct v3d_
- {
- int ret;
-
-+ /* Keep power on the device on until we're done with this
-+ * call, but skip the flush if the device is off and will be
-+ * reset when powered back on.
-+ */
-+ ret = pm_runtime_get_if_in_use(v3d->dev);
-+ if (ret == 0)
-+ return 0;
-+
- /* Make sure that another flush isn't already running when we
- * start this one.
- */
-@@ -61,6 +71,9 @@ static int v3d_mmu_flush_all(struct v3d_
- if (ret)
- dev_err(v3d->dev, "MMUC flush wait idle failed\n");
-
-+ pm_runtime_mark_last_busy(v3d->dev);
-+ pm_runtime_put_autosuspend(v3d->dev);
-+
- return ret;
- }
-
+++ /dev/null
-From 30dd82d785715b2ed52a5079595ffcd2ec1f728d Mon Sep 17 00:00:00 2001
-Date: Mon, 14 Jan 2019 14:47:57 -0800
-Subject: [PATCH] drm/v3d: Hook up the runtime PM ops.
-
-In translating the runtime PM code from vc4, I missed the ".pm"
-assignment to actually connect them up. Fixes missing MMU setup if
-runtime PM resets V3D.
-
-(cherry picked from commit ca197699af29baa8236c74c53d4904ca8957ee06)
----
- drivers/gpu/drm/v3d/v3d_drv.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -66,7 +66,7 @@ static int v3d_runtime_resume(struct dev
- }
- #endif
-
--static const struct dev_pm_ops v3d_v3d_pm_ops = {
-+static const struct dev_pm_ops v3d_pm_ops = {
- SET_RUNTIME_PM_OPS(v3d_runtime_suspend, v3d_runtime_resume, NULL)
- };
-
-@@ -371,6 +371,7 @@ static struct platform_driver v3d_platfo
- .driver = {
- .name = "v3d",
- .of_match_table = v3d_of_match,
-+ .pm = &v3d_pm_ops,
- },
- };
-
--- /dev/null
+From 50088003d803f04e536eb09ac2635df35b5c8ae4 Mon Sep 17 00:00:00 2001
+Date: Tue, 12 Mar 2019 09:08:10 -0700
+Subject: [PATCH] drm/v3d: Update to upstream IRQ code.
+
+---
+ drivers/gpu/drm/v3d/v3d_irq.c | 25 +++++++++++++++----------
+ 1 file changed, 15 insertions(+), 10 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_irq.c
++++ b/drivers/gpu/drm/v3d/v3d_irq.c
+@@ -168,7 +168,7 @@ v3d_hub_irq(int irq, void *arg)
+ int
+ v3d_irq_init(struct v3d_dev *v3d)
+ {
+- int ret, core;
++ int irq1, ret, core;
+
+ INIT_WORK(&v3d->overflow_mem_work, v3d_overflow_mem_work);
+
+@@ -179,24 +179,29 @@ v3d_irq_init(struct v3d_dev *v3d)
+ V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS);
+ V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS);
+
+- if (platform_get_irq(v3d->pdev, 1) < 0) {
+- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
++ irq1 = platform_get_irq(v3d->pdev, 1);
++ if (irq1 == -EPROBE_DEFER)
++ return irq1;
++ if (irq1 > 0) {
++ ret = devm_request_irq(v3d->dev, irq1,
+ v3d_irq, IRQF_SHARED,
+- "v3d", v3d);
+- v3d->single_irq_line = true;
+- } else {
++ "v3d_core0", v3d);
++ if (ret)
++ goto fail;
+ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
+ v3d_hub_irq, IRQF_SHARED,
+ "v3d_hub", v3d);
+ if (ret)
+ goto fail;
++ } else {
++ v3d->single_irq_line = true;
+
+- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 1),
++ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
+ v3d_irq, IRQF_SHARED,
+- "v3d_core0", v3d);
++ "v3d", v3d);
++ if (ret)
++ goto fail;
+ }
+- if (ret)
+- goto fail;
+
+ v3d_irq_enable(v3d);
+ return 0;
+++ /dev/null
-From 2d4f38abdc2a919d8002fbec7bc0be7c1312786a Mon Sep 17 00:00:00 2001
-Date: Mon, 14 Jan 2019 15:13:17 -0800
-Subject: [PATCH] drm/v3d: HACK: gut runtime pm for now.
-
-Something is still unstable -- on starting a new glxgears from an idle
-X11, I get an MMU violation in high addresses. The CTS also failed
-quite quickly. With this, CTS progresses for an hour before OOMing
-(allocating some big buffers when my board only has 600MB available to
-Linux)
-
----
- drivers/gpu/drm/v3d/v3d_debugfs.c | 16 +---------------
- drivers/gpu/drm/v3d/v3d_drv.c | 7 -------
- drivers/gpu/drm/v3d/v3d_gem.c | 20 --------------------
- 3 files changed, 1 insertion(+), 42 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_debugfs.c
-+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
-@@ -4,7 +4,6 @@
- #include <linux/circ_buf.h>
- #include <linux/ctype.h>
- #include <linux/debugfs.h>
--#include <linux/pm_runtime.h>
- #include <linux/seq_file.h>
- #include <drm/drmP.h>
-
-@@ -100,11 +99,8 @@ static int v3d_v3d_debugfs_ident(struct
- struct drm_device *dev = node->minor->dev;
- struct v3d_dev *v3d = to_v3d_dev(dev);
- u32 ident0, ident1, ident2, ident3, cores;
-- int ret, core;
-+ int core;
-
-- ret = pm_runtime_get_sync(v3d->dev);
-- if (ret < 0)
-- return ret;
-
- ident0 = V3D_READ(V3D_HUB_IDENT0);
- ident1 = V3D_READ(V3D_HUB_IDENT1);
-@@ -157,9 +153,6 @@ static int v3d_v3d_debugfs_ident(struct
- (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0);
- }
-
-- pm_runtime_mark_last_busy(v3d->dev);
-- pm_runtime_put_autosuspend(v3d->dev);
--
- return 0;
- }
-
-@@ -187,11 +180,6 @@ static int v3d_measure_clock(struct seq_
- uint32_t cycles;
- int core = 0;
- int measure_ms = 1000;
-- int ret;
--
-- ret = pm_runtime_get_sync(v3d->dev);
-- if (ret < 0)
-- return ret;
-
- if (v3d->ver >= 40) {
- V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
-@@ -215,8 +203,6 @@ static int v3d_measure_clock(struct seq_
- cycles / (measure_ms * 1000),
- (cycles / (measure_ms * 100)) % 10);
-
-- pm_runtime_mark_last_busy(v3d->dev);
-- pm_runtime_put_autosuspend(v3d->dev);
-
- return 0;
- }
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -75,7 +75,6 @@ static int v3d_get_param_ioctl(struct dr
- {
- struct v3d_dev *v3d = to_v3d_dev(dev);
- struct drm_v3d_get_param *args = data;
-- int ret;
- static const u32 reg_map[] = {
- [DRM_V3D_PARAM_V3D_UIFCFG] = V3D_HUB_UIFCFG,
- [DRM_V3D_PARAM_V3D_HUB_IDENT1] = V3D_HUB_IDENT1,
-@@ -101,15 +100,12 @@ static int v3d_get_param_ioctl(struct dr
- if (args->value != 0)
- return -EINVAL;
-
-- ret = pm_runtime_get_sync(v3d->dev);
- if (args->param >= DRM_V3D_PARAM_V3D_CORE0_IDENT0 &&
- args->param <= DRM_V3D_PARAM_V3D_CORE0_IDENT2) {
- args->value = V3D_CORE_READ(0, offset);
- } else {
- args->value = V3D_READ(offset);
- }
-- pm_runtime_mark_last_busy(v3d->dev);
-- pm_runtime_put_autosuspend(v3d->dev);
- return 0;
- }
-
-@@ -311,9 +307,6 @@ static int v3d_platform_drm_probe(struct
- goto dev_free;
- }
-
-- pm_runtime_use_autosuspend(dev);
-- pm_runtime_set_autosuspend_delay(dev, 50);
-- pm_runtime_enable(dev);
-
- ret = drm_dev_init(&v3d->drm, &v3d_drm_driver, dev);
- if (ret)
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -375,7 +375,6 @@ v3d_exec_cleanup(struct kref *ref)
- {
- struct v3d_exec_info *exec = container_of(ref, struct v3d_exec_info,
- refcount);
-- struct v3d_dev *v3d = exec->v3d;
- unsigned int i;
- struct v3d_bo *bo, *save;
-
-@@ -396,9 +395,6 @@ v3d_exec_cleanup(struct kref *ref)
- drm_gem_object_put_unlocked(&bo->base);
- }
-
-- pm_runtime_mark_last_busy(v3d->dev);
-- pm_runtime_put_autosuspend(v3d->dev);
--
- kfree(exec);
- }
-
-@@ -412,7 +408,6 @@ v3d_tfu_job_cleanup(struct kref *ref)
- {
- struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job,
- refcount);
-- struct v3d_dev *v3d = job->v3d;
- unsigned int i;
-
- dma_fence_put(job->in_fence);
-@@ -423,9 +418,6 @@ v3d_tfu_job_cleanup(struct kref *ref)
- drm_gem_object_put_unlocked(&job->bo[i]->base);
- }
-
-- pm_runtime_mark_last_busy(v3d->dev);
-- pm_runtime_put_autosuspend(v3d->dev);
--
- kfree(job);
- }
-
-@@ -519,12 +511,6 @@ v3d_submit_cl_ioctl(struct drm_device *d
- if (!exec)
- return -ENOMEM;
-
-- ret = pm_runtime_get_sync(v3d->dev);
-- if (ret < 0) {
-- kfree(exec);
-- return ret;
-- }
--
- kref_init(&exec->refcount);
-
- ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
-@@ -643,12 +629,6 @@ v3d_submit_tfu_ioctl(struct drm_device *
- if (!job)
- return -ENOMEM;
-
-- ret = pm_runtime_get_sync(v3d->dev);
-- if (ret < 0) {
-- kfree(job);
-- return ret;
-- }
--
- kref_init(&job->refcount);
-
- ret = drm_syncobj_find_fence(file_priv, args->in_sync,
--- /dev/null
+From 0d00e0340c1aa9ce36bdff46f927916fe4903cee Mon Sep 17 00:00:00 2001
+Date: Thu, 27 Dec 2018 14:04:44 -0800
+Subject: [PATCH] drm/v3d: Rename the fence signaled from IRQs to
+ "irq_fence".
+
+We have another thing called the "done fence" that tracks when the
+scheduler considers the job done, and having the shared name was
+confusing.
+
+---
+ drivers/gpu/drm/v3d/v3d_drv.h | 4 ++--
+ drivers/gpu/drm/v3d/v3d_gem.c | 6 +++---
+ drivers/gpu/drm/v3d/v3d_irq.c | 6 +++---
+ drivers/gpu/drm/v3d/v3d_sched.c | 12 ++++++------
+ 4 files changed, 14 insertions(+), 14 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.h
++++ b/drivers/gpu/drm/v3d/v3d_drv.h
+@@ -182,7 +182,7 @@ struct v3d_job {
+ struct dma_fence *in_fence;
+
+ /* v3d fence to be signaled by IRQ handler when the job is complete. */
+- struct dma_fence *done_fence;
++ struct dma_fence *irq_fence;
+
+ /* GPU virtual addresses of the start/end of the CL job. */
+ u32 start, end;
+@@ -229,7 +229,7 @@ struct v3d_tfu_job {
+ struct dma_fence *in_fence;
+
+ /* v3d fence to be signaled by IRQ handler when the job is complete. */
+- struct dma_fence *done_fence;
++ struct dma_fence *irq_fence;
+
+ struct v3d_dev *v3d;
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -381,8 +381,8 @@ v3d_exec_cleanup(struct kref *ref)
+ dma_fence_put(exec->bin.in_fence);
+ dma_fence_put(exec->render.in_fence);
+
+- dma_fence_put(exec->bin.done_fence);
+- dma_fence_put(exec->render.done_fence);
++ dma_fence_put(exec->bin.irq_fence);
++ dma_fence_put(exec->render.irq_fence);
+
+ dma_fence_put(exec->bin_done_fence);
+ dma_fence_put(exec->render_done_fence);
+@@ -411,7 +411,7 @@ v3d_tfu_job_cleanup(struct kref *ref)
+ unsigned int i;
+
+ dma_fence_put(job->in_fence);
+- dma_fence_put(job->done_fence);
++ dma_fence_put(job->irq_fence);
+
+ for (i = 0; i < ARRAY_SIZE(job->bo); i++) {
+ if (job->bo[i])
+--- a/drivers/gpu/drm/v3d/v3d_irq.c
++++ b/drivers/gpu/drm/v3d/v3d_irq.c
+@@ -93,7 +93,7 @@ v3d_irq(int irq, void *arg)
+
+ if (intsts & V3D_INT_FLDONE) {
+ struct v3d_fence *fence =
+- to_v3d_fence(v3d->bin_job->bin.done_fence);
++ to_v3d_fence(v3d->bin_job->bin.irq_fence);
+
+ trace_v3d_bcl_irq(&v3d->drm, fence->seqno);
+ dma_fence_signal(&fence->base);
+@@ -102,7 +102,7 @@ v3d_irq(int irq, void *arg)
+
+ if (intsts & V3D_INT_FRDONE) {
+ struct v3d_fence *fence =
+- to_v3d_fence(v3d->render_job->render.done_fence);
++ to_v3d_fence(v3d->render_job->render.irq_fence);
+
+ trace_v3d_rcl_irq(&v3d->drm, fence->seqno);
+ dma_fence_signal(&fence->base);
+@@ -138,7 +138,7 @@ v3d_hub_irq(int irq, void *arg)
+
+ if (intsts & V3D_HUB_INT_TFUC) {
+ struct v3d_fence *fence =
+- to_v3d_fence(v3d->tfu_job->done_fence);
++ to_v3d_fence(v3d->tfu_job->irq_fence);
+
+ trace_v3d_tfu_irq(&v3d->drm, fence->seqno);
+ dma_fence_signal(&fence->base);
+--- a/drivers/gpu/drm/v3d/v3d_sched.c
++++ b/drivers/gpu/drm/v3d/v3d_sched.c
+@@ -152,9 +152,9 @@ static struct dma_fence *v3d_job_run(str
+ if (IS_ERR(fence))
+ return NULL;
+
+- if (job->done_fence)
+- dma_fence_put(job->done_fence);
+- job->done_fence = dma_fence_get(fence);
++ if (job->irq_fence)
++ dma_fence_put(job->irq_fence);
++ job->irq_fence = dma_fence_get(fence);
+
+ trace_v3d_submit_cl(dev, q == V3D_RENDER, to_v3d_fence(fence)->seqno,
+ job->start, job->end);
+@@ -195,9 +195,9 @@ v3d_tfu_job_run(struct drm_sched_job *sc
+ return NULL;
+
+ v3d->tfu_job = job;
+- if (job->done_fence)
+- dma_fence_put(job->done_fence);
+- job->done_fence = dma_fence_get(fence);
++ if (job->irq_fence)
++ dma_fence_put(job->irq_fence);
++ job->irq_fence = dma_fence_get(fence);
+
+ trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);
+
--- /dev/null
+From ccf319a0265bfdb4a622a52645f159461bc88079 Mon Sep 17 00:00:00 2001
+Date: Thu, 27 Dec 2018 12:11:52 -0800
+Subject: [PATCH] drm/v3d: Refactor job management.
+
+The CL submission had two jobs embedded in an exec struct. When I
+added TFU support, I had to replicate some of the exec stuff and some
+of the job stuff. As I went to add CSD, it became clear that actually
+what was in exec should just be in the two CL jobs, and it would let
+us share a lot more code between the 4 queues.
+
+---
+ drivers/gpu/drm/v3d/v3d_drv.h | 77 ++++----
+ drivers/gpu/drm/v3d/v3d_gem.c | 331 +++++++++++++++++---------------
+ drivers/gpu/drm/v3d/v3d_irq.c | 8 +-
+ drivers/gpu/drm/v3d/v3d_sched.c | 264 ++++++++++++++-----------
+ 4 files changed, 373 insertions(+), 307 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.h
++++ b/drivers/gpu/drm/v3d/v3d_drv.h
+@@ -67,8 +67,8 @@ struct v3d_dev {
+
+ struct work_struct overflow_mem_work;
+
+- struct v3d_exec_info *bin_job;
+- struct v3d_exec_info *render_job;
++ struct v3d_bin_job *bin_job;
++ struct v3d_render_job *render_job;
+ struct v3d_tfu_job *tfu_job;
+
+ struct v3d_queue_state queue[V3D_MAX_QUEUES];
+@@ -132,7 +132,7 @@ struct v3d_bo {
+ struct list_head vmas; /* list of v3d_vma */
+
+ /* List entry for the BO's position in
+- * v3d_exec_info->unref_list
++ * v3d_render_job->unref_list
+ */
+ struct list_head unref_head;
+
+@@ -176,7 +176,15 @@ to_v3d_fence(struct dma_fence *fence)
+ struct v3d_job {
+ struct drm_sched_job base;
+
+- struct v3d_exec_info *exec;
++ struct kref refcount;
++
++ struct v3d_dev *v3d;
++
++ /* This is the array of BOs that were looked up at the start
++ * of submission.
++ */
++ struct v3d_bo **bo;
++ u32 bo_count;
+
+ /* An optional fence userspace can pass in for the job to depend on. */
+ struct dma_fence *in_fence;
+@@ -184,59 +192,53 @@ struct v3d_job {
+ /* v3d fence to be signaled by IRQ handler when the job is complete. */
+ struct dma_fence *irq_fence;
+
++ /* scheduler fence for when the job is considered complete and
++ * the BO reservations can be released.
++ */
++ struct dma_fence *done_fence;
++
++ /* Callback for the freeing of the job on refcount going to 0. */
++ void (*free)(struct kref *ref);
++};
++
++struct v3d_bin_job {
++ struct v3d_job base;
++
+ /* GPU virtual addresses of the start/end of the CL job. */
+ u32 start, end;
+
+ u32 timedout_ctca, timedout_ctra;
+-};
+
+-struct v3d_exec_info {
+- struct v3d_dev *v3d;
++ /* Corresponding render job, for attaching our overflow memory. */
++ struct v3d_render_job *render;
++
++ /* Submitted tile memory allocation start/size, tile state. */
++ u32 qma, qms, qts;
++};
+
+- struct v3d_job bin, render;
++struct v3d_render_job {
++ struct v3d_job base;
+
+- /* Fence for when the scheduler considers the binner to be
+- * done, for render to depend on.
++ /* Optional fence for the binner, to depend on before starting
++ * our job.
+ */
+ struct dma_fence *bin_done_fence;
+
+- /* Fence for when the scheduler considers the render to be
+- * done, for when the BOs reservations should be complete.
+- */
+- struct dma_fence *render_done_fence;
+-
+- struct kref refcount;
++ /* GPU virtual addresses of the start/end of the CL job. */
++ u32 start, end;
+
+- /* This is the array of BOs that were looked up at the start of exec. */
+- struct v3d_bo **bo;
+- u32 bo_count;
++ u32 timedout_ctca, timedout_ctra;
+
+ /* List of overflow BOs used in the job that need to be
+ * released once the job is complete.
+ */
+ struct list_head unref_list;
+-
+- /* Submitted tile memory allocation start/size, tile state. */
+- u32 qma, qms, qts;
+ };
+
+ struct v3d_tfu_job {
+- struct drm_sched_job base;
++ struct v3d_job base;
+
+ struct drm_v3d_submit_tfu args;
+-
+- /* An optional fence userspace can pass in for the job to depend on. */
+- struct dma_fence *in_fence;
+-
+- /* v3d fence to be signaled by IRQ handler when the job is complete. */
+- struct dma_fence *irq_fence;
+-
+- struct v3d_dev *v3d;
+-
+- struct kref refcount;
+-
+- /* This is the array of BOs that were looked up at the start of exec. */
+- struct v3d_bo *bo[4];
+ };
+
+ /**
+@@ -306,8 +308,7 @@ int v3d_submit_tfu_ioctl(struct drm_devi
+ struct drm_file *file_priv);
+ int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+-void v3d_exec_put(struct v3d_exec_info *exec);
+-void v3d_tfu_job_put(struct v3d_tfu_job *exec);
++void v3d_job_put(struct v3d_job *job);
+ void v3d_reset(struct v3d_dev *v3d);
+ void v3d_invalidate_caches(struct v3d_dev *v3d);
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -293,11 +293,11 @@ retry:
+ }
+
+ /**
+- * v3d_cl_lookup_bos() - Sets up exec->bo[] with the GEM objects
++ * v3d_lookup_bos() - Sets up job->bo[] with the GEM objects
+ * referenced by the job.
+ * @dev: DRM device
+ * @file_priv: DRM file for this fd
+- * @exec: V3D job being set up
++ * @job: V3D job being set up
+ *
+ * The command validator needs to reference BOs by their index within
+ * the submitted job's BO list. This does the validation of the job's
+@@ -307,18 +307,19 @@ retry:
+ * failure, because that will happen at v3d_exec_cleanup() time.
+ */
+ static int
+-v3d_cl_lookup_bos(struct drm_device *dev,
+- struct drm_file *file_priv,
+- struct drm_v3d_submit_cl *args,
+- struct v3d_exec_info *exec)
++v3d_lookup_bos(struct drm_device *dev,
++ struct drm_file *file_priv,
++ struct v3d_job *job,
++ u64 bo_handles,
++ u32 bo_count)
+ {
+ u32 *handles;
+ int ret = 0;
+ int i;
+
+- exec->bo_count = args->bo_handle_count;
++ job->bo_count = bo_count;
+
+- if (!exec->bo_count) {
++ if (!job->bo_count) {
+ /* See comment on bo_index for why we have to check
+ * this.
+ */
+@@ -326,15 +327,15 @@ v3d_cl_lookup_bos(struct drm_device *dev
+ return -EINVAL;
+ }
+
+- exec->bo = kvmalloc_array(exec->bo_count,
+- sizeof(struct drm_gem_cma_object *),
+- GFP_KERNEL | __GFP_ZERO);
+- if (!exec->bo) {
++ job->bo = kvmalloc_array(job->bo_count,
++ sizeof(struct drm_gem_cma_object *),
++ GFP_KERNEL | __GFP_ZERO);
++ if (!job->bo) {
+ DRM_DEBUG("Failed to allocate validated BO pointers\n");
+ return -ENOMEM;
+ }
+
+- handles = kvmalloc_array(exec->bo_count, sizeof(u32), GFP_KERNEL);
++ handles = kvmalloc_array(job->bo_count, sizeof(u32), GFP_KERNEL);
+ if (!handles) {
+ ret = -ENOMEM;
+ DRM_DEBUG("Failed to allocate incoming GEM handles\n");
+@@ -342,15 +343,15 @@ v3d_cl_lookup_bos(struct drm_device *dev
+ }
+
+ if (copy_from_user(handles,
+- (void __user *)(uintptr_t)args->bo_handles,
+- exec->bo_count * sizeof(u32))) {
++ (void __user *)(uintptr_t)bo_handles,
++ job->bo_count * sizeof(u32))) {
+ ret = -EFAULT;
+ DRM_DEBUG("Failed to copy in GEM handles\n");
+ goto fail;
+ }
+
+ spin_lock(&file_priv->table_lock);
+- for (i = 0; i < exec->bo_count; i++) {
++ for (i = 0; i < job->bo_count; i++) {
+ struct drm_gem_object *bo = idr_find(&file_priv->object_idr,
+ handles[i]);
+ if (!bo) {
+@@ -361,7 +362,7 @@ v3d_cl_lookup_bos(struct drm_device *dev
+ goto fail;
+ }
+ drm_gem_object_get(bo);
+- exec->bo[i] = to_v3d_bo(bo);
++ job->bo[i] = to_v3d_bo(bo);
+ }
+ spin_unlock(&file_priv->table_lock);
+
+@@ -371,59 +372,41 @@ fail:
+ }
+
+ static void
+-v3d_exec_cleanup(struct kref *ref)
++v3d_job_free(struct kref *ref)
+ {
+- struct v3d_exec_info *exec = container_of(ref, struct v3d_exec_info,
+- refcount);
+- unsigned int i;
+- struct v3d_bo *bo, *save;
+-
+- dma_fence_put(exec->bin.in_fence);
+- dma_fence_put(exec->render.in_fence);
+-
+- dma_fence_put(exec->bin.irq_fence);
+- dma_fence_put(exec->render.irq_fence);
+-
+- dma_fence_put(exec->bin_done_fence);
+- dma_fence_put(exec->render_done_fence);
+-
+- for (i = 0; i < exec->bo_count; i++)
+- drm_gem_object_put_unlocked(&exec->bo[i]->base);
+- kvfree(exec->bo);
++ struct v3d_job *job = container_of(ref, struct v3d_job, refcount);
++ int i;
+
+- list_for_each_entry_safe(bo, save, &exec->unref_list, unref_head) {
+- drm_gem_object_put_unlocked(&bo->base);
++ for (i = 0; i < job->bo_count; i++) {
++ if (job->bo[i])
++ drm_gem_object_put_unlocked(&job->bo[i]->base);
+ }
++ kvfree(job->bo);
+
+- kfree(exec);
+-}
++ dma_fence_put(job->in_fence);
++ dma_fence_put(job->irq_fence);
++ dma_fence_put(job->done_fence);
+
+-void v3d_exec_put(struct v3d_exec_info *exec)
+-{
+- kref_put(&exec->refcount, v3d_exec_cleanup);
++ kfree(job);
+ }
+
+ static void
+-v3d_tfu_job_cleanup(struct kref *ref)
++v3d_render_job_free(struct kref *ref)
+ {
+- struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job,
+- refcount);
+- unsigned int i;
+-
+- dma_fence_put(job->in_fence);
+- dma_fence_put(job->irq_fence);
++ struct v3d_render_job *job = container_of(ref, struct v3d_render_job,
++ base.refcount);
++ struct v3d_bo *bo, *save;
+
+- for (i = 0; i < ARRAY_SIZE(job->bo); i++) {
+- if (job->bo[i])
+- drm_gem_object_put_unlocked(&job->bo[i]->base);
++ list_for_each_entry_safe(bo, save, &job->unref_list, unref_head) {
++ drm_gem_object_put_unlocked(&bo->base);
+ }
+
+- kfree(job);
++ v3d_job_free(ref);
+ }
+
+-void v3d_tfu_job_put(struct v3d_tfu_job *job)
++void v3d_job_put(struct v3d_job *job)
+ {
+- kref_put(&job->refcount, v3d_tfu_job_cleanup);
++ kref_put(&job->refcount, job->free);
+ }
+
+ int
+@@ -476,6 +459,65 @@ v3d_wait_bo_ioctl(struct drm_device *dev
+ return ret;
+ }
+
++static int
++v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv,
++ struct v3d_job *job, void (*free)(struct kref *ref),
++ u32 in_sync)
++{
++ int ret;
++
++ job->v3d = v3d;
++ job->free = free;
++
++ ret = drm_syncobj_find_fence(file_priv, in_sync, 0, &job->in_fence);
++ if (ret == -EINVAL)
++ return ret;
++
++ kref_init(&job->refcount);
++
++ return 0;
++}
++
++static int
++v3d_push_job(struct v3d_file_priv *v3d_priv,
++ struct v3d_job *job, enum v3d_queue queue)
++{
++ int ret;
++
++ ret = drm_sched_job_init(&job->base, &v3d_priv->sched_entity[queue],
++ v3d_priv);
++ if (ret)
++ return ret;
++
++ job->done_fence = dma_fence_get(&job->base.s_fence->finished);
++
++ /* put by scheduler job completion */
++ kref_get(&job->refcount);
++
++ drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[queue]);
++
++ return 0;
++}
++
++static void
++v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv,
++ struct v3d_job *job,
++ struct ww_acquire_ctx *acquire_ctx,
++ u32 out_sync)
++{
++ struct drm_syncobj *sync_out;
++
++ v3d_attach_object_fences(job->bo, job->bo_count, job->done_fence);
++ v3d_unlock_bo_reservations(job->bo, job->bo_count, acquire_ctx);
++
++ /* Update the return sync object for the job */
++ sync_out = drm_syncobj_find(file_priv, out_sync);
++ if (sync_out) {
++ drm_syncobj_replace_fence(sync_out, job->done_fence);
++ drm_syncobj_put(sync_out);
++ }
++}
++
+ /**
+ * v3d_submit_cl_ioctl() - Submits a job (frame) to the V3D.
+ * @dev: DRM device
+@@ -495,9 +537,9 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ struct v3d_dev *v3d = to_v3d_dev(dev);
+ struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
+ struct drm_v3d_submit_cl *args = data;
+- struct v3d_exec_info *exec;
++ struct v3d_bin_job *bin = NULL;
++ struct v3d_render_job *render;
+ struct ww_acquire_ctx acquire_ctx;
+- struct drm_syncobj *sync_out;
+ int ret = 0;
+
+ trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end);
+@@ -507,95 +549,84 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ return -EINVAL;
+ }
+
+- exec = kcalloc(1, sizeof(*exec), GFP_KERNEL);
+- if (!exec)
++ render = kcalloc(1, sizeof(*render), GFP_KERNEL);
++ if (!render)
+ return -ENOMEM;
+
+- kref_init(&exec->refcount);
++ render->start = args->rcl_start;
++ render->end = args->rcl_end;
++ INIT_LIST_HEAD(&render->unref_list);
+
+- ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
+- 0, &exec->bin.in_fence);
+- if (ret == -EINVAL)
+- goto fail;
++ ret = v3d_job_init(v3d, file_priv, &render->base,
++ v3d_render_job_free, args->in_sync_rcl);
++ if (ret) {
++ kfree(bin);
++ kfree(render);
++ return ret;
++ }
+
+- ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl,
+- 0, &exec->render.in_fence);
+- if (ret == -EINVAL)
+- goto fail;
++ if (args->bcl_start != args->bcl_end) {
++ bin = kcalloc(1, sizeof(*bin), GFP_KERNEL);
++ if (!bin)
++ return -ENOMEM;
++
++ ret = v3d_job_init(v3d, file_priv, &bin->base,
++ v3d_job_free, args->in_sync_bcl);
++ if (ret) {
++ v3d_job_put(&render->base);
++ return ret;
++ }
+
+- exec->qma = args->qma;
+- exec->qms = args->qms;
+- exec->qts = args->qts;
+- exec->bin.exec = exec;
+- exec->bin.start = args->bcl_start;
+- exec->bin.end = args->bcl_end;
+- exec->render.exec = exec;
+- exec->render.start = args->rcl_start;
+- exec->render.end = args->rcl_end;
+- exec->v3d = v3d;
+- INIT_LIST_HEAD(&exec->unref_list);
++ bin->start = args->bcl_start;
++ bin->end = args->bcl_end;
++ bin->qma = args->qma;
++ bin->qms = args->qms;
++ bin->qts = args->qts;
++ bin->render = render;
++ }
+
+- ret = v3d_cl_lookup_bos(dev, file_priv, args, exec);
++ ret = v3d_lookup_bos(dev, file_priv, &render->base,
++ args->bo_handles, args->bo_handle_count);
+ if (ret)
+ goto fail;
+
+- ret = v3d_lock_bo_reservations(exec->bo, exec->bo_count,
++ ret = v3d_lock_bo_reservations(render->base.bo, render->base.bo_count,
+ &acquire_ctx);
+ if (ret)
+ goto fail;
+
+ mutex_lock(&v3d->sched_lock);
+- if (exec->bin.start != exec->bin.end) {
+- ret = drm_sched_job_init(&exec->bin.base,
+- &v3d_priv->sched_entity[V3D_BIN],
+- v3d_priv);
++ if (bin) {
++ ret = v3d_push_job(v3d_priv, &bin->base, V3D_BIN);
+ if (ret)
+ goto fail_unreserve;
+
+- exec->bin_done_fence =
+- dma_fence_get(&exec->bin.base.s_fence->finished);
+-
+- kref_get(&exec->refcount); /* put by scheduler job completion */
+- drm_sched_entity_push_job(&exec->bin.base,
+- &v3d_priv->sched_entity[V3D_BIN]);
++ render->bin_done_fence = dma_fence_get(bin->base.done_fence);
+ }
+
+- ret = drm_sched_job_init(&exec->render.base,
+- &v3d_priv->sched_entity[V3D_RENDER],
+- v3d_priv);
++ ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER);
+ if (ret)
+ goto fail_unreserve;
+-
+- exec->render_done_fence =
+- dma_fence_get(&exec->render.base.s_fence->finished);
+-
+- kref_get(&exec->refcount); /* put by scheduler job completion */
+- drm_sched_entity_push_job(&exec->render.base,
+- &v3d_priv->sched_entity[V3D_RENDER]);
+ mutex_unlock(&v3d->sched_lock);
+
+- v3d_attach_object_fences(exec->bo, exec->bo_count,
+- exec->render_done_fence);
+-
+- v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx);
+-
+- /* Update the return sync object for the */
+- sync_out = drm_syncobj_find(file_priv, args->out_sync);
+- if (sync_out) {
+- drm_syncobj_replace_fence(sync_out,
+- exec->render_done_fence);
+- drm_syncobj_put(sync_out);
+- }
+-
+- v3d_exec_put(exec);
++ v3d_attach_fences_and_unlock_reservation(file_priv,
++ &render->base, &acquire_ctx,
++ args->out_sync);
++
++ if (bin)
++ v3d_job_put(&bin->base);
++ v3d_job_put(&render->base);
+
+ return 0;
+
+ fail_unreserve:
+ mutex_unlock(&v3d->sched_lock);
+- v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx);
++ v3d_unlock_bo_reservations(render->base.bo,
++ render->base.bo_count, &acquire_ctx);
+ fail:
+- v3d_exec_put(exec);
++ if (bin)
++ v3d_job_put(&bin->base);
++ v3d_job_put(&render->base);
+
+ return ret;
+ }
+@@ -618,10 +649,7 @@ v3d_submit_tfu_ioctl(struct drm_device *
+ struct drm_v3d_submit_tfu *args = data;
+ struct v3d_tfu_job *job;
+ struct ww_acquire_ctx acquire_ctx;
+- struct drm_syncobj *sync_out;
+- struct dma_fence *sched_done_fence;
+ int ret = 0;
+- int bo_count;
+
+ trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia);
+
+@@ -629,75 +657,66 @@ v3d_submit_tfu_ioctl(struct drm_device *
+ if (!job)
+ return -ENOMEM;
+
+- kref_init(&job->refcount);
+-
+- ret = drm_syncobj_find_fence(file_priv, args->in_sync,
+- 0, &job->in_fence);
+- if (ret == -EINVAL)
+- goto fail;
++ ret = v3d_job_init(v3d, file_priv, &job->base,
++ v3d_job_free, args->in_sync);
++ if (ret) {
++ kfree(job);
++ return ret;
++ }
+
++ job->base.bo = kcalloc(ARRAY_SIZE(args->bo_handles),
++ sizeof(*job->base.bo), GFP_KERNEL);
+ job->args = *args;
+- job->v3d = v3d;
+
+ spin_lock(&file_priv->table_lock);
+- for (bo_count = 0; bo_count < ARRAY_SIZE(job->bo); bo_count++) {
++ for (job->base.bo_count = 0;
++ job->base.bo_count < ARRAY_SIZE(args->bo_handles);
++ job->base.bo_count++) {
+ struct drm_gem_object *bo;
+
+- if (!args->bo_handles[bo_count])
++ if (!args->bo_handles[job->base.bo_count])
+ break;
+
+ bo = idr_find(&file_priv->object_idr,
+- args->bo_handles[bo_count]);
++ args->bo_handles[job->base.bo_count]);
+ if (!bo) {
+ DRM_DEBUG("Failed to look up GEM BO %d: %d\n",
+- bo_count, args->bo_handles[bo_count]);
++ job->base.bo_count,
++ args->bo_handles[job->base.bo_count]);
+ ret = -ENOENT;
+ spin_unlock(&file_priv->table_lock);
+ goto fail;
+ }
+ drm_gem_object_get(bo);
+- job->bo[bo_count] = to_v3d_bo(bo);
++ job->base.bo[job->base.bo_count] = to_v3d_bo(bo);
+ }
+ spin_unlock(&file_priv->table_lock);
+
+- ret = v3d_lock_bo_reservations(job->bo, bo_count, &acquire_ctx);
++ ret = v3d_lock_bo_reservations(job->base.bo, job->base.bo_count,
++ &acquire_ctx);
+ if (ret)
+ goto fail;
+
+ mutex_lock(&v3d->sched_lock);
+- ret = drm_sched_job_init(&job->base,
+- &v3d_priv->sched_entity[V3D_TFU],
+- v3d_priv);
++ ret = v3d_push_job(v3d_priv, &job->base, V3D_TFU);
+ if (ret)
+ goto fail_unreserve;
+-
+- sched_done_fence = dma_fence_get(&job->base.s_fence->finished);
+-
+- kref_get(&job->refcount); /* put by scheduler job completion */
+- drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[V3D_TFU]);
+ mutex_unlock(&v3d->sched_lock);
+
+- v3d_attach_object_fences(job->bo, bo_count, sched_done_fence);
+-
+- v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx);
+-
+- /* Update the return sync object */
+- sync_out = drm_syncobj_find(file_priv, args->out_sync);
+- if (sync_out) {
+- drm_syncobj_replace_fence(sync_out, sched_done_fence);
+- drm_syncobj_put(sync_out);
+- }
+- dma_fence_put(sched_done_fence);
++ v3d_attach_fences_and_unlock_reservation(file_priv,
++ &job->base, &acquire_ctx,
++ args->out_sync);
+
+- v3d_tfu_job_put(job);
++ v3d_job_put(&job->base);
+
+ return 0;
+
+ fail_unreserve:
+ mutex_unlock(&v3d->sched_lock);
+- v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx);
++ v3d_unlock_bo_reservations(job->base.bo, job->base.bo_count,
++ &acquire_ctx);
+ fail:
+- v3d_tfu_job_put(job);
++ v3d_job_put(&job->base);
+
+ return ret;
+ }
+@@ -755,7 +774,7 @@ v3d_gem_destroy(struct drm_device *dev)
+
+ v3d_sched_fini(v3d);
+
+- /* Waiting for exec to finish would need to be done before
++ /* Waiting for jobs to finish would need to be done before
+ * unregistering V3D.
+ */
+ WARN_ON(v3d->bin_job);
+--- a/drivers/gpu/drm/v3d/v3d_irq.c
++++ b/drivers/gpu/drm/v3d/v3d_irq.c
+@@ -60,7 +60,7 @@ v3d_overflow_mem_work(struct work_struct
+ }
+
+ drm_gem_object_get(&bo->base);
+- list_add_tail(&bo->unref_head, &v3d->bin_job->unref_list);
++ list_add_tail(&bo->unref_head, &v3d->bin_job->render->unref_list);
+ spin_unlock_irqrestore(&v3d->job_lock, irqflags);
+
+ V3D_CORE_WRITE(0, V3D_PTB_BPOA, bo->node.start << PAGE_SHIFT);
+@@ -93,7 +93,7 @@ v3d_irq(int irq, void *arg)
+
+ if (intsts & V3D_INT_FLDONE) {
+ struct v3d_fence *fence =
+- to_v3d_fence(v3d->bin_job->bin.irq_fence);
++ to_v3d_fence(v3d->bin_job->base.irq_fence);
+
+ trace_v3d_bcl_irq(&v3d->drm, fence->seqno);
+ dma_fence_signal(&fence->base);
+@@ -102,7 +102,7 @@ v3d_irq(int irq, void *arg)
+
+ if (intsts & V3D_INT_FRDONE) {
+ struct v3d_fence *fence =
+- to_v3d_fence(v3d->render_job->render.irq_fence);
++ to_v3d_fence(v3d->render_job->base.irq_fence);
+
+ trace_v3d_rcl_irq(&v3d->drm, fence->seqno);
+ dma_fence_signal(&fence->base);
+@@ -138,7 +138,7 @@ v3d_hub_irq(int irq, void *arg)
+
+ if (intsts & V3D_HUB_INT_TFUC) {
+ struct v3d_fence *fence =
+- to_v3d_fence(v3d->tfu_job->irq_fence);
++ to_v3d_fence(v3d->tfu_job->base.irq_fence);
+
+ trace_v3d_tfu_irq(&v3d->drm, fence->seqno);
+ dma_fence_signal(&fence->base);
+--- a/drivers/gpu/drm/v3d/v3d_sched.c
++++ b/drivers/gpu/drm/v3d/v3d_sched.c
+@@ -30,39 +30,43 @@ to_v3d_job(struct drm_sched_job *sched_j
+ return container_of(sched_job, struct v3d_job, base);
+ }
+
+-static struct v3d_tfu_job *
+-to_tfu_job(struct drm_sched_job *sched_job)
++static struct v3d_bin_job *
++to_bin_job(struct drm_sched_job *sched_job)
+ {
+- return container_of(sched_job, struct v3d_tfu_job, base);
++ return container_of(sched_job, struct v3d_bin_job, base.base);
+ }
+
+-static void
+-v3d_job_free(struct drm_sched_job *sched_job)
++static struct v3d_render_job *
++to_render_job(struct drm_sched_job *sched_job)
+ {
+- struct v3d_job *job = to_v3d_job(sched_job);
++ return container_of(sched_job, struct v3d_render_job, base.base);
++}
+
+- v3d_exec_put(job->exec);
++static struct v3d_tfu_job *
++to_tfu_job(struct drm_sched_job *sched_job)
++{
++ return container_of(sched_job, struct v3d_tfu_job, base.base);
+ }
+
+ static void
+-v3d_tfu_job_free(struct drm_sched_job *sched_job)
++v3d_job_free(struct drm_sched_job *sched_job)
+ {
+- struct v3d_tfu_job *job = to_tfu_job(sched_job);
++ struct v3d_job *job = to_v3d_job(sched_job);
+
+- v3d_tfu_job_put(job);
++ v3d_job_put(job);
+ }
+
+ /**
+- * Returns the fences that the bin or render job depends on, one by one.
+- * v3d_job_run() won't be called until all of them have been signaled.
++ * Returns the fences that the job depends on, one by one.
++ *
++ * If placed in the scheduler's .dependency method, the corresponding
++ * .run_job won't be called until all of them have been signaled.
+ */
+ static struct dma_fence *
+ v3d_job_dependency(struct drm_sched_job *sched_job,
+ struct drm_sched_entity *s_entity)
+ {
+ struct v3d_job *job = to_v3d_job(sched_job);
+- struct v3d_exec_info *exec = job->exec;
+- enum v3d_queue q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
+ struct dma_fence *fence;
+
+ fence = job->in_fence;
+@@ -71,113 +75,132 @@ v3d_job_dependency(struct drm_sched_job
+ return fence;
+ }
+
+- if (q == V3D_RENDER) {
+- /* If we had a bin job, the render job definitely depends on
+- * it. We first have to wait for bin to be scheduled, so that
+- * its done_fence is created.
+- */
+- fence = exec->bin_done_fence;
+- if (fence) {
+- exec->bin_done_fence = NULL;
+- return fence;
+- }
+- }
+-
+- /* XXX: Wait on a fence for switching the GMP if necessary,
+- * and then do so.
+- */
+-
+- return fence;
++ return NULL;
+ }
+
+ /**
+- * Returns the fences that the TFU job depends on, one by one.
+- * v3d_tfu_job_run() won't be called until all of them have been
+- * signaled.
++ * Returns the fences that the render job depends on, one by one.
++ * v3d_job_run() won't be called until all of them have been signaled.
+ */
+ static struct dma_fence *
+-v3d_tfu_job_dependency(struct drm_sched_job *sched_job,
+- struct drm_sched_entity *s_entity)
++v3d_render_job_dependency(struct drm_sched_job *sched_job,
++ struct drm_sched_entity *s_entity)
+ {
+- struct v3d_tfu_job *job = to_tfu_job(sched_job);
++ struct v3d_render_job *job = to_render_job(sched_job);
+ struct dma_fence *fence;
+
+- fence = job->in_fence;
++ fence = v3d_job_dependency(sched_job, s_entity);
++ if (fence)
++ return fence;
++
++ /* If we had a bin job, the render job definitely depends on
++ * it. We first have to wait for bin to be scheduled, so that
++ * its done_fence is created.
++ */
++ fence = job->bin_done_fence;
+ if (fence) {
+- job->in_fence = NULL;
++ job->bin_done_fence = NULL;
+ return fence;
+ }
+
+- return NULL;
++ /* XXX: Wait on a fence for switching the GMP if necessary,
++ * and then do so.
++ */
++
++ return fence;
+ }
+
+-static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job)
++static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
+ {
+- struct v3d_job *job = to_v3d_job(sched_job);
+- struct v3d_exec_info *exec = job->exec;
+- enum v3d_queue q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
+- struct v3d_dev *v3d = exec->v3d;
++ struct v3d_bin_job *job = to_bin_job(sched_job);
++ struct v3d_dev *v3d = job->base.v3d;
+ struct drm_device *dev = &v3d->drm;
+ struct dma_fence *fence;
+ unsigned long irqflags;
+
+- if (unlikely(job->base.s_fence->finished.error))
++ if (unlikely(job->base.base.s_fence->finished.error))
+ return NULL;
+
+ /* Lock required around bin_job update vs
+ * v3d_overflow_mem_work().
+ */
+ spin_lock_irqsave(&v3d->job_lock, irqflags);
+- if (q == V3D_BIN) {
+- v3d->bin_job = job->exec;
++ v3d->bin_job = job;
++ /* Clear out the overflow allocation, so we don't
++ * reuse the overflow attached to a previous job.
++ */
++ V3D_CORE_WRITE(0, V3D_PTB_BPOS, 0);
++ spin_unlock_irqrestore(&v3d->job_lock, irqflags);
++
++ v3d_invalidate_caches(v3d);
+
+- /* Clear out the overflow allocation, so we don't
+- * reuse the overflow attached to a previous job.
+- */
+- V3D_CORE_WRITE(0, V3D_PTB_BPOS, 0);
+- } else {
+- v3d->render_job = job->exec;
++ fence = v3d_fence_create(v3d, V3D_BIN);
++ if (IS_ERR(fence))
++ return NULL;
++
++ if (job->base.irq_fence)
++ dma_fence_put(job->base.irq_fence);
++ job->base.irq_fence = dma_fence_get(fence);
++
++ trace_v3d_submit_cl(dev, false, to_v3d_fence(fence)->seqno,
++ job->start, job->end);
++
++ /* Set the current and end address of the control list.
++ * Writing the end register is what starts the job.
++ */
++ if (job->qma) {
++ V3D_CORE_WRITE(0, V3D_CLE_CT0QMA, job->qma);
++ V3D_CORE_WRITE(0, V3D_CLE_CT0QMS, job->qms);
+ }
+- spin_unlock_irqrestore(&v3d->job_lock, irqflags);
++ if (job->qts) {
++ V3D_CORE_WRITE(0, V3D_CLE_CT0QTS,
++ V3D_CLE_CT0QTS_ENABLE |
++ job->qts);
++ }
++ V3D_CORE_WRITE(0, V3D_CLE_CT0QBA, job->start);
++ V3D_CORE_WRITE(0, V3D_CLE_CT0QEA, job->end);
++
++ return fence;
++}
++
++static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)
++{
++ struct v3d_render_job *job = to_render_job(sched_job);
++ struct v3d_dev *v3d = job->base.v3d;
++ struct drm_device *dev = &v3d->drm;
++ struct dma_fence *fence;
++
++ if (unlikely(job->base.base.s_fence->finished.error))
++ return NULL;
+
+- /* Can we avoid this flush when q==RENDER? We need to be
+- * careful of scheduling, though -- imagine job0 rendering to
+- * texture and job1 reading, and them being executed as bin0,
+- * bin1, render0, render1, so that render1's flush at bin time
++ v3d->render_job = job;
++
++ /* Can we avoid this flush? We need to be careful of
++ * scheduling, though -- imagine job0 rendering to texture and
++ * job1 reading, and them being executed as bin0, bin1,
++ * render0, render1, so that render1's flush at bin time
+ * wasn't enough.
+ */
+ v3d_invalidate_caches(v3d);
+
+- fence = v3d_fence_create(v3d, q);
++ fence = v3d_fence_create(v3d, V3D_RENDER);
+ if (IS_ERR(fence))
+ return NULL;
+
+- if (job->irq_fence)
+- dma_fence_put(job->irq_fence);
+- job->irq_fence = dma_fence_get(fence);
++ if (job->base.irq_fence)
++ dma_fence_put(job->base.irq_fence);
++ job->base.irq_fence = dma_fence_get(fence);
+
+- trace_v3d_submit_cl(dev, q == V3D_RENDER, to_v3d_fence(fence)->seqno,
++ trace_v3d_submit_cl(dev, true, to_v3d_fence(fence)->seqno,
+ job->start, job->end);
+
+- if (q == V3D_BIN) {
+- if (exec->qma) {
+- V3D_CORE_WRITE(0, V3D_CLE_CT0QMA, exec->qma);
+- V3D_CORE_WRITE(0, V3D_CLE_CT0QMS, exec->qms);
+- }
+- if (exec->qts) {
+- V3D_CORE_WRITE(0, V3D_CLE_CT0QTS,
+- V3D_CLE_CT0QTS_ENABLE |
+- exec->qts);
+- }
+- } else {
+- /* XXX: Set the QCFG */
+- }
++ /* XXX: Set the QCFG */
+
+ /* Set the current and end address of the control list.
+ * Writing the end register is what starts the job.
+ */
+- V3D_CORE_WRITE(0, V3D_CLE_CTNQBA(q), job->start);
+- V3D_CORE_WRITE(0, V3D_CLE_CTNQEA(q), job->end);
++ V3D_CORE_WRITE(0, V3D_CLE_CT1QBA, job->start);
++ V3D_CORE_WRITE(0, V3D_CLE_CT1QEA, job->end);
+
+ return fence;
+ }
+@@ -186,7 +209,7 @@ static struct dma_fence *
+ v3d_tfu_job_run(struct drm_sched_job *sched_job)
+ {
+ struct v3d_tfu_job *job = to_tfu_job(sched_job);
+- struct v3d_dev *v3d = job->v3d;
++ struct v3d_dev *v3d = job->base.v3d;
+ struct drm_device *dev = &v3d->drm;
+ struct dma_fence *fence;
+
+@@ -195,9 +218,9 @@ v3d_tfu_job_run(struct drm_sched_job *sc
+ return NULL;
+
+ v3d->tfu_job = job;
+- if (job->irq_fence)
+- dma_fence_put(job->irq_fence);
+- job->irq_fence = dma_fence_get(fence);
++ if (job->base.irq_fence)
++ dma_fence_put(job->base.irq_fence);
++ job->base.irq_fence = dma_fence_get(fence);
+
+ trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);
+
+@@ -247,25 +270,23 @@ v3d_gpu_reset_for_timeout(struct v3d_dev
+ mutex_unlock(&v3d->reset_lock);
+ }
+
++/* If the current address or return address have changed, then the GPU
++ * has probably made progress and we should delay the reset. This
++ * could fail if the GPU got in an infinite loop in the CL, but that
++ * is pretty unlikely outside of an i-g-t testcase.
++ */
+ static void
+-v3d_job_timedout(struct drm_sched_job *sched_job)
++v3d_cl_job_timedout(struct drm_sched_job *sched_job, enum v3d_queue q,
++ u32 *timedout_ctca, u32 *timedout_ctra)
+ {
+ struct v3d_job *job = to_v3d_job(sched_job);
+- struct v3d_exec_info *exec = job->exec;
+- struct v3d_dev *v3d = exec->v3d;
+- enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
+- u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q));
+- u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q));
+-
+- /* If the current address or return address have changed, then
+- * the GPU has probably made progress and we should delay the
+- * reset. This could fail if the GPU got in an infinite loop
+- * in the CL, but that is pretty unlikely outside of an i-g-t
+- * testcase.
+- */
+- if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) {
+- job->timedout_ctca = ctca;
+- job->timedout_ctra = ctra;
++ struct v3d_dev *v3d = job->v3d;
++ u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(q));
++ u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(q));
++
++ if (*timedout_ctca != ctca || *timedout_ctra != ctra) {
++ *timedout_ctca = ctca;
++ *timedout_ctra = ctra;
+ schedule_delayed_work(&job->base.work_tdr,
+ job->base.sched->timeout);
+ return;
+@@ -275,25 +296,50 @@ v3d_job_timedout(struct drm_sched_job *s
+ }
+
+ static void
++v3d_bin_job_timedout(struct drm_sched_job *sched_job)
++{
++ struct v3d_bin_job *job = to_bin_job(sched_job);
++
++ v3d_cl_job_timedout(sched_job, V3D_BIN,
++ &job->timedout_ctca, &job->timedout_ctra);
++}
++
++static void
++v3d_render_job_timedout(struct drm_sched_job *sched_job)
++{
++ struct v3d_render_job *job = to_render_job(sched_job);
++
++ v3d_cl_job_timedout(sched_job, V3D_RENDER,
++ &job->timedout_ctca, &job->timedout_ctra);
++}
++
++static void
+ v3d_tfu_job_timedout(struct drm_sched_job *sched_job)
+ {
+- struct v3d_tfu_job *job = to_tfu_job(sched_job);
++ struct v3d_job *job = to_v3d_job(sched_job);
+
+ v3d_gpu_reset_for_timeout(job->v3d, sched_job);
+ }
+
+-static const struct drm_sched_backend_ops v3d_sched_ops = {
++static const struct drm_sched_backend_ops v3d_bin_sched_ops = {
+ .dependency = v3d_job_dependency,
+- .run_job = v3d_job_run,
+- .timedout_job = v3d_job_timedout,
+- .free_job = v3d_job_free
++ .run_job = v3d_bin_job_run,
++ .timedout_job = v3d_bin_job_timedout,
++ .free_job = v3d_job_free,
++};
++
++static const struct drm_sched_backend_ops v3d_render_sched_ops = {
++ .dependency = v3d_render_job_dependency,
++ .run_job = v3d_render_job_run,
++ .timedout_job = v3d_render_job_timedout,
++ .free_job = v3d_job_free,
+ };
+
+ static const struct drm_sched_backend_ops v3d_tfu_sched_ops = {
+- .dependency = v3d_tfu_job_dependency,
++ .dependency = v3d_job_dependency,
+ .run_job = v3d_tfu_job_run,
+ .timedout_job = v3d_tfu_job_timedout,
+- .free_job = v3d_tfu_job_free
++ .free_job = v3d_job_free,
+ };
+
+ int
+@@ -305,7 +351,7 @@ v3d_sched_init(struct v3d_dev *v3d)
+ int ret;
+
+ ret = drm_sched_init(&v3d->queue[V3D_BIN].sched,
+- &v3d_sched_ops,
++ &v3d_bin_sched_ops,
+ hw_jobs_limit, job_hang_limit,
+ msecs_to_jiffies(hang_limit_ms),
+ "v3d_bin");
+@@ -315,7 +361,7 @@ v3d_sched_init(struct v3d_dev *v3d)
+ }
+
+ ret = drm_sched_init(&v3d->queue[V3D_RENDER].sched,
+- &v3d_sched_ops,
++ &v3d_render_sched_ops,
+ hw_jobs_limit, job_hang_limit,
+ msecs_to_jiffies(hang_limit_ms),
+ "v3d_render");
+++ /dev/null
-From 50088003d803f04e536eb09ac2635df35b5c8ae4 Mon Sep 17 00:00:00 2001
-Date: Tue, 12 Mar 2019 09:08:10 -0700
-Subject: [PATCH] drm/v3d: Update to upstream IRQ code.
-
----
- drivers/gpu/drm/v3d/v3d_irq.c | 25 +++++++++++++++----------
- 1 file changed, 15 insertions(+), 10 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_irq.c
-+++ b/drivers/gpu/drm/v3d/v3d_irq.c
-@@ -168,7 +168,7 @@ v3d_hub_irq(int irq, void *arg)
- int
- v3d_irq_init(struct v3d_dev *v3d)
- {
-- int ret, core;
-+ int irq1, ret, core;
-
- INIT_WORK(&v3d->overflow_mem_work, v3d_overflow_mem_work);
-
-@@ -179,24 +179,29 @@ v3d_irq_init(struct v3d_dev *v3d)
- V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS);
- V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS);
-
-- if (platform_get_irq(v3d->pdev, 1) < 0) {
-- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
-+ irq1 = platform_get_irq(v3d->pdev, 1);
-+ if (irq1 == -EPROBE_DEFER)
-+ return irq1;
-+ if (irq1 > 0) {
-+ ret = devm_request_irq(v3d->dev, irq1,
- v3d_irq, IRQF_SHARED,
-- "v3d", v3d);
-- v3d->single_irq_line = true;
-- } else {
-+ "v3d_core0", v3d);
-+ if (ret)
-+ goto fail;
- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
- v3d_hub_irq, IRQF_SHARED,
- "v3d_hub", v3d);
- if (ret)
- goto fail;
-+ } else {
-+ v3d->single_irq_line = true;
-
-- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 1),
-+ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
- v3d_irq, IRQF_SHARED,
-- "v3d_core0", v3d);
-+ "v3d", v3d);
-+ if (ret)
-+ goto fail;
- }
-- if (ret)
-- goto fail;
-
- v3d_irq_enable(v3d);
- return 0;
--- /dev/null
+From 7713f79b0a5473eb0b8456d36b99ae00815dd8a1 Mon Sep 17 00:00:00 2001
+Date: Wed, 27 Mar 2019 17:44:40 -0700
+Subject: [PATCH] drm/v3d: Add missing implicit synchronization.
+
+It is the expectation of existing userspace (X11 + Mesa, in
+particular) that jobs submitted to the kernel against a shared BO will
+get implicitly synchronized by their submission order. If we want to
+allow clever userspace to disable implicit synchronization, we should
+do that under its own submit flag (as amdgpu and lima do).
+
+Note that we currently only implicitly sync for the rendering pass,
+not binning -- if you texture-from-pixmap in the binning vertex shader
+(vertex coordinate generation), you'll miss out on synchronization.
+
+Fixes flickering when multiple clients are running in parallel,
+particularly GL apps and compositors.
+
+---
+ drivers/gpu/drm/v3d/v3d_drv.h | 10 +---
+ drivers/gpu/drm/v3d/v3d_gem.c | 98 ++++++++++++++++++++++++++++++---
+ drivers/gpu/drm/v3d/v3d_sched.c | 45 ++-------------
+ 3 files changed, 96 insertions(+), 57 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.h
++++ b/drivers/gpu/drm/v3d/v3d_drv.h
+@@ -186,8 +186,9 @@ struct v3d_job {
+ struct v3d_bo **bo;
+ u32 bo_count;
+
+- /* An optional fence userspace can pass in for the job to depend on. */
+- struct dma_fence *in_fence;
++ struct dma_fence **deps;
++ int deps_count;
++ int deps_size;
+
+ /* v3d fence to be signaled by IRQ handler when the job is complete. */
+ struct dma_fence *irq_fence;
+@@ -219,11 +220,6 @@ struct v3d_bin_job {
+ struct v3d_render_job {
+ struct v3d_job base;
+
+- /* Optional fence for the binner, to depend on before starting
+- * our job.
+- */
+- struct dma_fence *bin_done_fence;
+-
+ /* GPU virtual addresses of the start/end of the CL job. */
+ u32 start, end;
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -218,6 +218,71 @@ v3d_unlock_bo_reservations(struct v3d_bo
+ ww_acquire_fini(acquire_ctx);
+ }
+
++static int
++v3d_add_dep(struct v3d_job *job, struct dma_fence *fence)
++{
++ if (!fence)
++ return 0;
++
++ if (job->deps_size == job->deps_count) {
++ int new_deps_size = max(job->deps_size * 2, 4);
++ struct dma_fence **new_deps =
++ krealloc(job->deps, new_deps_size * sizeof(*new_deps),
++ GFP_KERNEL);
++ if (!new_deps) {
++ dma_fence_put(fence);
++ return -ENOMEM;
++ }
++
++ job->deps = new_deps;
++ job->deps_size = new_deps_size;
++ }
++
++ job->deps[job->deps_count++] = fence;
++
++ return 0;
++}
++
++/**
++ * Adds the required implicit fences before executing the job
++ *
++ * Userspace (X11 + Mesa) requires that a job submitted against a shared BO
++ * from one fd will implicitly synchronize against previous jobs submitted
++ * against that BO from other fds.
++ *
++ * Currently we don't bother trying to track the shared BOs, and instead just
++ * sync everything. However, our synchronization is only for the render pass
++ * -- the binning stage (VS coordinate calculations) ignores implicit sync,
++ * since using shared buffers for texture coordinates seems unlikely, and
++ * implicitly syncing them would break bin/render parallelism. If we want to
++ * fix that, we should introduce a flag when VS texturing has been used in the
++ * binning stage, or a set of flags for which BOs are sampled during binning.
++ */
++static int
++v3d_add_implicit_fences(struct v3d_job *job, struct v3d_bo *bo)
++{
++ int i, ret, nr_fences;
++ struct dma_fence **fences;
++
++ ret = reservation_object_get_fences_rcu(bo->resv, NULL,
++ &nr_fences, &fences);
++ if (ret || !nr_fences)
++ return ret;
++
++ for (i = 0; i < nr_fences; i++) {
++ ret = v3d_add_dep(job, fences[i]);
++ if (ret)
++ break;
++ }
++
++ /* Free any remaining fences after error. */
++ for (; i < nr_fences; i++)
++ dma_fence_put(fences[i]);
++ kfree(fences);
++
++ return ret;
++}
++
+ /* Takes the reservation lock on all the BOs being referenced, so that
+ * at queue submit time we can update the reservations.
+ *
+@@ -226,10 +291,11 @@ v3d_unlock_bo_reservations(struct v3d_bo
+ * to v3d, so we don't attach dma-buf fences to them.
+ */
+ static int
+-v3d_lock_bo_reservations(struct v3d_bo **bos,
+- int bo_count,
++v3d_lock_bo_reservations(struct v3d_job *job,
+ struct ww_acquire_ctx *acquire_ctx)
+ {
++ struct v3d_bo **bos = job->bo;
++ int bo_count = job->bo_count;
+ int contended_lock = -1;
+ int i, ret;
+
+@@ -281,6 +347,13 @@ retry:
+ * before we commit the CL to the hardware.
+ */
+ for (i = 0; i < bo_count; i++) {
++ ret = v3d_add_implicit_fences(job, bos[i]);
++ if (ret) {
++ v3d_unlock_bo_reservations(bos, bo_count,
++ acquire_ctx);
++ return ret;
++ }
++
+ ret = reservation_object_reserve_shared(bos[i]->resv);
+ if (ret) {
+ v3d_unlock_bo_reservations(bos, bo_count,
+@@ -383,7 +456,10 @@ v3d_job_free(struct kref *ref)
+ }
+ kvfree(job->bo);
+
+- dma_fence_put(job->in_fence);
++ for (i = 0; i < job->deps_count; i++)
++ dma_fence_put(job->deps[i]);
++ kfree(job->deps);
++
+ dma_fence_put(job->irq_fence);
+ dma_fence_put(job->done_fence);
+
+@@ -464,15 +540,20 @@ v3d_job_init(struct v3d_dev *v3d, struct
+ struct v3d_job *job, void (*free)(struct kref *ref),
+ u32 in_sync)
+ {
++ struct dma_fence *in_fence = NULL;
+ int ret;
+
+ job->v3d = v3d;
+ job->free = free;
+
+- ret = drm_syncobj_find_fence(file_priv, in_sync, 0, &job->in_fence);
++ ret = drm_syncobj_find_fence(file_priv, in_sync, 0, &in_fence);
+ if (ret == -EINVAL)
+ return ret;
+
++ ret = v3d_add_dep(job, in_fence);
++ if (ret)
++ return ret;
++
+ kref_init(&job->refcount);
+
+ return 0;
+@@ -590,8 +671,7 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ if (ret)
+ goto fail;
+
+- ret = v3d_lock_bo_reservations(render->base.bo, render->base.bo_count,
+- &acquire_ctx);
++ ret = v3d_lock_bo_reservations(&render->base, &acquire_ctx);
+ if (ret)
+ goto fail;
+
+@@ -601,7 +681,8 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ if (ret)
+ goto fail_unreserve;
+
+- render->bin_done_fence = dma_fence_get(bin->base.done_fence);
++ ret = v3d_add_dep(&render->base,
++ dma_fence_get(bin->base.done_fence));
+ }
+
+ ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER);
+@@ -692,8 +773,7 @@ v3d_submit_tfu_ioctl(struct drm_device *
+ }
+ spin_unlock(&file_priv->table_lock);
+
+- ret = v3d_lock_bo_reservations(job->base.bo, job->base.bo_count,
+- &acquire_ctx);
++ ret = v3d_lock_bo_reservations(&job->base, &acquire_ctx);
+ if (ret)
+ goto fail;
+
+--- a/drivers/gpu/drm/v3d/v3d_sched.c
++++ b/drivers/gpu/drm/v3d/v3d_sched.c
+@@ -67,47 +67,10 @@ v3d_job_dependency(struct drm_sched_job
+ struct drm_sched_entity *s_entity)
+ {
+ struct v3d_job *job = to_v3d_job(sched_job);
+- struct dma_fence *fence;
+-
+- fence = job->in_fence;
+- if (fence) {
+- job->in_fence = NULL;
+- return fence;
+- }
+-
+- return NULL;
+-}
+
+-/**
+- * Returns the fences that the render job depends on, one by one.
+- * v3d_job_run() won't be called until all of them have been signaled.
+- */
+-static struct dma_fence *
+-v3d_render_job_dependency(struct drm_sched_job *sched_job,
+- struct drm_sched_entity *s_entity)
+-{
+- struct v3d_render_job *job = to_render_job(sched_job);
+- struct dma_fence *fence;
+-
+- fence = v3d_job_dependency(sched_job, s_entity);
+- if (fence)
+- return fence;
+-
+- /* If we had a bin job, the render job definitely depends on
+- * it. We first have to wait for bin to be scheduled, so that
+- * its done_fence is created.
+- */
+- fence = job->bin_done_fence;
+- if (fence) {
+- job->bin_done_fence = NULL;
+- return fence;
+- }
+-
+- /* XXX: Wait on a fence for switching the GMP if necessary,
+- * and then do so.
+- */
+-
+- return fence;
++ if (!job->deps_count)
++ return NULL;
++ return job->deps[--job->deps_count];
+ }
+
+ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
+@@ -329,7 +292,7 @@ static const struct drm_sched_backend_op
+ };
+
+ static const struct drm_sched_backend_ops v3d_render_sched_ops = {
+- .dependency = v3d_render_job_dependency,
++ .dependency = v3d_job_dependency,
+ .run_job = v3d_render_job_run,
+ .timedout_job = v3d_render_job_timedout,
+ .free_job = v3d_job_free,
+++ /dev/null
-From 0d00e0340c1aa9ce36bdff46f927916fe4903cee Mon Sep 17 00:00:00 2001
-Date: Thu, 27 Dec 2018 14:04:44 -0800
-Subject: [PATCH] drm/v3d: Rename the fence signaled from IRQs to
- "irq_fence".
-
-We have another thing called the "done fence" that tracks when the
-scheduler considers the job done, and having the shared name was
-confusing.
-
----
- drivers/gpu/drm/v3d/v3d_drv.h | 4 ++--
- drivers/gpu/drm/v3d/v3d_gem.c | 6 +++---
- drivers/gpu/drm/v3d/v3d_irq.c | 6 +++---
- drivers/gpu/drm/v3d/v3d_sched.c | 12 ++++++------
- 4 files changed, 14 insertions(+), 14 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.h
-+++ b/drivers/gpu/drm/v3d/v3d_drv.h
-@@ -182,7 +182,7 @@ struct v3d_job {
- struct dma_fence *in_fence;
-
- /* v3d fence to be signaled by IRQ handler when the job is complete. */
-- struct dma_fence *done_fence;
-+ struct dma_fence *irq_fence;
-
- /* GPU virtual addresses of the start/end of the CL job. */
- u32 start, end;
-@@ -229,7 +229,7 @@ struct v3d_tfu_job {
- struct dma_fence *in_fence;
-
- /* v3d fence to be signaled by IRQ handler when the job is complete. */
-- struct dma_fence *done_fence;
-+ struct dma_fence *irq_fence;
-
- struct v3d_dev *v3d;
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -381,8 +381,8 @@ v3d_exec_cleanup(struct kref *ref)
- dma_fence_put(exec->bin.in_fence);
- dma_fence_put(exec->render.in_fence);
-
-- dma_fence_put(exec->bin.done_fence);
-- dma_fence_put(exec->render.done_fence);
-+ dma_fence_put(exec->bin.irq_fence);
-+ dma_fence_put(exec->render.irq_fence);
-
- dma_fence_put(exec->bin_done_fence);
- dma_fence_put(exec->render_done_fence);
-@@ -411,7 +411,7 @@ v3d_tfu_job_cleanup(struct kref *ref)
- unsigned int i;
-
- dma_fence_put(job->in_fence);
-- dma_fence_put(job->done_fence);
-+ dma_fence_put(job->irq_fence);
-
- for (i = 0; i < ARRAY_SIZE(job->bo); i++) {
- if (job->bo[i])
---- a/drivers/gpu/drm/v3d/v3d_irq.c
-+++ b/drivers/gpu/drm/v3d/v3d_irq.c
-@@ -93,7 +93,7 @@ v3d_irq(int irq, void *arg)
-
- if (intsts & V3D_INT_FLDONE) {
- struct v3d_fence *fence =
-- to_v3d_fence(v3d->bin_job->bin.done_fence);
-+ to_v3d_fence(v3d->bin_job->bin.irq_fence);
-
- trace_v3d_bcl_irq(&v3d->drm, fence->seqno);
- dma_fence_signal(&fence->base);
-@@ -102,7 +102,7 @@ v3d_irq(int irq, void *arg)
-
- if (intsts & V3D_INT_FRDONE) {
- struct v3d_fence *fence =
-- to_v3d_fence(v3d->render_job->render.done_fence);
-+ to_v3d_fence(v3d->render_job->render.irq_fence);
-
- trace_v3d_rcl_irq(&v3d->drm, fence->seqno);
- dma_fence_signal(&fence->base);
-@@ -138,7 +138,7 @@ v3d_hub_irq(int irq, void *arg)
-
- if (intsts & V3D_HUB_INT_TFUC) {
- struct v3d_fence *fence =
-- to_v3d_fence(v3d->tfu_job->done_fence);
-+ to_v3d_fence(v3d->tfu_job->irq_fence);
-
- trace_v3d_tfu_irq(&v3d->drm, fence->seqno);
- dma_fence_signal(&fence->base);
---- a/drivers/gpu/drm/v3d/v3d_sched.c
-+++ b/drivers/gpu/drm/v3d/v3d_sched.c
-@@ -152,9 +152,9 @@ static struct dma_fence *v3d_job_run(str
- if (IS_ERR(fence))
- return NULL;
-
-- if (job->done_fence)
-- dma_fence_put(job->done_fence);
-- job->done_fence = dma_fence_get(fence);
-+ if (job->irq_fence)
-+ dma_fence_put(job->irq_fence);
-+ job->irq_fence = dma_fence_get(fence);
-
- trace_v3d_submit_cl(dev, q == V3D_RENDER, to_v3d_fence(fence)->seqno,
- job->start, job->end);
-@@ -195,9 +195,9 @@ v3d_tfu_job_run(struct drm_sched_job *sc
- return NULL;
-
- v3d->tfu_job = job;
-- if (job->done_fence)
-- dma_fence_put(job->done_fence);
-- job->done_fence = dma_fence_get(fence);
-+ if (job->irq_fence)
-+ dma_fence_put(job->irq_fence);
-+ job->irq_fence = dma_fence_get(fence);
-
- trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);
-
+++ /dev/null
-From ccf319a0265bfdb4a622a52645f159461bc88079 Mon Sep 17 00:00:00 2001
-Date: Thu, 27 Dec 2018 12:11:52 -0800
-Subject: [PATCH] drm/v3d: Refactor job management.
-
-The CL submission had two jobs embedded in an exec struct. When I
-added TFU support, I had to replicate some of the exec stuff and some
-of the job stuff. As I went to add CSD, it became clear that actually
-what was in exec should just be in the two CL jobs, and it would let
-us share a lot more code between the 4 queues.
-
----
- drivers/gpu/drm/v3d/v3d_drv.h | 77 ++++----
- drivers/gpu/drm/v3d/v3d_gem.c | 331 +++++++++++++++++---------------
- drivers/gpu/drm/v3d/v3d_irq.c | 8 +-
- drivers/gpu/drm/v3d/v3d_sched.c | 264 ++++++++++++++-----------
- 4 files changed, 373 insertions(+), 307 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.h
-+++ b/drivers/gpu/drm/v3d/v3d_drv.h
-@@ -67,8 +67,8 @@ struct v3d_dev {
-
- struct work_struct overflow_mem_work;
-
-- struct v3d_exec_info *bin_job;
-- struct v3d_exec_info *render_job;
-+ struct v3d_bin_job *bin_job;
-+ struct v3d_render_job *render_job;
- struct v3d_tfu_job *tfu_job;
-
- struct v3d_queue_state queue[V3D_MAX_QUEUES];
-@@ -132,7 +132,7 @@ struct v3d_bo {
- struct list_head vmas; /* list of v3d_vma */
-
- /* List entry for the BO's position in
-- * v3d_exec_info->unref_list
-+ * v3d_render_job->unref_list
- */
- struct list_head unref_head;
-
-@@ -176,7 +176,15 @@ to_v3d_fence(struct dma_fence *fence)
- struct v3d_job {
- struct drm_sched_job base;
-
-- struct v3d_exec_info *exec;
-+ struct kref refcount;
-+
-+ struct v3d_dev *v3d;
-+
-+ /* This is the array of BOs that were looked up at the start
-+ * of submission.
-+ */
-+ struct v3d_bo **bo;
-+ u32 bo_count;
-
- /* An optional fence userspace can pass in for the job to depend on. */
- struct dma_fence *in_fence;
-@@ -184,59 +192,53 @@ struct v3d_job {
- /* v3d fence to be signaled by IRQ handler when the job is complete. */
- struct dma_fence *irq_fence;
-
-+ /* scheduler fence for when the job is considered complete and
-+ * the BO reservations can be released.
-+ */
-+ struct dma_fence *done_fence;
-+
-+ /* Callback for the freeing of the job on refcount going to 0. */
-+ void (*free)(struct kref *ref);
-+};
-+
-+struct v3d_bin_job {
-+ struct v3d_job base;
-+
- /* GPU virtual addresses of the start/end of the CL job. */
- u32 start, end;
-
- u32 timedout_ctca, timedout_ctra;
--};
-
--struct v3d_exec_info {
-- struct v3d_dev *v3d;
-+ /* Corresponding render job, for attaching our overflow memory. */
-+ struct v3d_render_job *render;
-+
-+ /* Submitted tile memory allocation start/size, tile state. */
-+ u32 qma, qms, qts;
-+};
-
-- struct v3d_job bin, render;
-+struct v3d_render_job {
-+ struct v3d_job base;
-
-- /* Fence for when the scheduler considers the binner to be
-- * done, for render to depend on.
-+ /* Optional fence for the binner, to depend on before starting
-+ * our job.
- */
- struct dma_fence *bin_done_fence;
-
-- /* Fence for when the scheduler considers the render to be
-- * done, for when the BOs reservations should be complete.
-- */
-- struct dma_fence *render_done_fence;
--
-- struct kref refcount;
-+ /* GPU virtual addresses of the start/end of the CL job. */
-+ u32 start, end;
-
-- /* This is the array of BOs that were looked up at the start of exec. */
-- struct v3d_bo **bo;
-- u32 bo_count;
-+ u32 timedout_ctca, timedout_ctra;
-
- /* List of overflow BOs used in the job that need to be
- * released once the job is complete.
- */
- struct list_head unref_list;
--
-- /* Submitted tile memory allocation start/size, tile state. */
-- u32 qma, qms, qts;
- };
-
- struct v3d_tfu_job {
-- struct drm_sched_job base;
-+ struct v3d_job base;
-
- struct drm_v3d_submit_tfu args;
--
-- /* An optional fence userspace can pass in for the job to depend on. */
-- struct dma_fence *in_fence;
--
-- /* v3d fence to be signaled by IRQ handler when the job is complete. */
-- struct dma_fence *irq_fence;
--
-- struct v3d_dev *v3d;
--
-- struct kref refcount;
--
-- /* This is the array of BOs that were looked up at the start of exec. */
-- struct v3d_bo *bo[4];
- };
-
- /**
-@@ -306,8 +308,7 @@ int v3d_submit_tfu_ioctl(struct drm_devi
- struct drm_file *file_priv);
- int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
--void v3d_exec_put(struct v3d_exec_info *exec);
--void v3d_tfu_job_put(struct v3d_tfu_job *exec);
-+void v3d_job_put(struct v3d_job *job);
- void v3d_reset(struct v3d_dev *v3d);
- void v3d_invalidate_caches(struct v3d_dev *v3d);
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -293,11 +293,11 @@ retry:
- }
-
- /**
-- * v3d_cl_lookup_bos() - Sets up exec->bo[] with the GEM objects
-+ * v3d_lookup_bos() - Sets up job->bo[] with the GEM objects
- * referenced by the job.
- * @dev: DRM device
- * @file_priv: DRM file for this fd
-- * @exec: V3D job being set up
-+ * @job: V3D job being set up
- *
- * The command validator needs to reference BOs by their index within
- * the submitted job's BO list. This does the validation of the job's
-@@ -307,18 +307,19 @@ retry:
- * failure, because that will happen at v3d_exec_cleanup() time.
- */
- static int
--v3d_cl_lookup_bos(struct drm_device *dev,
-- struct drm_file *file_priv,
-- struct drm_v3d_submit_cl *args,
-- struct v3d_exec_info *exec)
-+v3d_lookup_bos(struct drm_device *dev,
-+ struct drm_file *file_priv,
-+ struct v3d_job *job,
-+ u64 bo_handles,
-+ u32 bo_count)
- {
- u32 *handles;
- int ret = 0;
- int i;
-
-- exec->bo_count = args->bo_handle_count;
-+ job->bo_count = bo_count;
-
-- if (!exec->bo_count) {
-+ if (!job->bo_count) {
- /* See comment on bo_index for why we have to check
- * this.
- */
-@@ -326,15 +327,15 @@ v3d_cl_lookup_bos(struct drm_device *dev
- return -EINVAL;
- }
-
-- exec->bo = kvmalloc_array(exec->bo_count,
-- sizeof(struct drm_gem_cma_object *),
-- GFP_KERNEL | __GFP_ZERO);
-- if (!exec->bo) {
-+ job->bo = kvmalloc_array(job->bo_count,
-+ sizeof(struct drm_gem_cma_object *),
-+ GFP_KERNEL | __GFP_ZERO);
-+ if (!job->bo) {
- DRM_DEBUG("Failed to allocate validated BO pointers\n");
- return -ENOMEM;
- }
-
-- handles = kvmalloc_array(exec->bo_count, sizeof(u32), GFP_KERNEL);
-+ handles = kvmalloc_array(job->bo_count, sizeof(u32), GFP_KERNEL);
- if (!handles) {
- ret = -ENOMEM;
- DRM_DEBUG("Failed to allocate incoming GEM handles\n");
-@@ -342,15 +343,15 @@ v3d_cl_lookup_bos(struct drm_device *dev
- }
-
- if (copy_from_user(handles,
-- (void __user *)(uintptr_t)args->bo_handles,
-- exec->bo_count * sizeof(u32))) {
-+ (void __user *)(uintptr_t)bo_handles,
-+ job->bo_count * sizeof(u32))) {
- ret = -EFAULT;
- DRM_DEBUG("Failed to copy in GEM handles\n");
- goto fail;
- }
-
- spin_lock(&file_priv->table_lock);
-- for (i = 0; i < exec->bo_count; i++) {
-+ for (i = 0; i < job->bo_count; i++) {
- struct drm_gem_object *bo = idr_find(&file_priv->object_idr,
- handles[i]);
- if (!bo) {
-@@ -361,7 +362,7 @@ v3d_cl_lookup_bos(struct drm_device *dev
- goto fail;
- }
- drm_gem_object_get(bo);
-- exec->bo[i] = to_v3d_bo(bo);
-+ job->bo[i] = to_v3d_bo(bo);
- }
- spin_unlock(&file_priv->table_lock);
-
-@@ -371,59 +372,41 @@ fail:
- }
-
- static void
--v3d_exec_cleanup(struct kref *ref)
-+v3d_job_free(struct kref *ref)
- {
-- struct v3d_exec_info *exec = container_of(ref, struct v3d_exec_info,
-- refcount);
-- unsigned int i;
-- struct v3d_bo *bo, *save;
--
-- dma_fence_put(exec->bin.in_fence);
-- dma_fence_put(exec->render.in_fence);
--
-- dma_fence_put(exec->bin.irq_fence);
-- dma_fence_put(exec->render.irq_fence);
--
-- dma_fence_put(exec->bin_done_fence);
-- dma_fence_put(exec->render_done_fence);
--
-- for (i = 0; i < exec->bo_count; i++)
-- drm_gem_object_put_unlocked(&exec->bo[i]->base);
-- kvfree(exec->bo);
-+ struct v3d_job *job = container_of(ref, struct v3d_job, refcount);
-+ int i;
-
-- list_for_each_entry_safe(bo, save, &exec->unref_list, unref_head) {
-- drm_gem_object_put_unlocked(&bo->base);
-+ for (i = 0; i < job->bo_count; i++) {
-+ if (job->bo[i])
-+ drm_gem_object_put_unlocked(&job->bo[i]->base);
- }
-+ kvfree(job->bo);
-
-- kfree(exec);
--}
-+ dma_fence_put(job->in_fence);
-+ dma_fence_put(job->irq_fence);
-+ dma_fence_put(job->done_fence);
-
--void v3d_exec_put(struct v3d_exec_info *exec)
--{
-- kref_put(&exec->refcount, v3d_exec_cleanup);
-+ kfree(job);
- }
-
- static void
--v3d_tfu_job_cleanup(struct kref *ref)
-+v3d_render_job_free(struct kref *ref)
- {
-- struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job,
-- refcount);
-- unsigned int i;
--
-- dma_fence_put(job->in_fence);
-- dma_fence_put(job->irq_fence);
-+ struct v3d_render_job *job = container_of(ref, struct v3d_render_job,
-+ base.refcount);
-+ struct v3d_bo *bo, *save;
-
-- for (i = 0; i < ARRAY_SIZE(job->bo); i++) {
-- if (job->bo[i])
-- drm_gem_object_put_unlocked(&job->bo[i]->base);
-+ list_for_each_entry_safe(bo, save, &job->unref_list, unref_head) {
-+ drm_gem_object_put_unlocked(&bo->base);
- }
-
-- kfree(job);
-+ v3d_job_free(ref);
- }
-
--void v3d_tfu_job_put(struct v3d_tfu_job *job)
-+void v3d_job_put(struct v3d_job *job)
- {
-- kref_put(&job->refcount, v3d_tfu_job_cleanup);
-+ kref_put(&job->refcount, job->free);
- }
-
- int
-@@ -476,6 +459,65 @@ v3d_wait_bo_ioctl(struct drm_device *dev
- return ret;
- }
-
-+static int
-+v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv,
-+ struct v3d_job *job, void (*free)(struct kref *ref),
-+ u32 in_sync)
-+{
-+ int ret;
-+
-+ job->v3d = v3d;
-+ job->free = free;
-+
-+ ret = drm_syncobj_find_fence(file_priv, in_sync, 0, &job->in_fence);
-+ if (ret == -EINVAL)
-+ return ret;
-+
-+ kref_init(&job->refcount);
-+
-+ return 0;
-+}
-+
-+static int
-+v3d_push_job(struct v3d_file_priv *v3d_priv,
-+ struct v3d_job *job, enum v3d_queue queue)
-+{
-+ int ret;
-+
-+ ret = drm_sched_job_init(&job->base, &v3d_priv->sched_entity[queue],
-+ v3d_priv);
-+ if (ret)
-+ return ret;
-+
-+ job->done_fence = dma_fence_get(&job->base.s_fence->finished);
-+
-+ /* put by scheduler job completion */
-+ kref_get(&job->refcount);
-+
-+ drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[queue]);
-+
-+ return 0;
-+}
-+
-+static void
-+v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv,
-+ struct v3d_job *job,
-+ struct ww_acquire_ctx *acquire_ctx,
-+ u32 out_sync)
-+{
-+ struct drm_syncobj *sync_out;
-+
-+ v3d_attach_object_fences(job->bo, job->bo_count, job->done_fence);
-+ v3d_unlock_bo_reservations(job->bo, job->bo_count, acquire_ctx);
-+
-+ /* Update the return sync object for the job */
-+ sync_out = drm_syncobj_find(file_priv, out_sync);
-+ if (sync_out) {
-+ drm_syncobj_replace_fence(sync_out, job->done_fence);
-+ drm_syncobj_put(sync_out);
-+ }
-+}
-+
- /**
- * v3d_submit_cl_ioctl() - Submits a job (frame) to the V3D.
- * @dev: DRM device
-@@ -495,9 +537,9 @@ v3d_submit_cl_ioctl(struct drm_device *d
- struct v3d_dev *v3d = to_v3d_dev(dev);
- struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
- struct drm_v3d_submit_cl *args = data;
-- struct v3d_exec_info *exec;
-+ struct v3d_bin_job *bin = NULL;
-+ struct v3d_render_job *render;
- struct ww_acquire_ctx acquire_ctx;
-- struct drm_syncobj *sync_out;
- int ret = 0;
-
- trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end);
-@@ -507,95 +549,84 @@ v3d_submit_cl_ioctl(struct drm_device *d
- return -EINVAL;
- }
-
-- exec = kcalloc(1, sizeof(*exec), GFP_KERNEL);
-- if (!exec)
-+ render = kcalloc(1, sizeof(*render), GFP_KERNEL);
-+ if (!render)
- return -ENOMEM;
-
-- kref_init(&exec->refcount);
-+ render->start = args->rcl_start;
-+ render->end = args->rcl_end;
-+ INIT_LIST_HEAD(&render->unref_list);
-
-- ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
-- 0, &exec->bin.in_fence);
-- if (ret == -EINVAL)
-- goto fail;
-+ ret = v3d_job_init(v3d, file_priv, &render->base,
-+ v3d_render_job_free, args->in_sync_rcl);
-+ if (ret) {
-+ kfree(bin);
-+ kfree(render);
-+ return ret;
-+ }
-
-- ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl,
-- 0, &exec->render.in_fence);
-- if (ret == -EINVAL)
-- goto fail;
-+ if (args->bcl_start != args->bcl_end) {
-+ bin = kcalloc(1, sizeof(*bin), GFP_KERNEL);
-+ if (!bin)
-+ return -ENOMEM;
-+
-+ ret = v3d_job_init(v3d, file_priv, &bin->base,
-+ v3d_job_free, args->in_sync_bcl);
-+ if (ret) {
-+ v3d_job_put(&render->base);
-+ return ret;
-+ }
-
-- exec->qma = args->qma;
-- exec->qms = args->qms;
-- exec->qts = args->qts;
-- exec->bin.exec = exec;
-- exec->bin.start = args->bcl_start;
-- exec->bin.end = args->bcl_end;
-- exec->render.exec = exec;
-- exec->render.start = args->rcl_start;
-- exec->render.end = args->rcl_end;
-- exec->v3d = v3d;
-- INIT_LIST_HEAD(&exec->unref_list);
-+ bin->start = args->bcl_start;
-+ bin->end = args->bcl_end;
-+ bin->qma = args->qma;
-+ bin->qms = args->qms;
-+ bin->qts = args->qts;
-+ bin->render = render;
-+ }
-
-- ret = v3d_cl_lookup_bos(dev, file_priv, args, exec);
-+ ret = v3d_lookup_bos(dev, file_priv, &render->base,
-+ args->bo_handles, args->bo_handle_count);
- if (ret)
- goto fail;
-
-- ret = v3d_lock_bo_reservations(exec->bo, exec->bo_count,
-+ ret = v3d_lock_bo_reservations(render->base.bo, render->base.bo_count,
- &acquire_ctx);
- if (ret)
- goto fail;
-
- mutex_lock(&v3d->sched_lock);
-- if (exec->bin.start != exec->bin.end) {
-- ret = drm_sched_job_init(&exec->bin.base,
-- &v3d_priv->sched_entity[V3D_BIN],
-- v3d_priv);
-+ if (bin) {
-+ ret = v3d_push_job(v3d_priv, &bin->base, V3D_BIN);
- if (ret)
- goto fail_unreserve;
-
-- exec->bin_done_fence =
-- dma_fence_get(&exec->bin.base.s_fence->finished);
--
-- kref_get(&exec->refcount); /* put by scheduler job completion */
-- drm_sched_entity_push_job(&exec->bin.base,
-- &v3d_priv->sched_entity[V3D_BIN]);
-+ render->bin_done_fence = dma_fence_get(bin->base.done_fence);
- }
-
-- ret = drm_sched_job_init(&exec->render.base,
-- &v3d_priv->sched_entity[V3D_RENDER],
-- v3d_priv);
-+ ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER);
- if (ret)
- goto fail_unreserve;
--
-- exec->render_done_fence =
-- dma_fence_get(&exec->render.base.s_fence->finished);
--
-- kref_get(&exec->refcount); /* put by scheduler job completion */
-- drm_sched_entity_push_job(&exec->render.base,
-- &v3d_priv->sched_entity[V3D_RENDER]);
- mutex_unlock(&v3d->sched_lock);
-
-- v3d_attach_object_fences(exec->bo, exec->bo_count,
-- exec->render_done_fence);
--
-- v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx);
--
-- /* Update the return sync object for the */
-- sync_out = drm_syncobj_find(file_priv, args->out_sync);
-- if (sync_out) {
-- drm_syncobj_replace_fence(sync_out,
-- exec->render_done_fence);
-- drm_syncobj_put(sync_out);
-- }
--
-- v3d_exec_put(exec);
-+ v3d_attach_fences_and_unlock_reservation(file_priv,
-+ &render->base, &acquire_ctx,
-+ args->out_sync);
-+
-+ if (bin)
-+ v3d_job_put(&bin->base);
-+ v3d_job_put(&render->base);
-
- return 0;
-
- fail_unreserve:
- mutex_unlock(&v3d->sched_lock);
-- v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx);
-+ v3d_unlock_bo_reservations(render->base.bo,
-+ render->base.bo_count, &acquire_ctx);
- fail:
-- v3d_exec_put(exec);
-+ if (bin)
-+ v3d_job_put(&bin->base);
-+ v3d_job_put(&render->base);
-
- return ret;
- }
-@@ -618,10 +649,7 @@ v3d_submit_tfu_ioctl(struct drm_device *
- struct drm_v3d_submit_tfu *args = data;
- struct v3d_tfu_job *job;
- struct ww_acquire_ctx acquire_ctx;
-- struct drm_syncobj *sync_out;
-- struct dma_fence *sched_done_fence;
- int ret = 0;
-- int bo_count;
-
- trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia);
-
-@@ -629,75 +657,66 @@ v3d_submit_tfu_ioctl(struct drm_device *
- if (!job)
- return -ENOMEM;
-
-- kref_init(&job->refcount);
--
-- ret = drm_syncobj_find_fence(file_priv, args->in_sync,
-- 0, &job->in_fence);
-- if (ret == -EINVAL)
-- goto fail;
-+ ret = v3d_job_init(v3d, file_priv, &job->base,
-+ v3d_job_free, args->in_sync);
-+ if (ret) {
-+ kfree(job);
-+ return ret;
-+ }
-
-+ job->base.bo = kcalloc(ARRAY_SIZE(args->bo_handles),
-+ sizeof(*job->base.bo), GFP_KERNEL);
- job->args = *args;
-- job->v3d = v3d;
-
- spin_lock(&file_priv->table_lock);
-- for (bo_count = 0; bo_count < ARRAY_SIZE(job->bo); bo_count++) {
-+ for (job->base.bo_count = 0;
-+ job->base.bo_count < ARRAY_SIZE(args->bo_handles);
-+ job->base.bo_count++) {
- struct drm_gem_object *bo;
-
-- if (!args->bo_handles[bo_count])
-+ if (!args->bo_handles[job->base.bo_count])
- break;
-
- bo = idr_find(&file_priv->object_idr,
-- args->bo_handles[bo_count]);
-+ args->bo_handles[job->base.bo_count]);
- if (!bo) {
- DRM_DEBUG("Failed to look up GEM BO %d: %d\n",
-- bo_count, args->bo_handles[bo_count]);
-+ job->base.bo_count,
-+ args->bo_handles[job->base.bo_count]);
- ret = -ENOENT;
- spin_unlock(&file_priv->table_lock);
- goto fail;
- }
- drm_gem_object_get(bo);
-- job->bo[bo_count] = to_v3d_bo(bo);
-+ job->base.bo[job->base.bo_count] = to_v3d_bo(bo);
- }
- spin_unlock(&file_priv->table_lock);
-
-- ret = v3d_lock_bo_reservations(job->bo, bo_count, &acquire_ctx);
-+ ret = v3d_lock_bo_reservations(job->base.bo, job->base.bo_count,
-+ &acquire_ctx);
- if (ret)
- goto fail;
-
- mutex_lock(&v3d->sched_lock);
-- ret = drm_sched_job_init(&job->base,
-- &v3d_priv->sched_entity[V3D_TFU],
-- v3d_priv);
-+ ret = v3d_push_job(v3d_priv, &job->base, V3D_TFU);
- if (ret)
- goto fail_unreserve;
--
-- sched_done_fence = dma_fence_get(&job->base.s_fence->finished);
--
-- kref_get(&job->refcount); /* put by scheduler job completion */
-- drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[V3D_TFU]);
- mutex_unlock(&v3d->sched_lock);
-
-- v3d_attach_object_fences(job->bo, bo_count, sched_done_fence);
--
-- v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx);
--
-- /* Update the return sync object */
-- sync_out = drm_syncobj_find(file_priv, args->out_sync);
-- if (sync_out) {
-- drm_syncobj_replace_fence(sync_out, sched_done_fence);
-- drm_syncobj_put(sync_out);
-- }
-- dma_fence_put(sched_done_fence);
-+ v3d_attach_fences_and_unlock_reservation(file_priv,
-+ &job->base, &acquire_ctx,
-+ args->out_sync);
-
-- v3d_tfu_job_put(job);
-+ v3d_job_put(&job->base);
-
- return 0;
-
- fail_unreserve:
- mutex_unlock(&v3d->sched_lock);
-- v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx);
-+ v3d_unlock_bo_reservations(job->base.bo, job->base.bo_count,
-+ &acquire_ctx);
- fail:
-- v3d_tfu_job_put(job);
-+ v3d_job_put(&job->base);
-
- return ret;
- }
-@@ -755,7 +774,7 @@ v3d_gem_destroy(struct drm_device *dev)
-
- v3d_sched_fini(v3d);
-
-- /* Waiting for exec to finish would need to be done before
-+ /* Waiting for jobs to finish would need to be done before
- * unregistering V3D.
- */
- WARN_ON(v3d->bin_job);
---- a/drivers/gpu/drm/v3d/v3d_irq.c
-+++ b/drivers/gpu/drm/v3d/v3d_irq.c
-@@ -60,7 +60,7 @@ v3d_overflow_mem_work(struct work_struct
- }
-
- drm_gem_object_get(&bo->base);
-- list_add_tail(&bo->unref_head, &v3d->bin_job->unref_list);
-+ list_add_tail(&bo->unref_head, &v3d->bin_job->render->unref_list);
- spin_unlock_irqrestore(&v3d->job_lock, irqflags);
-
- V3D_CORE_WRITE(0, V3D_PTB_BPOA, bo->node.start << PAGE_SHIFT);
-@@ -93,7 +93,7 @@ v3d_irq(int irq, void *arg)
-
- if (intsts & V3D_INT_FLDONE) {
- struct v3d_fence *fence =
-- to_v3d_fence(v3d->bin_job->bin.irq_fence);
-+ to_v3d_fence(v3d->bin_job->base.irq_fence);
-
- trace_v3d_bcl_irq(&v3d->drm, fence->seqno);
- dma_fence_signal(&fence->base);
-@@ -102,7 +102,7 @@ v3d_irq(int irq, void *arg)
-
- if (intsts & V3D_INT_FRDONE) {
- struct v3d_fence *fence =
-- to_v3d_fence(v3d->render_job->render.irq_fence);
-+ to_v3d_fence(v3d->render_job->base.irq_fence);
-
- trace_v3d_rcl_irq(&v3d->drm, fence->seqno);
- dma_fence_signal(&fence->base);
-@@ -138,7 +138,7 @@ v3d_hub_irq(int irq, void *arg)
-
- if (intsts & V3D_HUB_INT_TFUC) {
- struct v3d_fence *fence =
-- to_v3d_fence(v3d->tfu_job->irq_fence);
-+ to_v3d_fence(v3d->tfu_job->base.irq_fence);
-
- trace_v3d_tfu_irq(&v3d->drm, fence->seqno);
- dma_fence_signal(&fence->base);
---- a/drivers/gpu/drm/v3d/v3d_sched.c
-+++ b/drivers/gpu/drm/v3d/v3d_sched.c
-@@ -30,39 +30,43 @@ to_v3d_job(struct drm_sched_job *sched_j
- return container_of(sched_job, struct v3d_job, base);
- }
-
--static struct v3d_tfu_job *
--to_tfu_job(struct drm_sched_job *sched_job)
-+static struct v3d_bin_job *
-+to_bin_job(struct drm_sched_job *sched_job)
- {
-- return container_of(sched_job, struct v3d_tfu_job, base);
-+ return container_of(sched_job, struct v3d_bin_job, base.base);
- }
-
--static void
--v3d_job_free(struct drm_sched_job *sched_job)
-+static struct v3d_render_job *
-+to_render_job(struct drm_sched_job *sched_job)
- {
-- struct v3d_job *job = to_v3d_job(sched_job);
-+ return container_of(sched_job, struct v3d_render_job, base.base);
-+}
-
-- v3d_exec_put(job->exec);
-+static struct v3d_tfu_job *
-+to_tfu_job(struct drm_sched_job *sched_job)
-+{
-+ return container_of(sched_job, struct v3d_tfu_job, base.base);
- }
-
- static void
--v3d_tfu_job_free(struct drm_sched_job *sched_job)
-+v3d_job_free(struct drm_sched_job *sched_job)
- {
-- struct v3d_tfu_job *job = to_tfu_job(sched_job);
-+ struct v3d_job *job = to_v3d_job(sched_job);
-
-- v3d_tfu_job_put(job);
-+ v3d_job_put(job);
- }
-
- /**
-- * Returns the fences that the bin or render job depends on, one by one.
-- * v3d_job_run() won't be called until all of them have been signaled.
-+ * Returns the fences that the job depends on, one by one.
-+ *
-+ * If placed in the scheduler's .dependency method, the corresponding
-+ * .run_job won't be called until all of them have been signaled.
- */
- static struct dma_fence *
- v3d_job_dependency(struct drm_sched_job *sched_job,
- struct drm_sched_entity *s_entity)
- {
- struct v3d_job *job = to_v3d_job(sched_job);
-- struct v3d_exec_info *exec = job->exec;
-- enum v3d_queue q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
- struct dma_fence *fence;
-
- fence = job->in_fence;
-@@ -71,113 +75,132 @@ v3d_job_dependency(struct drm_sched_job
- return fence;
- }
-
-- if (q == V3D_RENDER) {
-- /* If we had a bin job, the render job definitely depends on
-- * it. We first have to wait for bin to be scheduled, so that
-- * its done_fence is created.
-- */
-- fence = exec->bin_done_fence;
-- if (fence) {
-- exec->bin_done_fence = NULL;
-- return fence;
-- }
-- }
--
-- /* XXX: Wait on a fence for switching the GMP if necessary,
-- * and then do so.
-- */
--
-- return fence;
-+ return NULL;
- }
-
- /**
-- * Returns the fences that the TFU job depends on, one by one.
-- * v3d_tfu_job_run() won't be called until all of them have been
-- * signaled.
-+ * Returns the fences that the render job depends on, one by one.
-+ * v3d_job_run() won't be called until all of them have been signaled.
- */
- static struct dma_fence *
--v3d_tfu_job_dependency(struct drm_sched_job *sched_job,
-- struct drm_sched_entity *s_entity)
-+v3d_render_job_dependency(struct drm_sched_job *sched_job,
-+ struct drm_sched_entity *s_entity)
- {
-- struct v3d_tfu_job *job = to_tfu_job(sched_job);
-+ struct v3d_render_job *job = to_render_job(sched_job);
- struct dma_fence *fence;
-
-- fence = job->in_fence;
-+ fence = v3d_job_dependency(sched_job, s_entity);
-+ if (fence)
-+ return fence;
-+
-+ /* If we had a bin job, the render job definitely depends on
-+ * it. We first have to wait for bin to be scheduled, so that
-+ * its done_fence is created.
-+ */
-+ fence = job->bin_done_fence;
- if (fence) {
-- job->in_fence = NULL;
-+ job->bin_done_fence = NULL;
- return fence;
- }
-
-- return NULL;
-+ /* XXX: Wait on a fence for switching the GMP if necessary,
-+ * and then do so.
-+ */
-+
-+ return fence;
- }
-
--static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job)
-+static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
- {
-- struct v3d_job *job = to_v3d_job(sched_job);
-- struct v3d_exec_info *exec = job->exec;
-- enum v3d_queue q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
-- struct v3d_dev *v3d = exec->v3d;
-+ struct v3d_bin_job *job = to_bin_job(sched_job);
-+ struct v3d_dev *v3d = job->base.v3d;
- struct drm_device *dev = &v3d->drm;
- struct dma_fence *fence;
- unsigned long irqflags;
-
-- if (unlikely(job->base.s_fence->finished.error))
-+ if (unlikely(job->base.base.s_fence->finished.error))
- return NULL;
-
- /* Lock required around bin_job update vs
- * v3d_overflow_mem_work().
- */
- spin_lock_irqsave(&v3d->job_lock, irqflags);
-- if (q == V3D_BIN) {
-- v3d->bin_job = job->exec;
-+ v3d->bin_job = job;
-+ /* Clear out the overflow allocation, so we don't
-+ * reuse the overflow attached to a previous job.
-+ */
-+ V3D_CORE_WRITE(0, V3D_PTB_BPOS, 0);
-+ spin_unlock_irqrestore(&v3d->job_lock, irqflags);
-+
-+ v3d_invalidate_caches(v3d);
-
-- /* Clear out the overflow allocation, so we don't
-- * reuse the overflow attached to a previous job.
-- */
-- V3D_CORE_WRITE(0, V3D_PTB_BPOS, 0);
-- } else {
-- v3d->render_job = job->exec;
-+ fence = v3d_fence_create(v3d, V3D_BIN);
-+ if (IS_ERR(fence))
-+ return NULL;
-+
-+ if (job->base.irq_fence)
-+ dma_fence_put(job->base.irq_fence);
-+ job->base.irq_fence = dma_fence_get(fence);
-+
-+ trace_v3d_submit_cl(dev, false, to_v3d_fence(fence)->seqno,
-+ job->start, job->end);
-+
-+ /* Set the current and end address of the control list.
-+ * Writing the end register is what starts the job.
-+ */
-+ if (job->qma) {
-+ V3D_CORE_WRITE(0, V3D_CLE_CT0QMA, job->qma);
-+ V3D_CORE_WRITE(0, V3D_CLE_CT0QMS, job->qms);
- }
-- spin_unlock_irqrestore(&v3d->job_lock, irqflags);
-+ if (job->qts) {
-+ V3D_CORE_WRITE(0, V3D_CLE_CT0QTS,
-+ V3D_CLE_CT0QTS_ENABLE |
-+ job->qts);
-+ }
-+ V3D_CORE_WRITE(0, V3D_CLE_CT0QBA, job->start);
-+ V3D_CORE_WRITE(0, V3D_CLE_CT0QEA, job->end);
-+
-+ return fence;
-+}
-+
-+static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)
-+{
-+ struct v3d_render_job *job = to_render_job(sched_job);
-+ struct v3d_dev *v3d = job->base.v3d;
-+ struct drm_device *dev = &v3d->drm;
-+ struct dma_fence *fence;
-+
-+ if (unlikely(job->base.base.s_fence->finished.error))
-+ return NULL;
-
-- /* Can we avoid this flush when q==RENDER? We need to be
-- * careful of scheduling, though -- imagine job0 rendering to
-- * texture and job1 reading, and them being executed as bin0,
-- * bin1, render0, render1, so that render1's flush at bin time
-+ v3d->render_job = job;
-+
-+ /* Can we avoid this flush? We need to be careful of
-+ * scheduling, though -- imagine job0 rendering to texture and
-+ * job1 reading, and them being executed as bin0, bin1,
-+ * render0, render1, so that render1's flush at bin time
- * wasn't enough.
- */
- v3d_invalidate_caches(v3d);
-
-- fence = v3d_fence_create(v3d, q);
-+ fence = v3d_fence_create(v3d, V3D_RENDER);
- if (IS_ERR(fence))
- return NULL;
-
-- if (job->irq_fence)
-- dma_fence_put(job->irq_fence);
-- job->irq_fence = dma_fence_get(fence);
-+ if (job->base.irq_fence)
-+ dma_fence_put(job->base.irq_fence);
-+ job->base.irq_fence = dma_fence_get(fence);
-
-- trace_v3d_submit_cl(dev, q == V3D_RENDER, to_v3d_fence(fence)->seqno,
-+ trace_v3d_submit_cl(dev, true, to_v3d_fence(fence)->seqno,
- job->start, job->end);
-
-- if (q == V3D_BIN) {
-- if (exec->qma) {
-- V3D_CORE_WRITE(0, V3D_CLE_CT0QMA, exec->qma);
-- V3D_CORE_WRITE(0, V3D_CLE_CT0QMS, exec->qms);
-- }
-- if (exec->qts) {
-- V3D_CORE_WRITE(0, V3D_CLE_CT0QTS,
-- V3D_CLE_CT0QTS_ENABLE |
-- exec->qts);
-- }
-- } else {
-- /* XXX: Set the QCFG */
-- }
-+ /* XXX: Set the QCFG */
-
- /* Set the current and end address of the control list.
- * Writing the end register is what starts the job.
- */
-- V3D_CORE_WRITE(0, V3D_CLE_CTNQBA(q), job->start);
-- V3D_CORE_WRITE(0, V3D_CLE_CTNQEA(q), job->end);
-+ V3D_CORE_WRITE(0, V3D_CLE_CT1QBA, job->start);
-+ V3D_CORE_WRITE(0, V3D_CLE_CT1QEA, job->end);
-
- return fence;
- }
-@@ -186,7 +209,7 @@ static struct dma_fence *
- v3d_tfu_job_run(struct drm_sched_job *sched_job)
- {
- struct v3d_tfu_job *job = to_tfu_job(sched_job);
-- struct v3d_dev *v3d = job->v3d;
-+ struct v3d_dev *v3d = job->base.v3d;
- struct drm_device *dev = &v3d->drm;
- struct dma_fence *fence;
-
-@@ -195,9 +218,9 @@ v3d_tfu_job_run(struct drm_sched_job *sc
- return NULL;
-
- v3d->tfu_job = job;
-- if (job->irq_fence)
-- dma_fence_put(job->irq_fence);
-- job->irq_fence = dma_fence_get(fence);
-+ if (job->base.irq_fence)
-+ dma_fence_put(job->base.irq_fence);
-+ job->base.irq_fence = dma_fence_get(fence);
-
- trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);
-
-@@ -247,25 +270,23 @@ v3d_gpu_reset_for_timeout(struct v3d_dev
- mutex_unlock(&v3d->reset_lock);
- }
-
-+/* If the current address or return address have changed, then the GPU
-+ * has probably made progress and we should delay the reset. This
-+ * could fail if the GPU got in an infinite loop in the CL, but that
-+ * is pretty unlikely outside of an i-g-t testcase.
-+ */
- static void
--v3d_job_timedout(struct drm_sched_job *sched_job)
-+v3d_cl_job_timedout(struct drm_sched_job *sched_job, enum v3d_queue q,
-+ u32 *timedout_ctca, u32 *timedout_ctra)
- {
- struct v3d_job *job = to_v3d_job(sched_job);
-- struct v3d_exec_info *exec = job->exec;
-- struct v3d_dev *v3d = exec->v3d;
-- enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
-- u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q));
-- u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q));
--
-- /* If the current address or return address have changed, then
-- * the GPU has probably made progress and we should delay the
-- * reset. This could fail if the GPU got in an infinite loop
-- * in the CL, but that is pretty unlikely outside of an i-g-t
-- * testcase.
-- */
-- if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) {
-- job->timedout_ctca = ctca;
-- job->timedout_ctra = ctra;
-+ struct v3d_dev *v3d = job->v3d;
-+ u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(q));
-+ u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(q));
-+
-+ if (*timedout_ctca != ctca || *timedout_ctra != ctra) {
-+ *timedout_ctca = ctca;
-+ *timedout_ctra = ctra;
- schedule_delayed_work(&job->base.work_tdr,
- job->base.sched->timeout);
- return;
-@@ -275,25 +296,50 @@ v3d_job_timedout(struct drm_sched_job *s
- }
-
- static void
-+v3d_bin_job_timedout(struct drm_sched_job *sched_job)
-+{
-+ struct v3d_bin_job *job = to_bin_job(sched_job);
-+
-+ v3d_cl_job_timedout(sched_job, V3D_BIN,
-+ &job->timedout_ctca, &job->timedout_ctra);
-+}
-+
-+static void
-+v3d_render_job_timedout(struct drm_sched_job *sched_job)
-+{
-+ struct v3d_render_job *job = to_render_job(sched_job);
-+
-+ v3d_cl_job_timedout(sched_job, V3D_RENDER,
-+ &job->timedout_ctca, &job->timedout_ctra);
-+}
-+
-+static void
- v3d_tfu_job_timedout(struct drm_sched_job *sched_job)
- {
-- struct v3d_tfu_job *job = to_tfu_job(sched_job);
-+ struct v3d_job *job = to_v3d_job(sched_job);
-
- v3d_gpu_reset_for_timeout(job->v3d, sched_job);
- }
-
--static const struct drm_sched_backend_ops v3d_sched_ops = {
-+static const struct drm_sched_backend_ops v3d_bin_sched_ops = {
- .dependency = v3d_job_dependency,
-- .run_job = v3d_job_run,
-- .timedout_job = v3d_job_timedout,
-- .free_job = v3d_job_free
-+ .run_job = v3d_bin_job_run,
-+ .timedout_job = v3d_bin_job_timedout,
-+ .free_job = v3d_job_free,
-+};
-+
-+static const struct drm_sched_backend_ops v3d_render_sched_ops = {
-+ .dependency = v3d_render_job_dependency,
-+ .run_job = v3d_render_job_run,
-+ .timedout_job = v3d_render_job_timedout,
-+ .free_job = v3d_job_free,
- };
-
- static const struct drm_sched_backend_ops v3d_tfu_sched_ops = {
-- .dependency = v3d_tfu_job_dependency,
-+ .dependency = v3d_job_dependency,
- .run_job = v3d_tfu_job_run,
- .timedout_job = v3d_tfu_job_timedout,
-- .free_job = v3d_tfu_job_free
-+ .free_job = v3d_job_free,
- };
-
- int
-@@ -305,7 +351,7 @@ v3d_sched_init(struct v3d_dev *v3d)
- int ret;
-
- ret = drm_sched_init(&v3d->queue[V3D_BIN].sched,
-- &v3d_sched_ops,
-+ &v3d_bin_sched_ops,
- hw_jobs_limit, job_hang_limit,
- msecs_to_jiffies(hang_limit_ms),
- "v3d_bin");
-@@ -315,7 +361,7 @@ v3d_sched_init(struct v3d_dev *v3d)
- }
-
- ret = drm_sched_init(&v3d->queue[V3D_RENDER].sched,
-- &v3d_sched_ops,
-+ &v3d_render_sched_ops,
- hw_jobs_limit, job_hang_limit,
- msecs_to_jiffies(hang_limit_ms),
- "v3d_render");
--- /dev/null
+From b0fedd829bb6725fef7b2667c85badc6b4a8e5e0 Mon Sep 17 00:00:00 2001
+Date: Thu, 28 Mar 2019 11:58:51 -0700
+Subject: [PATCH] drm/vc4: Fix synchronization firmwarekms against GL
+ rendering.
+
+We would present the framebuffer immediately without waiting for
+rendering to finish first, resulting in stuttering and flickering as a
+window was dragged around when the GPU was busy enough to not just win
+the race.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -15,6 +15,7 @@
+ */
+
+ #include "drm/drm_atomic_helper.h"
++#include "drm/drm_gem_framebuffer_helper.h"
+ #include "drm/drm_plane_helper.h"
+ #include "drm/drm_crtc_helper.h"
+ #include "drm/drm_fourcc.h"
+@@ -291,7 +292,7 @@ static const struct drm_plane_funcs vc4_
+ };
+
+ static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
+- .prepare_fb = NULL,
++ .prepare_fb = drm_gem_fb_prepare_fb,
+ .cleanup_fb = NULL,
+ .atomic_check = vc4_plane_atomic_check,
+ .atomic_update = vc4_primary_plane_atomic_update,
+@@ -299,7 +300,7 @@ static const struct drm_plane_helper_fun
+ };
+
+ static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = {
+- .prepare_fb = NULL,
++ .prepare_fb = drm_gem_fb_prepare_fb,
+ .cleanup_fb = NULL,
+ .atomic_check = vc4_plane_atomic_check,
+ .atomic_update = vc4_cursor_plane_atomic_update,
+++ /dev/null
-From 7713f79b0a5473eb0b8456d36b99ae00815dd8a1 Mon Sep 17 00:00:00 2001
-Date: Wed, 27 Mar 2019 17:44:40 -0700
-Subject: [PATCH] drm/v3d: Add missing implicit synchronization.
-
-It is the expectation of existing userspace (X11 + Mesa, in
-particular) that jobs submitted to the kernel against a shared BO will
-get implicitly synchronized by their submission order. If we want to
-allow clever userspace to disable implicit synchronization, we should
-do that under its own submit flag (as amdgpu and lima do).
-
-Note that we currently only implicitly sync for the rendering pass,
-not binning -- if you texture-from-pixmap in the binning vertex shader
-(vertex coordinate generation), you'll miss out on synchronization.
-
-Fixes flickering when multiple clients are running in parallel,
-particularly GL apps and compositors.
-
----
- drivers/gpu/drm/v3d/v3d_drv.h | 10 +---
- drivers/gpu/drm/v3d/v3d_gem.c | 98 ++++++++++++++++++++++++++++++---
- drivers/gpu/drm/v3d/v3d_sched.c | 45 ++-------------
- 3 files changed, 96 insertions(+), 57 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.h
-+++ b/drivers/gpu/drm/v3d/v3d_drv.h
-@@ -186,8 +186,9 @@ struct v3d_job {
- struct v3d_bo **bo;
- u32 bo_count;
-
-- /* An optional fence userspace can pass in for the job to depend on. */
-- struct dma_fence *in_fence;
-+ struct dma_fence **deps;
-+ int deps_count;
-+ int deps_size;
-
- /* v3d fence to be signaled by IRQ handler when the job is complete. */
- struct dma_fence *irq_fence;
-@@ -219,11 +220,6 @@ struct v3d_bin_job {
- struct v3d_render_job {
- struct v3d_job base;
-
-- /* Optional fence for the binner, to depend on before starting
-- * our job.
-- */
-- struct dma_fence *bin_done_fence;
--
- /* GPU virtual addresses of the start/end of the CL job. */
- u32 start, end;
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -218,6 +218,71 @@ v3d_unlock_bo_reservations(struct v3d_bo
- ww_acquire_fini(acquire_ctx);
- }
-
-+static int
-+v3d_add_dep(struct v3d_job *job, struct dma_fence *fence)
-+{
-+ if (!fence)
-+ return 0;
-+
-+ if (job->deps_size == job->deps_count) {
-+ int new_deps_size = max(job->deps_size * 2, 4);
-+ struct dma_fence **new_deps =
-+ krealloc(job->deps, new_deps_size * sizeof(*new_deps),
-+ GFP_KERNEL);
-+ if (!new_deps) {
-+ dma_fence_put(fence);
-+ return -ENOMEM;
-+ }
-+
-+ job->deps = new_deps;
-+ job->deps_size = new_deps_size;
-+ }
-+
-+ job->deps[job->deps_count++] = fence;
-+
-+ return 0;
-+}
-+
-+/**
-+ * Adds the required implicit fences before executing the job
-+ *
-+ * Userspace (X11 + Mesa) requires that a job submitted against a shared BO
-+ * from one fd will implicitly synchronize against previous jobs submitted
-+ * against that BO from other fds.
-+ *
-+ * Currently we don't bother trying to track the shared BOs, and instead just
-+ * sync everything. However, our synchronization is only for the render pass
-+ * -- the binning stage (VS coordinate calculations) ignores implicit sync,
-+ * since using shared buffers for texture coordinates seems unlikely, and
-+ * implicitly syncing them would break bin/render parallelism. If we want to
-+ * fix that, we should introduce a flag when VS texturing has been used in the
-+ * binning stage, or a set of flags for which BOs are sampled during binning.
-+ */
-+static int
-+v3d_add_implicit_fences(struct v3d_job *job, struct v3d_bo *bo)
-+{
-+ int i, ret, nr_fences;
-+ struct dma_fence **fences;
-+
-+ ret = reservation_object_get_fences_rcu(bo->resv, NULL,
-+ &nr_fences, &fences);
-+ if (ret || !nr_fences)
-+ return ret;
-+
-+ for (i = 0; i < nr_fences; i++) {
-+ ret = v3d_add_dep(job, fences[i]);
-+ if (ret)
-+ break;
-+ }
-+
-+ /* Free any remaining fences after error. */
-+ for (; i < nr_fences; i++)
-+ dma_fence_put(fences[i]);
-+ kfree(fences);
-+
-+ return ret;
-+}
-+
- /* Takes the reservation lock on all the BOs being referenced, so that
- * at queue submit time we can update the reservations.
- *
-@@ -226,10 +291,11 @@ v3d_unlock_bo_reservations(struct v3d_bo
- * to v3d, so we don't attach dma-buf fences to them.
- */
- static int
--v3d_lock_bo_reservations(struct v3d_bo **bos,
-- int bo_count,
-+v3d_lock_bo_reservations(struct v3d_job *job,
- struct ww_acquire_ctx *acquire_ctx)
- {
-+ struct v3d_bo **bos = job->bo;
-+ int bo_count = job->bo_count;
- int contended_lock = -1;
- int i, ret;
-
-@@ -281,6 +347,13 @@ retry:
- * before we commit the CL to the hardware.
- */
- for (i = 0; i < bo_count; i++) {
-+ ret = v3d_add_implicit_fences(job, bos[i]);
-+ if (ret) {
-+ v3d_unlock_bo_reservations(bos, bo_count,
-+ acquire_ctx);
-+ return ret;
-+ }
-+
- ret = reservation_object_reserve_shared(bos[i]->resv);
- if (ret) {
- v3d_unlock_bo_reservations(bos, bo_count,
-@@ -383,7 +456,10 @@ v3d_job_free(struct kref *ref)
- }
- kvfree(job->bo);
-
-- dma_fence_put(job->in_fence);
-+ for (i = 0; i < job->deps_count; i++)
-+ dma_fence_put(job->deps[i]);
-+ kfree(job->deps);
-+
- dma_fence_put(job->irq_fence);
- dma_fence_put(job->done_fence);
-
-@@ -464,15 +540,20 @@ v3d_job_init(struct v3d_dev *v3d, struct
- struct v3d_job *job, void (*free)(struct kref *ref),
- u32 in_sync)
- {
-+ struct dma_fence *in_fence = NULL;
- int ret;
-
- job->v3d = v3d;
- job->free = free;
-
-- ret = drm_syncobj_find_fence(file_priv, in_sync, 0, &job->in_fence);
-+ ret = drm_syncobj_find_fence(file_priv, in_sync, 0, &in_fence);
- if (ret == -EINVAL)
- return ret;
-
-+ ret = v3d_add_dep(job, in_fence);
-+ if (ret)
-+ return ret;
-+
- kref_init(&job->refcount);
-
- return 0;
-@@ -590,8 +671,7 @@ v3d_submit_cl_ioctl(struct drm_device *d
- if (ret)
- goto fail;
-
-- ret = v3d_lock_bo_reservations(render->base.bo, render->base.bo_count,
-- &acquire_ctx);
-+ ret = v3d_lock_bo_reservations(&render->base, &acquire_ctx);
- if (ret)
- goto fail;
-
-@@ -601,7 +681,8 @@ v3d_submit_cl_ioctl(struct drm_device *d
- if (ret)
- goto fail_unreserve;
-
-- render->bin_done_fence = dma_fence_get(bin->base.done_fence);
-+ ret = v3d_add_dep(&render->base,
-+ dma_fence_get(bin->base.done_fence));
- }
-
- ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER);
-@@ -692,8 +773,7 @@ v3d_submit_tfu_ioctl(struct drm_device *
- }
- spin_unlock(&file_priv->table_lock);
-
-- ret = v3d_lock_bo_reservations(job->base.bo, job->base.bo_count,
-- &acquire_ctx);
-+ ret = v3d_lock_bo_reservations(&job->base, &acquire_ctx);
- if (ret)
- goto fail;
-
---- a/drivers/gpu/drm/v3d/v3d_sched.c
-+++ b/drivers/gpu/drm/v3d/v3d_sched.c
-@@ -67,47 +67,10 @@ v3d_job_dependency(struct drm_sched_job
- struct drm_sched_entity *s_entity)
- {
- struct v3d_job *job = to_v3d_job(sched_job);
-- struct dma_fence *fence;
--
-- fence = job->in_fence;
-- if (fence) {
-- job->in_fence = NULL;
-- return fence;
-- }
--
-- return NULL;
--}
-
--/**
-- * Returns the fences that the render job depends on, one by one.
-- * v3d_job_run() won't be called until all of them have been signaled.
-- */
--static struct dma_fence *
--v3d_render_job_dependency(struct drm_sched_job *sched_job,
-- struct drm_sched_entity *s_entity)
--{
-- struct v3d_render_job *job = to_render_job(sched_job);
-- struct dma_fence *fence;
--
-- fence = v3d_job_dependency(sched_job, s_entity);
-- if (fence)
-- return fence;
--
-- /* If we had a bin job, the render job definitely depends on
-- * it. We first have to wait for bin to be scheduled, so that
-- * its done_fence is created.
-- */
-- fence = job->bin_done_fence;
-- if (fence) {
-- job->bin_done_fence = NULL;
-- return fence;
-- }
--
-- /* XXX: Wait on a fence for switching the GMP if necessary,
-- * and then do so.
-- */
--
-- return fence;
-+ if (!job->deps_count)
-+ return NULL;
-+ return job->deps[--job->deps_count];
- }
-
- static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
-@@ -329,7 +292,7 @@ static const struct drm_sched_backend_op
- };
-
- static const struct drm_sched_backend_ops v3d_render_sched_ops = {
-- .dependency = v3d_render_job_dependency,
-+ .dependency = v3d_job_dependency,
- .run_job = v3d_render_job_run,
- .timedout_job = v3d_render_job_timedout,
- .free_job = v3d_job_free,
--- /dev/null
+From 561918ec5e668f9d940051737d861ee0592816f6 Mon Sep 17 00:00:00 2001
+Date: Fri, 29 Mar 2019 12:04:36 -0700
+Subject: [PATCH] drm/vc4: Make sure that vblank waits work without v3d
+ loaded.
+
+This flag exists to protect legacy drivers, but when vc4's v3d doesn't
+probe, it doesn't get set up by vc4_v3d.c's call of drm_irq_install.
+This resulted in applications running as fast as possible, and laggy
+performance from compton as it had to wait for the latest rendering by
+the application for its presentation.
+
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -422,6 +422,7 @@ int vc4_kms_load(struct drm_device *dev)
+ /* Set support for vblank irq fast disable, before drm_vblank_init() */
+ dev->vblank_disable_immediate = true;
+
++ dev->irq_enabled = true;
+ ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+ if (ret < 0) {
+ dev_err(dev->dev, "failed to initialize vblank\n");
--- /dev/null
+From c7fc1e1cf922bd548ac983ef48b883b6f83e35ae Mon Sep 17 00:00:00 2001
+Date: Mon, 18 Mar 2019 16:38:32 -0700
+Subject: [PATCH] drm/vc4: Expose the format modifiers for firmware
+ kms.
+
+This should technically not expose VC4_T_TILED on pi4. However, if we
+don't expose anything, then userspace will assume that display can
+handle whatever modifiers 3d can do (UIF on 2711). By exposing a
+list, that will get intersected with what 3D can do so that we get T
+tiling for display on 2710 and linear on 2711.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 33 +++++++++++++++++++++++++-
+ 1 file changed, 32 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -281,6 +281,27 @@ static void vc4_plane_destroy(struct drm
+ drm_plane_cleanup(plane);
+ }
+
++static bool vc4_fkms_format_mod_supported(struct drm_plane *plane,
++ uint32_t format,
++ uint64_t modifier)
++{
++ /* Support T_TILING for RGB formats only. */
++ switch (format) {
++ case DRM_FORMAT_XRGB8888:
++ case DRM_FORMAT_ARGB8888:
++ switch (modifier) {
++ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
++ case DRM_FORMAT_MOD_LINEAR:
++ case DRM_FORMAT_MOD_BROADCOM_UIF:
++ return true;
++ default:
++ return false;
++ }
++ default:
++ return false;
++ }
++}
++
+ static const struct drm_plane_funcs vc4_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+@@ -289,6 +310,7 @@ static const struct drm_plane_funcs vc4_
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
++ .format_mod_supported = vc4_fkms_format_mod_supported,
+ };
+
+ static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
+@@ -316,6 +338,14 @@ static struct drm_plane *vc4_fkms_plane_
+ u32 argb8888 = DRM_FORMAT_ARGB8888;
+ int ret = 0;
+ bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
++ static const uint64_t modifiers[] = {
++ DRM_FORMAT_MOD_LINEAR,
++ /* VC4_T_TILED should come after linear, because we
++ * would prefer to scan out linear (less bus traffic).
++ */
++ DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
++ DRM_FORMAT_MOD_INVALID,
++ };
+
+ vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
+ GFP_KERNEL);
+@@ -327,7 +357,8 @@ static struct drm_plane *vc4_fkms_plane_
+ plane = &vc4_plane->base;
+ ret = drm_universal_plane_init(dev, plane, 0xff,
+ &vc4_plane_funcs,
+- primary ? &xrgb8888 : &argb8888, 1, NULL,
++ primary ? &xrgb8888 : &argb8888, 1,
++ modifiers,
+ type, primary ? "primary" : "cursor");
+
+ if (type == DRM_PLANE_TYPE_PRIMARY) {
+++ /dev/null
-From b0fedd829bb6725fef7b2667c85badc6b4a8e5e0 Mon Sep 17 00:00:00 2001
-Date: Thu, 28 Mar 2019 11:58:51 -0700
-Subject: [PATCH] drm/vc4: Fix synchronization firmwarekms against GL
- rendering.
-
-We would present the framebuffer immediately without waiting for
-rendering to finish first, resulting in stuttering and flickering as a
-window was dragged around when the GPU was busy enough to not just win
-the race.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -15,6 +15,7 @@
- */
-
- #include "drm/drm_atomic_helper.h"
-+#include "drm/drm_gem_framebuffer_helper.h"
- #include "drm/drm_plane_helper.h"
- #include "drm/drm_crtc_helper.h"
- #include "drm/drm_fourcc.h"
-@@ -291,7 +292,7 @@ static const struct drm_plane_funcs vc4_
- };
-
- static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
-- .prepare_fb = NULL,
-+ .prepare_fb = drm_gem_fb_prepare_fb,
- .cleanup_fb = NULL,
- .atomic_check = vc4_plane_atomic_check,
- .atomic_update = vc4_primary_plane_atomic_update,
-@@ -299,7 +300,7 @@ static const struct drm_plane_helper_fun
- };
-
- static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = {
-- .prepare_fb = NULL,
-+ .prepare_fb = drm_gem_fb_prepare_fb,
- .cleanup_fb = NULL,
- .atomic_check = vc4_plane_atomic_check,
- .atomic_update = vc4_cursor_plane_atomic_update,
--- /dev/null
+From c0041a9fe33d6031267d9f3e2372833908e97337 Mon Sep 17 00:00:00 2001
+Date: Tue, 2 Apr 2019 13:29:00 -0700
+Subject: [PATCH] drm/vc4: Fix vblank timestamping for firmwarekms.
+
+The core doesn't expect a false return from the scanoutpos function in
+normal usage, so we were doing the precise vblank timestamping path
+and thus "immediate" vblank disables (even though firmwarekms can't
+actually disable vblanks interrupts, sigh), and the kernel would get
+confused when getting timestamp info when also turning vblanks back
+on.
+
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 3 ---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 ++++++
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -133,9 +133,6 @@ bool vc4_crtc_get_scanoutpos(struct drm_
+ int vblank_lines;
+ bool ret = false;
+
+- if (vc4->firmware_kms)
+- return 0;
+-
+ /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
+
+ /* Get optional system timestamp before query. */
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -673,6 +673,12 @@ static int vc4_fkms_bind(struct device *
+
+ vc4->firmware_kms = true;
+
++ /* firmware kms doesn't have precise a scanoutpos implementation, so
++ * we can't do the precise vblank timestamp mode.
++ */
++ drm->driver->get_scanout_position = NULL;
++ drm->driver->get_vblank_timestamp = NULL;
++
+ vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
+ if (!vc4_crtc)
+ return -ENOMEM;
+++ /dev/null
-From 561918ec5e668f9d940051737d861ee0592816f6 Mon Sep 17 00:00:00 2001
-Date: Fri, 29 Mar 2019 12:04:36 -0700
-Subject: [PATCH] drm/vc4: Make sure that vblank waits work without v3d
- loaded.
-
-This flag exists to protect legacy drivers, but when vc4's v3d doesn't
-probe, it doesn't get set up by vc4_v3d.c's call of drm_irq_install.
-This resulted in applications running as fast as possible, and laggy
-performance from compton as it had to wait for the latest rendering by
-the application for its presentation.
-
----
- drivers/gpu/drm/vc4/vc4_kms.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -422,6 +422,7 @@ int vc4_kms_load(struct drm_device *dev)
- /* Set support for vblank irq fast disable, before drm_vblank_init() */
- dev->vblank_disable_immediate = true;
-
-+ dev->irq_enabled = true;
- ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
- if (ret < 0) {
- dev_err(dev->dev, "failed to initialize vblank\n");
+++ /dev/null
-From c7fc1e1cf922bd548ac983ef48b883b6f83e35ae Mon Sep 17 00:00:00 2001
-Date: Mon, 18 Mar 2019 16:38:32 -0700
-Subject: [PATCH] drm/vc4: Expose the format modifiers for firmware
- kms.
-
-This should technically not expose VC4_T_TILED on pi4. However, if we
-don't expose anything, then userspace will assume that display can
-handle whatever modifiers 3d can do (UIF on 2711). By exposing a
-list, that will get intersected with what 3D can do so that we get T
-tiling for display on 2710 and linear on 2711.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 33 +++++++++++++++++++++++++-
- 1 file changed, 32 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -281,6 +281,27 @@ static void vc4_plane_destroy(struct drm
- drm_plane_cleanup(plane);
- }
-
-+static bool vc4_fkms_format_mod_supported(struct drm_plane *plane,
-+ uint32_t format,
-+ uint64_t modifier)
-+{
-+ /* Support T_TILING for RGB formats only. */
-+ switch (format) {
-+ case DRM_FORMAT_XRGB8888:
-+ case DRM_FORMAT_ARGB8888:
-+ switch (modifier) {
-+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
-+ case DRM_FORMAT_MOD_LINEAR:
-+ case DRM_FORMAT_MOD_BROADCOM_UIF:
-+ return true;
-+ default:
-+ return false;
-+ }
-+ default:
-+ return false;
-+ }
-+}
-+
- static const struct drm_plane_funcs vc4_plane_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
-@@ -289,6 +310,7 @@ static const struct drm_plane_funcs vc4_
- .reset = drm_atomic_helper_plane_reset,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
-+ .format_mod_supported = vc4_fkms_format_mod_supported,
- };
-
- static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
-@@ -316,6 +338,14 @@ static struct drm_plane *vc4_fkms_plane_
- u32 argb8888 = DRM_FORMAT_ARGB8888;
- int ret = 0;
- bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
-+ static const uint64_t modifiers[] = {
-+ DRM_FORMAT_MOD_LINEAR,
-+ /* VC4_T_TILED should come after linear, because we
-+ * would prefer to scan out linear (less bus traffic).
-+ */
-+ DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
-+ DRM_FORMAT_MOD_INVALID,
-+ };
-
- vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
- GFP_KERNEL);
-@@ -327,7 +357,8 @@ static struct drm_plane *vc4_fkms_plane_
- plane = &vc4_plane->base;
- ret = drm_universal_plane_init(dev, plane, 0xff,
- &vc4_plane_funcs,
-- primary ? &xrgb8888 : &argb8888, 1, NULL,
-+ primary ? &xrgb8888 : &argb8888, 1,
-+ modifiers,
- type, primary ? "primary" : "cursor");
-
- if (type == DRM_PLANE_TYPE_PRIMARY) {
--- /dev/null
+From 3819888738de087ba726ceaa2ab20503f164f1ed Mon Sep 17 00:00:00 2001
+Date: Tue, 26 Mar 2019 14:43:06 +0000
+Subject: [PATCH] gpu: vc4-fkms: Switch to the newer mailbox frame
+ buffer API.
+
+The old mailbox FB API was ideally deprecated but still used by
+the FKMS driver.
+Update to the newer API.
+
+NB This needs current firmware that accepts ARM allocated buffers
+through the newer API.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 109 +++++++++++----------
+ include/soc/bcm2835/raspberrypi-firmware.h | 10 ++
+ 2 files changed, 67 insertions(+), 52 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -28,6 +28,25 @@
+ #include "vc4_regs.h"
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
++struct fb_alloc_tags {
++ struct rpi_firmware_property_tag_header tag1;
++ u32 xres, yres;
++ struct rpi_firmware_property_tag_header tag2;
++ u32 xres_virtual, yres_virtual;
++ struct rpi_firmware_property_tag_header tag3;
++ u32 bpp;
++ struct rpi_firmware_property_tag_header tag4;
++ u32 xoffset, yoffset;
++ struct rpi_firmware_property_tag_header tag5;
++ u32 base, screen_size;
++ struct rpi_firmware_property_tag_header tag6;
++ u32 pitch;
++ struct rpi_firmware_property_tag_header tag7;
++ u32 alpha_mode;
++ struct rpi_firmware_property_tag_header tag8;
++ u32 layer;
++};
++
+ /* The firmware delivers a vblank interrupt to us through the SMI
+ * hardware, which has only this one register.
+ */
+@@ -121,45 +140,39 @@ static void vc4_primary_plane_atomic_upd
+ struct drm_plane_state *old_state)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+- volatile struct fbinfo_s *fbinfo = vc4_plane->fbinfo;
++ u32 format = fb->format->format;
++ struct fb_alloc_tags fbinfo = {
++ .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT,
++ 8, 0, },
++ .xres = state->crtc_w,
++ .yres = state->crtc_h,
++ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT,
++ 8, 0, },
++ .xres_virtual = state->crtc_w,
++ .yres_virtual = state->crtc_h,
++ .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 },
++ .bpp = 32,
++ .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 },
++ .xoffset = 0,
++ .yoffset = 0,
++ .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
++ .base = bo->paddr + fb->offsets[0],
++ .screen_size = state->crtc_w * state->crtc_h * 4,
++ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
++ .pitch = fb->pitches[0],
++ .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 },
++ .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2,
++ .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 },
++ .layer = -127,
++ };
+ u32 bpp = 32;
+ int ret;
+
+- fbinfo->xres = state->crtc_w;
+- fbinfo->yres = state->crtc_h;
+- fbinfo->xres_virtual = state->crtc_w;
+- fbinfo->yres_virtual = state->crtc_h;
+- fbinfo->bpp = bpp;
+- fbinfo->xoffset = state->crtc_x;
+- fbinfo->yoffset = state->crtc_y;
+- fbinfo->base = bo->paddr + fb->offsets[0];
+- fbinfo->pitch = fb->pitches[0];
+-
+ if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
+- fbinfo->bpp |= BIT(31);
+-
+- /* A bug in the firmware makes it so that if the fb->base is
+- * set to nonzero, the configured pitch gets overwritten with
+- * the previous pitch. So, to get the configured pitch
+- * recomputed, we have to make it allocate itself a new buffer
+- * in VC memory, first.
+- */
+- if (vc4_plane->pitch != fb->pitches[0]) {
+- u32 saved_base = fbinfo->base;
+- fbinfo->base = 0;
+-
+- ret = rpi_firmware_transaction(vc4->firmware,
+- RPI_FIRMWARE_CHAN_FB,
+- vc4_plane->fbinfo_bus_addr);
+- fbinfo->base = saved_base;
+-
+- vc4_plane->pitch = fbinfo->pitch;
+- WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]);
+- }
++ fbinfo.bpp |= BIT(31);
+
+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n",
+ plane->base.id, plane->name,
+@@ -168,14 +181,13 @@ static void vc4_primary_plane_atomic_upd
+ bpp,
+ state->crtc_x,
+ state->crtc_y,
+- &fbinfo->base,
++ &fbinfo.base,
+ fb->pitches[0]);
+
+- ret = rpi_firmware_transaction(vc4->firmware,
+- RPI_FIRMWARE_CHAN_FB,
+- vc4_plane->fbinfo_bus_addr);
+- WARN_ON_ONCE(fbinfo->pitch != fb->pitches[0]);
+- WARN_ON_ONCE(fbinfo->base != bo->paddr + fb->offsets[0]);
++ ret = rpi_firmware_property_list(vc4->firmware, &fbinfo,
++ sizeof(fbinfo));
++ WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]);
++ WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]);
+
+ /* If the CRTC is on (or going to be on) and we're enabled,
+ * then unblank. Otherwise, stay blank until CRTC enable.
+@@ -332,10 +344,10 @@ static const struct drm_plane_helper_fun
+ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
+ enum drm_plane_type type)
+ {
++ /* Primary and cursor planes only */
+ struct drm_plane *plane = NULL;
+ struct vc4_fkms_plane *vc4_plane;
+- u32 xrgb8888 = DRM_FORMAT_XRGB8888;
+- u32 argb8888 = DRM_FORMAT_ARGB8888;
++ u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
+ int ret = 0;
+ bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
+ static const uint64_t modifiers[] = {
+@@ -357,22 +369,15 @@ static struct drm_plane *vc4_fkms_plane_
+ plane = &vc4_plane->base;
+ ret = drm_universal_plane_init(dev, plane, 0xff,
+ &vc4_plane_funcs,
+- primary ? &xrgb8888 : &argb8888, 1,
+- modifiers,
++ formats, primary ? 2 : 1, modifiers,
+ type, primary ? "primary" : "cursor");
+
+- if (type == DRM_PLANE_TYPE_PRIMARY) {
+- vc4_plane->fbinfo =
+- dma_alloc_coherent(dev->dev,
+- sizeof(*vc4_plane->fbinfo),
+- &vc4_plane->fbinfo_bus_addr,
+- GFP_KERNEL);
+- memset(vc4_plane->fbinfo, 0, sizeof(*vc4_plane->fbinfo));
+-
++ if (type == DRM_PLANE_TYPE_PRIMARY)
+ drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs);
+- } else {
++ else
+ drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs);
+- }
++
++ drm_plane_create_alpha_property(plane);
+
+ return plane;
+ fail:
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -111,9 +111,15 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_LAYER = 0x0004000c,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_TRANSFORM = 0x0004000d,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_VSYNC = 0x0004000e,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
+ RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
++ RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM = 0x00048013,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS = 0x00040013,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 0x00040014,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005,
+@@ -122,6 +128,8 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
++ RPI_FIRMWARE_FRAMEBUFFER_TEST_LAYER = 0x0004400c,
++ RPI_FIRMWARE_FRAMEBUFFER_TEST_TRANSFORM = 0x0004400d,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
+@@ -134,6 +142,8 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
++ RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER = 0x0004800c,
++ RPI_FIRMWARE_FRAMEBUFFER_SET_TRANSFORM = 0x0004800d,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
+
+ RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
--- /dev/null
+From 953d85d97f59691dccbbca743c478a8b01f92b59 Mon Sep 17 00:00:00 2001
+Date: Wed, 27 Mar 2019 17:45:01 +0000
+Subject: [PATCH] drm: vc4: Add an overlay plane to vc4-firmware-kms
+
+This uses a new API that is exposed via the mailbox service
+to stick an element straight on the screen using DispmanX.
+
+The primary and cursor planes have also been switched to using
+the new plane API, and it supports layering based on the DRM
+zpos parameter.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 518 ++++++++++++++-------
+ drivers/gpu/drm/vc4/vc4_kms.c | 1 +
+ drivers/gpu/drm/vc4/vc_image_types.h | 143 ++++++
+ include/soc/bcm2835/raspberrypi-firmware.h | 2 +
+ 4 files changed, 495 insertions(+), 169 deletions(-)
+ create mode 100644 drivers/gpu/drm/vc4/vc_image_types.h
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -26,8 +26,46 @@
+ #include "linux/of_device.h"
+ #include "vc4_drv.h"
+ #include "vc4_regs.h"
++#include "vc_image_types.h"
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
++struct set_plane {
++ u8 display;
++ u8 plane_id;
++ u8 vc_image_type;
++ s8 layer;
++
++ u16 width;
++ u16 height;
++
++ u16 pitch;
++ u16 vpitch;
++
++ u32 src_x; /* 16p16 */
++ u32 src_y; /* 16p16 */
++
++ u32 src_w; /* 16p16 */
++ u32 src_h; /* 16p16 */
++
++ s16 dst_x;
++ s16 dst_y;
++
++ u16 dst_w;
++ u16 dst_h;
++
++ u8 alpha;
++ u8 num_planes;
++ u8 is_vu;
++ u8 padding;
++
++ u32 planes[4]; /* DMA address of each plane */
++};
++
++struct mailbox_set_plane {
++ struct rpi_firmware_property_tag_header tag;
++ struct set_plane plane;
++};
++
+ struct fb_alloc_tags {
+ struct rpi_firmware_property_tag_header tag1;
+ u32 xres, yres;
+@@ -47,6 +85,79 @@ struct fb_alloc_tags {
+ u32 layer;
+ };
+
++static const struct vc_image_format {
++ u32 drm; /* DRM_FORMAT_* */
++ u32 vc_image; /* VC_IMAGE_* */
++ u32 is_vu;
++} vc_image_formats[] = {
++ {
++ .drm = DRM_FORMAT_XRGB8888,
++ .vc_image = VC_IMAGE_XRGB8888,
++ },
++ {
++ .drm = DRM_FORMAT_ARGB8888,
++ .vc_image = VC_IMAGE_ARGB8888,
++ },
++/*
++ * FIXME: Need to resolve which DRM format goes to which vc_image format
++ * for the remaining RGBA and RGBX formats.
++ * {
++ * .drm = DRM_FORMAT_ABGR8888,
++ * .vc_image = VC_IMAGE_RGBA8888,
++ * },
++ * {
++ * .drm = DRM_FORMAT_XBGR8888,
++ * .vc_image = VC_IMAGE_RGBA8888,
++ * },
++ */
++ {
++ .drm = DRM_FORMAT_RGB565,
++ .vc_image = VC_IMAGE_RGB565,
++ },
++ {
++ .drm = DRM_FORMAT_RGB888,
++ .vc_image = VC_IMAGE_BGR888,
++ },
++ {
++ .drm = DRM_FORMAT_BGR888,
++ .vc_image = VC_IMAGE_RGB888,
++ },
++ {
++ .drm = DRM_FORMAT_YUV422,
++ .vc_image = VC_IMAGE_YUV422PLANAR,
++ },
++ {
++ .drm = DRM_FORMAT_YUV420,
++ .vc_image = VC_IMAGE_YUV420,
++ },
++ {
++ .drm = DRM_FORMAT_YVU420,
++ .vc_image = VC_IMAGE_YUV420,
++ .is_vu = 1,
++ },
++ {
++ .drm = DRM_FORMAT_NV12,
++ .vc_image = VC_IMAGE_YUV420SP,
++ },
++ {
++ .drm = DRM_FORMAT_NV21,
++ .vc_image = VC_IMAGE_YUV420SP,
++ .is_vu = 1,
++ },
++};
++
++static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++) {
++ if (vc_image_formats[i].drm == drm_format)
++ return &vc_image_formats[i];
++ }
++
++ return NULL;
++}
++
+ /* The firmware delivers a vblank interrupt to us through the SMI
+ * hardware, which has only this one register.
+ */
+@@ -113,6 +224,7 @@ struct vc4_fkms_plane {
+ struct fbinfo_s *fbinfo;
+ dma_addr_t fbinfo_bus_addr;
+ u32 pitch;
++ struct mailbox_set_plane mb;
+ };
+
+ static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane)
+@@ -120,165 +232,183 @@ static inline struct vc4_fkms_plane *to_
+ return (struct vc4_fkms_plane *)plane;
+ }
+
+-/* Turns the display on/off. */
+-static int vc4_plane_set_primary_blank(struct drm_plane *plane, bool blank)
++static int vc4_plane_set_blank(struct drm_plane *plane, bool blank)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
++ struct mailbox_set_plane blank_mb = {
++ .tag = { RPI_FIRMWARE_SET_PLANE, sizeof(struct set_plane), 0 },
++ .plane = {
++ .display = vc4_plane->mb.plane.display,
++ .plane_id = vc4_plane->mb.plane.plane_id,
++ }
++ };
++ int ret;
+
+- u32 packet = blank;
+-
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary plane %s",
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s",
+ plane->base.id, plane->name,
+ blank ? "blank" : "unblank");
+
+- return rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_FRAMEBUFFER_BLANK,
+- &packet, sizeof(packet));
++ if (blank)
++ ret = rpi_firmware_property_list(vc4->firmware, &blank_mb,
++ sizeof(blank_mb));
++ else
++ ret = rpi_firmware_property_list(vc4->firmware, &vc4_plane->mb,
++ sizeof(vc4_plane->mb));
++
++ WARN_ONCE(ret, "%s: firmware call failed. Please update your firmware",
++ __func__);
++ return ret;
+ }
+
+-static void vc4_primary_plane_atomic_update(struct drm_plane *plane,
+- struct drm_plane_state *old_state)
++static void vc4_plane_atomic_update(struct drm_plane *plane,
++ struct drm_plane_state *old_state)
+ {
+- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+- u32 format = fb->format->format;
+- struct fb_alloc_tags fbinfo = {
+- .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT,
+- 8, 0, },
+- .xres = state->crtc_w,
+- .yres = state->crtc_h,
+- .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT,
+- 8, 0, },
+- .xres_virtual = state->crtc_w,
+- .yres_virtual = state->crtc_h,
+- .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 },
+- .bpp = 32,
+- .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 },
+- .xoffset = 0,
+- .yoffset = 0,
+- .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
+- .base = bo->paddr + fb->offsets[0],
+- .screen_size = state->crtc_w * state->crtc_h * 4,
+- .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
+- .pitch = fb->pitches[0],
+- .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 },
+- .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2,
+- .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 },
+- .layer = -127,
+- };
+- u32 bpp = 32;
+- int ret;
++ const struct drm_format_info *drm_fmt = fb->format;
++ const struct vc_image_format *vc_fmt =
++ vc4_get_vc_image_fmt(drm_fmt->format);
++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
++ struct mailbox_set_plane *mb = &vc4_plane->mb;
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
++ int num_planes = fb->format->num_planes;
++ struct drm_display_mode *mode = &state->crtc->mode;
+
+- if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
+- fbinfo.bpp |= BIT(31);
++ mb->plane.vc_image_type = vc_fmt->vc_image;
++ mb->plane.width = fb->width;
++ mb->plane.height = fb->height;
++ mb->plane.pitch = fb->pitches[0];
++ mb->plane.src_w = state->src_w;
++ mb->plane.src_h = state->src_h;
++ mb->plane.src_x = state->src_x;
++ mb->plane.src_y = state->src_y;
++ mb->plane.dst_w = state->crtc_w;
++ mb->plane.dst_h = state->crtc_h;
++ mb->plane.dst_x = state->crtc_x;
++ mb->plane.dst_y = state->crtc_y;
++ mb->plane.alpha = state->alpha >> 8;
++ mb->plane.layer = state->normalized_zpos ?
++ state->normalized_zpos : -127;
++ mb->plane.num_planes = num_planes;
++ mb->plane.is_vu = vc_fmt->is_vu;
++ mb->plane.planes[0] = bo->paddr + fb->offsets[0];
+
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n",
++ /* FIXME: If the dest rect goes off screen then clip the src rect so we
++ * don't have off-screen pixels.
++ */
++ if (plane->type == DRM_PLANE_TYPE_CURSOR) {
++ /* There is no scaling on the cursor plane, therefore the calcs
++ * to alter the source crop as the cursor goes off the screen
++ * are simple.
++ */
++ if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) {
++ mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x;
++ mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x)
++ << 16;
++ }
++ if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) {
++ mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y;
++ mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y)
++ << 16;
++ }
++ }
++
++ if (num_planes > 1) {
++ /* Assume this must be YUV */
++ /* Makes assumptions on the stride for the chroma planes as we
++ * can't easily plumb in non-standard pitches.
++ */
++ mb->plane.planes[1] = bo->paddr + fb->offsets[1];
++ if (num_planes > 2)
++ mb->plane.planes[2] = bo->paddr + fb->offsets[2];
++ else
++ mb->plane.planes[2] = 0;
++
++ /* Special case the YUV420 with U and V as line interleaved
++ * planes as we have special handling for that case.
++ */
++ if (num_planes == 3 &&
++ (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1])
++ mb->plane.vc_image_type = VC_IMAGE_YUV420_S;
++ } else {
++ mb->plane.planes[1] = 0;
++ mb->plane.planes[2] = 0;
++ }
++ mb->plane.planes[3] = 0;
++
++ switch (fb->modifier) {
++ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
++ switch (mb->plane.vc_image_type) {
++ case VC_IMAGE_RGBX32:
++ mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32;
++ break;
++ case VC_IMAGE_RGBA32:
++ mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
++ break;
++ case VC_IMAGE_RGB565:
++ mb->plane.vc_image_type = VC_IMAGE_TF_RGB565;
++ break;
++ }
++ break;
++ case DRM_FORMAT_MOD_BROADCOM_SAND128:
++ mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
++ mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
++ break;
++ }
++
++ if (vc4_crtc) {
++ mb->plane.dst_x += vc4_crtc->overscan[0];
++ mb->plane.dst_y += vc4_crtc->overscan[1];
++ }
++
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n",
+ plane->base.id, plane->name,
+- state->crtc_w,
+- state->crtc_h,
+- bpp,
++ mb->plane.width,
++ mb->plane.height,
++ mb->plane.vc_image_type,
+ state->crtc_x,
+ state->crtc_y,
+- &fbinfo.base,
+- fb->pitches[0]);
+-
+- ret = rpi_firmware_property_list(vc4->firmware, &fbinfo,
+- sizeof(fbinfo));
+- WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]);
+- WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]);
+-
+- /* If the CRTC is on (or going to be on) and we're enabled,
++ state->crtc_w,
++ state->crtc_h,
++ mb->plane.src_x,
++ mb->plane.src_y,
++ mb->plane.src_w,
++ mb->plane.src_h,
++ mb->plane.planes[0],
++ mb->plane.planes[1],
++ mb->plane.planes[2],
++ fb->pitches[0],
++ state->alpha,
++ state->normalized_zpos);
++
++ /*
++ * Do NOT set now, as we haven't checked if the crtc is active or not.
++ * Set from vc4_plane_set_blank instead.
++ *
++ * If the CRTC is on (or going to be on) and we're enabled,
+ * then unblank. Otherwise, stay blank until CRTC enable.
+- */
++ */
+ if (state->crtc->state->active)
+- vc4_plane_set_primary_blank(plane, false);
++ vc4_plane_set_blank(plane, false);
+ }
+
+-static void vc4_primary_plane_atomic_disable(struct drm_plane *plane,
+- struct drm_plane_state *old_state)
++static void vc4_plane_atomic_disable(struct drm_plane *plane,
++ struct drm_plane_state *old_state)
+ {
+- vc4_plane_set_primary_blank(plane, true);
+-}
+-
+-static void vc4_cursor_plane_atomic_update(struct drm_plane *plane,
+- struct drm_plane_state *old_state)
+-{
+- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
++ //struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+ struct drm_plane_state *state = plane->state;
+- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
+- struct drm_framebuffer *fb = state->fb;
+- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+- dma_addr_t addr = bo->paddr + fb->offsets[0];
+- int ret;
+- u32 packet_state[] = {
+- state->crtc->state->active,
+- state->crtc_x,
+- state->crtc_y,
+- 0
+- };
+- WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4);
++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%pad/%d)",
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
+ plane->base.id, plane->name,
+ state->crtc_w,
+ state->crtc_h,
++ vc4_plane->mb.plane.vc_image_type,
+ state->crtc_x,
+- state->crtc_y,
+- &addr,
+- fb->pitches[0]);
+-
+- /* add on the top/left offsets when overscan is active */
+- if (vc4_crtc) {
+- packet_state[1] += vc4_crtc->overscan[0];
+- packet_state[2] += vc4_crtc->overscan[1];
+- }
+-
+- ret = rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_SET_CURSOR_STATE,
+- &packet_state,
+- sizeof(packet_state));
+- if (ret || packet_state[0] != 0)
+- DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
+-
+- /* Note: When the cursor contents change, the modesetting
+- * driver calls drm_mode_cursor_univeral() with
+- * DRM_MODE_CURSOR_BO, which means a new fb will be allocated.
+- */
+- if (!old_state ||
+- state->crtc_w != old_state->crtc_w ||
+- state->crtc_h != old_state->crtc_h ||
+- fb != old_state->fb) {
+- u32 packet_info[] = { state->crtc_w, state->crtc_h,
+- 0, /* unused */
+- addr,
+- 0, 0, /* hotx, hoty */};
+-
+- ret = rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_SET_CURSOR_INFO,
+- &packet_info,
+- sizeof(packet_info));
+- if (ret || packet_info[0] != 0)
+- DRM_ERROR("Failed to set cursor info: 0x%08x\n", packet_info[0]);
+- }
+-}
+-
+-static void vc4_cursor_plane_atomic_disable(struct drm_plane *plane,
+- struct drm_plane_state *old_state)
+-{
+- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+- u32 packet_state[] = { false, 0, 0, 0 };
+- int ret;
+-
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] disabling cursor", plane->base.id, plane->name);
+-
+- ret = rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_SET_CURSOR_STATE,
+- &packet_state,
+- sizeof(packet_state));
+- if (ret || packet_state[0] != 0)
+- DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
++ state->crtc_y);
++ vc4_plane_set_blank(plane, true);
+ }
+
+ static int vc4_plane_atomic_check(struct drm_plane *plane,
+@@ -301,6 +431,7 @@ static bool vc4_fkms_format_mod_supporte
+ switch (format) {
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ARGB8888:
++ case DRM_FORMAT_RGB565:
+ switch (modifier) {
+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+ case DRM_FORMAT_MOD_LINEAR:
+@@ -309,8 +440,22 @@ static bool vc4_fkms_format_mod_supporte
+ default:
+ return false;
+ }
++ case DRM_FORMAT_NV12:
++ case DRM_FORMAT_NV21:
++ switch (fourcc_mod_broadcom_mod(modifier)) {
++ case DRM_FORMAT_MOD_LINEAR:
++ case DRM_FORMAT_MOD_BROADCOM_SAND128:
++ return true;
++ default:
++ return false;
++ }
++ case DRM_FORMAT_RGB888:
++ case DRM_FORMAT_BGR888:
++ case DRM_FORMAT_YUV422:
++ case DRM_FORMAT_YUV420:
++ case DRM_FORMAT_YVU420:
+ default:
+- return false;
++ return (modifier == DRM_FORMAT_MOD_LINEAR);
+ }
+ }
+
+@@ -325,31 +470,24 @@ static const struct drm_plane_funcs vc4_
+ .format_mod_supported = vc4_fkms_format_mod_supported,
+ };
+
+-static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
+- .prepare_fb = drm_gem_fb_prepare_fb,
+- .cleanup_fb = NULL,
+- .atomic_check = vc4_plane_atomic_check,
+- .atomic_update = vc4_primary_plane_atomic_update,
+- .atomic_disable = vc4_primary_plane_atomic_disable,
+-};
+-
+-static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = {
++static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
+ .prepare_fb = drm_gem_fb_prepare_fb,
+ .cleanup_fb = NULL,
+ .atomic_check = vc4_plane_atomic_check,
+- .atomic_update = vc4_cursor_plane_atomic_update,
+- .atomic_disable = vc4_cursor_plane_atomic_disable,
++ .atomic_update = vc4_plane_atomic_update,
++ .atomic_disable = vc4_plane_atomic_disable,
+ };
+
+ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
+- enum drm_plane_type type)
++ enum drm_plane_type type,
++ u8 plane_id)
+ {
+- /* Primary and cursor planes only */
+ struct drm_plane *plane = NULL;
+ struct vc4_fkms_plane *vc4_plane;
+- u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
++ u32 formats[ARRAY_SIZE(vc_image_formats)];
++ unsigned int default_zpos;
++ u32 num_formats = 0;
+ int ret = 0;
+- bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
+ static const uint64_t modifiers[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ /* VC4_T_TILED should come after linear, because we
+@@ -358,6 +496,7 @@ static struct drm_plane *vc4_fkms_plane_
+ DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
+ DRM_FORMAT_MOD_INVALID,
+ };
++ int i;
+
+ vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
+ GFP_KERNEL);
+@@ -366,19 +505,48 @@ static struct drm_plane *vc4_fkms_plane_
+ goto fail;
+ }
+
++ for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++)
++ formats[num_formats++] = vc_image_formats[i].drm;
++
+ plane = &vc4_plane->base;
+ ret = drm_universal_plane_init(dev, plane, 0xff,
+ &vc4_plane_funcs,
+- formats, primary ? 2 : 1, modifiers,
+- type, primary ? "primary" : "cursor");
++ formats, num_formats, modifiers,
++ type, NULL);
+
+- if (type == DRM_PLANE_TYPE_PRIMARY)
+- drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs);
+- else
+- drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs);
++ drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
+
+ drm_plane_create_alpha_property(plane);
+
++ /*
++ * Default frame buffer setup is with FB on -127, and raspistill etc
++ * tend to drop overlays on layer 2. Cursor plane was on layer +127.
++ *
++ * For F-KMS the mailbox call allows for a s8.
++ * Remap zpos 0 to -127 for the background layer, but leave all the
++ * other layers as requested by KMS.
++ */
++ switch (type) {
++ case DRM_PLANE_TYPE_PRIMARY:
++ default_zpos = 0;
++ break;
++ case DRM_PLANE_TYPE_OVERLAY:
++ default_zpos = 1;
++ break;
++ case DRM_PLANE_TYPE_CURSOR:
++ default_zpos = 2;
++ break;
++ }
++ drm_plane_create_zpos_property(plane, default_zpos, 0, 127);
++
++ /* Prepare the static elements of the mailbox structure */
++ vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
++ vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
++ vc4_plane->mb.tag.req_resp_size = 0;
++ vc4_plane->mb.plane.display = 0;
++ vc4_plane->mb.plane.plane_id = plane_id;
++ vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
++
+ return plane;
+ fail:
+ if (plane)
+@@ -400,19 +568,23 @@ static void vc4_crtc_disable(struct drm_
+ * whether anything scans out at all, but the firmware doesn't
+ * give us a CRTC-level control for that.
+ */
+- vc4_cursor_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
+- vc4_plane_set_primary_blank(crtc->primary, true);
++
++ vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
++ vc4_plane_atomic_disable(crtc->primary, crtc->primary->state);
++
++ /* FIXME: Disable overlay planes */
+ }
+
+ static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
+ /* Unblank the planes (if they're supposed to be displayed). */
++
+ if (crtc->primary->state->fb)
+- vc4_plane_set_primary_blank(crtc->primary, false);
+- if (crtc->cursor->state->fb) {
+- vc4_cursor_plane_atomic_update(crtc->cursor,
+- crtc->cursor->state);
+- }
++ vc4_plane_set_blank(crtc->primary, false);
++ if (crtc->cursor->state->fb)
++ vc4_plane_set_blank(crtc->cursor, crtc->cursor->state);
++
++ /* FIXME: Enable overlay planes */
+ }
+
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+@@ -672,8 +844,10 @@ static int vc4_fkms_bind(struct device *
+ struct vc4_crtc *vc4_crtc;
+ struct vc4_fkms_encoder *vc4_encoder;
+ struct drm_crtc *crtc;
+- struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp;
++ struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
++ struct drm_plane *destroy_plane, *temp;
+ struct device_node *firmware_node;
++ u32 blank = 1;
+ int ret;
+
+ vc4->firmware_kms = true;
+@@ -702,20 +876,26 @@ static int vc4_fkms_bind(struct device *
+ if (IS_ERR(vc4_crtc->regs))
+ return PTR_ERR(vc4_crtc->regs);
+
+- /* For now, we create just the primary and the legacy cursor
+- * planes. We should be able to stack more planes on easily,
+- * but to do that we would need to compute the bandwidth
+- * requirement of the plane configuration, and reject ones
+- * that will take too much.
+- */
+- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY);
++ /* Blank the firmware provided framebuffer */
++ rpi_firmware_property(vc4->firmware,
++ RPI_FIRMWARE_FRAMEBUFFER_BLANK,
++ &blank, sizeof(blank));
++
++ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
+ if (IS_ERR(primary_plane)) {
+ dev_err(dev, "failed to construct primary plane\n");
+ ret = PTR_ERR(primary_plane);
+ goto err;
+ }
+
+- cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
++ overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1);
++ if (IS_ERR(overlay_plane)) {
++ dev_err(dev, "failed to construct overlay plane\n");
++ ret = PTR_ERR(overlay_plane);
++ goto err;
++ }
++
++ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2);
+ if (IS_ERR(cursor_plane)) {
+ dev_err(dev, "failed to construct cursor plane\n");
+ ret = PTR_ERR(cursor_plane);
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -435,6 +435,7 @@ int vc4_kms_load(struct drm_device *dev)
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.async_page_flip = true;
+ dev->mode_config.allow_fb_modifiers = true;
++ dev->mode_config.normalize_zpos = true;
+
+ drm_modeset_lock_init(&vc4->ctm_state_lock);
+
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc_image_types.h
+@@ -0,0 +1,143 @@
++
++/*
++ * Copyright (c) 2012, Broadcom Europe Ltd
++ *
++ * Values taken from vc_image_types.h released by Broadcom at
++ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++enum {
++ VC_IMAGE_MIN = 0, //bounds for error checking
++
++ VC_IMAGE_RGB565 = 1,
++ VC_IMAGE_1BPP,
++ VC_IMAGE_YUV420,
++ VC_IMAGE_48BPP,
++ VC_IMAGE_RGB888,
++ VC_IMAGE_8BPP,
++ /* 4bpp palettised image */
++ VC_IMAGE_4BPP,
++ /* A separated format of 16 colour/light shorts followed by 16 z
++ * values
++ */
++ VC_IMAGE_3D32,
++ /* 16 colours followed by 16 z values */
++ VC_IMAGE_3D32B,
++ /* A separated format of 16 material/colour/light shorts followed by
++ * 16 z values
++ */
++ VC_IMAGE_3D32MAT,
++ /* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */
++ VC_IMAGE_RGB2X9,
++ /* 32-bit format holding 18 bits of 6.6.6 RGB */
++ VC_IMAGE_RGB666,
++ /* 4bpp palettised image with embedded palette */
++ VC_IMAGE_PAL4_OBSOLETE,
++ /* 8bpp palettised image with embedded palette */
++ VC_IMAGE_PAL8_OBSOLETE,
++ /* RGB888 with an alpha byte after each pixel */
++ VC_IMAGE_RGBA32,
++ /* a line of Y (32-byte padded), a line of U (16-byte padded), and a
++ * line of V (16-byte padded)
++ */
++ VC_IMAGE_YUV422,
++ /* RGB565 with a transparent patch */
++ VC_IMAGE_RGBA565,
++ /* Compressed (4444) version of RGBA32 */
++ VC_IMAGE_RGBA16,
++ /* VCIII codec format */
++ VC_IMAGE_YUV_UV,
++ /* VCIII T-format RGBA8888 */
++ VC_IMAGE_TF_RGBA32,
++ /* VCIII T-format RGBx8888 */
++ VC_IMAGE_TF_RGBX32,
++ /* VCIII T-format float */
++ VC_IMAGE_TF_FLOAT,
++ /* VCIII T-format RGBA4444 */
++ VC_IMAGE_TF_RGBA16,
++ /* VCIII T-format RGB5551 */
++ VC_IMAGE_TF_RGBA5551,
++ /* VCIII T-format RGB565 */
++ VC_IMAGE_TF_RGB565,
++ /* VCIII T-format 8-bit luma and 8-bit alpha */
++ VC_IMAGE_TF_YA88,
++ /* VCIII T-format 8 bit generic sample */
++ VC_IMAGE_TF_BYTE,
++ /* VCIII T-format 8-bit palette */
++ VC_IMAGE_TF_PAL8,
++ /* VCIII T-format 4-bit palette */
++ VC_IMAGE_TF_PAL4,
++ /* VCIII T-format Ericsson Texture Compressed */
++ VC_IMAGE_TF_ETC1,
++ /* RGB888 with R & B swapped */
++ VC_IMAGE_BGR888,
++ /* RGB888 with R & B swapped, but with no pitch, i.e. no padding after
++ * each row of pixels
++ */
++ VC_IMAGE_BGR888_NP,
++ /* Bayer image, extra defines which variant is being used */
++ VC_IMAGE_BAYER,
++ /* General wrapper for codec images e.g. JPEG from camera */
++ VC_IMAGE_CODEC,
++ /* VCIII codec format */
++ VC_IMAGE_YUV_UV32,
++ /* VCIII T-format 8-bit luma */
++ VC_IMAGE_TF_Y8,
++ /* VCIII T-format 8-bit alpha */
++ VC_IMAGE_TF_A8,
++ /* VCIII T-format 16-bit generic sample */
++ VC_IMAGE_TF_SHORT,
++ /* VCIII T-format 1bpp black/white */
++ VC_IMAGE_TF_1BPP,
++ VC_IMAGE_OPENGL,
++ /* VCIII-B0 HVS YUV 4:4:4 interleaved samples */
++ VC_IMAGE_YUV444I,
++ /* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on
++ * a per line basis)
++ */
++ VC_IMAGE_YUV422PLANAR,
++ /* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */
++ VC_IMAGE_ARGB8888,
++ /* 32bpp with 8bit unused at MS byte, with R, G, B (LS byte) */
++ VC_IMAGE_XRGB8888,
++
++ /* interleaved 8 bit samples of Y, U, Y, V (4 flavours) */
++ VC_IMAGE_YUV422YUYV,
++ VC_IMAGE_YUV422YVYU,
++ VC_IMAGE_YUV422UYVY,
++ VC_IMAGE_YUV422VYUY,
++
++ /* 32bpp like RGBA32 but with unused alpha */
++ VC_IMAGE_RGBX32,
++ /* 32bpp, corresponding to RGBA with unused alpha */
++ VC_IMAGE_RGBX8888,
++ /* 32bpp, corresponding to BGRA with unused alpha */
++ VC_IMAGE_BGRX8888,
++
++ /* Y as a plane, then UV byte interleaved in plane with with same pitch,
++ * half height
++ */
++ VC_IMAGE_YUV420SP,
++
++ /* Y, U, & V planes separately 4:4:4 */
++ VC_IMAGE_YUV444PLANAR,
++
++ /* T-format 8-bit U - same as TF_Y8 buf from U plane */
++ VC_IMAGE_TF_U8,
++ /* T-format 8-bit U - same as TF_Y8 buf from V plane */
++ VC_IMAGE_TF_V8,
++
++ /* YUV4:2:0 planar, 16bit values */
++ VC_IMAGE_YUV420_16,
++ /* YUV4:2:0 codec format, 16bit values */
++ VC_IMAGE_YUV_UV_16,
++ /* YUV4:2:0 with U,V in side-by-side format */
++ VC_IMAGE_YUV420_S,
++
++ VC_IMAGE_MAX, /* bounds for error checking */
++ VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
++};
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -148,6 +148,8 @@ enum rpi_firmware_property_tag {
+
+ RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
+
++ RPI_FIRMWARE_SET_PLANE = 0x00048015,
++
+ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
+ RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
+ };
+++ /dev/null
-From c0041a9fe33d6031267d9f3e2372833908e97337 Mon Sep 17 00:00:00 2001
-Date: Tue, 2 Apr 2019 13:29:00 -0700
-Subject: [PATCH] drm/vc4: Fix vblank timestamping for firmwarekms.
-
-The core doesn't expect a false return from the scanoutpos function in
-normal usage, so we were doing the precise vblank timestamping path
-and thus "immediate" vblank disables (even though firmwarekms can't
-actually disable vblanks interrupts, sigh), and the kernel would get
-confused when getting timestamp info when also turning vblanks back
-on.
-
----
- drivers/gpu/drm/vc4/vc4_crtc.c | 3 ---
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 ++++++
- 2 files changed, 6 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_crtc.c
-+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
-@@ -133,9 +133,6 @@ bool vc4_crtc_get_scanoutpos(struct drm_
- int vblank_lines;
- bool ret = false;
-
-- if (vc4->firmware_kms)
-- return 0;
--
- /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
-
- /* Get optional system timestamp before query. */
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -673,6 +673,12 @@ static int vc4_fkms_bind(struct device *
-
- vc4->firmware_kms = true;
-
-+ /* firmware kms doesn't have precise a scanoutpos implementation, so
-+ * we can't do the precise vblank timestamp mode.
-+ */
-+ drm->driver->get_scanout_position = NULL;
-+ drm->driver->get_vblank_timestamp = NULL;
-+
- vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
- if (!vc4_crtc)
- return -ENOMEM;
--- /dev/null
+From 7c4a99448be56e288a5845f3de77b7eef006a450 Mon Sep 17 00:00:00 2001
+Date: Wed, 3 Apr 2019 15:20:05 +0100
+Subject: [PATCH] drm: vc4: Increase max screen size to 4096x4096.
+
+We now should support 4k screens, therefore this limit needs to
+be increased.
+
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -429,8 +429,8 @@ int vc4_kms_load(struct drm_device *dev)
+ return ret;
+ }
+
+- dev->mode_config.max_width = 2048;
+- dev->mode_config.max_height = 2048;
++ dev->mode_config.max_width = 4096;
++ dev->mode_config.max_height = 4096;
+ dev->mode_config.funcs = &vc4_mode_funcs;
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.async_page_flip = true;
+++ /dev/null
-From 3819888738de087ba726ceaa2ab20503f164f1ed Mon Sep 17 00:00:00 2001
-Date: Tue, 26 Mar 2019 14:43:06 +0000
-Subject: [PATCH] gpu: vc4-fkms: Switch to the newer mailbox frame
- buffer API.
-
-The old mailbox FB API was ideally deprecated but still used by
-the FKMS driver.
-Update to the newer API.
-
-NB This needs current firmware that accepts ARM allocated buffers
-through the newer API.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 109 +++++++++++----------
- include/soc/bcm2835/raspberrypi-firmware.h | 10 ++
- 2 files changed, 67 insertions(+), 52 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -28,6 +28,25 @@
- #include "vc4_regs.h"
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
-+struct fb_alloc_tags {
-+ struct rpi_firmware_property_tag_header tag1;
-+ u32 xres, yres;
-+ struct rpi_firmware_property_tag_header tag2;
-+ u32 xres_virtual, yres_virtual;
-+ struct rpi_firmware_property_tag_header tag3;
-+ u32 bpp;
-+ struct rpi_firmware_property_tag_header tag4;
-+ u32 xoffset, yoffset;
-+ struct rpi_firmware_property_tag_header tag5;
-+ u32 base, screen_size;
-+ struct rpi_firmware_property_tag_header tag6;
-+ u32 pitch;
-+ struct rpi_firmware_property_tag_header tag7;
-+ u32 alpha_mode;
-+ struct rpi_firmware_property_tag_header tag8;
-+ u32 layer;
-+};
-+
- /* The firmware delivers a vblank interrupt to us through the SMI
- * hardware, which has only this one register.
- */
-@@ -121,45 +140,39 @@ static void vc4_primary_plane_atomic_upd
- struct drm_plane_state *old_state)
- {
- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
-- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
- struct drm_plane_state *state = plane->state;
- struct drm_framebuffer *fb = state->fb;
- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
-- volatile struct fbinfo_s *fbinfo = vc4_plane->fbinfo;
-+ u32 format = fb->format->format;
-+ struct fb_alloc_tags fbinfo = {
-+ .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT,
-+ 8, 0, },
-+ .xres = state->crtc_w,
-+ .yres = state->crtc_h,
-+ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT,
-+ 8, 0, },
-+ .xres_virtual = state->crtc_w,
-+ .yres_virtual = state->crtc_h,
-+ .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 },
-+ .bpp = 32,
-+ .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 },
-+ .xoffset = 0,
-+ .yoffset = 0,
-+ .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
-+ .base = bo->paddr + fb->offsets[0],
-+ .screen_size = state->crtc_w * state->crtc_h * 4,
-+ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
-+ .pitch = fb->pitches[0],
-+ .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 },
-+ .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2,
-+ .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 },
-+ .layer = -127,
-+ };
- u32 bpp = 32;
- int ret;
-
-- fbinfo->xres = state->crtc_w;
-- fbinfo->yres = state->crtc_h;
-- fbinfo->xres_virtual = state->crtc_w;
-- fbinfo->yres_virtual = state->crtc_h;
-- fbinfo->bpp = bpp;
-- fbinfo->xoffset = state->crtc_x;
-- fbinfo->yoffset = state->crtc_y;
-- fbinfo->base = bo->paddr + fb->offsets[0];
-- fbinfo->pitch = fb->pitches[0];
--
- if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
-- fbinfo->bpp |= BIT(31);
--
-- /* A bug in the firmware makes it so that if the fb->base is
-- * set to nonzero, the configured pitch gets overwritten with
-- * the previous pitch. So, to get the configured pitch
-- * recomputed, we have to make it allocate itself a new buffer
-- * in VC memory, first.
-- */
-- if (vc4_plane->pitch != fb->pitches[0]) {
-- u32 saved_base = fbinfo->base;
-- fbinfo->base = 0;
--
-- ret = rpi_firmware_transaction(vc4->firmware,
-- RPI_FIRMWARE_CHAN_FB,
-- vc4_plane->fbinfo_bus_addr);
-- fbinfo->base = saved_base;
--
-- vc4_plane->pitch = fbinfo->pitch;
-- WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]);
-- }
-+ fbinfo.bpp |= BIT(31);
-
- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n",
- plane->base.id, plane->name,
-@@ -168,14 +181,13 @@ static void vc4_primary_plane_atomic_upd
- bpp,
- state->crtc_x,
- state->crtc_y,
-- &fbinfo->base,
-+ &fbinfo.base,
- fb->pitches[0]);
-
-- ret = rpi_firmware_transaction(vc4->firmware,
-- RPI_FIRMWARE_CHAN_FB,
-- vc4_plane->fbinfo_bus_addr);
-- WARN_ON_ONCE(fbinfo->pitch != fb->pitches[0]);
-- WARN_ON_ONCE(fbinfo->base != bo->paddr + fb->offsets[0]);
-+ ret = rpi_firmware_property_list(vc4->firmware, &fbinfo,
-+ sizeof(fbinfo));
-+ WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]);
-+ WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]);
-
- /* If the CRTC is on (or going to be on) and we're enabled,
- * then unblank. Otherwise, stay blank until CRTC enable.
-@@ -332,10 +344,10 @@ static const struct drm_plane_helper_fun
- static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
- enum drm_plane_type type)
- {
-+ /* Primary and cursor planes only */
- struct drm_plane *plane = NULL;
- struct vc4_fkms_plane *vc4_plane;
-- u32 xrgb8888 = DRM_FORMAT_XRGB8888;
-- u32 argb8888 = DRM_FORMAT_ARGB8888;
-+ u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
- int ret = 0;
- bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
- static const uint64_t modifiers[] = {
-@@ -357,22 +369,15 @@ static struct drm_plane *vc4_fkms_plane_
- plane = &vc4_plane->base;
- ret = drm_universal_plane_init(dev, plane, 0xff,
- &vc4_plane_funcs,
-- primary ? &xrgb8888 : &argb8888, 1,
-- modifiers,
-+ formats, primary ? 2 : 1, modifiers,
- type, primary ? "primary" : "cursor");
-
-- if (type == DRM_PLANE_TYPE_PRIMARY) {
-- vc4_plane->fbinfo =
-- dma_alloc_coherent(dev->dev,
-- sizeof(*vc4_plane->fbinfo),
-- &vc4_plane->fbinfo_bus_addr,
-- GFP_KERNEL);
-- memset(vc4_plane->fbinfo, 0, sizeof(*vc4_plane->fbinfo));
--
-+ if (type == DRM_PLANE_TYPE_PRIMARY)
- drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs);
-- } else {
-+ else
- drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs);
-- }
-+
-+ drm_plane_create_alpha_property(plane);
-
- return plane;
- fail:
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -111,9 +111,15 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
- RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
- RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_LAYER = 0x0004000c,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_TRANSFORM = 0x0004000d,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_VSYNC = 0x0004000e,
- RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
- RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
- RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
-+ RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM = 0x00048013,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS = 0x00040013,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 0x00040014,
- RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
- RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
- RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005,
-@@ -122,6 +128,8 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
- RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
- RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
-+ RPI_FIRMWARE_FRAMEBUFFER_TEST_LAYER = 0x0004400c,
-+ RPI_FIRMWARE_FRAMEBUFFER_TEST_TRANSFORM = 0x0004400d,
- RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e,
- RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
- RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
-@@ -134,6 +142,8 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
- RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
- RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
-+ RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER = 0x0004800c,
-+ RPI_FIRMWARE_FRAMEBUFFER_SET_TRANSFORM = 0x0004800d,
- RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
-
- RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
+++ /dev/null
-From 953d85d97f59691dccbbca743c478a8b01f92b59 Mon Sep 17 00:00:00 2001
-Date: Wed, 27 Mar 2019 17:45:01 +0000
-Subject: [PATCH] drm: vc4: Add an overlay plane to vc4-firmware-kms
-
-This uses a new API that is exposed via the mailbox service
-to stick an element straight on the screen using DispmanX.
-
-The primary and cursor planes have also been switched to using
-the new plane API, and it supports layering based on the DRM
-zpos parameter.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 518 ++++++++++++++-------
- drivers/gpu/drm/vc4/vc4_kms.c | 1 +
- drivers/gpu/drm/vc4/vc_image_types.h | 143 ++++++
- include/soc/bcm2835/raspberrypi-firmware.h | 2 +
- 4 files changed, 495 insertions(+), 169 deletions(-)
- create mode 100644 drivers/gpu/drm/vc4/vc_image_types.h
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -26,8 +26,46 @@
- #include "linux/of_device.h"
- #include "vc4_drv.h"
- #include "vc4_regs.h"
-+#include "vc_image_types.h"
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
-+struct set_plane {
-+ u8 display;
-+ u8 plane_id;
-+ u8 vc_image_type;
-+ s8 layer;
-+
-+ u16 width;
-+ u16 height;
-+
-+ u16 pitch;
-+ u16 vpitch;
-+
-+ u32 src_x; /* 16p16 */
-+ u32 src_y; /* 16p16 */
-+
-+ u32 src_w; /* 16p16 */
-+ u32 src_h; /* 16p16 */
-+
-+ s16 dst_x;
-+ s16 dst_y;
-+
-+ u16 dst_w;
-+ u16 dst_h;
-+
-+ u8 alpha;
-+ u8 num_planes;
-+ u8 is_vu;
-+ u8 padding;
-+
-+ u32 planes[4]; /* DMA address of each plane */
-+};
-+
-+struct mailbox_set_plane {
-+ struct rpi_firmware_property_tag_header tag;
-+ struct set_plane plane;
-+};
-+
- struct fb_alloc_tags {
- struct rpi_firmware_property_tag_header tag1;
- u32 xres, yres;
-@@ -47,6 +85,79 @@ struct fb_alloc_tags {
- u32 layer;
- };
-
-+static const struct vc_image_format {
-+ u32 drm; /* DRM_FORMAT_* */
-+ u32 vc_image; /* VC_IMAGE_* */
-+ u32 is_vu;
-+} vc_image_formats[] = {
-+ {
-+ .drm = DRM_FORMAT_XRGB8888,
-+ .vc_image = VC_IMAGE_XRGB8888,
-+ },
-+ {
-+ .drm = DRM_FORMAT_ARGB8888,
-+ .vc_image = VC_IMAGE_ARGB8888,
-+ },
-+/*
-+ * FIXME: Need to resolve which DRM format goes to which vc_image format
-+ * for the remaining RGBA and RGBX formats.
-+ * {
-+ * .drm = DRM_FORMAT_ABGR8888,
-+ * .vc_image = VC_IMAGE_RGBA8888,
-+ * },
-+ * {
-+ * .drm = DRM_FORMAT_XBGR8888,
-+ * .vc_image = VC_IMAGE_RGBA8888,
-+ * },
-+ */
-+ {
-+ .drm = DRM_FORMAT_RGB565,
-+ .vc_image = VC_IMAGE_RGB565,
-+ },
-+ {
-+ .drm = DRM_FORMAT_RGB888,
-+ .vc_image = VC_IMAGE_BGR888,
-+ },
-+ {
-+ .drm = DRM_FORMAT_BGR888,
-+ .vc_image = VC_IMAGE_RGB888,
-+ },
-+ {
-+ .drm = DRM_FORMAT_YUV422,
-+ .vc_image = VC_IMAGE_YUV422PLANAR,
-+ },
-+ {
-+ .drm = DRM_FORMAT_YUV420,
-+ .vc_image = VC_IMAGE_YUV420,
-+ },
-+ {
-+ .drm = DRM_FORMAT_YVU420,
-+ .vc_image = VC_IMAGE_YUV420,
-+ .is_vu = 1,
-+ },
-+ {
-+ .drm = DRM_FORMAT_NV12,
-+ .vc_image = VC_IMAGE_YUV420SP,
-+ },
-+ {
-+ .drm = DRM_FORMAT_NV21,
-+ .vc_image = VC_IMAGE_YUV420SP,
-+ .is_vu = 1,
-+ },
-+};
-+
-+static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++) {
-+ if (vc_image_formats[i].drm == drm_format)
-+ return &vc_image_formats[i];
-+ }
-+
-+ return NULL;
-+}
-+
- /* The firmware delivers a vblank interrupt to us through the SMI
- * hardware, which has only this one register.
- */
-@@ -113,6 +224,7 @@ struct vc4_fkms_plane {
- struct fbinfo_s *fbinfo;
- dma_addr_t fbinfo_bus_addr;
- u32 pitch;
-+ struct mailbox_set_plane mb;
- };
-
- static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane)
-@@ -120,165 +232,183 @@ static inline struct vc4_fkms_plane *to_
- return (struct vc4_fkms_plane *)plane;
- }
-
--/* Turns the display on/off. */
--static int vc4_plane_set_primary_blank(struct drm_plane *plane, bool blank)
-+static int vc4_plane_set_blank(struct drm_plane *plane, bool blank)
- {
- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
-+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
-+ struct mailbox_set_plane blank_mb = {
-+ .tag = { RPI_FIRMWARE_SET_PLANE, sizeof(struct set_plane), 0 },
-+ .plane = {
-+ .display = vc4_plane->mb.plane.display,
-+ .plane_id = vc4_plane->mb.plane.plane_id,
-+ }
-+ };
-+ int ret;
-
-- u32 packet = blank;
--
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary plane %s",
-+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s",
- plane->base.id, plane->name,
- blank ? "blank" : "unblank");
-
-- return rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_FRAMEBUFFER_BLANK,
-- &packet, sizeof(packet));
-+ if (blank)
-+ ret = rpi_firmware_property_list(vc4->firmware, &blank_mb,
-+ sizeof(blank_mb));
-+ else
-+ ret = rpi_firmware_property_list(vc4->firmware, &vc4_plane->mb,
-+ sizeof(vc4_plane->mb));
-+
-+ WARN_ONCE(ret, "%s: firmware call failed. Please update your firmware",
-+ __func__);
-+ return ret;
- }
-
--static void vc4_primary_plane_atomic_update(struct drm_plane *plane,
-- struct drm_plane_state *old_state)
-+static void vc4_plane_atomic_update(struct drm_plane *plane,
-+ struct drm_plane_state *old_state)
- {
-- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
- struct drm_plane_state *state = plane->state;
- struct drm_framebuffer *fb = state->fb;
- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
-- u32 format = fb->format->format;
-- struct fb_alloc_tags fbinfo = {
-- .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT,
-- 8, 0, },
-- .xres = state->crtc_w,
-- .yres = state->crtc_h,
-- .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT,
-- 8, 0, },
-- .xres_virtual = state->crtc_w,
-- .yres_virtual = state->crtc_h,
-- .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 },
-- .bpp = 32,
-- .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 },
-- .xoffset = 0,
-- .yoffset = 0,
-- .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
-- .base = bo->paddr + fb->offsets[0],
-- .screen_size = state->crtc_w * state->crtc_h * 4,
-- .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
-- .pitch = fb->pitches[0],
-- .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 },
-- .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2,
-- .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 },
-- .layer = -127,
-- };
-- u32 bpp = 32;
-- int ret;
-+ const struct drm_format_info *drm_fmt = fb->format;
-+ const struct vc_image_format *vc_fmt =
-+ vc4_get_vc_image_fmt(drm_fmt->format);
-+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
-+ struct mailbox_set_plane *mb = &vc4_plane->mb;
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
-+ int num_planes = fb->format->num_planes;
-+ struct drm_display_mode *mode = &state->crtc->mode;
-
-- if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
-- fbinfo.bpp |= BIT(31);
-+ mb->plane.vc_image_type = vc_fmt->vc_image;
-+ mb->plane.width = fb->width;
-+ mb->plane.height = fb->height;
-+ mb->plane.pitch = fb->pitches[0];
-+ mb->plane.src_w = state->src_w;
-+ mb->plane.src_h = state->src_h;
-+ mb->plane.src_x = state->src_x;
-+ mb->plane.src_y = state->src_y;
-+ mb->plane.dst_w = state->crtc_w;
-+ mb->plane.dst_h = state->crtc_h;
-+ mb->plane.dst_x = state->crtc_x;
-+ mb->plane.dst_y = state->crtc_y;
-+ mb->plane.alpha = state->alpha >> 8;
-+ mb->plane.layer = state->normalized_zpos ?
-+ state->normalized_zpos : -127;
-+ mb->plane.num_planes = num_planes;
-+ mb->plane.is_vu = vc_fmt->is_vu;
-+ mb->plane.planes[0] = bo->paddr + fb->offsets[0];
-
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n",
-+ /* FIXME: If the dest rect goes off screen then clip the src rect so we
-+ * don't have off-screen pixels.
-+ */
-+ if (plane->type == DRM_PLANE_TYPE_CURSOR) {
-+ /* There is no scaling on the cursor plane, therefore the calcs
-+ * to alter the source crop as the cursor goes off the screen
-+ * are simple.
-+ */
-+ if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) {
-+ mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x;
-+ mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x)
-+ << 16;
-+ }
-+ if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) {
-+ mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y;
-+ mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y)
-+ << 16;
-+ }
-+ }
-+
-+ if (num_planes > 1) {
-+ /* Assume this must be YUV */
-+ /* Makes assumptions on the stride for the chroma planes as we
-+ * can't easily plumb in non-standard pitches.
-+ */
-+ mb->plane.planes[1] = bo->paddr + fb->offsets[1];
-+ if (num_planes > 2)
-+ mb->plane.planes[2] = bo->paddr + fb->offsets[2];
-+ else
-+ mb->plane.planes[2] = 0;
-+
-+ /* Special case the YUV420 with U and V as line interleaved
-+ * planes as we have special handling for that case.
-+ */
-+ if (num_planes == 3 &&
-+ (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1])
-+ mb->plane.vc_image_type = VC_IMAGE_YUV420_S;
-+ } else {
-+ mb->plane.planes[1] = 0;
-+ mb->plane.planes[2] = 0;
-+ }
-+ mb->plane.planes[3] = 0;
-+
-+ switch (fb->modifier) {
-+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
-+ switch (mb->plane.vc_image_type) {
-+ case VC_IMAGE_RGBX32:
-+ mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32;
-+ break;
-+ case VC_IMAGE_RGBA32:
-+ mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
-+ break;
-+ case VC_IMAGE_RGB565:
-+ mb->plane.vc_image_type = VC_IMAGE_TF_RGB565;
-+ break;
-+ }
-+ break;
-+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
-+ mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
-+ mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
-+ break;
-+ }
-+
-+ if (vc4_crtc) {
-+ mb->plane.dst_x += vc4_crtc->overscan[0];
-+ mb->plane.dst_y += vc4_crtc->overscan[1];
-+ }
-+
-+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n",
- plane->base.id, plane->name,
-- state->crtc_w,
-- state->crtc_h,
-- bpp,
-+ mb->plane.width,
-+ mb->plane.height,
-+ mb->plane.vc_image_type,
- state->crtc_x,
- state->crtc_y,
-- &fbinfo.base,
-- fb->pitches[0]);
--
-- ret = rpi_firmware_property_list(vc4->firmware, &fbinfo,
-- sizeof(fbinfo));
-- WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]);
-- WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]);
--
-- /* If the CRTC is on (or going to be on) and we're enabled,
-+ state->crtc_w,
-+ state->crtc_h,
-+ mb->plane.src_x,
-+ mb->plane.src_y,
-+ mb->plane.src_w,
-+ mb->plane.src_h,
-+ mb->plane.planes[0],
-+ mb->plane.planes[1],
-+ mb->plane.planes[2],
-+ fb->pitches[0],
-+ state->alpha,
-+ state->normalized_zpos);
-+
-+ /*
-+ * Do NOT set now, as we haven't checked if the crtc is active or not.
-+ * Set from vc4_plane_set_blank instead.
-+ *
-+ * If the CRTC is on (or going to be on) and we're enabled,
- * then unblank. Otherwise, stay blank until CRTC enable.
-- */
-+ */
- if (state->crtc->state->active)
-- vc4_plane_set_primary_blank(plane, false);
-+ vc4_plane_set_blank(plane, false);
- }
-
--static void vc4_primary_plane_atomic_disable(struct drm_plane *plane,
-- struct drm_plane_state *old_state)
-+static void vc4_plane_atomic_disable(struct drm_plane *plane,
-+ struct drm_plane_state *old_state)
- {
-- vc4_plane_set_primary_blank(plane, true);
--}
--
--static void vc4_cursor_plane_atomic_update(struct drm_plane *plane,
-- struct drm_plane_state *old_state)
--{
-- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
-+ //struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
- struct drm_plane_state *state = plane->state;
-- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
-- struct drm_framebuffer *fb = state->fb;
-- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
-- dma_addr_t addr = bo->paddr + fb->offsets[0];
-- int ret;
-- u32 packet_state[] = {
-- state->crtc->state->active,
-- state->crtc_x,
-- state->crtc_y,
-- 0
-- };
-- WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4);
-+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
-
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%pad/%d)",
-+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
- plane->base.id, plane->name,
- state->crtc_w,
- state->crtc_h,
-+ vc4_plane->mb.plane.vc_image_type,
- state->crtc_x,
-- state->crtc_y,
-- &addr,
-- fb->pitches[0]);
--
-- /* add on the top/left offsets when overscan is active */
-- if (vc4_crtc) {
-- packet_state[1] += vc4_crtc->overscan[0];
-- packet_state[2] += vc4_crtc->overscan[1];
-- }
--
-- ret = rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_SET_CURSOR_STATE,
-- &packet_state,
-- sizeof(packet_state));
-- if (ret || packet_state[0] != 0)
-- DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
--
-- /* Note: When the cursor contents change, the modesetting
-- * driver calls drm_mode_cursor_univeral() with
-- * DRM_MODE_CURSOR_BO, which means a new fb will be allocated.
-- */
-- if (!old_state ||
-- state->crtc_w != old_state->crtc_w ||
-- state->crtc_h != old_state->crtc_h ||
-- fb != old_state->fb) {
-- u32 packet_info[] = { state->crtc_w, state->crtc_h,
-- 0, /* unused */
-- addr,
-- 0, 0, /* hotx, hoty */};
--
-- ret = rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_SET_CURSOR_INFO,
-- &packet_info,
-- sizeof(packet_info));
-- if (ret || packet_info[0] != 0)
-- DRM_ERROR("Failed to set cursor info: 0x%08x\n", packet_info[0]);
-- }
--}
--
--static void vc4_cursor_plane_atomic_disable(struct drm_plane *plane,
-- struct drm_plane_state *old_state)
--{
-- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
-- u32 packet_state[] = { false, 0, 0, 0 };
-- int ret;
--
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] disabling cursor", plane->base.id, plane->name);
--
-- ret = rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_SET_CURSOR_STATE,
-- &packet_state,
-- sizeof(packet_state));
-- if (ret || packet_state[0] != 0)
-- DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
-+ state->crtc_y);
-+ vc4_plane_set_blank(plane, true);
- }
-
- static int vc4_plane_atomic_check(struct drm_plane *plane,
-@@ -301,6 +431,7 @@ static bool vc4_fkms_format_mod_supporte
- switch (format) {
- case DRM_FORMAT_XRGB8888:
- case DRM_FORMAT_ARGB8888:
-+ case DRM_FORMAT_RGB565:
- switch (modifier) {
- case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
- case DRM_FORMAT_MOD_LINEAR:
-@@ -309,8 +440,22 @@ static bool vc4_fkms_format_mod_supporte
- default:
- return false;
- }
-+ case DRM_FORMAT_NV12:
-+ case DRM_FORMAT_NV21:
-+ switch (fourcc_mod_broadcom_mod(modifier)) {
-+ case DRM_FORMAT_MOD_LINEAR:
-+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
-+ return true;
-+ default:
-+ return false;
-+ }
-+ case DRM_FORMAT_RGB888:
-+ case DRM_FORMAT_BGR888:
-+ case DRM_FORMAT_YUV422:
-+ case DRM_FORMAT_YUV420:
-+ case DRM_FORMAT_YVU420:
- default:
-- return false;
-+ return (modifier == DRM_FORMAT_MOD_LINEAR);
- }
- }
-
-@@ -325,31 +470,24 @@ static const struct drm_plane_funcs vc4_
- .format_mod_supported = vc4_fkms_format_mod_supported,
- };
-
--static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
-- .prepare_fb = drm_gem_fb_prepare_fb,
-- .cleanup_fb = NULL,
-- .atomic_check = vc4_plane_atomic_check,
-- .atomic_update = vc4_primary_plane_atomic_update,
-- .atomic_disable = vc4_primary_plane_atomic_disable,
--};
--
--static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = {
-+static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
- .prepare_fb = drm_gem_fb_prepare_fb,
- .cleanup_fb = NULL,
- .atomic_check = vc4_plane_atomic_check,
-- .atomic_update = vc4_cursor_plane_atomic_update,
-- .atomic_disable = vc4_cursor_plane_atomic_disable,
-+ .atomic_update = vc4_plane_atomic_update,
-+ .atomic_disable = vc4_plane_atomic_disable,
- };
-
- static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
-- enum drm_plane_type type)
-+ enum drm_plane_type type,
-+ u8 plane_id)
- {
-- /* Primary and cursor planes only */
- struct drm_plane *plane = NULL;
- struct vc4_fkms_plane *vc4_plane;
-- u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
-+ u32 formats[ARRAY_SIZE(vc_image_formats)];
-+ unsigned int default_zpos;
-+ u32 num_formats = 0;
- int ret = 0;
-- bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
- static const uint64_t modifiers[] = {
- DRM_FORMAT_MOD_LINEAR,
- /* VC4_T_TILED should come after linear, because we
-@@ -358,6 +496,7 @@ static struct drm_plane *vc4_fkms_plane_
- DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
- DRM_FORMAT_MOD_INVALID,
- };
-+ int i;
-
- vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
- GFP_KERNEL);
-@@ -366,19 +505,48 @@ static struct drm_plane *vc4_fkms_plane_
- goto fail;
- }
-
-+ for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++)
-+ formats[num_formats++] = vc_image_formats[i].drm;
-+
- plane = &vc4_plane->base;
- ret = drm_universal_plane_init(dev, plane, 0xff,
- &vc4_plane_funcs,
-- formats, primary ? 2 : 1, modifiers,
-- type, primary ? "primary" : "cursor");
-+ formats, num_formats, modifiers,
-+ type, NULL);
-
-- if (type == DRM_PLANE_TYPE_PRIMARY)
-- drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs);
-- else
-- drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs);
-+ drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
-
- drm_plane_create_alpha_property(plane);
-
-+ /*
-+ * Default frame buffer setup is with FB on -127, and raspistill etc
-+ * tend to drop overlays on layer 2. Cursor plane was on layer +127.
-+ *
-+ * For F-KMS the mailbox call allows for a s8.
-+ * Remap zpos 0 to -127 for the background layer, but leave all the
-+ * other layers as requested by KMS.
-+ */
-+ switch (type) {
-+ case DRM_PLANE_TYPE_PRIMARY:
-+ default_zpos = 0;
-+ break;
-+ case DRM_PLANE_TYPE_OVERLAY:
-+ default_zpos = 1;
-+ break;
-+ case DRM_PLANE_TYPE_CURSOR:
-+ default_zpos = 2;
-+ break;
-+ }
-+ drm_plane_create_zpos_property(plane, default_zpos, 0, 127);
-+
-+ /* Prepare the static elements of the mailbox structure */
-+ vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
-+ vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
-+ vc4_plane->mb.tag.req_resp_size = 0;
-+ vc4_plane->mb.plane.display = 0;
-+ vc4_plane->mb.plane.plane_id = plane_id;
-+ vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
-+
- return plane;
- fail:
- if (plane)
-@@ -400,19 +568,23 @@ static void vc4_crtc_disable(struct drm_
- * whether anything scans out at all, but the firmware doesn't
- * give us a CRTC-level control for that.
- */
-- vc4_cursor_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
-- vc4_plane_set_primary_blank(crtc->primary, true);
-+
-+ vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
-+ vc4_plane_atomic_disable(crtc->primary, crtc->primary->state);
-+
-+ /* FIXME: Disable overlay planes */
- }
-
- static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
- /* Unblank the planes (if they're supposed to be displayed). */
-+
- if (crtc->primary->state->fb)
-- vc4_plane_set_primary_blank(crtc->primary, false);
-- if (crtc->cursor->state->fb) {
-- vc4_cursor_plane_atomic_update(crtc->cursor,
-- crtc->cursor->state);
-- }
-+ vc4_plane_set_blank(crtc->primary, false);
-+ if (crtc->cursor->state->fb)
-+ vc4_plane_set_blank(crtc->cursor, crtc->cursor->state);
-+
-+ /* FIXME: Enable overlay planes */
- }
-
- static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
-@@ -672,8 +844,10 @@ static int vc4_fkms_bind(struct device *
- struct vc4_crtc *vc4_crtc;
- struct vc4_fkms_encoder *vc4_encoder;
- struct drm_crtc *crtc;
-- struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp;
-+ struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
-+ struct drm_plane *destroy_plane, *temp;
- struct device_node *firmware_node;
-+ u32 blank = 1;
- int ret;
-
- vc4->firmware_kms = true;
-@@ -702,20 +876,26 @@ static int vc4_fkms_bind(struct device *
- if (IS_ERR(vc4_crtc->regs))
- return PTR_ERR(vc4_crtc->regs);
-
-- /* For now, we create just the primary and the legacy cursor
-- * planes. We should be able to stack more planes on easily,
-- * but to do that we would need to compute the bandwidth
-- * requirement of the plane configuration, and reject ones
-- * that will take too much.
-- */
-- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY);
-+ /* Blank the firmware provided framebuffer */
-+ rpi_firmware_property(vc4->firmware,
-+ RPI_FIRMWARE_FRAMEBUFFER_BLANK,
-+ &blank, sizeof(blank));
-+
-+ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
- if (IS_ERR(primary_plane)) {
- dev_err(dev, "failed to construct primary plane\n");
- ret = PTR_ERR(primary_plane);
- goto err;
- }
-
-- cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
-+ overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1);
-+ if (IS_ERR(overlay_plane)) {
-+ dev_err(dev, "failed to construct overlay plane\n");
-+ ret = PTR_ERR(overlay_plane);
-+ goto err;
-+ }
-+
-+ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2);
- if (IS_ERR(cursor_plane)) {
- dev_err(dev, "failed to construct cursor plane\n");
- ret = PTR_ERR(cursor_plane);
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -435,6 +435,7 @@ int vc4_kms_load(struct drm_device *dev)
- dev->mode_config.preferred_depth = 24;
- dev->mode_config.async_page_flip = true;
- dev->mode_config.allow_fb_modifiers = true;
-+ dev->mode_config.normalize_zpos = true;
-
- drm_modeset_lock_init(&vc4->ctm_state_lock);
-
---- /dev/null
-+++ b/drivers/gpu/drm/vc4/vc_image_types.h
-@@ -0,0 +1,143 @@
-+
-+/*
-+ * Copyright (c) 2012, Broadcom Europe Ltd
-+ *
-+ * Values taken from vc_image_types.h released by Broadcom at
-+ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+
-+enum {
-+ VC_IMAGE_MIN = 0, //bounds for error checking
-+
-+ VC_IMAGE_RGB565 = 1,
-+ VC_IMAGE_1BPP,
-+ VC_IMAGE_YUV420,
-+ VC_IMAGE_48BPP,
-+ VC_IMAGE_RGB888,
-+ VC_IMAGE_8BPP,
-+ /* 4bpp palettised image */
-+ VC_IMAGE_4BPP,
-+ /* A separated format of 16 colour/light shorts followed by 16 z
-+ * values
-+ */
-+ VC_IMAGE_3D32,
-+ /* 16 colours followed by 16 z values */
-+ VC_IMAGE_3D32B,
-+ /* A separated format of 16 material/colour/light shorts followed by
-+ * 16 z values
-+ */
-+ VC_IMAGE_3D32MAT,
-+ /* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */
-+ VC_IMAGE_RGB2X9,
-+ /* 32-bit format holding 18 bits of 6.6.6 RGB */
-+ VC_IMAGE_RGB666,
-+ /* 4bpp palettised image with embedded palette */
-+ VC_IMAGE_PAL4_OBSOLETE,
-+ /* 8bpp palettised image with embedded palette */
-+ VC_IMAGE_PAL8_OBSOLETE,
-+ /* RGB888 with an alpha byte after each pixel */
-+ VC_IMAGE_RGBA32,
-+ /* a line of Y (32-byte padded), a line of U (16-byte padded), and a
-+ * line of V (16-byte padded)
-+ */
-+ VC_IMAGE_YUV422,
-+ /* RGB565 with a transparent patch */
-+ VC_IMAGE_RGBA565,
-+ /* Compressed (4444) version of RGBA32 */
-+ VC_IMAGE_RGBA16,
-+ /* VCIII codec format */
-+ VC_IMAGE_YUV_UV,
-+ /* VCIII T-format RGBA8888 */
-+ VC_IMAGE_TF_RGBA32,
-+ /* VCIII T-format RGBx8888 */
-+ VC_IMAGE_TF_RGBX32,
-+ /* VCIII T-format float */
-+ VC_IMAGE_TF_FLOAT,
-+ /* VCIII T-format RGBA4444 */
-+ VC_IMAGE_TF_RGBA16,
-+ /* VCIII T-format RGB5551 */
-+ VC_IMAGE_TF_RGBA5551,
-+ /* VCIII T-format RGB565 */
-+ VC_IMAGE_TF_RGB565,
-+ /* VCIII T-format 8-bit luma and 8-bit alpha */
-+ VC_IMAGE_TF_YA88,
-+ /* VCIII T-format 8 bit generic sample */
-+ VC_IMAGE_TF_BYTE,
-+ /* VCIII T-format 8-bit palette */
-+ VC_IMAGE_TF_PAL8,
-+ /* VCIII T-format 4-bit palette */
-+ VC_IMAGE_TF_PAL4,
-+ /* VCIII T-format Ericsson Texture Compressed */
-+ VC_IMAGE_TF_ETC1,
-+ /* RGB888 with R & B swapped */
-+ VC_IMAGE_BGR888,
-+ /* RGB888 with R & B swapped, but with no pitch, i.e. no padding after
-+ * each row of pixels
-+ */
-+ VC_IMAGE_BGR888_NP,
-+ /* Bayer image, extra defines which variant is being used */
-+ VC_IMAGE_BAYER,
-+ /* General wrapper for codec images e.g. JPEG from camera */
-+ VC_IMAGE_CODEC,
-+ /* VCIII codec format */
-+ VC_IMAGE_YUV_UV32,
-+ /* VCIII T-format 8-bit luma */
-+ VC_IMAGE_TF_Y8,
-+ /* VCIII T-format 8-bit alpha */
-+ VC_IMAGE_TF_A8,
-+ /* VCIII T-format 16-bit generic sample */
-+ VC_IMAGE_TF_SHORT,
-+ /* VCIII T-format 1bpp black/white */
-+ VC_IMAGE_TF_1BPP,
-+ VC_IMAGE_OPENGL,
-+ /* VCIII-B0 HVS YUV 4:4:4 interleaved samples */
-+ VC_IMAGE_YUV444I,
-+ /* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on
-+ * a per line basis)
-+ */
-+ VC_IMAGE_YUV422PLANAR,
-+ /* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */
-+ VC_IMAGE_ARGB8888,
-+ /* 32bpp with 8bit unused at MS byte, with R, G, B (LS byte) */
-+ VC_IMAGE_XRGB8888,
-+
-+ /* interleaved 8 bit samples of Y, U, Y, V (4 flavours) */
-+ VC_IMAGE_YUV422YUYV,
-+ VC_IMAGE_YUV422YVYU,
-+ VC_IMAGE_YUV422UYVY,
-+ VC_IMAGE_YUV422VYUY,
-+
-+ /* 32bpp like RGBA32 but with unused alpha */
-+ VC_IMAGE_RGBX32,
-+ /* 32bpp, corresponding to RGBA with unused alpha */
-+ VC_IMAGE_RGBX8888,
-+ /* 32bpp, corresponding to BGRA with unused alpha */
-+ VC_IMAGE_BGRX8888,
-+
-+ /* Y as a plane, then UV byte interleaved in plane with with same pitch,
-+ * half height
-+ */
-+ VC_IMAGE_YUV420SP,
-+
-+ /* Y, U, & V planes separately 4:4:4 */
-+ VC_IMAGE_YUV444PLANAR,
-+
-+ /* T-format 8-bit U - same as TF_Y8 buf from U plane */
-+ VC_IMAGE_TF_U8,
-+ /* T-format 8-bit U - same as TF_Y8 buf from V plane */
-+ VC_IMAGE_TF_V8,
-+
-+ /* YUV4:2:0 planar, 16bit values */
-+ VC_IMAGE_YUV420_16,
-+ /* YUV4:2:0 codec format, 16bit values */
-+ VC_IMAGE_YUV_UV_16,
-+ /* YUV4:2:0 with U,V in side-by-side format */
-+ VC_IMAGE_YUV420_S,
-+
-+ VC_IMAGE_MAX, /* bounds for error checking */
-+ VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
-+};
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -148,6 +148,8 @@ enum rpi_firmware_property_tag {
-
- RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
-
-+ RPI_FIRMWARE_SET_PLANE = 0x00048015,
-+
- RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
- RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
- };
--- /dev/null
+From 4817db177a74ac58671e1fe84d98d584375d9697 Mon Sep 17 00:00:00 2001
+Date: Wed, 3 Apr 2019 17:15:45 +0100
+Subject: [PATCH] drm: vc4: Add support for multiple displays to fkms
+
+There is a slightly nasty hack in that all crtcs share the
+same SMI interrupt from the firmware. This seems to currently
+work well enough, but ought to be fixed at a later date.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 160 +++++++++++++++++--------
+ 1 file changed, 113 insertions(+), 47 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -29,6 +29,8 @@
+ #include "vc_image_types.h"
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
++#define PLANES_PER_CRTC 3
++
+ struct set_plane {
+ u8 display;
+ u8 plane_id;
+@@ -175,6 +177,7 @@ struct vc4_crtc {
+ struct drm_pending_vblank_event *event;
+ u32 overscan[4];
+ bool vblank_enabled;
++ u32 display_number;
+ };
+
+ static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
+@@ -480,6 +483,7 @@ static const struct drm_plane_helper_fun
+
+ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
+ enum drm_plane_type type,
++ u8 display_num,
+ u8 plane_id)
+ {
+ struct drm_plane *plane = NULL;
+@@ -543,7 +547,7 @@ static struct drm_plane *vc4_fkms_plane_
+ vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
+ vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
+ vc4_plane->mb.tag.req_resp_size = 0;
+- vc4_plane->mb.plane.display = 0;
++ vc4_plane->mb.plane.display = display_num;
+ vc4_plane->mb.plane.plane_id = plane_id;
+ vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
+
+@@ -630,16 +634,20 @@ static void vc4_crtc_handle_page_flip(st
+
+ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
+ {
+- struct vc4_crtc *vc4_crtc = data;
+- u32 stat = readl(vc4_crtc->regs + SMICS);
++ struct vc4_crtc **crtc_list = data;
++ int i;
++ u32 stat = readl(crtc_list[0]->regs + SMICS);
+ irqreturn_t ret = IRQ_NONE;
+
+ if (stat & SMICS_INTERRUPTS) {
+- writel(0, vc4_crtc->regs + SMICS);
+- if (vc4_crtc->vblank_enabled)
+- drm_crtc_handle_vblank(&vc4_crtc->base);
+- vc4_crtc_handle_page_flip(vc4_crtc);
+- ret = IRQ_HANDLED;
++ writel(0, crtc_list[0]->regs + SMICS);
++
++ for (i = 0; crtc_list[i]; i++) {
++ if (crtc_list[i]->vblank_enabled)
++ drm_crtc_handle_vblank(&crtc_list[i]->base);
++ vc4_crtc_handle_page_flip(crtc_list[i]);
++ ret = IRQ_HANDLED;
++ }
+ }
+
+ return ret;
+@@ -836,66 +844,55 @@ static const struct drm_encoder_helper_f
+ .disable = vc4_fkms_encoder_disable,
+ };
+
+-static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
++static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
++ int display_idx, int display_ref,
++ struct vc4_crtc **ret_crtc)
+ {
+- struct platform_device *pdev = to_platform_device(dev);
+- struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
+ struct vc4_crtc *vc4_crtc;
+ struct vc4_fkms_encoder *vc4_encoder;
+ struct drm_crtc *crtc;
+ struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
+ struct drm_plane *destroy_plane, *temp;
+- struct device_node *firmware_node;
+ u32 blank = 1;
+ int ret;
+
+- vc4->firmware_kms = true;
+-
+- /* firmware kms doesn't have precise a scanoutpos implementation, so
+- * we can't do the precise vblank timestamp mode.
+- */
+- drm->driver->get_scanout_position = NULL;
+- drm->driver->get_vblank_timestamp = NULL;
+-
+ vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
+ if (!vc4_crtc)
+ return -ENOMEM;
+ crtc = &vc4_crtc->base;
+
+- firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
+- vc4->firmware = rpi_firmware_get(firmware_node);
+- if (!vc4->firmware) {
+- DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
+- return -EPROBE_DEFER;
+- }
+- of_node_put(firmware_node);
+-
+- /* Map the SMI interrupt reg */
+- vc4_crtc->regs = vc4_ioremap_regs(pdev, 0);
+- if (IS_ERR(vc4_crtc->regs))
+- return PTR_ERR(vc4_crtc->regs);
++ vc4_crtc->display_number = display_ref;
+
+ /* Blank the firmware provided framebuffer */
+ rpi_firmware_property(vc4->firmware,
+ RPI_FIRMWARE_FRAMEBUFFER_BLANK,
+ &blank, sizeof(blank));
+
+- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
++ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY,
++ display_ref,
++ 0 + (display_idx * PLANES_PER_CRTC)
++ );
+ if (IS_ERR(primary_plane)) {
+ dev_err(dev, "failed to construct primary plane\n");
+ ret = PTR_ERR(primary_plane);
+ goto err;
+ }
+
+- overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1);
++ overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY,
++ display_ref,
++ 1 + (display_idx * PLANES_PER_CRTC)
++ );
+ if (IS_ERR(overlay_plane)) {
+ dev_err(dev, "failed to construct overlay plane\n");
+ ret = PTR_ERR(overlay_plane);
+ goto err;
+ }
+
+- cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2);
++ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR,
++ display_ref,
++ 2 + (display_idx * PLANES_PER_CRTC)
++ );
+ if (IS_ERR(cursor_plane)) {
+ dev_err(dev, "failed to construct cursor plane\n");
+ ret = PTR_ERR(cursor_plane);
+@@ -922,13 +919,6 @@ static int vc4_fkms_bind(struct device *
+ goto err_destroy_encoder;
+ }
+
+- writel(0, vc4_crtc->regs + SMICS);
+- ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
+- vc4_crtc_irq_handler, 0, "vc4 firmware kms",
+- vc4_crtc);
+- if (ret)
+- goto err_destroy_connector;
+-
+ ret = rpi_firmware_property(vc4->firmware,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN,
+ &vc4_crtc->overscan,
+@@ -938,7 +928,7 @@ static int vc4_fkms_bind(struct device *
+ memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan));
+ }
+
+- platform_set_drvdata(pdev, vc4_crtc);
++ *ret_crtc = vc4_crtc;
+
+ return 0;
+
+@@ -955,15 +945,91 @@ err:
+ return ret;
+ }
+
++static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct drm_device *drm = dev_get_drvdata(master);
++ struct vc4_dev *vc4 = to_vc4_dev(drm);
++ struct device_node *firmware_node;
++ struct vc4_crtc **crtc_list;
++ u32 num_displays, display_num;
++ int ret;
++ const u32 display_num_lookup[] = {2, 7, 1};
++
++ vc4->firmware_kms = true;
++
++ /* firmware kms doesn't have precise a scanoutpos implementation, so
++ * we can't do the precise vblank timestamp mode.
++ */
++ drm->driver->get_scanout_position = NULL;
++ drm->driver->get_vblank_timestamp = NULL;
++
++ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
++ vc4->firmware = rpi_firmware_get(firmware_node);
++ if (!vc4->firmware) {
++ DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
++ return -EPROBE_DEFER;
++ }
++ of_node_put(firmware_node);
++
++ ret = rpi_firmware_property(vc4->firmware,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
++ &num_displays, sizeof(u32));
++
++ /* If we fail to get the number of displays, or it returns 0, then
++ * assume old firmware that doesn't have the mailbox call, so just
++ * set one display
++ */
++ if (ret || num_displays == 0) {
++ num_displays = 1;
++ DRM_WARN("Unable to determine number of displays's. Assuming 1\n");
++ ret = 0;
++ }
++
++ /* Allocate a list, with space for a NULL on the end */
++ crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
++ GFP_KERNEL);
++ if (!crtc_list)
++ return -ENOMEM;
++
++ for (display_num = 0; display_num < num_displays; display_num++) {
++ ret = vc4_fkms_create_screen(dev, drm, display_num,
++ display_num_lookup[display_num],
++ &crtc_list[display_num]);
++ if (ret)
++ DRM_ERROR("Oh dear, failed to create display %u\n",
++ display_num);
++ }
++
++ /* Map the SMI interrupt reg */
++ crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
++ if (IS_ERR(crtc_list[0]->regs))
++ DRM_ERROR("Oh dear, failed to map registers\n");
++
++ writel(0, crtc_list[0]->regs + SMICS);
++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
++ vc4_crtc_irq_handler, 0, "vc4 firmware kms",
++ crtc_list);
++ if (ret)
++ DRM_ERROR("Oh dear, failed to register IRQ\n");
++
++ platform_set_drvdata(pdev, crtc_list);
++
++ return 0;
++}
++
+ static void vc4_fkms_unbind(struct device *dev, struct device *master,
+ void *data)
+ {
+ struct platform_device *pdev = to_platform_device(dev);
+- struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev);
++ struct vc4_crtc **crtc_list = dev_get_drvdata(dev);
++ int i;
+
+- vc4_fkms_connector_destroy(vc4_crtc->connector);
+- vc4_fkms_encoder_destroy(vc4_crtc->encoder);
+- drm_crtc_cleanup(&vc4_crtc->base);
++ for (i = 0; crtc_list[i]; i++) {
++ vc4_fkms_connector_destroy(crtc_list[i]->connector);
++ vc4_fkms_encoder_destroy(crtc_list[i]->encoder);
++ drm_crtc_cleanup(&crtc_list[i]->base);
++ }
+
+ platform_set_drvdata(pdev, NULL);
+ }
--- /dev/null
+From 52d2903959ff9a1d68701a04884e18b31d051f30 Mon Sep 17 00:00:00 2001
+Date: Fri, 5 Apr 2019 17:21:56 +0100
+Subject: [PATCH] drm: vc4: Fix build warning
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -932,8 +932,6 @@ static int vc4_fkms_create_screen(struct
+
+ return 0;
+
+-err_destroy_connector:
+- vc4_fkms_connector_destroy(vc4_crtc->connector);
+ err_destroy_encoder:
+ vc4_fkms_encoder_destroy(vc4_crtc->encoder);
+ list_for_each_entry_safe(destroy_plane, temp,
+++ /dev/null
-From 7c4a99448be56e288a5845f3de77b7eef006a450 Mon Sep 17 00:00:00 2001
-Date: Wed, 3 Apr 2019 15:20:05 +0100
-Subject: [PATCH] drm: vc4: Increase max screen size to 4096x4096.
-
-We now should support 4k screens, therefore this limit needs to
-be increased.
-
----
- drivers/gpu/drm/vc4/vc4_kms.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -429,8 +429,8 @@ int vc4_kms_load(struct drm_device *dev)
- return ret;
- }
-
-- dev->mode_config.max_width = 2048;
-- dev->mode_config.max_height = 2048;
-+ dev->mode_config.max_width = 4096;
-+ dev->mode_config.max_height = 4096;
- dev->mode_config.funcs = &vc4_mode_funcs;
- dev->mode_config.preferred_depth = 24;
- dev->mode_config.async_page_flip = true;
+++ /dev/null
-From 4817db177a74ac58671e1fe84d98d584375d9697 Mon Sep 17 00:00:00 2001
-Date: Wed, 3 Apr 2019 17:15:45 +0100
-Subject: [PATCH] drm: vc4: Add support for multiple displays to fkms
-
-There is a slightly nasty hack in that all crtcs share the
-same SMI interrupt from the firmware. This seems to currently
-work well enough, but ought to be fixed at a later date.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 160 +++++++++++++++++--------
- 1 file changed, 113 insertions(+), 47 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -29,6 +29,8 @@
- #include "vc_image_types.h"
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
-+#define PLANES_PER_CRTC 3
-+
- struct set_plane {
- u8 display;
- u8 plane_id;
-@@ -175,6 +177,7 @@ struct vc4_crtc {
- struct drm_pending_vblank_event *event;
- u32 overscan[4];
- bool vblank_enabled;
-+ u32 display_number;
- };
-
- static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
-@@ -480,6 +483,7 @@ static const struct drm_plane_helper_fun
-
- static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
- enum drm_plane_type type,
-+ u8 display_num,
- u8 plane_id)
- {
- struct drm_plane *plane = NULL;
-@@ -543,7 +547,7 @@ static struct drm_plane *vc4_fkms_plane_
- vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
- vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
- vc4_plane->mb.tag.req_resp_size = 0;
-- vc4_plane->mb.plane.display = 0;
-+ vc4_plane->mb.plane.display = display_num;
- vc4_plane->mb.plane.plane_id = plane_id;
- vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
-
-@@ -630,16 +634,20 @@ static void vc4_crtc_handle_page_flip(st
-
- static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
- {
-- struct vc4_crtc *vc4_crtc = data;
-- u32 stat = readl(vc4_crtc->regs + SMICS);
-+ struct vc4_crtc **crtc_list = data;
-+ int i;
-+ u32 stat = readl(crtc_list[0]->regs + SMICS);
- irqreturn_t ret = IRQ_NONE;
-
- if (stat & SMICS_INTERRUPTS) {
-- writel(0, vc4_crtc->regs + SMICS);
-- if (vc4_crtc->vblank_enabled)
-- drm_crtc_handle_vblank(&vc4_crtc->base);
-- vc4_crtc_handle_page_flip(vc4_crtc);
-- ret = IRQ_HANDLED;
-+ writel(0, crtc_list[0]->regs + SMICS);
-+
-+ for (i = 0; crtc_list[i]; i++) {
-+ if (crtc_list[i]->vblank_enabled)
-+ drm_crtc_handle_vblank(&crtc_list[i]->base);
-+ vc4_crtc_handle_page_flip(crtc_list[i]);
-+ ret = IRQ_HANDLED;
-+ }
- }
-
- return ret;
-@@ -836,66 +844,55 @@ static const struct drm_encoder_helper_f
- .disable = vc4_fkms_encoder_disable,
- };
-
--static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
-+static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
-+ int display_idx, int display_ref,
-+ struct vc4_crtc **ret_crtc)
- {
-- struct platform_device *pdev = to_platform_device(dev);
-- struct drm_device *drm = dev_get_drvdata(master);
- struct vc4_dev *vc4 = to_vc4_dev(drm);
- struct vc4_crtc *vc4_crtc;
- struct vc4_fkms_encoder *vc4_encoder;
- struct drm_crtc *crtc;
- struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
- struct drm_plane *destroy_plane, *temp;
-- struct device_node *firmware_node;
- u32 blank = 1;
- int ret;
-
-- vc4->firmware_kms = true;
--
-- /* firmware kms doesn't have precise a scanoutpos implementation, so
-- * we can't do the precise vblank timestamp mode.
-- */
-- drm->driver->get_scanout_position = NULL;
-- drm->driver->get_vblank_timestamp = NULL;
--
- vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
- if (!vc4_crtc)
- return -ENOMEM;
- crtc = &vc4_crtc->base;
-
-- firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
-- vc4->firmware = rpi_firmware_get(firmware_node);
-- if (!vc4->firmware) {
-- DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
-- return -EPROBE_DEFER;
-- }
-- of_node_put(firmware_node);
--
-- /* Map the SMI interrupt reg */
-- vc4_crtc->regs = vc4_ioremap_regs(pdev, 0);
-- if (IS_ERR(vc4_crtc->regs))
-- return PTR_ERR(vc4_crtc->regs);
-+ vc4_crtc->display_number = display_ref;
-
- /* Blank the firmware provided framebuffer */
- rpi_firmware_property(vc4->firmware,
- RPI_FIRMWARE_FRAMEBUFFER_BLANK,
- &blank, sizeof(blank));
-
-- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
-+ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY,
-+ display_ref,
-+ 0 + (display_idx * PLANES_PER_CRTC)
-+ );
- if (IS_ERR(primary_plane)) {
- dev_err(dev, "failed to construct primary plane\n");
- ret = PTR_ERR(primary_plane);
- goto err;
- }
-
-- overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1);
-+ overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY,
-+ display_ref,
-+ 1 + (display_idx * PLANES_PER_CRTC)
-+ );
- if (IS_ERR(overlay_plane)) {
- dev_err(dev, "failed to construct overlay plane\n");
- ret = PTR_ERR(overlay_plane);
- goto err;
- }
-
-- cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2);
-+ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR,
-+ display_ref,
-+ 2 + (display_idx * PLANES_PER_CRTC)
-+ );
- if (IS_ERR(cursor_plane)) {
- dev_err(dev, "failed to construct cursor plane\n");
- ret = PTR_ERR(cursor_plane);
-@@ -922,13 +919,6 @@ static int vc4_fkms_bind(struct device *
- goto err_destroy_encoder;
- }
-
-- writel(0, vc4_crtc->regs + SMICS);
-- ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
-- vc4_crtc_irq_handler, 0, "vc4 firmware kms",
-- vc4_crtc);
-- if (ret)
-- goto err_destroy_connector;
--
- ret = rpi_firmware_property(vc4->firmware,
- RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN,
- &vc4_crtc->overscan,
-@@ -938,7 +928,7 @@ static int vc4_fkms_bind(struct device *
- memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan));
- }
-
-- platform_set_drvdata(pdev, vc4_crtc);
-+ *ret_crtc = vc4_crtc;
-
- return 0;
-
-@@ -955,15 +945,91 @@ err:
- return ret;
- }
-
-+static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
-+{
-+ struct platform_device *pdev = to_platform_device(dev);
-+ struct drm_device *drm = dev_get_drvdata(master);
-+ struct vc4_dev *vc4 = to_vc4_dev(drm);
-+ struct device_node *firmware_node;
-+ struct vc4_crtc **crtc_list;
-+ u32 num_displays, display_num;
-+ int ret;
-+ const u32 display_num_lookup[] = {2, 7, 1};
-+
-+ vc4->firmware_kms = true;
-+
-+ /* firmware kms doesn't have precise a scanoutpos implementation, so
-+ * we can't do the precise vblank timestamp mode.
-+ */
-+ drm->driver->get_scanout_position = NULL;
-+ drm->driver->get_vblank_timestamp = NULL;
-+
-+ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
-+ vc4->firmware = rpi_firmware_get(firmware_node);
-+ if (!vc4->firmware) {
-+ DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
-+ return -EPROBE_DEFER;
-+ }
-+ of_node_put(firmware_node);
-+
-+ ret = rpi_firmware_property(vc4->firmware,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
-+ &num_displays, sizeof(u32));
-+
-+ /* If we fail to get the number of displays, or it returns 0, then
-+ * assume old firmware that doesn't have the mailbox call, so just
-+ * set one display
-+ */
-+ if (ret || num_displays == 0) {
-+ num_displays = 1;
-+ DRM_WARN("Unable to determine number of displays's. Assuming 1\n");
-+ ret = 0;
-+ }
-+
-+ /* Allocate a list, with space for a NULL on the end */
-+ crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
-+ GFP_KERNEL);
-+ if (!crtc_list)
-+ return -ENOMEM;
-+
-+ for (display_num = 0; display_num < num_displays; display_num++) {
-+ ret = vc4_fkms_create_screen(dev, drm, display_num,
-+ display_num_lookup[display_num],
-+ &crtc_list[display_num]);
-+ if (ret)
-+ DRM_ERROR("Oh dear, failed to create display %u\n",
-+ display_num);
-+ }
-+
-+ /* Map the SMI interrupt reg */
-+ crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
-+ if (IS_ERR(crtc_list[0]->regs))
-+ DRM_ERROR("Oh dear, failed to map registers\n");
-+
-+ writel(0, crtc_list[0]->regs + SMICS);
-+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
-+ vc4_crtc_irq_handler, 0, "vc4 firmware kms",
-+ crtc_list);
-+ if (ret)
-+ DRM_ERROR("Oh dear, failed to register IRQ\n");
-+
-+ platform_set_drvdata(pdev, crtc_list);
-+
-+ return 0;
-+}
-+
- static void vc4_fkms_unbind(struct device *dev, struct device *master,
- void *data)
- {
- struct platform_device *pdev = to_platform_device(dev);
-- struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev);
-+ struct vc4_crtc **crtc_list = dev_get_drvdata(dev);
-+ int i;
-
-- vc4_fkms_connector_destroy(vc4_crtc->connector);
-- vc4_fkms_encoder_destroy(vc4_crtc->encoder);
-- drm_crtc_cleanup(&vc4_crtc->base);
-+ for (i = 0; crtc_list[i]; i++) {
-+ vc4_fkms_connector_destroy(crtc_list[i]->connector);
-+ vc4_fkms_encoder_destroy(crtc_list[i]->encoder);
-+ drm_crtc_cleanup(&crtc_list[i]->base);
-+ }
-
- platform_set_drvdata(pdev, NULL);
- }
--- /dev/null
+From a267031f384a4433fdcd662a97bce7c4949d3fd6 Mon Sep 17 00:00:00 2001
+Date: Fri, 5 Apr 2019 17:23:15 +0100
+Subject: [PATCH] drm: vc4: Select display to blank during
+ initialisation
+
+Otherwise the rainbow splash screen remained in the display list
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -87,6 +87,13 @@ struct fb_alloc_tags {
+ u32 layer;
+ };
+
++struct mailbox_blank_display {
++ struct rpi_firmware_property_tag_header tag1;
++ u32 display;
++ struct rpi_firmware_property_tag_header tag2;
++ u32 blank;
++};
++
+ static const struct vc_image_format {
+ u32 drm; /* DRM_FORMAT_* */
+ u32 vc_image; /* VC_IMAGE_* */
+@@ -854,7 +861,12 @@ static int vc4_fkms_create_screen(struct
+ struct drm_crtc *crtc;
+ struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
+ struct drm_plane *destroy_plane, *temp;
+- u32 blank = 1;
++ struct mailbox_blank_display blank = {
++ .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
++ .display = display_idx,
++ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_BLANK, 4, 0, },
++ .blank = 1,
++ };
+ int ret;
+
+ vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
+@@ -865,9 +877,7 @@ static int vc4_fkms_create_screen(struct
+ vc4_crtc->display_number = display_ref;
+
+ /* Blank the firmware provided framebuffer */
+- rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_FRAMEBUFFER_BLANK,
+- &blank, sizeof(blank));
++ rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank));
+
+ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY,
+ display_ref,
+++ /dev/null
-From 52d2903959ff9a1d68701a04884e18b31d051f30 Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Apr 2019 17:21:56 +0100
-Subject: [PATCH] drm: vc4: Fix build warning
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 --
- 1 file changed, 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -932,8 +932,6 @@ static int vc4_fkms_create_screen(struct
-
- return 0;
-
--err_destroy_connector:
-- vc4_fkms_connector_destroy(vc4_crtc->connector);
- err_destroy_encoder:
- vc4_fkms_encoder_destroy(vc4_crtc->encoder);
- list_for_each_entry_safe(destroy_plane, temp,
--- /dev/null
+From 0bbbf4f4a618072e6987f439784f2d24a81b8f2d Mon Sep 17 00:00:00 2001
+Date: Fri, 5 Apr 2019 17:24:20 +0100
+Subject: [PATCH] drm: vc4: Remove now unused structure.
+
+Cleaning up structure that was unused after
+fbb59a2 drm: vc4: Add an overlay plane to vc4-firmware-kms
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 19 -------------------
+ 1 file changed, 19 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -68,25 +68,6 @@ struct mailbox_set_plane {
+ struct set_plane plane;
+ };
+
+-struct fb_alloc_tags {
+- struct rpi_firmware_property_tag_header tag1;
+- u32 xres, yres;
+- struct rpi_firmware_property_tag_header tag2;
+- u32 xres_virtual, yres_virtual;
+- struct rpi_firmware_property_tag_header tag3;
+- u32 bpp;
+- struct rpi_firmware_property_tag_header tag4;
+- u32 xoffset, yoffset;
+- struct rpi_firmware_property_tag_header tag5;
+- u32 base, screen_size;
+- struct rpi_firmware_property_tag_header tag6;
+- u32 pitch;
+- struct rpi_firmware_property_tag_header tag7;
+- u32 alpha_mode;
+- struct rpi_firmware_property_tag_header tag8;
+- u32 layer;
+-};
+-
+ struct mailbox_blank_display {
+ struct rpi_firmware_property_tag_header tag1;
+ u32 display;
--- /dev/null
+From 13723c680a129d79a7872ee131c0201374ba62ce Mon Sep 17 00:00:00 2001
+Date: Tue, 9 Apr 2019 12:37:28 +0100
+Subject: [PATCH] drm: vc4: Query the display ID for each display in
+ FKMS
+
+Replace the hard coded list of display IDs for a mailbox call
+that returns the display ID for each display that has been
+detected.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++---
+ include/soc/bcm2835/raspberrypi-firmware.h | 1 +
+ 2 files changed, 14 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -943,7 +943,7 @@ static int vc4_fkms_bind(struct device *
+ struct vc4_crtc **crtc_list;
+ u32 num_displays, display_num;
+ int ret;
+- const u32 display_num_lookup[] = {2, 7, 1};
++ u32 display_id;
+
+ vc4->firmware_kms = true;
+
+@@ -982,8 +982,18 @@ static int vc4_fkms_bind(struct device *
+ return -ENOMEM;
+
+ for (display_num = 0; display_num < num_displays; display_num++) {
+- ret = vc4_fkms_create_screen(dev, drm, display_num,
+- display_num_lookup[display_num],
++ display_id = display_num;
++ ret = rpi_firmware_property(vc4->firmware,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
++ &display_id, sizeof(display_id));
++ /* FIXME: Determine the correct error handling here.
++ * Should we fail to create the one "screen" but keep the
++ * others, or fail the whole thing?
++ */
++ if (ret)
++ DRM_ERROR("Failed to get display id %u\n", display_num);
++
++ ret = vc4_fkms_create_screen(dev, drm, display_num, display_id,
+ &crtc_list[display_num]);
+ if (ret)
+ DRM_ERROR("Oh dear, failed to create display %u\n",
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -117,6 +117,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
+ RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID = 0x00040016,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM = 0x00048013,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS = 0x00040013,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 0x00040014,
+++ /dev/null
-From a267031f384a4433fdcd662a97bce7c4949d3fd6 Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Apr 2019 17:23:15 +0100
-Subject: [PATCH] drm: vc4: Select display to blank during
- initialisation
-
-Otherwise the rainbow splash screen remained in the display list
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 18 ++++++++++++++----
- 1 file changed, 14 insertions(+), 4 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -87,6 +87,13 @@ struct fb_alloc_tags {
- u32 layer;
- };
-
-+struct mailbox_blank_display {
-+ struct rpi_firmware_property_tag_header tag1;
-+ u32 display;
-+ struct rpi_firmware_property_tag_header tag2;
-+ u32 blank;
-+};
-+
- static const struct vc_image_format {
- u32 drm; /* DRM_FORMAT_* */
- u32 vc_image; /* VC_IMAGE_* */
-@@ -854,7 +861,12 @@ static int vc4_fkms_create_screen(struct
- struct drm_crtc *crtc;
- struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
- struct drm_plane *destroy_plane, *temp;
-- u32 blank = 1;
-+ struct mailbox_blank_display blank = {
-+ .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
-+ .display = display_idx,
-+ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_BLANK, 4, 0, },
-+ .blank = 1,
-+ };
- int ret;
-
- vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
-@@ -865,9 +877,7 @@ static int vc4_fkms_create_screen(struct
- vc4_crtc->display_number = display_ref;
-
- /* Blank the firmware provided framebuffer */
-- rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_FRAMEBUFFER_BLANK,
-- &blank, sizeof(blank));
-+ rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank));
-
- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY,
- display_ref,
+++ /dev/null
-From 0bbbf4f4a618072e6987f439784f2d24a81b8f2d Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Apr 2019 17:24:20 +0100
-Subject: [PATCH] drm: vc4: Remove now unused structure.
-
-Cleaning up structure that was unused after
-fbb59a2 drm: vc4: Add an overlay plane to vc4-firmware-kms
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 19 -------------------
- 1 file changed, 19 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -68,25 +68,6 @@ struct mailbox_set_plane {
- struct set_plane plane;
- };
-
--struct fb_alloc_tags {
-- struct rpi_firmware_property_tag_header tag1;
-- u32 xres, yres;
-- struct rpi_firmware_property_tag_header tag2;
-- u32 xres_virtual, yres_virtual;
-- struct rpi_firmware_property_tag_header tag3;
-- u32 bpp;
-- struct rpi_firmware_property_tag_header tag4;
-- u32 xoffset, yoffset;
-- struct rpi_firmware_property_tag_header tag5;
-- u32 base, screen_size;
-- struct rpi_firmware_property_tag_header tag6;
-- u32 pitch;
-- struct rpi_firmware_property_tag_header tag7;
-- u32 alpha_mode;
-- struct rpi_firmware_property_tag_header tag8;
-- u32 layer;
--};
--
- struct mailbox_blank_display {
- struct rpi_firmware_property_tag_header tag1;
- u32 display;
--- /dev/null
+From 1b9eb8d557c692e5f1dd831b5e7134e6d07a4dd4 Mon Sep 17 00:00:00 2001
+Date: Tue, 9 Apr 2019 14:00:07 +0100
+Subject: [PATCH] drm/vc4: Set the display number when querying the
+ display resolution
+
+Without this the two displays got set to the same resolution.
+(Requires a firmware bug fix to work).
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 +++++++++++++++++++-------
+ 1 file changed, 27 insertions(+), 10 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -75,6 +75,13 @@ struct mailbox_blank_display {
+ u32 blank;
+ };
+
++struct mailbox_get_width_height {
++ struct rpi_firmware_property_tag_header tag1;
++ u32 display;
++ struct rpi_firmware_property_tag_header tag2;
++ u32 wh[2];
++};
++
+ static const struct vc_image_format {
+ u32 drm; /* DRM_FORMAT_* */
+ u32 vc_image; /* VC_IMAGE_* */
+@@ -192,6 +199,7 @@ struct vc4_fkms_connector {
+ * hook.
+ */
+ struct drm_encoder *encoder;
++ u32 display_idx;
+ };
+
+ static inline struct vc4_fkms_connector *
+@@ -723,21 +731,27 @@ vc4_fkms_connector_detect(struct drm_con
+ static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
+ {
+ struct drm_device *dev = connector->dev;
++ struct vc4_fkms_connector *fkms_connector =
++ to_vc4_fkms_connector(connector);
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+- u32 wh[2] = {0, 0};
+- int ret;
+ struct drm_display_mode *mode;
++ struct mailbox_get_width_height wh = {
++ .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
++ .display = fkms_connector->display_idx,
++ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
++ 8, 0, },
++ };
++ int ret;
++
++ ret = rpi_firmware_property_list(vc4->firmware, &wh, sizeof(wh));
+
+- ret = rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
+- &wh, sizeof(wh));
+ if (ret) {
+ DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n",
+- ret, wh[0], wh[1]);
++ ret, wh.wh[0], wh.wh[1]);
+ return 0;
+ }
+
+- mode = drm_cvt_mode(dev, wh[0], wh[1], 60 /* vrefresh */,
++ mode = drm_cvt_mode(dev, wh.wh[0], wh.wh[1], 60 /* vrefresh */,
+ 0, 0, false);
+ drm_mode_probed_add(connector, mode);
+
+@@ -772,8 +786,9 @@ static const struct drm_connector_helper
+ .best_encoder = vc4_fkms_connector_best_encoder,
+ };
+
+-static struct drm_connector *vc4_fkms_connector_init(struct drm_device *dev,
+- struct drm_encoder *encoder)
++static struct drm_connector *
++vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
++ u32 display_idx)
+ {
+ struct drm_connector *connector = NULL;
+ struct vc4_fkms_connector *fkms_connector;
+@@ -788,6 +803,7 @@ static struct drm_connector *vc4_fkms_co
+ connector = &fkms_connector->base;
+
+ fkms_connector->encoder = encoder;
++ fkms_connector->display_idx = display_idx;
+
+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+@@ -904,7 +920,8 @@ static int vc4_fkms_create_screen(struct
+ drm_encoder_helper_add(&vc4_encoder->base,
+ &vc4_fkms_encoder_helper_funcs);
+
+- vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base);
++ vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base,
++ display_idx);
+ if (IS_ERR(vc4_crtc->connector)) {
+ ret = PTR_ERR(vc4_crtc->connector);
+ goto err_destroy_encoder;
--- /dev/null
+From fe2432615ecc3500cc265d6b84334950b9cbd4bf Mon Sep 17 00:00:00 2001
+Date: Tue, 9 Apr 2019 18:14:44 +0100
+Subject: [PATCH] from
+ vc4_crtc_[en|dis]able
+
+vblank needs to be enabled and disabled by the driver to avoid the
+DRM framework complaining in the kernel log.
+
+vc4_fkms_disable_vblank needs to signal that we don't want vblank
+callbacks too.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -562,6 +562,8 @@ static void vc4_crtc_mode_set_nofb(struc
+
+ static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
++ drm_crtc_vblank_off(crtc);
++
+ /* Always turn the planes off on CRTC disable. In DRM, planes
+ * are enabled/disabled through the update/disable hooks
+ * above, and the CRTC enable/disable independently controls
+@@ -577,6 +579,7 @@ static void vc4_crtc_disable(struct drm_
+
+ static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
++ drm_crtc_vblank_on(crtc);
+ /* Unblank the planes (if they're supposed to be displayed). */
+
+ if (crtc->primary->state->fb)
+@@ -673,6 +676,9 @@ static int vc4_fkms_enable_vblank(struct
+
+ static void vc4_fkms_disable_vblank(struct drm_crtc *crtc)
+ {
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++
++ vc4_crtc->vblank_enabled = false;
+ }
+
+ static const struct drm_crtc_funcs vc4_crtc_funcs = {
+++ /dev/null
-From 13723c680a129d79a7872ee131c0201374ba62ce Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2019 12:37:28 +0100
-Subject: [PATCH] drm: vc4: Query the display ID for each display in
- FKMS
-
-Replace the hard coded list of display IDs for a mailbox call
-that returns the display ID for each display that has been
-detected.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++---
- include/soc/bcm2835/raspberrypi-firmware.h | 1 +
- 2 files changed, 14 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -943,7 +943,7 @@ static int vc4_fkms_bind(struct device *
- struct vc4_crtc **crtc_list;
- u32 num_displays, display_num;
- int ret;
-- const u32 display_num_lookup[] = {2, 7, 1};
-+ u32 display_id;
-
- vc4->firmware_kms = true;
-
-@@ -982,8 +982,18 @@ static int vc4_fkms_bind(struct device *
- return -ENOMEM;
-
- for (display_num = 0; display_num < num_displays; display_num++) {
-- ret = vc4_fkms_create_screen(dev, drm, display_num,
-- display_num_lookup[display_num],
-+ display_id = display_num;
-+ ret = rpi_firmware_property(vc4->firmware,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
-+ &display_id, sizeof(display_id));
-+ /* FIXME: Determine the correct error handling here.
-+ * Should we fail to create the one "screen" but keep the
-+ * others, or fail the whole thing?
-+ */
-+ if (ret)
-+ DRM_ERROR("Failed to get display id %u\n", display_num);
-+
-+ ret = vc4_fkms_create_screen(dev, drm, display_num, display_id,
- &crtc_list[display_num]);
- if (ret)
- DRM_ERROR("Oh dear, failed to create display %u\n",
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -117,6 +117,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
- RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
- RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID = 0x00040016,
- RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM = 0x00048013,
- RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS = 0x00040013,
- RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 0x00040014,
--- /dev/null
+From 129100bd38125bef5fe237ab867349dbe8b210ba Mon Sep 17 00:00:00 2001
+Date: Tue, 9 Apr 2019 17:19:51 +0100
+Subject: [PATCH] drm: vc4: Add support for H & V flips on each plane
+ for FKMS
+
+They are near zero cost options for the HVS, therefore they
+may as well be implemented, and it allows us to invert the
+DSI display.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 36 ++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -61,8 +61,21 @@ struct set_plane {
+ u8 padding;
+
+ u32 planes[4]; /* DMA address of each plane */
++
++ u32 transform;
+ };
+
++/* Values for the transform field */
++#define TRANSFORM_NO_ROTATE 0
++#define TRANSFORM_ROTATE_180 BIT(1)
++#define TRANSFORM_FLIP_HRIZ BIT(16)
++#define TRANSFORM_FLIP_VERT BIT(17)
++
++#define SUPPORTED_ROTATIONS (DRM_MODE_ROTATE_0 | \
++ DRM_MODE_ROTATE_180 | \
++ DRM_MODE_REFLECT_X | \
++ DRM_MODE_REFLECT_Y)
++
+ struct mailbox_set_plane {
+ struct rpi_firmware_property_tag_header tag;
+ struct set_plane plane;
+@@ -274,6 +287,7 @@ static void vc4_plane_atomic_update(stru
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
+ int num_planes = fb->format->num_planes;
+ struct drm_display_mode *mode = &state->crtc->mode;
++ unsigned int rotation = SUPPORTED_ROTATIONS;
+
+ mb->plane.vc_image_type = vc_fmt->vc_image;
+ mb->plane.width = fb->width;
+@@ -294,6 +308,24 @@ static void vc4_plane_atomic_update(stru
+ mb->plane.is_vu = vc_fmt->is_vu;
+ mb->plane.planes[0] = bo->paddr + fb->offsets[0];
+
++ rotation = drm_rotation_simplify(state->rotation, rotation);
++
++ switch (rotation) {
++ default:
++ case DRM_MODE_ROTATE_0:
++ mb->plane.transform = TRANSFORM_NO_ROTATE;
++ break;
++ case DRM_MODE_ROTATE_180:
++ mb->plane.transform = TRANSFORM_ROTATE_180;
++ break;
++ case DRM_MODE_REFLECT_X:
++ mb->plane.transform = TRANSFORM_FLIP_HRIZ;
++ break;
++ case DRM_MODE_REFLECT_Y:
++ mb->plane.transform = TRANSFORM_FLIP_VERT;
++ break;
++ }
++
+ /* FIXME: If the dest rect goes off screen then clip the src rect so we
+ * don't have off-screen pixels.
+ */
+@@ -514,9 +546,13 @@ static struct drm_plane *vc4_fkms_plane_
+ formats, num_formats, modifiers,
+ type, NULL);
+
++ /* FIXME: Do we need to be checking return values from all these calls?
++ */
+ drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
+
+ drm_plane_create_alpha_property(plane);
++ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
++ SUPPORTED_ROTATIONS);
+
+ /*
+ * Default frame buffer setup is with FB on -127, and raspistill etc
+++ /dev/null
-From 1b9eb8d557c692e5f1dd831b5e7134e6d07a4dd4 Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2019 14:00:07 +0100
-Subject: [PATCH] drm/vc4: Set the display number when querying the
- display resolution
-
-Without this the two displays got set to the same resolution.
-(Requires a firmware bug fix to work).
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 +++++++++++++++++++-------
- 1 file changed, 27 insertions(+), 10 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -75,6 +75,13 @@ struct mailbox_blank_display {
- u32 blank;
- };
-
-+struct mailbox_get_width_height {
-+ struct rpi_firmware_property_tag_header tag1;
-+ u32 display;
-+ struct rpi_firmware_property_tag_header tag2;
-+ u32 wh[2];
-+};
-+
- static const struct vc_image_format {
- u32 drm; /* DRM_FORMAT_* */
- u32 vc_image; /* VC_IMAGE_* */
-@@ -192,6 +199,7 @@ struct vc4_fkms_connector {
- * hook.
- */
- struct drm_encoder *encoder;
-+ u32 display_idx;
- };
-
- static inline struct vc4_fkms_connector *
-@@ -723,21 +731,27 @@ vc4_fkms_connector_detect(struct drm_con
- static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
- {
- struct drm_device *dev = connector->dev;
-+ struct vc4_fkms_connector *fkms_connector =
-+ to_vc4_fkms_connector(connector);
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-- u32 wh[2] = {0, 0};
-- int ret;
- struct drm_display_mode *mode;
-+ struct mailbox_get_width_height wh = {
-+ .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
-+ .display = fkms_connector->display_idx,
-+ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
-+ 8, 0, },
-+ };
-+ int ret;
-+
-+ ret = rpi_firmware_property_list(vc4->firmware, &wh, sizeof(wh));
-
-- ret = rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
-- &wh, sizeof(wh));
- if (ret) {
- DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n",
-- ret, wh[0], wh[1]);
-+ ret, wh.wh[0], wh.wh[1]);
- return 0;
- }
-
-- mode = drm_cvt_mode(dev, wh[0], wh[1], 60 /* vrefresh */,
-+ mode = drm_cvt_mode(dev, wh.wh[0], wh.wh[1], 60 /* vrefresh */,
- 0, 0, false);
- drm_mode_probed_add(connector, mode);
-
-@@ -772,8 +786,9 @@ static const struct drm_connector_helper
- .best_encoder = vc4_fkms_connector_best_encoder,
- };
-
--static struct drm_connector *vc4_fkms_connector_init(struct drm_device *dev,
-- struct drm_encoder *encoder)
-+static struct drm_connector *
-+vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
-+ u32 display_idx)
- {
- struct drm_connector *connector = NULL;
- struct vc4_fkms_connector *fkms_connector;
-@@ -788,6 +803,7 @@ static struct drm_connector *vc4_fkms_co
- connector = &fkms_connector->base;
-
- fkms_connector->encoder = encoder;
-+ fkms_connector->display_idx = display_idx;
-
- drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA);
-@@ -904,7 +920,8 @@ static int vc4_fkms_create_screen(struct
- drm_encoder_helper_add(&vc4_encoder->base,
- &vc4_fkms_encoder_helper_funcs);
-
-- vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base);
-+ vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base,
-+ display_idx);
- if (IS_ERR(vc4_crtc->connector)) {
- ret = PTR_ERR(vc4_crtc->connector);
- goto err_destroy_encoder;
+++ /dev/null
-From fe2432615ecc3500cc265d6b84334950b9cbd4bf Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2019 18:14:44 +0100
-Subject: [PATCH] from
- vc4_crtc_[en|dis]able
-
-vblank needs to be enabled and disabled by the driver to avoid the
-DRM framework complaining in the kernel log.
-
-vc4_fkms_disable_vblank needs to signal that we don't want vblank
-callbacks too.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -562,6 +562,8 @@ static void vc4_crtc_mode_set_nofb(struc
-
- static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
-+ drm_crtc_vblank_off(crtc);
-+
- /* Always turn the planes off on CRTC disable. In DRM, planes
- * are enabled/disabled through the update/disable hooks
- * above, and the CRTC enable/disable independently controls
-@@ -577,6 +579,7 @@ static void vc4_crtc_disable(struct drm_
-
- static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
-+ drm_crtc_vblank_on(crtc);
- /* Unblank the planes (if they're supposed to be displayed). */
-
- if (crtc->primary->state->fb)
-@@ -673,6 +676,9 @@ static int vc4_fkms_enable_vblank(struct
-
- static void vc4_fkms_disable_vblank(struct drm_crtc *crtc)
- {
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-+
-+ vc4_crtc->vblank_enabled = false;
- }
-
- static const struct drm_crtc_funcs vc4_crtc_funcs = {
--- /dev/null
+From 6885af169f6eeb386f410e556029c6518c6b67b2 Mon Sep 17 00:00:00 2001
+Date: Wed, 10 Apr 2019 17:35:05 +0100
+Subject: [PATCH] drm: vc4: Remove unused vc4_fkms_cancel_page_flip
+ function
+
+"32a3dbe drm/vc4: Nuke preclose hook" removed vc4_cancel_page_flip,
+but vc4_fkms_cancel_page_flip was still be added to with the
+fkms driver, even though it was never called.
+Nuke it too.
+
+---
+ drivers/gpu/drm/vc4/vc4_drv.h | 1 -
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 --------------------
+ 2 files changed, 21 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -724,7 +724,6 @@ extern const struct dma_fence_ops vc4_fe
+
+ /* vc4_firmware_kms.c */
+ extern struct platform_driver vc4_firmware_kms_driver;
+-void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
+
+ /* vc4_gem.c */
+ void vc4_gem_init(struct drm_device *dev);
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -739,26 +739,6 @@ static const struct drm_crtc_helper_func
+ .atomic_flush = vc4_crtc_atomic_flush,
+ };
+
+-/* Frees the page flip event when the DRM device is closed with the
+- * event still outstanding.
+- */
+-void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
+-{
+- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+- struct drm_device *dev = crtc->dev;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&dev->event_lock, flags);
+-
+- if (vc4_crtc->event && vc4_crtc->event->base.file_priv == file) {
+- kfree(&vc4_crtc->event->base);
+- drm_crtc_vblank_put(crtc);
+- vc4_crtc->event = NULL;
+- }
+-
+- spin_unlock_irqrestore(&dev->event_lock, flags);
+-}
+-
+ static const struct of_device_id vc4_firmware_kms_dt_match[] = {
+ { .compatible = "raspberrypi,rpi-firmware-kms" },
+ {}
+++ /dev/null
-From 129100bd38125bef5fe237ab867349dbe8b210ba Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2019 17:19:51 +0100
-Subject: [PATCH] drm: vc4: Add support for H & V flips on each plane
- for FKMS
-
-They are near zero cost options for the HVS, therefore they
-may as well be implemented, and it allows us to invert the
-DSI display.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 36 ++++++++++++++++++++++++++
- 1 file changed, 36 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -61,8 +61,21 @@ struct set_plane {
- u8 padding;
-
- u32 planes[4]; /* DMA address of each plane */
-+
-+ u32 transform;
- };
-
-+/* Values for the transform field */
-+#define TRANSFORM_NO_ROTATE 0
-+#define TRANSFORM_ROTATE_180 BIT(1)
-+#define TRANSFORM_FLIP_HRIZ BIT(16)
-+#define TRANSFORM_FLIP_VERT BIT(17)
-+
-+#define SUPPORTED_ROTATIONS (DRM_MODE_ROTATE_0 | \
-+ DRM_MODE_ROTATE_180 | \
-+ DRM_MODE_REFLECT_X | \
-+ DRM_MODE_REFLECT_Y)
-+
- struct mailbox_set_plane {
- struct rpi_firmware_property_tag_header tag;
- struct set_plane plane;
-@@ -274,6 +287,7 @@ static void vc4_plane_atomic_update(stru
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
- int num_planes = fb->format->num_planes;
- struct drm_display_mode *mode = &state->crtc->mode;
-+ unsigned int rotation = SUPPORTED_ROTATIONS;
-
- mb->plane.vc_image_type = vc_fmt->vc_image;
- mb->plane.width = fb->width;
-@@ -294,6 +308,24 @@ static void vc4_plane_atomic_update(stru
- mb->plane.is_vu = vc_fmt->is_vu;
- mb->plane.planes[0] = bo->paddr + fb->offsets[0];
-
-+ rotation = drm_rotation_simplify(state->rotation, rotation);
-+
-+ switch (rotation) {
-+ default:
-+ case DRM_MODE_ROTATE_0:
-+ mb->plane.transform = TRANSFORM_NO_ROTATE;
-+ break;
-+ case DRM_MODE_ROTATE_180:
-+ mb->plane.transform = TRANSFORM_ROTATE_180;
-+ break;
-+ case DRM_MODE_REFLECT_X:
-+ mb->plane.transform = TRANSFORM_FLIP_HRIZ;
-+ break;
-+ case DRM_MODE_REFLECT_Y:
-+ mb->plane.transform = TRANSFORM_FLIP_VERT;
-+ break;
-+ }
-+
- /* FIXME: If the dest rect goes off screen then clip the src rect so we
- * don't have off-screen pixels.
- */
-@@ -514,9 +546,13 @@ static struct drm_plane *vc4_fkms_plane_
- formats, num_formats, modifiers,
- type, NULL);
-
-+ /* FIXME: Do we need to be checking return values from all these calls?
-+ */
- drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
-
- drm_plane_create_alpha_property(plane);
-+ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
-+ SUPPORTED_ROTATIONS);
-
- /*
- * Default frame buffer setup is with FB on -127, and raspistill etc
--- /dev/null
+From 501dabdd480e2da1b3b1395b5ebf9d5306fec689 Mon Sep 17 00:00:00 2001
+Date: Wed, 10 Apr 2019 17:42:37 +0100
+Subject: [PATCH] drm: vc4: Iterate over all planes in
+ vc4_crtc_[dis|en]able
+
+Fixes a FIXME where the overlay plane wouldn't be restored.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 +++++++++++---------
+ 1 file changed, 11 insertions(+), 9 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -598,6 +598,8 @@ static void vc4_crtc_mode_set_nofb(struc
+
+ static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
++ struct drm_plane *plane;
++
+ drm_crtc_vblank_off(crtc);
+
+ /* Always turn the planes off on CRTC disable. In DRM, planes
+@@ -607,23 +609,23 @@ static void vc4_crtc_disable(struct drm_
+ * give us a CRTC-level control for that.
+ */
+
+- vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
+- vc4_plane_atomic_disable(crtc->primary, crtc->primary->state);
+-
+- /* FIXME: Disable overlay planes */
++ drm_atomic_crtc_for_each_plane(plane, crtc)
++ vc4_plane_atomic_disable(plane, plane->state);
+ }
+
+ static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
++ struct drm_plane *plane;
++
+ drm_crtc_vblank_on(crtc);
++
+ /* Unblank the planes (if they're supposed to be displayed). */
++ drm_atomic_crtc_for_each_plane(plane, crtc)
++ if (plane->state->fb)
++ vc4_plane_set_blank(plane, plane->state->visible);
++}
+
+- if (crtc->primary->state->fb)
+- vc4_plane_set_blank(crtc->primary, false);
+- if (crtc->cursor->state->fb)
+- vc4_plane_set_blank(crtc->cursor, crtc->cursor->state);
+
+- /* FIXME: Enable overlay planes */
+ }
+
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
--- /dev/null
+From d4df2766945e0410d1975434f34e647e7e13b992 Mon Sep 17 00:00:00 2001
+Date: Wed, 10 Apr 2019 17:43:57 +0100
+Subject: [PATCH] drm: vc4: Bring fkms into line with kms in blocking
+ doublescan modes
+
+Implement vc4_crtc_mode_valid so that it blocks doublescan modes
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -625,7 +625,17 @@ static void vc4_crtc_enable(struct drm_c
+ vc4_plane_set_blank(plane, plane->state->visible);
+ }
+
++static enum drm_mode_status
++vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
++{
++ /* Do not allow doublescan modes from user space */
++ if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
++ DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
++ crtc->base.id);
++ return MODE_NO_DBLESCAN;
++ }
+
++ return MODE_OK;
+ }
+
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+@@ -735,10 +745,11 @@ static const struct drm_crtc_funcs vc4_c
+
+ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
+ .mode_set_nofb = vc4_crtc_mode_set_nofb,
+- .atomic_disable = vc4_crtc_disable,
+- .atomic_enable = vc4_crtc_enable,
++ .mode_valid = vc4_crtc_mode_valid,
+ .atomic_check = vc4_crtc_atomic_check,
+ .atomic_flush = vc4_crtc_atomic_flush,
++ .atomic_enable = vc4_crtc_enable,
++ .atomic_disable = vc4_crtc_disable,
+ };
+
+ static const struct of_device_id vc4_firmware_kms_dt_match[] = {
+++ /dev/null
-From 6885af169f6eeb386f410e556029c6518c6b67b2 Mon Sep 17 00:00:00 2001
-Date: Wed, 10 Apr 2019 17:35:05 +0100
-Subject: [PATCH] drm: vc4: Remove unused vc4_fkms_cancel_page_flip
- function
-
-"32a3dbe drm/vc4: Nuke preclose hook" removed vc4_cancel_page_flip,
-but vc4_fkms_cancel_page_flip was still be added to with the
-fkms driver, even though it was never called.
-Nuke it too.
-
----
- drivers/gpu/drm/vc4/vc4_drv.h | 1 -
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 --------------------
- 2 files changed, 21 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -724,7 +724,6 @@ extern const struct dma_fence_ops vc4_fe
-
- /* vc4_firmware_kms.c */
- extern struct platform_driver vc4_firmware_kms_driver;
--void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
-
- /* vc4_gem.c */
- void vc4_gem_init(struct drm_device *dev);
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -739,26 +739,6 @@ static const struct drm_crtc_helper_func
- .atomic_flush = vc4_crtc_atomic_flush,
- };
-
--/* Frees the page flip event when the DRM device is closed with the
-- * event still outstanding.
-- */
--void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
--{
-- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-- struct drm_device *dev = crtc->dev;
-- unsigned long flags;
--
-- spin_lock_irqsave(&dev->event_lock, flags);
--
-- if (vc4_crtc->event && vc4_crtc->event->base.file_priv == file) {
-- kfree(&vc4_crtc->event->base);
-- drm_crtc_vblank_put(crtc);
-- vc4_crtc->event = NULL;
-- }
--
-- spin_unlock_irqrestore(&dev->event_lock, flags);
--}
--
- static const struct of_device_id vc4_firmware_kms_dt_match[] = {
- { .compatible = "raspberrypi,rpi-firmware-kms" },
- {}
--- /dev/null
+From b4ed0c4f55542b642f16ee6376b69968d6bafc3b Mon Sep 17 00:00:00 2001
+Date: Mon, 29 Apr 2019 18:45:00 +0100
+Subject: [PATCH] drm: vc4: Increase max_width/height to 7680.
+
+There are some limits still being investigated that stop
+us going up to 8192, but 7680 is sufficient for dual 4k
+displays.
+
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -429,8 +429,8 @@ int vc4_kms_load(struct drm_device *dev)
+ return ret;
+ }
+
+- dev->mode_config.max_width = 4096;
+- dev->mode_config.max_height = 4096;
++ dev->mode_config.max_width = 7680;
++ dev->mode_config.max_height = 7680;
+ dev->mode_config.funcs = &vc4_mode_funcs;
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.async_page_flip = true;
+++ /dev/null
-From 501dabdd480e2da1b3b1395b5ebf9d5306fec689 Mon Sep 17 00:00:00 2001
-Date: Wed, 10 Apr 2019 17:42:37 +0100
-Subject: [PATCH] drm: vc4: Iterate over all planes in
- vc4_crtc_[dis|en]able
-
-Fixes a FIXME where the overlay plane wouldn't be restored.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 +++++++++++---------
- 1 file changed, 11 insertions(+), 9 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -598,6 +598,8 @@ static void vc4_crtc_mode_set_nofb(struc
-
- static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
-+ struct drm_plane *plane;
-+
- drm_crtc_vblank_off(crtc);
-
- /* Always turn the planes off on CRTC disable. In DRM, planes
-@@ -607,23 +609,23 @@ static void vc4_crtc_disable(struct drm_
- * give us a CRTC-level control for that.
- */
-
-- vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
-- vc4_plane_atomic_disable(crtc->primary, crtc->primary->state);
--
-- /* FIXME: Disable overlay planes */
-+ drm_atomic_crtc_for_each_plane(plane, crtc)
-+ vc4_plane_atomic_disable(plane, plane->state);
- }
-
- static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
-+ struct drm_plane *plane;
-+
- drm_crtc_vblank_on(crtc);
-+
- /* Unblank the planes (if they're supposed to be displayed). */
-+ drm_atomic_crtc_for_each_plane(plane, crtc)
-+ if (plane->state->fb)
-+ vc4_plane_set_blank(plane, plane->state->visible);
-+}
-
-- if (crtc->primary->state->fb)
-- vc4_plane_set_blank(crtc->primary, false);
-- if (crtc->cursor->state->fb)
-- vc4_plane_set_blank(crtc->cursor, crtc->cursor->state);
-
-- /* FIXME: Enable overlay planes */
- }
-
- static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+++ /dev/null
-From d4df2766945e0410d1975434f34e647e7e13b992 Mon Sep 17 00:00:00 2001
-Date: Wed, 10 Apr 2019 17:43:57 +0100
-Subject: [PATCH] drm: vc4: Bring fkms into line with kms in blocking
- doublescan modes
-
-Implement vc4_crtc_mode_valid so that it blocks doublescan modes
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 +++++++++++++--
- 1 file changed, 13 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -625,7 +625,17 @@ static void vc4_crtc_enable(struct drm_c
- vc4_plane_set_blank(plane, plane->state->visible);
- }
-
-+static enum drm_mode_status
-+vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
-+{
-+ /* Do not allow doublescan modes from user space */
-+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
-+ DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
-+ crtc->base.id);
-+ return MODE_NO_DBLESCAN;
-+ }
-
-+ return MODE_OK;
- }
-
- static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
-@@ -735,10 +745,11 @@ static const struct drm_crtc_funcs vc4_c
-
- static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
- .mode_set_nofb = vc4_crtc_mode_set_nofb,
-- .atomic_disable = vc4_crtc_disable,
-- .atomic_enable = vc4_crtc_enable,
-+ .mode_valid = vc4_crtc_mode_valid,
- .atomic_check = vc4_crtc_atomic_check,
- .atomic_flush = vc4_crtc_atomic_flush,
-+ .atomic_enable = vc4_crtc_enable,
-+ .atomic_disable = vc4_crtc_disable,
- };
-
- static const struct of_device_id vc4_firmware_kms_dt_match[] = {
--- /dev/null
+From 9536044338d9c341e805e288a58090c49a793638 Mon Sep 17 00:00:00 2001
+Date: Tue, 9 Apr 2019 18:23:41 +0100
+Subject: [PATCH] drm: vc4: FKMS reads the EDID from fw, and supports
+ mode setting
+
+This extends FKMS to read the EDID from the display, and support
+requesting a particular mode via KMS.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 334 ++++++++++++++++++---
+ include/soc/bcm2835/raspberrypi-firmware.h | 2 +
+ 2 files changed, 302 insertions(+), 34 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -88,11 +88,60 @@ struct mailbox_blank_display {
+ u32 blank;
+ };
+
+-struct mailbox_get_width_height {
++struct mailbox_get_edid {
+ struct rpi_firmware_property_tag_header tag1;
+- u32 display;
+- struct rpi_firmware_property_tag_header tag2;
+- u32 wh[2];
++ u32 block;
++ u32 display_number;
++ u8 edid[128];
++};
++
++struct set_timings {
++ u8 display;
++ u8 padding;
++ u16 video_id_code;
++
++ u32 clock; /* in kHz */
++
++ u16 hdisplay;
++ u16 hsync_start;
++
++ u16 hsync_end;
++ u16 htotal;
++
++ u16 hskew;
++ u16 vdisplay;
++
++ u16 vsync_start;
++ u16 vsync_end;
++
++ u16 vtotal;
++ u16 vscan;
++
++ u16 vrefresh;
++ u16 padding2;
++
++ u32 flags;
++#define TIMINGS_FLAGS_H_SYNC_POS BIT(0)
++#define TIMINGS_FLAGS_H_SYNC_NEG 0
++#define TIMINGS_FLAGS_V_SYNC_POS BIT(1)
++#define TIMINGS_FLAGS_V_SYNC_NEG 0
++
++#define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4)
++#define TIMINGS_FLAGS_ASPECT_NONE (0 << 4)
++#define TIMINGS_FLAGS_ASPECT_4_3 (1 << 4)
++#define TIMINGS_FLAGS_ASPECT_16_9 (2 << 4)
++#define TIMINGS_FLAGS_ASPECT_64_27 (3 << 4)
++#define TIMINGS_FLAGS_ASPECT_256_135 (4 << 4)
++
++/* Limited range RGB flag. Not set corresponds to full range. */
++#define TIMINGS_FLAGS_RGB_LIMITED BIT(8)
++/* DVI monitor, therefore disable infoframes. Not set corresponds to HDMI. */
++#define TIMINGS_FLAGS_DVI BIT(9)
++};
++
++struct mailbox_set_mode {
++ struct rpi_firmware_property_tag_header tag1;
++ struct set_timings timings;
+ };
+
+ static const struct vc_image_format {
+@@ -186,6 +235,7 @@ struct vc4_crtc {
+ u32 overscan[4];
+ bool vblank_enabled;
+ u32 display_number;
++ u32 display_type;
+ };
+
+ static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
+@@ -195,6 +245,8 @@ static inline struct vc4_crtc *to_vc4_cr
+
+ struct vc4_fkms_encoder {
+ struct drm_encoder base;
++ bool hdmi_monitor;
++ bool rgb_range_selectable;
+ };
+
+ static inline struct vc4_fkms_encoder *
+@@ -212,7 +264,9 @@ struct vc4_fkms_connector {
+ * hook.
+ */
+ struct drm_encoder *encoder;
+- u32 display_idx;
++ struct vc4_dev *vc4_dev;
++ u32 display_number;
++ u32 display_type;
+ };
+
+ static inline struct vc4_fkms_connector *
+@@ -221,6 +275,26 @@ to_vc4_fkms_connector(struct drm_connect
+ return container_of(connector, struct vc4_fkms_connector, base);
+ }
+
++static u32 vc4_get_display_type(u32 display_number)
++{
++ const u32 display_types[] = {
++ /* The firmware display (DispmanX) IDs map to specific types in
++ * a fixed manner.
++ */
++ DRM_MODE_ENCODER_DSI, /* MAIN_LCD */
++ DRM_MODE_ENCODER_DSI, /* AUX_LCD */
++ DRM_MODE_ENCODER_TMDS, /* HDMI0 */
++ DRM_MODE_ENCODER_TVDAC, /* VEC */
++ DRM_MODE_ENCODER_NONE, /* FORCE_LCD */
++ DRM_MODE_ENCODER_NONE, /* FORCE_TV */
++ DRM_MODE_ENCODER_NONE, /* FORCE_OTHER */
++ DRM_MODE_ENCODER_TMDS, /* HDMI1 */
++ DRM_MODE_ENCODER_NONE, /* FORCE_TV2 */
++ };
++ return display_number > ARRAY_SIZE(display_types) - 1 ?
++ DRM_MODE_ENCODER_NONE : display_types[display_number];
++}
++
+ /* Firmware's structure for making an FB mbox call. */
+ struct fbinfo_s {
+ u32 xres, yres, xres_virtual, yres_virtual;
+@@ -255,10 +329,15 @@ static int vc4_plane_set_blank(struct dr
+ .plane_id = vc4_plane->mb.plane.plane_id,
+ }
+ };
++ static const char * const plane_types[] = {
++ "overlay",
++ "primary",
++ "cursor"
++ };
+ int ret;
+
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s",
+- plane->base.id, plane->name,
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] %s plane %s",
++ plane->base.id, plane->name, plane_types[plane->type],
+ blank ? "blank" : "unblank");
+
+ if (blank)
+@@ -593,13 +672,102 @@ fail:
+
+ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
+ {
+- /* Everyting is handled in the planes. */
++ struct drm_device *dev = crtc->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
++ struct vc4_fkms_encoder *vc4_encoder =
++ to_vc4_fkms_encoder(vc4_crtc->encoder);
++ struct mailbox_set_mode mb = {
++ .tag1 = { RPI_FIRMWARE_SET_TIMING,
++ sizeof(struct set_timings), 0},
++ };
++ union hdmi_infoframe frame;
++ int ret;
++
++ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false);
++ if (ret < 0) {
++ DRM_ERROR("couldn't fill AVI infoframe\n");
++ return;
++ }
++
++ DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u\n",
++ vc4_crtc->display_number, mode->name, mode->clock,
++ mode->hdisplay, mode->hsync_start, mode->hsync_end,
++ mode->htotal, mode->hskew, mode->vdisplay,
++ mode->vsync_start, mode->vsync_end, mode->vtotal,
++ mode->vscan, mode->vrefresh, mode->picture_aspect_ratio);
++ mb.timings.display = vc4_crtc->display_number;
++
++ mb.timings.video_id_code = frame.avi.video_code;
++
++ mb.timings.clock = mode->clock;
++ mb.timings.hdisplay = mode->hdisplay;
++ mb.timings.hsync_start = mode->hsync_start;
++ mb.timings.hsync_end = mode->hsync_end;
++ mb.timings.htotal = mode->htotal;
++ mb.timings.hskew = mode->hskew;
++ mb.timings.vdisplay = mode->vdisplay;
++ mb.timings.vsync_start = mode->vsync_start;
++ mb.timings.vsync_end = mode->vsync_end;
++ mb.timings.vtotal = mode->vtotal;
++ mb.timings.vscan = mode->vscan;
++ mb.timings.vrefresh = 0;
++ mb.timings.flags = 0;
++ if (mode->flags & DRM_MODE_FLAG_PHSYNC)
++ mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS;
++ if (mode->flags & DRM_MODE_FLAG_PVSYNC)
++ mb.timings.flags |= TIMINGS_FLAGS_V_SYNC_POS;
++
++ switch (frame.avi.picture_aspect) {
++ default:
++ case HDMI_PICTURE_ASPECT_NONE:
++ mode->flags |= TIMINGS_FLAGS_ASPECT_NONE;
++ break;
++ case HDMI_PICTURE_ASPECT_4_3:
++ mode->flags |= TIMINGS_FLAGS_ASPECT_4_3;
++ break;
++ case HDMI_PICTURE_ASPECT_16_9:
++ mode->flags |= TIMINGS_FLAGS_ASPECT_16_9;
++ break;
++ case HDMI_PICTURE_ASPECT_64_27:
++ mode->flags |= TIMINGS_FLAGS_ASPECT_64_27;
++ break;
++ case HDMI_PICTURE_ASPECT_256_135:
++ mode->flags |= TIMINGS_FLAGS_ASPECT_256_135;
++ break;
++ }
++
++ if (!vc4_encoder->hdmi_monitor)
++ mb.timings.flags |= TIMINGS_FLAGS_DVI;
++ else if (drm_default_rgb_quant_range(mode) ==
++ HDMI_QUANTIZATION_RANGE_LIMITED)
++ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
++
++ /*
++ FIXME: To implement
++ switch(mode->flag & DRM_MODE_FLAG_3D_MASK) {
++ case DRM_MODE_FLAG_3D_NONE:
++ case DRM_MODE_FLAG_3D_FRAME_PACKING:
++ case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
++ case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
++ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
++ case DRM_MODE_FLAG_3D_L_DEPTH:
++ case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
++ case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
++ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
++ }
++ */
++
++ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
+ }
+
+ static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
+ struct drm_plane *plane;
+
++ DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
++ crtc->base.id);
+ drm_crtc_vblank_off(crtc);
+
+ /* Always turn the planes off on CRTC disable. In DRM, planes
+@@ -617,6 +785,8 @@ static void vc4_crtc_enable(struct drm_c
+ {
+ struct drm_plane *plane;
+
++ DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
++ crtc->base.id);
+ drm_crtc_vblank_on(crtc);
+
+ /* Unblank the planes (if they're supposed to be displayed). */
+@@ -635,12 +805,20 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ return MODE_NO_DBLESCAN;
+ }
+
++ /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling
++ * working.
++ */
++ if (mode->clock > 340000)
++ return MODE_CLOCK_HIGH;
++
+ return MODE_OK;
+ }
+
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+ {
++ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n",
++ crtc->base.id);
+ return 0;
+ }
+
+@@ -650,6 +828,8 @@ static void vc4_crtc_atomic_flush(struct
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+
++ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
++ crtc->base.id);
+ if (crtc->state->event) {
+ unsigned long flags;
+
+@@ -717,6 +897,8 @@ static int vc4_fkms_enable_vblank(struct
+ {
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+
++ DRM_DEBUG_KMS("[CRTC:%d] enable_vblank.\n",
++ crtc->base.id);
+ vc4_crtc->vblank_enabled = true;
+
+ return 0;
+@@ -726,6 +908,8 @@ static void vc4_fkms_disable_vblank(stru
+ {
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+
++ DRM_DEBUG_KMS("[CRTC:%d] disable_vblank.\n",
++ crtc->base.id);
+ vc4_crtc->vblank_enabled = false;
+ }
+
+@@ -760,36 +944,92 @@ static const struct of_device_id vc4_fir
+ static enum drm_connector_status
+ vc4_fkms_connector_detect(struct drm_connector *connector, bool force)
+ {
++ DRM_DEBUG_KMS("connector detect.\n");
+ return connector_status_connected;
+ }
+
+-static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
++static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
++ size_t len)
+ {
+- struct drm_device *dev = connector->dev;
+ struct vc4_fkms_connector *fkms_connector =
+- to_vc4_fkms_connector(connector);
+- struct vc4_dev *vc4 = to_vc4_dev(dev);
+- struct drm_display_mode *mode;
+- struct mailbox_get_width_height wh = {
+- .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
+- .display = fkms_connector->display_idx,
+- .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
+- 8, 0, },
++ (struct vc4_fkms_connector *)data;
++ struct vc4_dev *vc4 = fkms_connector->vc4_dev;
++ struct mailbox_get_edid mb = {
++ .tag1 = { RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY,
++ 128 + 8, 0 },
++ .block = block,
++ .display_number = fkms_connector->display_number,
+ };
+- int ret;
++ int ret = 0;
++
++ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
++
++ if (!ret)
++ memcpy(buf, mb.edid, len);
++
++ return ret;
++}
++
++static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
++{
++ struct vc4_fkms_connector *fkms_connector =
++ to_vc4_fkms_connector(connector);
++ struct drm_encoder *encoder = fkms_connector->encoder;
++ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
++ int ret = 0;
++ struct edid *edid;
++
++ edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
++ fkms_connector);
++
++ /* FIXME: Can we do CEC?
++ * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
++ * if (!edid)
++ * return -ENODEV;
++ */
++
++ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
+
+- ret = rpi_firmware_property_list(vc4->firmware, &wh, sizeof(wh));
++ if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
++ vc4_encoder->rgb_range_selectable =
++ drm_rgb_quant_range_selectable(edid);
++ }
++
++ drm_connector_update_edid_property(connector, edid);
++ ret = drm_add_edid_modes(connector, edid);
++ kfree(edid);
++
++ return ret;
++}
++
++/* FIXME: Read LCD mode from the firmware. This is the DSI panel resolution. */
++static const struct drm_display_mode lcd_mode = {
++ DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
++ 25979400 / 1000,
++ 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0,
++ 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0,
++ DRM_MODE_FLAG_INTERLACE)
++};
++
++static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
++{
++ //struct vc4_fkms_connector *fkms_connector =
++ // to_vc4_fkms_connector(connector);
++ //struct drm_encoder *encoder = fkms_connector->encoder;
++ //struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
++ struct drm_display_mode *mode;
++ //int ret = 0;
+
+- if (ret) {
+- DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n",
+- ret, wh.wh[0], wh.wh[1]);
+- return 0;
++ mode = drm_mode_duplicate(connector->dev,
++ &lcd_mode);
++ if (!mode) {
++ DRM_ERROR("Failed to create a new display mode\n");
++ return -ENOMEM;
+ }
+
+- mode = drm_cvt_mode(dev, wh.wh[0], wh.wh[1], 60 /* vrefresh */,
+- 0, 0, false);
+ drm_mode_probed_add(connector, mode);
+
++ /* We have one mode */
+ return 1;
+ }
+
+@@ -798,11 +1038,14 @@ vc4_fkms_connector_best_encoder(struct d
+ {
+ struct vc4_fkms_connector *fkms_connector =
+ to_vc4_fkms_connector(connector);
++ DRM_DEBUG_KMS("best_connector.\n");
+ return fkms_connector->encoder;
+ }
+
+ static void vc4_fkms_connector_destroy(struct drm_connector *connector)
+ {
++ DRM_DEBUG_KMS("[CONNECTOR:%d] destroy.\n",
++ connector->base.id);
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+ }
+@@ -821,14 +1064,22 @@ static const struct drm_connector_helper
+ .best_encoder = vc4_fkms_connector_best_encoder,
+ };
+
++static const struct drm_connector_helper_funcs vc4_fkms_lcd_conn_helper_funcs = {
++ .get_modes = vc4_fkms_lcd_connector_get_modes,
++ .best_encoder = vc4_fkms_connector_best_encoder,
++};
++
+ static struct drm_connector *
+ vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
+- u32 display_idx)
++ u32 display_num)
+ {
+ struct drm_connector *connector = NULL;
+ struct vc4_fkms_connector *fkms_connector;
++ struct vc4_dev *vc4_dev = to_vc4_dev(dev);
+ int ret = 0;
+
++ DRM_DEBUG_KMS("connector_init, display_num %u\n", display_num);
++
+ fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
+ GFP_KERNEL);
+ if (!fkms_connector) {
+@@ -838,11 +1089,21 @@ vc4_fkms_connector_init(struct drm_devic
+ connector = &fkms_connector->base;
+
+ fkms_connector->encoder = encoder;
+- fkms_connector->display_idx = display_idx;
+-
+- drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
+- DRM_MODE_CONNECTOR_HDMIA);
+- drm_connector_helper_add(connector, &vc4_fkms_connector_helper_funcs);
++ fkms_connector->display_number = display_num;
++ fkms_connector->display_type = vc4_get_display_type(display_num);
++ fkms_connector->vc4_dev = vc4_dev;
++
++ if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) {
++ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
++ DRM_MODE_CONNECTOR_DSI);
++ drm_connector_helper_add(connector,
++ &vc4_fkms_lcd_conn_helper_funcs);
++ } else {
++ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
++ DRM_MODE_CONNECTOR_HDMIA);
++ drm_connector_helper_add(connector,
++ &vc4_fkms_connector_helper_funcs);
++ }
+
+ connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT);
+@@ -863,6 +1124,7 @@ vc4_fkms_connector_init(struct drm_devic
+
+ static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder)
+ {
++ DRM_DEBUG_KMS("Encoder_destroy\n");
+ drm_encoder_cleanup(encoder);
+ }
+
+@@ -872,10 +1134,12 @@ static const struct drm_encoder_funcs vc
+
+ static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
+ {
++ DRM_DEBUG_KMS("Encoder_enable\n");
+ }
+
+ static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
+ {
++ DRM_DEBUG_KMS("Encoder_disable\n");
+ }
+
+ static const struct drm_encoder_helper_funcs vc4_fkms_encoder_helper_funcs = {
+@@ -907,6 +1171,7 @@ static int vc4_fkms_create_screen(struct
+ crtc = &vc4_crtc->base;
+
+ vc4_crtc->display_number = display_ref;
++ vc4_crtc->display_type = vc4_get_display_type(display_ref);
+
+ /* Blank the firmware provided framebuffer */
+ rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank));
+@@ -950,13 +1215,14 @@ static int vc4_fkms_create_screen(struct
+ return -ENOMEM;
+ vc4_crtc->encoder = &vc4_encoder->base;
+ vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ;
++
+ drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
+- DRM_MODE_ENCODER_TMDS, NULL);
++ vc4_crtc->display_type, NULL);
+ drm_encoder_helper_add(&vc4_encoder->base,
+ &vc4_fkms_encoder_helper_funcs);
+
+ vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base,
+- display_idx);
++ display_ref);
+ if (IS_ERR(vc4_crtc->connector)) {
+ ret = PTR_ERR(vc4_crtc->connector);
+ goto err_destroy_encoder;
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -78,6 +78,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
+ RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
+ RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
++ RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY = 0x00030023,
+ RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
+ RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
+ RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
+@@ -150,6 +151,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
+
+ RPI_FIRMWARE_SET_PLANE = 0x00048015,
++ RPI_FIRMWARE_SET_TIMING = 0x00048017,
+
+ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
+ RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
--- /dev/null
+From bf85b92a97a95161d98874571c520fb1395c5aa2 Mon Sep 17 00:00:00 2001
+Date: Thu, 2 May 2019 15:11:05 -0700
+Subject: [PATCH] clk: bcm2835: Add support for setting leaf clock
+ rates while running.
+
+As long as you wait for !BUSY, you can do glitch-free updates of clock
+rate while the clock is running.
+
+---
+ drivers/clk/bcm/clk-bcm2835.c | 22 +++++++++++++---------
+ 1 file changed, 13 insertions(+), 9 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1097,15 +1097,19 @@ static int bcm2835_clock_set_rate(struct
+
+ spin_lock(&cprman->regs_lock);
+
+- /*
+- * Setting up frac support
+- *
+- * In principle it is recommended to stop/start the clock first,
+- * but as we set CLK_SET_RATE_GATE during registration of the
+- * clock this requirement should be take care of by the
+- * clk-framework.
++ ctl = cprman_read(cprman, data->ctl_reg);
++
++ /* If the clock is running, we have to pause clock generation while
++ * updating the control and div regs. This is glitchless (no clock
++ * signals generated faster than the rate) but each reg access is two
++ * OSC cycles so the clock will slow down for a moment.
+ */
+- ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC;
++ if (ctl & CM_ENABLE) {
++ cprman_write(cprman, data->ctl_reg, ctl & ~CM_ENABLE);
++ bcm2835_clock_wait_busy(clock);
++ }
++
++ ctl &= ~CM_FRAC;
+ ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
+ cprman_write(cprman, data->ctl_reg, ctl);
+
+@@ -1475,7 +1479,7 @@ static struct clk_hw *bcm2835_register_c
+ init.ops = &bcm2835_vpu_clock_clk_ops;
+ } else {
+ init.ops = &bcm2835_clock_clk_ops;
+- init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
++ init.flags |= CLK_SET_PARENT_GATE;
+
+ /* If the clock wasn't actually enabled at boot, it's not
+ * critical.
+++ /dev/null
-From b4ed0c4f55542b642f16ee6376b69968d6bafc3b Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Apr 2019 18:45:00 +0100
-Subject: [PATCH] drm: vc4: Increase max_width/height to 7680.
-
-There are some limits still being investigated that stop
-us going up to 8192, but 7680 is sufficient for dual 4k
-displays.
-
----
- drivers/gpu/drm/vc4/vc4_kms.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -429,8 +429,8 @@ int vc4_kms_load(struct drm_device *dev)
- return ret;
- }
-
-- dev->mode_config.max_width = 4096;
-- dev->mode_config.max_height = 4096;
-+ dev->mode_config.max_width = 7680;
-+ dev->mode_config.max_height = 7680;
- dev->mode_config.funcs = &vc4_mode_funcs;
- dev->mode_config.preferred_depth = 24;
- dev->mode_config.async_page_flip = true;
--- /dev/null
+From d46285327ba5961c992643d468b2862c70f4c7e5 Mon Sep 17 00:00:00 2001
+Date: Thu, 2 May 2019 15:24:04 -0700
+Subject: [PATCH] clk: bcm2835: Allow reparenting leaf clocks while
+ they're running.
+
+This falls under the same "we can reprogram glitch-free as long as we
+pause generation" rule as updating the div/frac fields. This can be
+used for runtime reclocking of V3D to manage power leakage.
+
+---
+ drivers/clk/bcm/clk-bcm2835.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1086,8 +1086,10 @@ static int bcm2835_clock_on(struct clk_h
+ return 0;
+ }
+
+-static int bcm2835_clock_set_rate(struct clk_hw *hw,
+- unsigned long rate, unsigned long parent_rate)
++static int bcm2835_clock_set_rate_and_parent(struct clk_hw *hw,
++ unsigned long rate,
++ unsigned long parent_rate,
++ u8 parent)
+ {
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ struct bcm2835_cprman *cprman = clock->cprman;
+@@ -1109,6 +1111,11 @@ static int bcm2835_clock_set_rate(struct
+ bcm2835_clock_wait_busy(clock);
+ }
+
++ if (parent != 0xff) {
++ ctl &= ~(CM_SRC_MASK << CM_SRC_SHIFT);
++ ctl |= parent << CM_SRC_SHIFT;
++ }
++
+ ctl &= ~CM_FRAC;
+ ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
+ cprman_write(cprman, data->ctl_reg, ctl);
+@@ -1120,6 +1127,12 @@ static int bcm2835_clock_set_rate(struct
+ return 0;
+ }
+
++static int bcm2835_clock_set_rate(struct clk_hw *hw,
++ unsigned long rate, unsigned long parent_rate)
++{
++ return bcm2835_clock_set_rate_and_parent(hw, rate, parent_rate, 0xff);
++}
++
+ static bool
+ bcm2835_clk_is_pllc(struct clk_hw *hw)
+ {
+@@ -1303,6 +1316,7 @@ static const struct clk_ops bcm2835_cloc
+ .unprepare = bcm2835_clock_off,
+ .recalc_rate = bcm2835_clock_get_rate,
+ .set_rate = bcm2835_clock_set_rate,
++ .set_rate_and_parent = bcm2835_clock_set_rate_and_parent,
+ .determine_rate = bcm2835_clock_determine_rate,
+ .set_parent = bcm2835_clock_set_parent,
+ .get_parent = bcm2835_clock_get_parent,
+@@ -1479,7 +1493,6 @@ static struct clk_hw *bcm2835_register_c
+ init.ops = &bcm2835_vpu_clock_clk_ops;
+ } else {
+ init.ops = &bcm2835_clock_clk_ops;
+- init.flags |= CLK_SET_PARENT_GATE;
+
+ /* If the clock wasn't actually enabled at boot, it's not
+ * critical.
+++ /dev/null
-From 9536044338d9c341e805e288a58090c49a793638 Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Apr 2019 18:23:41 +0100
-Subject: [PATCH] drm: vc4: FKMS reads the EDID from fw, and supports
- mode setting
-
-This extends FKMS to read the EDID from the display, and support
-requesting a particular mode via KMS.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 334 ++++++++++++++++++---
- include/soc/bcm2835/raspberrypi-firmware.h | 2 +
- 2 files changed, 302 insertions(+), 34 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -88,11 +88,60 @@ struct mailbox_blank_display {
- u32 blank;
- };
-
--struct mailbox_get_width_height {
-+struct mailbox_get_edid {
- struct rpi_firmware_property_tag_header tag1;
-- u32 display;
-- struct rpi_firmware_property_tag_header tag2;
-- u32 wh[2];
-+ u32 block;
-+ u32 display_number;
-+ u8 edid[128];
-+};
-+
-+struct set_timings {
-+ u8 display;
-+ u8 padding;
-+ u16 video_id_code;
-+
-+ u32 clock; /* in kHz */
-+
-+ u16 hdisplay;
-+ u16 hsync_start;
-+
-+ u16 hsync_end;
-+ u16 htotal;
-+
-+ u16 hskew;
-+ u16 vdisplay;
-+
-+ u16 vsync_start;
-+ u16 vsync_end;
-+
-+ u16 vtotal;
-+ u16 vscan;
-+
-+ u16 vrefresh;
-+ u16 padding2;
-+
-+ u32 flags;
-+#define TIMINGS_FLAGS_H_SYNC_POS BIT(0)
-+#define TIMINGS_FLAGS_H_SYNC_NEG 0
-+#define TIMINGS_FLAGS_V_SYNC_POS BIT(1)
-+#define TIMINGS_FLAGS_V_SYNC_NEG 0
-+
-+#define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4)
-+#define TIMINGS_FLAGS_ASPECT_NONE (0 << 4)
-+#define TIMINGS_FLAGS_ASPECT_4_3 (1 << 4)
-+#define TIMINGS_FLAGS_ASPECT_16_9 (2 << 4)
-+#define TIMINGS_FLAGS_ASPECT_64_27 (3 << 4)
-+#define TIMINGS_FLAGS_ASPECT_256_135 (4 << 4)
-+
-+/* Limited range RGB flag. Not set corresponds to full range. */
-+#define TIMINGS_FLAGS_RGB_LIMITED BIT(8)
-+/* DVI monitor, therefore disable infoframes. Not set corresponds to HDMI. */
-+#define TIMINGS_FLAGS_DVI BIT(9)
-+};
-+
-+struct mailbox_set_mode {
-+ struct rpi_firmware_property_tag_header tag1;
-+ struct set_timings timings;
- };
-
- static const struct vc_image_format {
-@@ -186,6 +235,7 @@ struct vc4_crtc {
- u32 overscan[4];
- bool vblank_enabled;
- u32 display_number;
-+ u32 display_type;
- };
-
- static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
-@@ -195,6 +245,8 @@ static inline struct vc4_crtc *to_vc4_cr
-
- struct vc4_fkms_encoder {
- struct drm_encoder base;
-+ bool hdmi_monitor;
-+ bool rgb_range_selectable;
- };
-
- static inline struct vc4_fkms_encoder *
-@@ -212,7 +264,9 @@ struct vc4_fkms_connector {
- * hook.
- */
- struct drm_encoder *encoder;
-- u32 display_idx;
-+ struct vc4_dev *vc4_dev;
-+ u32 display_number;
-+ u32 display_type;
- };
-
- static inline struct vc4_fkms_connector *
-@@ -221,6 +275,26 @@ to_vc4_fkms_connector(struct drm_connect
- return container_of(connector, struct vc4_fkms_connector, base);
- }
-
-+static u32 vc4_get_display_type(u32 display_number)
-+{
-+ const u32 display_types[] = {
-+ /* The firmware display (DispmanX) IDs map to specific types in
-+ * a fixed manner.
-+ */
-+ DRM_MODE_ENCODER_DSI, /* MAIN_LCD */
-+ DRM_MODE_ENCODER_DSI, /* AUX_LCD */
-+ DRM_MODE_ENCODER_TMDS, /* HDMI0 */
-+ DRM_MODE_ENCODER_TVDAC, /* VEC */
-+ DRM_MODE_ENCODER_NONE, /* FORCE_LCD */
-+ DRM_MODE_ENCODER_NONE, /* FORCE_TV */
-+ DRM_MODE_ENCODER_NONE, /* FORCE_OTHER */
-+ DRM_MODE_ENCODER_TMDS, /* HDMI1 */
-+ DRM_MODE_ENCODER_NONE, /* FORCE_TV2 */
-+ };
-+ return display_number > ARRAY_SIZE(display_types) - 1 ?
-+ DRM_MODE_ENCODER_NONE : display_types[display_number];
-+}
-+
- /* Firmware's structure for making an FB mbox call. */
- struct fbinfo_s {
- u32 xres, yres, xres_virtual, yres_virtual;
-@@ -255,10 +329,15 @@ static int vc4_plane_set_blank(struct dr
- .plane_id = vc4_plane->mb.plane.plane_id,
- }
- };
-+ static const char * const plane_types[] = {
-+ "overlay",
-+ "primary",
-+ "cursor"
-+ };
- int ret;
-
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s",
-- plane->base.id, plane->name,
-+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] %s plane %s",
-+ plane->base.id, plane->name, plane_types[plane->type],
- blank ? "blank" : "unblank");
-
- if (blank)
-@@ -593,13 +672,102 @@ fail:
-
- static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
- {
-- /* Everyting is handled in the planes. */
-+ struct drm_device *dev = crtc->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-+ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
-+ struct vc4_fkms_encoder *vc4_encoder =
-+ to_vc4_fkms_encoder(vc4_crtc->encoder);
-+ struct mailbox_set_mode mb = {
-+ .tag1 = { RPI_FIRMWARE_SET_TIMING,
-+ sizeof(struct set_timings), 0},
-+ };
-+ union hdmi_infoframe frame;
-+ int ret;
-+
-+ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false);
-+ if (ret < 0) {
-+ DRM_ERROR("couldn't fill AVI infoframe\n");
-+ return;
-+ }
-+
-+ DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u\n",
-+ vc4_crtc->display_number, mode->name, mode->clock,
-+ mode->hdisplay, mode->hsync_start, mode->hsync_end,
-+ mode->htotal, mode->hskew, mode->vdisplay,
-+ mode->vsync_start, mode->vsync_end, mode->vtotal,
-+ mode->vscan, mode->vrefresh, mode->picture_aspect_ratio);
-+ mb.timings.display = vc4_crtc->display_number;
-+
-+ mb.timings.video_id_code = frame.avi.video_code;
-+
-+ mb.timings.clock = mode->clock;
-+ mb.timings.hdisplay = mode->hdisplay;
-+ mb.timings.hsync_start = mode->hsync_start;
-+ mb.timings.hsync_end = mode->hsync_end;
-+ mb.timings.htotal = mode->htotal;
-+ mb.timings.hskew = mode->hskew;
-+ mb.timings.vdisplay = mode->vdisplay;
-+ mb.timings.vsync_start = mode->vsync_start;
-+ mb.timings.vsync_end = mode->vsync_end;
-+ mb.timings.vtotal = mode->vtotal;
-+ mb.timings.vscan = mode->vscan;
-+ mb.timings.vrefresh = 0;
-+ mb.timings.flags = 0;
-+ if (mode->flags & DRM_MODE_FLAG_PHSYNC)
-+ mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS;
-+ if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-+ mb.timings.flags |= TIMINGS_FLAGS_V_SYNC_POS;
-+
-+ switch (frame.avi.picture_aspect) {
-+ default:
-+ case HDMI_PICTURE_ASPECT_NONE:
-+ mode->flags |= TIMINGS_FLAGS_ASPECT_NONE;
-+ break;
-+ case HDMI_PICTURE_ASPECT_4_3:
-+ mode->flags |= TIMINGS_FLAGS_ASPECT_4_3;
-+ break;
-+ case HDMI_PICTURE_ASPECT_16_9:
-+ mode->flags |= TIMINGS_FLAGS_ASPECT_16_9;
-+ break;
-+ case HDMI_PICTURE_ASPECT_64_27:
-+ mode->flags |= TIMINGS_FLAGS_ASPECT_64_27;
-+ break;
-+ case HDMI_PICTURE_ASPECT_256_135:
-+ mode->flags |= TIMINGS_FLAGS_ASPECT_256_135;
-+ break;
-+ }
-+
-+ if (!vc4_encoder->hdmi_monitor)
-+ mb.timings.flags |= TIMINGS_FLAGS_DVI;
-+ else if (drm_default_rgb_quant_range(mode) ==
-+ HDMI_QUANTIZATION_RANGE_LIMITED)
-+ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
-+
-+ /*
-+ FIXME: To implement
-+ switch(mode->flag & DRM_MODE_FLAG_3D_MASK) {
-+ case DRM_MODE_FLAG_3D_NONE:
-+ case DRM_MODE_FLAG_3D_FRAME_PACKING:
-+ case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
-+ case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
-+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
-+ case DRM_MODE_FLAG_3D_L_DEPTH:
-+ case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
-+ case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
-+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
-+ }
-+ */
-+
-+ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
- }
-
- static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
- struct drm_plane *plane;
-
-+ DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
-+ crtc->base.id);
- drm_crtc_vblank_off(crtc);
-
- /* Always turn the planes off on CRTC disable. In DRM, planes
-@@ -617,6 +785,8 @@ static void vc4_crtc_enable(struct drm_c
- {
- struct drm_plane *plane;
-
-+ DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
-+ crtc->base.id);
- drm_crtc_vblank_on(crtc);
-
- /* Unblank the planes (if they're supposed to be displayed). */
-@@ -635,12 +805,20 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
- return MODE_NO_DBLESCAN;
- }
-
-+ /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling
-+ * working.
-+ */
-+ if (mode->clock > 340000)
-+ return MODE_CLOCK_HIGH;
-+
- return MODE_OK;
- }
-
- static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_crtc_state *state)
- {
-+ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n",
-+ crtc->base.id);
- return 0;
- }
-
-@@ -650,6 +828,8 @@ static void vc4_crtc_atomic_flush(struct
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
- struct drm_device *dev = crtc->dev;
-
-+ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
-+ crtc->base.id);
- if (crtc->state->event) {
- unsigned long flags;
-
-@@ -717,6 +897,8 @@ static int vc4_fkms_enable_vblank(struct
- {
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-
-+ DRM_DEBUG_KMS("[CRTC:%d] enable_vblank.\n",
-+ crtc->base.id);
- vc4_crtc->vblank_enabled = true;
-
- return 0;
-@@ -726,6 +908,8 @@ static void vc4_fkms_disable_vblank(stru
- {
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-
-+ DRM_DEBUG_KMS("[CRTC:%d] disable_vblank.\n",
-+ crtc->base.id);
- vc4_crtc->vblank_enabled = false;
- }
-
-@@ -760,36 +944,92 @@ static const struct of_device_id vc4_fir
- static enum drm_connector_status
- vc4_fkms_connector_detect(struct drm_connector *connector, bool force)
- {
-+ DRM_DEBUG_KMS("connector detect.\n");
- return connector_status_connected;
- }
-
--static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
-+static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
-+ size_t len)
- {
-- struct drm_device *dev = connector->dev;
- struct vc4_fkms_connector *fkms_connector =
-- to_vc4_fkms_connector(connector);
-- struct vc4_dev *vc4 = to_vc4_dev(dev);
-- struct drm_display_mode *mode;
-- struct mailbox_get_width_height wh = {
-- .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
-- .display = fkms_connector->display_idx,
-- .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
-- 8, 0, },
-+ (struct vc4_fkms_connector *)data;
-+ struct vc4_dev *vc4 = fkms_connector->vc4_dev;
-+ struct mailbox_get_edid mb = {
-+ .tag1 = { RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY,
-+ 128 + 8, 0 },
-+ .block = block,
-+ .display_number = fkms_connector->display_number,
- };
-- int ret;
-+ int ret = 0;
-+
-+ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
-+
-+ if (!ret)
-+ memcpy(buf, mb.edid, len);
-+
-+ return ret;
-+}
-+
-+static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
-+{
-+ struct vc4_fkms_connector *fkms_connector =
-+ to_vc4_fkms_connector(connector);
-+ struct drm_encoder *encoder = fkms_connector->encoder;
-+ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
-+ int ret = 0;
-+ struct edid *edid;
-+
-+ edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
-+ fkms_connector);
-+
-+ /* FIXME: Can we do CEC?
-+ * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
-+ * if (!edid)
-+ * return -ENODEV;
-+ */
-+
-+ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
-
-- ret = rpi_firmware_property_list(vc4->firmware, &wh, sizeof(wh));
-+ if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
-+ vc4_encoder->rgb_range_selectable =
-+ drm_rgb_quant_range_selectable(edid);
-+ }
-+
-+ drm_connector_update_edid_property(connector, edid);
-+ ret = drm_add_edid_modes(connector, edid);
-+ kfree(edid);
-+
-+ return ret;
-+}
-+
-+/* FIXME: Read LCD mode from the firmware. This is the DSI panel resolution. */
-+static const struct drm_display_mode lcd_mode = {
-+ DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
-+ 25979400 / 1000,
-+ 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0,
-+ 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0,
-+ DRM_MODE_FLAG_INTERLACE)
-+};
-+
-+static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
-+{
-+ //struct vc4_fkms_connector *fkms_connector =
-+ // to_vc4_fkms_connector(connector);
-+ //struct drm_encoder *encoder = fkms_connector->encoder;
-+ //struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
-+ struct drm_display_mode *mode;
-+ //int ret = 0;
-
-- if (ret) {
-- DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n",
-- ret, wh.wh[0], wh.wh[1]);
-- return 0;
-+ mode = drm_mode_duplicate(connector->dev,
-+ &lcd_mode);
-+ if (!mode) {
-+ DRM_ERROR("Failed to create a new display mode\n");
-+ return -ENOMEM;
- }
-
-- mode = drm_cvt_mode(dev, wh.wh[0], wh.wh[1], 60 /* vrefresh */,
-- 0, 0, false);
- drm_mode_probed_add(connector, mode);
-
-+ /* We have one mode */
- return 1;
- }
-
-@@ -798,11 +1038,14 @@ vc4_fkms_connector_best_encoder(struct d
- {
- struct vc4_fkms_connector *fkms_connector =
- to_vc4_fkms_connector(connector);
-+ DRM_DEBUG_KMS("best_connector.\n");
- return fkms_connector->encoder;
- }
-
- static void vc4_fkms_connector_destroy(struct drm_connector *connector)
- {
-+ DRM_DEBUG_KMS("[CONNECTOR:%d] destroy.\n",
-+ connector->base.id);
- drm_connector_unregister(connector);
- drm_connector_cleanup(connector);
- }
-@@ -821,14 +1064,22 @@ static const struct drm_connector_helper
- .best_encoder = vc4_fkms_connector_best_encoder,
- };
-
-+static const struct drm_connector_helper_funcs vc4_fkms_lcd_conn_helper_funcs = {
-+ .get_modes = vc4_fkms_lcd_connector_get_modes,
-+ .best_encoder = vc4_fkms_connector_best_encoder,
-+};
-+
- static struct drm_connector *
- vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
-- u32 display_idx)
-+ u32 display_num)
- {
- struct drm_connector *connector = NULL;
- struct vc4_fkms_connector *fkms_connector;
-+ struct vc4_dev *vc4_dev = to_vc4_dev(dev);
- int ret = 0;
-
-+ DRM_DEBUG_KMS("connector_init, display_num %u\n", display_num);
-+
- fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
- GFP_KERNEL);
- if (!fkms_connector) {
-@@ -838,11 +1089,21 @@ vc4_fkms_connector_init(struct drm_devic
- connector = &fkms_connector->base;
-
- fkms_connector->encoder = encoder;
-- fkms_connector->display_idx = display_idx;
--
-- drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
-- DRM_MODE_CONNECTOR_HDMIA);
-- drm_connector_helper_add(connector, &vc4_fkms_connector_helper_funcs);
-+ fkms_connector->display_number = display_num;
-+ fkms_connector->display_type = vc4_get_display_type(display_num);
-+ fkms_connector->vc4_dev = vc4_dev;
-+
-+ if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) {
-+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
-+ DRM_MODE_CONNECTOR_DSI);
-+ drm_connector_helper_add(connector,
-+ &vc4_fkms_lcd_conn_helper_funcs);
-+ } else {
-+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
-+ DRM_MODE_CONNECTOR_HDMIA);
-+ drm_connector_helper_add(connector,
-+ &vc4_fkms_connector_helper_funcs);
-+ }
-
- connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
- DRM_CONNECTOR_POLL_DISCONNECT);
-@@ -863,6 +1124,7 @@ vc4_fkms_connector_init(struct drm_devic
-
- static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder)
- {
-+ DRM_DEBUG_KMS("Encoder_destroy\n");
- drm_encoder_cleanup(encoder);
- }
-
-@@ -872,10 +1134,12 @@ static const struct drm_encoder_funcs vc
-
- static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
- {
-+ DRM_DEBUG_KMS("Encoder_enable\n");
- }
-
- static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
- {
-+ DRM_DEBUG_KMS("Encoder_disable\n");
- }
-
- static const struct drm_encoder_helper_funcs vc4_fkms_encoder_helper_funcs = {
-@@ -907,6 +1171,7 @@ static int vc4_fkms_create_screen(struct
- crtc = &vc4_crtc->base;
-
- vc4_crtc->display_number = display_ref;
-+ vc4_crtc->display_type = vc4_get_display_type(display_ref);
-
- /* Blank the firmware provided framebuffer */
- rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank));
-@@ -950,13 +1215,14 @@ static int vc4_fkms_create_screen(struct
- return -ENOMEM;
- vc4_crtc->encoder = &vc4_encoder->base;
- vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ;
-+
- drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
-- DRM_MODE_ENCODER_TMDS, NULL);
-+ vc4_crtc->display_type, NULL);
- drm_encoder_helper_add(&vc4_encoder->base,
- &vc4_fkms_encoder_helper_funcs);
-
- vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base,
-- display_idx);
-+ display_ref);
- if (IS_ERR(vc4_crtc->connector)) {
- ret = PTR_ERR(vc4_crtc->connector);
- goto err_destroy_encoder;
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -78,6 +78,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
- RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
- RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
-+ RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY = 0x00030023,
- RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
- RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
- RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
-@@ -150,6 +151,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
-
- RPI_FIRMWARE_SET_PLANE = 0x00048015,
-+ RPI_FIRMWARE_SET_TIMING = 0x00048017,
-
- RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
- RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
+++ /dev/null
-From bf85b92a97a95161d98874571c520fb1395c5aa2 Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2019 15:11:05 -0700
-Subject: [PATCH] clk: bcm2835: Add support for setting leaf clock
- rates while running.
-
-As long as you wait for !BUSY, you can do glitch-free updates of clock
-rate while the clock is running.
-
----
- drivers/clk/bcm/clk-bcm2835.c | 22 +++++++++++++---------
- 1 file changed, 13 insertions(+), 9 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -1097,15 +1097,19 @@ static int bcm2835_clock_set_rate(struct
-
- spin_lock(&cprman->regs_lock);
-
-- /*
-- * Setting up frac support
-- *
-- * In principle it is recommended to stop/start the clock first,
-- * but as we set CLK_SET_RATE_GATE during registration of the
-- * clock this requirement should be take care of by the
-- * clk-framework.
-+ ctl = cprman_read(cprman, data->ctl_reg);
-+
-+ /* If the clock is running, we have to pause clock generation while
-+ * updating the control and div regs. This is glitchless (no clock
-+ * signals generated faster than the rate) but each reg access is two
-+ * OSC cycles so the clock will slow down for a moment.
- */
-- ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC;
-+ if (ctl & CM_ENABLE) {
-+ cprman_write(cprman, data->ctl_reg, ctl & ~CM_ENABLE);
-+ bcm2835_clock_wait_busy(clock);
-+ }
-+
-+ ctl &= ~CM_FRAC;
- ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
- cprman_write(cprman, data->ctl_reg, ctl);
-
-@@ -1475,7 +1479,7 @@ static struct clk_hw *bcm2835_register_c
- init.ops = &bcm2835_vpu_clock_clk_ops;
- } else {
- init.ops = &bcm2835_clock_clk_ops;
-- init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
-+ init.flags |= CLK_SET_PARENT_GATE;
-
- /* If the clock wasn't actually enabled at boot, it's not
- * critical.
--- /dev/null
+From 22dbf1420a552d1952d22b92d8c30f8162b026b5 Mon Sep 17 00:00:00 2001
+Date: Tue, 16 Apr 2019 15:58:54 -0700
+Subject: [PATCH] drm/v3d: Add support for compute shader dispatch.
+
+The compute shader dispatch interface is pretty simple -- just pass in
+the regs that userspace has passed us, with no CLs to run. However,
+with no CL to run it means that we need to do manual cache flushing of
+the L2 after the HW execution completes (for SSBO, atomic, and
+image_load_store writes that are the output of compute shaders).
+
+This doesn't yet expose the L2 cache's ability to have a region of the
+address space not write back to memory (which could be used for
+shared_var storage).
+
+So far, the Mesa side has been tested on V3D v4.2 simpenrose (passing
+the ES31 tests), and on the kernel side on 7278 (failing atomic
+compswap tests in a way that doesn't reproduce on simpenrose).
+
+v2: Fix excessive allocation for the clean_job (reported by Dan
+ Carpenter). Keep refs on jobs until clean_job is finished, to
+ avoid spurious MMU errors if the output BOs are freed by userspace
+ before L2 cleaning is finished.
+
+---
+ drivers/gpu/drm/v3d/v3d_debugfs.c | 22 +++++
+ drivers/gpu/drm/v3d/v3d_drv.c | 10 +-
+ drivers/gpu/drm/v3d/v3d_drv.h | 28 +++++-
+ drivers/gpu/drm/v3d/v3d_fence.c | 2 +
+ drivers/gpu/drm/v3d/v3d_gem.c | 156 +++++++++++++++++++++++++++++-
+ drivers/gpu/drm/v3d/v3d_irq.c | 16 ++-
+ drivers/gpu/drm/v3d/v3d_regs.h | 73 ++++++++++++++
+ drivers/gpu/drm/v3d/v3d_sched.c | 121 +++++++++++++++++++++--
+ drivers/gpu/drm/v3d/v3d_trace.h | 94 ++++++++++++++++++
+ include/uapi/drm/v3d_drm.h | 28 ++++++
+ 10 files changed, 531 insertions(+), 19 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
++++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
+@@ -57,6 +57,17 @@ static const struct v3d_reg_def v3d_core
+ REGDEF(V3D_GMP_VIO_ADDR),
+ };
+
++static const struct v3d_reg_def v3d_csd_reg_defs[] = {
++ REGDEF(V3D_CSD_STATUS),
++ REGDEF(V3D_CSD_CURRENT_CFG0),
++ REGDEF(V3D_CSD_CURRENT_CFG1),
++ REGDEF(V3D_CSD_CURRENT_CFG2),
++ REGDEF(V3D_CSD_CURRENT_CFG3),
++ REGDEF(V3D_CSD_CURRENT_CFG4),
++ REGDEF(V3D_CSD_CURRENT_CFG5),
++ REGDEF(V3D_CSD_CURRENT_CFG6),
++};
++
+ static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
+ {
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+@@ -88,6 +99,17 @@ static int v3d_v3d_debugfs_regs(struct s
+ V3D_CORE_READ(core,
+ v3d_core_reg_defs[i].reg));
+ }
++
++ if (v3d_has_csd(v3d)) {
++ for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) {
++ seq_printf(m, "core %d %s (0x%04x): 0x%08x\n",
++ core,
++ v3d_csd_reg_defs[i].name,
++ v3d_csd_reg_defs[i].reg,
++ V3D_CORE_READ(core,
++ v3d_csd_reg_defs[i].reg));
++ }
++ }
+ }
+
+ return 0;
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -7,9 +7,9 @@
+ * This driver supports the Broadcom V3D 3.3 and 4.1 OpenGL ES GPUs.
+ * For V3D 2.x support, see the VC4 driver.
+ *
+- * Currently only single-core rendering using the binner and renderer,
+- * along with TFU (texture formatting unit) rendering is supported.
+- * V3D 4.x's CSD (compute shader dispatch) is not yet supported.
++ * The V3D GPU includes a tiled render (composed of a bin and render
++ * pipelines), the TFU (texture formatting unit), and the CSD (compute
++ * shader dispatch).
+ */
+
+ #include <linux/clk.h>
+@@ -114,6 +114,9 @@ static int v3d_get_param_ioctl(struct dr
+ case DRM_V3D_PARAM_SUPPORTS_TFU:
+ args->value = 1;
+ return 0;
++ case DRM_V3D_PARAM_SUPPORTS_CSD:
++ args->value = v3d_has_csd(v3d);
++ return 0;
+ default:
+ DRM_DEBUG("Unknown parameter %d\n", args->param);
+ return -EINVAL;
+@@ -183,6 +186,7 @@ static const struct drm_ioctl_desc v3d_d
+ DRM_IOCTL_DEF_DRV(V3D_GET_PARAM, v3d_get_param_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(V3D_GET_BO_OFFSET, v3d_get_bo_offset_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(V3D_SUBMIT_TFU, v3d_submit_tfu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
++ DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CSD, v3d_submit_csd_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
+ };
+
+ static const struct vm_operations_struct v3d_vm_ops = {
+--- a/drivers/gpu/drm/v3d/v3d_drv.h
++++ b/drivers/gpu/drm/v3d/v3d_drv.h
+@@ -16,9 +16,11 @@ enum v3d_queue {
+ V3D_BIN,
+ V3D_RENDER,
+ V3D_TFU,
++ V3D_CSD,
++ V3D_CACHE_CLEAN,
+ };
+
+-#define V3D_MAX_QUEUES (V3D_TFU + 1)
++#define V3D_MAX_QUEUES (V3D_CACHE_CLEAN + 1)
+
+ struct v3d_queue_state {
+ struct drm_gpu_scheduler sched;
+@@ -70,6 +72,7 @@ struct v3d_dev {
+ struct v3d_bin_job *bin_job;
+ struct v3d_render_job *render_job;
+ struct v3d_tfu_job *tfu_job;
++ struct v3d_csd_job *csd_job;
+
+ struct v3d_queue_state queue[V3D_MAX_QUEUES];
+
+@@ -92,6 +95,12 @@ struct v3d_dev {
+ */
+ struct mutex sched_lock;
+
++ /* Lock taken during a cache clean and when initiating an L2
++ * flush, to keep L2 flushes from interfering with the
++ * synchronous L2 cleans.
++ */
++ struct mutex cache_clean_lock;
++
+ struct {
+ u32 num_allocated;
+ u32 pages_allocated;
+@@ -104,6 +113,12 @@ to_v3d_dev(struct drm_device *dev)
+ return (struct v3d_dev *)dev->dev_private;
+ }
+
++static inline bool
++v3d_has_csd(struct v3d_dev *v3d)
++{
++ return v3d->ver >= 41;
++}
++
+ /* The per-fd struct, which tracks the MMU mappings. */
+ struct v3d_file_priv {
+ struct v3d_dev *v3d;
+@@ -237,6 +252,14 @@ struct v3d_tfu_job {
+ struct drm_v3d_submit_tfu args;
+ };
+
++struct v3d_csd_job {
++ struct v3d_job base;
++
++ u32 timedout_batches;
++
++ struct drm_v3d_submit_csd args;
++};
++
+ /**
+ * _wait_for - magic (register) wait macro
+ *
+@@ -302,11 +325,14 @@ int v3d_submit_cl_ioctl(struct drm_devic
+ struct drm_file *file_priv);
+ int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
++int v3d_submit_csd_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv);
+ int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+ void v3d_job_put(struct v3d_job *job);
+ void v3d_reset(struct v3d_dev *v3d);
+ void v3d_invalidate_caches(struct v3d_dev *v3d);
++void v3d_clean_caches(struct v3d_dev *v3d);
+
+ /* v3d_irq.c */
+ int v3d_irq_init(struct v3d_dev *v3d);
+--- a/drivers/gpu/drm/v3d/v3d_fence.c
++++ b/drivers/gpu/drm/v3d/v3d_fence.c
+@@ -36,6 +36,8 @@ static const char *v3d_fence_get_timelin
+ return "v3d-render";
+ case V3D_TFU:
+ return "v3d-tfu";
++ case V3D_CSD:
++ return "v3d-csd";
+ default:
+ return NULL;
+ }
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -162,10 +162,52 @@ v3d_flush_l2t(struct v3d_dev *v3d, int c
+ /* While there is a busy bit (V3D_L2TCACTL_L2TFLS), we don't
+ * need to wait for completion before dispatching the job --
+ * L2T accesses will be stalled until the flush has completed.
++ * However, we do need to make sure we don't try to trigger a
++ * new flush while the L2_CLEAN queue is trying to
++ * synchronously clean after a job.
+ */
++ mutex_lock(&v3d->cache_clean_lock);
+ V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL,
+ V3D_L2TCACTL_L2TFLS |
+ V3D_SET_FIELD(V3D_L2TCACTL_FLM_FLUSH, V3D_L2TCACTL_FLM));
++ mutex_unlock(&v3d->cache_clean_lock);
++}
++
++/* Cleans texture L1 and L2 cachelines (writing back dirty data).
++ *
++ * For cleaning, which happens from the CACHE_CLEAN queue after CSD has
++ * executed, we need to make sure that the clean is done before
++ * signaling job completion. So, we synchronously wait before
++ * returning, and we make sure that L2 invalidates don't happen in the
++ * meantime to confuse our are-we-done checks.
++ */
++void
++v3d_clean_caches(struct v3d_dev *v3d)
++{
++ struct drm_device *dev = &v3d->drm;
++ int core = 0;
++
++ trace_v3d_cache_clean_begin(dev);
++
++ V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, V3D_L2TCACTL_TMUWCF);
++ if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
++ V3D_L2TCACTL_L2TFLS), 100)) {
++ DRM_ERROR("Timeout waiting for L1T write combiner flush\n");
++ }
++
++ mutex_lock(&v3d->cache_clean_lock);
++ V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL,
++ V3D_L2TCACTL_L2TFLS |
++ V3D_SET_FIELD(V3D_L2TCACTL_FLM_CLEAN, V3D_L2TCACTL_FLM));
++
++ if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
++ V3D_L2TCACTL_L2TFLS), 100)) {
++ DRM_ERROR("Timeout waiting for L2T clean\n");
++ }
++
++ mutex_unlock(&v3d->cache_clean_lock);
++
++ trace_v3d_cache_clean_end(dev);
+ }
+
+ /* Invalidates the slice caches. These are read-only caches. */
+@@ -584,7 +626,8 @@ static void
+ v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv,
+ struct v3d_job *job,
+ struct ww_acquire_ctx *acquire_ctx,
+- u32 out_sync)
++ u32 out_sync,
++ struct dma_fence *done_fence)
+ {
+ struct drm_syncobj *sync_out;
+
+@@ -594,7 +637,7 @@ v3d_attach_fences_and_unlock_reservation
+ /* Update the return sync object for the job */
+ sync_out = drm_syncobj_find(file_priv, out_sync);
+ if (sync_out) {
+- drm_syncobj_replace_fence(sync_out, job->done_fence);
++ drm_syncobj_replace_fence(sync_out, done_fence);
+ drm_syncobj_put(sync_out);
+ }
+ }
+@@ -691,8 +734,10 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ mutex_unlock(&v3d->sched_lock);
+
+ v3d_attach_fences_and_unlock_reservation(file_priv,
+- &render->base, &acquire_ctx,
+- args->out_sync);
++ &render->base,
++ &acquire_ctx,
++ args->out_sync,
++ render->base.done_fence);
+
+ if (bin)
+ v3d_job_put(&bin->base);
+@@ -785,7 +830,8 @@ v3d_submit_tfu_ioctl(struct drm_device *
+
+ v3d_attach_fences_and_unlock_reservation(file_priv,
+ &job->base, &acquire_ctx,
+- args->out_sync);
++ args->out_sync,
++ job->base.done_fence);
+
+ v3d_job_put(&job->base);
+
+@@ -801,6 +847,105 @@ fail:
+ return ret;
+ }
+
++/**
++ * v3d_submit_csd_ioctl() - Submits a CSD (texture formatting) job to the V3D.
++ * @dev: DRM device
++ * @data: ioctl argument
++ * @file_priv: DRM file for this fd
++ *
++ * Userspace provides the register setup for the CSD, which we don't
++ * need to validate since the CSD is behind the MMU.
++ */
++int
++v3d_submit_csd_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ struct v3d_dev *v3d = to_v3d_dev(dev);
++ struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
++ struct drm_v3d_submit_csd *args = data;
++ struct v3d_csd_job *job;
++ struct v3d_job *clean_job;
++ struct ww_acquire_ctx acquire_ctx;
++ int ret;
++
++ trace_v3d_submit_csd_ioctl(&v3d->drm, args->cfg[5], args->cfg[6]);
++
++ if (!v3d_has_csd(v3d)) {
++ DRM_DEBUG("Attempting CSD submit on non-CSD hardware\n");
++ return -EINVAL;
++ }
++
++ job = kcalloc(1, sizeof(*job), GFP_KERNEL);
++ if (!job)
++ return -ENOMEM;
++
++ ret = v3d_job_init(v3d, file_priv, &job->base,
++ v3d_job_free, args->in_sync);
++ if (ret) {
++ kfree(job);
++ return ret;
++ }
++
++ clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL);
++ if (!clean_job) {
++ v3d_job_put(&job->base);
++ kfree(job);
++ return -ENOMEM;
++ }
++
++ ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0);
++ if (ret) {
++ v3d_job_put(&job->base);
++ kfree(clean_job);
++ return ret;
++ }
++
++ job->args = *args;
++
++ ret = v3d_lookup_bos(dev, file_priv, clean_job,
++ args->bo_handles, args->bo_handle_count);
++ if (ret)
++ goto fail;
++
++ ret = v3d_lock_bo_reservations(clean_job, &acquire_ctx);
++ if (ret)
++ goto fail;
++
++ mutex_lock(&v3d->sched_lock);
++ ret = v3d_push_job(v3d_priv, &job->base, V3D_CSD);
++ if (ret)
++ goto fail_unreserve;
++
++ ret = v3d_add_dep(clean_job, dma_fence_get(job->base.done_fence));
++ if (ret)
++ goto fail_unreserve;
++ ret = v3d_push_job(v3d_priv, clean_job, V3D_CACHE_CLEAN);
++ if (ret)
++ goto fail_unreserve;
++ mutex_unlock(&v3d->sched_lock);
++
++ v3d_attach_fences_and_unlock_reservation(file_priv,
++ clean_job,
++ &acquire_ctx,
++ args->out_sync,
++ clean_job->done_fence);
++
++ v3d_job_put(&job->base);
++ v3d_job_put(clean_job);
++
++ return 0;
++
++fail_unreserve:
++ mutex_unlock(&v3d->sched_lock);
++ v3d_unlock_bo_reservations(clean_job->bo, clean_job->bo_count,
++ &acquire_ctx);
++fail:
++ v3d_job_put(&job->base);
++ v3d_job_put(clean_job);
++
++ return ret;
++}
++
+ int
+ v3d_gem_init(struct drm_device *dev)
+ {
+@@ -816,6 +961,7 @@ v3d_gem_init(struct drm_device *dev)
+ mutex_init(&v3d->bo_lock);
+ mutex_init(&v3d->reset_lock);
+ mutex_init(&v3d->sched_lock);
++ mutex_init(&v3d->cache_clean_lock);
+
+ /* Note: We don't allocate address 0. Various bits of HW
+ * treat 0 as special, such as the occlusion query counters
+--- a/drivers/gpu/drm/v3d/v3d_irq.c
++++ b/drivers/gpu/drm/v3d/v3d_irq.c
+@@ -4,9 +4,9 @@
+ /**
+ * DOC: Interrupt management for the V3D engine
+ *
+- * When we take a bin, render, or TFU done interrupt, we need to
+- * signal the fence for that job so that the scheduler can queue up
+- * the next one and unblock any waiters.
++ * When we take a bin, render, TFU done, or CSD done interrupt, we
++ * need to signal the fence for that job so that the scheduler can
++ * queue up the next one and unblock any waiters.
+ *
+ * When we take the binner out of memory interrupt, we need to
+ * allocate some new memory and pass it to the binner so that the
+@@ -20,6 +20,7 @@
+ #define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \
+ V3D_INT_FLDONE | \
+ V3D_INT_FRDONE | \
++ V3D_INT_CSDDONE | \
+ V3D_INT_GMPV))
+
+ #define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \
+@@ -108,6 +109,15 @@ v3d_irq(int irq, void *arg)
+ dma_fence_signal(&fence->base);
+ status = IRQ_HANDLED;
+ }
++
++ if (intsts & V3D_INT_CSDDONE) {
++ struct v3d_fence *fence =
++ to_v3d_fence(v3d->csd_job->base.irq_fence);
++
++ trace_v3d_csd_irq(&v3d->drm, fence->seqno);
++ dma_fence_signal(&fence->base);
++ status = IRQ_HANDLED;
++ }
+
+ /* We shouldn't be triggering these if we have GMP in
+ * always-allowed mode.
+--- a/drivers/gpu/drm/v3d/v3d_regs.h
++++ b/drivers/gpu/drm/v3d/v3d_regs.h
+@@ -238,8 +238,11 @@
+ #define V3D_CTL_L2TCACTL 0x00030
+ # define V3D_L2TCACTL_TMUWCF BIT(8)
+ # define V3D_L2TCACTL_L2T_NO_WM BIT(4)
++/* Invalidates cache lines. */
+ # define V3D_L2TCACTL_FLM_FLUSH 0
++/* Removes cachelines without writing dirty lines back. */
+ # define V3D_L2TCACTL_FLM_CLEAR 1
++/* Writes out dirty cachelines and marks them clean, but doesn't invalidate. */
+ # define V3D_L2TCACTL_FLM_CLEAN 2
+ # define V3D_L2TCACTL_FLM_MASK V3D_MASK(2, 1)
+ # define V3D_L2TCACTL_FLM_SHIFT 1
+@@ -255,6 +258,8 @@
+ #define V3D_CTL_INT_MSK_CLR 0x00064
+ # define V3D_INT_QPU_MASK V3D_MASK(27, 16)
+ # define V3D_INT_QPU_SHIFT 16
++# define V3D_INT_CSDDONE BIT(7)
++# define V3D_INT_PCTR BIT(6)
+ # define V3D_INT_GMPV BIT(5)
+ # define V3D_INT_TRFB BIT(4)
+ # define V3D_INT_SPILLUSE BIT(3)
+@@ -374,4 +379,72 @@
+ #define V3D_GMP_PRESERVE_LOAD 0x00818
+ #define V3D_GMP_VALID_LINES 0x00820
+
++#define V3D_CSD_STATUS 0x00900
++# define V3D_CSD_STATUS_NUM_COMPLETED_MASK V3D_MASK(11, 4)
++# define V3D_CSD_STATUS_NUM_COMPLETED_SHIFT 4
++# define V3D_CSD_STATUS_NUM_ACTIVE_MASK V3D_MASK(3, 2)
++# define V3D_CSD_STATUS_NUM_ACTIVE_SHIFT 2
++# define V3D_CSD_STATUS_HAVE_CURRENT_DISPATCH BIT(1)
++# define V3D_CSD_STATUS_HAVE_QUEUED_DISPATCH BIT(0)
++
++#define V3D_CSD_QUEUED_CFG0 0x00904
++# define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_MASK V3D_MASK(31, 16)
++# define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_SHIFT 16
++# define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_MASK V3D_MASK(15, 0)
++# define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_SHIFT 0
++
++#define V3D_CSD_QUEUED_CFG1 0x00908
++# define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_MASK V3D_MASK(31, 16)
++# define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_SHIFT 16
++# define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_MASK V3D_MASK(15, 0)
++# define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_SHIFT 0
++
++#define V3D_CSD_QUEUED_CFG2 0x0090c
++# define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_MASK V3D_MASK(31, 16)
++# define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_SHIFT 16
++# define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_MASK V3D_MASK(15, 0)
++# define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_SHIFT 0
++
++#define V3D_CSD_QUEUED_CFG3 0x00910
++# define V3D_CSD_QUEUED_CFG3_OVERLAP_WITH_PREV BIT(26)
++# define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_MASK V3D_MASK(25, 20)
++# define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_SHIFT 20
++# define V3D_CSD_QUEUED_CFG3_BATCHES_PER_SG_M1_MASK V3D_MASK(19, 12)
++# define V3D_CSD_QUEUED_CFG3_BATCHES_PER_SG_M1_SHIFT 12
++# define V3D_CSD_QUEUED_CFG3_WGS_PER_SG_MASK V3D_MASK(11, 8)
++# define V3D_CSD_QUEUED_CFG3_WGS_PER_SG_SHIFT 8
++# define V3D_CSD_QUEUED_CFG3_WG_SIZE_MASK V3D_MASK(7, 0)
++# define V3D_CSD_QUEUED_CFG3_WG_SIZE_SHIFT 0
++
++/* Number of batches, minus 1 */
++#define V3D_CSD_QUEUED_CFG4 0x00914
++
++/* Shader address, pnan, singleseg, threading, like a shader record. */
++#define V3D_CSD_QUEUED_CFG5 0x00918
++
++/* Uniforms address (4 byte aligned) */
++#define V3D_CSD_QUEUED_CFG6 0x0091c
++
++#define V3D_CSD_CURRENT_CFG0 0x00920
++#define V3D_CSD_CURRENT_CFG1 0x00924
++#define V3D_CSD_CURRENT_CFG2 0x00928
++#define V3D_CSD_CURRENT_CFG3 0x0092c
++#define V3D_CSD_CURRENT_CFG4 0x00930
++#define V3D_CSD_CURRENT_CFG5 0x00934
++#define V3D_CSD_CURRENT_CFG6 0x00938
++
++#define V3D_CSD_CURRENT_ID0 0x0093c
++# define V3D_CSD_CURRENT_ID0_WG_X_MASK V3D_MASK(31, 16)
++# define V3D_CSD_CURRENT_ID0_WG_X_SHIFT 16
++# define V3D_CSD_CURRENT_ID0_WG_IN_SG_MASK V3D_MASK(11, 8)
++# define V3D_CSD_CURRENT_ID0_WG_IN_SG_SHIFT 8
++# define V3D_CSD_CURRENT_ID0_L_IDX_MASK V3D_MASK(7, 0)
++# define V3D_CSD_CURRENT_ID0_L_IDX_SHIFT 0
++
++#define V3D_CSD_CURRENT_ID1 0x00940
++# define V3D_CSD_CURRENT_ID0_WG_Z_MASK V3D_MASK(31, 16)
++# define V3D_CSD_CURRENT_ID0_WG_Z_SHIFT 16
++# define V3D_CSD_CURRENT_ID0_WG_Y_MASK V3D_MASK(15, 0)
++# define V3D_CSD_CURRENT_ID0_WG_Y_SHIFT 0
++
+ #endif /* V3D_REGS_H */
+--- a/drivers/gpu/drm/v3d/v3d_sched.c
++++ b/drivers/gpu/drm/v3d/v3d_sched.c
+@@ -48,6 +48,12 @@ to_tfu_job(struct drm_sched_job *sched_j
+ return container_of(sched_job, struct v3d_tfu_job, base.base);
+ }
+
++static struct v3d_csd_job *
++to_csd_job(struct drm_sched_job *sched_job)
++{
++ return container_of(sched_job, struct v3d_csd_job, base.base);
++}
++
+ static void
+ v3d_job_free(struct drm_sched_job *sched_job)
+ {
+@@ -205,6 +211,48 @@ v3d_tfu_job_run(struct drm_sched_job *sc
+ return fence;
+ }
+
++static struct dma_fence *
++v3d_csd_job_run(struct drm_sched_job *sched_job)
++{
++ struct v3d_csd_job *job = to_csd_job(sched_job);
++ struct v3d_dev *v3d = job->base.v3d;
++ struct drm_device *dev = &v3d->drm;
++ struct dma_fence *fence;
++ int i;
++
++ v3d->csd_job = job;
++
++ v3d_invalidate_caches(v3d);
++
++ fence = v3d_fence_create(v3d, V3D_CSD);
++ if (IS_ERR(fence))
++ return NULL;
++
++ if (job->base.irq_fence)
++ dma_fence_put(job->base.irq_fence);
++ job->base.irq_fence = dma_fence_get(fence);
++
++ trace_v3d_submit_csd(dev, to_v3d_fence(fence)->seqno);
++
++ for (i = 1; i <= 6; i++)
++ V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0 + 4 * i, job->args.cfg[i]);
++ /* CFG0 write kicks off the job. */
++ V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0, job->args.cfg[0]);
++
++ return fence;
++}
++
++static struct dma_fence *
++v3d_cache_clean_job_run(struct drm_sched_job *sched_job)
++{
++ struct v3d_job *job = to_v3d_job(sched_job);
++ struct v3d_dev *v3d = job->v3d;
++
++ v3d_clean_caches(v3d);
++
++ return NULL;
++}
++
+ static void
+ v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job)
+ {
+@@ -277,13 +325,31 @@ v3d_render_job_timedout(struct drm_sched
+ }
+
+ static void
+-v3d_tfu_job_timedout(struct drm_sched_job *sched_job)
++v3d_generic_job_timedout(struct drm_sched_job *sched_job)
+ {
+ struct v3d_job *job = to_v3d_job(sched_job);
+
+ v3d_gpu_reset_for_timeout(job->v3d, sched_job);
+ }
+
++static void
++v3d_csd_job_timedout(struct drm_sched_job *sched_job)
++{
++ struct v3d_csd_job *job = to_csd_job(sched_job);
++ struct v3d_dev *v3d = job->base.v3d;
++ u32 batches = V3D_CORE_READ(0, V3D_CSD_CURRENT_CFG4);
++
++ /* If we've made progress, skip reset and let the timer get
++ * rearmed.
++ */
++ if (job->timedout_batches != batches) {
++ job->timedout_batches = batches;
++ return;
++ }
++
++ v3d_gpu_reset_for_timeout(v3d, sched_job);
++}
++
+ static const struct drm_sched_backend_ops v3d_bin_sched_ops = {
+ .dependency = v3d_job_dependency,
+ .run_job = v3d_bin_job_run,
+@@ -301,10 +367,24 @@ static const struct drm_sched_backend_op
+ static const struct drm_sched_backend_ops v3d_tfu_sched_ops = {
+ .dependency = v3d_job_dependency,
+ .run_job = v3d_tfu_job_run,
+- .timedout_job = v3d_tfu_job_timedout,
++ .timedout_job = v3d_generic_job_timedout,
+ .free_job = v3d_job_free,
+ };
+
++static const struct drm_sched_backend_ops v3d_csd_sched_ops = {
++ .dependency = v3d_job_dependency,
++ .run_job = v3d_csd_job_run,
++ .timedout_job = v3d_csd_job_timedout,
++ .free_job = v3d_job_free
++};
++
++static const struct drm_sched_backend_ops v3d_cache_clean_sched_ops = {
++ .dependency = v3d_job_dependency,
++ .run_job = v3d_cache_clean_job_run,
++ .timedout_job = v3d_generic_job_timedout,
++ .free_job = v3d_job_free
++};
++
+ int
+ v3d_sched_init(struct v3d_dev *v3d)
+ {
+@@ -331,7 +411,7 @@ v3d_sched_init(struct v3d_dev *v3d)
+ if (ret) {
+ dev_err(v3d->dev, "Failed to create render scheduler: %d.",
+ ret);
+- drm_sched_fini(&v3d->queue[V3D_BIN].sched);
++ v3d_sched_fini(v3d);
+ return ret;
+ }
+
+@@ -343,11 +423,36 @@ v3d_sched_init(struct v3d_dev *v3d)
+ if (ret) {
+ dev_err(v3d->dev, "Failed to create TFU scheduler: %d.",
+ ret);
+- drm_sched_fini(&v3d->queue[V3D_RENDER].sched);
+- drm_sched_fini(&v3d->queue[V3D_BIN].sched);
++ v3d_sched_fini(v3d);
+ return ret;
+ }
+
++ if (v3d_has_csd(v3d)) {
++ ret = drm_sched_init(&v3d->queue[V3D_CSD].sched,
++ &v3d_csd_sched_ops,
++ hw_jobs_limit, job_hang_limit,
++ msecs_to_jiffies(hang_limit_ms),
++ "v3d_csd");
++ if (ret) {
++ dev_err(v3d->dev, "Failed to create CSD scheduler: %d.",
++ ret);
++ v3d_sched_fini(v3d);
++ return ret;
++ }
++
++ ret = drm_sched_init(&v3d->queue[V3D_CACHE_CLEAN].sched,
++ &v3d_cache_clean_sched_ops,
++ hw_jobs_limit, job_hang_limit,
++ msecs_to_jiffies(hang_limit_ms),
++ "v3d_cache_clean");
++ if (ret) {
++ dev_err(v3d->dev, "Failed to create CACHE_CLEAN scheduler: %d.",
++ ret);
++ v3d_sched_fini(v3d);
++ return ret;
++ }
++ }
++
+ return 0;
+ }
+
+@@ -356,6 +461,8 @@ v3d_sched_fini(struct v3d_dev *v3d)
+ {
+ enum v3d_queue q;
+
+- for (q = 0; q < V3D_MAX_QUEUES; q++)
+- drm_sched_fini(&v3d->queue[q].sched);
++ for (q = 0; q < V3D_MAX_QUEUES; q++) {
++ if (v3d->queue[q].sched.ops)
++ drm_sched_fini(&v3d->queue[q].sched);
++ }
+ }
+--- a/drivers/gpu/drm/v3d/v3d_trace.h
++++ b/drivers/gpu/drm/v3d/v3d_trace.h
+@@ -124,6 +124,26 @@ TRACE_EVENT(v3d_tfu_irq,
+ __entry->seqno)
+ );
+
++TRACE_EVENT(v3d_csd_irq,
++ TP_PROTO(struct drm_device *dev,
++ uint64_t seqno),
++ TP_ARGS(dev, seqno),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ __field(u64, seqno)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ __entry->seqno = seqno;
++ ),
++
++ TP_printk("dev=%u, seqno=%llu",
++ __entry->dev,
++ __entry->seqno)
++);
++
+ TRACE_EVENT(v3d_submit_tfu_ioctl,
+ TP_PROTO(struct drm_device *dev, u32 iia),
+ TP_ARGS(dev, iia),
+@@ -163,6 +183,80 @@ TRACE_EVENT(v3d_submit_tfu,
+ __entry->seqno)
+ );
+
++TRACE_EVENT(v3d_submit_csd_ioctl,
++ TP_PROTO(struct drm_device *dev, u32 cfg5, u32 cfg6),
++ TP_ARGS(dev, cfg5, cfg6),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ __field(u32, cfg5)
++ __field(u32, cfg6)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ __entry->cfg5 = cfg5;
++ __entry->cfg6 = cfg6;
++ ),
++
++ TP_printk("dev=%u, CFG5 0x%08x, CFG6 0x%08x",
++ __entry->dev,
++ __entry->cfg5,
++ __entry->cfg6)
++);
++
++TRACE_EVENT(v3d_submit_csd,
++ TP_PROTO(struct drm_device *dev,
++ uint64_t seqno),
++ TP_ARGS(dev, seqno),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ __field(u64, seqno)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ __entry->seqno = seqno;
++ ),
++
++ TP_printk("dev=%u, seqno=%llu",
++ __entry->dev,
++ __entry->seqno)
++);
++
++TRACE_EVENT(v3d_cache_clean_begin,
++ TP_PROTO(struct drm_device *dev),
++ TP_ARGS(dev),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ ),
++
++ TP_printk("dev=%u",
++ __entry->dev)
++);
++
++TRACE_EVENT(v3d_cache_clean_end,
++ TP_PROTO(struct drm_device *dev),
++ TP_ARGS(dev),
++
++ TP_STRUCT__entry(
++ __field(u32, dev)
++ ),
++
++ TP_fast_assign(
++ __entry->dev = dev->primary->index;
++ ),
++
++ TP_printk("dev=%u",
++ __entry->dev)
++);
++
+ TRACE_EVENT(v3d_reset_begin,
+ TP_PROTO(struct drm_device *dev),
+ TP_ARGS(dev),
+--- a/include/uapi/drm/v3d_drm.h
++++ b/include/uapi/drm/v3d_drm.h
+@@ -37,6 +37,7 @@ extern "C" {
+ #define DRM_V3D_GET_PARAM 0x04
+ #define DRM_V3D_GET_BO_OFFSET 0x05
+ #define DRM_V3D_SUBMIT_TFU 0x06
++#define DRM_V3D_SUBMIT_CSD 0x07
+
+ #define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl)
+ #define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo)
+@@ -45,6 +46,7 @@ extern "C" {
+ #define DRM_IOCTL_V3D_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_PARAM, struct drm_v3d_get_param)
+ #define DRM_IOCTL_V3D_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_BO_OFFSET, struct drm_v3d_get_bo_offset)
+ #define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu)
++#define DRM_IOCTL_V3D_SUBMIT_CSD DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CSD, struct drm_v3d_submit_csd)
+
+ /**
+ * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D
+@@ -172,6 +174,7 @@ enum drm_v3d_param {
+ DRM_V3D_PARAM_V3D_CORE0_IDENT1,
+ DRM_V3D_PARAM_V3D_CORE0_IDENT2,
+ DRM_V3D_PARAM_SUPPORTS_TFU,
++ DRM_V3D_PARAM_SUPPORTS_CSD,
+ };
+
+ struct drm_v3d_get_param {
+@@ -212,6 +215,31 @@ struct drm_v3d_submit_tfu {
+ __u32 out_sync;
+ };
+
++/* Submits a compute shader for dispatch. This job will block on any
++ * previous compute shaders submitted on this fd, and any other
++ * synchronization must be performed with in_sync/out_sync.
++ */
++struct drm_v3d_submit_csd {
++ __u32 cfg[7];
++ __u32 coef[4];
++
++ /* Pointer to a u32 array of the BOs that are referenced by the job.
++ */
++ __u64 bo_handles;
++
++ /* Number of BO handles passed in (size is that times 4). */
++ __u32 bo_handle_count;
++
++ /* sync object to block on before running the CSD job. Each
++ * CSD job will execute in the order submitted to its FD.
++ * Synchronization against rendering/TFU jobs or CSD from
++ * other fds requires using sync objects.
++ */
++ __u32 in_sync;
++ /* Sync object to signal when the CSD job is done. */
++ __u32 out_sync;
++};
++
+ #if defined(__cplusplus)
+ }
+ #endif
+++ /dev/null
-From d46285327ba5961c992643d468b2862c70f4c7e5 Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2019 15:24:04 -0700
-Subject: [PATCH] clk: bcm2835: Allow reparenting leaf clocks while
- they're running.
-
-This falls under the same "we can reprogram glitch-free as long as we
-pause generation" rule as updating the div/frac fields. This can be
-used for runtime reclocking of V3D to manage power leakage.
-
----
- drivers/clk/bcm/clk-bcm2835.c | 19 ++++++++++++++++---
- 1 file changed, 16 insertions(+), 3 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -1086,8 +1086,10 @@ static int bcm2835_clock_on(struct clk_h
- return 0;
- }
-
--static int bcm2835_clock_set_rate(struct clk_hw *hw,
-- unsigned long rate, unsigned long parent_rate)
-+static int bcm2835_clock_set_rate_and_parent(struct clk_hw *hw,
-+ unsigned long rate,
-+ unsigned long parent_rate,
-+ u8 parent)
- {
- struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
- struct bcm2835_cprman *cprman = clock->cprman;
-@@ -1109,6 +1111,11 @@ static int bcm2835_clock_set_rate(struct
- bcm2835_clock_wait_busy(clock);
- }
-
-+ if (parent != 0xff) {
-+ ctl &= ~(CM_SRC_MASK << CM_SRC_SHIFT);
-+ ctl |= parent << CM_SRC_SHIFT;
-+ }
-+
- ctl &= ~CM_FRAC;
- ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
- cprman_write(cprman, data->ctl_reg, ctl);
-@@ -1120,6 +1127,12 @@ static int bcm2835_clock_set_rate(struct
- return 0;
- }
-
-+static int bcm2835_clock_set_rate(struct clk_hw *hw,
-+ unsigned long rate, unsigned long parent_rate)
-+{
-+ return bcm2835_clock_set_rate_and_parent(hw, rate, parent_rate, 0xff);
-+}
-+
- static bool
- bcm2835_clk_is_pllc(struct clk_hw *hw)
- {
-@@ -1303,6 +1316,7 @@ static const struct clk_ops bcm2835_cloc
- .unprepare = bcm2835_clock_off,
- .recalc_rate = bcm2835_clock_get_rate,
- .set_rate = bcm2835_clock_set_rate,
-+ .set_rate_and_parent = bcm2835_clock_set_rate_and_parent,
- .determine_rate = bcm2835_clock_determine_rate,
- .set_parent = bcm2835_clock_set_parent,
- .get_parent = bcm2835_clock_get_parent,
-@@ -1479,7 +1493,6 @@ static struct clk_hw *bcm2835_register_c
- init.ops = &bcm2835_vpu_clock_clk_ops;
- } else {
- init.ops = &bcm2835_clock_clk_ops;
-- init.flags |= CLK_SET_PARENT_GATE;
-
- /* If the clock wasn't actually enabled at boot, it's not
- * critical.
--- /dev/null
+From 3e6b687bae81bdf5a430ffaa04aa04ee195a866c Mon Sep 17 00:00:00 2001
+Date: Thu, 2 May 2019 13:22:53 -0700
+Subject: [PATCH] drm/v3d: Clock V3D down when not in use.
+
+My various attempts at re-enabling runtime PM have failed, so just
+crank the clock down when V3D is idle to reduce power consumption.
+
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 18 +++++++++++++
+ drivers/gpu/drm/v3d/v3d_drv.h | 6 +++++
+ drivers/gpu/drm/v3d/v3d_gem.c | 49 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 73 insertions(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -297,6 +297,21 @@ static int v3d_platform_drm_probe(struct
+ }
+ }
+
++ v3d->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(v3d->clk)) {
++ if (ret != -EPROBE_DEFER)
++ dev_err(dev, "Failed to get clock\n");
++ goto dev_free;
++ }
++ v3d->clk_up_rate = clk_get_rate(v3d->clk);
++ /* For downclocking, drop it to the minimum frequency we can get from
++ * the CPRMAN clock generator dividing off our parent. The divider is
++ * 4 bits, but ask for just higher than that so that rounding doesn't
++ * make cprman reject our rate.
++ */
++ v3d->clk_down_rate =
++ (clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000;
++
+ if (v3d->ver < 41) {
+ ret = map_regs(v3d, &v3d->gca_regs, "gca");
+ if (ret)
+@@ -331,6 +346,9 @@ static int v3d_platform_drm_probe(struct
+ if (ret)
+ goto irq_disable;
+
++ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
++ WARN_ON_ONCE(ret != 0);
++
+ return 0;
+
+ irq_disable:
+--- a/drivers/gpu/drm/v3d/v3d_drv.h
++++ b/drivers/gpu/drm/v3d/v3d_drv.h
+@@ -45,6 +45,12 @@ struct v3d_dev {
+ void __iomem *bridge_regs;
+ void __iomem *gca_regs;
+ struct clk *clk;
++ struct delayed_work clk_down_work;
++ unsigned long clk_up_rate, clk_down_rate;
++ struct mutex clk_lock;
++ u32 clk_refcount;
++ bool clk_up;
++
+ struct reset_control *reset;
+
+ /* Virtual and DMA addresses of the single shared page table. */
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -3,6 +3,7 @@
+
+ #include <drm/drmP.h>
+ #include <drm/drm_syncobj.h>
++#include <linux/clk.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_runtime.h>
+@@ -17,6 +18,47 @@
+ #include "v3d_trace.h"
+
+ static void
++v3d_clock_down_work(struct work_struct *work)
++{
++ struct v3d_dev *v3d =
++ container_of(work, struct v3d_dev, clk_down_work.work);
++ int ret;
++
++ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
++ v3d->clk_up = false;
++ WARN_ON_ONCE(ret != 0);
++}
++
++static void
++v3d_clock_up_get(struct v3d_dev *v3d)
++{
++ mutex_lock(&v3d->clk_lock);
++ if (v3d->clk_refcount++ == 0) {
++ cancel_delayed_work_sync(&v3d->clk_down_work);
++ if (!v3d->clk_up) {
++ int ret;
++
++ ret = clk_set_rate(v3d->clk, v3d->clk_up_rate);
++ WARN_ON_ONCE(ret != 0);
++ v3d->clk_up = true;
++ }
++ }
++ mutex_unlock(&v3d->clk_lock);
++}
++
++static void
++v3d_clock_up_put(struct v3d_dev *v3d)
++{
++ mutex_lock(&v3d->clk_lock);
++ if (--v3d->clk_refcount == 0) {
++ schedule_delayed_work(&v3d->clk_down_work,
++ msecs_to_jiffies(100));
++ }
++ mutex_unlock(&v3d->clk_lock);
++}
++
++
++static void
+ v3d_init_core(struct v3d_dev *v3d, int core)
+ {
+ /* Set OVRTMUOUT, which means that the texture sampler uniform
+@@ -490,6 +532,7 @@ static void
+ v3d_job_free(struct kref *ref)
+ {
+ struct v3d_job *job = container_of(ref, struct v3d_job, refcount);
++ struct v3d_dev *v3d = job->v3d;
+ int i;
+
+ for (i = 0; i < job->bo_count; i++) {
+@@ -505,6 +548,8 @@ v3d_job_free(struct kref *ref)
+ dma_fence_put(job->irq_fence);
+ dma_fence_put(job->done_fence);
+
++ v3d_clock_up_put(v3d);
++
+ kfree(job);
+ }
+
+@@ -596,6 +641,7 @@ v3d_job_init(struct v3d_dev *v3d, struct
+ if (ret)
+ return ret;
+
++ v3d_clock_up_get(v3d);
+ kref_init(&job->refcount);
+
+ return 0;
+@@ -963,6 +1009,9 @@ v3d_gem_init(struct drm_device *dev)
+ mutex_init(&v3d->sched_lock);
+ mutex_init(&v3d->cache_clean_lock);
+
++ mutex_init(&v3d->clk_lock);
++ INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work);
++
+ /* Note: We don't allocate address 0. Various bits of HW
+ * treat 0 as special, such as the occlusion query counters
+ * where 0 means "disabled".
+++ /dev/null
-From 22dbf1420a552d1952d22b92d8c30f8162b026b5 Mon Sep 17 00:00:00 2001
-Date: Tue, 16 Apr 2019 15:58:54 -0700
-Subject: [PATCH] drm/v3d: Add support for compute shader dispatch.
-
-The compute shader dispatch interface is pretty simple -- just pass in
-the regs that userspace has passed us, with no CLs to run. However,
-with no CL to run it means that we need to do manual cache flushing of
-the L2 after the HW execution completes (for SSBO, atomic, and
-image_load_store writes that are the output of compute shaders).
-
-This doesn't yet expose the L2 cache's ability to have a region of the
-address space not write back to memory (which could be used for
-shared_var storage).
-
-So far, the Mesa side has been tested on V3D v4.2 simpenrose (passing
-the ES31 tests), and on the kernel side on 7278 (failing atomic
-compswap tests in a way that doesn't reproduce on simpenrose).
-
-v2: Fix excessive allocation for the clean_job (reported by Dan
- Carpenter). Keep refs on jobs until clean_job is finished, to
- avoid spurious MMU errors if the output BOs are freed by userspace
- before L2 cleaning is finished.
-
----
- drivers/gpu/drm/v3d/v3d_debugfs.c | 22 +++++
- drivers/gpu/drm/v3d/v3d_drv.c | 10 +-
- drivers/gpu/drm/v3d/v3d_drv.h | 28 +++++-
- drivers/gpu/drm/v3d/v3d_fence.c | 2 +
- drivers/gpu/drm/v3d/v3d_gem.c | 156 +++++++++++++++++++++++++++++-
- drivers/gpu/drm/v3d/v3d_irq.c | 16 ++-
- drivers/gpu/drm/v3d/v3d_regs.h | 73 ++++++++++++++
- drivers/gpu/drm/v3d/v3d_sched.c | 121 +++++++++++++++++++++--
- drivers/gpu/drm/v3d/v3d_trace.h | 94 ++++++++++++++++++
- include/uapi/drm/v3d_drm.h | 28 ++++++
- 10 files changed, 531 insertions(+), 19 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_debugfs.c
-+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
-@@ -57,6 +57,17 @@ static const struct v3d_reg_def v3d_core
- REGDEF(V3D_GMP_VIO_ADDR),
- };
-
-+static const struct v3d_reg_def v3d_csd_reg_defs[] = {
-+ REGDEF(V3D_CSD_STATUS),
-+ REGDEF(V3D_CSD_CURRENT_CFG0),
-+ REGDEF(V3D_CSD_CURRENT_CFG1),
-+ REGDEF(V3D_CSD_CURRENT_CFG2),
-+ REGDEF(V3D_CSD_CURRENT_CFG3),
-+ REGDEF(V3D_CSD_CURRENT_CFG4),
-+ REGDEF(V3D_CSD_CURRENT_CFG5),
-+ REGDEF(V3D_CSD_CURRENT_CFG6),
-+};
-+
- static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
- {
- struct drm_info_node *node = (struct drm_info_node *)m->private;
-@@ -88,6 +99,17 @@ static int v3d_v3d_debugfs_regs(struct s
- V3D_CORE_READ(core,
- v3d_core_reg_defs[i].reg));
- }
-+
-+ if (v3d_has_csd(v3d)) {
-+ for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) {
-+ seq_printf(m, "core %d %s (0x%04x): 0x%08x\n",
-+ core,
-+ v3d_csd_reg_defs[i].name,
-+ v3d_csd_reg_defs[i].reg,
-+ V3D_CORE_READ(core,
-+ v3d_csd_reg_defs[i].reg));
-+ }
-+ }
- }
-
- return 0;
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -7,9 +7,9 @@
- * This driver supports the Broadcom V3D 3.3 and 4.1 OpenGL ES GPUs.
- * For V3D 2.x support, see the VC4 driver.
- *
-- * Currently only single-core rendering using the binner and renderer,
-- * along with TFU (texture formatting unit) rendering is supported.
-- * V3D 4.x's CSD (compute shader dispatch) is not yet supported.
-+ * The V3D GPU includes a tiled render (composed of a bin and render
-+ * pipelines), the TFU (texture formatting unit), and the CSD (compute
-+ * shader dispatch).
- */
-
- #include <linux/clk.h>
-@@ -114,6 +114,9 @@ static int v3d_get_param_ioctl(struct dr
- case DRM_V3D_PARAM_SUPPORTS_TFU:
- args->value = 1;
- return 0;
-+ case DRM_V3D_PARAM_SUPPORTS_CSD:
-+ args->value = v3d_has_csd(v3d);
-+ return 0;
- default:
- DRM_DEBUG("Unknown parameter %d\n", args->param);
- return -EINVAL;
-@@ -183,6 +186,7 @@ static const struct drm_ioctl_desc v3d_d
- DRM_IOCTL_DEF_DRV(V3D_GET_PARAM, v3d_get_param_ioctl, DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(V3D_GET_BO_OFFSET, v3d_get_bo_offset_ioctl, DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(V3D_SUBMIT_TFU, v3d_submit_tfu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
-+ DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CSD, v3d_submit_csd_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
- };
-
- static const struct vm_operations_struct v3d_vm_ops = {
---- a/drivers/gpu/drm/v3d/v3d_drv.h
-+++ b/drivers/gpu/drm/v3d/v3d_drv.h
-@@ -16,9 +16,11 @@ enum v3d_queue {
- V3D_BIN,
- V3D_RENDER,
- V3D_TFU,
-+ V3D_CSD,
-+ V3D_CACHE_CLEAN,
- };
-
--#define V3D_MAX_QUEUES (V3D_TFU + 1)
-+#define V3D_MAX_QUEUES (V3D_CACHE_CLEAN + 1)
-
- struct v3d_queue_state {
- struct drm_gpu_scheduler sched;
-@@ -70,6 +72,7 @@ struct v3d_dev {
- struct v3d_bin_job *bin_job;
- struct v3d_render_job *render_job;
- struct v3d_tfu_job *tfu_job;
-+ struct v3d_csd_job *csd_job;
-
- struct v3d_queue_state queue[V3D_MAX_QUEUES];
-
-@@ -92,6 +95,12 @@ struct v3d_dev {
- */
- struct mutex sched_lock;
-
-+ /* Lock taken during a cache clean and when initiating an L2
-+ * flush, to keep L2 flushes from interfering with the
-+ * synchronous L2 cleans.
-+ */
-+ struct mutex cache_clean_lock;
-+
- struct {
- u32 num_allocated;
- u32 pages_allocated;
-@@ -104,6 +113,12 @@ to_v3d_dev(struct drm_device *dev)
- return (struct v3d_dev *)dev->dev_private;
- }
-
-+static inline bool
-+v3d_has_csd(struct v3d_dev *v3d)
-+{
-+ return v3d->ver >= 41;
-+}
-+
- /* The per-fd struct, which tracks the MMU mappings. */
- struct v3d_file_priv {
- struct v3d_dev *v3d;
-@@ -237,6 +252,14 @@ struct v3d_tfu_job {
- struct drm_v3d_submit_tfu args;
- };
-
-+struct v3d_csd_job {
-+ struct v3d_job base;
-+
-+ u32 timedout_batches;
-+
-+ struct drm_v3d_submit_csd args;
-+};
-+
- /**
- * _wait_for - magic (register) wait macro
- *
-@@ -302,11 +325,14 @@ int v3d_submit_cl_ioctl(struct drm_devic
- struct drm_file *file_priv);
- int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-+int v3d_submit_csd_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv);
- int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
- void v3d_job_put(struct v3d_job *job);
- void v3d_reset(struct v3d_dev *v3d);
- void v3d_invalidate_caches(struct v3d_dev *v3d);
-+void v3d_clean_caches(struct v3d_dev *v3d);
-
- /* v3d_irq.c */
- int v3d_irq_init(struct v3d_dev *v3d);
---- a/drivers/gpu/drm/v3d/v3d_fence.c
-+++ b/drivers/gpu/drm/v3d/v3d_fence.c
-@@ -36,6 +36,8 @@ static const char *v3d_fence_get_timelin
- return "v3d-render";
- case V3D_TFU:
- return "v3d-tfu";
-+ case V3D_CSD:
-+ return "v3d-csd";
- default:
- return NULL;
- }
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -162,10 +162,52 @@ v3d_flush_l2t(struct v3d_dev *v3d, int c
- /* While there is a busy bit (V3D_L2TCACTL_L2TFLS), we don't
- * need to wait for completion before dispatching the job --
- * L2T accesses will be stalled until the flush has completed.
-+ * However, we do need to make sure we don't try to trigger a
-+ * new flush while the L2_CLEAN queue is trying to
-+ * synchronously clean after a job.
- */
-+ mutex_lock(&v3d->cache_clean_lock);
- V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL,
- V3D_L2TCACTL_L2TFLS |
- V3D_SET_FIELD(V3D_L2TCACTL_FLM_FLUSH, V3D_L2TCACTL_FLM));
-+ mutex_unlock(&v3d->cache_clean_lock);
-+}
-+
-+/* Cleans texture L1 and L2 cachelines (writing back dirty data).
-+ *
-+ * For cleaning, which happens from the CACHE_CLEAN queue after CSD has
-+ * executed, we need to make sure that the clean is done before
-+ * signaling job completion. So, we synchronously wait before
-+ * returning, and we make sure that L2 invalidates don't happen in the
-+ * meantime to confuse our are-we-done checks.
-+ */
-+void
-+v3d_clean_caches(struct v3d_dev *v3d)
-+{
-+ struct drm_device *dev = &v3d->drm;
-+ int core = 0;
-+
-+ trace_v3d_cache_clean_begin(dev);
-+
-+ V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, V3D_L2TCACTL_TMUWCF);
-+ if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
-+ V3D_L2TCACTL_L2TFLS), 100)) {
-+ DRM_ERROR("Timeout waiting for L1T write combiner flush\n");
-+ }
-+
-+ mutex_lock(&v3d->cache_clean_lock);
-+ V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL,
-+ V3D_L2TCACTL_L2TFLS |
-+ V3D_SET_FIELD(V3D_L2TCACTL_FLM_CLEAN, V3D_L2TCACTL_FLM));
-+
-+ if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
-+ V3D_L2TCACTL_L2TFLS), 100)) {
-+ DRM_ERROR("Timeout waiting for L2T clean\n");
-+ }
-+
-+ mutex_unlock(&v3d->cache_clean_lock);
-+
-+ trace_v3d_cache_clean_end(dev);
- }
-
- /* Invalidates the slice caches. These are read-only caches. */
-@@ -584,7 +626,8 @@ static void
- v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv,
- struct v3d_job *job,
- struct ww_acquire_ctx *acquire_ctx,
-- u32 out_sync)
-+ u32 out_sync,
-+ struct dma_fence *done_fence)
- {
- struct drm_syncobj *sync_out;
-
-@@ -594,7 +637,7 @@ v3d_attach_fences_and_unlock_reservation
- /* Update the return sync object for the job */
- sync_out = drm_syncobj_find(file_priv, out_sync);
- if (sync_out) {
-- drm_syncobj_replace_fence(sync_out, job->done_fence);
-+ drm_syncobj_replace_fence(sync_out, done_fence);
- drm_syncobj_put(sync_out);
- }
- }
-@@ -691,8 +734,10 @@ v3d_submit_cl_ioctl(struct drm_device *d
- mutex_unlock(&v3d->sched_lock);
-
- v3d_attach_fences_and_unlock_reservation(file_priv,
-- &render->base, &acquire_ctx,
-- args->out_sync);
-+ &render->base,
-+ &acquire_ctx,
-+ args->out_sync,
-+ render->base.done_fence);
-
- if (bin)
- v3d_job_put(&bin->base);
-@@ -785,7 +830,8 @@ v3d_submit_tfu_ioctl(struct drm_device *
-
- v3d_attach_fences_and_unlock_reservation(file_priv,
- &job->base, &acquire_ctx,
-- args->out_sync);
-+ args->out_sync,
-+ job->base.done_fence);
-
- v3d_job_put(&job->base);
-
-@@ -801,6 +847,105 @@ fail:
- return ret;
- }
-
-+/**
-+ * v3d_submit_csd_ioctl() - Submits a CSD (texture formatting) job to the V3D.
-+ * @dev: DRM device
-+ * @data: ioctl argument
-+ * @file_priv: DRM file for this fd
-+ *
-+ * Userspace provides the register setup for the CSD, which we don't
-+ * need to validate since the CSD is behind the MMU.
-+ */
-+int
-+v3d_submit_csd_ioctl(struct drm_device *dev, void *data,
-+ struct drm_file *file_priv)
-+{
-+ struct v3d_dev *v3d = to_v3d_dev(dev);
-+ struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
-+ struct drm_v3d_submit_csd *args = data;
-+ struct v3d_csd_job *job;
-+ struct v3d_job *clean_job;
-+ struct ww_acquire_ctx acquire_ctx;
-+ int ret;
-+
-+ trace_v3d_submit_csd_ioctl(&v3d->drm, args->cfg[5], args->cfg[6]);
-+
-+ if (!v3d_has_csd(v3d)) {
-+ DRM_DEBUG("Attempting CSD submit on non-CSD hardware\n");
-+ return -EINVAL;
-+ }
-+
-+ job = kcalloc(1, sizeof(*job), GFP_KERNEL);
-+ if (!job)
-+ return -ENOMEM;
-+
-+ ret = v3d_job_init(v3d, file_priv, &job->base,
-+ v3d_job_free, args->in_sync);
-+ if (ret) {
-+ kfree(job);
-+ return ret;
-+ }
-+
-+ clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL);
-+ if (!clean_job) {
-+ v3d_job_put(&job->base);
-+ kfree(job);
-+ return -ENOMEM;
-+ }
-+
-+ ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0);
-+ if (ret) {
-+ v3d_job_put(&job->base);
-+ kfree(clean_job);
-+ return ret;
-+ }
-+
-+ job->args = *args;
-+
-+ ret = v3d_lookup_bos(dev, file_priv, clean_job,
-+ args->bo_handles, args->bo_handle_count);
-+ if (ret)
-+ goto fail;
-+
-+ ret = v3d_lock_bo_reservations(clean_job, &acquire_ctx);
-+ if (ret)
-+ goto fail;
-+
-+ mutex_lock(&v3d->sched_lock);
-+ ret = v3d_push_job(v3d_priv, &job->base, V3D_CSD);
-+ if (ret)
-+ goto fail_unreserve;
-+
-+ ret = v3d_add_dep(clean_job, dma_fence_get(job->base.done_fence));
-+ if (ret)
-+ goto fail_unreserve;
-+ ret = v3d_push_job(v3d_priv, clean_job, V3D_CACHE_CLEAN);
-+ if (ret)
-+ goto fail_unreserve;
-+ mutex_unlock(&v3d->sched_lock);
-+
-+ v3d_attach_fences_and_unlock_reservation(file_priv,
-+ clean_job,
-+ &acquire_ctx,
-+ args->out_sync,
-+ clean_job->done_fence);
-+
-+ v3d_job_put(&job->base);
-+ v3d_job_put(clean_job);
-+
-+ return 0;
-+
-+fail_unreserve:
-+ mutex_unlock(&v3d->sched_lock);
-+ v3d_unlock_bo_reservations(clean_job->bo, clean_job->bo_count,
-+ &acquire_ctx);
-+fail:
-+ v3d_job_put(&job->base);
-+ v3d_job_put(clean_job);
-+
-+ return ret;
-+}
-+
- int
- v3d_gem_init(struct drm_device *dev)
- {
-@@ -816,6 +961,7 @@ v3d_gem_init(struct drm_device *dev)
- mutex_init(&v3d->bo_lock);
- mutex_init(&v3d->reset_lock);
- mutex_init(&v3d->sched_lock);
-+ mutex_init(&v3d->cache_clean_lock);
-
- /* Note: We don't allocate address 0. Various bits of HW
- * treat 0 as special, such as the occlusion query counters
---- a/drivers/gpu/drm/v3d/v3d_irq.c
-+++ b/drivers/gpu/drm/v3d/v3d_irq.c
-@@ -4,9 +4,9 @@
- /**
- * DOC: Interrupt management for the V3D engine
- *
-- * When we take a bin, render, or TFU done interrupt, we need to
-- * signal the fence for that job so that the scheduler can queue up
-- * the next one and unblock any waiters.
-+ * When we take a bin, render, TFU done, or CSD done interrupt, we
-+ * need to signal the fence for that job so that the scheduler can
-+ * queue up the next one and unblock any waiters.
- *
- * When we take the binner out of memory interrupt, we need to
- * allocate some new memory and pass it to the binner so that the
-@@ -20,6 +20,7 @@
- #define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \
- V3D_INT_FLDONE | \
- V3D_INT_FRDONE | \
-+ V3D_INT_CSDDONE | \
- V3D_INT_GMPV))
-
- #define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \
-@@ -108,6 +109,15 @@ v3d_irq(int irq, void *arg)
- dma_fence_signal(&fence->base);
- status = IRQ_HANDLED;
- }
-+
-+ if (intsts & V3D_INT_CSDDONE) {
-+ struct v3d_fence *fence =
-+ to_v3d_fence(v3d->csd_job->base.irq_fence);
-+
-+ trace_v3d_csd_irq(&v3d->drm, fence->seqno);
-+ dma_fence_signal(&fence->base);
-+ status = IRQ_HANDLED;
-+ }
-
- /* We shouldn't be triggering these if we have GMP in
- * always-allowed mode.
---- a/drivers/gpu/drm/v3d/v3d_regs.h
-+++ b/drivers/gpu/drm/v3d/v3d_regs.h
-@@ -238,8 +238,11 @@
- #define V3D_CTL_L2TCACTL 0x00030
- # define V3D_L2TCACTL_TMUWCF BIT(8)
- # define V3D_L2TCACTL_L2T_NO_WM BIT(4)
-+/* Invalidates cache lines. */
- # define V3D_L2TCACTL_FLM_FLUSH 0
-+/* Removes cachelines without writing dirty lines back. */
- # define V3D_L2TCACTL_FLM_CLEAR 1
-+/* Writes out dirty cachelines and marks them clean, but doesn't invalidate. */
- # define V3D_L2TCACTL_FLM_CLEAN 2
- # define V3D_L2TCACTL_FLM_MASK V3D_MASK(2, 1)
- # define V3D_L2TCACTL_FLM_SHIFT 1
-@@ -255,6 +258,8 @@
- #define V3D_CTL_INT_MSK_CLR 0x00064
- # define V3D_INT_QPU_MASK V3D_MASK(27, 16)
- # define V3D_INT_QPU_SHIFT 16
-+# define V3D_INT_CSDDONE BIT(7)
-+# define V3D_INT_PCTR BIT(6)
- # define V3D_INT_GMPV BIT(5)
- # define V3D_INT_TRFB BIT(4)
- # define V3D_INT_SPILLUSE BIT(3)
-@@ -374,4 +379,72 @@
- #define V3D_GMP_PRESERVE_LOAD 0x00818
- #define V3D_GMP_VALID_LINES 0x00820
-
-+#define V3D_CSD_STATUS 0x00900
-+# define V3D_CSD_STATUS_NUM_COMPLETED_MASK V3D_MASK(11, 4)
-+# define V3D_CSD_STATUS_NUM_COMPLETED_SHIFT 4
-+# define V3D_CSD_STATUS_NUM_ACTIVE_MASK V3D_MASK(3, 2)
-+# define V3D_CSD_STATUS_NUM_ACTIVE_SHIFT 2
-+# define V3D_CSD_STATUS_HAVE_CURRENT_DISPATCH BIT(1)
-+# define V3D_CSD_STATUS_HAVE_QUEUED_DISPATCH BIT(0)
-+
-+#define V3D_CSD_QUEUED_CFG0 0x00904
-+# define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_MASK V3D_MASK(31, 16)
-+# define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_SHIFT 16
-+# define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_MASK V3D_MASK(15, 0)
-+# define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_SHIFT 0
-+
-+#define V3D_CSD_QUEUED_CFG1 0x00908
-+# define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_MASK V3D_MASK(31, 16)
-+# define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_SHIFT 16
-+# define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_MASK V3D_MASK(15, 0)
-+# define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_SHIFT 0
-+
-+#define V3D_CSD_QUEUED_CFG2 0x0090c
-+# define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_MASK V3D_MASK(31, 16)
-+# define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_SHIFT 16
-+# define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_MASK V3D_MASK(15, 0)
-+# define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_SHIFT 0
-+
-+#define V3D_CSD_QUEUED_CFG3 0x00910
-+# define V3D_CSD_QUEUED_CFG3_OVERLAP_WITH_PREV BIT(26)
-+# define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_MASK V3D_MASK(25, 20)
-+# define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_SHIFT 20
-+# define V3D_CSD_QUEUED_CFG3_BATCHES_PER_SG_M1_MASK V3D_MASK(19, 12)
-+# define V3D_CSD_QUEUED_CFG3_BATCHES_PER_SG_M1_SHIFT 12
-+# define V3D_CSD_QUEUED_CFG3_WGS_PER_SG_MASK V3D_MASK(11, 8)
-+# define V3D_CSD_QUEUED_CFG3_WGS_PER_SG_SHIFT 8
-+# define V3D_CSD_QUEUED_CFG3_WG_SIZE_MASK V3D_MASK(7, 0)
-+# define V3D_CSD_QUEUED_CFG3_WG_SIZE_SHIFT 0
-+
-+/* Number of batches, minus 1 */
-+#define V3D_CSD_QUEUED_CFG4 0x00914
-+
-+/* Shader address, pnan, singleseg, threading, like a shader record. */
-+#define V3D_CSD_QUEUED_CFG5 0x00918
-+
-+/* Uniforms address (4 byte aligned) */
-+#define V3D_CSD_QUEUED_CFG6 0x0091c
-+
-+#define V3D_CSD_CURRENT_CFG0 0x00920
-+#define V3D_CSD_CURRENT_CFG1 0x00924
-+#define V3D_CSD_CURRENT_CFG2 0x00928
-+#define V3D_CSD_CURRENT_CFG3 0x0092c
-+#define V3D_CSD_CURRENT_CFG4 0x00930
-+#define V3D_CSD_CURRENT_CFG5 0x00934
-+#define V3D_CSD_CURRENT_CFG6 0x00938
-+
-+#define V3D_CSD_CURRENT_ID0 0x0093c
-+# define V3D_CSD_CURRENT_ID0_WG_X_MASK V3D_MASK(31, 16)
-+# define V3D_CSD_CURRENT_ID0_WG_X_SHIFT 16
-+# define V3D_CSD_CURRENT_ID0_WG_IN_SG_MASK V3D_MASK(11, 8)
-+# define V3D_CSD_CURRENT_ID0_WG_IN_SG_SHIFT 8
-+# define V3D_CSD_CURRENT_ID0_L_IDX_MASK V3D_MASK(7, 0)
-+# define V3D_CSD_CURRENT_ID0_L_IDX_SHIFT 0
-+
-+#define V3D_CSD_CURRENT_ID1 0x00940
-+# define V3D_CSD_CURRENT_ID0_WG_Z_MASK V3D_MASK(31, 16)
-+# define V3D_CSD_CURRENT_ID0_WG_Z_SHIFT 16
-+# define V3D_CSD_CURRENT_ID0_WG_Y_MASK V3D_MASK(15, 0)
-+# define V3D_CSD_CURRENT_ID0_WG_Y_SHIFT 0
-+
- #endif /* V3D_REGS_H */
---- a/drivers/gpu/drm/v3d/v3d_sched.c
-+++ b/drivers/gpu/drm/v3d/v3d_sched.c
-@@ -48,6 +48,12 @@ to_tfu_job(struct drm_sched_job *sched_j
- return container_of(sched_job, struct v3d_tfu_job, base.base);
- }
-
-+static struct v3d_csd_job *
-+to_csd_job(struct drm_sched_job *sched_job)
-+{
-+ return container_of(sched_job, struct v3d_csd_job, base.base);
-+}
-+
- static void
- v3d_job_free(struct drm_sched_job *sched_job)
- {
-@@ -205,6 +211,48 @@ v3d_tfu_job_run(struct drm_sched_job *sc
- return fence;
- }
-
-+static struct dma_fence *
-+v3d_csd_job_run(struct drm_sched_job *sched_job)
-+{
-+ struct v3d_csd_job *job = to_csd_job(sched_job);
-+ struct v3d_dev *v3d = job->base.v3d;
-+ struct drm_device *dev = &v3d->drm;
-+ struct dma_fence *fence;
-+ int i;
-+
-+ v3d->csd_job = job;
-+
-+ v3d_invalidate_caches(v3d);
-+
-+ fence = v3d_fence_create(v3d, V3D_CSD);
-+ if (IS_ERR(fence))
-+ return NULL;
-+
-+ if (job->base.irq_fence)
-+ dma_fence_put(job->base.irq_fence);
-+ job->base.irq_fence = dma_fence_get(fence);
-+
-+ trace_v3d_submit_csd(dev, to_v3d_fence(fence)->seqno);
-+
-+ for (i = 1; i <= 6; i++)
-+ V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0 + 4 * i, job->args.cfg[i]);
-+ /* CFG0 write kicks off the job. */
-+ V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0, job->args.cfg[0]);
-+
-+ return fence;
-+}
-+
-+static struct dma_fence *
-+v3d_cache_clean_job_run(struct drm_sched_job *sched_job)
-+{
-+ struct v3d_job *job = to_v3d_job(sched_job);
-+ struct v3d_dev *v3d = job->v3d;
-+
-+ v3d_clean_caches(v3d);
-+
-+ return NULL;
-+}
-+
- static void
- v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job)
- {
-@@ -277,13 +325,31 @@ v3d_render_job_timedout(struct drm_sched
- }
-
- static void
--v3d_tfu_job_timedout(struct drm_sched_job *sched_job)
-+v3d_generic_job_timedout(struct drm_sched_job *sched_job)
- {
- struct v3d_job *job = to_v3d_job(sched_job);
-
- v3d_gpu_reset_for_timeout(job->v3d, sched_job);
- }
-
-+static void
-+v3d_csd_job_timedout(struct drm_sched_job *sched_job)
-+{
-+ struct v3d_csd_job *job = to_csd_job(sched_job);
-+ struct v3d_dev *v3d = job->base.v3d;
-+ u32 batches = V3D_CORE_READ(0, V3D_CSD_CURRENT_CFG4);
-+
-+ /* If we've made progress, skip reset and let the timer get
-+ * rearmed.
-+ */
-+ if (job->timedout_batches != batches) {
-+ job->timedout_batches = batches;
-+ return;
-+ }
-+
-+ v3d_gpu_reset_for_timeout(v3d, sched_job);
-+}
-+
- static const struct drm_sched_backend_ops v3d_bin_sched_ops = {
- .dependency = v3d_job_dependency,
- .run_job = v3d_bin_job_run,
-@@ -301,10 +367,24 @@ static const struct drm_sched_backend_op
- static const struct drm_sched_backend_ops v3d_tfu_sched_ops = {
- .dependency = v3d_job_dependency,
- .run_job = v3d_tfu_job_run,
-- .timedout_job = v3d_tfu_job_timedout,
-+ .timedout_job = v3d_generic_job_timedout,
- .free_job = v3d_job_free,
- };
-
-+static const struct drm_sched_backend_ops v3d_csd_sched_ops = {
-+ .dependency = v3d_job_dependency,
-+ .run_job = v3d_csd_job_run,
-+ .timedout_job = v3d_csd_job_timedout,
-+ .free_job = v3d_job_free
-+};
-+
-+static const struct drm_sched_backend_ops v3d_cache_clean_sched_ops = {
-+ .dependency = v3d_job_dependency,
-+ .run_job = v3d_cache_clean_job_run,
-+ .timedout_job = v3d_generic_job_timedout,
-+ .free_job = v3d_job_free
-+};
-+
- int
- v3d_sched_init(struct v3d_dev *v3d)
- {
-@@ -331,7 +411,7 @@ v3d_sched_init(struct v3d_dev *v3d)
- if (ret) {
- dev_err(v3d->dev, "Failed to create render scheduler: %d.",
- ret);
-- drm_sched_fini(&v3d->queue[V3D_BIN].sched);
-+ v3d_sched_fini(v3d);
- return ret;
- }
-
-@@ -343,11 +423,36 @@ v3d_sched_init(struct v3d_dev *v3d)
- if (ret) {
- dev_err(v3d->dev, "Failed to create TFU scheduler: %d.",
- ret);
-- drm_sched_fini(&v3d->queue[V3D_RENDER].sched);
-- drm_sched_fini(&v3d->queue[V3D_BIN].sched);
-+ v3d_sched_fini(v3d);
- return ret;
- }
-
-+ if (v3d_has_csd(v3d)) {
-+ ret = drm_sched_init(&v3d->queue[V3D_CSD].sched,
-+ &v3d_csd_sched_ops,
-+ hw_jobs_limit, job_hang_limit,
-+ msecs_to_jiffies(hang_limit_ms),
-+ "v3d_csd");
-+ if (ret) {
-+ dev_err(v3d->dev, "Failed to create CSD scheduler: %d.",
-+ ret);
-+ v3d_sched_fini(v3d);
-+ return ret;
-+ }
-+
-+ ret = drm_sched_init(&v3d->queue[V3D_CACHE_CLEAN].sched,
-+ &v3d_cache_clean_sched_ops,
-+ hw_jobs_limit, job_hang_limit,
-+ msecs_to_jiffies(hang_limit_ms),
-+ "v3d_cache_clean");
-+ if (ret) {
-+ dev_err(v3d->dev, "Failed to create CACHE_CLEAN scheduler: %d.",
-+ ret);
-+ v3d_sched_fini(v3d);
-+ return ret;
-+ }
-+ }
-+
- return 0;
- }
-
-@@ -356,6 +461,8 @@ v3d_sched_fini(struct v3d_dev *v3d)
- {
- enum v3d_queue q;
-
-- for (q = 0; q < V3D_MAX_QUEUES; q++)
-- drm_sched_fini(&v3d->queue[q].sched);
-+ for (q = 0; q < V3D_MAX_QUEUES; q++) {
-+ if (v3d->queue[q].sched.ops)
-+ drm_sched_fini(&v3d->queue[q].sched);
-+ }
- }
---- a/drivers/gpu/drm/v3d/v3d_trace.h
-+++ b/drivers/gpu/drm/v3d/v3d_trace.h
-@@ -124,6 +124,26 @@ TRACE_EVENT(v3d_tfu_irq,
- __entry->seqno)
- );
-
-+TRACE_EVENT(v3d_csd_irq,
-+ TP_PROTO(struct drm_device *dev,
-+ uint64_t seqno),
-+ TP_ARGS(dev, seqno),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ __field(u64, seqno)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ __entry->seqno = seqno;
-+ ),
-+
-+ TP_printk("dev=%u, seqno=%llu",
-+ __entry->dev,
-+ __entry->seqno)
-+);
-+
- TRACE_EVENT(v3d_submit_tfu_ioctl,
- TP_PROTO(struct drm_device *dev, u32 iia),
- TP_ARGS(dev, iia),
-@@ -163,6 +183,80 @@ TRACE_EVENT(v3d_submit_tfu,
- __entry->seqno)
- );
-
-+TRACE_EVENT(v3d_submit_csd_ioctl,
-+ TP_PROTO(struct drm_device *dev, u32 cfg5, u32 cfg6),
-+ TP_ARGS(dev, cfg5, cfg6),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ __field(u32, cfg5)
-+ __field(u32, cfg6)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ __entry->cfg5 = cfg5;
-+ __entry->cfg6 = cfg6;
-+ ),
-+
-+ TP_printk("dev=%u, CFG5 0x%08x, CFG6 0x%08x",
-+ __entry->dev,
-+ __entry->cfg5,
-+ __entry->cfg6)
-+);
-+
-+TRACE_EVENT(v3d_submit_csd,
-+ TP_PROTO(struct drm_device *dev,
-+ uint64_t seqno),
-+ TP_ARGS(dev, seqno),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ __field(u64, seqno)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ __entry->seqno = seqno;
-+ ),
-+
-+ TP_printk("dev=%u, seqno=%llu",
-+ __entry->dev,
-+ __entry->seqno)
-+);
-+
-+TRACE_EVENT(v3d_cache_clean_begin,
-+ TP_PROTO(struct drm_device *dev),
-+ TP_ARGS(dev),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ ),
-+
-+ TP_printk("dev=%u",
-+ __entry->dev)
-+);
-+
-+TRACE_EVENT(v3d_cache_clean_end,
-+ TP_PROTO(struct drm_device *dev),
-+ TP_ARGS(dev),
-+
-+ TP_STRUCT__entry(
-+ __field(u32, dev)
-+ ),
-+
-+ TP_fast_assign(
-+ __entry->dev = dev->primary->index;
-+ ),
-+
-+ TP_printk("dev=%u",
-+ __entry->dev)
-+);
-+
- TRACE_EVENT(v3d_reset_begin,
- TP_PROTO(struct drm_device *dev),
- TP_ARGS(dev),
---- a/include/uapi/drm/v3d_drm.h
-+++ b/include/uapi/drm/v3d_drm.h
-@@ -37,6 +37,7 @@ extern "C" {
- #define DRM_V3D_GET_PARAM 0x04
- #define DRM_V3D_GET_BO_OFFSET 0x05
- #define DRM_V3D_SUBMIT_TFU 0x06
-+#define DRM_V3D_SUBMIT_CSD 0x07
-
- #define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl)
- #define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo)
-@@ -45,6 +46,7 @@ extern "C" {
- #define DRM_IOCTL_V3D_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_PARAM, struct drm_v3d_get_param)
- #define DRM_IOCTL_V3D_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_BO_OFFSET, struct drm_v3d_get_bo_offset)
- #define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu)
-+#define DRM_IOCTL_V3D_SUBMIT_CSD DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CSD, struct drm_v3d_submit_csd)
-
- /**
- * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D
-@@ -172,6 +174,7 @@ enum drm_v3d_param {
- DRM_V3D_PARAM_V3D_CORE0_IDENT1,
- DRM_V3D_PARAM_V3D_CORE0_IDENT2,
- DRM_V3D_PARAM_SUPPORTS_TFU,
-+ DRM_V3D_PARAM_SUPPORTS_CSD,
- };
-
- struct drm_v3d_get_param {
-@@ -212,6 +215,31 @@ struct drm_v3d_submit_tfu {
- __u32 out_sync;
- };
-
-+/* Submits a compute shader for dispatch. This job will block on any
-+ * previous compute shaders submitted on this fd, and any other
-+ * synchronization must be performed with in_sync/out_sync.
-+ */
-+struct drm_v3d_submit_csd {
-+ __u32 cfg[7];
-+ __u32 coef[4];
-+
-+ /* Pointer to a u32 array of the BOs that are referenced by the job.
-+ */
-+ __u64 bo_handles;
-+
-+ /* Number of BO handles passed in (size is that times 4). */
-+ __u32 bo_handle_count;
-+
-+ /* sync object to block on before running the CSD job. Each
-+ * CSD job will execute in the order submitted to its FD.
-+ * Synchronization against rendering/TFU jobs or CSD from
-+ * other fds requires using sync objects.
-+ */
-+ __u32 in_sync;
-+ /* Sync object to signal when the CSD job is done. */
-+ __u32 out_sync;
-+};
-+
- #if defined(__cplusplus)
- }
- #endif
--- /dev/null
+From 3cd15f787b391db5224a27715fe9dc6fc8559bee Mon Sep 17 00:00:00 2001
+Date: Fri, 3 May 2019 13:58:03 +0100
+Subject: [PATCH] drm: vc4-firmware-kms: Remove incorrect overscan
+ support.
+
+The overscan support was required for the old mailbox API
+in order to match up the cursor and frame buffer planes.
+With the newer API directly talking to dispmanx there is no
+difference, therefore FKMS does not need to make any
+adjustments.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 ---------------
+ 1 file changed, 15 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -232,7 +232,6 @@ struct vc4_crtc {
+ void __iomem *regs;
+
+ struct drm_pending_vblank_event *event;
+- u32 overscan[4];
+ bool vblank_enabled;
+ u32 display_number;
+ u32 display_type;
+@@ -468,11 +467,6 @@ static void vc4_plane_atomic_update(stru
+ break;
+ }
+
+- if (vc4_crtc) {
+- mb->plane.dst_x += vc4_crtc->overscan[0];
+- mb->plane.dst_y += vc4_crtc->overscan[1];
+- }
+-
+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n",
+ plane->base.id, plane->name,
+ mb->plane.width,
+@@ -1228,15 +1222,6 @@ static int vc4_fkms_create_screen(struct
+ goto err_destroy_encoder;
+ }
+
+- ret = rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN,
+- &vc4_crtc->overscan,
+- sizeof(vc4_crtc->overscan));
+- if (ret) {
+- DRM_ERROR("Failed to get overscan state: 0x%08x\n", vc4_crtc->overscan[0]);
+- memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan));
+- }
+-
+ *ret_crtc = vc4_crtc;
+
+ return 0;
+++ /dev/null
-From 3e6b687bae81bdf5a430ffaa04aa04ee195a866c Mon Sep 17 00:00:00 2001
-Date: Thu, 2 May 2019 13:22:53 -0700
-Subject: [PATCH] drm/v3d: Clock V3D down when not in use.
-
-My various attempts at re-enabling runtime PM have failed, so just
-crank the clock down when V3D is idle to reduce power consumption.
-
----
- drivers/gpu/drm/v3d/v3d_drv.c | 18 +++++++++++++
- drivers/gpu/drm/v3d/v3d_drv.h | 6 +++++
- drivers/gpu/drm/v3d/v3d_gem.c | 49 +++++++++++++++++++++++++++++++++++
- 3 files changed, 73 insertions(+)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -297,6 +297,21 @@ static int v3d_platform_drm_probe(struct
- }
- }
-
-+ v3d->clk = devm_clk_get(dev, NULL);
-+ if (IS_ERR(v3d->clk)) {
-+ if (ret != -EPROBE_DEFER)
-+ dev_err(dev, "Failed to get clock\n");
-+ goto dev_free;
-+ }
-+ v3d->clk_up_rate = clk_get_rate(v3d->clk);
-+ /* For downclocking, drop it to the minimum frequency we can get from
-+ * the CPRMAN clock generator dividing off our parent. The divider is
-+ * 4 bits, but ask for just higher than that so that rounding doesn't
-+ * make cprman reject our rate.
-+ */
-+ v3d->clk_down_rate =
-+ (clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000;
-+
- if (v3d->ver < 41) {
- ret = map_regs(v3d, &v3d->gca_regs, "gca");
- if (ret)
-@@ -331,6 +346,9 @@ static int v3d_platform_drm_probe(struct
- if (ret)
- goto irq_disable;
-
-+ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
-+ WARN_ON_ONCE(ret != 0);
-+
- return 0;
-
- irq_disable:
---- a/drivers/gpu/drm/v3d/v3d_drv.h
-+++ b/drivers/gpu/drm/v3d/v3d_drv.h
-@@ -45,6 +45,12 @@ struct v3d_dev {
- void __iomem *bridge_regs;
- void __iomem *gca_regs;
- struct clk *clk;
-+ struct delayed_work clk_down_work;
-+ unsigned long clk_up_rate, clk_down_rate;
-+ struct mutex clk_lock;
-+ u32 clk_refcount;
-+ bool clk_up;
-+
- struct reset_control *reset;
-
- /* Virtual and DMA addresses of the single shared page table. */
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -3,6 +3,7 @@
-
- #include <drm/drmP.h>
- #include <drm/drm_syncobj.h>
-+#include <linux/clk.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/pm_runtime.h>
-@@ -17,6 +18,47 @@
- #include "v3d_trace.h"
-
- static void
-+v3d_clock_down_work(struct work_struct *work)
-+{
-+ struct v3d_dev *v3d =
-+ container_of(work, struct v3d_dev, clk_down_work.work);
-+ int ret;
-+
-+ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
-+ v3d->clk_up = false;
-+ WARN_ON_ONCE(ret != 0);
-+}
-+
-+static void
-+v3d_clock_up_get(struct v3d_dev *v3d)
-+{
-+ mutex_lock(&v3d->clk_lock);
-+ if (v3d->clk_refcount++ == 0) {
-+ cancel_delayed_work_sync(&v3d->clk_down_work);
-+ if (!v3d->clk_up) {
-+ int ret;
-+
-+ ret = clk_set_rate(v3d->clk, v3d->clk_up_rate);
-+ WARN_ON_ONCE(ret != 0);
-+ v3d->clk_up = true;
-+ }
-+ }
-+ mutex_unlock(&v3d->clk_lock);
-+}
-+
-+static void
-+v3d_clock_up_put(struct v3d_dev *v3d)
-+{
-+ mutex_lock(&v3d->clk_lock);
-+ if (--v3d->clk_refcount == 0) {
-+ schedule_delayed_work(&v3d->clk_down_work,
-+ msecs_to_jiffies(100));
-+ }
-+ mutex_unlock(&v3d->clk_lock);
-+}
-+
-+
-+static void
- v3d_init_core(struct v3d_dev *v3d, int core)
- {
- /* Set OVRTMUOUT, which means that the texture sampler uniform
-@@ -490,6 +532,7 @@ static void
- v3d_job_free(struct kref *ref)
- {
- struct v3d_job *job = container_of(ref, struct v3d_job, refcount);
-+ struct v3d_dev *v3d = job->v3d;
- int i;
-
- for (i = 0; i < job->bo_count; i++) {
-@@ -505,6 +548,8 @@ v3d_job_free(struct kref *ref)
- dma_fence_put(job->irq_fence);
- dma_fence_put(job->done_fence);
-
-+ v3d_clock_up_put(v3d);
-+
- kfree(job);
- }
-
-@@ -596,6 +641,7 @@ v3d_job_init(struct v3d_dev *v3d, struct
- if (ret)
- return ret;
-
-+ v3d_clock_up_get(v3d);
- kref_init(&job->refcount);
-
- return 0;
-@@ -963,6 +1009,9 @@ v3d_gem_init(struct drm_device *dev)
- mutex_init(&v3d->sched_lock);
- mutex_init(&v3d->cache_clean_lock);
-
-+ mutex_init(&v3d->clk_lock);
-+ INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work);
-+
- /* Note: We don't allocate address 0. Various bits of HW
- * treat 0 as special, such as the occlusion query counters
- * where 0 means "disabled".
--- /dev/null
+From 07288c2bd9733dc9317c5f9b02980a59a05ce3af Mon Sep 17 00:00:00 2001
+Date: Tue, 7 May 2019 12:13:34 +0100
+Subject: [PATCH] drm: vc4: Log flags in fkms mode set
+
+The flags contain info such as limited/full range RGB, aspect
+ratio, and a fwe other useful things.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -685,12 +685,13 @@ static void vc4_crtc_mode_set_nofb(struc
+ return;
+ }
+
+- DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u\n",
++ DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u, flags 0x%04x\n",
+ vc4_crtc->display_number, mode->name, mode->clock,
+ mode->hdisplay, mode->hsync_start, mode->hsync_end,
+ mode->htotal, mode->hskew, mode->vdisplay,
+ mode->vsync_start, mode->vsync_end, mode->vtotal,
+- mode->vscan, mode->vrefresh, mode->picture_aspect_ratio);
++ mode->vscan, mode->vrefresh, mode->picture_aspect_ratio,
++ mode->flags);
+ mb.timings.display = vc4_crtc->display_number;
+
+ mb.timings.video_id_code = frame.avi.video_code;
--- /dev/null
+From d66b1d056d07b27803ba0756ecdb0d4419bcaaa2 Mon Sep 17 00:00:00 2001
+Date: Thu, 16 May 2019 17:49:42 +0100
+Subject: [PATCH] drm: vc4-firmware-kms: Fix DSI display support
+
+The mode was incorrectly listed as interlaced, which was then
+rejected.
+Correct this and FKMS works with the DSI display.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1003,7 +1003,7 @@ static const struct drm_display_mode lcd
+ 25979400 / 1000,
+ 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0,
+ 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0,
+- DRM_MODE_FLAG_INTERLACE)
++ 0)
+ };
+
+ static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
+++ /dev/null
-From 3cd15f787b391db5224a27715fe9dc6fc8559bee Mon Sep 17 00:00:00 2001
-Date: Fri, 3 May 2019 13:58:03 +0100
-Subject: [PATCH] drm: vc4-firmware-kms: Remove incorrect overscan
- support.
-
-The overscan support was required for the old mailbox API
-in order to match up the cursor and frame buffer planes.
-With the newer API directly talking to dispmanx there is no
-difference, therefore FKMS does not need to make any
-adjustments.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 ---------------
- 1 file changed, 15 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -232,7 +232,6 @@ struct vc4_crtc {
- void __iomem *regs;
-
- struct drm_pending_vblank_event *event;
-- u32 overscan[4];
- bool vblank_enabled;
- u32 display_number;
- u32 display_type;
-@@ -468,11 +467,6 @@ static void vc4_plane_atomic_update(stru
- break;
- }
-
-- if (vc4_crtc) {
-- mb->plane.dst_x += vc4_crtc->overscan[0];
-- mb->plane.dst_y += vc4_crtc->overscan[1];
-- }
--
- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n",
- plane->base.id, plane->name,
- mb->plane.width,
-@@ -1228,15 +1222,6 @@ static int vc4_fkms_create_screen(struct
- goto err_destroy_encoder;
- }
-
-- ret = rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN,
-- &vc4_crtc->overscan,
-- sizeof(vc4_crtc->overscan));
-- if (ret) {
-- DRM_ERROR("Failed to get overscan state: 0x%08x\n", vc4_crtc->overscan[0]);
-- memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan));
-- }
--
- *ret_crtc = vc4_crtc;
-
- return 0;
+++ /dev/null
-From 07288c2bd9733dc9317c5f9b02980a59a05ce3af Mon Sep 17 00:00:00 2001
-Date: Tue, 7 May 2019 12:13:34 +0100
-Subject: [PATCH] drm: vc4: Log flags in fkms mode set
-
-The flags contain info such as limited/full range RGB, aspect
-ratio, and a fwe other useful things.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -685,12 +685,13 @@ static void vc4_crtc_mode_set_nofb(struc
- return;
- }
-
-- DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u\n",
-+ DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u, flags 0x%04x\n",
- vc4_crtc->display_number, mode->name, mode->clock,
- mode->hdisplay, mode->hsync_start, mode->hsync_end,
- mode->htotal, mode->hskew, mode->vdisplay,
- mode->vsync_start, mode->vsync_end, mode->vtotal,
-- mode->vscan, mode->vrefresh, mode->picture_aspect_ratio);
-+ mode->vscan, mode->vrefresh, mode->picture_aspect_ratio,
-+ mode->flags);
- mb.timings.display = vc4_crtc->display_number;
-
- mb.timings.video_id_code = frame.avi.video_code;
--- /dev/null
+From b4ffa49d762a4af832d0d8660caf59722c0ff75a Mon Sep 17 00:00:00 2001
+Date: Tue, 21 May 2019 11:50:00 +0100
+Subject: [PATCH] drm: vc4: Probe DPI/DSI timings from the firmware
+
+For DPI and DSI displays query the firmware as to the configuration
+and add it as the only mode for DRM.
+
+In theory we can add plumbing for setting the DPI/DSI mode from
+KMS, but this is not being added at present as the support frameworks
+aren't present in the firmware.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 60 ++++++++++++++++++----
+ include/soc/bcm2835/raspberrypi-firmware.h | 1 +
+ 2 files changed, 51 insertions(+), 10 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -280,7 +280,7 @@ static u32 vc4_get_display_type(u32 disp
+ /* The firmware display (DispmanX) IDs map to specific types in
+ * a fixed manner.
+ */
+- DRM_MODE_ENCODER_DSI, /* MAIN_LCD */
++ DRM_MODE_ENCODER_DSI, /* MAIN_LCD - DSI or DPI */
+ DRM_MODE_ENCODER_DSI, /* AUX_LCD */
+ DRM_MODE_ENCODER_TMDS, /* HDMI0 */
+ DRM_MODE_ENCODER_TVDAC, /* VEC */
+@@ -362,7 +362,6 @@ static void vc4_plane_atomic_update(stru
+ vc4_get_vc_image_fmt(drm_fmt->format);
+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+ struct mailbox_set_plane *mb = &vc4_plane->mb;
+- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
+ int num_planes = fb->format->num_planes;
+ struct drm_display_mode *mode = &state->crtc->mode;
+ unsigned int rotation = SUPPORTED_ROTATIONS;
+@@ -997,7 +996,9 @@ static int vc4_fkms_connector_get_modes(
+ return ret;
+ }
+
+-/* FIXME: Read LCD mode from the firmware. This is the DSI panel resolution. */
++/* This is the DSI panel resolution. Use this as a default should the firmware
++ * not respond to our request for the timings.
++ */
+ static const struct drm_display_mode lcd_mode = {
+ DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+ 25979400 / 1000,
+@@ -1008,15 +1009,54 @@ static const struct drm_display_mode lcd
+
+ static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
+ {
+- //struct vc4_fkms_connector *fkms_connector =
+- // to_vc4_fkms_connector(connector);
+- //struct drm_encoder *encoder = fkms_connector->encoder;
+- //struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
++ struct vc4_fkms_connector *fkms_connector =
++ to_vc4_fkms_connector(connector);
++ struct vc4_dev *vc4 = fkms_connector->vc4_dev;
+ struct drm_display_mode *mode;
+- //int ret = 0;
++ struct mailbox_set_mode mb = {
++ .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING,
++ sizeof(struct set_timings), 0},
++ .timings = { .display = fkms_connector->display_number },
++ };
++ struct drm_display_mode fw_mode;
++ int ret = 0;
++
++ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
++ if (!ret) {
++ /* Equivalent to DRM_MODE macro. */
++ memset(&fw_mode, 0, sizeof(fw_mode));
++ strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name));
++ fw_mode.status = 0;
++ fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
++ fw_mode.clock = mb.timings.clock;
++ fw_mode.hdisplay = mb.timings.hdisplay;
++ fw_mode.hsync_start = mb.timings.hsync_start;
++ fw_mode.hsync_end = mb.timings.hsync_end;
++ fw_mode.htotal = mb.timings.htotal;
++ fw_mode.hskew = 0;
++ fw_mode.vdisplay = mb.timings.vdisplay;
++ fw_mode.vsync_start = mb.timings.vsync_start;
++ fw_mode.vsync_end = mb.timings.vsync_end;
++ fw_mode.vtotal = mb.timings.vtotal;
++ fw_mode.vscan = mb.timings.vscan;
++ if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
++ fw_mode.flags |= DRM_MODE_FLAG_PHSYNC;
++ else
++ fw_mode.flags |= DRM_MODE_FLAG_NHSYNC;
++ if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
++ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
++ else
++ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
++
++ fw_mode.base.type = DRM_MODE_OBJECT_MODE;
++
++ mode = drm_mode_duplicate(connector->dev,
++ &fw_mode);
++ } else {
++ mode = drm_mode_duplicate(connector->dev,
++ &lcd_mode);
++ }
+
+- mode = drm_mode_duplicate(connector->dev,
+- &lcd_mode);
+ if (!mode) {
+ DRM_ERROR("Failed to create a new display mode\n");
+ return -ENOMEM;
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -151,6 +151,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
+
+ RPI_FIRMWARE_SET_PLANE = 0x00048015,
++ RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
+ RPI_FIRMWARE_SET_TIMING = 0x00048017,
+
+ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
+++ /dev/null
-From d66b1d056d07b27803ba0756ecdb0d4419bcaaa2 Mon Sep 17 00:00:00 2001
-Date: Thu, 16 May 2019 17:49:42 +0100
-Subject: [PATCH] drm: vc4-firmware-kms: Fix DSI display support
-
-The mode was incorrectly listed as interlaced, which was then
-rejected.
-Correct this and FKMS works with the DSI display.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1003,7 +1003,7 @@ static const struct drm_display_mode lcd
- 25979400 / 1000,
- 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0,
- 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0,
-- DRM_MODE_FLAG_INTERLACE)
-+ 0)
- };
-
- static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
--- /dev/null
+From dd99aa50a3ea7f7fe1ddfd59b1a2e969c744b8a0 Mon Sep 17 00:00:00 2001
+Date: Tue, 28 May 2019 13:56:06 +0100
+Subject: [PATCH] drm: vc4: handle the case where there are no
+ available displays
+
+It's reasonable for the firmware to return zero as the number of
+attached displays. Handle this case as otherwise drm thinks that
+the DSI panel is attached, which is nonsense.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 32 +++++++++++++++-----------
+ 1 file changed, 18 insertions(+), 14 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1309,13 +1309,13 @@ static int vc4_fkms_bind(struct device *
+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
+ &num_displays, sizeof(u32));
+
+- /* If we fail to get the number of displays, or it returns 0, then
++ /* If we fail to get the number of displays, then
+ * assume old firmware that doesn't have the mailbox call, so just
+ * set one display
+ */
+- if (ret || num_displays == 0) {
++ if (ret) {
+ num_displays = 1;
+- DRM_WARN("Unable to determine number of displays's. Assuming 1\n");
++ DRM_WARN("Unable to determine number of displays - assuming 1\n");
+ ret = 0;
+ }
+
+@@ -1344,17 +1344,21 @@ static int vc4_fkms_bind(struct device *
+ display_num);
+ }
+
+- /* Map the SMI interrupt reg */
+- crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
+- if (IS_ERR(crtc_list[0]->regs))
+- DRM_ERROR("Oh dear, failed to map registers\n");
+-
+- writel(0, crtc_list[0]->regs + SMICS);
+- ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
+- vc4_crtc_irq_handler, 0, "vc4 firmware kms",
+- crtc_list);
+- if (ret)
+- DRM_ERROR("Oh dear, failed to register IRQ\n");
++ if (num_displays > 0) {
++ /* Map the SMI interrupt reg */
++ crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
++ if (IS_ERR(crtc_list[0]->regs))
++ DRM_ERROR("Oh dear, failed to map registers\n");
++
++ writel(0, crtc_list[0]->regs + SMICS);
++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
++ vc4_crtc_irq_handler, 0,
++ "vc4 firmware kms", crtc_list);
++ if (ret)
++ DRM_ERROR("Oh dear, failed to register IRQ\n");
++ } else {
++ DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n");
++ }
+
+ platform_set_drvdata(pdev, crtc_list);
+
+++ /dev/null
-From b4ffa49d762a4af832d0d8660caf59722c0ff75a Mon Sep 17 00:00:00 2001
-Date: Tue, 21 May 2019 11:50:00 +0100
-Subject: [PATCH] drm: vc4: Probe DPI/DSI timings from the firmware
-
-For DPI and DSI displays query the firmware as to the configuration
-and add it as the only mode for DRM.
-
-In theory we can add plumbing for setting the DPI/DSI mode from
-KMS, but this is not being added at present as the support frameworks
-aren't present in the firmware.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 60 ++++++++++++++++++----
- include/soc/bcm2835/raspberrypi-firmware.h | 1 +
- 2 files changed, 51 insertions(+), 10 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -280,7 +280,7 @@ static u32 vc4_get_display_type(u32 disp
- /* The firmware display (DispmanX) IDs map to specific types in
- * a fixed manner.
- */
-- DRM_MODE_ENCODER_DSI, /* MAIN_LCD */
-+ DRM_MODE_ENCODER_DSI, /* MAIN_LCD - DSI or DPI */
- DRM_MODE_ENCODER_DSI, /* AUX_LCD */
- DRM_MODE_ENCODER_TMDS, /* HDMI0 */
- DRM_MODE_ENCODER_TVDAC, /* VEC */
-@@ -362,7 +362,6 @@ static void vc4_plane_atomic_update(stru
- vc4_get_vc_image_fmt(drm_fmt->format);
- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
- struct mailbox_set_plane *mb = &vc4_plane->mb;
-- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
- int num_planes = fb->format->num_planes;
- struct drm_display_mode *mode = &state->crtc->mode;
- unsigned int rotation = SUPPORTED_ROTATIONS;
-@@ -997,7 +996,9 @@ static int vc4_fkms_connector_get_modes(
- return ret;
- }
-
--/* FIXME: Read LCD mode from the firmware. This is the DSI panel resolution. */
-+/* This is the DSI panel resolution. Use this as a default should the firmware
-+ * not respond to our request for the timings.
-+ */
- static const struct drm_display_mode lcd_mode = {
- DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
- 25979400 / 1000,
-@@ -1008,15 +1009,54 @@ static const struct drm_display_mode lcd
-
- static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
- {
-- //struct vc4_fkms_connector *fkms_connector =
-- // to_vc4_fkms_connector(connector);
-- //struct drm_encoder *encoder = fkms_connector->encoder;
-- //struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
-+ struct vc4_fkms_connector *fkms_connector =
-+ to_vc4_fkms_connector(connector);
-+ struct vc4_dev *vc4 = fkms_connector->vc4_dev;
- struct drm_display_mode *mode;
-- //int ret = 0;
-+ struct mailbox_set_mode mb = {
-+ .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING,
-+ sizeof(struct set_timings), 0},
-+ .timings = { .display = fkms_connector->display_number },
-+ };
-+ struct drm_display_mode fw_mode;
-+ int ret = 0;
-+
-+ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
-+ if (!ret) {
-+ /* Equivalent to DRM_MODE macro. */
-+ memset(&fw_mode, 0, sizeof(fw_mode));
-+ strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name));
-+ fw_mode.status = 0;
-+ fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-+ fw_mode.clock = mb.timings.clock;
-+ fw_mode.hdisplay = mb.timings.hdisplay;
-+ fw_mode.hsync_start = mb.timings.hsync_start;
-+ fw_mode.hsync_end = mb.timings.hsync_end;
-+ fw_mode.htotal = mb.timings.htotal;
-+ fw_mode.hskew = 0;
-+ fw_mode.vdisplay = mb.timings.vdisplay;
-+ fw_mode.vsync_start = mb.timings.vsync_start;
-+ fw_mode.vsync_end = mb.timings.vsync_end;
-+ fw_mode.vtotal = mb.timings.vtotal;
-+ fw_mode.vscan = mb.timings.vscan;
-+ if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
-+ fw_mode.flags |= DRM_MODE_FLAG_PHSYNC;
-+ else
-+ fw_mode.flags |= DRM_MODE_FLAG_NHSYNC;
-+ if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
-+ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
-+ else
-+ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
-+
-+ fw_mode.base.type = DRM_MODE_OBJECT_MODE;
-+
-+ mode = drm_mode_duplicate(connector->dev,
-+ &fw_mode);
-+ } else {
-+ mode = drm_mode_duplicate(connector->dev,
-+ &lcd_mode);
-+ }
-
-- mode = drm_mode_duplicate(connector->dev,
-- &lcd_mode);
- if (!mode) {
- DRM_ERROR("Failed to create a new display mode\n");
- return -ENOMEM;
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -151,6 +151,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
-
- RPI_FIRMWARE_SET_PLANE = 0x00048015,
-+ RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
- RPI_FIRMWARE_SET_TIMING = 0x00048017,
-
- RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
--- /dev/null
+From 82ef7a95f5ae86df811253d58d93ca4fb2cbd45a Mon Sep 17 00:00:00 2001
+Date: Fri, 24 May 2019 17:59:01 +0100
+Subject: [PATCH] drm/vc4: Support the VEC in FKMS
+
+Extends the DPI/DSI support to also report the VEC output
+which supports interlacing too.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -125,6 +125,7 @@ struct set_timings {
+ #define TIMINGS_FLAGS_H_SYNC_NEG 0
+ #define TIMINGS_FLAGS_V_SYNC_POS BIT(1)
+ #define TIMINGS_FLAGS_V_SYNC_NEG 0
++#define TIMINGS_FLAGS_INTERLACE BIT(2)
+
+ #define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4)
+ #define TIMINGS_FLAGS_ASPECT_NONE (0 << 4)
+@@ -1047,6 +1048,12 @@ static int vc4_fkms_lcd_connector_get_mo
+ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
+ else
+ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
++ if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
++ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
++ else
++ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
++ if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE)
++ fw_mode.flags |= DRM_MODE_FLAG_INTERLACE;
+
+ fw_mode.base.type = DRM_MODE_OBJECT_MODE;
+
+@@ -1133,17 +1140,24 @@ vc4_fkms_connector_init(struct drm_devic
+ DRM_MODE_CONNECTOR_DSI);
+ drm_connector_helper_add(connector,
+ &vc4_fkms_lcd_conn_helper_funcs);
++ connector->interlace_allowed = 0;
++ } else if (fkms_connector->display_type == DRM_MODE_ENCODER_TVDAC) {
++ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
++ DRM_MODE_CONNECTOR_Composite);
++ drm_connector_helper_add(connector,
++ &vc4_fkms_lcd_conn_helper_funcs);
++ connector->interlace_allowed = 1;
+ } else {
+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ drm_connector_helper_add(connector,
+ &vc4_fkms_connector_helper_funcs);
++ connector->interlace_allowed = 0;
+ }
+
+ connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT);
+
+- connector->interlace_allowed = 0;
+ connector->doublescan_allowed = 0;
+
+ drm_connector_attach_encoder(connector, encoder);
--- /dev/null
+From 2d35ddcd988499ac7bfd08997086cecfc6b5acb3 Mon Sep 17 00:00:00 2001
+Date: Tue, 7 May 2019 15:00:02 +0100
+Subject: [PATCH] drm: vc4: Fixup typo when setting HDMI aspect ratio
+
+Assignment was to the wrong structure.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -717,19 +717,19 @@ static void vc4_crtc_mode_set_nofb(struc
+ switch (frame.avi.picture_aspect) {
+ default:
+ case HDMI_PICTURE_ASPECT_NONE:
+- mode->flags |= TIMINGS_FLAGS_ASPECT_NONE;
++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_NONE;
+ break;
+ case HDMI_PICTURE_ASPECT_4_3:
+- mode->flags |= TIMINGS_FLAGS_ASPECT_4_3;
++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_4_3;
+ break;
+ case HDMI_PICTURE_ASPECT_16_9:
+- mode->flags |= TIMINGS_FLAGS_ASPECT_16_9;
++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_16_9;
+ break;
+ case HDMI_PICTURE_ASPECT_64_27:
+- mode->flags |= TIMINGS_FLAGS_ASPECT_64_27;
++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_64_27;
+ break;
+ case HDMI_PICTURE_ASPECT_256_135:
+- mode->flags |= TIMINGS_FLAGS_ASPECT_256_135;
++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_256_135;
+ break;
+ }
+
+++ /dev/null
-From dd99aa50a3ea7f7fe1ddfd59b1a2e969c744b8a0 Mon Sep 17 00:00:00 2001
-Date: Tue, 28 May 2019 13:56:06 +0100
-Subject: [PATCH] drm: vc4: handle the case where there are no
- available displays
-
-It's reasonable for the firmware to return zero as the number of
-attached displays. Handle this case as otherwise drm thinks that
-the DSI panel is attached, which is nonsense.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 32 +++++++++++++++-----------
- 1 file changed, 18 insertions(+), 14 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1309,13 +1309,13 @@ static int vc4_fkms_bind(struct device *
- RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
- &num_displays, sizeof(u32));
-
-- /* If we fail to get the number of displays, or it returns 0, then
-+ /* If we fail to get the number of displays, then
- * assume old firmware that doesn't have the mailbox call, so just
- * set one display
- */
-- if (ret || num_displays == 0) {
-+ if (ret) {
- num_displays = 1;
-- DRM_WARN("Unable to determine number of displays's. Assuming 1\n");
-+ DRM_WARN("Unable to determine number of displays - assuming 1\n");
- ret = 0;
- }
-
-@@ -1344,17 +1344,21 @@ static int vc4_fkms_bind(struct device *
- display_num);
- }
-
-- /* Map the SMI interrupt reg */
-- crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
-- if (IS_ERR(crtc_list[0]->regs))
-- DRM_ERROR("Oh dear, failed to map registers\n");
--
-- writel(0, crtc_list[0]->regs + SMICS);
-- ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
-- vc4_crtc_irq_handler, 0, "vc4 firmware kms",
-- crtc_list);
-- if (ret)
-- DRM_ERROR("Oh dear, failed to register IRQ\n");
-+ if (num_displays > 0) {
-+ /* Map the SMI interrupt reg */
-+ crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
-+ if (IS_ERR(crtc_list[0]->regs))
-+ DRM_ERROR("Oh dear, failed to map registers\n");
-+
-+ writel(0, crtc_list[0]->regs + SMICS);
-+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
-+ vc4_crtc_irq_handler, 0,
-+ "vc4 firmware kms", crtc_list);
-+ if (ret)
-+ DRM_ERROR("Oh dear, failed to register IRQ\n");
-+ } else {
-+ DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n");
-+ }
-
- platform_set_drvdata(pdev, crtc_list);
-
--- /dev/null
+From 0dbdeb9e76e956df275e162224e12eacb0cc8b02 Mon Sep 17 00:00:00 2001
+Date: Wed, 29 May 2019 15:44:11 +0100
+Subject: [PATCH] drm/vc4: Correct SAND support for FKMS.
+
+It was accepting NV21 which doesn't map through, but
+also wasn't advertising the modifier so nothing would know
+to request it.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -545,7 +545,6 @@ static bool vc4_fkms_format_mod_supporte
+ return false;
+ }
+ case DRM_FORMAT_NV12:
+- case DRM_FORMAT_NV21:
+ switch (fourcc_mod_broadcom_mod(modifier)) {
+ case DRM_FORMAT_MOD_LINEAR:
+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
+@@ -553,6 +552,7 @@ static bool vc4_fkms_format_mod_supporte
+ default:
+ return false;
+ }
++ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_BGR888:
+ case DRM_FORMAT_YUV422:
+@@ -599,6 +599,7 @@ static struct drm_plane *vc4_fkms_plane_
+ * would prefer to scan out linear (less bus traffic).
+ */
+ DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
++ DRM_FORMAT_MOD_BROADCOM_SAND128,
+ DRM_FORMAT_MOD_INVALID,
+ };
+ int i;
+++ /dev/null
-From 82ef7a95f5ae86df811253d58d93ca4fb2cbd45a Mon Sep 17 00:00:00 2001
-Date: Fri, 24 May 2019 17:59:01 +0100
-Subject: [PATCH] drm/vc4: Support the VEC in FKMS
-
-Extends the DPI/DSI support to also report the VEC output
-which supports interlacing too.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++++-
- 1 file changed, 15 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -125,6 +125,7 @@ struct set_timings {
- #define TIMINGS_FLAGS_H_SYNC_NEG 0
- #define TIMINGS_FLAGS_V_SYNC_POS BIT(1)
- #define TIMINGS_FLAGS_V_SYNC_NEG 0
-+#define TIMINGS_FLAGS_INTERLACE BIT(2)
-
- #define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4)
- #define TIMINGS_FLAGS_ASPECT_NONE (0 << 4)
-@@ -1047,6 +1048,12 @@ static int vc4_fkms_lcd_connector_get_mo
- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
- else
- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
-+ if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
-+ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
-+ else
-+ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
-+ if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE)
-+ fw_mode.flags |= DRM_MODE_FLAG_INTERLACE;
-
- fw_mode.base.type = DRM_MODE_OBJECT_MODE;
-
-@@ -1133,17 +1140,24 @@ vc4_fkms_connector_init(struct drm_devic
- DRM_MODE_CONNECTOR_DSI);
- drm_connector_helper_add(connector,
- &vc4_fkms_lcd_conn_helper_funcs);
-+ connector->interlace_allowed = 0;
-+ } else if (fkms_connector->display_type == DRM_MODE_ENCODER_TVDAC) {
-+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
-+ DRM_MODE_CONNECTOR_Composite);
-+ drm_connector_helper_add(connector,
-+ &vc4_fkms_lcd_conn_helper_funcs);
-+ connector->interlace_allowed = 1;
- } else {
- drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA);
- drm_connector_helper_add(connector,
- &vc4_fkms_connector_helper_funcs);
-+ connector->interlace_allowed = 0;
- }
-
- connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
- DRM_CONNECTOR_POLL_DISCONNECT);
-
-- connector->interlace_allowed = 0;
- connector->doublescan_allowed = 0;
-
- drm_connector_attach_encoder(connector, encoder);
+++ /dev/null
-From 2d35ddcd988499ac7bfd08997086cecfc6b5acb3 Mon Sep 17 00:00:00 2001
-Date: Tue, 7 May 2019 15:00:02 +0100
-Subject: [PATCH] drm: vc4: Fixup typo when setting HDMI aspect ratio
-
-Assignment was to the wrong structure.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -717,19 +717,19 @@ static void vc4_crtc_mode_set_nofb(struc
- switch (frame.avi.picture_aspect) {
- default:
- case HDMI_PICTURE_ASPECT_NONE:
-- mode->flags |= TIMINGS_FLAGS_ASPECT_NONE;
-+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_NONE;
- break;
- case HDMI_PICTURE_ASPECT_4_3:
-- mode->flags |= TIMINGS_FLAGS_ASPECT_4_3;
-+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_4_3;
- break;
- case HDMI_PICTURE_ASPECT_16_9:
-- mode->flags |= TIMINGS_FLAGS_ASPECT_16_9;
-+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_16_9;
- break;
- case HDMI_PICTURE_ASPECT_64_27:
-- mode->flags |= TIMINGS_FLAGS_ASPECT_64_27;
-+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_64_27;
- break;
- case HDMI_PICTURE_ASPECT_256_135:
-- mode->flags |= TIMINGS_FLAGS_ASPECT_256_135;
-+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_256_135;
- break;
- }
-
--- /dev/null
+From 23e6a2c2d33050255c76a499ea080e5279d6edfc Mon Sep 17 00:00:00 2001
+Date: Thu, 30 May 2019 13:56:15 +0100
+Subject: [PATCH] drm/vc4: fkms to query the VPU for HDMI clock limits
+
+The VPU has configured clocks for 4k (or not) via config.txt,
+and will limit the choice of video modes based on that.
+Make fkms query it for these limits too to avoid selecting modes
+that can not be handled by the current clock setup.
+
+---
+ drivers/gpu/drm/vc4/vc4_drv.h | 1 +
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++++++
+ include/soc/bcm2835/raspberrypi-firmware.h | 1 +
+ 3 files changed, 50 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -77,6 +77,7 @@ struct vc4_dev {
+ struct vc4_dsi *dsi1;
+ struct vc4_vec *vec;
+ struct vc4_txp *txp;
++ struct vc4_fkms *fkms;
+
+ struct vc4_hang_state *hang_state;
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -29,6 +29,14 @@
+ #include "vc_image_types.h"
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
++struct get_display_cfg {
++ u32 max_pixel_clock[2]; //Max pixel clock for each display
++};
++
++struct vc4_fkms {
++ struct get_display_cfg cfg;
++};
++
+ #define PLANES_PER_CRTC 3
+
+ struct set_plane {
+@@ -794,6 +802,11 @@ static void vc4_crtc_enable(struct drm_c
+ static enum drm_mode_status
+ vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
+ {
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++ struct drm_device *dev = crtc->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_fkms *fkms = vc4->fkms;
++
+ /* Do not allow doublescan modes from user space */
+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
+ DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
+@@ -801,6 +814,22 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ return MODE_NO_DBLESCAN;
+ }
+
++ /* Limit the pixel clock based on the HDMI clock limits from the
++ * firmware
++ */
++ switch (vc4_crtc->display_number) {
++ case 2: /* HDMI0 */
++ if (fkms->cfg.max_pixel_clock[0] &&
++ mode->clock > fkms->cfg.max_pixel_clock[0])
++ return MODE_CLOCK_HIGH;
++ break;
++ case 7: /* HDMI1 */
++ if (fkms->cfg.max_pixel_clock[1] &&
++ mode->clock > fkms->cfg.max_pixel_clock[1])
++ return MODE_CLOCK_HIGH;
++ break;
++ }
++
+ /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling
+ * working.
+ */
+@@ -1301,11 +1330,16 @@ static int vc4_fkms_bind(struct device *
+ struct device_node *firmware_node;
+ struct vc4_crtc **crtc_list;
+ u32 num_displays, display_num;
++ struct vc4_fkms *fkms;
+ int ret;
+ u32 display_id;
+
+ vc4->firmware_kms = true;
+
++ fkms = devm_kzalloc(dev, sizeof(*fkms), GFP_KERNEL);
++ if (!fkms)
++ return -ENOMEM;
++
+ /* firmware kms doesn't have precise a scanoutpos implementation, so
+ * we can't do the precise vblank timestamp mode.
+ */
+@@ -1334,6 +1368,18 @@ static int vc4_fkms_bind(struct device *
+ ret = 0;
+ }
+
++ ret = rpi_firmware_property(vc4->firmware,
++ RPI_FIRMWARE_GET_DISPLAY_CFG,
++ &fkms->cfg, sizeof(fkms->cfg));
++
++ if (ret)
++ return -EINVAL;
++ /* The firmware works in Hz. This will be compared against kHz, so div
++ * 1000 now rather than multiple times later.
++ */
++ fkms->cfg.max_pixel_clock[0] /= 1000;
++ fkms->cfg.max_pixel_clock[1] /= 1000;
++
+ /* Allocate a list, with space for a NULL on the end */
+ crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
+ GFP_KERNEL);
+@@ -1375,6 +1421,8 @@ static int vc4_fkms_bind(struct device *
+ DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n");
+ }
+
++ vc4->fkms = fkms;
++
+ platform_set_drvdata(pdev, crtc_list);
+
+ return 0;
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -153,6 +153,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_SET_PLANE = 0x00048015,
+ RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
+ RPI_FIRMWARE_SET_TIMING = 0x00048017,
++ RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018,
+
+ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
+ RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
+++ /dev/null
-From 0dbdeb9e76e956df275e162224e12eacb0cc8b02 Mon Sep 17 00:00:00 2001
-Date: Wed, 29 May 2019 15:44:11 +0100
-Subject: [PATCH] drm/vc4: Correct SAND support for FKMS.
-
-It was accepting NV21 which doesn't map through, but
-also wasn't advertising the modifier so nothing would know
-to request it.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -545,7 +545,6 @@ static bool vc4_fkms_format_mod_supporte
- return false;
- }
- case DRM_FORMAT_NV12:
-- case DRM_FORMAT_NV21:
- switch (fourcc_mod_broadcom_mod(modifier)) {
- case DRM_FORMAT_MOD_LINEAR:
- case DRM_FORMAT_MOD_BROADCOM_SAND128:
-@@ -553,6 +552,7 @@ static bool vc4_fkms_format_mod_supporte
- default:
- return false;
- }
-+ case DRM_FORMAT_NV21:
- case DRM_FORMAT_RGB888:
- case DRM_FORMAT_BGR888:
- case DRM_FORMAT_YUV422:
-@@ -599,6 +599,7 @@ static struct drm_plane *vc4_fkms_plane_
- * would prefer to scan out linear (less bus traffic).
- */
- DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
-+ DRM_FORMAT_MOD_BROADCOM_SAND128,
- DRM_FORMAT_MOD_INVALID,
- };
- int i;
--- /dev/null
+From bce8c3dc146e3287519d5f6bb965dc2458e6684d Mon Sep 17 00:00:00 2001
+Date: Thu, 30 May 2019 15:55:15 +0100
+Subject: [PATCH] drm/vc4: Max resolution of 7680 is conditional on
+ being Pi4
+
+The max resolution had been increased from 2048 to 7680 for all
+platforms. This code is common with Pi0-3 which have a max render
+target for GL of 2048, therefore the increased resolution has to
+be conditional on the platform.
+Switch based on whether the bcm2835-v3d node is found, as that is
+not present on Pi4. (There is a potential configuration on Pi0-3
+with no v3d, but this is very unlikely).
+
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -429,8 +429,14 @@ int vc4_kms_load(struct drm_device *dev)
+ return ret;
+ }
+
+- dev->mode_config.max_width = 7680;
+- dev->mode_config.max_height = 7680;
++ if (!drm_core_check_feature(dev, DRIVER_RENDER)) {
++ /* No V3D as part of vc4. Assume this is Pi4. */
++ dev->mode_config.max_width = 7680;
++ dev->mode_config.max_height = 7680;
++ } else {
++ dev->mode_config.max_width = 2048;
++ dev->mode_config.max_height = 2048;
++ }
+ dev->mode_config.funcs = &vc4_mode_funcs;
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.async_page_flip = true;
+++ /dev/null
-From 23e6a2c2d33050255c76a499ea080e5279d6edfc Mon Sep 17 00:00:00 2001
-Date: Thu, 30 May 2019 13:56:15 +0100
-Subject: [PATCH] drm/vc4: fkms to query the VPU for HDMI clock limits
-
-The VPU has configured clocks for 4k (or not) via config.txt,
-and will limit the choice of video modes based on that.
-Make fkms query it for these limits too to avoid selecting modes
-that can not be handled by the current clock setup.
-
----
- drivers/gpu/drm/vc4/vc4_drv.h | 1 +
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++++++
- include/soc/bcm2835/raspberrypi-firmware.h | 1 +
- 3 files changed, 50 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -77,6 +77,7 @@ struct vc4_dev {
- struct vc4_dsi *dsi1;
- struct vc4_vec *vec;
- struct vc4_txp *txp;
-+ struct vc4_fkms *fkms;
-
- struct vc4_hang_state *hang_state;
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -29,6 +29,14 @@
- #include "vc_image_types.h"
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
-+struct get_display_cfg {
-+ u32 max_pixel_clock[2]; //Max pixel clock for each display
-+};
-+
-+struct vc4_fkms {
-+ struct get_display_cfg cfg;
-+};
-+
- #define PLANES_PER_CRTC 3
-
- struct set_plane {
-@@ -794,6 +802,11 @@ static void vc4_crtc_enable(struct drm_c
- static enum drm_mode_status
- vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
- {
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-+ struct drm_device *dev = crtc->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct vc4_fkms *fkms = vc4->fkms;
-+
- /* Do not allow doublescan modes from user space */
- if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
- DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
-@@ -801,6 +814,22 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
- return MODE_NO_DBLESCAN;
- }
-
-+ /* Limit the pixel clock based on the HDMI clock limits from the
-+ * firmware
-+ */
-+ switch (vc4_crtc->display_number) {
-+ case 2: /* HDMI0 */
-+ if (fkms->cfg.max_pixel_clock[0] &&
-+ mode->clock > fkms->cfg.max_pixel_clock[0])
-+ return MODE_CLOCK_HIGH;
-+ break;
-+ case 7: /* HDMI1 */
-+ if (fkms->cfg.max_pixel_clock[1] &&
-+ mode->clock > fkms->cfg.max_pixel_clock[1])
-+ return MODE_CLOCK_HIGH;
-+ break;
-+ }
-+
- /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling
- * working.
- */
-@@ -1301,11 +1330,16 @@ static int vc4_fkms_bind(struct device *
- struct device_node *firmware_node;
- struct vc4_crtc **crtc_list;
- u32 num_displays, display_num;
-+ struct vc4_fkms *fkms;
- int ret;
- u32 display_id;
-
- vc4->firmware_kms = true;
-
-+ fkms = devm_kzalloc(dev, sizeof(*fkms), GFP_KERNEL);
-+ if (!fkms)
-+ return -ENOMEM;
-+
- /* firmware kms doesn't have precise a scanoutpos implementation, so
- * we can't do the precise vblank timestamp mode.
- */
-@@ -1334,6 +1368,18 @@ static int vc4_fkms_bind(struct device *
- ret = 0;
- }
-
-+ ret = rpi_firmware_property(vc4->firmware,
-+ RPI_FIRMWARE_GET_DISPLAY_CFG,
-+ &fkms->cfg, sizeof(fkms->cfg));
-+
-+ if (ret)
-+ return -EINVAL;
-+ /* The firmware works in Hz. This will be compared against kHz, so div
-+ * 1000 now rather than multiple times later.
-+ */
-+ fkms->cfg.max_pixel_clock[0] /= 1000;
-+ fkms->cfg.max_pixel_clock[1] /= 1000;
-+
- /* Allocate a list, with space for a NULL on the end */
- crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
- GFP_KERNEL);
-@@ -1375,6 +1421,8 @@ static int vc4_fkms_bind(struct device *
- DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n");
- }
-
-+ vc4->fkms = fkms;
-+
- platform_set_drvdata(pdev, crtc_list);
-
- return 0;
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -153,6 +153,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_SET_PLANE = 0x00048015,
- RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
- RPI_FIRMWARE_SET_TIMING = 0x00048017,
-+ RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018,
-
- RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
- RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
--- /dev/null
+From 84b54ee2ff01005f0201c51f50985faf4e79edc6 Mon Sep 17 00:00:00 2001
+Date: Mon, 10 Dec 2018 17:35:58 +0000
+Subject: [PATCH] staging: vc-sm-cma: Remove obsolete comment and make
+ function static
+
+Removes obsolete comment about wanting to pass a function
+pointer into mmal-vchiq as we now do.
+As the function is passed as a function pointer, the function itself
+can be static.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -594,8 +594,7 @@ error:
+ return ret;
+ }
+
+-/* FIXME: Pass a function pointer to this into vc_vchi_sm.c */
+-void
++static void
+ vc_sm_vpu_event(struct sm_instance *instance, struct vc_sm_result_t *reply,
+ int reply_len)
+ {
+++ /dev/null
-From bce8c3dc146e3287519d5f6bb965dc2458e6684d Mon Sep 17 00:00:00 2001
-Date: Thu, 30 May 2019 15:55:15 +0100
-Subject: [PATCH] drm/vc4: Max resolution of 7680 is conditional on
- being Pi4
-
-The max resolution had been increased from 2048 to 7680 for all
-platforms. This code is common with Pi0-3 which have a max render
-target for GL of 2048, therefore the increased resolution has to
-be conditional on the platform.
-Switch based on whether the bcm2835-v3d node is found, as that is
-not present on Pi4. (There is a potential configuration on Pi0-3
-with no v3d, but this is very unlikely).
-
----
- drivers/gpu/drm/vc4/vc4_kms.c | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -429,8 +429,14 @@ int vc4_kms_load(struct drm_device *dev)
- return ret;
- }
-
-- dev->mode_config.max_width = 7680;
-- dev->mode_config.max_height = 7680;
-+ if (!drm_core_check_feature(dev, DRIVER_RENDER)) {
-+ /* No V3D as part of vc4. Assume this is Pi4. */
-+ dev->mode_config.max_width = 7680;
-+ dev->mode_config.max_height = 7680;
-+ } else {
-+ dev->mode_config.max_width = 2048;
-+ dev->mode_config.max_height = 2048;
-+ }
- dev->mode_config.funcs = &vc4_mode_funcs;
- dev->mode_config.preferred_depth = 24;
- dev->mode_config.async_page_flip = true;
--- /dev/null
+From 275f4673d8c0601e5dbb16e743187d264e7dbed6 Mon Sep 17 00:00:00 2001
+Date: Fri, 21 Dec 2018 16:50:53 +0000
+Subject: [PATCH] staging: vc-sm-cma: Add in allocation for VPU
+ requests.
+
+Module has to change from tristate to bool as all CMA functions
+are boolean.
+
+---
+ .../staging/vc04_services/vc-sm-cma/Kconfig | 4 +-
+ .../staging/vc04_services/vc-sm-cma/Makefile | 2 +-
+ .../staging/vc04_services/vc-sm-cma/vc_sm.c | 642 +++++++++++++++---
+ .../staging/vc04_services/vc-sm-cma/vc_sm.h | 30 +-
+ .../vc04_services/vc-sm-cma/vc_sm_cma.c | 99 +++
+ .../vc04_services/vc-sm-cma/vc_sm_cma.h | 39 ++
+ .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 10 +
+ .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.h | 4 +
+ .../vc04_services/vc-sm-cma/vc_sm_defs.h | 2 +
+ 9 files changed, 723 insertions(+), 109 deletions(-)
+ create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
+ create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/Kconfig
++++ b/drivers/staging/vc04_services/vc-sm-cma/Kconfig
+@@ -1,6 +1,6 @@
+ config BCM_VC_SM_CMA
+- tristate "VideoCore Shared Memory (CMA) driver"
+- depends on BCM2835_VCHIQ
++ bool "VideoCore Shared Memory (CMA) driver"
++ depends on BCM2835_VCHIQ && DMA_CMA
+ select RBTREE
+ select DMA_SHARED_BUFFER
+ help
+--- a/drivers/staging/vc04_services/vc-sm-cma/Makefile
++++ b/drivers/staging/vc04_services/vc-sm-cma/Makefile
+@@ -3,6 +3,6 @@ ccflags-y += -Idrivers/staging/vc04_serv
+ ccflags-y += -D__VCCOREVER__=0
+
+ vc-sm-cma-$(CONFIG_BCM_VC_SM_CMA) := \
+- vc_sm.o vc_sm_cma_vchi.o
++ vc_sm.o vc_sm_cma_vchi.o vc_sm_cma.o
+
+ obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma.o
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -9,10 +9,21 @@
+ * and taking some code for CMA/dmabuf handling from the Android Ion
+ * driver (Google/Linaro).
+ *
+- * This is cut down version to only support import of dma_bufs from
+- * other kernel drivers. A more complete implementation of the old
+- * vmcs_sm functionality can follow later.
+ *
++ * This driver has 3 main uses:
++ * 1) Allocating buffers for the kernel or userspace that can be shared with the
++ * VPU.
++ * 2) Importing dmabufs from elsewhere for sharing with the VPU.
++ * 3) Allocating buffers for use by the VPU.
++ *
++ * In the first and second cases the native handle is a dmabuf. Releasing the
++ * resource inherently comes from releasing the dmabuf, and this will trigger
++ * unmapping on the VPU. The underlying allocation and our buffer structure are
++ * retained until the VPU has confirmed that it has finished with it.
++ *
++ * For the VPU allocations the VPU is responsible for triggering the release,
++ * and therefore the released message decrements the dma_buf refcount (with the
++ * VPU mapping having already been marked as released).
+ */
+
+ /* ---- Include Files ----------------------------------------------------- */
+@@ -39,6 +50,7 @@
+ #include "vc_sm_cma_vchi.h"
+
+ #include "vc_sm.h"
++#include "vc_sm_cma.h"
+ #include "vc_sm_knl.h"
+
+ /* ---- Private Constants and Types --------------------------------------- */
+@@ -72,6 +84,7 @@ struct sm_state_t {
+ struct platform_device *pdev;
+
+ struct sm_instance *sm_handle; /* Handle for videocore service. */
++ struct cma *cma_heap;
+
+ spinlock_t kernelid_map_lock; /* Spinlock protecting kernelid_map */
+ struct idr kernelid_map;
+@@ -80,6 +93,7 @@ struct sm_state_t {
+ struct list_head buffer_list; /* List of buffer. */
+
+ struct vc_sm_privdata_t *data_knl; /* Kernel internal data tracking. */
++ struct vc_sm_privdata_t *vpu_allocs; /* All allocations from the VPU */
+ struct dentry *dir_root; /* Debug fs entries root. */
+ struct sm_pde_t dir_state; /* Debug fs entries state sub-tree. */
+
+@@ -89,6 +103,12 @@ struct sm_state_t {
+ u32 int_trans_id; /* Interrupted transaction. */
+ };
+
++struct vc_sm_dma_buf_attachment {
++ struct device *dev;
++ struct sg_table *table;
++ struct list_head list;
++};
++
+ /* ---- Private Variables ----------------------------------------------- */
+
+ static struct sm_state_t *sm_state;
+@@ -172,12 +192,14 @@ static int vc_sm_cma_global_state_show(s
+ resource->size);
+ seq_printf(s, " DMABUF %p\n",
+ resource->dma_buf);
+- seq_printf(s, " ATTACH %p\n",
+- resource->attach);
++ if (resource->imported) {
++ seq_printf(s, " ATTACH %p\n",
++ resource->import.attach);
++ seq_printf(s, " SGT %p\n",
++ resource->import.sgt);
++ }
+ seq_printf(s, " SG_TABLE %p\n",
+ resource->sg_table);
+- seq_printf(s, " SGT %p\n",
+- resource->sgt);
+ seq_printf(s, " DMA_ADDR %pad\n",
+ &resource->dma_addr);
+ seq_printf(s, " VC_HANDLE %08x\n",
+@@ -209,17 +231,33 @@ static void vc_sm_add_resource(struct vc
+ }
+
+ /*
+- * Release an allocation.
+- * All refcounting is done via the dma buf object.
++ * Cleans up imported dmabuf.
+ */
+-static void vc_sm_release_resource(struct vc_sm_buffer *buffer, int force)
++static void vc_sm_clean_up_dmabuf(struct vc_sm_buffer *buffer)
+ {
+- mutex_lock(&sm_state->map_lock);
+- mutex_lock(&buffer->lock);
++ if (!buffer->imported)
++ return;
+
+- pr_debug("[%s]: buffer %p (name %s, size %zu)\n",
+- __func__, buffer, buffer->name, buffer->size);
++ /* Handle cleaning up imported dmabufs */
++ mutex_lock(&buffer->lock);
++ if (buffer->import.sgt) {
++ dma_buf_unmap_attachment(buffer->import.attach,
++ buffer->import.sgt,
++ DMA_BIDIRECTIONAL);
++ buffer->import.sgt = NULL;
++ }
++ if (buffer->import.attach) {
++ dma_buf_detach(buffer->dma_buf, buffer->import.attach);
++ buffer->import.attach = NULL;
++ }
++ mutex_unlock(&buffer->lock);
++}
+
++/*
++ * Instructs VPU to decrement the refcount on a buffer.
++ */
++static void vc_sm_vpu_free(struct vc_sm_buffer *buffer)
++{
+ if (buffer->vc_handle && buffer->vpu_state == VPU_MAPPED) {
+ struct vc_sm_free_t free = { buffer->vc_handle, 0 };
+ int status = vc_sm_cma_vchi_free(sm_state->sm_handle, &free,
+@@ -230,17 +268,32 @@ static void vc_sm_release_resource(struc
+ }
+
+ if (sm_state->require_released_callback) {
+- /* Need to wait for the VPU to confirm the free */
++ /* Need to wait for the VPU to confirm the free. */
+
+ /* Retain a reference on this until the VPU has
+ * released it
+ */
+ buffer->vpu_state = VPU_UNMAPPING;
+- goto defer;
++ } else {
++ buffer->vpu_state = VPU_NOT_MAPPED;
++ buffer->vc_handle = 0;
+ }
+- buffer->vpu_state = VPU_NOT_MAPPED;
+- buffer->vc_handle = 0;
+ }
++}
++
++/*
++ * Release an allocation.
++ * All refcounting is done via the dma buf object.
++ *
++ * Must be called with the mutex held. The function will either release the
++ * mutex (if defering the release) or destroy it. The caller must therefore not
++ * reuse the buffer on return.
++ */
++static void vc_sm_release_resource(struct vc_sm_buffer *buffer)
++{
++ pr_debug("[%s]: buffer %p (name %s, size %zu)\n",
++ __func__, buffer, buffer->name, buffer->size);
++
+ if (buffer->vc_handle) {
+ /* We've sent the unmap request but not had the response. */
+ pr_err("[%s]: Waiting for VPU unmap response on %p\n",
+@@ -248,45 +301,43 @@ static void vc_sm_release_resource(struc
+ goto defer;
+ }
+ if (buffer->in_use) {
+- /* Don't release dmabuf here - we await the release */
++ /* dmabuf still in use - we await the release */
+ pr_err("[%s]: buffer %p is still in use\n",
+ __func__, buffer);
+ goto defer;
+ }
+
+- /* Handle cleaning up imported dmabufs */
+- if (buffer->sgt) {
+- dma_buf_unmap_attachment(buffer->attach, buffer->sgt,
+- DMA_BIDIRECTIONAL);
+- buffer->sgt = NULL;
+- }
+- if (buffer->attach) {
+- dma_buf_detach(buffer->dma_buf, buffer->attach);
+- buffer->attach = NULL;
+- }
+-
+- /* Release the dma_buf (whether ours or imported) */
+- if (buffer->import_dma_buf) {
+- dma_buf_put(buffer->import_dma_buf);
+- buffer->import_dma_buf = NULL;
+- buffer->dma_buf = NULL;
+- } else if (buffer->dma_buf) {
+- dma_buf_put(buffer->dma_buf);
+- buffer->dma_buf = NULL;
++ /* Release the allocation (whether imported dmabuf or CMA allocation) */
++ if (buffer->imported) {
++ pr_debug("%s: Release imported dmabuf %p\n", __func__,
++ buffer->import.dma_buf);
++ if (buffer->import.dma_buf)
++ dma_buf_put(buffer->import.dma_buf);
++ else
++ pr_err("%s: Imported dmabuf already been put for buf %p\n",
++ __func__, buffer);
++ buffer->import.dma_buf = NULL;
++ } else {
++ if (buffer->sg_table) {
++ /* Our own allocation that we need to dma_unmap_sg */
++ dma_unmap_sg(&sm_state->pdev->dev,
++ buffer->sg_table->sgl,
++ buffer->sg_table->nents,
++ DMA_BIDIRECTIONAL);
++ }
++ pr_debug("%s: Release our allocation\n", __func__);
++ vc_sm_cma_buffer_free(&buffer->alloc);
++ pr_debug("%s: Release our allocation - done\n", __func__);
+ }
+
+- if (buffer->sg_table && !buffer->import_dma_buf) {
+- /* Our own allocation that we need to dma_unmap_sg */
+- dma_unmap_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
+- buffer->sg_table->nents, DMA_BIDIRECTIONAL);
+- }
+
+- /* Free the local resource. Start by removing it from the list */
+- buffer->private = NULL;
++ /* Free our buffer. Start by removing it from the list */
++ mutex_lock(&sm_state->map_lock);
+ list_del(&buffer->global_buffer_list);
++ mutex_unlock(&sm_state->map_lock);
+
++ pr_debug("%s: Release our allocation - done\n", __func__);
+ mutex_unlock(&buffer->lock);
+- mutex_unlock(&sm_state->map_lock);
+
+ mutex_destroy(&buffer->lock);
+
+@@ -295,7 +346,7 @@ static void vc_sm_release_resource(struc
+
+ defer:
+ mutex_unlock(&buffer->lock);
+- mutex_unlock(&sm_state->map_lock);
++ return;
+ }
+
+ /* Create support for private data tracking. */
+@@ -317,16 +368,267 @@ static struct vc_sm_privdata_t *vc_sm_cm
+ return file_data;
+ }
+
++static struct sg_table *dup_sg_table(struct sg_table *table)
++{
++ struct sg_table *new_table;
++ int ret, i;
++ struct scatterlist *sg, *new_sg;
++
++ new_table = kzalloc(sizeof(*new_table), GFP_KERNEL);
++ if (!new_table)
++ return ERR_PTR(-ENOMEM);
++
++ ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
++ if (ret) {
++ kfree(new_table);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ new_sg = new_table->sgl;
++ for_each_sg(table->sgl, sg, table->nents, i) {
++ memcpy(new_sg, sg, sizeof(*sg));
++ sg->dma_address = 0;
++ new_sg = sg_next(new_sg);
++ }
++
++ return new_table;
++}
++
++static void free_duped_table(struct sg_table *table)
++{
++ sg_free_table(table);
++ kfree(table);
++}
++
++/* Dma buf operations for use with our own allocations */
++
++static int vc_sm_dma_buf_attach(struct dma_buf *dmabuf,
++ struct dma_buf_attachment *attachment)
++
++{
++ struct vc_sm_dma_buf_attachment *a;
++ struct sg_table *table;
++ struct vc_sm_buffer *buf = dmabuf->priv;
++
++ a = kzalloc(sizeof(*a), GFP_KERNEL);
++ if (!a)
++ return -ENOMEM;
++
++ table = dup_sg_table(buf->sg_table);
++ if (IS_ERR(table)) {
++ kfree(a);
++ return -ENOMEM;
++ }
++
++ a->table = table;
++ INIT_LIST_HEAD(&a->list);
++
++ attachment->priv = a;
++
++ mutex_lock(&buf->lock);
++ list_add(&a->list, &buf->attachments);
++ mutex_unlock(&buf->lock);
++ pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
++
++ return 0;
++}
++
++static void vc_sm_dma_buf_detatch(struct dma_buf *dmabuf,
++ struct dma_buf_attachment *attachment)
++{
++ struct vc_sm_dma_buf_attachment *a = attachment->priv;
++ struct vc_sm_buffer *buf = dmabuf->priv;
++
++ pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
++ free_duped_table(a->table);
++ mutex_lock(&buf->lock);
++ list_del(&a->list);
++ mutex_unlock(&buf->lock);
++
++ kfree(a);
++}
++
++static struct sg_table *vc_sm_map_dma_buf(struct dma_buf_attachment *attachment,
++ enum dma_data_direction direction)
++{
++ struct vc_sm_dma_buf_attachment *a = attachment->priv;
++ struct sg_table *table;
++
++ table = a->table;
++
++ if (!dma_map_sg(attachment->dev, table->sgl, table->nents,
++ direction))
++ return ERR_PTR(-ENOMEM);
++
++ pr_debug("%s attachment %p\n", __func__, attachment);
++ return table;
++}
++
++static void vc_sm_unmap_dma_buf(struct dma_buf_attachment *attachment,
++ struct sg_table *table,
++ enum dma_data_direction direction)
++{
++ pr_debug("%s attachment %p\n", __func__, attachment);
++ dma_unmap_sg(attachment->dev, table->sgl, table->nents, direction);
++}
++
++static int vc_sm_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
++{
++ struct vc_sm_buffer *buf = dmabuf->priv;
++ struct sg_table *table = buf->sg_table;
++ unsigned long addr = vma->vm_start;
++ unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
++ struct scatterlist *sg;
++ int i;
++ int ret = 0;
++
++ pr_debug("%s dmabuf %p, buf %p, vm_start %08lX\n", __func__, dmabuf,
++ buf, addr);
++
++ mutex_lock(&buf->lock);
++
++ /* now map it to userspace */
++ for_each_sg(table->sgl, sg, table->nents, i) {
++ struct page *page = sg_page(sg);
++ unsigned long remainder = vma->vm_end - addr;
++ unsigned long len = sg->length;
++
++ if (offset >= sg->length) {
++ offset -= sg->length;
++ continue;
++ } else if (offset) {
++ page += offset / PAGE_SIZE;
++ len = sg->length - offset;
++ offset = 0;
++ }
++ len = min(len, remainder);
++ ret = remap_pfn_range(vma, addr, page_to_pfn(page), len,
++ vma->vm_page_prot);
++ if (ret)
++ break;
++ addr += len;
++ if (addr >= vma->vm_end)
++ break;
++ }
++ mutex_unlock(&buf->lock);
++
++ if (ret)
++ pr_err("%s: failure mapping buffer to userspace\n",
++ __func__);
++
++ return ret;
++}
++
++static void vc_sm_dma_buf_release(struct dma_buf *dmabuf)
++{
++ struct vc_sm_buffer *buffer;
++
++ if (!dmabuf)
++ return;
++
++ buffer = (struct vc_sm_buffer *)dmabuf->priv;
++
++ mutex_lock(&buffer->lock);
++
++ pr_debug("%s dmabuf %p, buffer %p\n", __func__, dmabuf, buffer);
++
++ buffer->in_use = 0;
++
++ /* Unmap on the VPU */
++ vc_sm_vpu_free(buffer);
++ pr_debug("%s vpu_free done\n", __func__);
++
++ /* Unmap our dma_buf object (the vc_sm_buffer remains until released
++ * on the VPU).
++ */
++ vc_sm_clean_up_dmabuf(buffer);
++ pr_debug("%s clean_up dmabuf done\n", __func__);
++
++ vc_sm_release_resource(buffer);
++ pr_debug("%s done\n", __func__);
++}
++
++static int vc_sm_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
++ enum dma_data_direction direction)
++{
++ struct vc_sm_buffer *buf;
++ struct vc_sm_dma_buf_attachment *a;
++
++ if (!dmabuf)
++ return -EFAULT;
++
++ buf = dmabuf->priv;
++ if (!buf)
++ return -EFAULT;
++
++ mutex_lock(&buf->lock);
++
++ list_for_each_entry(a, &buf->attachments, list) {
++ dma_sync_sg_for_cpu(a->dev, a->table->sgl, a->table->nents,
++ direction);
++ }
++ mutex_unlock(&buf->lock);
++
++ return 0;
++}
++
++static int vc_sm_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
++ enum dma_data_direction direction)
++{
++ struct vc_sm_buffer *buf;
++ struct vc_sm_dma_buf_attachment *a;
++
++ if (!dmabuf)
++ return -EFAULT;
++ buf = dmabuf->priv;
++ if (!buf)
++ return -EFAULT;
++
++ mutex_lock(&buf->lock);
++
++ list_for_each_entry(a, &buf->attachments, list) {
++ dma_sync_sg_for_device(a->dev, a->table->sgl, a->table->nents,
++ direction);
++ }
++ mutex_unlock(&buf->lock);
++
++ return 0;
++}
++
++static void *vc_sm_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset)
++{
++ /* FIXME */
++ return NULL;
++}
++
++static void vc_sm_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset,
++ void *ptr)
++{
++ /* FIXME */
++}
++
++static const struct dma_buf_ops dma_buf_ops = {
++ .map_dma_buf = vc_sm_map_dma_buf,
++ .unmap_dma_buf = vc_sm_unmap_dma_buf,
++ .mmap = vc_sm_dmabuf_mmap,
++ .release = vc_sm_dma_buf_release,
++ .attach = vc_sm_dma_buf_attach,
++ .detach = vc_sm_dma_buf_detatch,
++ .begin_cpu_access = vc_sm_dma_buf_begin_cpu_access,
++ .end_cpu_access = vc_sm_dma_buf_end_cpu_access,
++ .map = vc_sm_dma_buf_kmap,
++ .unmap = vc_sm_dma_buf_kunmap,
++};
+ /* Dma_buf operations for chaining through to an imported dma_buf */
+ static
+ int vc_sm_import_dma_buf_attach(struct dma_buf *dmabuf,
+ struct dma_buf_attachment *attachment)
+ {
+- struct vc_sm_buffer *res = dmabuf->priv;
++ struct vc_sm_buffer *buf = dmabuf->priv;
+
+- if (!res->import_dma_buf)
++ if (!buf->imported)
+ return -EINVAL;
+- return res->import_dma_buf->ops->attach(res->import_dma_buf,
++ return buf->import.dma_buf->ops->attach(buf->import.dma_buf,
+ attachment);
+ }
+
+@@ -334,22 +636,23 @@ static
+ void vc_sm_import_dma_buf_detatch(struct dma_buf *dmabuf,
+ struct dma_buf_attachment *attachment)
+ {
+- struct vc_sm_buffer *res = dmabuf->priv;
++ struct vc_sm_buffer *buf = dmabuf->priv;
+
+- if (!res->import_dma_buf)
++ if (!buf->imported)
+ return;
+- res->import_dma_buf->ops->detach(res->import_dma_buf, attachment);
++ buf->import.dma_buf->ops->detach(buf->import.dma_buf, attachment);
+ }
+
+ static
+ struct sg_table *vc_sm_import_map_dma_buf(struct dma_buf_attachment *attachment,
+ enum dma_data_direction direction)
+ {
+- struct vc_sm_buffer *res = attachment->dmabuf->priv;
++ struct vc_sm_buffer *buf = attachment->dmabuf->priv;
+
+- if (!res->import_dma_buf)
++ if (!buf->imported)
+ return NULL;
+- return res->import_dma_buf->ops->map_dma_buf(attachment, direction);
++ return buf->import.dma_buf->ops->map_dma_buf(attachment,
++ direction);
+ }
+
+ static
+@@ -357,87 +660,88 @@ void vc_sm_import_unmap_dma_buf(struct d
+ struct sg_table *table,
+ enum dma_data_direction direction)
+ {
+- struct vc_sm_buffer *res = attachment->dmabuf->priv;
++ struct vc_sm_buffer *buf = attachment->dmabuf->priv;
+
+- if (!res->import_dma_buf)
++ if (!buf->imported)
+ return;
+- res->import_dma_buf->ops->unmap_dma_buf(attachment, table, direction);
++ buf->import.dma_buf->ops->unmap_dma_buf(attachment, table, direction);
+ }
+
+ static
+ int vc_sm_import_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
+ {
+- struct vc_sm_buffer *res = dmabuf->priv;
++ struct vc_sm_buffer *buf = dmabuf->priv;
+
+- pr_debug("%s: mmap dma_buf %p, res %p, imported db %p\n", __func__,
+- dmabuf, res, res->import_dma_buf);
+- if (!res->import_dma_buf) {
++ pr_debug("%s: mmap dma_buf %p, buf %p, imported db %p\n", __func__,
++ dmabuf, buf, buf->import.dma_buf);
++ if (!buf->imported) {
+ pr_err("%s: mmap dma_buf %p- not an imported buffer\n",
+ __func__, dmabuf);
+ return -EINVAL;
+ }
+- return res->import_dma_buf->ops->mmap(res->import_dma_buf, vma);
++ return buf->import.dma_buf->ops->mmap(buf->import.dma_buf, vma);
+ }
+
+ static
+ void vc_sm_import_dma_buf_release(struct dma_buf *dmabuf)
+ {
+- struct vc_sm_buffer *res = dmabuf->priv;
++ struct vc_sm_buffer *buf = dmabuf->priv;
+
+ pr_debug("%s: Relasing dma_buf %p\n", __func__, dmabuf);
+- if (!res->import_dma_buf)
++ mutex_lock(&buf->lock);
++ if (!buf->imported)
+ return;
+
+- res->in_use = 0;
++ buf->in_use = 0;
+
+- vc_sm_release_resource(res, 0);
++ vc_sm_vpu_free(buf);
++
++ vc_sm_release_resource(buf);
+ }
+
+ static
+ void *vc_sm_import_dma_buf_kmap(struct dma_buf *dmabuf,
+ unsigned long offset)
+ {
+- struct vc_sm_buffer *res = dmabuf->priv;
++ struct vc_sm_buffer *buf = dmabuf->priv;
+
+- if (!res->import_dma_buf)
++ if (!buf->imported)
+ return NULL;
+- return res->import_dma_buf->ops->map(res->import_dma_buf,
+- offset);
++ return buf->import.dma_buf->ops->map(buf->import.dma_buf, offset);
+ }
+
+ static
+ void vc_sm_import_dma_buf_kunmap(struct dma_buf *dmabuf,
+ unsigned long offset, void *ptr)
+ {
+- struct vc_sm_buffer *res = dmabuf->priv;
++ struct vc_sm_buffer *buf = dmabuf->priv;
+
+- if (!res->import_dma_buf)
++ if (!buf->imported)
+ return;
+- res->import_dma_buf->ops->unmap(res->import_dma_buf,
+- offset, ptr);
++ buf->import.dma_buf->ops->unmap(buf->import.dma_buf, offset, ptr);
+ }
+
+ static
+ int vc_sm_import_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
+ enum dma_data_direction direction)
+ {
+- struct vc_sm_buffer *res = dmabuf->priv;
++ struct vc_sm_buffer *buf = dmabuf->priv;
+
+- if (!res->import_dma_buf)
++ if (!buf->imported)
+ return -EINVAL;
+- return res->import_dma_buf->ops->begin_cpu_access(res->import_dma_buf,
+- direction);
++ return buf->import.dma_buf->ops->begin_cpu_access(buf->import.dma_buf,
++ direction);
+ }
+
+ static
+ int vc_sm_import_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
+ enum dma_data_direction direction)
+ {
+- struct vc_sm_buffer *res = dmabuf->priv;
++ struct vc_sm_buffer *buf = dmabuf->priv;
+
+- if (!res->import_dma_buf)
++ if (!buf->imported)
+ return -EINVAL;
+- return res->import_dma_buf->ops->end_cpu_access(res->import_dma_buf,
++ return buf->import.dma_buf->ops->end_cpu_access(buf->import.dma_buf,
+ direction);
+ }
+
+@@ -516,9 +820,8 @@ vc_sm_cma_import_dmabuf_internal(struct
+ memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT,
+ sizeof(VC_SM_RESOURCE_NAME_DEFAULT));
+
+- pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %pad, size %u\n",
+- __func__, import.name, import.type, &dma_addr,
+- import.size);
++ pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %pad, size %u.\n",
++ __func__, import.name, import.type, &dma_addr, import.size);
+
+ /* Allocate the videocore buffer. */
+ status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result,
+@@ -548,12 +851,14 @@ vc_sm_cma_import_dmabuf_internal(struct
+ buffer->size = import.size;
+ buffer->vpu_state = VPU_MAPPED;
+
+- buffer->import_dma_buf = dma_buf;
++ buffer->imported = 1;
++ buffer->import.dma_buf = dma_buf;
+
+- buffer->attach = attach;
+- buffer->sgt = sgt;
++ buffer->import.attach = attach;
++ buffer->import.sgt = sgt;
+ buffer->dma_addr = dma_addr;
+ buffer->in_use = 1;
++ buffer->kernel_id = import.kernel_id;
+
+ /*
+ * We're done - we need to export a new dmabuf chaining through most
+@@ -594,6 +899,91 @@ error:
+ return ret;
+ }
+
++static int vc_sm_cma_vpu_alloc(u32 size, uint32_t align, const char *name,
++ u32 mem_handle, struct vc_sm_buffer **ret_buffer)
++{
++ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
++ struct vc_sm_buffer *buffer = NULL;
++ int aligned_size;
++ int ret = 0;
++
++ /* Align to the user requested align */
++ aligned_size = ALIGN(size, align);
++ /* and then to a page boundary */
++ aligned_size = PAGE_ALIGN(aligned_size);
++
++ if (!aligned_size)
++ return -EINVAL;
++
++ /* Allocate local buffer to track this allocation. */
++ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
++ if (!buffer)
++ return -ENOMEM;
++
++ mutex_init(&buffer->lock);
++
++ if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
++ aligned_size)) {
++ pr_err("[%s]: cma alloc of %d bytes failed\n",
++ __func__, aligned_size);
++ ret = -ENOMEM;
++ goto error;
++ }
++ buffer->sg_table = buffer->alloc.sg_table;
++
++ pr_debug("[%s]: cma alloc of %d bytes success\n",
++ __func__, aligned_size);
++
++ if (dma_map_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
++ buffer->sg_table->nents, DMA_BIDIRECTIONAL) <= 0) {
++ pr_err("[%s]: dma_map_sg failed\n", __func__);
++ goto error;
++ }
++
++ INIT_LIST_HEAD(&buffer->attachments);
++
++ memcpy(buffer->name, name,
++ min(sizeof(buffer->name), strlen(name)));
++
++ exp_info.ops = &dma_buf_ops;
++ exp_info.size = aligned_size;
++ exp_info.flags = O_RDWR;
++ exp_info.priv = buffer;
++
++ buffer->dma_buf = dma_buf_export(&exp_info);
++ if (IS_ERR(buffer->dma_buf)) {
++ ret = PTR_ERR(buffer->dma_buf);
++ goto error;
++ }
++ buffer->dma_addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
++ if ((buffer->dma_addr & 0xC0000000) != 0xC0000000) {
++ pr_err("%s: Expecting an uncached alias for dma_addr %pad\n",
++ __func__, &buffer->dma_addr);
++ buffer->dma_addr |= 0xC0000000;
++ }
++ buffer->private = sm_state->vpu_allocs;
++
++ buffer->vc_handle = mem_handle;
++ buffer->vpu_state = VPU_MAPPED;
++ buffer->vpu_allocated = 1;
++ buffer->size = size;
++ /*
++ * Create an ID that will be passed along with our message so
++ * that when we service the release reply, we can look up which
++ * resource is being released.
++ */
++ buffer->kernel_id = get_kernel_id(buffer);
++
++ vc_sm_add_resource(sm_state->vpu_allocs, buffer);
++
++ *ret_buffer = buffer;
++ return 0;
++error:
++ if (buffer)
++ vc_sm_release_resource(buffer);
++ return ret;
++}
++
+ static void
+ vc_sm_vpu_event(struct sm_instance *instance, struct vc_sm_result_t *reply,
+ int reply_len)
+@@ -612,21 +1002,61 @@ vc_sm_vpu_event(struct sm_instance *inst
+ struct vc_sm_released *release = (struct vc_sm_released *)reply;
+ struct vc_sm_buffer *buffer =
+ lookup_kernel_id(release->kernel_id);
++ if (!buffer) {
++ pr_err("%s: VC released a buffer that is already released, kernel_id %d\n",
++ __func__, release->kernel_id);
++ break;
++ }
++ mutex_lock(&buffer->lock);
+
+- /*
+- * FIXME: Need to check buffer is still valid and allocated
+- * before continuing
+- */
+ pr_debug("%s: Released addr %08x, size %u, id %08x, mem_handle %08x\n",
+ __func__, release->addr, release->size,
+ release->kernel_id, release->vc_handle);
+- mutex_lock(&buffer->lock);
++
+ buffer->vc_handle = 0;
+ buffer->vpu_state = VPU_NOT_MAPPED;
+- mutex_unlock(&buffer->lock);
+ free_kernel_id(release->kernel_id);
+
+- vc_sm_release_resource(buffer, 0);
++ if (buffer->vpu_allocated) {
++ /* VPU allocation, so release the dmabuf which will
++ * trigger the clean up.
++ */
++ mutex_unlock(&buffer->lock);
++ dma_buf_put(buffer->dma_buf);
++ } else {
++ vc_sm_release_resource(buffer);
++ }
++ }
++ break;
++ case VC_SM_MSG_TYPE_VC_MEM_REQUEST:
++ {
++ struct vc_sm_buffer *buffer = NULL;
++ struct vc_sm_vc_mem_request *req =
++ (struct vc_sm_vc_mem_request *)reply;
++ struct vc_sm_vc_mem_request_result reply;
++ int ret;
++
++ pr_debug("%s: Request %u bytes of memory, align %d name %s, trans_id %08x\n",
++ __func__, req->size, req->align, req->name,
++ req->trans_id);
++ ret = vc_sm_cma_vpu_alloc(req->size, req->align, req->name,
++ req->vc_handle, &buffer);
++
++ reply.trans_id = req->trans_id;
++ if (!ret) {
++ reply.addr = buffer->dma_addr;
++ reply.kernel_id = buffer->kernel_id;
++ pr_debug("%s: Allocated resource buffer %p, addr %pad\n",
++ __func__, buffer, &buffer->dma_addr);
++ } else {
++ pr_err("%s: Allocation failed size %u, name %s, vc_handle %u\n",
++ __func__, req->size, req->name, req->vc_handle);
++ reply.addr = 0;
++ reply.kernel_id = 0;
++ }
++ vc_sm_vchi_client_vc_mem_req_reply(sm_state->sm_handle, &reply,
++ &sm_state->int_trans_id);
++ break;
+ }
+ break;
+ default:
+@@ -645,6 +1075,14 @@ static void vc_sm_connected_init(void)
+
+ pr_info("[%s]: start\n", __func__);
+
++ if (vc_sm_cma_add_heaps(&sm_state->cma_heap) ||
++ !sm_state->cma_heap) {
++ pr_err("[%s]: failed to initialise CMA heaps\n",
++ __func__);
++ ret = -EIO;
++ goto err_free_mem;
++ }
++
+ /*
+ * Initialize and create a VCHI connection for the shared memory service
+ * running on videocore.
+@@ -696,7 +1134,7 @@ static void vc_sm_connected_init(void)
+ goto err_remove_shared_memory;
+ }
+
+- version.version = 1;
++ version.version = 2;
+ ret = vc_sm_cma_vchi_client_version(sm_state->sm_handle, &version,
+ &version_result,
+ &sm_state->int_trans_id);
+@@ -768,7 +1206,7 @@ static int bcm2835_vc_sm_cma_remove(stru
+ int vc_sm_cma_int_handle(void *handle)
+ {
+ struct dma_buf *dma_buf = (struct dma_buf *)handle;
+- struct vc_sm_buffer *res;
++ struct vc_sm_buffer *buf;
+
+ /* Validate we can work with this device. */
+ if (!sm_state || !handle) {
+@@ -776,8 +1214,8 @@ int vc_sm_cma_int_handle(void *handle)
+ return 0;
+ }
+
+- res = (struct vc_sm_buffer *)dma_buf->priv;
+- return res->vc_handle;
++ buf = (struct vc_sm_buffer *)dma_buf->priv;
++ return buf->vc_handle;
+ }
+ EXPORT_SYMBOL_GPL(vc_sm_cma_int_handle);
+
+@@ -804,7 +1242,7 @@ EXPORT_SYMBOL_GPL(vc_sm_cma_free);
+ int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, void **handle)
+ {
+ struct dma_buf *new_dma_buf;
+- struct vc_sm_buffer *res;
++ struct vc_sm_buffer *buf;
+ int ret;
+
+ /* Validate we can work with this device. */
+@@ -818,7 +1256,7 @@ int vc_sm_cma_import_dmabuf(struct dma_b
+
+ if (!ret) {
+ pr_debug("%s: imported to ptr %p\n", __func__, new_dma_buf);
+- res = (struct vc_sm_buffer *)new_dma_buf->priv;
++ buf = (struct vc_sm_buffer *)new_dma_buf->priv;
+
+ /* Assign valid handle at this time.*/
+ *handle = new_dma_buf;
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
+@@ -21,6 +21,8 @@
+ #include <linux/types.h>
+ #include <linux/miscdevice.h>
+
++#include "vc_sm_cma.h"
++
+ #define VC_SM_MAX_NAME_LEN 32
+
+ enum vc_sm_vpu_mapping_state {
+@@ -29,31 +31,51 @@ enum vc_sm_vpu_mapping_state {
+ VPU_UNMAPPING
+ };
+
++struct vc_sm_imported {
++ struct dma_buf *dma_buf;
++ struct dma_buf_attachment *attach;
++ struct sg_table *sgt;
++};
++
+ struct vc_sm_buffer {
+ struct list_head global_buffer_list; /* Global list of buffers. */
+
++ /* Index in the kernel_id idr so that we can find the
++ * mmal_msg_context again when servicing the VCHI reply.
++ */
++ int kernel_id;
++
+ size_t size;
+
+ /* Lock over all the following state for this buffer */
+ struct mutex lock;
+- struct sg_table *sg_table;
+ struct list_head attachments;
+
+ char name[VC_SM_MAX_NAME_LEN];
+
+ int in_use:1; /* Kernel is still using this resource */
++ int imported:1; /* Imported dmabuf */
++
++ struct sg_table *sg_table;
+
+ enum vc_sm_vpu_mapping_state vpu_state;
+ u32 vc_handle; /* VideoCore handle for this buffer */
++ int vpu_allocated; /*
++ * The VPU made this allocation. Release the
++ * local dma_buf when the VPU releases the
++ * resource.
++ */
+
+ /* DMABUF related fields */
+- struct dma_buf *import_dma_buf;
+ struct dma_buf *dma_buf;
+- struct dma_buf_attachment *attach;
+- struct sg_table *sgt;
+ dma_addr_t dma_addr;
+
+ struct vc_sm_privdata_t *private;
++
++ union {
++ struct vc_sm_cma_alloc_data alloc;
++ struct vc_sm_imported import;
++ };
+ };
+
+ #endif
+--- /dev/null
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
+@@ -0,0 +1,99 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * VideoCore Shared Memory CMA allocator
++ *
++ * Copyright: 2018, Raspberry Pi (Trading) Ltd
++ *
++ * Based on the Android ION allocator
++ * Copyright (C) Linaro 2012
++ *
++ */
++
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/cma.h>
++#include <linux/scatterlist.h>
++
++#include "vc_sm_cma.h"
++
++/* CMA heap operations functions */
++int vc_sm_cma_buffer_allocate(struct cma *cma_heap,
++ struct vc_sm_cma_alloc_data *buffer,
++ unsigned long len)
++{
++ /* len should already be page aligned */
++ unsigned long num_pages = len / PAGE_SIZE;
++ struct sg_table *table;
++ struct page *pages;
++ int ret;
++
++ pages = cma_alloc(cma_heap, num_pages, 0, GFP_KERNEL);
++ if (!pages)
++ return -ENOMEM;
++
++ table = kmalloc(sizeof(*table), GFP_KERNEL);
++ if (!table)
++ goto err;
++
++ ret = sg_alloc_table(table, 1, GFP_KERNEL);
++ if (ret)
++ goto free_mem;
++
++ sg_set_page(table->sgl, pages, len, 0);
++
++ buffer->priv_virt = pages;
++ buffer->sg_table = table;
++ buffer->cma_heap = cma_heap;
++ buffer->num_pages = num_pages;
++ return 0;
++
++free_mem:
++ kfree(table);
++err:
++ cma_release(cma_heap, pages, num_pages);
++ return -ENOMEM;
++}
++
++void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer)
++{
++ struct cma *cma_heap = buffer->cma_heap;
++ struct page *pages = buffer->priv_virt;
++
++ /* release memory */
++ if (cma_heap)
++ cma_release(cma_heap, pages, buffer->num_pages);
++
++ /* release sg table */
++ if (buffer->sg_table) {
++ sg_free_table(buffer->sg_table);
++ kfree(buffer->sg_table);
++ buffer->sg_table = NULL;
++ }
++}
++
++int __vc_sm_cma_add_heaps(struct cma *cma, void *priv)
++{
++ struct cma **heap = (struct cma **)priv;
++ const char *name = cma_get_name(cma);
++
++ if (!(*heap)) {
++ phys_addr_t phys_addr = cma_get_base(cma);
++
++ pr_debug("%s: Adding cma heap %s (start %pap, size %lu) for use by vcsm\n",
++ __func__, name, &phys_addr, cma_get_size(cma));
++ *heap = cma;
++ } else {
++ pr_err("%s: Ignoring heap %s as already set\n",
++ __func__, name);
++ }
++
++ return 0;
++}
++
++int vc_sm_cma_add_heaps(struct cma **cma_heap)
++{
++ cma_for_each_area(__vc_sm_cma_add_heaps, cma_heap);
++ return 0;
++}
+--- /dev/null
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
+@@ -0,0 +1,39 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++
++/*
++ * VideoCore Shared Memory CMA allocator
++ *
++ * Copyright: 2018, Raspberry Pi (Trading) Ltd
++ *
++ * Based on the Android ION allocator
++ * Copyright (C) Linaro 2012
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ */
++#ifndef VC_SM_CMA_H
++#define VC_SM_CMA_H
++
++struct vc_sm_cma_alloc_data {
++ struct cma *cma_heap;
++ unsigned long num_pages;
++ void *priv_virt;
++ struct sg_table *sg_table;
++};
++
++int vc_sm_cma_buffer_allocate(struct cma *cma_heap,
++ struct vc_sm_cma_alloc_data *buffer,
++ unsigned long len);
++void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer);
++
++int vc_sm_cma_add_heaps(struct cma **cma_heap);
++
++#endif
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
+@@ -500,3 +500,13 @@ int vc_sm_cma_vchi_client_version(struct
+ msg, sizeof(*msg), NULL, 0,
+ cur_trans_id, 0);
+ }
++
++int vc_sm_vchi_client_vc_mem_req_reply(struct sm_instance *handle,
++ struct vc_sm_vc_mem_request_result *msg,
++ uint32_t *cur_trans_id)
++{
++ return vc_sm_cma_vchi_send_msg(handle,
++ VC_SM_MSG_TYPE_VC_MEM_REQUEST_REPLY,
++ msg, sizeof(*msg), 0, 0, cur_trans_id,
++ 0);
++}
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h
+@@ -56,4 +56,8 @@ int vc_sm_cma_vchi_client_version(struct
+ struct vc_sm_result_t *result,
+ u32 *cur_trans_id);
+
++int vc_sm_vchi_client_vc_mem_req_reply(struct sm_instance *handle,
++ struct vc_sm_vc_mem_request_result *msg,
++ uint32_t *cur_trans_id);
++
+ #endif /* __VC_SM_CMA_VCHI_H__INCLUDED__ */
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h
+@@ -264,6 +264,8 @@ struct vc_sm_vc_mem_request {
+ u32 align;
+ /* resource name (for easier tracking) */
+ char name[VC_SM_RESOURCE_NAME];
++ /* VPU handle for the resource */
++ u32 vc_handle;
+ };
+
+ /* Response from the kernel to provide the VPU with some memory */
+++ /dev/null
-From 84b54ee2ff01005f0201c51f50985faf4e79edc6 Mon Sep 17 00:00:00 2001
-Date: Mon, 10 Dec 2018 17:35:58 +0000
-Subject: [PATCH] staging: vc-sm-cma: Remove obsolete comment and make
- function static
-
-Removes obsolete comment about wanting to pass a function
-pointer into mmal-vchiq as we now do.
-As the function is passed as a function pointer, the function itself
-can be static.
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -594,8 +594,7 @@ error:
- return ret;
- }
-
--/* FIXME: Pass a function pointer to this into vc_vchi_sm.c */
--void
-+static void
- vc_sm_vpu_event(struct sm_instance *instance, struct vc_sm_result_t *reply,
- int reply_len)
- {
--- /dev/null
+From 753e73267994a88505b6883cdf463d1d0bacf090 Mon Sep 17 00:00:00 2001
+Date: Mon, 11 Mar 2019 16:38:32 +0000
+Subject: [PATCH] staging: vc-sm-cma: Update TODO.
+
+The driver is already a platform driver, so that can be
+deleted from the TODO.
+There are no known issues that need to be resolved.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/TODO | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/TODO
++++ b/drivers/staging/vc04_services/vc-sm-cma/TODO
+@@ -1,2 +1 @@
+-1) Convert to a platform driver.
+-
++No currently outstanding tasks except some clean-up.
+++ /dev/null
-From 275f4673d8c0601e5dbb16e743187d264e7dbed6 Mon Sep 17 00:00:00 2001
-Date: Fri, 21 Dec 2018 16:50:53 +0000
-Subject: [PATCH] staging: vc-sm-cma: Add in allocation for VPU
- requests.
-
-Module has to change from tristate to bool as all CMA functions
-are boolean.
-
----
- .../staging/vc04_services/vc-sm-cma/Kconfig | 4 +-
- .../staging/vc04_services/vc-sm-cma/Makefile | 2 +-
- .../staging/vc04_services/vc-sm-cma/vc_sm.c | 642 +++++++++++++++---
- .../staging/vc04_services/vc-sm-cma/vc_sm.h | 30 +-
- .../vc04_services/vc-sm-cma/vc_sm_cma.c | 99 +++
- .../vc04_services/vc-sm-cma/vc_sm_cma.h | 39 ++
- .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 10 +
- .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.h | 4 +
- .../vc04_services/vc-sm-cma/vc_sm_defs.h | 2 +
- 9 files changed, 723 insertions(+), 109 deletions(-)
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
-
---- a/drivers/staging/vc04_services/vc-sm-cma/Kconfig
-+++ b/drivers/staging/vc04_services/vc-sm-cma/Kconfig
-@@ -1,6 +1,6 @@
- config BCM_VC_SM_CMA
-- tristate "VideoCore Shared Memory (CMA) driver"
-- depends on BCM2835_VCHIQ
-+ bool "VideoCore Shared Memory (CMA) driver"
-+ depends on BCM2835_VCHIQ && DMA_CMA
- select RBTREE
- select DMA_SHARED_BUFFER
- help
---- a/drivers/staging/vc04_services/vc-sm-cma/Makefile
-+++ b/drivers/staging/vc04_services/vc-sm-cma/Makefile
-@@ -3,6 +3,6 @@ ccflags-y += -Idrivers/staging/vc04_serv
- ccflags-y += -D__VCCOREVER__=0
-
- vc-sm-cma-$(CONFIG_BCM_VC_SM_CMA) := \
-- vc_sm.o vc_sm_cma_vchi.o
-+ vc_sm.o vc_sm_cma_vchi.o vc_sm_cma.o
-
- obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma.o
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -9,10 +9,21 @@
- * and taking some code for CMA/dmabuf handling from the Android Ion
- * driver (Google/Linaro).
- *
-- * This is cut down version to only support import of dma_bufs from
-- * other kernel drivers. A more complete implementation of the old
-- * vmcs_sm functionality can follow later.
- *
-+ * This driver has 3 main uses:
-+ * 1) Allocating buffers for the kernel or userspace that can be shared with the
-+ * VPU.
-+ * 2) Importing dmabufs from elsewhere for sharing with the VPU.
-+ * 3) Allocating buffers for use by the VPU.
-+ *
-+ * In the first and second cases the native handle is a dmabuf. Releasing the
-+ * resource inherently comes from releasing the dmabuf, and this will trigger
-+ * unmapping on the VPU. The underlying allocation and our buffer structure are
-+ * retained until the VPU has confirmed that it has finished with it.
-+ *
-+ * For the VPU allocations the VPU is responsible for triggering the release,
-+ * and therefore the released message decrements the dma_buf refcount (with the
-+ * VPU mapping having already been marked as released).
- */
-
- /* ---- Include Files ----------------------------------------------------- */
-@@ -39,6 +50,7 @@
- #include "vc_sm_cma_vchi.h"
-
- #include "vc_sm.h"
-+#include "vc_sm_cma.h"
- #include "vc_sm_knl.h"
-
- /* ---- Private Constants and Types --------------------------------------- */
-@@ -72,6 +84,7 @@ struct sm_state_t {
- struct platform_device *pdev;
-
- struct sm_instance *sm_handle; /* Handle for videocore service. */
-+ struct cma *cma_heap;
-
- spinlock_t kernelid_map_lock; /* Spinlock protecting kernelid_map */
- struct idr kernelid_map;
-@@ -80,6 +93,7 @@ struct sm_state_t {
- struct list_head buffer_list; /* List of buffer. */
-
- struct vc_sm_privdata_t *data_knl; /* Kernel internal data tracking. */
-+ struct vc_sm_privdata_t *vpu_allocs; /* All allocations from the VPU */
- struct dentry *dir_root; /* Debug fs entries root. */
- struct sm_pde_t dir_state; /* Debug fs entries state sub-tree. */
-
-@@ -89,6 +103,12 @@ struct sm_state_t {
- u32 int_trans_id; /* Interrupted transaction. */
- };
-
-+struct vc_sm_dma_buf_attachment {
-+ struct device *dev;
-+ struct sg_table *table;
-+ struct list_head list;
-+};
-+
- /* ---- Private Variables ----------------------------------------------- */
-
- static struct sm_state_t *sm_state;
-@@ -172,12 +192,14 @@ static int vc_sm_cma_global_state_show(s
- resource->size);
- seq_printf(s, " DMABUF %p\n",
- resource->dma_buf);
-- seq_printf(s, " ATTACH %p\n",
-- resource->attach);
-+ if (resource->imported) {
-+ seq_printf(s, " ATTACH %p\n",
-+ resource->import.attach);
-+ seq_printf(s, " SGT %p\n",
-+ resource->import.sgt);
-+ }
- seq_printf(s, " SG_TABLE %p\n",
- resource->sg_table);
-- seq_printf(s, " SGT %p\n",
-- resource->sgt);
- seq_printf(s, " DMA_ADDR %pad\n",
- &resource->dma_addr);
- seq_printf(s, " VC_HANDLE %08x\n",
-@@ -209,17 +231,33 @@ static void vc_sm_add_resource(struct vc
- }
-
- /*
-- * Release an allocation.
-- * All refcounting is done via the dma buf object.
-+ * Cleans up imported dmabuf.
- */
--static void vc_sm_release_resource(struct vc_sm_buffer *buffer, int force)
-+static void vc_sm_clean_up_dmabuf(struct vc_sm_buffer *buffer)
- {
-- mutex_lock(&sm_state->map_lock);
-- mutex_lock(&buffer->lock);
-+ if (!buffer->imported)
-+ return;
-
-- pr_debug("[%s]: buffer %p (name %s, size %zu)\n",
-- __func__, buffer, buffer->name, buffer->size);
-+ /* Handle cleaning up imported dmabufs */
-+ mutex_lock(&buffer->lock);
-+ if (buffer->import.sgt) {
-+ dma_buf_unmap_attachment(buffer->import.attach,
-+ buffer->import.sgt,
-+ DMA_BIDIRECTIONAL);
-+ buffer->import.sgt = NULL;
-+ }
-+ if (buffer->import.attach) {
-+ dma_buf_detach(buffer->dma_buf, buffer->import.attach);
-+ buffer->import.attach = NULL;
-+ }
-+ mutex_unlock(&buffer->lock);
-+}
-
-+/*
-+ * Instructs VPU to decrement the refcount on a buffer.
-+ */
-+static void vc_sm_vpu_free(struct vc_sm_buffer *buffer)
-+{
- if (buffer->vc_handle && buffer->vpu_state == VPU_MAPPED) {
- struct vc_sm_free_t free = { buffer->vc_handle, 0 };
- int status = vc_sm_cma_vchi_free(sm_state->sm_handle, &free,
-@@ -230,17 +268,32 @@ static void vc_sm_release_resource(struc
- }
-
- if (sm_state->require_released_callback) {
-- /* Need to wait for the VPU to confirm the free */
-+ /* Need to wait for the VPU to confirm the free. */
-
- /* Retain a reference on this until the VPU has
- * released it
- */
- buffer->vpu_state = VPU_UNMAPPING;
-- goto defer;
-+ } else {
-+ buffer->vpu_state = VPU_NOT_MAPPED;
-+ buffer->vc_handle = 0;
- }
-- buffer->vpu_state = VPU_NOT_MAPPED;
-- buffer->vc_handle = 0;
- }
-+}
-+
-+/*
-+ * Release an allocation.
-+ * All refcounting is done via the dma buf object.
-+ *
-+ * Must be called with the mutex held. The function will either release the
-+ * mutex (if defering the release) or destroy it. The caller must therefore not
-+ * reuse the buffer on return.
-+ */
-+static void vc_sm_release_resource(struct vc_sm_buffer *buffer)
-+{
-+ pr_debug("[%s]: buffer %p (name %s, size %zu)\n",
-+ __func__, buffer, buffer->name, buffer->size);
-+
- if (buffer->vc_handle) {
- /* We've sent the unmap request but not had the response. */
- pr_err("[%s]: Waiting for VPU unmap response on %p\n",
-@@ -248,45 +301,43 @@ static void vc_sm_release_resource(struc
- goto defer;
- }
- if (buffer->in_use) {
-- /* Don't release dmabuf here - we await the release */
-+ /* dmabuf still in use - we await the release */
- pr_err("[%s]: buffer %p is still in use\n",
- __func__, buffer);
- goto defer;
- }
-
-- /* Handle cleaning up imported dmabufs */
-- if (buffer->sgt) {
-- dma_buf_unmap_attachment(buffer->attach, buffer->sgt,
-- DMA_BIDIRECTIONAL);
-- buffer->sgt = NULL;
-- }
-- if (buffer->attach) {
-- dma_buf_detach(buffer->dma_buf, buffer->attach);
-- buffer->attach = NULL;
-- }
--
-- /* Release the dma_buf (whether ours or imported) */
-- if (buffer->import_dma_buf) {
-- dma_buf_put(buffer->import_dma_buf);
-- buffer->import_dma_buf = NULL;
-- buffer->dma_buf = NULL;
-- } else if (buffer->dma_buf) {
-- dma_buf_put(buffer->dma_buf);
-- buffer->dma_buf = NULL;
-+ /* Release the allocation (whether imported dmabuf or CMA allocation) */
-+ if (buffer->imported) {
-+ pr_debug("%s: Release imported dmabuf %p\n", __func__,
-+ buffer->import.dma_buf);
-+ if (buffer->import.dma_buf)
-+ dma_buf_put(buffer->import.dma_buf);
-+ else
-+ pr_err("%s: Imported dmabuf already been put for buf %p\n",
-+ __func__, buffer);
-+ buffer->import.dma_buf = NULL;
-+ } else {
-+ if (buffer->sg_table) {
-+ /* Our own allocation that we need to dma_unmap_sg */
-+ dma_unmap_sg(&sm_state->pdev->dev,
-+ buffer->sg_table->sgl,
-+ buffer->sg_table->nents,
-+ DMA_BIDIRECTIONAL);
-+ }
-+ pr_debug("%s: Release our allocation\n", __func__);
-+ vc_sm_cma_buffer_free(&buffer->alloc);
-+ pr_debug("%s: Release our allocation - done\n", __func__);
- }
-
-- if (buffer->sg_table && !buffer->import_dma_buf) {
-- /* Our own allocation that we need to dma_unmap_sg */
-- dma_unmap_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
-- buffer->sg_table->nents, DMA_BIDIRECTIONAL);
-- }
-
-- /* Free the local resource. Start by removing it from the list */
-- buffer->private = NULL;
-+ /* Free our buffer. Start by removing it from the list */
-+ mutex_lock(&sm_state->map_lock);
- list_del(&buffer->global_buffer_list);
-+ mutex_unlock(&sm_state->map_lock);
-
-+ pr_debug("%s: Release our allocation - done\n", __func__);
- mutex_unlock(&buffer->lock);
-- mutex_unlock(&sm_state->map_lock);
-
- mutex_destroy(&buffer->lock);
-
-@@ -295,7 +346,7 @@ static void vc_sm_release_resource(struc
-
- defer:
- mutex_unlock(&buffer->lock);
-- mutex_unlock(&sm_state->map_lock);
-+ return;
- }
-
- /* Create support for private data tracking. */
-@@ -317,16 +368,267 @@ static struct vc_sm_privdata_t *vc_sm_cm
- return file_data;
- }
-
-+static struct sg_table *dup_sg_table(struct sg_table *table)
-+{
-+ struct sg_table *new_table;
-+ int ret, i;
-+ struct scatterlist *sg, *new_sg;
-+
-+ new_table = kzalloc(sizeof(*new_table), GFP_KERNEL);
-+ if (!new_table)
-+ return ERR_PTR(-ENOMEM);
-+
-+ ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
-+ if (ret) {
-+ kfree(new_table);
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ new_sg = new_table->sgl;
-+ for_each_sg(table->sgl, sg, table->nents, i) {
-+ memcpy(new_sg, sg, sizeof(*sg));
-+ sg->dma_address = 0;
-+ new_sg = sg_next(new_sg);
-+ }
-+
-+ return new_table;
-+}
-+
-+static void free_duped_table(struct sg_table *table)
-+{
-+ sg_free_table(table);
-+ kfree(table);
-+}
-+
-+/* Dma buf operations for use with our own allocations */
-+
-+static int vc_sm_dma_buf_attach(struct dma_buf *dmabuf,
-+ struct dma_buf_attachment *attachment)
-+
-+{
-+ struct vc_sm_dma_buf_attachment *a;
-+ struct sg_table *table;
-+ struct vc_sm_buffer *buf = dmabuf->priv;
-+
-+ a = kzalloc(sizeof(*a), GFP_KERNEL);
-+ if (!a)
-+ return -ENOMEM;
-+
-+ table = dup_sg_table(buf->sg_table);
-+ if (IS_ERR(table)) {
-+ kfree(a);
-+ return -ENOMEM;
-+ }
-+
-+ a->table = table;
-+ INIT_LIST_HEAD(&a->list);
-+
-+ attachment->priv = a;
-+
-+ mutex_lock(&buf->lock);
-+ list_add(&a->list, &buf->attachments);
-+ mutex_unlock(&buf->lock);
-+ pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
-+
-+ return 0;
-+}
-+
-+static void vc_sm_dma_buf_detatch(struct dma_buf *dmabuf,
-+ struct dma_buf_attachment *attachment)
-+{
-+ struct vc_sm_dma_buf_attachment *a = attachment->priv;
-+ struct vc_sm_buffer *buf = dmabuf->priv;
-+
-+ pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
-+ free_duped_table(a->table);
-+ mutex_lock(&buf->lock);
-+ list_del(&a->list);
-+ mutex_unlock(&buf->lock);
-+
-+ kfree(a);
-+}
-+
-+static struct sg_table *vc_sm_map_dma_buf(struct dma_buf_attachment *attachment,
-+ enum dma_data_direction direction)
-+{
-+ struct vc_sm_dma_buf_attachment *a = attachment->priv;
-+ struct sg_table *table;
-+
-+ table = a->table;
-+
-+ if (!dma_map_sg(attachment->dev, table->sgl, table->nents,
-+ direction))
-+ return ERR_PTR(-ENOMEM);
-+
-+ pr_debug("%s attachment %p\n", __func__, attachment);
-+ return table;
-+}
-+
-+static void vc_sm_unmap_dma_buf(struct dma_buf_attachment *attachment,
-+ struct sg_table *table,
-+ enum dma_data_direction direction)
-+{
-+ pr_debug("%s attachment %p\n", __func__, attachment);
-+ dma_unmap_sg(attachment->dev, table->sgl, table->nents, direction);
-+}
-+
-+static int vc_sm_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
-+{
-+ struct vc_sm_buffer *buf = dmabuf->priv;
-+ struct sg_table *table = buf->sg_table;
-+ unsigned long addr = vma->vm_start;
-+ unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
-+ struct scatterlist *sg;
-+ int i;
-+ int ret = 0;
-+
-+ pr_debug("%s dmabuf %p, buf %p, vm_start %08lX\n", __func__, dmabuf,
-+ buf, addr);
-+
-+ mutex_lock(&buf->lock);
-+
-+ /* now map it to userspace */
-+ for_each_sg(table->sgl, sg, table->nents, i) {
-+ struct page *page = sg_page(sg);
-+ unsigned long remainder = vma->vm_end - addr;
-+ unsigned long len = sg->length;
-+
-+ if (offset >= sg->length) {
-+ offset -= sg->length;
-+ continue;
-+ } else if (offset) {
-+ page += offset / PAGE_SIZE;
-+ len = sg->length - offset;
-+ offset = 0;
-+ }
-+ len = min(len, remainder);
-+ ret = remap_pfn_range(vma, addr, page_to_pfn(page), len,
-+ vma->vm_page_prot);
-+ if (ret)
-+ break;
-+ addr += len;
-+ if (addr >= vma->vm_end)
-+ break;
-+ }
-+ mutex_unlock(&buf->lock);
-+
-+ if (ret)
-+ pr_err("%s: failure mapping buffer to userspace\n",
-+ __func__);
-+
-+ return ret;
-+}
-+
-+static void vc_sm_dma_buf_release(struct dma_buf *dmabuf)
-+{
-+ struct vc_sm_buffer *buffer;
-+
-+ if (!dmabuf)
-+ return;
-+
-+ buffer = (struct vc_sm_buffer *)dmabuf->priv;
-+
-+ mutex_lock(&buffer->lock);
-+
-+ pr_debug("%s dmabuf %p, buffer %p\n", __func__, dmabuf, buffer);
-+
-+ buffer->in_use = 0;
-+
-+ /* Unmap on the VPU */
-+ vc_sm_vpu_free(buffer);
-+ pr_debug("%s vpu_free done\n", __func__);
-+
-+ /* Unmap our dma_buf object (the vc_sm_buffer remains until released
-+ * on the VPU).
-+ */
-+ vc_sm_clean_up_dmabuf(buffer);
-+ pr_debug("%s clean_up dmabuf done\n", __func__);
-+
-+ vc_sm_release_resource(buffer);
-+ pr_debug("%s done\n", __func__);
-+}
-+
-+static int vc_sm_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
-+ enum dma_data_direction direction)
-+{
-+ struct vc_sm_buffer *buf;
-+ struct vc_sm_dma_buf_attachment *a;
-+
-+ if (!dmabuf)
-+ return -EFAULT;
-+
-+ buf = dmabuf->priv;
-+ if (!buf)
-+ return -EFAULT;
-+
-+ mutex_lock(&buf->lock);
-+
-+ list_for_each_entry(a, &buf->attachments, list) {
-+ dma_sync_sg_for_cpu(a->dev, a->table->sgl, a->table->nents,
-+ direction);
-+ }
-+ mutex_unlock(&buf->lock);
-+
-+ return 0;
-+}
-+
-+static int vc_sm_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
-+ enum dma_data_direction direction)
-+{
-+ struct vc_sm_buffer *buf;
-+ struct vc_sm_dma_buf_attachment *a;
-+
-+ if (!dmabuf)
-+ return -EFAULT;
-+ buf = dmabuf->priv;
-+ if (!buf)
-+ return -EFAULT;
-+
-+ mutex_lock(&buf->lock);
-+
-+ list_for_each_entry(a, &buf->attachments, list) {
-+ dma_sync_sg_for_device(a->dev, a->table->sgl, a->table->nents,
-+ direction);
-+ }
-+ mutex_unlock(&buf->lock);
-+
-+ return 0;
-+}
-+
-+static void *vc_sm_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset)
-+{
-+ /* FIXME */
-+ return NULL;
-+}
-+
-+static void vc_sm_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset,
-+ void *ptr)
-+{
-+ /* FIXME */
-+}
-+
-+static const struct dma_buf_ops dma_buf_ops = {
-+ .map_dma_buf = vc_sm_map_dma_buf,
-+ .unmap_dma_buf = vc_sm_unmap_dma_buf,
-+ .mmap = vc_sm_dmabuf_mmap,
-+ .release = vc_sm_dma_buf_release,
-+ .attach = vc_sm_dma_buf_attach,
-+ .detach = vc_sm_dma_buf_detatch,
-+ .begin_cpu_access = vc_sm_dma_buf_begin_cpu_access,
-+ .end_cpu_access = vc_sm_dma_buf_end_cpu_access,
-+ .map = vc_sm_dma_buf_kmap,
-+ .unmap = vc_sm_dma_buf_kunmap,
-+};
- /* Dma_buf operations for chaining through to an imported dma_buf */
- static
- int vc_sm_import_dma_buf_attach(struct dma_buf *dmabuf,
- struct dma_buf_attachment *attachment)
- {
-- struct vc_sm_buffer *res = dmabuf->priv;
-+ struct vc_sm_buffer *buf = dmabuf->priv;
-
-- if (!res->import_dma_buf)
-+ if (!buf->imported)
- return -EINVAL;
-- return res->import_dma_buf->ops->attach(res->import_dma_buf,
-+ return buf->import.dma_buf->ops->attach(buf->import.dma_buf,
- attachment);
- }
-
-@@ -334,22 +636,23 @@ static
- void vc_sm_import_dma_buf_detatch(struct dma_buf *dmabuf,
- struct dma_buf_attachment *attachment)
- {
-- struct vc_sm_buffer *res = dmabuf->priv;
-+ struct vc_sm_buffer *buf = dmabuf->priv;
-
-- if (!res->import_dma_buf)
-+ if (!buf->imported)
- return;
-- res->import_dma_buf->ops->detach(res->import_dma_buf, attachment);
-+ buf->import.dma_buf->ops->detach(buf->import.dma_buf, attachment);
- }
-
- static
- struct sg_table *vc_sm_import_map_dma_buf(struct dma_buf_attachment *attachment,
- enum dma_data_direction direction)
- {
-- struct vc_sm_buffer *res = attachment->dmabuf->priv;
-+ struct vc_sm_buffer *buf = attachment->dmabuf->priv;
-
-- if (!res->import_dma_buf)
-+ if (!buf->imported)
- return NULL;
-- return res->import_dma_buf->ops->map_dma_buf(attachment, direction);
-+ return buf->import.dma_buf->ops->map_dma_buf(attachment,
-+ direction);
- }
-
- static
-@@ -357,87 +660,88 @@ void vc_sm_import_unmap_dma_buf(struct d
- struct sg_table *table,
- enum dma_data_direction direction)
- {
-- struct vc_sm_buffer *res = attachment->dmabuf->priv;
-+ struct vc_sm_buffer *buf = attachment->dmabuf->priv;
-
-- if (!res->import_dma_buf)
-+ if (!buf->imported)
- return;
-- res->import_dma_buf->ops->unmap_dma_buf(attachment, table, direction);
-+ buf->import.dma_buf->ops->unmap_dma_buf(attachment, table, direction);
- }
-
- static
- int vc_sm_import_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
- {
-- struct vc_sm_buffer *res = dmabuf->priv;
-+ struct vc_sm_buffer *buf = dmabuf->priv;
-
-- pr_debug("%s: mmap dma_buf %p, res %p, imported db %p\n", __func__,
-- dmabuf, res, res->import_dma_buf);
-- if (!res->import_dma_buf) {
-+ pr_debug("%s: mmap dma_buf %p, buf %p, imported db %p\n", __func__,
-+ dmabuf, buf, buf->import.dma_buf);
-+ if (!buf->imported) {
- pr_err("%s: mmap dma_buf %p- not an imported buffer\n",
- __func__, dmabuf);
- return -EINVAL;
- }
-- return res->import_dma_buf->ops->mmap(res->import_dma_buf, vma);
-+ return buf->import.dma_buf->ops->mmap(buf->import.dma_buf, vma);
- }
-
- static
- void vc_sm_import_dma_buf_release(struct dma_buf *dmabuf)
- {
-- struct vc_sm_buffer *res = dmabuf->priv;
-+ struct vc_sm_buffer *buf = dmabuf->priv;
-
- pr_debug("%s: Relasing dma_buf %p\n", __func__, dmabuf);
-- if (!res->import_dma_buf)
-+ mutex_lock(&buf->lock);
-+ if (!buf->imported)
- return;
-
-- res->in_use = 0;
-+ buf->in_use = 0;
-
-- vc_sm_release_resource(res, 0);
-+ vc_sm_vpu_free(buf);
-+
-+ vc_sm_release_resource(buf);
- }
-
- static
- void *vc_sm_import_dma_buf_kmap(struct dma_buf *dmabuf,
- unsigned long offset)
- {
-- struct vc_sm_buffer *res = dmabuf->priv;
-+ struct vc_sm_buffer *buf = dmabuf->priv;
-
-- if (!res->import_dma_buf)
-+ if (!buf->imported)
- return NULL;
-- return res->import_dma_buf->ops->map(res->import_dma_buf,
-- offset);
-+ return buf->import.dma_buf->ops->map(buf->import.dma_buf, offset);
- }
-
- static
- void vc_sm_import_dma_buf_kunmap(struct dma_buf *dmabuf,
- unsigned long offset, void *ptr)
- {
-- struct vc_sm_buffer *res = dmabuf->priv;
-+ struct vc_sm_buffer *buf = dmabuf->priv;
-
-- if (!res->import_dma_buf)
-+ if (!buf->imported)
- return;
-- res->import_dma_buf->ops->unmap(res->import_dma_buf,
-- offset, ptr);
-+ buf->import.dma_buf->ops->unmap(buf->import.dma_buf, offset, ptr);
- }
-
- static
- int vc_sm_import_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
- enum dma_data_direction direction)
- {
-- struct vc_sm_buffer *res = dmabuf->priv;
-+ struct vc_sm_buffer *buf = dmabuf->priv;
-
-- if (!res->import_dma_buf)
-+ if (!buf->imported)
- return -EINVAL;
-- return res->import_dma_buf->ops->begin_cpu_access(res->import_dma_buf,
-- direction);
-+ return buf->import.dma_buf->ops->begin_cpu_access(buf->import.dma_buf,
-+ direction);
- }
-
- static
- int vc_sm_import_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
- enum dma_data_direction direction)
- {
-- struct vc_sm_buffer *res = dmabuf->priv;
-+ struct vc_sm_buffer *buf = dmabuf->priv;
-
-- if (!res->import_dma_buf)
-+ if (!buf->imported)
- return -EINVAL;
-- return res->import_dma_buf->ops->end_cpu_access(res->import_dma_buf,
-+ return buf->import.dma_buf->ops->end_cpu_access(buf->import.dma_buf,
- direction);
- }
-
-@@ -516,9 +820,8 @@ vc_sm_cma_import_dmabuf_internal(struct
- memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT,
- sizeof(VC_SM_RESOURCE_NAME_DEFAULT));
-
-- pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %pad, size %u\n",
-- __func__, import.name, import.type, &dma_addr,
-- import.size);
-+ pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %pad, size %u.\n",
-+ __func__, import.name, import.type, &dma_addr, import.size);
-
- /* Allocate the videocore buffer. */
- status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result,
-@@ -548,12 +851,14 @@ vc_sm_cma_import_dmabuf_internal(struct
- buffer->size = import.size;
- buffer->vpu_state = VPU_MAPPED;
-
-- buffer->import_dma_buf = dma_buf;
-+ buffer->imported = 1;
-+ buffer->import.dma_buf = dma_buf;
-
-- buffer->attach = attach;
-- buffer->sgt = sgt;
-+ buffer->import.attach = attach;
-+ buffer->import.sgt = sgt;
- buffer->dma_addr = dma_addr;
- buffer->in_use = 1;
-+ buffer->kernel_id = import.kernel_id;
-
- /*
- * We're done - we need to export a new dmabuf chaining through most
-@@ -594,6 +899,91 @@ error:
- return ret;
- }
-
-+static int vc_sm_cma_vpu_alloc(u32 size, uint32_t align, const char *name,
-+ u32 mem_handle, struct vc_sm_buffer **ret_buffer)
-+{
-+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
-+ struct vc_sm_buffer *buffer = NULL;
-+ int aligned_size;
-+ int ret = 0;
-+
-+ /* Align to the user requested align */
-+ aligned_size = ALIGN(size, align);
-+ /* and then to a page boundary */
-+ aligned_size = PAGE_ALIGN(aligned_size);
-+
-+ if (!aligned_size)
-+ return -EINVAL;
-+
-+ /* Allocate local buffer to track this allocation. */
-+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
-+ if (!buffer)
-+ return -ENOMEM;
-+
-+ mutex_init(&buffer->lock);
-+
-+ if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
-+ aligned_size)) {
-+ pr_err("[%s]: cma alloc of %d bytes failed\n",
-+ __func__, aligned_size);
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+ buffer->sg_table = buffer->alloc.sg_table;
-+
-+ pr_debug("[%s]: cma alloc of %d bytes success\n",
-+ __func__, aligned_size);
-+
-+ if (dma_map_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
-+ buffer->sg_table->nents, DMA_BIDIRECTIONAL) <= 0) {
-+ pr_err("[%s]: dma_map_sg failed\n", __func__);
-+ goto error;
-+ }
-+
-+ INIT_LIST_HEAD(&buffer->attachments);
-+
-+ memcpy(buffer->name, name,
-+ min(sizeof(buffer->name), strlen(name)));
-+
-+ exp_info.ops = &dma_buf_ops;
-+ exp_info.size = aligned_size;
-+ exp_info.flags = O_RDWR;
-+ exp_info.priv = buffer;
-+
-+ buffer->dma_buf = dma_buf_export(&exp_info);
-+ if (IS_ERR(buffer->dma_buf)) {
-+ ret = PTR_ERR(buffer->dma_buf);
-+ goto error;
-+ }
-+ buffer->dma_addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
-+ if ((buffer->dma_addr & 0xC0000000) != 0xC0000000) {
-+ pr_err("%s: Expecting an uncached alias for dma_addr %pad\n",
-+ __func__, &buffer->dma_addr);
-+ buffer->dma_addr |= 0xC0000000;
-+ }
-+ buffer->private = sm_state->vpu_allocs;
-+
-+ buffer->vc_handle = mem_handle;
-+ buffer->vpu_state = VPU_MAPPED;
-+ buffer->vpu_allocated = 1;
-+ buffer->size = size;
-+ /*
-+ * Create an ID that will be passed along with our message so
-+ * that when we service the release reply, we can look up which
-+ * resource is being released.
-+ */
-+ buffer->kernel_id = get_kernel_id(buffer);
-+
-+ vc_sm_add_resource(sm_state->vpu_allocs, buffer);
-+
-+ *ret_buffer = buffer;
-+ return 0;
-+error:
-+ if (buffer)
-+ vc_sm_release_resource(buffer);
-+ return ret;
-+}
-+
- static void
- vc_sm_vpu_event(struct sm_instance *instance, struct vc_sm_result_t *reply,
- int reply_len)
-@@ -612,21 +1002,61 @@ vc_sm_vpu_event(struct sm_instance *inst
- struct vc_sm_released *release = (struct vc_sm_released *)reply;
- struct vc_sm_buffer *buffer =
- lookup_kernel_id(release->kernel_id);
-+ if (!buffer) {
-+ pr_err("%s: VC released a buffer that is already released, kernel_id %d\n",
-+ __func__, release->kernel_id);
-+ break;
-+ }
-+ mutex_lock(&buffer->lock);
-
-- /*
-- * FIXME: Need to check buffer is still valid and allocated
-- * before continuing
-- */
- pr_debug("%s: Released addr %08x, size %u, id %08x, mem_handle %08x\n",
- __func__, release->addr, release->size,
- release->kernel_id, release->vc_handle);
-- mutex_lock(&buffer->lock);
-+
- buffer->vc_handle = 0;
- buffer->vpu_state = VPU_NOT_MAPPED;
-- mutex_unlock(&buffer->lock);
- free_kernel_id(release->kernel_id);
-
-- vc_sm_release_resource(buffer, 0);
-+ if (buffer->vpu_allocated) {
-+ /* VPU allocation, so release the dmabuf which will
-+ * trigger the clean up.
-+ */
-+ mutex_unlock(&buffer->lock);
-+ dma_buf_put(buffer->dma_buf);
-+ } else {
-+ vc_sm_release_resource(buffer);
-+ }
-+ }
-+ break;
-+ case VC_SM_MSG_TYPE_VC_MEM_REQUEST:
-+ {
-+ struct vc_sm_buffer *buffer = NULL;
-+ struct vc_sm_vc_mem_request *req =
-+ (struct vc_sm_vc_mem_request *)reply;
-+ struct vc_sm_vc_mem_request_result reply;
-+ int ret;
-+
-+ pr_debug("%s: Request %u bytes of memory, align %d name %s, trans_id %08x\n",
-+ __func__, req->size, req->align, req->name,
-+ req->trans_id);
-+ ret = vc_sm_cma_vpu_alloc(req->size, req->align, req->name,
-+ req->vc_handle, &buffer);
-+
-+ reply.trans_id = req->trans_id;
-+ if (!ret) {
-+ reply.addr = buffer->dma_addr;
-+ reply.kernel_id = buffer->kernel_id;
-+ pr_debug("%s: Allocated resource buffer %p, addr %pad\n",
-+ __func__, buffer, &buffer->dma_addr);
-+ } else {
-+ pr_err("%s: Allocation failed size %u, name %s, vc_handle %u\n",
-+ __func__, req->size, req->name, req->vc_handle);
-+ reply.addr = 0;
-+ reply.kernel_id = 0;
-+ }
-+ vc_sm_vchi_client_vc_mem_req_reply(sm_state->sm_handle, &reply,
-+ &sm_state->int_trans_id);
-+ break;
- }
- break;
- default:
-@@ -645,6 +1075,14 @@ static void vc_sm_connected_init(void)
-
- pr_info("[%s]: start\n", __func__);
-
-+ if (vc_sm_cma_add_heaps(&sm_state->cma_heap) ||
-+ !sm_state->cma_heap) {
-+ pr_err("[%s]: failed to initialise CMA heaps\n",
-+ __func__);
-+ ret = -EIO;
-+ goto err_free_mem;
-+ }
-+
- /*
- * Initialize and create a VCHI connection for the shared memory service
- * running on videocore.
-@@ -696,7 +1134,7 @@ static void vc_sm_connected_init(void)
- goto err_remove_shared_memory;
- }
-
-- version.version = 1;
-+ version.version = 2;
- ret = vc_sm_cma_vchi_client_version(sm_state->sm_handle, &version,
- &version_result,
- &sm_state->int_trans_id);
-@@ -768,7 +1206,7 @@ static int bcm2835_vc_sm_cma_remove(stru
- int vc_sm_cma_int_handle(void *handle)
- {
- struct dma_buf *dma_buf = (struct dma_buf *)handle;
-- struct vc_sm_buffer *res;
-+ struct vc_sm_buffer *buf;
-
- /* Validate we can work with this device. */
- if (!sm_state || !handle) {
-@@ -776,8 +1214,8 @@ int vc_sm_cma_int_handle(void *handle)
- return 0;
- }
-
-- res = (struct vc_sm_buffer *)dma_buf->priv;
-- return res->vc_handle;
-+ buf = (struct vc_sm_buffer *)dma_buf->priv;
-+ return buf->vc_handle;
- }
- EXPORT_SYMBOL_GPL(vc_sm_cma_int_handle);
-
-@@ -804,7 +1242,7 @@ EXPORT_SYMBOL_GPL(vc_sm_cma_free);
- int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, void **handle)
- {
- struct dma_buf *new_dma_buf;
-- struct vc_sm_buffer *res;
-+ struct vc_sm_buffer *buf;
- int ret;
-
- /* Validate we can work with this device. */
-@@ -818,7 +1256,7 @@ int vc_sm_cma_import_dmabuf(struct dma_b
-
- if (!ret) {
- pr_debug("%s: imported to ptr %p\n", __func__, new_dma_buf);
-- res = (struct vc_sm_buffer *)new_dma_buf->priv;
-+ buf = (struct vc_sm_buffer *)new_dma_buf->priv;
-
- /* Assign valid handle at this time.*/
- *handle = new_dma_buf;
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
-@@ -21,6 +21,8 @@
- #include <linux/types.h>
- #include <linux/miscdevice.h>
-
-+#include "vc_sm_cma.h"
-+
- #define VC_SM_MAX_NAME_LEN 32
-
- enum vc_sm_vpu_mapping_state {
-@@ -29,31 +31,51 @@ enum vc_sm_vpu_mapping_state {
- VPU_UNMAPPING
- };
-
-+struct vc_sm_imported {
-+ struct dma_buf *dma_buf;
-+ struct dma_buf_attachment *attach;
-+ struct sg_table *sgt;
-+};
-+
- struct vc_sm_buffer {
- struct list_head global_buffer_list; /* Global list of buffers. */
-
-+ /* Index in the kernel_id idr so that we can find the
-+ * mmal_msg_context again when servicing the VCHI reply.
-+ */
-+ int kernel_id;
-+
- size_t size;
-
- /* Lock over all the following state for this buffer */
- struct mutex lock;
-- struct sg_table *sg_table;
- struct list_head attachments;
-
- char name[VC_SM_MAX_NAME_LEN];
-
- int in_use:1; /* Kernel is still using this resource */
-+ int imported:1; /* Imported dmabuf */
-+
-+ struct sg_table *sg_table;
-
- enum vc_sm_vpu_mapping_state vpu_state;
- u32 vc_handle; /* VideoCore handle for this buffer */
-+ int vpu_allocated; /*
-+ * The VPU made this allocation. Release the
-+ * local dma_buf when the VPU releases the
-+ * resource.
-+ */
-
- /* DMABUF related fields */
-- struct dma_buf *import_dma_buf;
- struct dma_buf *dma_buf;
-- struct dma_buf_attachment *attach;
-- struct sg_table *sgt;
- dma_addr_t dma_addr;
-
- struct vc_sm_privdata_t *private;
-+
-+ union {
-+ struct vc_sm_cma_alloc_data alloc;
-+ struct vc_sm_imported import;
-+ };
- };
-
- #endif
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
-@@ -0,0 +1,99 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * VideoCore Shared Memory CMA allocator
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ *
-+ * Based on the Android ION allocator
-+ * Copyright (C) Linaro 2012
-+ *
-+ */
-+
-+#include <linux/slab.h>
-+#include <linux/errno.h>
-+#include <linux/err.h>
-+#include <linux/cma.h>
-+#include <linux/scatterlist.h>
-+
-+#include "vc_sm_cma.h"
-+
-+/* CMA heap operations functions */
-+int vc_sm_cma_buffer_allocate(struct cma *cma_heap,
-+ struct vc_sm_cma_alloc_data *buffer,
-+ unsigned long len)
-+{
-+ /* len should already be page aligned */
-+ unsigned long num_pages = len / PAGE_SIZE;
-+ struct sg_table *table;
-+ struct page *pages;
-+ int ret;
-+
-+ pages = cma_alloc(cma_heap, num_pages, 0, GFP_KERNEL);
-+ if (!pages)
-+ return -ENOMEM;
-+
-+ table = kmalloc(sizeof(*table), GFP_KERNEL);
-+ if (!table)
-+ goto err;
-+
-+ ret = sg_alloc_table(table, 1, GFP_KERNEL);
-+ if (ret)
-+ goto free_mem;
-+
-+ sg_set_page(table->sgl, pages, len, 0);
-+
-+ buffer->priv_virt = pages;
-+ buffer->sg_table = table;
-+ buffer->cma_heap = cma_heap;
-+ buffer->num_pages = num_pages;
-+ return 0;
-+
-+free_mem:
-+ kfree(table);
-+err:
-+ cma_release(cma_heap, pages, num_pages);
-+ return -ENOMEM;
-+}
-+
-+void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer)
-+{
-+ struct cma *cma_heap = buffer->cma_heap;
-+ struct page *pages = buffer->priv_virt;
-+
-+ /* release memory */
-+ if (cma_heap)
-+ cma_release(cma_heap, pages, buffer->num_pages);
-+
-+ /* release sg table */
-+ if (buffer->sg_table) {
-+ sg_free_table(buffer->sg_table);
-+ kfree(buffer->sg_table);
-+ buffer->sg_table = NULL;
-+ }
-+}
-+
-+int __vc_sm_cma_add_heaps(struct cma *cma, void *priv)
-+{
-+ struct cma **heap = (struct cma **)priv;
-+ const char *name = cma_get_name(cma);
-+
-+ if (!(*heap)) {
-+ phys_addr_t phys_addr = cma_get_base(cma);
-+
-+ pr_debug("%s: Adding cma heap %s (start %pap, size %lu) for use by vcsm\n",
-+ __func__, name, &phys_addr, cma_get_size(cma));
-+ *heap = cma;
-+ } else {
-+ pr_err("%s: Ignoring heap %s as already set\n",
-+ __func__, name);
-+ }
-+
-+ return 0;
-+}
-+
-+int vc_sm_cma_add_heaps(struct cma **cma_heap)
-+{
-+ cma_for_each_area(__vc_sm_cma_add_heaps, cma_heap);
-+ return 0;
-+}
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
-@@ -0,0 +1,39 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/*
-+ * VideoCore Shared Memory CMA allocator
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ *
-+ * Based on the Android ION allocator
-+ * Copyright (C) Linaro 2012
-+ *
-+ * This software is licensed under the terms of the GNU General Public
-+ * License version 2, as published by the Free Software Foundation, and
-+ * may be copied, distributed, and modified under those terms.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ */
-+#ifndef VC_SM_CMA_H
-+#define VC_SM_CMA_H
-+
-+struct vc_sm_cma_alloc_data {
-+ struct cma *cma_heap;
-+ unsigned long num_pages;
-+ void *priv_virt;
-+ struct sg_table *sg_table;
-+};
-+
-+int vc_sm_cma_buffer_allocate(struct cma *cma_heap,
-+ struct vc_sm_cma_alloc_data *buffer,
-+ unsigned long len);
-+void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer);
-+
-+int vc_sm_cma_add_heaps(struct cma **cma_heap);
-+
-+#endif
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
-@@ -500,3 +500,13 @@ int vc_sm_cma_vchi_client_version(struct
- msg, sizeof(*msg), NULL, 0,
- cur_trans_id, 0);
- }
-+
-+int vc_sm_vchi_client_vc_mem_req_reply(struct sm_instance *handle,
-+ struct vc_sm_vc_mem_request_result *msg,
-+ uint32_t *cur_trans_id)
-+{
-+ return vc_sm_cma_vchi_send_msg(handle,
-+ VC_SM_MSG_TYPE_VC_MEM_REQUEST_REPLY,
-+ msg, sizeof(*msg), 0, 0, cur_trans_id,
-+ 0);
-+}
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h
-@@ -56,4 +56,8 @@ int vc_sm_cma_vchi_client_version(struct
- struct vc_sm_result_t *result,
- u32 *cur_trans_id);
-
-+int vc_sm_vchi_client_vc_mem_req_reply(struct sm_instance *handle,
-+ struct vc_sm_vc_mem_request_result *msg,
-+ uint32_t *cur_trans_id);
-+
- #endif /* __VC_SM_CMA_VCHI_H__INCLUDED__ */
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h
-@@ -264,6 +264,8 @@ struct vc_sm_vc_mem_request {
- u32 align;
- /* resource name (for easier tracking) */
- char name[VC_SM_RESOURCE_NAME];
-+ /* VPU handle for the resource */
-+ u32 vc_handle;
- };
-
- /* Response from the kernel to provide the VPU with some memory */
--- /dev/null
+From 549c0266e570da686f19e4435d76411cd7137954 Mon Sep 17 00:00:00 2001
+Date: Mon, 11 Mar 2019 16:35:23 +0000
+Subject: [PATCH] staging: vc-sm-cma: Add in userspace allocation API
+
+Replacing the functionality from the older vc-sm driver,
+add in a userspace API that allows allocation of buffers,
+and importing of dma-bufs.
+The driver hands out dma-buf fds, therefore much of the
+handling around lifespan and odd mmaps from the old driver
+goes away.
+
+---
+ .../staging/vc04_services/vc-sm-cma/vc_sm.c | 371 ++++++++++++++++--
+ .../vc04_services/vc-sm-cma/vc_sm_cma.c | 3 +-
+ .../vc04_services/vc-sm-cma/vc_sm_cma.h | 2 +-
+ include/linux/broadcom/vc_sm_cma_ioctl.h | 87 ++++
+ 4 files changed, 435 insertions(+), 28 deletions(-)
+ create mode 100644 include/linux/broadcom/vc_sm_cma_ioctl.h
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -36,6 +36,7 @@
+ #include <linux/fs.h>
+ #include <linux/kernel.h>
+ #include <linux/list.h>
++#include <linux/miscdevice.h>
+ #include <linux/module.h>
+ #include <linux/mm.h>
+ #include <linux/of_device.h>
+@@ -52,6 +53,7 @@
+ #include "vc_sm.h"
+ #include "vc_sm_cma.h"
+ #include "vc_sm_knl.h"
++#include <linux/broadcom/vc_sm_cma_ioctl.h>
+
+ /* ---- Private Constants and Types --------------------------------------- */
+
+@@ -83,6 +85,8 @@ struct sm_pde_t {
+ struct sm_state_t {
+ struct platform_device *pdev;
+
++ struct miscdevice misc_dev;
++
+ struct sm_instance *sm_handle; /* Handle for videocore service. */
+ struct cma *cma_heap;
+
+@@ -346,7 +350,6 @@ static void vc_sm_release_resource(struc
+
+ defer:
+ mutex_unlock(&buffer->lock);
+- return;
+ }
+
+ /* Create support for private data tracking. */
+@@ -381,7 +384,7 @@ static struct sg_table *dup_sg_table(str
+ ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
+ if (ret) {
+ kfree(new_table);
+- return ERR_PTR(-ENOMEM);
++ return ERR_PTR(ret);
+ }
+
+ new_sg = new_table->sgl;
+@@ -417,7 +420,7 @@ static int vc_sm_dma_buf_attach(struct d
+ table = dup_sg_table(buf->sg_table);
+ if (IS_ERR(table)) {
+ kfree(a);
+- return -ENOMEM;
++ return PTR_ERR(table);
+ }
+
+ a->table = table;
+@@ -433,8 +436,8 @@ static int vc_sm_dma_buf_attach(struct d
+ return 0;
+ }
+
+-static void vc_sm_dma_buf_detatch(struct dma_buf *dmabuf,
+- struct dma_buf_attachment *attachment)
++static void vc_sm_dma_buf_detach(struct dma_buf *dmabuf,
++ struct dma_buf_attachment *attachment)
+ {
+ struct vc_sm_dma_buf_attachment *a = attachment->priv;
+ struct vc_sm_buffer *buf = dmabuf->priv;
+@@ -544,6 +547,9 @@ static void vc_sm_dma_buf_release(struct
+ vc_sm_clean_up_dmabuf(buffer);
+ pr_debug("%s clean_up dmabuf done\n", __func__);
+
++ /* buffer->lock will be destroyed by vc_sm_release_resource if finished
++ * with, otherwise unlocked. Do NOT unlock here.
++ */
+ vc_sm_release_resource(buffer);
+ pr_debug("%s done\n", __func__);
+ }
+@@ -613,7 +619,7 @@ static const struct dma_buf_ops dma_buf_
+ .mmap = vc_sm_dmabuf_mmap,
+ .release = vc_sm_dma_buf_release,
+ .attach = vc_sm_dma_buf_attach,
+- .detach = vc_sm_dma_buf_detatch,
++ .detach = vc_sm_dma_buf_detach,
+ .begin_cpu_access = vc_sm_dma_buf_begin_cpu_access,
+ .end_cpu_access = vc_sm_dma_buf_end_cpu_access,
+ .map = vc_sm_dma_buf_kmap,
+@@ -762,6 +768,7 @@ static const struct dma_buf_ops dma_buf_
+ int
+ vc_sm_cma_import_dmabuf_internal(struct vc_sm_privdata_t *private,
+ struct dma_buf *dma_buf,
++ int fd,
+ struct dma_buf **imported_buf)
+ {
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+@@ -775,10 +782,15 @@ vc_sm_cma_import_dmabuf_internal(struct
+ int status;
+
+ /* Setup our allocation parameters */
+- pr_debug("%s: importing dma_buf %p\n", __func__, dma_buf);
++ pr_debug("%s: importing dma_buf %p/fd %d\n", __func__, dma_buf, fd);
+
+- get_dma_buf(dma_buf);
+- dma_buf = dma_buf;
++ if (fd < 0)
++ get_dma_buf(dma_buf);
++ else
++ dma_buf = dma_buf_get(fd);
++
++ if (!dma_buf)
++ return -EINVAL;
+
+ attach = dma_buf_attach(dma_buf, &sm_state->pdev->dev);
+ if (IS_ERR(attach)) {
+@@ -921,6 +933,10 @@ static int vc_sm_cma_vpu_alloc(u32 size,
+ return -ENOMEM;
+
+ mutex_init(&buffer->lock);
++ /* Acquire the mutex as vc_sm_release_resource will release it in the
++ * error path.
++ */
++ mutex_lock(&buffer->lock);
+
+ if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
+ aligned_size)) {
+@@ -976,6 +992,8 @@ static int vc_sm_cma_vpu_alloc(u32 size,
+
+ vc_sm_add_resource(sm_state->vpu_allocs, buffer);
+
++ mutex_unlock(&buffer->lock);
++
+ *ret_buffer = buffer;
+ return 0;
+ error:
+@@ -1065,6 +1083,297 @@ vc_sm_vpu_event(struct sm_instance *inst
+ }
+ }
+
++/* Userspace handling */
++/*
++ * Open the device. Creates a private state to help track all allocation
++ * associated with this device.
++ */
++static int vc_sm_cma_open(struct inode *inode, struct file *file)
++{
++ /* Make sure the device was started properly. */
++ if (!sm_state) {
++ pr_err("[%s]: invalid device\n", __func__);
++ return -EPERM;
++ }
++
++ file->private_data = vc_sm_cma_create_priv_data(current->tgid);
++ if (!file->private_data) {
++ pr_err("[%s]: failed to create data tracker\n", __func__);
++
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++/*
++ * Close the vcsm-cma device.
++ * All allocations are file descriptors to the dmabuf objects, so we will get
++ * the clean up request on those as those are cleaned up.
++ */
++static int vc_sm_cma_release(struct inode *inode, struct file *file)
++{
++ struct vc_sm_privdata_t *file_data =
++ (struct vc_sm_privdata_t *)file->private_data;
++ int ret = 0;
++
++ /* Make sure the device was started properly. */
++ if (!sm_state || !file_data) {
++ pr_err("[%s]: invalid device\n", __func__);
++ ret = -EPERM;
++ goto out;
++ }
++
++ pr_debug("[%s]: using private data %p\n", __func__, file_data);
++
++ /* Terminate the private data. */
++ kfree(file_data);
++
++out:
++ return ret;
++}
++
++/*
++ * Allocate a shared memory handle and block.
++ * Allocation is from CMA, and then imported into the VPU mappings.
++ */
++int vc_sm_cma_ioctl_alloc(struct vc_sm_privdata_t *private,
++ struct vc_sm_cma_ioctl_alloc *ioparam)
++{
++ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
++ struct vc_sm_buffer *buffer = NULL;
++ struct vc_sm_import import = { 0 };
++ struct vc_sm_import_result result = { 0 };
++ struct dma_buf *dmabuf = NULL;
++ int aligned_size;
++ int ret = 0;
++ int status;
++ int fd = -1;
++
++ aligned_size = PAGE_ALIGN(ioparam->size);
++
++ if (!aligned_size)
++ return -EINVAL;
++
++ /* Allocate local buffer to track this allocation. */
++ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
++ if (!buffer) {
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
++ aligned_size)) {
++ pr_err("[%s]: cma alloc of %d bytes failed\n",
++ __func__, aligned_size);
++ kfree(buffer);
++ return -ENOMEM;
++ }
++ buffer->sg_table = buffer->alloc.sg_table;
++
++ if (dma_map_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
++ buffer->sg_table->nents, DMA_BIDIRECTIONAL) <= 0) {
++ pr_err("[%s]: dma_map_sg failed\n", __func__);
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ import.type = VC_SM_ALLOC_NON_CACHED;
++ import.allocator = current->tgid;
++
++ if (*ioparam->name)
++ memcpy(import.name, ioparam->name, sizeof(import.name) - 1);
++ else
++ memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT,
++ sizeof(VC_SM_RESOURCE_NAME_DEFAULT));
++
++ mutex_init(&buffer->lock);
++ INIT_LIST_HEAD(&buffer->attachments);
++ memcpy(buffer->name, import.name,
++ min(sizeof(buffer->name), sizeof(import.name) - 1));
++
++ exp_info.ops = &dma_buf_ops;
++ exp_info.size = aligned_size;
++ exp_info.flags = O_RDWR;
++ exp_info.priv = buffer;
++
++ dmabuf = dma_buf_export(&exp_info);
++ if (IS_ERR(dmabuf)) {
++ ret = PTR_ERR(dmabuf);
++ goto error;
++ }
++ buffer->dma_buf = dmabuf;
++
++ import.addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
++ import.size = aligned_size;
++ import.kernel_id = (uint32_t)buffer;
++
++ /* Wrap it into a videocore buffer. */
++ status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result,
++ &sm_state->int_trans_id);
++ if (status == -EINTR) {
++ pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n",
++ __func__, sm_state->int_trans_id);
++ ret = -ERESTARTSYS;
++ private->restart_sys = -EINTR;
++ private->int_action = VC_SM_MSG_TYPE_IMPORT;
++ goto error;
++ } else if (status || !result.res_handle) {
++ pr_err("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n",
++ __func__, status, sm_state->int_trans_id);
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ /* Keep track of the buffer we created. */
++ buffer->private = private;
++ buffer->vc_handle = result.res_handle;
++ buffer->size = import.size;
++ buffer->dma_addr = import.addr;
++ buffer->vpu_state = VPU_MAPPED;
++ //buffer->res_cached = ioparam->cached;
++
++ fd = dma_buf_fd(dmabuf, O_CLOEXEC);
++ if (fd < 0)
++ goto error;
++
++ vc_sm_add_resource(private, buffer);
++
++ pr_debug("[%s]: Added resource as fd %d, buffer %p, private %p, dma_addr %pad\n",
++ __func__, fd, buffer, private, &buffer->dma_addr);
++
++ /* We're done */
++ ioparam->handle = fd;
++ ioparam->vc_handle = buffer->vc_handle;
++ ioparam->dma_addr = buffer->dma_addr;
++ return 0;
++
++error:
++ if (buffer) {
++ pr_err("[%s]: something failed - cleanup. ret %d\n", __func__,
++ ret);
++
++ dma_buf_put(dmabuf);
++ }
++ return ret;
++}
++
++static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int ret = 0;
++ unsigned int cmdnr = _IOC_NR(cmd);
++ struct vc_sm_privdata_t *file_data =
++ (struct vc_sm_privdata_t *)file->private_data;
++
++ /* Validate we can work with this device. */
++ if (!sm_state || !file_data) {
++ pr_err("[%s]: invalid device\n", __func__);
++ return -EPERM;
++ }
++
++ pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
++ current->tgid, file_data->pid);
++
++ /* Action is a re-post of a previously interrupted action? */
++ if (file_data->restart_sys == -EINTR) {
++ struct vc_sm_action_clean_t action_clean;
++
++ pr_debug("[%s]: clean up of action %u (trans_id: %u) following EINTR\n",
++ __func__, file_data->int_action,
++ file_data->int_trans_id);
++
++ action_clean.res_action = file_data->int_action;
++ action_clean.action_trans_id = file_data->int_trans_id;
++
++ file_data->restart_sys = 0;
++ }
++
++ /* Now process the command. */
++ switch (cmdnr) {
++ /* New memory allocation.
++ */
++ case VC_SM_CMA_CMD_ALLOC:
++ {
++ struct vc_sm_cma_ioctl_alloc ioparam;
++
++ /* Get the parameter data. */
++ if (copy_from_user
++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ break;
++ }
++
++ ret = vc_sm_cma_ioctl_alloc(file_data, &ioparam);
++ if (!ret &&
++ (copy_to_user((void *)arg, &ioparam,
++ sizeof(ioparam)) != 0)) {
++ /* FIXME: Release allocation */
++ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ }
++ break;
++ }
++
++ case VC_SM_CMA_CMD_IMPORT_DMABUF:
++ {
++ struct vc_sm_cma_ioctl_import_dmabuf ioparam;
++ struct dma_buf *new_dmabuf;
++
++ /* Get the parameter data. */
++ if (copy_from_user
++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
++ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ break;
++ }
++
++ ret = vc_sm_cma_import_dmabuf_internal(file_data,
++ NULL,
++ ioparam.dmabuf_fd,
++ &new_dmabuf);
++
++ if (!ret) {
++ struct vc_sm_buffer *buf = new_dmabuf->priv;
++
++ ioparam.size = buf->size;
++ ioparam.handle = dma_buf_fd(new_dmabuf,
++ O_CLOEXEC);
++ ioparam.vc_handle = buf->vc_handle;
++ ioparam.dma_addr = buf->dma_addr;
++
++ if (ioparam.handle < 0 ||
++ (copy_to_user((void *)arg, &ioparam,
++ sizeof(ioparam)) != 0)) {
++ dma_buf_put(new_dmabuf);
++ /* FIXME: Release allocation */
++ ret = -EFAULT;
++ }
++ }
++ break;
++ }
++
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret;
++}
++
++/* Device operations that we managed in this driver. */
++static const struct file_operations vc_sm_ops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = vc_sm_cma_ioctl,
++ .open = vc_sm_cma_open,
++ .release = vc_sm_cma_release,
++};
++
++/* Driver load/unload functions */
+ /* Videocore connected. */
+ static void vc_sm_connected_init(void)
+ {
+@@ -1075,12 +1384,11 @@ static void vc_sm_connected_init(void)
+
+ pr_info("[%s]: start\n", __func__);
+
+- if (vc_sm_cma_add_heaps(&sm_state->cma_heap) ||
+- !sm_state->cma_heap) {
+- pr_err("[%s]: failed to initialise CMA heaps\n",
++ vc_sm_cma_add_heaps(&sm_state->cma_heap);
++ if (!sm_state->cma_heap) {
++ pr_err("[%s]: failed to initialise CMA heap\n",
+ __func__);
+- ret = -EIO;
+- goto err_free_mem;
++ return;
+ }
+
+ /*
+@@ -1092,8 +1400,7 @@ static void vc_sm_connected_init(void)
+ pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
+ __func__, ret);
+
+- ret = -EIO;
+- goto err_failed;
++ return;
+ }
+
+ ret = vchi_connect(NULL, 0, vchi_instance);
+@@ -1101,8 +1408,7 @@ static void vc_sm_connected_init(void)
+ pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
+ __func__, ret);
+
+- ret = -EIO;
+- goto err_failed;
++ return;
+ }
+
+ /* Initialize an instance of the shared memory service. */
+@@ -1112,8 +1418,7 @@ static void vc_sm_connected_init(void)
+ pr_err("[%s]: failed to initialize shared memory service\n",
+ __func__);
+
+- ret = -EPERM;
+- goto err_failed;
++ return;
+ }
+
+ /* Create a debug fs directory entry (root). */
+@@ -1127,11 +1432,22 @@ static void vc_sm_connected_init(void)
+
+ INIT_LIST_HEAD(&sm_state->buffer_list);
+
++ /* Create a shared memory device. */
++ sm_state->misc_dev.minor = MISC_DYNAMIC_MINOR;
++ sm_state->misc_dev.name = DEVICE_NAME;
++ sm_state->misc_dev.fops = &vc_sm_ops;
++ sm_state->misc_dev.parent = NULL;
++ ret = misc_register(&sm_state->misc_dev);
++ if (ret) {
++ pr_err("vcsm-cma: failed to register misc device.\n");
++ goto err_remove_debugfs;
++ }
++
+ sm_state->data_knl = vc_sm_cma_create_priv_data(0);
+ if (!sm_state->data_knl) {
+ pr_err("[%s]: failed to create kernel private data tracker\n",
+ __func__);
+- goto err_remove_shared_memory;
++ goto err_remove_misc_dev;
+ }
+
+ version.version = 2;
+@@ -1148,11 +1464,13 @@ static void vc_sm_connected_init(void)
+ pr_info("[%s]: installed successfully\n", __func__);
+ return;
+
+-err_remove_shared_memory:
++err_remove_misc_dev:
++ misc_deregister(&sm_state->misc_dev);
++err_remove_debugfs:
+ debugfs_remove_recursive(sm_state->dir_root);
+ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
+-err_failed:
+- pr_info("[%s]: failed, ret %d\n", __func__, ret);
++
++ return;
+ }
+
+ /* Driver loading. */
+@@ -1184,6 +1502,8 @@ static int bcm2835_vc_sm_cma_remove(stru
+ {
+ pr_debug("[%s]: start\n", __func__);
+ if (sm_inited) {
++ misc_deregister(&sm_state->misc_dev);
++
+ /* Remove all proc entries. */
+ debugfs_remove_recursive(sm_state->dir_root);
+
+@@ -1202,6 +1522,7 @@ static int bcm2835_vc_sm_cma_remove(stru
+ return 0;
+ }
+
++/* Kernel API calls */
+ /* Get an internal resource handle mapped from the external one. */
+ int vc_sm_cma_int_handle(void *handle)
+ {
+@@ -1252,7 +1573,7 @@ int vc_sm_cma_import_dmabuf(struct dma_b
+ }
+
+ ret = vc_sm_cma_import_dmabuf_internal(sm_state->data_knl, src_dmabuf,
+- &new_dma_buf);
++ -1, &new_dma_buf);
+
+ if (!ret) {
+ pr_debug("%s: imported to ptr %p\n", __func__, new_dma_buf);
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
+@@ -92,8 +92,7 @@ int __vc_sm_cma_add_heaps(struct cma *cm
+ return 0;
+ }
+
+-int vc_sm_cma_add_heaps(struct cma **cma_heap)
++void vc_sm_cma_add_heaps(struct cma **cma_heap)
+ {
+ cma_for_each_area(__vc_sm_cma_add_heaps, cma_heap);
+- return 0;
+ }
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
+@@ -34,6 +34,6 @@ int vc_sm_cma_buffer_allocate(struct cma
+ unsigned long len);
+ void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer);
+
+-int vc_sm_cma_add_heaps(struct cma **cma_heap);
++void vc_sm_cma_add_heaps(struct cma **cma_heap);
+
+ #endif
+--- /dev/null
++++ b/include/linux/broadcom/vc_sm_cma_ioctl.h
+@@ -0,0 +1,87 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++
++/*
++ * Copyright 2019 Raspberry Pi (Trading) Ltd. All rights reserved.
++ *
++ * Based on vmcs_sm_ioctl.h Copyright Broadcom Corporation.
++ */
++
++#ifndef __VC_SM_CMA_IOCTL_H
++#define __VC_SM_CMA_IOCTL_H
++
++/* ---- Include Files ---------------------------------------------------- */
++
++#if defined(__KERNEL__)
++#include <linux/types.h> /* Needed for standard types */
++#else
++#include <stdint.h>
++#endif
++
++#include <linux/ioctl.h>
++
++/* ---- Constants and Types ---------------------------------------------- */
++
++#define VC_SM_CMA_RESOURCE_NAME 32
++#define VC_SM_CMA_RESOURCE_NAME_DEFAULT "sm-host-resource"
++
++/* Type define used to create unique IOCTL number */
++#define VC_SM_CMA_MAGIC_TYPE 'J'
++
++/* IOCTL commands on /dev/vc-sm-cma */
++enum vc_sm_cma_cmd_e {
++ VC_SM_CMA_CMD_ALLOC = 0x5A, /* Start at 0x5A arbitrarily */
++
++ VC_SM_CMA_CMD_IMPORT_DMABUF,
++
++ VC_SM_CMA_CMD_LAST /* Do not delete */
++};
++
++/* Cache type supported, conveniently matches the user space definition in
++ * user-vcsm.h.
++ */
++enum vc_sm_cma_cache_e {
++ VC_SM_CMA_CACHE_NONE,
++ VC_SM_CMA_CACHE_HOST,
++ VC_SM_CMA_CACHE_VC,
++ VC_SM_CMA_CACHE_BOTH,
++};
++
++/* IOCTL Data structures */
++struct vc_sm_cma_ioctl_alloc {
++ /* user -> kernel */
++ __u32 size;
++ __u32 num;
++ __u32 cached; /* enum vc_sm_cma_cache_e */
++ __u32 pad;
++ __u8 name[VC_SM_CMA_RESOURCE_NAME];
++
++ /* kernel -> user */
++ __s32 handle;
++ __u32 vc_handle;
++ __u64 dma_addr;
++};
++
++struct vc_sm_cma_ioctl_import_dmabuf {
++ /* user -> kernel */
++ __s32 dmabuf_fd;
++ __u32 cached; /* enum vc_sm_cma_cache_e */
++ __u8 name[VC_SM_CMA_RESOURCE_NAME];
++
++ /* kernel -> user */
++ __s32 handle;
++ __u32 vc_handle;
++ __u32 size;
++ __u32 pad;
++ __u64 dma_addr;
++};
++
++/* IOCTL numbers */
++#define VC_SM_CMA_IOCTL_MEM_ALLOC\
++ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_ALLOC,\
++ struct vc_sm_cma_ioctl_alloc)
++
++#define VC_SM_CMA_IOCTL_MEM_IMPORT_DMABUF\
++ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_IMPORT_DMABUF,\
++ struct vc_sm_cma_ioctl_import_dmabuf)
++
++#endif /* __VC_SM_CMA_IOCTL_H */
+++ /dev/null
-From 753e73267994a88505b6883cdf463d1d0bacf090 Mon Sep 17 00:00:00 2001
-Date: Mon, 11 Mar 2019 16:38:32 +0000
-Subject: [PATCH] staging: vc-sm-cma: Update TODO.
-
-The driver is already a platform driver, so that can be
-deleted from the TODO.
-There are no known issues that need to be resolved.
-
----
- drivers/staging/vc04_services/vc-sm-cma/TODO | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/TODO
-+++ b/drivers/staging/vc04_services/vc-sm-cma/TODO
-@@ -1,2 +1 @@
--1) Convert to a platform driver.
--
-+No currently outstanding tasks except some clean-up.
--- /dev/null
+From b17f6dc1d79ae057294ac2d8d824aa2258ab09a8 Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Mar 2019 10:40:00 +0000
+Subject: [PATCH] staging: vcsm-cma: Add cache control ioctls
+
+The old driver allowed for direct cache manipulation and that
+was used by various clients. Replicate here.
+
+---
+ .../staging/vc04_services/vc-sm-cma/vc_sm.c | 141 +++++++++++++++++-
+ include/linux/broadcom/vc_sm_cma_ioctl.h | 27 ++++
+ 2 files changed, 165 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -46,6 +46,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/syscalls.h>
+ #include <linux/types.h>
++#include <asm/cacheflush.h>
+
+ #include "vchiq_connected.h"
+ #include "vc_sm_cma_vchi.h"
+@@ -1258,6 +1259,99 @@ error:
+ return ret;
+ }
+
++/* Converts VCSM_CACHE_OP_* to an operating function. */
++static void (*cache_op_to_func(const unsigned int cache_op))
++ (const void*, const void*)
++{
++ switch (cache_op) {
++ case VC_SM_CACHE_OP_NOP:
++ return NULL;
++
++ case VC_SM_CACHE_OP_INV:
++ return dmac_inv_range;
++
++ case VC_SM_CACHE_OP_CLEAN:
++ return dmac_clean_range;
++
++ case VC_SM_CACHE_OP_FLUSH:
++ return dmac_flush_range;
++
++ default:
++ pr_err("[%s]: Invalid cache_op: 0x%08x\n", __func__, cache_op);
++ return NULL;
++ }
++}
++
++/*
++ * Clean/invalid/flush cache of which buffer is already pinned (i.e. accessed).
++ */
++static int clean_invalid_contig_2d(const void __user *addr,
++ const size_t block_count,
++ const size_t block_size,
++ const size_t stride,
++ const unsigned int cache_op)
++{
++ size_t i;
++ void (*op_fn)(const void *start, const void *end);
++
++ if (!block_size) {
++ pr_err("[%s]: size cannot be 0\n", __func__);
++ return -EINVAL;
++ }
++
++ op_fn = cache_op_to_func(cache_op);
++ if (!op_fn)
++ return -EINVAL;
++
++ for (i = 0; i < block_count; i ++, addr += stride)
++ op_fn(addr, addr + block_size);
++
++ return 0;
++}
++
++static int vc_sm_cma_clean_invalid2(unsigned int cmdnr, unsigned long arg)
++{
++ struct vc_sm_cma_ioctl_clean_invalid2 ioparam;
++ struct vc_sm_cma_ioctl_clean_invalid_block *block = NULL;
++ int i, ret = 0;
++
++ /* Get parameter data. */
++ if (copy_from_user(&ioparam, (void *)arg, sizeof(ioparam))) {
++ pr_err("[%s]: failed to copy-from-user header for cmd %x\n",
++ __func__, cmdnr);
++ return -EFAULT;
++ }
++ block = kmalloc(ioparam.op_count * sizeof(*block), GFP_KERNEL);
++ if (!block)
++ return -EFAULT;
++
++ if (copy_from_user(block, (void *)(arg + sizeof(ioparam)),
++ ioparam.op_count * sizeof(*block)) != 0) {
++ pr_err("[%s]: failed to copy-from-user payload for cmd %x\n",
++ __func__, cmdnr);
++ ret = -EFAULT;
++ goto out;
++ }
++
++ for (i = 0; i < ioparam.op_count; i++) {
++ const struct vc_sm_cma_ioctl_clean_invalid_block * const op = block + i;
++
++ if (op->invalidate_mode == VC_SM_CACHE_OP_NOP)
++ continue;
++
++ ret = clean_invalid_contig_2d((void __user *)op->start_address,
++ op->block_count, op->block_size,
++ op->inter_block_stride,
++ op->invalidate_mode);
++ if (ret)
++ break;
++ }
++out:
++ kfree(block);
++
++ return ret;
++}
++
+ static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+ {
+@@ -1272,9 +1366,6 @@ static long vc_sm_cma_ioctl(struct file
+ return -EPERM;
+ }
+
+- pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
+- current->tgid, file_data->pid);
+-
+ /* Action is a re-post of a previously interrupted action? */
+ if (file_data->restart_sys == -EINTR) {
+ struct vc_sm_action_clean_t action_clean;
+@@ -1357,7 +1448,18 @@ static long vc_sm_cma_ioctl(struct file
+ break;
+ }
+
++ /*
++ * Flush/Invalidate the cache for a given mapping.
++ * Blocks must be pinned (i.e. accessed) before this call.
++ */
++ case VC_SM_CMA_CMD_CLEAN_INVALID2:
++ ret = vc_sm_cma_clean_invalid2(cmdnr, arg);
++ break;
++
+ default:
++ pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
++ current->tgid, file_data->pid);
++
+ ret = -EINVAL;
+ break;
+ }
+@@ -1365,10 +1467,43 @@ static long vc_sm_cma_ioctl(struct file
+ return ret;
+ }
+
++#ifdef CONFIG_COMPAT
++struct vc_sm_cma_ioctl_clean_invalid2_32 {
++ u32 op_count;
++ struct vc_sm_cma_ioctl_clean_invalid_block {
++ u16 invalidate_mode;
++ u16 block_count;
++ compat_uptr_t start_address;
++ u32 block_size;
++ u32 inter_block_stride;
++ } s[0];
++};
++
++#define VC_SM_CMA_CMD_CLEAN_INVALID2_32\
++ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\
++ struct vc_sm_cma_ioctl_clean_invalid2)
++
++static long vc_sm_cma_compat_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ switch (cmd) {
++ case VC_SM_CMA_CMD_CLEAN_INVALID2_32:
++ /* FIXME */
++ break;
++
++ default:
++ return vc_sm_cma_compat_ioctl(file, cmd, arg);
++ }
++}
++#endif
++
+ /* Device operations that we managed in this driver. */
+ static const struct file_operations vc_sm_ops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = vc_sm_cma_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = vc_sm_cma_compat_ioctl,
++#endif
+ .open = vc_sm_cma_open,
+ .release = vc_sm_cma_release,
+ };
+--- a/include/linux/broadcom/vc_sm_cma_ioctl.h
++++ b/include/linux/broadcom/vc_sm_cma_ioctl.h
+@@ -33,6 +33,8 @@ enum vc_sm_cma_cmd_e {
+
+ VC_SM_CMA_CMD_IMPORT_DMABUF,
+
++ VC_SM_CMA_CMD_CLEAN_INVALID2,
++
+ VC_SM_CMA_CMD_LAST /* Do not delete */
+ };
+
+@@ -75,6 +77,27 @@ struct vc_sm_cma_ioctl_import_dmabuf {
+ __u64 dma_addr;
+ };
+
++/*
++ * Cache functions to be set to struct vc_sm_cma_ioctl_clean_invalid2
++ * invalidate_mode.
++ */
++#define VC_SM_CACHE_OP_NOP 0x00
++#define VC_SM_CACHE_OP_INV 0x01
++#define VC_SM_CACHE_OP_CLEAN 0x02
++#define VC_SM_CACHE_OP_FLUSH 0x03
++
++struct vc_sm_cma_ioctl_clean_invalid2 {
++ __u32 op_count;
++ __u32 pad;
++ struct vc_sm_cma_ioctl_clean_invalid_block {
++ __u32 invalidate_mode;
++ __u32 block_count;
++ void * __user start_address;
++ __u32 block_size;
++ __u32 inter_block_stride;
++ } s[0];
++};
++
+ /* IOCTL numbers */
+ #define VC_SM_CMA_IOCTL_MEM_ALLOC\
+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_ALLOC,\
+@@ -84,4 +107,8 @@ struct vc_sm_cma_ioctl_import_dmabuf {
+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_IMPORT_DMABUF,\
+ struct vc_sm_cma_ioctl_import_dmabuf)
+
++#define VC_SM_CMA_IOCTL_MEM_CLEAN_INVALID2\
++ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\
++ struct vc_sm_cma_ioctl_clean_invalid2)
++
+ #endif /* __VC_SM_CMA_IOCTL_H */
+++ /dev/null
-From 549c0266e570da686f19e4435d76411cd7137954 Mon Sep 17 00:00:00 2001
-Date: Mon, 11 Mar 2019 16:35:23 +0000
-Subject: [PATCH] staging: vc-sm-cma: Add in userspace allocation API
-
-Replacing the functionality from the older vc-sm driver,
-add in a userspace API that allows allocation of buffers,
-and importing of dma-bufs.
-The driver hands out dma-buf fds, therefore much of the
-handling around lifespan and odd mmaps from the old driver
-goes away.
-
----
- .../staging/vc04_services/vc-sm-cma/vc_sm.c | 371 ++++++++++++++++--
- .../vc04_services/vc-sm-cma/vc_sm_cma.c | 3 +-
- .../vc04_services/vc-sm-cma/vc_sm_cma.h | 2 +-
- include/linux/broadcom/vc_sm_cma_ioctl.h | 87 ++++
- 4 files changed, 435 insertions(+), 28 deletions(-)
- create mode 100644 include/linux/broadcom/vc_sm_cma_ioctl.h
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -36,6 +36,7 @@
- #include <linux/fs.h>
- #include <linux/kernel.h>
- #include <linux/list.h>
-+#include <linux/miscdevice.h>
- #include <linux/module.h>
- #include <linux/mm.h>
- #include <linux/of_device.h>
-@@ -52,6 +53,7 @@
- #include "vc_sm.h"
- #include "vc_sm_cma.h"
- #include "vc_sm_knl.h"
-+#include <linux/broadcom/vc_sm_cma_ioctl.h>
-
- /* ---- Private Constants and Types --------------------------------------- */
-
-@@ -83,6 +85,8 @@ struct sm_pde_t {
- struct sm_state_t {
- struct platform_device *pdev;
-
-+ struct miscdevice misc_dev;
-+
- struct sm_instance *sm_handle; /* Handle for videocore service. */
- struct cma *cma_heap;
-
-@@ -346,7 +350,6 @@ static void vc_sm_release_resource(struc
-
- defer:
- mutex_unlock(&buffer->lock);
-- return;
- }
-
- /* Create support for private data tracking. */
-@@ -381,7 +384,7 @@ static struct sg_table *dup_sg_table(str
- ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
- if (ret) {
- kfree(new_table);
-- return ERR_PTR(-ENOMEM);
-+ return ERR_PTR(ret);
- }
-
- new_sg = new_table->sgl;
-@@ -417,7 +420,7 @@ static int vc_sm_dma_buf_attach(struct d
- table = dup_sg_table(buf->sg_table);
- if (IS_ERR(table)) {
- kfree(a);
-- return -ENOMEM;
-+ return PTR_ERR(table);
- }
-
- a->table = table;
-@@ -433,8 +436,8 @@ static int vc_sm_dma_buf_attach(struct d
- return 0;
- }
-
--static void vc_sm_dma_buf_detatch(struct dma_buf *dmabuf,
-- struct dma_buf_attachment *attachment)
-+static void vc_sm_dma_buf_detach(struct dma_buf *dmabuf,
-+ struct dma_buf_attachment *attachment)
- {
- struct vc_sm_dma_buf_attachment *a = attachment->priv;
- struct vc_sm_buffer *buf = dmabuf->priv;
-@@ -544,6 +547,9 @@ static void vc_sm_dma_buf_release(struct
- vc_sm_clean_up_dmabuf(buffer);
- pr_debug("%s clean_up dmabuf done\n", __func__);
-
-+ /* buffer->lock will be destroyed by vc_sm_release_resource if finished
-+ * with, otherwise unlocked. Do NOT unlock here.
-+ */
- vc_sm_release_resource(buffer);
- pr_debug("%s done\n", __func__);
- }
-@@ -613,7 +619,7 @@ static const struct dma_buf_ops dma_buf_
- .mmap = vc_sm_dmabuf_mmap,
- .release = vc_sm_dma_buf_release,
- .attach = vc_sm_dma_buf_attach,
-- .detach = vc_sm_dma_buf_detatch,
-+ .detach = vc_sm_dma_buf_detach,
- .begin_cpu_access = vc_sm_dma_buf_begin_cpu_access,
- .end_cpu_access = vc_sm_dma_buf_end_cpu_access,
- .map = vc_sm_dma_buf_kmap,
-@@ -762,6 +768,7 @@ static const struct dma_buf_ops dma_buf_
- int
- vc_sm_cma_import_dmabuf_internal(struct vc_sm_privdata_t *private,
- struct dma_buf *dma_buf,
-+ int fd,
- struct dma_buf **imported_buf)
- {
- DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
-@@ -775,10 +782,15 @@ vc_sm_cma_import_dmabuf_internal(struct
- int status;
-
- /* Setup our allocation parameters */
-- pr_debug("%s: importing dma_buf %p\n", __func__, dma_buf);
-+ pr_debug("%s: importing dma_buf %p/fd %d\n", __func__, dma_buf, fd);
-
-- get_dma_buf(dma_buf);
-- dma_buf = dma_buf;
-+ if (fd < 0)
-+ get_dma_buf(dma_buf);
-+ else
-+ dma_buf = dma_buf_get(fd);
-+
-+ if (!dma_buf)
-+ return -EINVAL;
-
- attach = dma_buf_attach(dma_buf, &sm_state->pdev->dev);
- if (IS_ERR(attach)) {
-@@ -921,6 +933,10 @@ static int vc_sm_cma_vpu_alloc(u32 size,
- return -ENOMEM;
-
- mutex_init(&buffer->lock);
-+ /* Acquire the mutex as vc_sm_release_resource will release it in the
-+ * error path.
-+ */
-+ mutex_lock(&buffer->lock);
-
- if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
- aligned_size)) {
-@@ -976,6 +992,8 @@ static int vc_sm_cma_vpu_alloc(u32 size,
-
- vc_sm_add_resource(sm_state->vpu_allocs, buffer);
-
-+ mutex_unlock(&buffer->lock);
-+
- *ret_buffer = buffer;
- return 0;
- error:
-@@ -1065,6 +1083,297 @@ vc_sm_vpu_event(struct sm_instance *inst
- }
- }
-
-+/* Userspace handling */
-+/*
-+ * Open the device. Creates a private state to help track all allocation
-+ * associated with this device.
-+ */
-+static int vc_sm_cma_open(struct inode *inode, struct file *file)
-+{
-+ /* Make sure the device was started properly. */
-+ if (!sm_state) {
-+ pr_err("[%s]: invalid device\n", __func__);
-+ return -EPERM;
-+ }
-+
-+ file->private_data = vc_sm_cma_create_priv_data(current->tgid);
-+ if (!file->private_data) {
-+ pr_err("[%s]: failed to create data tracker\n", __func__);
-+
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * Close the vcsm-cma device.
-+ * All allocations are file descriptors to the dmabuf objects, so we will get
-+ * the clean up request on those as those are cleaned up.
-+ */
-+static int vc_sm_cma_release(struct inode *inode, struct file *file)
-+{
-+ struct vc_sm_privdata_t *file_data =
-+ (struct vc_sm_privdata_t *)file->private_data;
-+ int ret = 0;
-+
-+ /* Make sure the device was started properly. */
-+ if (!sm_state || !file_data) {
-+ pr_err("[%s]: invalid device\n", __func__);
-+ ret = -EPERM;
-+ goto out;
-+ }
-+
-+ pr_debug("[%s]: using private data %p\n", __func__, file_data);
-+
-+ /* Terminate the private data. */
-+ kfree(file_data);
-+
-+out:
-+ return ret;
-+}
-+
-+/*
-+ * Allocate a shared memory handle and block.
-+ * Allocation is from CMA, and then imported into the VPU mappings.
-+ */
-+int vc_sm_cma_ioctl_alloc(struct vc_sm_privdata_t *private,
-+ struct vc_sm_cma_ioctl_alloc *ioparam)
-+{
-+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
-+ struct vc_sm_buffer *buffer = NULL;
-+ struct vc_sm_import import = { 0 };
-+ struct vc_sm_import_result result = { 0 };
-+ struct dma_buf *dmabuf = NULL;
-+ int aligned_size;
-+ int ret = 0;
-+ int status;
-+ int fd = -1;
-+
-+ aligned_size = PAGE_ALIGN(ioparam->size);
-+
-+ if (!aligned_size)
-+ return -EINVAL;
-+
-+ /* Allocate local buffer to track this allocation. */
-+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
-+ if (!buffer) {
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
-+ aligned_size)) {
-+ pr_err("[%s]: cma alloc of %d bytes failed\n",
-+ __func__, aligned_size);
-+ kfree(buffer);
-+ return -ENOMEM;
-+ }
-+ buffer->sg_table = buffer->alloc.sg_table;
-+
-+ if (dma_map_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
-+ buffer->sg_table->nents, DMA_BIDIRECTIONAL) <= 0) {
-+ pr_err("[%s]: dma_map_sg failed\n", __func__);
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ import.type = VC_SM_ALLOC_NON_CACHED;
-+ import.allocator = current->tgid;
-+
-+ if (*ioparam->name)
-+ memcpy(import.name, ioparam->name, sizeof(import.name) - 1);
-+ else
-+ memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT,
-+ sizeof(VC_SM_RESOURCE_NAME_DEFAULT));
-+
-+ mutex_init(&buffer->lock);
-+ INIT_LIST_HEAD(&buffer->attachments);
-+ memcpy(buffer->name, import.name,
-+ min(sizeof(buffer->name), sizeof(import.name) - 1));
-+
-+ exp_info.ops = &dma_buf_ops;
-+ exp_info.size = aligned_size;
-+ exp_info.flags = O_RDWR;
-+ exp_info.priv = buffer;
-+
-+ dmabuf = dma_buf_export(&exp_info);
-+ if (IS_ERR(dmabuf)) {
-+ ret = PTR_ERR(dmabuf);
-+ goto error;
-+ }
-+ buffer->dma_buf = dmabuf;
-+
-+ import.addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
-+ import.size = aligned_size;
-+ import.kernel_id = (uint32_t)buffer;
-+
-+ /* Wrap it into a videocore buffer. */
-+ status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result,
-+ &sm_state->int_trans_id);
-+ if (status == -EINTR) {
-+ pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n",
-+ __func__, sm_state->int_trans_id);
-+ ret = -ERESTARTSYS;
-+ private->restart_sys = -EINTR;
-+ private->int_action = VC_SM_MSG_TYPE_IMPORT;
-+ goto error;
-+ } else if (status || !result.res_handle) {
-+ pr_err("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n",
-+ __func__, status, sm_state->int_trans_id);
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ /* Keep track of the buffer we created. */
-+ buffer->private = private;
-+ buffer->vc_handle = result.res_handle;
-+ buffer->size = import.size;
-+ buffer->dma_addr = import.addr;
-+ buffer->vpu_state = VPU_MAPPED;
-+ //buffer->res_cached = ioparam->cached;
-+
-+ fd = dma_buf_fd(dmabuf, O_CLOEXEC);
-+ if (fd < 0)
-+ goto error;
-+
-+ vc_sm_add_resource(private, buffer);
-+
-+ pr_debug("[%s]: Added resource as fd %d, buffer %p, private %p, dma_addr %pad\n",
-+ __func__, fd, buffer, private, &buffer->dma_addr);
-+
-+ /* We're done */
-+ ioparam->handle = fd;
-+ ioparam->vc_handle = buffer->vc_handle;
-+ ioparam->dma_addr = buffer->dma_addr;
-+ return 0;
-+
-+error:
-+ if (buffer) {
-+ pr_err("[%s]: something failed - cleanup. ret %d\n", __func__,
-+ ret);
-+
-+ dma_buf_put(dmabuf);
-+ }
-+ return ret;
-+}
-+
-+static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
-+ unsigned long arg)
-+{
-+ int ret = 0;
-+ unsigned int cmdnr = _IOC_NR(cmd);
-+ struct vc_sm_privdata_t *file_data =
-+ (struct vc_sm_privdata_t *)file->private_data;
-+
-+ /* Validate we can work with this device. */
-+ if (!sm_state || !file_data) {
-+ pr_err("[%s]: invalid device\n", __func__);
-+ return -EPERM;
-+ }
-+
-+ pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
-+ current->tgid, file_data->pid);
-+
-+ /* Action is a re-post of a previously interrupted action? */
-+ if (file_data->restart_sys == -EINTR) {
-+ struct vc_sm_action_clean_t action_clean;
-+
-+ pr_debug("[%s]: clean up of action %u (trans_id: %u) following EINTR\n",
-+ __func__, file_data->int_action,
-+ file_data->int_trans_id);
-+
-+ action_clean.res_action = file_data->int_action;
-+ action_clean.action_trans_id = file_data->int_trans_id;
-+
-+ file_data->restart_sys = 0;
-+ }
-+
-+ /* Now process the command. */
-+ switch (cmdnr) {
-+ /* New memory allocation.
-+ */
-+ case VC_SM_CMA_CMD_ALLOC:
-+ {
-+ struct vc_sm_cma_ioctl_alloc ioparam;
-+
-+ /* Get the parameter data. */
-+ if (copy_from_user
-+ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ ret = vc_sm_cma_ioctl_alloc(file_data, &ioparam);
-+ if (!ret &&
-+ (copy_to_user((void *)arg, &ioparam,
-+ sizeof(ioparam)) != 0)) {
-+ /* FIXME: Release allocation */
-+ pr_err("[%s]: failed to copy-to-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ }
-+ break;
-+ }
-+
-+ case VC_SM_CMA_CMD_IMPORT_DMABUF:
-+ {
-+ struct vc_sm_cma_ioctl_import_dmabuf ioparam;
-+ struct dma_buf *new_dmabuf;
-+
-+ /* Get the parameter data. */
-+ if (copy_from_user
-+ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ ret = vc_sm_cma_import_dmabuf_internal(file_data,
-+ NULL,
-+ ioparam.dmabuf_fd,
-+ &new_dmabuf);
-+
-+ if (!ret) {
-+ struct vc_sm_buffer *buf = new_dmabuf->priv;
-+
-+ ioparam.size = buf->size;
-+ ioparam.handle = dma_buf_fd(new_dmabuf,
-+ O_CLOEXEC);
-+ ioparam.vc_handle = buf->vc_handle;
-+ ioparam.dma_addr = buf->dma_addr;
-+
-+ if (ioparam.handle < 0 ||
-+ (copy_to_user((void *)arg, &ioparam,
-+ sizeof(ioparam)) != 0)) {
-+ dma_buf_put(new_dmabuf);
-+ /* FIXME: Release allocation */
-+ ret = -EFAULT;
-+ }
-+ }
-+ break;
-+ }
-+
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+/* Device operations that we managed in this driver. */
-+static const struct file_operations vc_sm_ops = {
-+ .owner = THIS_MODULE,
-+ .unlocked_ioctl = vc_sm_cma_ioctl,
-+ .open = vc_sm_cma_open,
-+ .release = vc_sm_cma_release,
-+};
-+
-+/* Driver load/unload functions */
- /* Videocore connected. */
- static void vc_sm_connected_init(void)
- {
-@@ -1075,12 +1384,11 @@ static void vc_sm_connected_init(void)
-
- pr_info("[%s]: start\n", __func__);
-
-- if (vc_sm_cma_add_heaps(&sm_state->cma_heap) ||
-- !sm_state->cma_heap) {
-- pr_err("[%s]: failed to initialise CMA heaps\n",
-+ vc_sm_cma_add_heaps(&sm_state->cma_heap);
-+ if (!sm_state->cma_heap) {
-+ pr_err("[%s]: failed to initialise CMA heap\n",
- __func__);
-- ret = -EIO;
-- goto err_free_mem;
-+ return;
- }
-
- /*
-@@ -1092,8 +1400,7 @@ static void vc_sm_connected_init(void)
- pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
- __func__, ret);
-
-- ret = -EIO;
-- goto err_failed;
-+ return;
- }
-
- ret = vchi_connect(NULL, 0, vchi_instance);
-@@ -1101,8 +1408,7 @@ static void vc_sm_connected_init(void)
- pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
- __func__, ret);
-
-- ret = -EIO;
-- goto err_failed;
-+ return;
- }
-
- /* Initialize an instance of the shared memory service. */
-@@ -1112,8 +1418,7 @@ static void vc_sm_connected_init(void)
- pr_err("[%s]: failed to initialize shared memory service\n",
- __func__);
-
-- ret = -EPERM;
-- goto err_failed;
-+ return;
- }
-
- /* Create a debug fs directory entry (root). */
-@@ -1127,11 +1432,22 @@ static void vc_sm_connected_init(void)
-
- INIT_LIST_HEAD(&sm_state->buffer_list);
-
-+ /* Create a shared memory device. */
-+ sm_state->misc_dev.minor = MISC_DYNAMIC_MINOR;
-+ sm_state->misc_dev.name = DEVICE_NAME;
-+ sm_state->misc_dev.fops = &vc_sm_ops;
-+ sm_state->misc_dev.parent = NULL;
-+ ret = misc_register(&sm_state->misc_dev);
-+ if (ret) {
-+ pr_err("vcsm-cma: failed to register misc device.\n");
-+ goto err_remove_debugfs;
-+ }
-+
- sm_state->data_knl = vc_sm_cma_create_priv_data(0);
- if (!sm_state->data_knl) {
- pr_err("[%s]: failed to create kernel private data tracker\n",
- __func__);
-- goto err_remove_shared_memory;
-+ goto err_remove_misc_dev;
- }
-
- version.version = 2;
-@@ -1148,11 +1464,13 @@ static void vc_sm_connected_init(void)
- pr_info("[%s]: installed successfully\n", __func__);
- return;
-
--err_remove_shared_memory:
-+err_remove_misc_dev:
-+ misc_deregister(&sm_state->misc_dev);
-+err_remove_debugfs:
- debugfs_remove_recursive(sm_state->dir_root);
- vc_sm_cma_vchi_stop(&sm_state->sm_handle);
--err_failed:
-- pr_info("[%s]: failed, ret %d\n", __func__, ret);
-+
-+ return;
- }
-
- /* Driver loading. */
-@@ -1184,6 +1502,8 @@ static int bcm2835_vc_sm_cma_remove(stru
- {
- pr_debug("[%s]: start\n", __func__);
- if (sm_inited) {
-+ misc_deregister(&sm_state->misc_dev);
-+
- /* Remove all proc entries. */
- debugfs_remove_recursive(sm_state->dir_root);
-
-@@ -1202,6 +1522,7 @@ static int bcm2835_vc_sm_cma_remove(stru
- return 0;
- }
-
-+/* Kernel API calls */
- /* Get an internal resource handle mapped from the external one. */
- int vc_sm_cma_int_handle(void *handle)
- {
-@@ -1252,7 +1573,7 @@ int vc_sm_cma_import_dmabuf(struct dma_b
- }
-
- ret = vc_sm_cma_import_dmabuf_internal(sm_state->data_knl, src_dmabuf,
-- &new_dma_buf);
-+ -1, &new_dma_buf);
-
- if (!ret) {
- pr_debug("%s: imported to ptr %p\n", __func__, new_dma_buf);
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
-@@ -92,8 +92,7 @@ int __vc_sm_cma_add_heaps(struct cma *cm
- return 0;
- }
-
--int vc_sm_cma_add_heaps(struct cma **cma_heap)
-+void vc_sm_cma_add_heaps(struct cma **cma_heap)
- {
- cma_for_each_area(__vc_sm_cma_add_heaps, cma_heap);
-- return 0;
- }
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
-@@ -34,6 +34,6 @@ int vc_sm_cma_buffer_allocate(struct cma
- unsigned long len);
- void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer);
-
--int vc_sm_cma_add_heaps(struct cma **cma_heap);
-+void vc_sm_cma_add_heaps(struct cma **cma_heap);
-
- #endif
---- /dev/null
-+++ b/include/linux/broadcom/vc_sm_cma_ioctl.h
-@@ -0,0 +1,87 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/*
-+ * Copyright 2019 Raspberry Pi (Trading) Ltd. All rights reserved.
-+ *
-+ * Based on vmcs_sm_ioctl.h Copyright Broadcom Corporation.
-+ */
-+
-+#ifndef __VC_SM_CMA_IOCTL_H
-+#define __VC_SM_CMA_IOCTL_H
-+
-+/* ---- Include Files ---------------------------------------------------- */
-+
-+#if defined(__KERNEL__)
-+#include <linux/types.h> /* Needed for standard types */
-+#else
-+#include <stdint.h>
-+#endif
-+
-+#include <linux/ioctl.h>
-+
-+/* ---- Constants and Types ---------------------------------------------- */
-+
-+#define VC_SM_CMA_RESOURCE_NAME 32
-+#define VC_SM_CMA_RESOURCE_NAME_DEFAULT "sm-host-resource"
-+
-+/* Type define used to create unique IOCTL number */
-+#define VC_SM_CMA_MAGIC_TYPE 'J'
-+
-+/* IOCTL commands on /dev/vc-sm-cma */
-+enum vc_sm_cma_cmd_e {
-+ VC_SM_CMA_CMD_ALLOC = 0x5A, /* Start at 0x5A arbitrarily */
-+
-+ VC_SM_CMA_CMD_IMPORT_DMABUF,
-+
-+ VC_SM_CMA_CMD_LAST /* Do not delete */
-+};
-+
-+/* Cache type supported, conveniently matches the user space definition in
-+ * user-vcsm.h.
-+ */
-+enum vc_sm_cma_cache_e {
-+ VC_SM_CMA_CACHE_NONE,
-+ VC_SM_CMA_CACHE_HOST,
-+ VC_SM_CMA_CACHE_VC,
-+ VC_SM_CMA_CACHE_BOTH,
-+};
-+
-+/* IOCTL Data structures */
-+struct vc_sm_cma_ioctl_alloc {
-+ /* user -> kernel */
-+ __u32 size;
-+ __u32 num;
-+ __u32 cached; /* enum vc_sm_cma_cache_e */
-+ __u32 pad;
-+ __u8 name[VC_SM_CMA_RESOURCE_NAME];
-+
-+ /* kernel -> user */
-+ __s32 handle;
-+ __u32 vc_handle;
-+ __u64 dma_addr;
-+};
-+
-+struct vc_sm_cma_ioctl_import_dmabuf {
-+ /* user -> kernel */
-+ __s32 dmabuf_fd;
-+ __u32 cached; /* enum vc_sm_cma_cache_e */
-+ __u8 name[VC_SM_CMA_RESOURCE_NAME];
-+
-+ /* kernel -> user */
-+ __s32 handle;
-+ __u32 vc_handle;
-+ __u32 size;
-+ __u32 pad;
-+ __u64 dma_addr;
-+};
-+
-+/* IOCTL numbers */
-+#define VC_SM_CMA_IOCTL_MEM_ALLOC\
-+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_ALLOC,\
-+ struct vc_sm_cma_ioctl_alloc)
-+
-+#define VC_SM_CMA_IOCTL_MEM_IMPORT_DMABUF\
-+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_IMPORT_DMABUF,\
-+ struct vc_sm_cma_ioctl_import_dmabuf)
-+
-+#endif /* __VC_SM_CMA_IOCTL_H */
--- /dev/null
+From 4b78daea312bd39e892eb94f8c7905e2d5b682b4 Mon Sep 17 00:00:00 2001
+Date: Mon, 13 May 2019 16:47:54 +0100
+Subject: [PATCH] staging: vcsm-cma: Alter dev node permissions to 0666
+
+Until the udev rules are updated, open up access to this node by
+default.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -1572,6 +1572,8 @@ static void vc_sm_connected_init(void)
+ sm_state->misc_dev.name = DEVICE_NAME;
+ sm_state->misc_dev.fops = &vc_sm_ops;
+ sm_state->misc_dev.parent = NULL;
++ /* Temporarily set as 666 until udev rules have been sorted */
++ sm_state->misc_dev.mode = 0666;
+ ret = misc_register(&sm_state->misc_dev);
+ if (ret) {
+ pr_err("vcsm-cma: failed to register misc device.\n");
+++ /dev/null
-From b17f6dc1d79ae057294ac2d8d824aa2258ab09a8 Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Mar 2019 10:40:00 +0000
-Subject: [PATCH] staging: vcsm-cma: Add cache control ioctls
-
-The old driver allowed for direct cache manipulation and that
-was used by various clients. Replicate here.
-
----
- .../staging/vc04_services/vc-sm-cma/vc_sm.c | 141 +++++++++++++++++-
- include/linux/broadcom/vc_sm_cma_ioctl.h | 27 ++++
- 2 files changed, 165 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -46,6 +46,7 @@
- #include <linux/seq_file.h>
- #include <linux/syscalls.h>
- #include <linux/types.h>
-+#include <asm/cacheflush.h>
-
- #include "vchiq_connected.h"
- #include "vc_sm_cma_vchi.h"
-@@ -1258,6 +1259,99 @@ error:
- return ret;
- }
-
-+/* Converts VCSM_CACHE_OP_* to an operating function. */
-+static void (*cache_op_to_func(const unsigned int cache_op))
-+ (const void*, const void*)
-+{
-+ switch (cache_op) {
-+ case VC_SM_CACHE_OP_NOP:
-+ return NULL;
-+
-+ case VC_SM_CACHE_OP_INV:
-+ return dmac_inv_range;
-+
-+ case VC_SM_CACHE_OP_CLEAN:
-+ return dmac_clean_range;
-+
-+ case VC_SM_CACHE_OP_FLUSH:
-+ return dmac_flush_range;
-+
-+ default:
-+ pr_err("[%s]: Invalid cache_op: 0x%08x\n", __func__, cache_op);
-+ return NULL;
-+ }
-+}
-+
-+/*
-+ * Clean/invalid/flush cache of which buffer is already pinned (i.e. accessed).
-+ */
-+static int clean_invalid_contig_2d(const void __user *addr,
-+ const size_t block_count,
-+ const size_t block_size,
-+ const size_t stride,
-+ const unsigned int cache_op)
-+{
-+ size_t i;
-+ void (*op_fn)(const void *start, const void *end);
-+
-+ if (!block_size) {
-+ pr_err("[%s]: size cannot be 0\n", __func__);
-+ return -EINVAL;
-+ }
-+
-+ op_fn = cache_op_to_func(cache_op);
-+ if (!op_fn)
-+ return -EINVAL;
-+
-+ for (i = 0; i < block_count; i ++, addr += stride)
-+ op_fn(addr, addr + block_size);
-+
-+ return 0;
-+}
-+
-+static int vc_sm_cma_clean_invalid2(unsigned int cmdnr, unsigned long arg)
-+{
-+ struct vc_sm_cma_ioctl_clean_invalid2 ioparam;
-+ struct vc_sm_cma_ioctl_clean_invalid_block *block = NULL;
-+ int i, ret = 0;
-+
-+ /* Get parameter data. */
-+ if (copy_from_user(&ioparam, (void *)arg, sizeof(ioparam))) {
-+ pr_err("[%s]: failed to copy-from-user header for cmd %x\n",
-+ __func__, cmdnr);
-+ return -EFAULT;
-+ }
-+ block = kmalloc(ioparam.op_count * sizeof(*block), GFP_KERNEL);
-+ if (!block)
-+ return -EFAULT;
-+
-+ if (copy_from_user(block, (void *)(arg + sizeof(ioparam)),
-+ ioparam.op_count * sizeof(*block)) != 0) {
-+ pr_err("[%s]: failed to copy-from-user payload for cmd %x\n",
-+ __func__, cmdnr);
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ for (i = 0; i < ioparam.op_count; i++) {
-+ const struct vc_sm_cma_ioctl_clean_invalid_block * const op = block + i;
-+
-+ if (op->invalidate_mode == VC_SM_CACHE_OP_NOP)
-+ continue;
-+
-+ ret = clean_invalid_contig_2d((void __user *)op->start_address,
-+ op->block_count, op->block_size,
-+ op->inter_block_stride,
-+ op->invalidate_mode);
-+ if (ret)
-+ break;
-+ }
-+out:
-+ kfree(block);
-+
-+ return ret;
-+}
-+
- static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
- {
-@@ -1272,9 +1366,6 @@ static long vc_sm_cma_ioctl(struct file
- return -EPERM;
- }
-
-- pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
-- current->tgid, file_data->pid);
--
- /* Action is a re-post of a previously interrupted action? */
- if (file_data->restart_sys == -EINTR) {
- struct vc_sm_action_clean_t action_clean;
-@@ -1357,7 +1448,18 @@ static long vc_sm_cma_ioctl(struct file
- break;
- }
-
-+ /*
-+ * Flush/Invalidate the cache for a given mapping.
-+ * Blocks must be pinned (i.e. accessed) before this call.
-+ */
-+ case VC_SM_CMA_CMD_CLEAN_INVALID2:
-+ ret = vc_sm_cma_clean_invalid2(cmdnr, arg);
-+ break;
-+
- default:
-+ pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
-+ current->tgid, file_data->pid);
-+
- ret = -EINVAL;
- break;
- }
-@@ -1365,10 +1467,43 @@ static long vc_sm_cma_ioctl(struct file
- return ret;
- }
-
-+#ifdef CONFIG_COMPAT
-+struct vc_sm_cma_ioctl_clean_invalid2_32 {
-+ u32 op_count;
-+ struct vc_sm_cma_ioctl_clean_invalid_block {
-+ u16 invalidate_mode;
-+ u16 block_count;
-+ compat_uptr_t start_address;
-+ u32 block_size;
-+ u32 inter_block_stride;
-+ } s[0];
-+};
-+
-+#define VC_SM_CMA_CMD_CLEAN_INVALID2_32\
-+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\
-+ struct vc_sm_cma_ioctl_clean_invalid2)
-+
-+static long vc_sm_cma_compat_ioctl(struct file *file, unsigned int cmd,
-+ unsigned long arg)
-+{
-+ switch (cmd) {
-+ case VC_SM_CMA_CMD_CLEAN_INVALID2_32:
-+ /* FIXME */
-+ break;
-+
-+ default:
-+ return vc_sm_cma_compat_ioctl(file, cmd, arg);
-+ }
-+}
-+#endif
-+
- /* Device operations that we managed in this driver. */
- static const struct file_operations vc_sm_ops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = vc_sm_cma_ioctl,
-+#ifdef CONFIG_COMPAT
-+ .compat_ioctl = vc_sm_cma_compat_ioctl,
-+#endif
- .open = vc_sm_cma_open,
- .release = vc_sm_cma_release,
- };
---- a/include/linux/broadcom/vc_sm_cma_ioctl.h
-+++ b/include/linux/broadcom/vc_sm_cma_ioctl.h
-@@ -33,6 +33,8 @@ enum vc_sm_cma_cmd_e {
-
- VC_SM_CMA_CMD_IMPORT_DMABUF,
-
-+ VC_SM_CMA_CMD_CLEAN_INVALID2,
-+
- VC_SM_CMA_CMD_LAST /* Do not delete */
- };
-
-@@ -75,6 +77,27 @@ struct vc_sm_cma_ioctl_import_dmabuf {
- __u64 dma_addr;
- };
-
-+/*
-+ * Cache functions to be set to struct vc_sm_cma_ioctl_clean_invalid2
-+ * invalidate_mode.
-+ */
-+#define VC_SM_CACHE_OP_NOP 0x00
-+#define VC_SM_CACHE_OP_INV 0x01
-+#define VC_SM_CACHE_OP_CLEAN 0x02
-+#define VC_SM_CACHE_OP_FLUSH 0x03
-+
-+struct vc_sm_cma_ioctl_clean_invalid2 {
-+ __u32 op_count;
-+ __u32 pad;
-+ struct vc_sm_cma_ioctl_clean_invalid_block {
-+ __u32 invalidate_mode;
-+ __u32 block_count;
-+ void * __user start_address;
-+ __u32 block_size;
-+ __u32 inter_block_stride;
-+ } s[0];
-+};
-+
- /* IOCTL numbers */
- #define VC_SM_CMA_IOCTL_MEM_ALLOC\
- _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_ALLOC,\
-@@ -84,4 +107,8 @@ struct vc_sm_cma_ioctl_import_dmabuf {
- _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_IMPORT_DMABUF,\
- struct vc_sm_cma_ioctl_import_dmabuf)
-
-+#define VC_SM_CMA_IOCTL_MEM_CLEAN_INVALID2\
-+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\
-+ struct vc_sm_cma_ioctl_clean_invalid2)
-+
- #endif /* __VC_SM_CMA_IOCTL_H */
--- /dev/null
+From c38256621d4dffbbc0c19737d724724f04b0df9a Mon Sep 17 00:00:00 2001
+Date: Thu, 16 May 2019 15:17:19 +0100
+Subject: [PATCH] staging: vcsm-cma: Drop logging level on messages in
+ vc_sm_release_resource
+
+They weren't errors but were logged as such.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -301,14 +301,13 @@ static void vc_sm_release_resource(struc
+
+ if (buffer->vc_handle) {
+ /* We've sent the unmap request but not had the response. */
+- pr_err("[%s]: Waiting for VPU unmap response on %p\n",
+- __func__, buffer);
++ pr_debug("[%s]: Waiting for VPU unmap response on %p\n",
++ __func__, buffer);
+ goto defer;
+ }
+ if (buffer->in_use) {
+ /* dmabuf still in use - we await the release */
+- pr_err("[%s]: buffer %p is still in use\n",
+- __func__, buffer);
++ pr_debug("[%s]: buffer %p is still in use\n", __func__, buffer);
+ goto defer;
+ }
+
+++ /dev/null
-From 4b78daea312bd39e892eb94f8c7905e2d5b682b4 Mon Sep 17 00:00:00 2001
-Date: Mon, 13 May 2019 16:47:54 +0100
-Subject: [PATCH] staging: vcsm-cma: Alter dev node permissions to 0666
-
-Until the udev rules are updated, open up access to this node by
-default.
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -1572,6 +1572,8 @@ static void vc_sm_connected_init(void)
- sm_state->misc_dev.name = DEVICE_NAME;
- sm_state->misc_dev.fops = &vc_sm_ops;
- sm_state->misc_dev.parent = NULL;
-+ /* Temporarily set as 666 until udev rules have been sorted */
-+ sm_state->misc_dev.mode = 0666;
- ret = misc_register(&sm_state->misc_dev);
- if (ret) {
- pr_err("vcsm-cma: failed to register misc device.\n");
--- /dev/null
+From 52f881e3afa89bb1ca9e8b037f7600bcc97626e8 Mon Sep 17 00:00:00 2001
+Date: Wed, 22 May 2019 15:40:37 +0100
+Subject: [PATCH] staging: vcsm-cma: Fixup the alloc code handling of
+ kernel_id
+
+The allocation code had been copied in from an old branch prior
+to having added the IDR for 64bit support. It was therefore pushing
+a pointer into the kernel_id field instead of an IDR handle, the
+lookup therefore failed, and we never released the buffer.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -1206,7 +1206,7 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
+
+ import.addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
+ import.size = aligned_size;
+- import.kernel_id = (uint32_t)buffer;
++ import.kernel_id = get_kernel_id(buffer);
+
+ /* Wrap it into a videocore buffer. */
+ status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result,
+@@ -1231,6 +1231,7 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
+ buffer->size = import.size;
+ buffer->dma_addr = import.addr;
+ buffer->vpu_state = VPU_MAPPED;
++ buffer->kernel_id = import.kernel_id;
+ //buffer->res_cached = ioparam->cached;
+
+ fd = dma_buf_fd(dmabuf, O_CLOEXEC);
--- /dev/null
+From 3e33fb46eb8791ba39fe4781f278487bcc2c3356 Mon Sep 17 00:00:00 2001
+Date: Thu, 14 Mar 2019 13:27:54 +0000
+Subject: [PATCH] Pulled in the multi frame buffer support from the Pi3
+ repo
+
+---
+ drivers/video/fbdev/bcm2708_fb.c | 580 +++++++++++++++------
+ include/soc/bcm2835/raspberrypi-firmware.h | 4 +
+ 2 files changed, 432 insertions(+), 152 deletions(-)
+
+--- a/drivers/video/fbdev/bcm2708_fb.c
++++ b/drivers/video/fbdev/bcm2708_fb.c
+@@ -2,6 +2,7 @@
+ * linux/drivers/video/bcm2708_fb.c
+ *
+ * Copyright (C) 2010 Broadcom
++ * Copyright (C) 2018 Raspberry Pi (Trading) Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+@@ -13,6 +14,7 @@
+ *
+ */
++
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/errno.h>
+@@ -36,6 +38,7 @@
+ #include <linux/dma-mapping.h>
+ #include <linux/cred.h>
+ #include <soc/bcm2835/raspberrypi-firmware.h>
++#include <linux/mutex.h>
+
+ //#define BCM2708_FB_DEBUG
+ #define MODULE_NAME "bcm2708_fb"
+@@ -82,62 +85,139 @@ struct bcm2708_fb_stats {
+ u32 dma_irqs;
+ };
+
++struct vc4_display_settings_t {
++ u32 display_num;
++ u32 width;
++ u32 height;
++ u32 pitch;
++ u32 depth;
++ u32 virtual_width;
++ u32 virtual_height;
++ u32 virtual_width_offset;
++ u32 virtual_height_offset;
++ unsigned long fb_bus_address;
++};
++
++struct bcm2708_fb_dev;
++
+ struct bcm2708_fb {
+ struct fb_info fb;
+ struct platform_device *dev;
+- struct rpi_firmware *fw;
+ u32 cmap[16];
+ u32 gpu_cmap[256];
++ struct dentry *debugfs_dir;
++ struct dentry *debugfs_subdir;
++ unsigned long fb_bus_address;
++ struct { u32 base, length; } gpu;
++ struct vc4_display_settings_t display_settings;
++ struct debugfs_regset32 screeninfo_regset;
++ struct bcm2708_fb_dev *fbdev;
++ unsigned int image_size;
++ dma_addr_t dma_addr;
++ void *cpuaddr;
++};
++
++#define MAX_FRAMEBUFFERS 3
++
++struct bcm2708_fb_dev {
++ int firmware_supports_multifb;
++ /* Protects the DMA system from multiple FB access */
++ struct mutex dma_mutex;
+ int dma_chan;
+ int dma_irq;
+ void __iomem *dma_chan_base;
+- void *cb_base; /* DMA control blocks */
+- dma_addr_t cb_handle;
+- struct dentry *debugfs_dir;
+ wait_queue_head_t dma_waitq;
+- struct bcm2708_fb_stats stats;
+- unsigned long fb_bus_address;
+- struct { u32 base, length; } gpu;
++ bool disable_arm_alloc;
++ struct bcm2708_fb_stats dma_stats;
++ void *cb_base; /* DMA control blocks */
++ dma_addr_t cb_handle;
++ int instance_count;
++ int num_displays;
++ struct rpi_firmware *fw;
++ struct bcm2708_fb displays[MAX_FRAMEBUFFERS];
+ };
+
+ #define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb)
+
+ static void bcm2708_fb_debugfs_deinit(struct bcm2708_fb *fb)
+ {
+- debugfs_remove_recursive(fb->debugfs_dir);
+- fb->debugfs_dir = NULL;
++ debugfs_remove_recursive(fb->debugfs_subdir);
++ fb->debugfs_subdir = NULL;
++
++ fb->fbdev->instance_count--;
++
++ if (!fb->fbdev->instance_count) {
++ debugfs_remove_recursive(fb->debugfs_dir);
++ fb->debugfs_dir = NULL;
++ }
+ }
+
+ static int bcm2708_fb_debugfs_init(struct bcm2708_fb *fb)
+ {
++ char buf[3];
++ struct bcm2708_fb_dev *fbdev = fb->fbdev;
++
+ static struct debugfs_reg32 stats_registers[] = {
+- {
+- "dma_copies",
+- offsetof(struct bcm2708_fb_stats, dma_copies)
+- },
+- {
+- "dma_irqs",
+- offsetof(struct bcm2708_fb_stats, dma_irqs)
+- },
++ {"dma_copies", offsetof(struct bcm2708_fb_stats, dma_copies)},
++ {"dma_irqs", offsetof(struct bcm2708_fb_stats, dma_irqs)},
+ };
+
+- fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL);
++ static struct debugfs_reg32 screeninfo[] = {
++ {"width", offsetof(struct fb_var_screeninfo, xres)},
++ {"height", offsetof(struct fb_var_screeninfo, yres)},
++ {"bpp", offsetof(struct fb_var_screeninfo, bits_per_pixel)},
++ {"xres_virtual", offsetof(struct fb_var_screeninfo, xres_virtual)},
++ {"yres_virtual", offsetof(struct fb_var_screeninfo, yres_virtual)},
++ {"xoffset", offsetof(struct fb_var_screeninfo, xoffset)},
++ {"yoffset", offsetof(struct fb_var_screeninfo, yoffset)},
++ };
++
++ fb->debugfs_dir = debugfs_lookup(DRIVER_NAME, NULL);
++
++ if (!fb->debugfs_dir)
++ fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL);
++
+ if (!fb->debugfs_dir) {
+- pr_warn("%s: could not create debugfs entry\n",
+- __func__);
++ dev_warn(fb->fb.dev, "%s: could not create debugfs folder\n",
++ __func__);
++ return -EFAULT;
++ }
++
++ snprintf(buf, sizeof(buf), "%u", fb->display_settings.display_num);
++
++ fb->debugfs_subdir = debugfs_create_dir(buf, fb->debugfs_dir);
++
++ if (!fb->debugfs_subdir) {
++ dev_warn(fb->fb.dev, "%s: could not create debugfs entry %u\n",
++ __func__, fb->display_settings.display_num);
+ return -EFAULT;
+ }
+
+- fb->stats.regset.regs = stats_registers;
+- fb->stats.regset.nregs = ARRAY_SIZE(stats_registers);
+- fb->stats.regset.base = &fb->stats;
+-
+- if (!debugfs_create_regset32("stats", 0444, fb->debugfs_dir,
+- &fb->stats.regset)) {
+- pr_warn("%s: could not create statistics registers\n",
+- __func__);
++ fbdev->dma_stats.regset.regs = stats_registers;
++ fbdev->dma_stats.regset.nregs = ARRAY_SIZE(stats_registers);
++ fbdev->dma_stats.regset.base = &fbdev->dma_stats;
++
++ if (!debugfs_create_regset32("dma_stats", 0444, fb->debugfs_subdir,
++ &fbdev->dma_stats.regset)) {
++ dev_warn(fb->fb.dev, "%s: could not create statistics registers\n",
++ __func__);
++ goto fail;
++ }
++
++ fb->screeninfo_regset.regs = screeninfo;
++ fb->screeninfo_regset.nregs = ARRAY_SIZE(screeninfo);
++ fb->screeninfo_regset.base = &fb->fb.var;
++
++ if (!debugfs_create_regset32("screeninfo", 0444, fb->debugfs_subdir,
++ &fb->screeninfo_regset)) {
++ dev_warn(fb->fb.dev,
++ "%s: could not create dimensions registers\n",
++ __func__);
+ goto fail;
+ }
++
++ fbdev->instance_count++;
++
+ return 0;
+
+ fail:
+@@ -145,6 +225,20 @@ fail:
+ return -EFAULT;
+ }
+
++static void set_display_num(struct bcm2708_fb *fb)
++{
++ if (fb && fb->fbdev && fb->fbdev->firmware_supports_multifb) {
++ u32 tmp = fb->display_settings.display_num;
++
++ if (rpi_firmware_property(fb->fbdev->fw,
++ RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM,
++ &tmp,
++ sizeof(tmp)))
++ dev_warn_once(fb->fb.dev,
++ "Set display number call failed. Old GPU firmware?");
++ }
++}
++
+ static int bcm2708_fb_set_bitfields(struct fb_var_screeninfo *var)
+ {
+ int ret = 0;
+@@ -222,11 +316,11 @@ static int bcm2708_fb_check_var(struct f
+ struct fb_info *info)
+ {
+ /* info input, var output */
+- print_debug("%s(%p) %dx%d (%dx%d), %d, %d\n",
++ print_debug("%s(%p) %ux%u (%ux%u), %ul, %u\n",
+ __func__, info, info->var.xres, info->var.yres,
+ info->var.xres_virtual, info->var.yres_virtual,
+- (int)info->screen_size, info->var.bits_per_pixel);
+- print_debug("%s(%p) %dx%d (%dx%d), %d\n", __func__, var, var->xres,
++ info->screen_size, info->var.bits_per_pixel);
++ print_debug("%s(%p) %ux%u (%ux%u), %u\n", __func__, var, var->xres,
+ var->yres, var->xres_virtual, var->yres_virtual,
+ var->bits_per_pixel);
+
+@@ -283,23 +377,96 @@ static int bcm2708_fb_set_par(struct fb_
+ .xoffset = info->var.xoffset,
+ .yoffset = info->var.yoffset,
+ .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
+- .base = 0,
+- .screen_size = 0,
+- .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH, 4, 0 },
+- .pitch = 0,
++ /* base and screen_size will be initialised later */
++ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
++ /* pitch will be initialised later */
+ };
+- int ret;
++ int ret, image_size;
++
+
+- print_debug("%s(%p) %dx%d (%dx%d), %d, %d\n", __func__, info,
++ print_debug("%s(%p) %dx%d (%dx%d), %d, %d (display %d)\n", __func__,
++ info,
+ info->var.xres, info->var.yres, info->var.xres_virtual,
+ info->var.yres_virtual, (int)info->screen_size,
+- info->var.bits_per_pixel);
++ info->var.bits_per_pixel, value);
++
++ /* Need to set the display number to act on first
++ * Cannot do it in the tag list because on older firmware the call
++ * will fail and stop the rest of the list being executed.
++ * We can ignore this call failing as the default at other end is 0
++ */
++ set_display_num(fb);
++
++ /* Try allocating our own buffer. We can specify all the parameters */
++ image_size = ((info->var.xres * info->var.yres) *
++ info->var.bits_per_pixel) >> 3;
++
++ if (!fb->fbdev->disable_arm_alloc &&
++ (image_size != fb->image_size || !fb->dma_addr)) {
++ if (fb->dma_addr) {
++ dma_free_coherent(info->device, fb->image_size,
++ fb->cpuaddr, fb->dma_addr);
++ fb->image_size = 0;
++ fb->cpuaddr = NULL;
++ fb->dma_addr = 0;
++ }
++
++ fb->cpuaddr = dma_alloc_coherent(info->device, image_size,
++ &fb->dma_addr, GFP_KERNEL);
++
++ if (!fb->cpuaddr) {
++ fb->dma_addr = 0;
++ fb->fbdev->disable_arm_alloc = true;
++ } else {
++ fb->image_size = image_size;
++ }
++ }
++
++ if (fb->cpuaddr) {
++ fbinfo.base = fb->dma_addr;
++ fbinfo.screen_size = image_size;
++ fbinfo.pitch = (info->var.xres * info->var.bits_per_pixel) >> 3;
++
++ ret = rpi_firmware_property_list(fb->fbdev->fw, &fbinfo,
++ sizeof(fbinfo));
++ if (ret || fbinfo.base != fb->dma_addr) {
++ /* Firmware either failed, or assigned a different base
++ * address (ie it doesn't support being passed an FB
++ * allocation).
++ * Destroy the allocation, and don't try again.
++ */
++ dma_free_coherent(info->device, fb->image_size,
++ fb->cpuaddr, fb->dma_addr);
++ fb->image_size = 0;
++ fb->cpuaddr = NULL;
++ fb->dma_addr = 0;
++ fb->fbdev->disable_arm_alloc = true;
++ }
++ } else {
++ /* Our allocation failed - drop into the old scheme of
++ * allocation by the VPU.
++ */
++ ret = -ENOMEM;
++ }
+
+- ret = rpi_firmware_property_list(fb->fw, &fbinfo, sizeof(fbinfo));
+ if (ret) {
+- dev_err(info->device,
+- "Failed to allocate GPU framebuffer (%d)\n", ret);
+- return ret;
++ /* Old scheme:
++ * - FRAMEBUFFER_ALLOCATE passes 0 for base and screen_size.
++ * - GET_PITCH instead of SET_PITCH.
++ */
++ fbinfo.base = 0;
++ fbinfo.screen_size = 0;
++ fbinfo.tag6.tag = RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH;
++ fbinfo.pitch = 0;
++
++ ret = rpi_firmware_property_list(fb->fbdev->fw, &fbinfo,
++ sizeof(fbinfo));
++ if (ret) {
++ dev_err(info->device,
++ "Failed to allocate GPU framebuffer (%d)\n",
++ ret);
++ return ret;
++ }
+ }
+
+ if (info->var.bits_per_pixel <= 8)
+@@ -314,9 +481,17 @@ static int bcm2708_fb_set_par(struct fb_
+ fb->fb.fix.smem_start = fbinfo.base;
+ fb->fb.fix.smem_len = fbinfo.pitch * fbinfo.yres_virtual;
+ fb->fb.screen_size = fbinfo.screen_size;
+- if (fb->fb.screen_base)
+- iounmap(fb->fb.screen_base);
+- fb->fb.screen_base = ioremap_wc(fbinfo.base, fb->fb.screen_size);
++
++ if (!fb->dma_addr) {
++ if (fb->fb.screen_base)
++ iounmap(fb->fb.screen_base);
++
++ fb->fb.screen_base = ioremap_wc(fbinfo.base,
++ fb->fb.screen_size);
++ } else {
++ fb->fb.screen_base = fb->cpuaddr;
++ }
++
+ if (!fb->fb.screen_base) {
+ /* the console may currently be locked */
+ console_trylock();
+@@ -374,7 +549,10 @@ static int bcm2708_fb_setcolreg(unsigned
+ packet->length = regno + 1;
+ memcpy(packet->cmap, fb->gpu_cmap,
+ sizeof(packet->cmap));
+- ret = rpi_firmware_property(fb->fw,
++
++ set_display_num(fb);
++
++ ret = rpi_firmware_property(fb->fbdev->fw,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE,
+ packet,
+ (2 + packet->length) * sizeof(u32));
+@@ -413,8 +591,11 @@ static int bcm2708_fb_blank(int blank_mo
+ return -EINVAL;
+ }
+
+- ret = rpi_firmware_property(fb->fw, RPI_FIRMWARE_FRAMEBUFFER_BLANK,
++ set_display_num(fb);
++
++ ret = rpi_firmware_property(fb->fbdev->fw, RPI_FIRMWARE_FRAMEBUFFER_BLANK,
+ &value, sizeof(value));
++
+ if (ret)
+ dev_err(info->device, "%s(%d) failed: %d\n", __func__,
+ blank_mode, ret);
+@@ -431,7 +612,7 @@ static int bcm2708_fb_pan_display(struct
+ info->var.yoffset = var->yoffset;
+ result = bcm2708_fb_set_par(info);
+ if (result != 0)
+- pr_err("%s(%d,%d) returns=%d\n", __func__, var->xoffset,
++ pr_err("%s(%u,%u) returns=%d\n", __func__, var->xoffset,
+ var->yoffset, result);
+ return result;
+ }
+@@ -439,8 +620,9 @@ static int bcm2708_fb_pan_display(struct
+ static void dma_memcpy(struct bcm2708_fb *fb, dma_addr_t dst, dma_addr_t src,
+ int size)
+ {
+- int burst_size = (fb->dma_chan == 0) ? 8 : 2;
+- struct bcm2708_dma_cb *cb = fb->cb_base;
++ struct bcm2708_fb_dev *fbdev = fb->fbdev;
++ struct bcm2708_dma_cb *cb = fbdev->cb_base;
++ int burst_size = (fbdev->dma_chan == 0) ? 8 : 2;
+
+ cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH |
+ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
+@@ -453,21 +635,27 @@ static void dma_memcpy(struct bcm2708_fb
+ cb->pad[1] = 0;
+ cb->next = 0;
+
++ // Not sure what to do if this gets a signal whilst waiting
++ if (mutex_lock_interruptible(&fbdev->dma_mutex))
++ return;
++
+ if (size < dma_busy_wait_threshold) {
+- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
+- bcm_dma_wait_idle(fb->dma_chan_base);
++ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle);
++ bcm_dma_wait_idle(fbdev->dma_chan_base);
+ } else {
+- void __iomem *dma_chan = fb->dma_chan_base;
++ void __iomem *local_dma_chan = fbdev->dma_chan_base;
+
+ cb->info |= BCM2708_DMA_INT_EN;
+- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
+- while (bcm_dma_is_busy(dma_chan)) {
+- wait_event_interruptible(fb->dma_waitq,
+- !bcm_dma_is_busy(dma_chan));
++ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle);
++ while (bcm_dma_is_busy(local_dma_chan)) {
++ wait_event_interruptible(fbdev->dma_waitq,
++ !bcm_dma_is_busy(local_dma_chan));
+ }
+- fb->stats.dma_irqs++;
++ fbdev->dma_stats.dma_irqs++;
+ }
+- fb->stats.dma_copies++;
++ fbdev->dma_stats.dma_copies++;
++
++ mutex_unlock(&fbdev->dma_mutex);
+ }
+
+ /* address with no aliases */
+@@ -542,10 +730,13 @@ static int bcm2708_ioctl(struct fb_info
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+- ret = rpi_firmware_property(fb->fw,
++ set_display_num(fb);
++
++ ret = rpi_firmware_property(fb->fbdev->fw,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC,
+ &dummy, sizeof(dummy));
+ break;
++
+ case FBIODMACOPY:
+ {
+ struct fb_dmacopy ioparam;
+@@ -615,23 +806,22 @@ static int bcm2708_compat_ioctl(struct f
+ static void bcm2708_fb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+ {
+- /* (is called) print_debug("bcm2708_fb_fillrect\n"); */
+ cfb_fillrect(info, rect);
+ }
+
+ /* A helper function for configuring dma control block */
+ static void set_dma_cb(struct bcm2708_dma_cb *cb,
+- int burst_size,
+- dma_addr_t dst,
+- int dst_stride,
+- dma_addr_t src,
+- int src_stride,
+- int w,
+- int h)
++ int burst_size,
++ dma_addr_t dst,
++ int dst_stride,
++ dma_addr_t src,
++ int src_stride,
++ int w,
++ int h)
+ {
+ cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH |
+- BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
+- BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE;
++ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
++ BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE;
+ cb->dst = dst;
+ cb->src = src;
+ /*
+@@ -649,15 +839,19 @@ static void bcm2708_fb_copyarea(struct f
+ const struct fb_copyarea *region)
+ {
+ struct bcm2708_fb *fb = to_bcm2708(info);
+- struct bcm2708_dma_cb *cb = fb->cb_base;
++ struct bcm2708_fb_dev *fbdev = fb->fbdev;
++ struct bcm2708_dma_cb *cb = fbdev->cb_base;
+ int bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3;
+
+ /* Channel 0 supports larger bursts and is a bit faster */
+- int burst_size = (fb->dma_chan == 0) ? 8 : 2;
++ int burst_size = (fbdev->dma_chan == 0) ? 8 : 2;
+ int pixels = region->width * region->height;
+
+- /* Fallback to cfb_copyarea() if we don't like something */
+- if (bytes_per_pixel > 4 ||
++ /* If DMA is currently in use (ie being used on another FB), then
++ * rather than wait for it to finish, just use the cfb_copyarea
++ */
++ if (!mutex_trylock(&fbdev->dma_mutex) ||
++ bytes_per_pixel > 4 ||
+ info->var.xres * info->var.yres > 1920 * 1200 ||
+ region->width <= 0 || region->width > info->var.xres ||
+ region->height <= 0 || region->height > info->var.yres ||
+@@ -684,8 +878,8 @@ static void bcm2708_fb_copyarea(struct f
+ * 1920x1200 resolution at 32bpp pixel depth.
+ */
+ int y;
+- dma_addr_t control_block_pa = fb->cb_handle;
+- dma_addr_t scratchbuf = fb->cb_handle + 16 * 1024;
++ dma_addr_t control_block_pa = fbdev->cb_handle;
++ dma_addr_t scratchbuf = fbdev->cb_handle + 16 * 1024;
+ int scanline_size = bytes_per_pixel * region->width;
+ int scanlines_per_cb = (64 * 1024 - 16 * 1024) / scanline_size;
+
+@@ -735,10 +929,10 @@ static void bcm2708_fb_copyarea(struct f
+ }
+ set_dma_cb(cb, burst_size,
+ fb->fb_bus_address + dy * fb->fb.fix.line_length +
+- bytes_per_pixel * region->dx,
++ bytes_per_pixel * region->dx,
+ stride,
+ fb->fb_bus_address + sy * fb->fb.fix.line_length +
+- bytes_per_pixel * region->sx,
++ bytes_per_pixel * region->sx,
+ stride,
+ region->width * bytes_per_pixel,
+ region->height);
+@@ -748,32 +942,33 @@ static void bcm2708_fb_copyarea(struct f
+ cb->next = 0;
+
+ if (pixels < dma_busy_wait_threshold) {
+- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
+- bcm_dma_wait_idle(fb->dma_chan_base);
++ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle);
++ bcm_dma_wait_idle(fbdev->dma_chan_base);
+ } else {
+- void __iomem *dma_chan = fb->dma_chan_base;
++ void __iomem *local_dma_chan = fbdev->dma_chan_base;
+
+ cb->info |= BCM2708_DMA_INT_EN;
+- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
+- while (bcm_dma_is_busy(dma_chan)) {
+- wait_event_interruptible(fb->dma_waitq,
+- !bcm_dma_is_busy(dma_chan));
++ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle);
++ while (bcm_dma_is_busy(local_dma_chan)) {
++ wait_event_interruptible(fbdev->dma_waitq,
++ !bcm_dma_is_busy(local_dma_chan));
+ }
+- fb->stats.dma_irqs++;
++ fbdev->dma_stats.dma_irqs++;
+ }
+- fb->stats.dma_copies++;
++ fbdev->dma_stats.dma_copies++;
++
++ mutex_unlock(&fbdev->dma_mutex);
+ }
+
+ static void bcm2708_fb_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+ {
+- /* (is called) print_debug("bcm2708_fb_imageblit\n"); */
+ cfb_imageblit(info, image);
+ }
+
+ static irqreturn_t bcm2708_fb_dma_irq(int irq, void *cxt)
+ {
+- struct bcm2708_fb *fb = cxt;
++ struct bcm2708_fb_dev *fbdev = cxt;
+
+ /* FIXME: should read status register to check if this is
+ * actually interrupting us or not, in case this interrupt
+@@ -783,9 +978,9 @@ static irqreturn_t bcm2708_fb_dma_irq(in
+ */
+
+ /* acknowledge the interrupt */
+- writel(BCM2708_DMA_INT, fb->dma_chan_base + BCM2708_DMA_CS);
++ writel(BCM2708_DMA_INT, fbdev->dma_chan_base + BCM2708_DMA_CS);
+
+- wake_up(&fb->dma_waitq);
++ wake_up(&fbdev->dma_waitq);
+ return IRQ_HANDLED;
+ }
+
+@@ -821,11 +1016,23 @@ static int bcm2708_fb_register(struct bc
+ fb->fb.fix.ywrapstep = 0;
+ fb->fb.fix.accel = FB_ACCEL_NONE;
+
+- fb->fb.var.xres = fbwidth;
+- fb->fb.var.yres = fbheight;
+- fb->fb.var.xres_virtual = fbwidth;
+- fb->fb.var.yres_virtual = fbheight;
+- fb->fb.var.bits_per_pixel = fbdepth;
++ /* If we have data from the VC4 on FB's, use that, otherwise use the
++ * module parameters
++ */
++ if (fb->display_settings.width) {
++ fb->fb.var.xres = fb->display_settings.width;
++ fb->fb.var.yres = fb->display_settings.height;
++ fb->fb.var.xres_virtual = fb->fb.var.xres;
++ fb->fb.var.yres_virtual = fb->fb.var.yres;
++ fb->fb.var.bits_per_pixel = fb->display_settings.depth;
++ } else {
++ fb->fb.var.xres = fbwidth;
++ fb->fb.var.yres = fbheight;
++ fb->fb.var.xres_virtual = fbwidth;
++ fb->fb.var.yres_virtual = fbheight;
++ fb->fb.var.bits_per_pixel = fbdepth;
++ }
++
+ fb->fb.var.vmode = FB_VMODE_NONINTERLACED;
+ fb->fb.var.activate = FB_ACTIVATE_NOW;
+ fb->fb.var.nonstd = 0;
+@@ -841,26 +1048,23 @@ static int bcm2708_fb_register(struct bc
+ fb->fb.monspecs.dclkmax = 100000000;
+
+ bcm2708_fb_set_bitfields(&fb->fb.var);
+- init_waitqueue_head(&fb->dma_waitq);
+
+ /*
+ * Allocate colourmap.
+ */
+-
+ fb_set_var(&fb->fb, &fb->fb.var);
++
+ ret = bcm2708_fb_set_par(&fb->fb);
++
+ if (ret)
+ return ret;
+
+- print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n",
+- fbwidth, fbheight, fbdepth, fbswap);
+-
+ ret = register_framebuffer(&fb->fb);
+- print_debug("BCM2708FB: register framebuffer (%d)\n", ret);
++
+ if (ret == 0)
+ goto out;
+
+- print_debug("BCM2708FB: cannot register framebuffer (%d)\n", ret);
++ dev_warn(fb->fb.dev, "Unable to register framebuffer (%d)\n", ret);
+ out:
+ return ret;
+ }
+@@ -869,10 +1073,18 @@ static int bcm2708_fb_probe(struct platf
+ {
+ struct device_node *fw_np;
+ struct rpi_firmware *fw;
+- struct bcm2708_fb *fb;
+- int ret;
++ int ret, i;
++ u32 num_displays;
++ struct bcm2708_fb_dev *fbdev;
++ struct { u32 base, length; } gpu_mem;
++
++ fbdev = devm_kzalloc(&dev->dev, sizeof(*fbdev), GFP_KERNEL);
++
++ if (!fbdev)
++ return -ENOMEM;
+
+ fw_np = of_parse_phandle(dev->dev.of_node, "firmware", 0);
++
+ /* Remove comment when booting without Device Tree is no longer supported
+ * if (!fw_np) {
+ * dev_err(&dev->dev, "Missing firmware node\n");
+@@ -880,90 +1092,154 @@ static int bcm2708_fb_probe(struct platf
+ * }
+ */
+ fw = rpi_firmware_get(fw_np);
++ fbdev->fw = fw;
++
+ if (!fw)
+ return -EPROBE_DEFER;
+
+- fb = kzalloc(sizeof(*fb), GFP_KERNEL);
+- if (!fb) {
+- ret = -ENOMEM;
+- goto free_region;
++ ret = rpi_firmware_property(fw,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
++ &num_displays, sizeof(u32));
++
++ /* If we fail to get the number of displays, or it returns 0, then
++ * assume old firmware that doesn't have the mailbox call, so just
++ * set one display
++ */
++ if (ret || num_displays == 0) {
++ num_displays = 1;
++ dev_err(&dev->dev,
++ "Unable to determine number of FB's. Assuming 1\n");
++ ret = 0;
++ } else {
++ fbdev->firmware_supports_multifb = 1;
+ }
+
+- fb->fw = fw;
+- bcm2708_fb_debugfs_init(fb);
++ if (num_displays > MAX_FRAMEBUFFERS) {
++ dev_warn(&dev->dev,
++ "More displays reported from firmware than supported in driver (%u vs %u)",
++ num_displays, MAX_FRAMEBUFFERS);
++ num_displays = MAX_FRAMEBUFFERS;
++ }
+
+- fb->cb_base = dma_alloc_writecombine(&dev->dev, SZ_64K,
+- &fb->cb_handle, GFP_KERNEL);
+- if (!fb->cb_base) {
++ dev_info(&dev->dev, "FB found %d display(s)\n", num_displays);
++
++ /* Set up the DMA information. Note we have just one set of DMA
++ * parameters to work with all the FB's so requires synchronising when
++ * being used
++ */
++
++ mutex_init(&fbdev->dma_mutex);
++
++ fbdev->cb_base = dma_alloc_writecombine(&dev->dev, SZ_64K,
++ &fbdev->cb_handle,
++ GFP_KERNEL);
++ if (!fbdev->cb_base) {
+ dev_err(&dev->dev, "cannot allocate DMA CBs\n");
+ ret = -ENOMEM;
+ goto free_fb;
+ }
+
+- pr_info("BCM2708FB: allocated DMA memory %pad\n", &fb->cb_handle);
+-
+ ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK,
+- &fb->dma_chan_base, &fb->dma_irq);
++ &fbdev->dma_chan_base,
++ &fbdev->dma_irq);
+ if (ret < 0) {
+- dev_err(&dev->dev, "couldn't allocate a DMA channel\n");
++ dev_err(&dev->dev, "Couldn't allocate a DMA channel\n");
+ goto free_cb;
+ }
+- fb->dma_chan = ret;
++ fbdev->dma_chan = ret;
+
+- ret = request_irq(fb->dma_irq, bcm2708_fb_dma_irq,
+- 0, "bcm2708_fb dma", fb);
++ ret = request_irq(fbdev->dma_irq, bcm2708_fb_dma_irq,
++ 0, "bcm2708_fb DMA", fbdev);
+ if (ret) {
+- pr_err("%s: failed to request DMA irq\n", __func__);
++ dev_err(&dev->dev,
++ "Failed to request DMA irq\n");
+ goto free_dma_chan;
+ }
+
+- pr_info("BCM2708FB: allocated DMA channel %d\n", fb->dma_chan);
++ rpi_firmware_property(fbdev->fw,
++ RPI_FIRMWARE_GET_VC_MEMORY,
++ &gpu_mem, sizeof(gpu_mem));
++
++ for (i = 0; i < num_displays; i++) {
++ struct bcm2708_fb *fb = &fbdev->displays[i];
++
++ fb->display_settings.display_num = i;
++ fb->dev = dev;
++ fb->fb.device = &dev->dev;
++ fb->fbdev = fbdev;
++
++ fb->gpu.base = gpu_mem.base;
++ fb->gpu.length = gpu_mem.length;
++
++ if (fbdev->firmware_supports_multifb) {
++ ret = rpi_firmware_property(fw,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS,
++ &fb->display_settings,
++ GET_DISPLAY_SETTINGS_PAYLOAD_SIZE);
++ } else {
++ memset(&fb->display_settings, 0,
++ sizeof(fb->display_settings));
++ }
++
++ ret = bcm2708_fb_register(fb);
+
+- fb->dev = dev;
+- fb->fb.device = &dev->dev;
++ if (ret == 0) {
++ bcm2708_fb_debugfs_init(fb);
+
+- /* failure here isn't fatal, but we'll fail in vc_mem_copy if
+- * fb->gpu is not valid
+- */
+- rpi_firmware_property(fb->fw, RPI_FIRMWARE_GET_VC_MEMORY, &fb->gpu,
+- sizeof(fb->gpu));
++ fbdev->num_displays++;
+
+- ret = bcm2708_fb_register(fb);
+- if (ret == 0) {
+- platform_set_drvdata(dev, fb);
+- goto out;
++ dev_info(&dev->dev,
++ "Registered framebuffer for display %u, size %ux%u\n",
++ fb->display_settings.display_num,
++ fb->fb.var.xres,
++ fb->fb.var.yres);
++ } else {
++ // Use this to flag if this FB entry is in use.
++ fb->fbdev = NULL;
++ }
++ }
++
++ // Did we actually successfully create any FB's?
++ if (fbdev->num_displays) {
++ init_waitqueue_head(&fbdev->dma_waitq);
++ platform_set_drvdata(dev, fbdev);
++ return ret;
+ }
+
+ free_dma_chan:
+- bcm_dma_chan_free(fb->dma_chan);
++ bcm_dma_chan_free(fbdev->dma_chan);
+ free_cb:
+- dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
++ dma_free_writecombine(&dev->dev, SZ_64K, fbdev->cb_base,
++ fbdev->cb_handle);
+ free_fb:
+- kfree(fb);
+-free_region:
+ dev_err(&dev->dev, "probe failed, err %d\n", ret);
+-out:
++
+ return ret;
+ }
+
+ static int bcm2708_fb_remove(struct platform_device *dev)
+ {
+- struct bcm2708_fb *fb = platform_get_drvdata(dev);
++ struct bcm2708_fb_dev *fbdev = platform_get_drvdata(dev);
++ int i;
+
+ platform_set_drvdata(dev, NULL);
+
+- if (fb->fb.screen_base)
+- iounmap(fb->fb.screen_base);
+- unregister_framebuffer(&fb->fb);
+-
+- dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
+- bcm_dma_chan_free(fb->dma_chan);
+-
+- bcm2708_fb_debugfs_deinit(fb);
++ for (i = 0; i < fbdev->num_displays; i++) {
++ if (fbdev->displays[i].fb.screen_base)
++ iounmap(fbdev->displays[i].fb.screen_base);
++
++ if (fbdev->displays[i].fbdev) {
++ unregister_framebuffer(&fbdev->displays[i].fb);
++ bcm2708_fb_debugfs_deinit(&fbdev->displays[i]);
++ }
++ }
+
+- free_irq(fb->dma_irq, fb);
++ dma_free_writecombine(&dev->dev, SZ_64K, fbdev->cb_base,
++ fbdev->cb_handle);
++ bcm_dma_chan_free(fbdev->dma_chan);
++ free_irq(fbdev->dma_irq, fbdev);
+
+- kfree(fb);
++ mutex_destroy(&fbdev->dma_mutex);
+
+ return 0;
+ }
+@@ -978,10 +1254,10 @@ static struct platform_driver bcm2708_fb
+ .probe = bcm2708_fb_probe,
+ .remove = bcm2708_fb_remove,
+ .driver = {
+- .name = DRIVER_NAME,
+- .owner = THIS_MODULE,
+- .of_match_table = bcm2708_fb_of_match_table,
+- },
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = bcm2708_fb_of_match_table,
++ },
+ };
+
+ static int __init bcm2708_fb_init(void)
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -138,9 +138,11 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007,
++ RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH = 0x00048008,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
++
+ RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
+@@ -159,6 +161,8 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
+ };
+
++#define GET_DISPLAY_SETTINGS_PAYLOAD_SIZE 64
++
+ #if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE)
+ int rpi_firmware_property(struct rpi_firmware *fw,
+ u32 tag, void *data, size_t len);
+++ /dev/null
-From c38256621d4dffbbc0c19737d724724f04b0df9a Mon Sep 17 00:00:00 2001
-Date: Thu, 16 May 2019 15:17:19 +0100
-Subject: [PATCH] staging: vcsm-cma: Drop logging level on messages in
- vc_sm_release_resource
-
-They weren't errors but were logged as such.
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 7 +++----
- 1 file changed, 3 insertions(+), 4 deletions(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -301,14 +301,13 @@ static void vc_sm_release_resource(struc
-
- if (buffer->vc_handle) {
- /* We've sent the unmap request but not had the response. */
-- pr_err("[%s]: Waiting for VPU unmap response on %p\n",
-- __func__, buffer);
-+ pr_debug("[%s]: Waiting for VPU unmap response on %p\n",
-+ __func__, buffer);
- goto defer;
- }
- if (buffer->in_use) {
- /* dmabuf still in use - we await the release */
-- pr_err("[%s]: buffer %p is still in use\n",
-- __func__, buffer);
-+ pr_debug("[%s]: buffer %p is still in use\n", __func__, buffer);
- goto defer;
- }
-
--- /dev/null
+From 545c00748a070340e9669740e45afc2672e1fcb6 Mon Sep 17 00:00:00 2001
+Date: Sun, 19 May 2019 12:26:21 +0200
+Subject: [PATCH] ARM: dts: bcm283x: Move BCM2835/6/7 specific to
+ bcm2835-common.dtsi
+
+We want all common BCM2835/6/7/8 functions in bcm283x.dtsi and all
+BCM2835/6/7 specific in the new bcm2835-common.dtsi.
+
+---
+ arch/arm/boot/dts/bcm2835-common.dtsi | 53 +++++++++++++++++++++++++++
+ arch/arm/boot/dts/bcm2835.dtsi | 1 +
+ arch/arm/boot/dts/bcm2836.dtsi | 1 +
+ arch/arm/boot/dts/bcm2837.dtsi | 1 +
+ arch/arm/boot/dts/bcm283x.dtsi | 43 +---------------------
+ 5 files changed, 57 insertions(+), 42 deletions(-)
+ create mode 100644 arch/arm/boot/dts/bcm2835-common.dtsi
+
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2835-common.dtsi
+@@ -0,0 +1,53 @@
++// SPDX-License-Identifier: GPL-2.0
++
++/* This include file covers the common peripherals and configuration between
++ * bcm2835, bcm2836 and bcm2837 implementations.
++ */
++
++/ {
++ soc {
++ timer@7e003000 {
++ compatible = "brcm,bcm2835-system-timer";
++ reg = <0x7e003000 0x1000>;
++ interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
++ /* This could be a reference to BCM2835_CLOCK_TIMER,
++ * but we don't have the driver using the common clock
++ * support yet.
++ */
++ clock-frequency = <1000000>;
++ };
++
++ intc: interrupt-controller@7e00b200 {
++ compatible = "brcm,bcm2835-armctrl-ic";
++ reg = <0x7e00b200 0x200>;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ thermal: thermal@7e212000 {
++ compatible = "brcm,bcm2835-thermal";
++ reg = <0x7e212000 0x8>;
++ clocks = <&clocks BCM2835_CLOCK_TSENS>;
++ #thermal-sensor-cells = <0>;
++ status = "disabled";
++ };
++
++ v3d: v3d@7ec00000 {
++ compatible = "brcm,bcm2835-v3d";
++ reg = <0x7ec00000 0x1000>;
++ interrupts = <1 10>;
++ };
++ };
++};
++
++&gpio {
++ i2c_slave_gpio18: i2c_slave_gpio18 {
++ brcm,pins = <18 19 20 21>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++
++ jtag_gpio4: jtag_gpio4 {
++ brcm,pins = <4 5 6 12 13>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++};
+--- a/arch/arm/boot/dts/bcm2835.dtsi
++++ b/arch/arm/boot/dts/bcm2835.dtsi
+@@ -1,5 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0
+ #include "bcm283x.dtsi"
++#include "bcm2835-common.dtsi"
+
+ / {
+ compatible = "brcm,bcm2835";
+--- a/arch/arm/boot/dts/bcm2836.dtsi
++++ b/arch/arm/boot/dts/bcm2836.dtsi
+@@ -1,5 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0
+ #include "bcm283x.dtsi"
++#include "bcm2835-common.dtsi"
+
+ / {
+ compatible = "brcm,bcm2836";
+--- a/arch/arm/boot/dts/bcm2837.dtsi
++++ b/arch/arm/boot/dts/bcm2837.dtsi
+@@ -1,4 +1,5 @@
+ #include "bcm283x.dtsi"
++#include "bcm2835-common.dtsi"
+
+ / {
+ compatible = "brcm,bcm2837";
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -55,17 +55,6 @@
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+- timer@7e003000 {
+- compatible = "brcm,bcm2835-system-timer";
+- reg = <0x7e003000 0x1000>;
+- interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
+- /* This could be a reference to BCM2835_CLOCK_TIMER,
+- * but we don't have the driver using the common clock
+- * support yet.
+- */
+- clock-frequency = <1000000>;
+- };
+-
+ txp@7e004000 {
+ compatible = "brcm,bcm2835-txp";
+ reg = <0x7e004000 0x20>;
+@@ -113,13 +102,6 @@
+ brcm,dma-channel-mask = <0x7f35>;
+ };
+
+- intc: interrupt-controller@7e00b200 {
+- compatible = "brcm,bcm2835-armctrl-ic";
+- reg = <0x7e00b200 0x200>;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+ watchdog@7e100000 {
+ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
+ #power-domain-cells = <1>;
+@@ -183,8 +165,7 @@
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+- /* Defines pin muxing groups according to
+- * BCM2835-ARM-Peripherals.pdf page 102.
++ /* Defines common pin muxing groups
+ *
+ * While each pin can have its mux selected
+ * for various functions individually, some
+@@ -262,15 +243,7 @@
+ brcm,pins = <44 45>;
+ brcm,function = <BCM2835_FSEL_ALT2>;
+ };
+- i2c_slave_gpio18: i2c_slave_gpio18 {
+- brcm,pins = <18 19 20 21>;
+- brcm,function = <BCM2835_FSEL_ALT3>;
+- };
+
+- jtag_gpio4: jtag_gpio4 {
+- brcm,pins = <4 5 6 12 13>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+ jtag_gpio22: jtag_gpio22 {
+ brcm,pins = <22 23 24 25 26 27>;
+ brcm,function = <BCM2835_FSEL_ALT4>;
+@@ -487,14 +460,6 @@
+
+ };
+
+- thermal: thermal@7e212000 {
+- compatible = "brcm,bcm2835-thermal";
+- reg = <0x7e212000 0x8>;
+- clocks = <&clocks BCM2835_CLOCK_TSENS>;
+- #thermal-sensor-cells = <0>;
+- status = "disabled";
+- };
+-
+ aux: aux@7e215000 {
+ compatible = "brcm,bcm2835-aux";
+ #clock-cells = <1>;
+@@ -660,12 +625,6 @@
+ phy-names = "usb2-phy";
+ };
+
+- v3d: v3d@7ec00000 {
+- compatible = "brcm,bcm2835-v3d";
+- reg = <0x7ec00000 0x1000>;
+- interrupts = <1 10>;
+- };
+-
+ vc4: gpu {
+ compatible = "brcm,bcm2835-vc4";
+ };
+++ /dev/null
-From 52f881e3afa89bb1ca9e8b037f7600bcc97626e8 Mon Sep 17 00:00:00 2001
-Date: Wed, 22 May 2019 15:40:37 +0100
-Subject: [PATCH] staging: vcsm-cma: Fixup the alloc code handling of
- kernel_id
-
-The allocation code had been copied in from an old branch prior
-to having added the IDR for 64bit support. It was therefore pushing
-a pointer into the kernel_id field instead of an IDR handle, the
-lookup therefore failed, and we never released the buffer.
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -1206,7 +1206,7 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
-
- import.addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
- import.size = aligned_size;
-- import.kernel_id = (uint32_t)buffer;
-+ import.kernel_id = get_kernel_id(buffer);
-
- /* Wrap it into a videocore buffer. */
- status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result,
-@@ -1231,6 +1231,7 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
- buffer->size = import.size;
- buffer->dma_addr = import.addr;
- buffer->vpu_state = VPU_MAPPED;
-+ buffer->kernel_id = import.kernel_id;
- //buffer->res_cached = ioparam->cached;
-
- fd = dma_buf_fd(dmabuf, O_CLOEXEC);
--- /dev/null
+From ff78cbcd8d7d656a5f43abd2c744e610b8c6c740 Mon Sep 17 00:00:00 2001
+Date: Wed, 29 May 2019 13:54:21 +0100
+Subject: [PATCH] ARM: dts: Add bcm2711-rpi-4-b.dts and components
+
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 320 ++++++++++++
+ arch/arm/boot/dts/bcm2711.dtsi | 50 ++
+ arch/arm/boot/dts/bcm2838.dtsi | 724 ++++++++++++++++++++++++++
+ 4 files changed, 1095 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+ create mode 100644 arch/arm/boot/dts/bcm2711.dtsi
+ create mode 100644 arch/arm/boot/dts/bcm2838.dtsi
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -8,6 +8,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2708-rpi-zero-w.dtb \
+ bcm2709-rpi-2-b.dtb \
+ bcm2710-rpi-3-b.dtb \
++ bcm2711-rpi-4-b.dtb \
+ bcm2710-rpi-3-b-plus.dtb \
+ bcm2710-rpi-cm3.dtb
+
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -0,0 +1,320 @@
++/dts-v1/;
++
++#include "bcm2711.dtsi"
++
++/ {
++ compatible = "raspberrypi,4-model-b", "brcm,bcm2838", "brcm,bcm2837";
++ model = "Raspberry Pi 4 Model B";
++ #address-cells = <2>;
++ #size-cells = <1>;
++
++ memory {
++ device_type = "memory";
++ reg = <0x0 0x0 0x0>;
++ };
++
++ chosen {
++ bootargs = "8250.nr_uarts=1 cma=64M";
++ };
++
++ aliases {
++ serial0 = &uart1;
++ serial1 = &uart0;
++ mmc0 = &emmc2;
++ mmc1 = &mmcnr;
++ mmc2 = &sdhost;
++ /delete-property/ ethernet;
++ /delete-property/ intc;
++ ethernet0 = &genet;
++ };
++};
++
++&soc {
++ virtgpio: virtgpio {
++ compatible = "brcm,bcm2835-virtgpio";
++ gpio-controller;
++ #gpio-cells = <2>;
++ firmware = <&firmware>;
++ status = "okay";
++ };
++};
++
++&mmcnr {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdio_pins>;
++ bus-width = <4>;
++ status = "okay";
++};
++
++&firmware {
++ expgpio: expgpio {
++ compatible = "raspberrypi,firmware-gpio";
++ gpio-controller;
++ #gpio-cells = <2>;
++ 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>;
++ };
++};
++
++// =============================================
++// Board specific stuff here
++
++/ {
++
++ sd_io_1v8_reg: sd_io_1v8_reg {
++ status = "okay";
++ compatible = "regulator-gpio";
++ vin-supply = <&vdd_5v0_reg>;
++ regulator-name = "vdd-sd-io";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ regulator-settling-time-us = <5000>;
++
++ gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
++ states = <1800000 0x1
++ 3300000 0x0>;
++ };
++};
++
++&sdhost {
++ status = "disabled";
++};
++
++&emmc2 {
++ status = "okay";
++ broken-cd;
++ vqmmc-supply = <&sd_io_1v8_reg>;
++};
++
++&leds {
++ act_led: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&gpio 42 0>;
++ };
++
++ pwr_led: pwr {
++ label = "led1";
++ linux,default-trigger = "input";
++ gpios = <&expgpio 2 0>;
++ };
++};
++
++&audio {
++ pinctrl-names = "default";
++ pinctrl-0 = <&audio_pins>;
++};
++
++&sdhost_gpio48 {
++ brcm,pins = <22 23 24 25 26 27>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++};
++
++&gpio {
++ spi0_pins: spi0_pins {
++ brcm,pins = <9 10 11>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++
++ spi0_cs_pins: spi0_cs_pins {
++ brcm,pins = <8 7>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++
++ spi3_pins: spi3_pins {
++ brcm,pins = <1 2 3>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++
++ spi3_cs_pins: spi3_cs_pins {
++ brcm,pins = <0 24>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++
++ spi4_pins: spi4_pins {
++ brcm,pins = <5 6 7>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++
++ spi4_cs_pins: spi4_cs_pins {
++ brcm,pins = <4 25>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++
++ spi5_pins: spi5_pins {
++ brcm,pins = <13 14 15>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++
++ spi5_cs_pins: spi5_cs_pins {
++ brcm,pins = <12 26>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++
++ spi6_pins: spi6_pins {
++ brcm,pins = <19 20 21>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++
++ spi6_cs_pins: spi6_cs_pins {
++ brcm,pins = <18 27>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++
++ i2c0_pins: i2c0 {
++ brcm,pins = <0 1>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++
++ i2c1_pins: i2c1 {
++ brcm,pins = <2 3>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++
++ i2c3_pins: i2c3 {
++ brcm,pins = <4 5>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++
++ i2c4_pins: i2c4 {
++ brcm,pins = <8 9>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++
++ i2c5_pins: i2c5 {
++ brcm,pins = <12 13>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++
++ i2c6_pins: i2c6 {
++ brcm,pins = <22 23>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++
++ i2s_pins: i2s {
++ brcm,pins = <18 19 20 21>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++
++ sdio_pins: sdio_pins {
++ brcm,pins = <34 35 36 37 38 39>;
++ brcm,function = <BCM2835_FSEL_ALT3>; // alt3 = SD1
++ brcm,pull = <0 2 2 2 2 2>;
++ };
++
++ bt_pins: bt_pins {
++ brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0
++ // to fool pinctrl
++ brcm,function = <0>;
++ brcm,pull = <2>;
++ };
++
++ uart0_pins: uart0_pins {
++ brcm,pins = <32 33>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ brcm,pull = <0 2>;
++ };
++
++ uart1_pins: uart1_pins {
++ brcm,pins;
++ brcm,function;
++ brcm,pull;
++ };
++
++ uart2_pins: uart2_pins {
++ brcm,pins = <0 1>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <0 2>;
++ };
++
++ uart3_pins: uart3_pins {
++ brcm,pins = <4 5>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <0 2>;
++ };
++
++ uart4_pins: uart4_pins {
++ brcm,pins = <8 9>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <0 2>;
++ };
++
++ uart5_pins: uart5_pins {
++ brcm,pins = <12 13>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <0 2>;
++ };
++
++ audio_pins: audio_pins {
++ brcm,pins = <40 41>;
++ brcm,function = <4>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ 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>;
++};
++
++/ {
++ __overrides__ {
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++
++ pwr_led_gpio = <&pwr_led>,"gpios:4";
++ pwr_led_activelow = <&pwr_led>,"gpios:8";
++ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2711.dtsi
+@@ -0,0 +1,50 @@
++#include "bcm2838.dtsi"
++#include "bcm270x.dtsi"
++#include "bcm2708-rpi.dtsi"
++
++/ {
++ soc {
++ /delete-node/ mailbox@7e00b840;
++ /delete-node/ v3d@7ec00000;
++ };
++
++ __overrides__ {
++ arm_freq;
++ };
++};
++
++&dma {
++ brcm,dma-channel-mask = <0x7ef5>;
++};
++
++&txp {
++ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&firmwarekms {
++ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&smi {
++ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&mmc {
++ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&mmcnr {
++ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&usb {
++ reg = <0x7e980000 0x10000>,
++ <0x7e00b200 0x200>;
++ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&gpio {
++ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -0,0 +1,724 @@
++// SPDX-License-Identifier: GPL-2.0
++#include "bcm283x.dtsi"
++
++#include <dt-bindings/interrupt-controller/arm-gic.h>
++#include <dt-bindings/soc/bcm2835-pm.h>
++
++/ {
++ compatible = "brcm,bcm2838", "brcm,bcm2837";
++
++ interrupt-parent = <&gicv2>;
++
++ soc {
++ ranges = <0x7e000000 0x0 0xfe000000 0x01800000>,
++ <0x7c000000 0x0 0xfc000000 0x02000000>,
++ <0x40000000 0x0 0xff800000 0x00800000>;
++ /* Emulate a contiguous 30-bit address range for DMA */
++ dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
++
++ /delete-node/ mailbox@7e00b840;
++ /delete-node/ interrupt-controller@7e00f300;
++
++ local_intc: local_intc@40000000 {
++ compatible = "brcm,bcm2836-l1-intc";
++ reg = <0x40000000 0x100>;
++ };
++
++ gicv2: gic400@40041000 {
++ interrupt-controller;
++ #interrupt-cells = <3>;
++ compatible = "arm,gic-400";
++ reg = <0x40041000 0x1000>,
++ <0x40042000 0x2000>,
++ <0x40046000 0x2000>,
++ <0x40048000 0x2000>;
++ };
++
++ thermal: thermal@7d5d2200 {
++ compatible = "brcm,avs-tmon-bcm2838";
++ reg = <0x7d5d2200 0x2c>;
++ interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "tmon";
++ clocks = <&clocks BCM2835_CLOCK_TSENS>;
++ #thermal-sensor-cells = <0>;
++ status = "okay";
++ };
++
++ pm: watchdog@7e100000 {
++ reg = <0x7e100000 0x114>,
++ <0x7e00a000 0x24>,
++ <0x7ec11000 0x20>;
++ };
++
++ rng@7e104000 {
++ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ uart2: serial@7e201400 {
++ compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
++ reg = <0x7e201400 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ uart3: serial@7e201600 {
++ compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
++ reg = <0x7e201600 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ uart4: serial@7e201800 {
++ compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
++ reg = <0x7e201800 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ uart5: serial@7e201a00 {
++ compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
++ reg = <0x7e201a00 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ spi@7e204000 {
++ reg = <0x7e204000 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ spi3: spi@7e204600 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204600 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi4: spi@7e204800 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204800 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi5: spi@7e204a00 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204a00 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi6: spi@7e204c00 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204c00 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c3: i2c@7e205600 {
++ compatible = "brcm,bcm2835-i2c";
++ reg = <0x7e205600 0x200>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c4: i2c@7e205800 {
++ compatible = "brcm,bcm2835-i2c";
++ reg = <0x7e205800 0x200>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c5: i2c@7e205a00 {
++ compatible = "brcm,bcm2835-i2c";
++ reg = <0x7e205a00 0x200>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c6: i2c@7e205c00 {
++ compatible = "brcm,bcm2835-i2c";
++ reg = <0x7e205c00 0x200>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ pixelvalve@7e206000 {
++ interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ pixelvalve@7e207000 {
++ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ emmc2: emmc2@7e340000 {
++ compatible = "brcm,bcm2711-emmc2";
++ status = "okay";
++ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2838_CLOCK_EMMC2>;
++ reg = <0x7e340000 0x100>;
++ };
++
++ hvs@7e400000 {
++ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ pixelvalve@7e807000 {
++ interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
++ };
++ };
++
++ arm-pmu {
++ /*
++ * N.B. the A72 PMU support only exists in arch/arm64, hence
++ * the fallback to the A53 version.
++ */
++ compatible = "arm,cortex-a72-pmu", "arm,cortex-a53-pmu";
++ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ timer {
++ compatible = "arm,armv7-timer";
++ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>,
++ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>,
++ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>,
++ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>;
++ arm,cpu-registers-not-fw-configured;
++ always-on;
++ };
++
++ cpus: cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
++
++ cpu0: cpu@0 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a72";
++ reg = <0>;
++ enable-method = "spin-table";
++ cpu-release-addr = <0x0 0x000000d8>;
++ };
++
++ cpu1: cpu@1 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a72";
++ reg = <1>;
++ enable-method = "spin-table";
++ cpu-release-addr = <0x0 0x000000e0>;
++ };
++
++ cpu2: cpu@2 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a72";
++ reg = <2>;
++ enable-method = "spin-table";
++ cpu-release-addr = <0x0 0x000000e8>;
++ };
++
++ cpu3: cpu@3 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a72";
++ reg = <3>;
++ enable-method = "spin-table";
++ cpu-release-addr = <0x0 0x000000f0>;
++ };
++ };
++
++ v3dbus {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges = <0x7c500000 0x0 0xfc500000 0x03300000>,
++ <0x40000000 0x0 0xff800000 0x00800000>;
++ dma-ranges = <0x00000000 0x0 0x00000000 0x3c000000>;
++
++ v3d: v3d@7ec04000 {
++ compatible = "brcm,2711-v3d";
++ reg =
++ <0x7ec00000 0x4000>,
++ <0x7ec04000 0x4000>;
++ reg-names = "hub", "core0";
++
++ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
++ resets = <&pm BCM2835_RESET_V3D>;
++ clocks = <&clocks BCM2835_CLOCK_V3D>;
++ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
++ status = "okay";
++ };
++ };
++
++ scb: scb {
++ compatible = "simple-bus";
++ #address-cells = <2>;
++ #size-cells = <1>;
++
++ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>,
++ <0x0 0x40000000 0x0 0xff800000 0x00800000>,
++ <0x6 0x00000000 0x6 0x00000000 0x40000000>,
++ <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
++ dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
++
++ pcie_0: pcie@7d500000 {
++ reg = <0x0 0x7d500000 0x9310>,
++ <0x0 0x7e00f300 0x20>;
++ msi-controller;
++ msi-parent = <&pcie_0>;
++ #address-cells = <3>;
++ #interrupt-cells = <1>;
++ #size-cells = <2>;
++ bus-range = <0x0 0x01>;
++ compatible = "brcm,bcm7211-pcie", "brcm,bcm7445-pcie",
++ "brcm,pci-plat-dev";
++ max-link-speed = <2>;
++ tot-num-pcie = <1>;
++ linux,pci-domain = <0>;
++ interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "pcie", "msi";
++ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143
++ IRQ_TYPE_LEVEL_HIGH
++ 0 0 0 2 &gicv2 GIC_SPI 144
++ IRQ_TYPE_LEVEL_HIGH
++ 0 0 0 3 &gicv2 GIC_SPI 145
++ IRQ_TYPE_LEVEL_HIGH
++ 0 0 0 4 &gicv2 GIC_SPI 146
++ IRQ_TYPE_LEVEL_HIGH>;
++
++ /* Map outbound accesses from scb:0x6_00000000-03ffffff
++ * to pci:0x0_f8000000-fbffffff
++ */
++ ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000
++ 0x0 0x04000000>;
++ /* Map inbound accesses from pci:0x0_00000000..ffffffff
++ * to scb:0x0_00000000-ffffffff
++ */
++ dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000
++ 0x1 0x00000000>;
++ status = "okay";
++ };
++
++ genet: genet@7d580000 {
++ compatible = "brcm,genet-v5";
++ reg = <0x0 0x7d580000 0x10000>;
++ status = "okay";
++ #address-cells = <0x1>;
++ #size-cells = <0x1>;
++ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
++ phy-handle = <&phy1>;
++ phy-mode = "rgmii";
++ mdio@e14 {
++ #address-cells = <0x0>;
++ #size-cells = <0x1>;
++ compatible = "brcm,genet-mdio-v5";
++ reg = <0xe14 0x8>;
++ reg-names = "mdio";
++ phy1: genet-phy@0 {
++ compatible =
++ "ethernet-phy-ieee802.3-c22";
++ /* No interrupts - use PHY_POLL */
++ max-speed = <1000>;
++ reg = <0x1>;
++ };
++ };
++ };
++
++ xhci: xhci@7e9c0000 {
++ compatible = "generic-xhci";
++ status = "disabled";
++ reg = <0x0 0x7e9c0000 0x100000>;
++ interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ vchiq: mailbox@7e00b840 {
++ compatible = "brcm,bcm2838-vchiq";
++ reg = <0 0x7e00b840 0x3c>;
++ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ hevc-decoder@7eb00000 {
++ compatible = "raspberrypi,argon-hevc-decoder";
++ reg = <0x0 0x7eb00000 0x10000>;
++ status = "okay";
++ };
++
++ argon-local-intc@7eb10000 {
++ compatible = "raspberrypi,argon-local-intc";
++ reg = <0x0 0x7eb10000 0x1000>;
++ status = "okay";
++ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ h264-decoder@7eb20000 {
++ compatible = "raspberrypi,argon-h264-decoder";
++ reg = <0x0 0x7eb20000 0x10000>;
++ status = "okay";
++ };
++
++ vp9-decoder@7eb30000 {
++ compatible = "raspberrypi,argon-vp9-decoder";
++ reg = <0x0 0x7eb30000 0x10000>;
++ status = "okay";
++ };
++ };
++};
++
++&clk_osc {
++ clock-frequency = <54000000>;
++};
++
++&clocks {
++ compatible = "brcm,bcm2838-cprman";
++};
++
++&cpu_thermal {
++ coefficients = <(-487) 410040>;
++};
++
++&dsi0 {
++ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&dsi1 {
++ interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&gpio {
++ gpclk0_gpio49: gpclk0_gpio49 {
++ brcm,pins = <49>;
++ brcm,function = <BCM2835_FSEL_ALT1>;
++ brcm,pull = <BCM2835_PUD_OFF>;
++ };
++ gpclk1_gpio50: gpclk1_gpio50 {
++ brcm,pins = <50>;
++ brcm,function = <BCM2835_FSEL_ALT1>;
++ brcm,pull = <BCM2835_PUD_OFF>;
++ };
++ gpclk2_gpio51: gpclk2_gpio51 {
++ brcm,pins = <51>;
++ brcm,function = <BCM2835_FSEL_ALT1>;
++ brcm,pull = <BCM2835_PUD_OFF>;
++ };
++
++ i2c0_gpio46: i2c0_gpio46 {
++ brcm,pins = <46 47>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++ i2c1_gpio46: i2c1_gpio46 {
++ brcm,pins = <46 47>;
++ brcm,function = <BCM2835_FSEL_ALT1>;
++ };
++ i2c3_gpio2: i2c3_gpio2 {
++ brcm,pins = <2 3>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ i2c3_gpio4: i2c3_gpio4 {
++ brcm,pins = <4 5>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ i2c4_gpio6: i2c4_gpio6 {
++ brcm,pins = <6 7>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ i2c4_gpio8: i2c4_gpio8 {
++ brcm,pins = <8 9>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ i2c5_gpio10: i2c5_gpio10 {
++ brcm,pins = <10 11>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ i2c5_gpio12: i2c5_gpio12 {
++ brcm,pins = <12 13>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ i2c6_gpio0: i2c6_gpio0 {
++ brcm,pins = <0 1>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ i2c6_gpio22: i2c6_gpio22 {
++ brcm,pins = <22 23>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ i2c_slave_gpio8: i2c_slave_gpio8 {
++ brcm,pins = <8 9 10 11>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++
++ jtag_gpio48: jtag_gpio48 {
++ brcm,pins = <48 49 50 51 52 53>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ };
++
++ mii_gpio28: mii_gpio28 {
++ brcm,pins = <28 29 30 31>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ };
++ mii_gpio36: mii_gpio36 {
++ brcm,pins = <36 37 38 39>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++
++ pcm_gpio50: pcm_gpio50 {
++ brcm,pins = <50 51 52 53>;
++ brcm,function = <BCM2835_FSEL_ALT2>;
++ };
++
++ pwm0_gpio52: pwm0_gpio52 {
++ brcm,pins = <52>;
++ brcm,function = <BCM2835_FSEL_ALT1>;
++ brcm,pull = <BCM2835_PUD_OFF>;
++ };
++ pwm1_gpio53: pwm1_gpio53 {
++ brcm,pins = <53>;
++ brcm,function = <BCM2835_FSEL_ALT1>;
++ brcm,pull = <BCM2835_PUD_OFF>;
++ };
++
++ /* The following group consists of:
++ * RGMII_START_STOP
++ * RGMII_RX_OK
++ */
++ rgmii_gpio35: rgmii_gpio35 {
++ brcm,pins = <35 36>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ };
++ rgmii_irq_gpio34: rgmii_irq_gpio34 {
++ brcm,pins = <34>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ rgmii_irq_gpio39: rgmii_irq_gpio39 {
++ brcm,pins = <39>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ };
++ rgmii_mdio_gpio28: rgmii_mdio_gpio28 {
++ brcm,pins = <28 29>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ rgmii_mdio_gpio37: rgmii_mdio_gpio37 {
++ brcm,pins = <37 38>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ };
++
++ spi0_gpio46: spi0_gpio46 {
++ brcm,pins = <46 47 48 49>;
++ brcm,function = <BCM2835_FSEL_ALT2>;
++ };
++ spi2_gpio46: spi2_gpio46 {
++ brcm,pins = <46 47 48 49 50>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ spi3_gpio0: spi3_gpio0 {
++ brcm,pins = <0 1 2 3>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++ spi4_gpio4: spi4_gpio4 {
++ brcm,pins = <4 5 6 7>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++ spi5_gpio12: spi5_gpio12 {
++ brcm,pins = <12 13 14 15>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++ spi6_gpio18: spi6_gpio18 {
++ brcm,pins = <18 19 20 21>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++
++ uart2_gpio0: uart2_gpio0 {
++ brcm,pins = <0 1>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
++ };
++ uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 {
++ brcm,pins = <2 3>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
++ };
++ uart3_gpio4: uart3_gpio4 {
++ brcm,pins = <4 5>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
++ };
++ uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 {
++ brcm,pins = <6 7>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
++ };
++ uart4_gpio8: uart4_gpio8 {
++ brcm,pins = <8 9>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
++ };
++ uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 {
++ brcm,pins = <10 11>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
++ };
++ uart5_gpio12: uart5_gpio12 {
++ brcm,pins = <12 13>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
++ };
++ uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 {
++ brcm,pins = <14 15>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
++ };
++};
++
++&vec {
++ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&usb {
++ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&hdmi {
++ interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&uart1 {
++ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&spi1 {
++ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&spi2 {
++ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&csi0 {
++ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&csi1 {
++ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&sdhci {
++ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&i2c0 {
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&i2c1 {
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&i2c2 {
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&gpio {
++ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&mailbox {
++ interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&rng {
++ compatible = "brcm,bcm2838-rng200";
++};
++
++&sdhost {
++ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&uart0 {
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&dma {
++ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 7 */
++ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 8 */
++ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 9 */
++ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 10 */
++ /* DMA4 - 40 bit DMA engines */
++ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
++ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 12 */
++ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, /* dma4 13 */
++ <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; /* dma4 14 */
++ interrupt-names = "dma0",
++ "dma1",
++ "dma2",
++ "dma3",
++ "dma4",
++ "dma5",
++ "dma6",
++ "dma7",
++ "dma8",
++ "dma9",
++ "dma10",
++ "dma11",
++ "dma12",
++ "dma13",
++ "dma14";
++ brcm,dma-channel-mask = <0x7ef5>;
++};
+++ /dev/null
-From 3e33fb46eb8791ba39fe4781f278487bcc2c3356 Mon Sep 17 00:00:00 2001
-Date: Thu, 14 Mar 2019 13:27:54 +0000
-Subject: [PATCH] Pulled in the multi frame buffer support from the Pi3
- repo
-
----
- drivers/video/fbdev/bcm2708_fb.c | 580 +++++++++++++++------
- include/soc/bcm2835/raspberrypi-firmware.h | 4 +
- 2 files changed, 432 insertions(+), 152 deletions(-)
-
---- a/drivers/video/fbdev/bcm2708_fb.c
-+++ b/drivers/video/fbdev/bcm2708_fb.c
-@@ -2,6 +2,7 @@
- * linux/drivers/video/bcm2708_fb.c
- *
- * Copyright (C) 2010 Broadcom
-+ * Copyright (C) 2018 Raspberry Pi (Trading) Ltd
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
-@@ -13,6 +14,7 @@
- *
- */
-+
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/errno.h>
-@@ -36,6 +38,7 @@
- #include <linux/dma-mapping.h>
- #include <linux/cred.h>
- #include <soc/bcm2835/raspberrypi-firmware.h>
-+#include <linux/mutex.h>
-
- //#define BCM2708_FB_DEBUG
- #define MODULE_NAME "bcm2708_fb"
-@@ -82,62 +85,139 @@ struct bcm2708_fb_stats {
- u32 dma_irqs;
- };
-
-+struct vc4_display_settings_t {
-+ u32 display_num;
-+ u32 width;
-+ u32 height;
-+ u32 pitch;
-+ u32 depth;
-+ u32 virtual_width;
-+ u32 virtual_height;
-+ u32 virtual_width_offset;
-+ u32 virtual_height_offset;
-+ unsigned long fb_bus_address;
-+};
-+
-+struct bcm2708_fb_dev;
-+
- struct bcm2708_fb {
- struct fb_info fb;
- struct platform_device *dev;
-- struct rpi_firmware *fw;
- u32 cmap[16];
- u32 gpu_cmap[256];
-+ struct dentry *debugfs_dir;
-+ struct dentry *debugfs_subdir;
-+ unsigned long fb_bus_address;
-+ struct { u32 base, length; } gpu;
-+ struct vc4_display_settings_t display_settings;
-+ struct debugfs_regset32 screeninfo_regset;
-+ struct bcm2708_fb_dev *fbdev;
-+ unsigned int image_size;
-+ dma_addr_t dma_addr;
-+ void *cpuaddr;
-+};
-+
-+#define MAX_FRAMEBUFFERS 3
-+
-+struct bcm2708_fb_dev {
-+ int firmware_supports_multifb;
-+ /* Protects the DMA system from multiple FB access */
-+ struct mutex dma_mutex;
- int dma_chan;
- int dma_irq;
- void __iomem *dma_chan_base;
-- void *cb_base; /* DMA control blocks */
-- dma_addr_t cb_handle;
-- struct dentry *debugfs_dir;
- wait_queue_head_t dma_waitq;
-- struct bcm2708_fb_stats stats;
-- unsigned long fb_bus_address;
-- struct { u32 base, length; } gpu;
-+ bool disable_arm_alloc;
-+ struct bcm2708_fb_stats dma_stats;
-+ void *cb_base; /* DMA control blocks */
-+ dma_addr_t cb_handle;
-+ int instance_count;
-+ int num_displays;
-+ struct rpi_firmware *fw;
-+ struct bcm2708_fb displays[MAX_FRAMEBUFFERS];
- };
-
- #define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb)
-
- static void bcm2708_fb_debugfs_deinit(struct bcm2708_fb *fb)
- {
-- debugfs_remove_recursive(fb->debugfs_dir);
-- fb->debugfs_dir = NULL;
-+ debugfs_remove_recursive(fb->debugfs_subdir);
-+ fb->debugfs_subdir = NULL;
-+
-+ fb->fbdev->instance_count--;
-+
-+ if (!fb->fbdev->instance_count) {
-+ debugfs_remove_recursive(fb->debugfs_dir);
-+ fb->debugfs_dir = NULL;
-+ }
- }
-
- static int bcm2708_fb_debugfs_init(struct bcm2708_fb *fb)
- {
-+ char buf[3];
-+ struct bcm2708_fb_dev *fbdev = fb->fbdev;
-+
- static struct debugfs_reg32 stats_registers[] = {
-- {
-- "dma_copies",
-- offsetof(struct bcm2708_fb_stats, dma_copies)
-- },
-- {
-- "dma_irqs",
-- offsetof(struct bcm2708_fb_stats, dma_irqs)
-- },
-+ {"dma_copies", offsetof(struct bcm2708_fb_stats, dma_copies)},
-+ {"dma_irqs", offsetof(struct bcm2708_fb_stats, dma_irqs)},
- };
-
-- fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL);
-+ static struct debugfs_reg32 screeninfo[] = {
-+ {"width", offsetof(struct fb_var_screeninfo, xres)},
-+ {"height", offsetof(struct fb_var_screeninfo, yres)},
-+ {"bpp", offsetof(struct fb_var_screeninfo, bits_per_pixel)},
-+ {"xres_virtual", offsetof(struct fb_var_screeninfo, xres_virtual)},
-+ {"yres_virtual", offsetof(struct fb_var_screeninfo, yres_virtual)},
-+ {"xoffset", offsetof(struct fb_var_screeninfo, xoffset)},
-+ {"yoffset", offsetof(struct fb_var_screeninfo, yoffset)},
-+ };
-+
-+ fb->debugfs_dir = debugfs_lookup(DRIVER_NAME, NULL);
-+
-+ if (!fb->debugfs_dir)
-+ fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL);
-+
- if (!fb->debugfs_dir) {
-- pr_warn("%s: could not create debugfs entry\n",
-- __func__);
-+ dev_warn(fb->fb.dev, "%s: could not create debugfs folder\n",
-+ __func__);
-+ return -EFAULT;
-+ }
-+
-+ snprintf(buf, sizeof(buf), "%u", fb->display_settings.display_num);
-+
-+ fb->debugfs_subdir = debugfs_create_dir(buf, fb->debugfs_dir);
-+
-+ if (!fb->debugfs_subdir) {
-+ dev_warn(fb->fb.dev, "%s: could not create debugfs entry %u\n",
-+ __func__, fb->display_settings.display_num);
- return -EFAULT;
- }
-
-- fb->stats.regset.regs = stats_registers;
-- fb->stats.regset.nregs = ARRAY_SIZE(stats_registers);
-- fb->stats.regset.base = &fb->stats;
--
-- if (!debugfs_create_regset32("stats", 0444, fb->debugfs_dir,
-- &fb->stats.regset)) {
-- pr_warn("%s: could not create statistics registers\n",
-- __func__);
-+ fbdev->dma_stats.regset.regs = stats_registers;
-+ fbdev->dma_stats.regset.nregs = ARRAY_SIZE(stats_registers);
-+ fbdev->dma_stats.regset.base = &fbdev->dma_stats;
-+
-+ if (!debugfs_create_regset32("dma_stats", 0444, fb->debugfs_subdir,
-+ &fbdev->dma_stats.regset)) {
-+ dev_warn(fb->fb.dev, "%s: could not create statistics registers\n",
-+ __func__);
-+ goto fail;
-+ }
-+
-+ fb->screeninfo_regset.regs = screeninfo;
-+ fb->screeninfo_regset.nregs = ARRAY_SIZE(screeninfo);
-+ fb->screeninfo_regset.base = &fb->fb.var;
-+
-+ if (!debugfs_create_regset32("screeninfo", 0444, fb->debugfs_subdir,
-+ &fb->screeninfo_regset)) {
-+ dev_warn(fb->fb.dev,
-+ "%s: could not create dimensions registers\n",
-+ __func__);
- goto fail;
- }
-+
-+ fbdev->instance_count++;
-+
- return 0;
-
- fail:
-@@ -145,6 +225,20 @@ fail:
- return -EFAULT;
- }
-
-+static void set_display_num(struct bcm2708_fb *fb)
-+{
-+ if (fb && fb->fbdev && fb->fbdev->firmware_supports_multifb) {
-+ u32 tmp = fb->display_settings.display_num;
-+
-+ if (rpi_firmware_property(fb->fbdev->fw,
-+ RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM,
-+ &tmp,
-+ sizeof(tmp)))
-+ dev_warn_once(fb->fb.dev,
-+ "Set display number call failed. Old GPU firmware?");
-+ }
-+}
-+
- static int bcm2708_fb_set_bitfields(struct fb_var_screeninfo *var)
- {
- int ret = 0;
-@@ -222,11 +316,11 @@ static int bcm2708_fb_check_var(struct f
- struct fb_info *info)
- {
- /* info input, var output */
-- print_debug("%s(%p) %dx%d (%dx%d), %d, %d\n",
-+ print_debug("%s(%p) %ux%u (%ux%u), %ul, %u\n",
- __func__, info, info->var.xres, info->var.yres,
- info->var.xres_virtual, info->var.yres_virtual,
-- (int)info->screen_size, info->var.bits_per_pixel);
-- print_debug("%s(%p) %dx%d (%dx%d), %d\n", __func__, var, var->xres,
-+ info->screen_size, info->var.bits_per_pixel);
-+ print_debug("%s(%p) %ux%u (%ux%u), %u\n", __func__, var, var->xres,
- var->yres, var->xres_virtual, var->yres_virtual,
- var->bits_per_pixel);
-
-@@ -283,23 +377,96 @@ static int bcm2708_fb_set_par(struct fb_
- .xoffset = info->var.xoffset,
- .yoffset = info->var.yoffset,
- .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
-- .base = 0,
-- .screen_size = 0,
-- .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH, 4, 0 },
-- .pitch = 0,
-+ /* base and screen_size will be initialised later */
-+ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
-+ /* pitch will be initialised later */
- };
-- int ret;
-+ int ret, image_size;
-+
-
-- print_debug("%s(%p) %dx%d (%dx%d), %d, %d\n", __func__, info,
-+ print_debug("%s(%p) %dx%d (%dx%d), %d, %d (display %d)\n", __func__,
-+ info,
- info->var.xres, info->var.yres, info->var.xres_virtual,
- info->var.yres_virtual, (int)info->screen_size,
-- info->var.bits_per_pixel);
-+ info->var.bits_per_pixel, value);
-+
-+ /* Need to set the display number to act on first
-+ * Cannot do it in the tag list because on older firmware the call
-+ * will fail and stop the rest of the list being executed.
-+ * We can ignore this call failing as the default at other end is 0
-+ */
-+ set_display_num(fb);
-+
-+ /* Try allocating our own buffer. We can specify all the parameters */
-+ image_size = ((info->var.xres * info->var.yres) *
-+ info->var.bits_per_pixel) >> 3;
-+
-+ if (!fb->fbdev->disable_arm_alloc &&
-+ (image_size != fb->image_size || !fb->dma_addr)) {
-+ if (fb->dma_addr) {
-+ dma_free_coherent(info->device, fb->image_size,
-+ fb->cpuaddr, fb->dma_addr);
-+ fb->image_size = 0;
-+ fb->cpuaddr = NULL;
-+ fb->dma_addr = 0;
-+ }
-+
-+ fb->cpuaddr = dma_alloc_coherent(info->device, image_size,
-+ &fb->dma_addr, GFP_KERNEL);
-+
-+ if (!fb->cpuaddr) {
-+ fb->dma_addr = 0;
-+ fb->fbdev->disable_arm_alloc = true;
-+ } else {
-+ fb->image_size = image_size;
-+ }
-+ }
-+
-+ if (fb->cpuaddr) {
-+ fbinfo.base = fb->dma_addr;
-+ fbinfo.screen_size = image_size;
-+ fbinfo.pitch = (info->var.xres * info->var.bits_per_pixel) >> 3;
-+
-+ ret = rpi_firmware_property_list(fb->fbdev->fw, &fbinfo,
-+ sizeof(fbinfo));
-+ if (ret || fbinfo.base != fb->dma_addr) {
-+ /* Firmware either failed, or assigned a different base
-+ * address (ie it doesn't support being passed an FB
-+ * allocation).
-+ * Destroy the allocation, and don't try again.
-+ */
-+ dma_free_coherent(info->device, fb->image_size,
-+ fb->cpuaddr, fb->dma_addr);
-+ fb->image_size = 0;
-+ fb->cpuaddr = NULL;
-+ fb->dma_addr = 0;
-+ fb->fbdev->disable_arm_alloc = true;
-+ }
-+ } else {
-+ /* Our allocation failed - drop into the old scheme of
-+ * allocation by the VPU.
-+ */
-+ ret = -ENOMEM;
-+ }
-
-- ret = rpi_firmware_property_list(fb->fw, &fbinfo, sizeof(fbinfo));
- if (ret) {
-- dev_err(info->device,
-- "Failed to allocate GPU framebuffer (%d)\n", ret);
-- return ret;
-+ /* Old scheme:
-+ * - FRAMEBUFFER_ALLOCATE passes 0 for base and screen_size.
-+ * - GET_PITCH instead of SET_PITCH.
-+ */
-+ fbinfo.base = 0;
-+ fbinfo.screen_size = 0;
-+ fbinfo.tag6.tag = RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH;
-+ fbinfo.pitch = 0;
-+
-+ ret = rpi_firmware_property_list(fb->fbdev->fw, &fbinfo,
-+ sizeof(fbinfo));
-+ if (ret) {
-+ dev_err(info->device,
-+ "Failed to allocate GPU framebuffer (%d)\n",
-+ ret);
-+ return ret;
-+ }
- }
-
- if (info->var.bits_per_pixel <= 8)
-@@ -314,9 +481,17 @@ static int bcm2708_fb_set_par(struct fb_
- fb->fb.fix.smem_start = fbinfo.base;
- fb->fb.fix.smem_len = fbinfo.pitch * fbinfo.yres_virtual;
- fb->fb.screen_size = fbinfo.screen_size;
-- if (fb->fb.screen_base)
-- iounmap(fb->fb.screen_base);
-- fb->fb.screen_base = ioremap_wc(fbinfo.base, fb->fb.screen_size);
-+
-+ if (!fb->dma_addr) {
-+ if (fb->fb.screen_base)
-+ iounmap(fb->fb.screen_base);
-+
-+ fb->fb.screen_base = ioremap_wc(fbinfo.base,
-+ fb->fb.screen_size);
-+ } else {
-+ fb->fb.screen_base = fb->cpuaddr;
-+ }
-+
- if (!fb->fb.screen_base) {
- /* the console may currently be locked */
- console_trylock();
-@@ -374,7 +549,10 @@ static int bcm2708_fb_setcolreg(unsigned
- packet->length = regno + 1;
- memcpy(packet->cmap, fb->gpu_cmap,
- sizeof(packet->cmap));
-- ret = rpi_firmware_property(fb->fw,
-+
-+ set_display_num(fb);
-+
-+ ret = rpi_firmware_property(fb->fbdev->fw,
- RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE,
- packet,
- (2 + packet->length) * sizeof(u32));
-@@ -413,8 +591,11 @@ static int bcm2708_fb_blank(int blank_mo
- return -EINVAL;
- }
-
-- ret = rpi_firmware_property(fb->fw, RPI_FIRMWARE_FRAMEBUFFER_BLANK,
-+ set_display_num(fb);
-+
-+ ret = rpi_firmware_property(fb->fbdev->fw, RPI_FIRMWARE_FRAMEBUFFER_BLANK,
- &value, sizeof(value));
-+
- if (ret)
- dev_err(info->device, "%s(%d) failed: %d\n", __func__,
- blank_mode, ret);
-@@ -431,7 +612,7 @@ static int bcm2708_fb_pan_display(struct
- info->var.yoffset = var->yoffset;
- result = bcm2708_fb_set_par(info);
- if (result != 0)
-- pr_err("%s(%d,%d) returns=%d\n", __func__, var->xoffset,
-+ pr_err("%s(%u,%u) returns=%d\n", __func__, var->xoffset,
- var->yoffset, result);
- return result;
- }
-@@ -439,8 +620,9 @@ static int bcm2708_fb_pan_display(struct
- static void dma_memcpy(struct bcm2708_fb *fb, dma_addr_t dst, dma_addr_t src,
- int size)
- {
-- int burst_size = (fb->dma_chan == 0) ? 8 : 2;
-- struct bcm2708_dma_cb *cb = fb->cb_base;
-+ struct bcm2708_fb_dev *fbdev = fb->fbdev;
-+ struct bcm2708_dma_cb *cb = fbdev->cb_base;
-+ int burst_size = (fbdev->dma_chan == 0) ? 8 : 2;
-
- cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH |
- BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
-@@ -453,21 +635,27 @@ static void dma_memcpy(struct bcm2708_fb
- cb->pad[1] = 0;
- cb->next = 0;
-
-+ // Not sure what to do if this gets a signal whilst waiting
-+ if (mutex_lock_interruptible(&fbdev->dma_mutex))
-+ return;
-+
- if (size < dma_busy_wait_threshold) {
-- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
-- bcm_dma_wait_idle(fb->dma_chan_base);
-+ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle);
-+ bcm_dma_wait_idle(fbdev->dma_chan_base);
- } else {
-- void __iomem *dma_chan = fb->dma_chan_base;
-+ void __iomem *local_dma_chan = fbdev->dma_chan_base;
-
- cb->info |= BCM2708_DMA_INT_EN;
-- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
-- while (bcm_dma_is_busy(dma_chan)) {
-- wait_event_interruptible(fb->dma_waitq,
-- !bcm_dma_is_busy(dma_chan));
-+ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle);
-+ while (bcm_dma_is_busy(local_dma_chan)) {
-+ wait_event_interruptible(fbdev->dma_waitq,
-+ !bcm_dma_is_busy(local_dma_chan));
- }
-- fb->stats.dma_irqs++;
-+ fbdev->dma_stats.dma_irqs++;
- }
-- fb->stats.dma_copies++;
-+ fbdev->dma_stats.dma_copies++;
-+
-+ mutex_unlock(&fbdev->dma_mutex);
- }
-
- /* address with no aliases */
-@@ -542,10 +730,13 @@ static int bcm2708_ioctl(struct fb_info
-
- switch (cmd) {
- case FBIO_WAITFORVSYNC:
-- ret = rpi_firmware_property(fb->fw,
-+ set_display_num(fb);
-+
-+ ret = rpi_firmware_property(fb->fbdev->fw,
- RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC,
- &dummy, sizeof(dummy));
- break;
-+
- case FBIODMACOPY:
- {
- struct fb_dmacopy ioparam;
-@@ -615,23 +806,22 @@ static int bcm2708_compat_ioctl(struct f
- static void bcm2708_fb_fillrect(struct fb_info *info,
- const struct fb_fillrect *rect)
- {
-- /* (is called) print_debug("bcm2708_fb_fillrect\n"); */
- cfb_fillrect(info, rect);
- }
-
- /* A helper function for configuring dma control block */
- static void set_dma_cb(struct bcm2708_dma_cb *cb,
-- int burst_size,
-- dma_addr_t dst,
-- int dst_stride,
-- dma_addr_t src,
-- int src_stride,
-- int w,
-- int h)
-+ int burst_size,
-+ dma_addr_t dst,
-+ int dst_stride,
-+ dma_addr_t src,
-+ int src_stride,
-+ int w,
-+ int h)
- {
- cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH |
-- BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
-- BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE;
-+ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
-+ BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE;
- cb->dst = dst;
- cb->src = src;
- /*
-@@ -649,15 +839,19 @@ static void bcm2708_fb_copyarea(struct f
- const struct fb_copyarea *region)
- {
- struct bcm2708_fb *fb = to_bcm2708(info);
-- struct bcm2708_dma_cb *cb = fb->cb_base;
-+ struct bcm2708_fb_dev *fbdev = fb->fbdev;
-+ struct bcm2708_dma_cb *cb = fbdev->cb_base;
- int bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3;
-
- /* Channel 0 supports larger bursts and is a bit faster */
-- int burst_size = (fb->dma_chan == 0) ? 8 : 2;
-+ int burst_size = (fbdev->dma_chan == 0) ? 8 : 2;
- int pixels = region->width * region->height;
-
-- /* Fallback to cfb_copyarea() if we don't like something */
-- if (bytes_per_pixel > 4 ||
-+ /* If DMA is currently in use (ie being used on another FB), then
-+ * rather than wait for it to finish, just use the cfb_copyarea
-+ */
-+ if (!mutex_trylock(&fbdev->dma_mutex) ||
-+ bytes_per_pixel > 4 ||
- info->var.xres * info->var.yres > 1920 * 1200 ||
- region->width <= 0 || region->width > info->var.xres ||
- region->height <= 0 || region->height > info->var.yres ||
-@@ -684,8 +878,8 @@ static void bcm2708_fb_copyarea(struct f
- * 1920x1200 resolution at 32bpp pixel depth.
- */
- int y;
-- dma_addr_t control_block_pa = fb->cb_handle;
-- dma_addr_t scratchbuf = fb->cb_handle + 16 * 1024;
-+ dma_addr_t control_block_pa = fbdev->cb_handle;
-+ dma_addr_t scratchbuf = fbdev->cb_handle + 16 * 1024;
- int scanline_size = bytes_per_pixel * region->width;
- int scanlines_per_cb = (64 * 1024 - 16 * 1024) / scanline_size;
-
-@@ -735,10 +929,10 @@ static void bcm2708_fb_copyarea(struct f
- }
- set_dma_cb(cb, burst_size,
- fb->fb_bus_address + dy * fb->fb.fix.line_length +
-- bytes_per_pixel * region->dx,
-+ bytes_per_pixel * region->dx,
- stride,
- fb->fb_bus_address + sy * fb->fb.fix.line_length +
-- bytes_per_pixel * region->sx,
-+ bytes_per_pixel * region->sx,
- stride,
- region->width * bytes_per_pixel,
- region->height);
-@@ -748,32 +942,33 @@ static void bcm2708_fb_copyarea(struct f
- cb->next = 0;
-
- if (pixels < dma_busy_wait_threshold) {
-- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
-- bcm_dma_wait_idle(fb->dma_chan_base);
-+ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle);
-+ bcm_dma_wait_idle(fbdev->dma_chan_base);
- } else {
-- void __iomem *dma_chan = fb->dma_chan_base;
-+ void __iomem *local_dma_chan = fbdev->dma_chan_base;
-
- cb->info |= BCM2708_DMA_INT_EN;
-- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
-- while (bcm_dma_is_busy(dma_chan)) {
-- wait_event_interruptible(fb->dma_waitq,
-- !bcm_dma_is_busy(dma_chan));
-+ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle);
-+ while (bcm_dma_is_busy(local_dma_chan)) {
-+ wait_event_interruptible(fbdev->dma_waitq,
-+ !bcm_dma_is_busy(local_dma_chan));
- }
-- fb->stats.dma_irqs++;
-+ fbdev->dma_stats.dma_irqs++;
- }
-- fb->stats.dma_copies++;
-+ fbdev->dma_stats.dma_copies++;
-+
-+ mutex_unlock(&fbdev->dma_mutex);
- }
-
- static void bcm2708_fb_imageblit(struct fb_info *info,
- const struct fb_image *image)
- {
-- /* (is called) print_debug("bcm2708_fb_imageblit\n"); */
- cfb_imageblit(info, image);
- }
-
- static irqreturn_t bcm2708_fb_dma_irq(int irq, void *cxt)
- {
-- struct bcm2708_fb *fb = cxt;
-+ struct bcm2708_fb_dev *fbdev = cxt;
-
- /* FIXME: should read status register to check if this is
- * actually interrupting us or not, in case this interrupt
-@@ -783,9 +978,9 @@ static irqreturn_t bcm2708_fb_dma_irq(in
- */
-
- /* acknowledge the interrupt */
-- writel(BCM2708_DMA_INT, fb->dma_chan_base + BCM2708_DMA_CS);
-+ writel(BCM2708_DMA_INT, fbdev->dma_chan_base + BCM2708_DMA_CS);
-
-- wake_up(&fb->dma_waitq);
-+ wake_up(&fbdev->dma_waitq);
- return IRQ_HANDLED;
- }
-
-@@ -821,11 +1016,23 @@ static int bcm2708_fb_register(struct bc
- fb->fb.fix.ywrapstep = 0;
- fb->fb.fix.accel = FB_ACCEL_NONE;
-
-- fb->fb.var.xres = fbwidth;
-- fb->fb.var.yres = fbheight;
-- fb->fb.var.xres_virtual = fbwidth;
-- fb->fb.var.yres_virtual = fbheight;
-- fb->fb.var.bits_per_pixel = fbdepth;
-+ /* If we have data from the VC4 on FB's, use that, otherwise use the
-+ * module parameters
-+ */
-+ if (fb->display_settings.width) {
-+ fb->fb.var.xres = fb->display_settings.width;
-+ fb->fb.var.yres = fb->display_settings.height;
-+ fb->fb.var.xres_virtual = fb->fb.var.xres;
-+ fb->fb.var.yres_virtual = fb->fb.var.yres;
-+ fb->fb.var.bits_per_pixel = fb->display_settings.depth;
-+ } else {
-+ fb->fb.var.xres = fbwidth;
-+ fb->fb.var.yres = fbheight;
-+ fb->fb.var.xres_virtual = fbwidth;
-+ fb->fb.var.yres_virtual = fbheight;
-+ fb->fb.var.bits_per_pixel = fbdepth;
-+ }
-+
- fb->fb.var.vmode = FB_VMODE_NONINTERLACED;
- fb->fb.var.activate = FB_ACTIVATE_NOW;
- fb->fb.var.nonstd = 0;
-@@ -841,26 +1048,23 @@ static int bcm2708_fb_register(struct bc
- fb->fb.monspecs.dclkmax = 100000000;
-
- bcm2708_fb_set_bitfields(&fb->fb.var);
-- init_waitqueue_head(&fb->dma_waitq);
-
- /*
- * Allocate colourmap.
- */
--
- fb_set_var(&fb->fb, &fb->fb.var);
-+
- ret = bcm2708_fb_set_par(&fb->fb);
-+
- if (ret)
- return ret;
-
-- print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n",
-- fbwidth, fbheight, fbdepth, fbswap);
--
- ret = register_framebuffer(&fb->fb);
-- print_debug("BCM2708FB: register framebuffer (%d)\n", ret);
-+
- if (ret == 0)
- goto out;
-
-- print_debug("BCM2708FB: cannot register framebuffer (%d)\n", ret);
-+ dev_warn(fb->fb.dev, "Unable to register framebuffer (%d)\n", ret);
- out:
- return ret;
- }
-@@ -869,10 +1073,18 @@ static int bcm2708_fb_probe(struct platf
- {
- struct device_node *fw_np;
- struct rpi_firmware *fw;
-- struct bcm2708_fb *fb;
-- int ret;
-+ int ret, i;
-+ u32 num_displays;
-+ struct bcm2708_fb_dev *fbdev;
-+ struct { u32 base, length; } gpu_mem;
-+
-+ fbdev = devm_kzalloc(&dev->dev, sizeof(*fbdev), GFP_KERNEL);
-+
-+ if (!fbdev)
-+ return -ENOMEM;
-
- fw_np = of_parse_phandle(dev->dev.of_node, "firmware", 0);
-+
- /* Remove comment when booting without Device Tree is no longer supported
- * if (!fw_np) {
- * dev_err(&dev->dev, "Missing firmware node\n");
-@@ -880,90 +1092,154 @@ static int bcm2708_fb_probe(struct platf
- * }
- */
- fw = rpi_firmware_get(fw_np);
-+ fbdev->fw = fw;
-+
- if (!fw)
- return -EPROBE_DEFER;
-
-- fb = kzalloc(sizeof(*fb), GFP_KERNEL);
-- if (!fb) {
-- ret = -ENOMEM;
-- goto free_region;
-+ ret = rpi_firmware_property(fw,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
-+ &num_displays, sizeof(u32));
-+
-+ /* If we fail to get the number of displays, or it returns 0, then
-+ * assume old firmware that doesn't have the mailbox call, so just
-+ * set one display
-+ */
-+ if (ret || num_displays == 0) {
-+ num_displays = 1;
-+ dev_err(&dev->dev,
-+ "Unable to determine number of FB's. Assuming 1\n");
-+ ret = 0;
-+ } else {
-+ fbdev->firmware_supports_multifb = 1;
- }
-
-- fb->fw = fw;
-- bcm2708_fb_debugfs_init(fb);
-+ if (num_displays > MAX_FRAMEBUFFERS) {
-+ dev_warn(&dev->dev,
-+ "More displays reported from firmware than supported in driver (%u vs %u)",
-+ num_displays, MAX_FRAMEBUFFERS);
-+ num_displays = MAX_FRAMEBUFFERS;
-+ }
-
-- fb->cb_base = dma_alloc_writecombine(&dev->dev, SZ_64K,
-- &fb->cb_handle, GFP_KERNEL);
-- if (!fb->cb_base) {
-+ dev_info(&dev->dev, "FB found %d display(s)\n", num_displays);
-+
-+ /* Set up the DMA information. Note we have just one set of DMA
-+ * parameters to work with all the FB's so requires synchronising when
-+ * being used
-+ */
-+
-+ mutex_init(&fbdev->dma_mutex);
-+
-+ fbdev->cb_base = dma_alloc_writecombine(&dev->dev, SZ_64K,
-+ &fbdev->cb_handle,
-+ GFP_KERNEL);
-+ if (!fbdev->cb_base) {
- dev_err(&dev->dev, "cannot allocate DMA CBs\n");
- ret = -ENOMEM;
- goto free_fb;
- }
-
-- pr_info("BCM2708FB: allocated DMA memory %pad\n", &fb->cb_handle);
--
- ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK,
-- &fb->dma_chan_base, &fb->dma_irq);
-+ &fbdev->dma_chan_base,
-+ &fbdev->dma_irq);
- if (ret < 0) {
-- dev_err(&dev->dev, "couldn't allocate a DMA channel\n");
-+ dev_err(&dev->dev, "Couldn't allocate a DMA channel\n");
- goto free_cb;
- }
-- fb->dma_chan = ret;
-+ fbdev->dma_chan = ret;
-
-- ret = request_irq(fb->dma_irq, bcm2708_fb_dma_irq,
-- 0, "bcm2708_fb dma", fb);
-+ ret = request_irq(fbdev->dma_irq, bcm2708_fb_dma_irq,
-+ 0, "bcm2708_fb DMA", fbdev);
- if (ret) {
-- pr_err("%s: failed to request DMA irq\n", __func__);
-+ dev_err(&dev->dev,
-+ "Failed to request DMA irq\n");
- goto free_dma_chan;
- }
-
-- pr_info("BCM2708FB: allocated DMA channel %d\n", fb->dma_chan);
-+ rpi_firmware_property(fbdev->fw,
-+ RPI_FIRMWARE_GET_VC_MEMORY,
-+ &gpu_mem, sizeof(gpu_mem));
-+
-+ for (i = 0; i < num_displays; i++) {
-+ struct bcm2708_fb *fb = &fbdev->displays[i];
-+
-+ fb->display_settings.display_num = i;
-+ fb->dev = dev;
-+ fb->fb.device = &dev->dev;
-+ fb->fbdev = fbdev;
-+
-+ fb->gpu.base = gpu_mem.base;
-+ fb->gpu.length = gpu_mem.length;
-+
-+ if (fbdev->firmware_supports_multifb) {
-+ ret = rpi_firmware_property(fw,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS,
-+ &fb->display_settings,
-+ GET_DISPLAY_SETTINGS_PAYLOAD_SIZE);
-+ } else {
-+ memset(&fb->display_settings, 0,
-+ sizeof(fb->display_settings));
-+ }
-+
-+ ret = bcm2708_fb_register(fb);
-
-- fb->dev = dev;
-- fb->fb.device = &dev->dev;
-+ if (ret == 0) {
-+ bcm2708_fb_debugfs_init(fb);
-
-- /* failure here isn't fatal, but we'll fail in vc_mem_copy if
-- * fb->gpu is not valid
-- */
-- rpi_firmware_property(fb->fw, RPI_FIRMWARE_GET_VC_MEMORY, &fb->gpu,
-- sizeof(fb->gpu));
-+ fbdev->num_displays++;
-
-- ret = bcm2708_fb_register(fb);
-- if (ret == 0) {
-- platform_set_drvdata(dev, fb);
-- goto out;
-+ dev_info(&dev->dev,
-+ "Registered framebuffer for display %u, size %ux%u\n",
-+ fb->display_settings.display_num,
-+ fb->fb.var.xres,
-+ fb->fb.var.yres);
-+ } else {
-+ // Use this to flag if this FB entry is in use.
-+ fb->fbdev = NULL;
-+ }
-+ }
-+
-+ // Did we actually successfully create any FB's?
-+ if (fbdev->num_displays) {
-+ init_waitqueue_head(&fbdev->dma_waitq);
-+ platform_set_drvdata(dev, fbdev);
-+ return ret;
- }
-
- free_dma_chan:
-- bcm_dma_chan_free(fb->dma_chan);
-+ bcm_dma_chan_free(fbdev->dma_chan);
- free_cb:
-- dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
-+ dma_free_writecombine(&dev->dev, SZ_64K, fbdev->cb_base,
-+ fbdev->cb_handle);
- free_fb:
-- kfree(fb);
--free_region:
- dev_err(&dev->dev, "probe failed, err %d\n", ret);
--out:
-+
- return ret;
- }
-
- static int bcm2708_fb_remove(struct platform_device *dev)
- {
-- struct bcm2708_fb *fb = platform_get_drvdata(dev);
-+ struct bcm2708_fb_dev *fbdev = platform_get_drvdata(dev);
-+ int i;
-
- platform_set_drvdata(dev, NULL);
-
-- if (fb->fb.screen_base)
-- iounmap(fb->fb.screen_base);
-- unregister_framebuffer(&fb->fb);
--
-- dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
-- bcm_dma_chan_free(fb->dma_chan);
--
-- bcm2708_fb_debugfs_deinit(fb);
-+ for (i = 0; i < fbdev->num_displays; i++) {
-+ if (fbdev->displays[i].fb.screen_base)
-+ iounmap(fbdev->displays[i].fb.screen_base);
-+
-+ if (fbdev->displays[i].fbdev) {
-+ unregister_framebuffer(&fbdev->displays[i].fb);
-+ bcm2708_fb_debugfs_deinit(&fbdev->displays[i]);
-+ }
-+ }
-
-- free_irq(fb->dma_irq, fb);
-+ dma_free_writecombine(&dev->dev, SZ_64K, fbdev->cb_base,
-+ fbdev->cb_handle);
-+ bcm_dma_chan_free(fbdev->dma_chan);
-+ free_irq(fbdev->dma_irq, fbdev);
-
-- kfree(fb);
-+ mutex_destroy(&fbdev->dma_mutex);
-
- return 0;
- }
-@@ -978,10 +1254,10 @@ static struct platform_driver bcm2708_fb
- .probe = bcm2708_fb_probe,
- .remove = bcm2708_fb_remove,
- .driver = {
-- .name = DRIVER_NAME,
-- .owner = THIS_MODULE,
-- .of_match_table = bcm2708_fb_of_match_table,
-- },
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = bcm2708_fb_of_match_table,
-+ },
- };
-
- static int __init bcm2708_fb_init(void)
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -138,9 +138,11 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
- RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006,
- RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007,
-+ RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH = 0x00048008,
- RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
- RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
- RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
-+
- RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
- RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
- RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
-@@ -159,6 +161,8 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
- };
-
-+#define GET_DISPLAY_SETTINGS_PAYLOAD_SIZE 64
-+
- #if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE)
- int rpi_firmware_property(struct rpi_firmware *fw,
- u32 tag, void *data, size_t len);
+++ /dev/null
-From 545c00748a070340e9669740e45afc2672e1fcb6 Mon Sep 17 00:00:00 2001
-Date: Sun, 19 May 2019 12:26:21 +0200
-Subject: [PATCH] ARM: dts: bcm283x: Move BCM2835/6/7 specific to
- bcm2835-common.dtsi
-
-We want all common BCM2835/6/7/8 functions in bcm283x.dtsi and all
-BCM2835/6/7 specific in the new bcm2835-common.dtsi.
-
----
- arch/arm/boot/dts/bcm2835-common.dtsi | 53 +++++++++++++++++++++++++++
- arch/arm/boot/dts/bcm2835.dtsi | 1 +
- arch/arm/boot/dts/bcm2836.dtsi | 1 +
- arch/arm/boot/dts/bcm2837.dtsi | 1 +
- arch/arm/boot/dts/bcm283x.dtsi | 43 +---------------------
- 5 files changed, 57 insertions(+), 42 deletions(-)
- create mode 100644 arch/arm/boot/dts/bcm2835-common.dtsi
-
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2835-common.dtsi
-@@ -0,0 +1,53 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* This include file covers the common peripherals and configuration between
-+ * bcm2835, bcm2836 and bcm2837 implementations.
-+ */
-+
-+/ {
-+ soc {
-+ timer@7e003000 {
-+ compatible = "brcm,bcm2835-system-timer";
-+ reg = <0x7e003000 0x1000>;
-+ interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
-+ /* This could be a reference to BCM2835_CLOCK_TIMER,
-+ * but we don't have the driver using the common clock
-+ * support yet.
-+ */
-+ clock-frequency = <1000000>;
-+ };
-+
-+ intc: interrupt-controller@7e00b200 {
-+ compatible = "brcm,bcm2835-armctrl-ic";
-+ reg = <0x7e00b200 0x200>;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ thermal: thermal@7e212000 {
-+ compatible = "brcm,bcm2835-thermal";
-+ reg = <0x7e212000 0x8>;
-+ clocks = <&clocks BCM2835_CLOCK_TSENS>;
-+ #thermal-sensor-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ v3d: v3d@7ec00000 {
-+ compatible = "brcm,bcm2835-v3d";
-+ reg = <0x7ec00000 0x1000>;
-+ interrupts = <1 10>;
-+ };
-+ };
-+};
-+
-+&gpio {
-+ i2c_slave_gpio18: i2c_slave_gpio18 {
-+ brcm,pins = <18 19 20 21>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+
-+ jtag_gpio4: jtag_gpio4 {
-+ brcm,pins = <4 5 6 12 13>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+};
---- a/arch/arm/boot/dts/bcm2835.dtsi
-+++ b/arch/arm/boot/dts/bcm2835.dtsi
-@@ -1,5 +1,6 @@
- // SPDX-License-Identifier: GPL-2.0
- #include "bcm283x.dtsi"
-+#include "bcm2835-common.dtsi"
-
- / {
- compatible = "brcm,bcm2835";
---- a/arch/arm/boot/dts/bcm2836.dtsi
-+++ b/arch/arm/boot/dts/bcm2836.dtsi
-@@ -1,5 +1,6 @@
- // SPDX-License-Identifier: GPL-2.0
- #include "bcm283x.dtsi"
-+#include "bcm2835-common.dtsi"
-
- / {
- compatible = "brcm,bcm2836";
---- a/arch/arm/boot/dts/bcm2837.dtsi
-+++ b/arch/arm/boot/dts/bcm2837.dtsi
-@@ -1,4 +1,5 @@
- #include "bcm283x.dtsi"
-+#include "bcm2835-common.dtsi"
-
- / {
- compatible = "brcm,bcm2837";
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -55,17 +55,6 @@
- #address-cells = <1>;
- #size-cells = <1>;
-
-- timer@7e003000 {
-- compatible = "brcm,bcm2835-system-timer";
-- reg = <0x7e003000 0x1000>;
-- interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
-- /* This could be a reference to BCM2835_CLOCK_TIMER,
-- * but we don't have the driver using the common clock
-- * support yet.
-- */
-- clock-frequency = <1000000>;
-- };
--
- txp@7e004000 {
- compatible = "brcm,bcm2835-txp";
- reg = <0x7e004000 0x20>;
-@@ -113,13 +102,6 @@
- brcm,dma-channel-mask = <0x7f35>;
- };
-
-- intc: interrupt-controller@7e00b200 {
-- compatible = "brcm,bcm2835-armctrl-ic";
-- reg = <0x7e00b200 0x200>;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
- watchdog@7e100000 {
- compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
- #power-domain-cells = <1>;
-@@ -183,8 +165,7 @@
- interrupt-controller;
- #interrupt-cells = <2>;
-
-- /* Defines pin muxing groups according to
-- * BCM2835-ARM-Peripherals.pdf page 102.
-+ /* Defines common pin muxing groups
- *
- * While each pin can have its mux selected
- * for various functions individually, some
-@@ -262,15 +243,7 @@
- brcm,pins = <44 45>;
- brcm,function = <BCM2835_FSEL_ALT2>;
- };
-- i2c_slave_gpio18: i2c_slave_gpio18 {
-- brcm,pins = <18 19 20 21>;
-- brcm,function = <BCM2835_FSEL_ALT3>;
-- };
-
-- jtag_gpio4: jtag_gpio4 {
-- brcm,pins = <4 5 6 12 13>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
- jtag_gpio22: jtag_gpio22 {
- brcm,pins = <22 23 24 25 26 27>;
- brcm,function = <BCM2835_FSEL_ALT4>;
-@@ -487,14 +460,6 @@
-
- };
-
-- thermal: thermal@7e212000 {
-- compatible = "brcm,bcm2835-thermal";
-- reg = <0x7e212000 0x8>;
-- clocks = <&clocks BCM2835_CLOCK_TSENS>;
-- #thermal-sensor-cells = <0>;
-- status = "disabled";
-- };
--
- aux: aux@7e215000 {
- compatible = "brcm,bcm2835-aux";
- #clock-cells = <1>;
-@@ -660,12 +625,6 @@
- phy-names = "usb2-phy";
- };
-
-- v3d: v3d@7ec00000 {
-- compatible = "brcm,bcm2835-v3d";
-- reg = <0x7ec00000 0x1000>;
-- interrupts = <1 10>;
-- };
--
- vc4: gpu {
- compatible = "brcm,bcm2835-vc4";
- };
--- /dev/null
+From 13be2bbd1a22f1b4d9fd260d80b561698f623ac1 Mon Sep 17 00:00:00 2001
+Date: Thu, 30 May 2019 16:44:24 +0100
+Subject: [PATCH] overlays: Add i2c3-6 and uart2-5 overlays
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 8 +++
+ arch/arm/boot/dts/overlays/README | 52 ++++++++++++++++++++
+ arch/arm/boot/dts/overlays/i2c3-overlay.dts | 27 ++++++++++
+ arch/arm/boot/dts/overlays/i2c4-overlay.dts | 27 ++++++++++
+ arch/arm/boot/dts/overlays/i2c5-overlay.dts | 27 ++++++++++
+ arch/arm/boot/dts/overlays/i2c6-overlay.dts | 27 ++++++++++
+ arch/arm/boot/dts/overlays/uart2-overlay.dts | 27 ++++++++++
+ arch/arm/boot/dts/overlays/uart3-overlay.dts | 27 ++++++++++
+ arch/arm/boot/dts/overlays/uart4-overlay.dts | 27 ++++++++++
+ arch/arm/boot/dts/overlays/uart5-overlay.dts | 27 ++++++++++
+ 10 files changed, 276 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/i2c3-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/i2c4-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/i2c5-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/i2c6-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/uart2-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/uart3-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/uart4-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/uart5-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -65,6 +65,10 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ i2c-sensor.dtbo \
+ i2c0-bcm2708.dtbo \
+ i2c1-bcm2708.dtbo \
++ i2c3.dtbo \
++ i2c4.dtbo \
++ i2c5.dtbo \
++ i2c6.dtbo \
+ i2s-gpio28-31.dtbo \
+ ilitek251x.dtbo \
+ iqaudio-codec.dtbo \
+@@ -149,6 +153,10 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ tpm-slb9670.dtbo \
+ uart0.dtbo \
+ uart1.dtbo \
++ uart2.dtbo \
++ uart3.dtbo \
++ uart4.dtbo \
++ uart5.dtbo \
+ udrc.dtbo \
+ upstream.dtbo \
+ vc4-fkms-v3d.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1137,6 +1137,34 @@ Params: sda1_pin GPIO pin
+ "yes")
+
+
++Name: i2c3
++Info: Enable the i2c3 bus
++Load: dtoverlay=i2c3,<param>
++Params: pins_2_3 Use GPIOs 2 and 3
++ pins_4_5 Use GPIOs 4 and 5 (default)
++
++
++Name: i2c4
++Info: Enable the i2c4 bus
++Load: dtoverlay=i2c4,<param>
++Params: pins_6_7 Use GPIOs 6 and 7
++ pins_8_9 Use GPIOs 8 and 9 (default)
++
++
++Name: i2c5
++Info: Enable the i2c5 bus
++Load: dtoverlay=i2c5,<param>
++Params: pins_10_11 Use GPIOs 10 and 11
++ pins_12_13 Use GPIOs 12 and 13 (default)
++
++
++Name: i2c6
++Info: Enable the i2c6 bus
++Load: dtoverlay=i2c6,<param>
++Params: pins_0_1 Use GPIOs 0 and 1
++ pins_22_23 Use GPIOs 22 and 23 (default)
++
++
+ Name: i2s-gpio28-31
+ Info: move I2S function block to GPIO 28 to 31
+ Load: dtoverlay=i2s-gpio28-31
+@@ -2199,6 +2227,30 @@ Params: txd1_pin GPIO pin
+ rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
+
+
++Name: uart2
++Info: Enable uart 2 on GPIOs 0-3
++Load: dtoverlay=uart2,<param>
++Params: ctsrts Enable CTS/RTS on GPIOs 2-3 (default off)
++
++
++Name: uart3
++Info: Enable uart 3 on GPIOs 4-7
++Load: dtoverlay=uart3,<param>
++Params: ctsrts Enable CTS/RTS on GPIOs 6-7 (default off)
++
++
++Name: uart4
++Info: Enable uart 4 on GPIOs 8-11
++Load: dtoverlay=uart4,<param>
++Params: ctsrts Enable CTS/RTS on GPIOs 10-11 (default off)
++
++
++Name: uart5
++Info: Enable uart 5 on GPIOs 12-15
++Load: dtoverlay=uart5,<param>
++Params: ctsrts Enable CTS/RTS on GPIOs 14-15 (default off)
++
++
+ Name: udrc
+ Info: Configures the NW Digital Radio UDRC Hat
+ Load: dtoverlay=udrc,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c3-overlay.dts
+@@ -0,0 +1,27 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&i2c3>;
++ __overlay__ {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c3_pins>;
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c3_pins>;
++ __dormant__ {
++ brcm,pins = <2 3>;
++ };
++ };
++
++ __overrides__ {
++ pins_2_3 = <0>,"=1";
++ pins_4_5 = <0>,"!1";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c4-overlay.dts
+@@ -0,0 +1,27 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&i2c4>;
++ __overlay__ {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c4_pins>;
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c4_pins>;
++ __dormant__ {
++ brcm,pins = <6 7>;
++ };
++ };
++
++ __overrides__ {
++ pins_6_7 = <0>,"=1";
++ pins_8_9 = <0>,"!1";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c5-overlay.dts
+@@ -0,0 +1,27 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&i2c5>;
++ __overlay__ {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c5_pins>;
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c5_pins>;
++ __dormant__ {
++ brcm,pins = <10 11>;
++ };
++ };
++
++ __overrides__ {
++ pins_10_11 = <0>,"=1";
++ pins_12_13 = <0>,"!1";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c6-overlay.dts
+@@ -0,0 +1,27 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&i2c6>;
++ __overlay__ {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c6_pins>;
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c6_pins>;
++ __dormant__ {
++ brcm,pins = <0 1>;
++ };
++ };
++
++ __overrides__ {
++ pins_0_1 = <0>,"=1";
++ pins_22_23 = <0>,"!1";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/uart2-overlay.dts
+@@ -0,0 +1,27 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&uart2>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart2_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&uart2_pins>;
++ __dormant__ {
++ brcm,pins = <0 1 2 3>;
++ brcm,pull = <0 2 2 0>;
++ };
++ };
++
++ __overrides__ {
++ ctsrts = <0>,"=1";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/uart3-overlay.dts
+@@ -0,0 +1,27 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&uart3>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart3_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&uart3_pins>;
++ __dormant__ {
++ brcm,pins = <4 5 6 7>;
++ brcm,pull = <0 2 2 0>;
++ };
++ };
++
++ __overrides__ {
++ ctsrts = <0>,"=1";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/uart4-overlay.dts
+@@ -0,0 +1,27 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&uart4>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart4_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&uart4_pins>;
++ __dormant__ {
++ brcm,pins = <8 9 10 11>;
++ brcm,pull = <0 2 2 0>;
++ };
++ };
++
++ __overrides__ {
++ ctsrts = <0>,"=1";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/uart5-overlay.dts
+@@ -0,0 +1,27 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&uart5>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart5_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&uart5_pins>;
++ __dormant__ {
++ brcm,pins = <12 13 14 15>;
++ brcm,pull = <0 2 2 0>;
++ };
++ };
++
++ __overrides__ {
++ ctsrts = <0>,"=1";
++ };
++};
+++ /dev/null
-From ff78cbcd8d7d656a5f43abd2c744e610b8c6c740 Mon Sep 17 00:00:00 2001
-Date: Wed, 29 May 2019 13:54:21 +0100
-Subject: [PATCH] ARM: dts: Add bcm2711-rpi-4-b.dts and components
-
----
- arch/arm/boot/dts/Makefile | 1 +
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 320 ++++++++++++
- arch/arm/boot/dts/bcm2711.dtsi | 50 ++
- arch/arm/boot/dts/bcm2838.dtsi | 724 ++++++++++++++++++++++++++
- 4 files changed, 1095 insertions(+)
- create mode 100644 arch/arm/boot/dts/bcm2711-rpi-4-b.dts
- create mode 100644 arch/arm/boot/dts/bcm2711.dtsi
- create mode 100644 arch/arm/boot/dts/bcm2838.dtsi
-
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -8,6 +8,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
- bcm2708-rpi-zero-w.dtb \
- bcm2709-rpi-2-b.dtb \
- bcm2710-rpi-3-b.dtb \
-+ bcm2711-rpi-4-b.dtb \
- bcm2710-rpi-3-b-plus.dtb \
- bcm2710-rpi-cm3.dtb
-
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -0,0 +1,320 @@
-+/dts-v1/;
-+
-+#include "bcm2711.dtsi"
-+
-+/ {
-+ compatible = "raspberrypi,4-model-b", "brcm,bcm2838", "brcm,bcm2837";
-+ model = "Raspberry Pi 4 Model B";
-+ #address-cells = <2>;
-+ #size-cells = <1>;
-+
-+ memory {
-+ device_type = "memory";
-+ reg = <0x0 0x0 0x0>;
-+ };
-+
-+ chosen {
-+ bootargs = "8250.nr_uarts=1 cma=64M";
-+ };
-+
-+ aliases {
-+ serial0 = &uart1;
-+ serial1 = &uart0;
-+ mmc0 = &emmc2;
-+ mmc1 = &mmcnr;
-+ mmc2 = &sdhost;
-+ /delete-property/ ethernet;
-+ /delete-property/ intc;
-+ ethernet0 = &genet;
-+ };
-+};
-+
-+&soc {
-+ virtgpio: virtgpio {
-+ compatible = "brcm,bcm2835-virtgpio";
-+ gpio-controller;
-+ #gpio-cells = <2>;
-+ firmware = <&firmware>;
-+ status = "okay";
-+ };
-+};
-+
-+&mmcnr {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdio_pins>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
-+&firmware {
-+ expgpio: expgpio {
-+ compatible = "raspberrypi,firmware-gpio";
-+ gpio-controller;
-+ #gpio-cells = <2>;
-+ 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>;
-+ };
-+};
-+
-+// =============================================
-+// Board specific stuff here
-+
-+/ {
-+
-+ sd_io_1v8_reg: sd_io_1v8_reg {
-+ status = "okay";
-+ compatible = "regulator-gpio";
-+ vin-supply = <&vdd_5v0_reg>;
-+ regulator-name = "vdd-sd-io";
-+ regulator-min-microvolt = <1800000>;
-+ regulator-max-microvolt = <3300000>;
-+ regulator-boot-on;
-+ regulator-always-on;
-+ regulator-settling-time-us = <5000>;
-+
-+ gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
-+ states = <1800000 0x1
-+ 3300000 0x0>;
-+ };
-+};
-+
-+&sdhost {
-+ status = "disabled";
-+};
-+
-+&emmc2 {
-+ status = "okay";
-+ broken-cd;
-+ vqmmc-supply = <&sd_io_1v8_reg>;
-+};
-+
-+&leds {
-+ act_led: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 42 0>;
-+ };
-+
-+ pwr_led: pwr {
-+ label = "led1";
-+ linux,default-trigger = "input";
-+ gpios = <&expgpio 2 0>;
-+ };
-+};
-+
-+&audio {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&audio_pins>;
-+};
-+
-+&sdhost_gpio48 {
-+ brcm,pins = <22 23 24 25 26 27>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+};
-+
-+&gpio {
-+ spi0_pins: spi0_pins {
-+ brcm,pins = <9 10 11>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ };
-+
-+ spi0_cs_pins: spi0_cs_pins {
-+ brcm,pins = <8 7>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
-+
-+ spi3_pins: spi3_pins {
-+ brcm,pins = <1 2 3>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+
-+ spi3_cs_pins: spi3_cs_pins {
-+ brcm,pins = <0 24>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
-+
-+ spi4_pins: spi4_pins {
-+ brcm,pins = <5 6 7>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+
-+ spi4_cs_pins: spi4_cs_pins {
-+ brcm,pins = <4 25>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
-+
-+ spi5_pins: spi5_pins {
-+ brcm,pins = <13 14 15>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+
-+ spi5_cs_pins: spi5_cs_pins {
-+ brcm,pins = <12 26>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
-+
-+ spi6_pins: spi6_pins {
-+ brcm,pins = <19 20 21>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+
-+ spi6_cs_pins: spi6_cs_pins {
-+ brcm,pins = <18 27>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
-+
-+ i2c0_pins: i2c0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ };
-+
-+ i2c1_pins: i2c1 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ };
-+
-+ i2c3_pins: i2c3 {
-+ brcm,pins = <4 5>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+
-+ i2c4_pins: i2c4 {
-+ brcm,pins = <8 9>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+
-+ i2c5_pins: i2c5 {
-+ brcm,pins = <12 13>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+
-+ i2c6_pins: i2c6 {
-+ brcm,pins = <22 23>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+
-+ i2s_pins: i2s {
-+ brcm,pins = <18 19 20 21>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ };
-+
-+ sdio_pins: sdio_pins {
-+ brcm,pins = <34 35 36 37 38 39>;
-+ brcm,function = <BCM2835_FSEL_ALT3>; // alt3 = SD1
-+ brcm,pull = <0 2 2 2 2 2>;
-+ };
-+
-+ bt_pins: bt_pins {
-+ brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0
-+ // to fool pinctrl
-+ brcm,function = <0>;
-+ brcm,pull = <2>;
-+ };
-+
-+ uart0_pins: uart0_pins {
-+ brcm,pins = <32 33>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ brcm,pull = <0 2>;
-+ };
-+
-+ uart1_pins: uart1_pins {
-+ brcm,pins;
-+ brcm,function;
-+ brcm,pull;
-+ };
-+
-+ uart2_pins: uart2_pins {
-+ brcm,pins = <0 1>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <0 2>;
-+ };
-+
-+ uart3_pins: uart3_pins {
-+ brcm,pins = <4 5>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <0 2>;
-+ };
-+
-+ uart4_pins: uart4_pins {
-+ brcm,pins = <8 9>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <0 2>;
-+ };
-+
-+ uart5_pins: uart5_pins {
-+ brcm,pins = <12 13>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <0 2>;
-+ };
-+
-+ audio_pins: audio_pins {
-+ brcm,pins = <40 41>;
-+ brcm,function = <4>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ 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>;
-+};
-+
-+/ {
-+ __overrides__ {
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+
-+ pwr_led_gpio = <&pwr_led>,"gpios:4";
-+ pwr_led_activelow = <&pwr_led>,"gpios:8";
-+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2711.dtsi
-@@ -0,0 +1,50 @@
-+#include "bcm2838.dtsi"
-+#include "bcm270x.dtsi"
-+#include "bcm2708-rpi.dtsi"
-+
-+/ {
-+ soc {
-+ /delete-node/ mailbox@7e00b840;
-+ /delete-node/ v3d@7ec00000;
-+ };
-+
-+ __overrides__ {
-+ arm_freq;
-+ };
-+};
-+
-+&dma {
-+ brcm,dma-channel-mask = <0x7ef5>;
-+};
-+
-+&txp {
-+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&firmwarekms {
-+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&smi {
-+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&mmc {
-+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&mmcnr {
-+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&usb {
-+ reg = <0x7e980000 0x10000>,
-+ <0x7e00b200 0x200>;
-+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&gpio {
-+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -0,0 +1,724 @@
-+// SPDX-License-Identifier: GPL-2.0
-+#include "bcm283x.dtsi"
-+
-+#include <dt-bindings/interrupt-controller/arm-gic.h>
-+#include <dt-bindings/soc/bcm2835-pm.h>
-+
-+/ {
-+ compatible = "brcm,bcm2838", "brcm,bcm2837";
-+
-+ interrupt-parent = <&gicv2>;
-+
-+ soc {
-+ ranges = <0x7e000000 0x0 0xfe000000 0x01800000>,
-+ <0x7c000000 0x0 0xfc000000 0x02000000>,
-+ <0x40000000 0x0 0xff800000 0x00800000>;
-+ /* Emulate a contiguous 30-bit address range for DMA */
-+ dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
-+
-+ /delete-node/ mailbox@7e00b840;
-+ /delete-node/ interrupt-controller@7e00f300;
-+
-+ local_intc: local_intc@40000000 {
-+ compatible = "brcm,bcm2836-l1-intc";
-+ reg = <0x40000000 0x100>;
-+ };
-+
-+ gicv2: gic400@40041000 {
-+ interrupt-controller;
-+ #interrupt-cells = <3>;
-+ compatible = "arm,gic-400";
-+ reg = <0x40041000 0x1000>,
-+ <0x40042000 0x2000>,
-+ <0x40046000 0x2000>,
-+ <0x40048000 0x2000>;
-+ };
-+
-+ thermal: thermal@7d5d2200 {
-+ compatible = "brcm,avs-tmon-bcm2838";
-+ reg = <0x7d5d2200 0x2c>;
-+ interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "tmon";
-+ clocks = <&clocks BCM2835_CLOCK_TSENS>;
-+ #thermal-sensor-cells = <0>;
-+ status = "okay";
-+ };
-+
-+ pm: watchdog@7e100000 {
-+ reg = <0x7e100000 0x114>,
-+ <0x7e00a000 0x24>,
-+ <0x7ec11000 0x20>;
-+ };
-+
-+ rng@7e104000 {
-+ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+
-+ uart2: serial@7e201400 {
-+ compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
-+ reg = <0x7e201400 0x200>;
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_UART>,
-+ <&clocks BCM2835_CLOCK_VPU>;
-+ clock-names = "uartclk", "apb_pclk";
-+ arm,primecell-periphid = <0x00241011>;
-+ status = "disabled";
-+ };
-+
-+ uart3: serial@7e201600 {
-+ compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
-+ reg = <0x7e201600 0x200>;
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_UART>,
-+ <&clocks BCM2835_CLOCK_VPU>;
-+ clock-names = "uartclk", "apb_pclk";
-+ arm,primecell-periphid = <0x00241011>;
-+ status = "disabled";
-+ };
-+
-+ uart4: serial@7e201800 {
-+ compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
-+ reg = <0x7e201800 0x200>;
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_UART>,
-+ <&clocks BCM2835_CLOCK_VPU>;
-+ clock-names = "uartclk", "apb_pclk";
-+ arm,primecell-periphid = <0x00241011>;
-+ status = "disabled";
-+ };
-+
-+ uart5: serial@7e201a00 {
-+ compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
-+ reg = <0x7e201a00 0x200>;
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_UART>,
-+ <&clocks BCM2835_CLOCK_VPU>;
-+ clock-names = "uartclk", "apb_pclk";
-+ arm,primecell-periphid = <0x00241011>;
-+ status = "disabled";
-+ };
-+
-+ spi@7e204000 {
-+ reg = <0x7e204000 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+
-+ spi3: spi@7e204600 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204600 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ spi4: spi@7e204800 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204800 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ spi5: spi@7e204a00 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204a00 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ spi6: spi@7e204c00 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204c00 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c3: i2c@7e205600 {
-+ compatible = "brcm,bcm2835-i2c";
-+ reg = <0x7e205600 0x200>;
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c4: i2c@7e205800 {
-+ compatible = "brcm,bcm2835-i2c";
-+ reg = <0x7e205800 0x200>;
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c5: i2c@7e205a00 {
-+ compatible = "brcm,bcm2835-i2c";
-+ reg = <0x7e205a00 0x200>;
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c6: i2c@7e205c00 {
-+ compatible = "brcm,bcm2835-i2c";
-+ reg = <0x7e205c00 0x200>;
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ pixelvalve@7e206000 {
-+ interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+
-+ pixelvalve@7e207000 {
-+ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+
-+ emmc2: emmc2@7e340000 {
-+ compatible = "brcm,bcm2711-emmc2";
-+ status = "okay";
-+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2838_CLOCK_EMMC2>;
-+ reg = <0x7e340000 0x100>;
-+ };
-+
-+ hvs@7e400000 {
-+ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+
-+ pixelvalve@7e807000 {
-+ interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+ };
-+
-+ arm-pmu {
-+ /*
-+ * N.B. the A72 PMU support only exists in arch/arm64, hence
-+ * the fallback to the A53 version.
-+ */
-+ compatible = "arm,cortex-a72-pmu", "arm,cortex-a53-pmu";
-+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+
-+ timer {
-+ compatible = "arm,armv7-timer";
-+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_LOW)>,
-+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_LOW)>,
-+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_LOW)>,
-+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_LOW)>;
-+ arm,cpu-registers-not-fw-configured;
-+ always-on;
-+ };
-+
-+ cpus: cpus {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
-+
-+ cpu0: cpu@0 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a72";
-+ reg = <0>;
-+ enable-method = "spin-table";
-+ cpu-release-addr = <0x0 0x000000d8>;
-+ };
-+
-+ cpu1: cpu@1 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a72";
-+ reg = <1>;
-+ enable-method = "spin-table";
-+ cpu-release-addr = <0x0 0x000000e0>;
-+ };
-+
-+ cpu2: cpu@2 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a72";
-+ reg = <2>;
-+ enable-method = "spin-table";
-+ cpu-release-addr = <0x0 0x000000e8>;
-+ };
-+
-+ cpu3: cpu@3 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a72";
-+ reg = <3>;
-+ enable-method = "spin-table";
-+ cpu-release-addr = <0x0 0x000000f0>;
-+ };
-+ };
-+
-+ v3dbus {
-+ compatible = "simple-bus";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ ranges = <0x7c500000 0x0 0xfc500000 0x03300000>,
-+ <0x40000000 0x0 0xff800000 0x00800000>;
-+ dma-ranges = <0x00000000 0x0 0x00000000 0x3c000000>;
-+
-+ v3d: v3d@7ec04000 {
-+ compatible = "brcm,2711-v3d";
-+ reg =
-+ <0x7ec00000 0x4000>,
-+ <0x7ec04000 0x4000>;
-+ reg-names = "hub", "core0";
-+
-+ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
-+ resets = <&pm BCM2835_RESET_V3D>;
-+ clocks = <&clocks BCM2835_CLOCK_V3D>;
-+ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
-+ status = "okay";
-+ };
-+ };
-+
-+ scb: scb {
-+ compatible = "simple-bus";
-+ #address-cells = <2>;
-+ #size-cells = <1>;
-+
-+ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>,
-+ <0x0 0x40000000 0x0 0xff800000 0x00800000>,
-+ <0x6 0x00000000 0x6 0x00000000 0x40000000>,
-+ <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
-+ dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
-+
-+ pcie_0: pcie@7d500000 {
-+ reg = <0x0 0x7d500000 0x9310>,
-+ <0x0 0x7e00f300 0x20>;
-+ msi-controller;
-+ msi-parent = <&pcie_0>;
-+ #address-cells = <3>;
-+ #interrupt-cells = <1>;
-+ #size-cells = <2>;
-+ bus-range = <0x0 0x01>;
-+ compatible = "brcm,bcm7211-pcie", "brcm,bcm7445-pcie",
-+ "brcm,pci-plat-dev";
-+ max-link-speed = <2>;
-+ tot-num-pcie = <1>;
-+ linux,pci-domain = <0>;
-+ interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "pcie", "msi";
-+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
-+ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143
-+ IRQ_TYPE_LEVEL_HIGH
-+ 0 0 0 2 &gicv2 GIC_SPI 144
-+ IRQ_TYPE_LEVEL_HIGH
-+ 0 0 0 3 &gicv2 GIC_SPI 145
-+ IRQ_TYPE_LEVEL_HIGH
-+ 0 0 0 4 &gicv2 GIC_SPI 146
-+ IRQ_TYPE_LEVEL_HIGH>;
-+
-+ /* Map outbound accesses from scb:0x6_00000000-03ffffff
-+ * to pci:0x0_f8000000-fbffffff
-+ */
-+ ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000
-+ 0x0 0x04000000>;
-+ /* Map inbound accesses from pci:0x0_00000000..ffffffff
-+ * to scb:0x0_00000000-ffffffff
-+ */
-+ dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000
-+ 0x1 0x00000000>;
-+ status = "okay";
-+ };
-+
-+ genet: genet@7d580000 {
-+ compatible = "brcm,genet-v5";
-+ reg = <0x0 0x7d580000 0x10000>;
-+ status = "okay";
-+ #address-cells = <0x1>;
-+ #size-cells = <0x1>;
-+ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
-+ phy-handle = <&phy1>;
-+ phy-mode = "rgmii";
-+ mdio@e14 {
-+ #address-cells = <0x0>;
-+ #size-cells = <0x1>;
-+ compatible = "brcm,genet-mdio-v5";
-+ reg = <0xe14 0x8>;
-+ reg-names = "mdio";
-+ phy1: genet-phy@0 {
-+ compatible =
-+ "ethernet-phy-ieee802.3-c22";
-+ /* No interrupts - use PHY_POLL */
-+ max-speed = <1000>;
-+ reg = <0x1>;
-+ };
-+ };
-+ };
-+
-+ xhci: xhci@7e9c0000 {
-+ compatible = "generic-xhci";
-+ status = "disabled";
-+ reg = <0x0 0x7e9c0000 0x100000>;
-+ interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+
-+ vchiq: mailbox@7e00b840 {
-+ compatible = "brcm,bcm2838-vchiq";
-+ reg = <0 0x7e00b840 0x3c>;
-+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+
-+ hevc-decoder@7eb00000 {
-+ compatible = "raspberrypi,argon-hevc-decoder";
-+ reg = <0x0 0x7eb00000 0x10000>;
-+ status = "okay";
-+ };
-+
-+ argon-local-intc@7eb10000 {
-+ compatible = "raspberrypi,argon-local-intc";
-+ reg = <0x0 0x7eb10000 0x1000>;
-+ status = "okay";
-+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+
-+ h264-decoder@7eb20000 {
-+ compatible = "raspberrypi,argon-h264-decoder";
-+ reg = <0x0 0x7eb20000 0x10000>;
-+ status = "okay";
-+ };
-+
-+ vp9-decoder@7eb30000 {
-+ compatible = "raspberrypi,argon-vp9-decoder";
-+ reg = <0x0 0x7eb30000 0x10000>;
-+ status = "okay";
-+ };
-+ };
-+};
-+
-+&clk_osc {
-+ clock-frequency = <54000000>;
-+};
-+
-+&clocks {
-+ compatible = "brcm,bcm2838-cprman";
-+};
-+
-+&cpu_thermal {
-+ coefficients = <(-487) 410040>;
-+};
-+
-+&dsi0 {
-+ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&dsi1 {
-+ interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&gpio {
-+ gpclk0_gpio49: gpclk0_gpio49 {
-+ brcm,pins = <49>;
-+ brcm,function = <BCM2835_FSEL_ALT1>;
-+ brcm,pull = <BCM2835_PUD_OFF>;
-+ };
-+ gpclk1_gpio50: gpclk1_gpio50 {
-+ brcm,pins = <50>;
-+ brcm,function = <BCM2835_FSEL_ALT1>;
-+ brcm,pull = <BCM2835_PUD_OFF>;
-+ };
-+ gpclk2_gpio51: gpclk2_gpio51 {
-+ brcm,pins = <51>;
-+ brcm,function = <BCM2835_FSEL_ALT1>;
-+ brcm,pull = <BCM2835_PUD_OFF>;
-+ };
-+
-+ i2c0_gpio46: i2c0_gpio46 {
-+ brcm,pins = <46 47>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ };
-+ i2c1_gpio46: i2c1_gpio46 {
-+ brcm,pins = <46 47>;
-+ brcm,function = <BCM2835_FSEL_ALT1>;
-+ };
-+ i2c3_gpio2: i2c3_gpio2 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ i2c3_gpio4: i2c3_gpio4 {
-+ brcm,pins = <4 5>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ i2c4_gpio6: i2c4_gpio6 {
-+ brcm,pins = <6 7>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ i2c4_gpio8: i2c4_gpio8 {
-+ brcm,pins = <8 9>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ i2c5_gpio10: i2c5_gpio10 {
-+ brcm,pins = <10 11>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ i2c5_gpio12: i2c5_gpio12 {
-+ brcm,pins = <12 13>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ i2c6_gpio0: i2c6_gpio0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ i2c6_gpio22: i2c6_gpio22 {
-+ brcm,pins = <22 23>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ i2c_slave_gpio8: i2c_slave_gpio8 {
-+ brcm,pins = <8 9 10 11>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+
-+ jtag_gpio48: jtag_gpio48 {
-+ brcm,pins = <48 49 50 51 52 53>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ };
-+
-+ mii_gpio28: mii_gpio28 {
-+ brcm,pins = <28 29 30 31>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ };
-+ mii_gpio36: mii_gpio36 {
-+ brcm,pins = <36 37 38 39>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+
-+ pcm_gpio50: pcm_gpio50 {
-+ brcm,pins = <50 51 52 53>;
-+ brcm,function = <BCM2835_FSEL_ALT2>;
-+ };
-+
-+ pwm0_gpio52: pwm0_gpio52 {
-+ brcm,pins = <52>;
-+ brcm,function = <BCM2835_FSEL_ALT1>;
-+ brcm,pull = <BCM2835_PUD_OFF>;
-+ };
-+ pwm1_gpio53: pwm1_gpio53 {
-+ brcm,pins = <53>;
-+ brcm,function = <BCM2835_FSEL_ALT1>;
-+ brcm,pull = <BCM2835_PUD_OFF>;
-+ };
-+
-+ /* The following group consists of:
-+ * RGMII_START_STOP
-+ * RGMII_RX_OK
-+ */
-+ rgmii_gpio35: rgmii_gpio35 {
-+ brcm,pins = <35 36>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ };
-+ rgmii_irq_gpio34: rgmii_irq_gpio34 {
-+ brcm,pins = <34>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ rgmii_irq_gpio39: rgmii_irq_gpio39 {
-+ brcm,pins = <39>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ };
-+ rgmii_mdio_gpio28: rgmii_mdio_gpio28 {
-+ brcm,pins = <28 29>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ rgmii_mdio_gpio37: rgmii_mdio_gpio37 {
-+ brcm,pins = <37 38>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ };
-+
-+ spi0_gpio46: spi0_gpio46 {
-+ brcm,pins = <46 47 48 49>;
-+ brcm,function = <BCM2835_FSEL_ALT2>;
-+ };
-+ spi2_gpio46: spi2_gpio46 {
-+ brcm,pins = <46 47 48 49 50>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ spi3_gpio0: spi3_gpio0 {
-+ brcm,pins = <0 1 2 3>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+ spi4_gpio4: spi4_gpio4 {
-+ brcm,pins = <4 5 6 7>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+ spi5_gpio12: spi5_gpio12 {
-+ brcm,pins = <12 13 14 15>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+ spi6_gpio18: spi6_gpio18 {
-+ brcm,pins = <18 19 20 21>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+
-+ uart2_gpio0: uart2_gpio0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
-+ };
-+ uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
-+ };
-+ uart3_gpio4: uart3_gpio4 {
-+ brcm,pins = <4 5>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
-+ };
-+ uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 {
-+ brcm,pins = <6 7>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
-+ };
-+ uart4_gpio8: uart4_gpio8 {
-+ brcm,pins = <8 9>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
-+ };
-+ uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 {
-+ brcm,pins = <10 11>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
-+ };
-+ uart5_gpio12: uart5_gpio12 {
-+ brcm,pins = <12 13>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
-+ };
-+ uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 {
-+ brcm,pins = <14 15>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
-+ };
-+};
-+
-+&vec {
-+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&usb {
-+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&hdmi {
-+ interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&uart1 {
-+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&spi1 {
-+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&spi2 {
-+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&csi0 {
-+ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&csi1 {
-+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&sdhci {
-+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&i2c0 {
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&i2c1 {
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&i2c2 {
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&gpio {
-+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&mailbox {
-+ interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&rng {
-+ compatible = "brcm,bcm2838-rng200";
-+};
-+
-+&sdhost {
-+ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&uart0 {
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&dma {
-+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 7 */
-+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 8 */
-+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 9 */
-+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 10 */
-+ /* DMA4 - 40 bit DMA engines */
-+ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
-+ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 12 */
-+ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, /* dma4 13 */
-+ <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; /* dma4 14 */
-+ interrupt-names = "dma0",
-+ "dma1",
-+ "dma2",
-+ "dma3",
-+ "dma4",
-+ "dma5",
-+ "dma6",
-+ "dma7",
-+ "dma8",
-+ "dma9",
-+ "dma10",
-+ "dma11",
-+ "dma12",
-+ "dma13",
-+ "dma14";
-+ brcm,dma-channel-mask = <0x7ef5>;
-+};
--- /dev/null
+From a4ea446a07d7ba010c3c32286a22dc89cffa1e54 Mon Sep 17 00:00:00 2001
+Date: Sun, 12 May 2019 16:17:08 +0000
+Subject: [PATCH] spi: devicetree: add overlays for spi 3 to 6
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 8 ++
+ arch/arm/boot/dts/overlays/README | 104 ++++++++++++++++++
+ .../boot/dts/overlays/spi3-1cs-overlay.dts | 44 ++++++++
+ .../boot/dts/overlays/spi3-2cs-overlay.dts | 56 ++++++++++
+ .../boot/dts/overlays/spi4-1cs-overlay.dts | 44 ++++++++
+ .../boot/dts/overlays/spi4-2cs-overlay.dts | 56 ++++++++++
+ .../boot/dts/overlays/spi5-1cs-overlay.dts | 44 ++++++++
+ .../boot/dts/overlays/spi5-2cs-overlay.dts | 56 ++++++++++
+ .../boot/dts/overlays/spi6-1cs-overlay.dts | 44 ++++++++
+ .../boot/dts/overlays/spi6-2cs-overlay.dts | 56 ++++++++++
+ 10 files changed, 512 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -144,6 +144,14 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ spi2-1cs.dtbo \
+ spi2-2cs.dtbo \
+ spi2-3cs.dtbo \
++ spi3-1cs.dtbo \
++ spi3-2cs.dtbo \
++ spi4-1cs.dtbo \
++ spi4-2cs.dtbo \
++ spi5-1cs.dtbo \
++ spi5-2cs.dtbo \
++ spi6-1cs.dtbo \
++ spi6-2cs.dtbo \
+ ssd1306.dtbo \
+ superaudioboard.dtbo \
+ sx150x.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2085,6 +2085,110 @@ Params: cs0_pin GPIO pin
+ is 'okay' or enabled).
+
+
++Name: spi3-1cs
++Info: Enables spi3 with a single chip select (CS) line and associated spidev
++ dev node. The gpio pin number for the CS line and spidev device node
++ creation are configurable.
++Load: dtoverlay=spi3-1cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 0 - BCM SPI3_CE0).
++ cs0_spidev Set to 'off' to prevent the creation of a
++ userspace device node /dev/spidev3.0 (default
++ is 'on' or enabled).
++
++
++Name: spi3-2cs
++Info: Enables spi3 with two chip select (CS) lines and associated spidev
++ dev nodes. The gpio pin numbers for the CS lines and spidev device node
++ creation are configurable.
++Load: dtoverlay=spi3-2cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 0 - BCM SPI3_CE0).
++ cs1_pin GPIO pin for CS1 (default 24 - BCM SPI3_CE1).
++ cs0_spidev Set to 'off' to prevent the creation of a
++ userspace device node /dev/spidev3.0 (default
++ is 'on' or enabled).
++ cs1_spidev Set to 'off' to prevent the creation of a
++ userspace device node /dev/spidev3.1 (default
++ is 'on' or enabled).
++
++
++Name: spi4-1cs
++Info: Enables spi4 with a single chip select (CS) line and associated spidev
++ dev node. The gpio pin number for the CS line and spidev device node
++ creation are configurable.
++Load: dtoverlay=spi4-1cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 4 - BCM SPI4_CE0).
++ cs0_spidev Set to 'off' to prevent the creation of a
++ userspace device node /dev/spidev4.0 (default
++ is 'on' or enabled).
++
++
++Name: spi4-2cs
++Info: Enables spi4 with two chip select (CS) lines and associated spidev
++ dev nodes. The gpio pin numbers for the CS lines and spidev device node
++ creation are configurable.
++Load: dtoverlay=spi4-2cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 4 - BCM SPI4_CE0).
++ cs1_pin GPIO pin for CS1 (default 25 - BCM SPI4_CE1).
++ cs0_spidev Set to 'off' to prevent the creation of a
++ userspace device node /dev/spidev4.0 (default
++ is 'on' or enabled).
++ cs1_spidev Set to 'off' to prevent the creation of a
++ userspace device node /dev/spidev4.1 (default
++ is 'on' or enabled).
++
++
++Name: spi5-1cs
++Info: Enables spi5 with a single chip select (CS) line and associated spidev
++ dev node. The gpio pin numbers for the CS lines and spidev device node
++ creation are configurable.
++Load: dtoverlay=spi5-1cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 12 - BCM SPI5_CE0).
++ cs0_spidev Set to 'off' to prevent the creation of a
++ userspace device node /dev/spidev5.0 (default
++ is 'on' or enabled).
++
++
++Name: spi5-2cs
++Info: Enables spi5 with two chip select (CS) lines and associated spidev
++ dev nodes. The gpio pin numbers for the CS lines and spidev device node
++ creation are configurable.
++Load: dtoverlay=spi5-2cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 12 - BCM SPI5_CE0).
++ cs1_pin GPIO pin for CS1 (default 26 - BCM SPI5_CE1).
++ cs0_spidev Set to 'off' to prevent the creation of a
++ userspace device node /dev/spidev5.0 (default
++ is 'on' or enabled).
++ cs1_spidev Set to 'off' to prevent the creation of a
++ userspace device node /dev/spidev5.1 (default
++ is 'on' or enabled).
++
++
++Name: spi6-1cs
++Info: Enables spi6 with a single chip select (CS) line and associated spidev
++ dev node. The gpio pin number for the CS line and spidev device node
++ creation are configurable.
++Load: dtoverlay=spi6-1cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI6_CE0).
++ cs0_spidev Set to 'off' to prevent the creation of a
++ userspace device node /dev/spidev6.0 (default
++ is 'on' or enabled).
++
++
++Name: spi6-2cs
++Info: Enables spi6 with two chip select (CS) lines and associated spidev
++ dev nodes. The gpio pin numbers for the CS lines and spidev device node
++ creation are configurable.
++Load: dtoverlay=spi6-2cs,<param>=<val>
++Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI6_CE0).
++ cs1_pin GPIO pin for CS1 (default 27 - BCM SPI6_CE1).
++ cs0_spidev Set to 'off' to prevent the creation of a
++ userspace device node /dev/spidev6.0 (default
++ is 'on' or enabled).
++ cs1_spidev Set to 'off' to prevent the creation of a
++ userspace device node /dev/spidev6.1 (default
++ is 'on' or enabled).
++
++
+ Name: ssd1306
+ Info: Overlay for activation of SSD1306 over I2C OLED display framebuffer.
+ Load: dtoverlay=ssd1306,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts
+@@ -0,0 +1,44 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&spi3_cs_pins>;
++ frag0: __overlay__ {
++ brcm,pins = <0>;
++ brcm,function = <1>; /* output */
++ };
++ };
++
++ fragment@1 {
++ target = <&spi3>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi3_pins &spi3_cs_pins>;
++ cs-gpios = <&gpio 0 1>;
++ status = "okay";
++
++ spidev3_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ status = "okay";
++ };
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&frag0>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs0_spidev = <&spidev3_0>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts
+@@ -0,0 +1,56 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&spi3_cs_pins>;
++ frag0: __overlay__ {
++ brcm,pins = <0 24>;
++ brcm,function = <1>; /* output */
++ };
++ };
++
++ fragment@1 {
++ target = <&spi3>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi3_pins &spi3_cs_pins>;
++ cs-gpios = <&gpio 0 1>, <&gpio 24 1>;
++ status = "okay";
++
++ spidev3_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ status = "okay";
++ };
++
++ spidev3_1: spidev@1 {
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ status = "okay";
++ };
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&frag0>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs1_pin = <&frag0>,"brcm,pins:4",
++ <&frag1>,"cs-gpios:16";
++ cs0_spidev = <&spidev3_0>,"status";
++ cs1_spidev = <&spidev3_1>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts
+@@ -0,0 +1,44 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&spi4_cs_pins>;
++ frag0: __overlay__ {
++ brcm,pins = <4>;
++ brcm,function = <1>; /* output */
++ };
++ };
++
++ fragment@1 {
++ target = <&spi4>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi4_pins &spi4_cs_pins>;
++ cs-gpios = <&gpio 4 1>;
++ status = "okay";
++
++ spidev4_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ status = "okay";
++ };
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&frag0>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs0_spidev = <&spidev4_0>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts
+@@ -0,0 +1,56 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&spi4_cs_pins>;
++ frag0: __overlay__ {
++ brcm,pins = <4 25>;
++ brcm,function = <1>; /* output */
++ };
++ };
++
++ fragment@1 {
++ target = <&spi4>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi4_pins &spi4_cs_pins>;
++ cs-gpios = <&gpio 4 1>, <&gpio 25 1>;
++ status = "okay";
++
++ spidev4_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ status = "okay";
++ };
++
++ spidev4_1: spidev@1 {
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ status = "okay";
++ };
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&frag0>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs1_pin = <&frag0>,"brcm,pins:4",
++ <&frag1>,"cs-gpios:16";
++ cs0_spidev = <&spidev4_0>,"status";
++ cs1_spidev = <&spidev4_1>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts
+@@ -0,0 +1,44 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&spi5_cs_pins>;
++ frag0: __overlay__ {
++ brcm,pins = <12>;
++ brcm,function = <1>; /* output */
++ };
++ };
++
++ fragment@1 {
++ target = <&spi5>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi5_pins &spi5_cs_pins>;
++ cs-gpios = <&gpio 12 1>;
++ status = "okay";
++
++ spidev5_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ status = "okay";
++ };
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&frag0>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs0_spidev = <&spidev5_0>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts
+@@ -0,0 +1,56 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&spi5_cs_pins>;
++ frag0: __overlay__ {
++ brcm,pins = <12 26>;
++ brcm,function = <1>; /* output */
++ };
++ };
++
++ fragment@1 {
++ target = <&spi5>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi5_pins &spi5_cs_pins>;
++ cs-gpios = <&gpio 12 1>, <&gpio 26 1>;
++ status = "okay";
++
++ spidev5_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ status = "okay";
++ };
++
++ spidev5_1: spidev@1 {
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ status = "okay";
++ };
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&frag0>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs1_pin = <&frag0>,"brcm,pins:4",
++ <&frag1>,"cs-gpios:16";
++ cs0_spidev = <&spidev5_0>,"status";
++ cs1_spidev = <&spidev5_1>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts
+@@ -0,0 +1,44 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&spi6_cs_pins>;
++ frag0: __overlay__ {
++ brcm,pins = <18>;
++ brcm,function = <1>; /* output */
++ };
++ };
++
++ fragment@1 {
++ target = <&spi6>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi6_pins &spi6_cs_pins>;
++ cs-gpios = <&gpio 18 1>;
++ status = "okay";
++
++ spidev6_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ status = "okay";
++ };
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&frag0>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs0_spidev = <&spidev6_0>,"status";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts
+@@ -0,0 +1,56 @@
++/dts-v1/;
++/plugin/;
++
++
++/ {
++ compatible = "brcm,bcm2838";
++
++ fragment@0 {
++ target = <&spi6_cs_pins>;
++ frag0: __overlay__ {
++ brcm,pins = <18 27>;
++ brcm,function = <1>; /* output */
++ };
++ };
++
++ fragment@1 {
++ target = <&spi6>;
++ frag1: __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi6_pins &spi6_cs_pins>;
++ cs-gpios = <&gpio 18 1>, <&gpio 27 1>;
++ status = "okay";
++
++ spidev6_0: spidev@0 {
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ status = "okay";
++ };
++
++ spidev6_1: spidev@1 {
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ status = "okay";
++ };
++ };
++ };
++
++ __overrides__ {
++ cs0_pin = <&frag0>,"brcm,pins:0",
++ <&frag1>,"cs-gpios:4";
++ cs1_pin = <&frag0>,"brcm,pins:4",
++ <&frag1>,"cs-gpios:16";
++ cs0_spidev = <&spidev6_0>,"status";
++ cs1_spidev = <&spidev6_1>,"status";
++ };
++};
+++ /dev/null
-From 13be2bbd1a22f1b4d9fd260d80b561698f623ac1 Mon Sep 17 00:00:00 2001
-Date: Thu, 30 May 2019 16:44:24 +0100
-Subject: [PATCH] overlays: Add i2c3-6 and uart2-5 overlays
-
----
- arch/arm/boot/dts/overlays/Makefile | 8 +++
- arch/arm/boot/dts/overlays/README | 52 ++++++++++++++++++++
- arch/arm/boot/dts/overlays/i2c3-overlay.dts | 27 ++++++++++
- arch/arm/boot/dts/overlays/i2c4-overlay.dts | 27 ++++++++++
- arch/arm/boot/dts/overlays/i2c5-overlay.dts | 27 ++++++++++
- arch/arm/boot/dts/overlays/i2c6-overlay.dts | 27 ++++++++++
- arch/arm/boot/dts/overlays/uart2-overlay.dts | 27 ++++++++++
- arch/arm/boot/dts/overlays/uart3-overlay.dts | 27 ++++++++++
- arch/arm/boot/dts/overlays/uart4-overlay.dts | 27 ++++++++++
- arch/arm/boot/dts/overlays/uart5-overlay.dts | 27 ++++++++++
- 10 files changed, 276 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/i2c3-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/i2c4-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/i2c5-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/i2c6-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/uart2-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/uart3-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/uart4-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/uart5-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -65,6 +65,10 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- i2c-sensor.dtbo \
- i2c0-bcm2708.dtbo \
- i2c1-bcm2708.dtbo \
-+ i2c3.dtbo \
-+ i2c4.dtbo \
-+ i2c5.dtbo \
-+ i2c6.dtbo \
- i2s-gpio28-31.dtbo \
- ilitek251x.dtbo \
- iqaudio-codec.dtbo \
-@@ -149,6 +153,10 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- tpm-slb9670.dtbo \
- uart0.dtbo \
- uart1.dtbo \
-+ uart2.dtbo \
-+ uart3.dtbo \
-+ uart4.dtbo \
-+ uart5.dtbo \
- udrc.dtbo \
- upstream.dtbo \
- vc4-fkms-v3d.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1137,6 +1137,34 @@ Params: sda1_pin GPIO pin
- "yes")
-
-
-+Name: i2c3
-+Info: Enable the i2c3 bus
-+Load: dtoverlay=i2c3,<param>
-+Params: pins_2_3 Use GPIOs 2 and 3
-+ pins_4_5 Use GPIOs 4 and 5 (default)
-+
-+
-+Name: i2c4
-+Info: Enable the i2c4 bus
-+Load: dtoverlay=i2c4,<param>
-+Params: pins_6_7 Use GPIOs 6 and 7
-+ pins_8_9 Use GPIOs 8 and 9 (default)
-+
-+
-+Name: i2c5
-+Info: Enable the i2c5 bus
-+Load: dtoverlay=i2c5,<param>
-+Params: pins_10_11 Use GPIOs 10 and 11
-+ pins_12_13 Use GPIOs 12 and 13 (default)
-+
-+
-+Name: i2c6
-+Info: Enable the i2c6 bus
-+Load: dtoverlay=i2c6,<param>
-+Params: pins_0_1 Use GPIOs 0 and 1
-+ pins_22_23 Use GPIOs 22 and 23 (default)
-+
-+
- Name: i2s-gpio28-31
- Info: move I2S function block to GPIO 28 to 31
- Load: dtoverlay=i2s-gpio28-31
-@@ -2199,6 +2227,30 @@ Params: txd1_pin GPIO pin
- rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
-
-
-+Name: uart2
-+Info: Enable uart 2 on GPIOs 0-3
-+Load: dtoverlay=uart2,<param>
-+Params: ctsrts Enable CTS/RTS on GPIOs 2-3 (default off)
-+
-+
-+Name: uart3
-+Info: Enable uart 3 on GPIOs 4-7
-+Load: dtoverlay=uart3,<param>
-+Params: ctsrts Enable CTS/RTS on GPIOs 6-7 (default off)
-+
-+
-+Name: uart4
-+Info: Enable uart 4 on GPIOs 8-11
-+Load: dtoverlay=uart4,<param>
-+Params: ctsrts Enable CTS/RTS on GPIOs 10-11 (default off)
-+
-+
-+Name: uart5
-+Info: Enable uart 5 on GPIOs 12-15
-+Load: dtoverlay=uart5,<param>
-+Params: ctsrts Enable CTS/RTS on GPIOs 14-15 (default off)
-+
-+
- Name: udrc
- Info: Configures the NW Digital Radio UDRC Hat
- Load: dtoverlay=udrc,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/i2c3-overlay.dts
-@@ -0,0 +1,27 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&i2c3>;
-+ __overlay__ {
-+ status = "okay";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c3_pins>;
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2c3_pins>;
-+ __dormant__ {
-+ brcm,pins = <2 3>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ pins_2_3 = <0>,"=1";
-+ pins_4_5 = <0>,"!1";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/i2c4-overlay.dts
-@@ -0,0 +1,27 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&i2c4>;
-+ __overlay__ {
-+ status = "okay";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c4_pins>;
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2c4_pins>;
-+ __dormant__ {
-+ brcm,pins = <6 7>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ pins_6_7 = <0>,"=1";
-+ pins_8_9 = <0>,"!1";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/i2c5-overlay.dts
-@@ -0,0 +1,27 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&i2c5>;
-+ __overlay__ {
-+ status = "okay";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c5_pins>;
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2c5_pins>;
-+ __dormant__ {
-+ brcm,pins = <10 11>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ pins_10_11 = <0>,"=1";
-+ pins_12_13 = <0>,"!1";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/i2c6-overlay.dts
-@@ -0,0 +1,27 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&i2c6>;
-+ __overlay__ {
-+ status = "okay";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c6_pins>;
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2c6_pins>;
-+ __dormant__ {
-+ brcm,pins = <0 1>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ pins_0_1 = <0>,"=1";
-+ pins_22_23 = <0>,"!1";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/uart2-overlay.dts
-@@ -0,0 +1,27 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&uart2>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart2_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&uart2_pins>;
-+ __dormant__ {
-+ brcm,pins = <0 1 2 3>;
-+ brcm,pull = <0 2 2 0>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ ctsrts = <0>,"=1";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/uart3-overlay.dts
-@@ -0,0 +1,27 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&uart3>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart3_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&uart3_pins>;
-+ __dormant__ {
-+ brcm,pins = <4 5 6 7>;
-+ brcm,pull = <0 2 2 0>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ ctsrts = <0>,"=1";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/uart4-overlay.dts
-@@ -0,0 +1,27 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&uart4>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart4_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&uart4_pins>;
-+ __dormant__ {
-+ brcm,pins = <8 9 10 11>;
-+ brcm,pull = <0 2 2 0>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ ctsrts = <0>,"=1";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/uart5-overlay.dts
-@@ -0,0 +1,27 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&uart5>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart5_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&uart5_pins>;
-+ __dormant__ {
-+ brcm,pins = <12 13 14 15>;
-+ brcm,pull = <0 2 2 0>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ ctsrts = <0>,"=1";
-+ };
-+};
--- /dev/null
+From 726da40b8c272d181a41686195f91b914363167b Mon Sep 17 00:00:00 2001
+Date: Tue, 22 Jan 2019 10:49:41 +0000
+Subject: [PATCH] overlays: Add the spi-gpio40-45 overlay
+
+The 2711 B0 boot EEPROM is programmed via SPI0 on GPIO
+pins 40-43 CS0. Add a device tree overlay to optionally
+change the SPI0 pinmux from the external GPIO pins to
+the boot EEPROM pins.
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 ++++
+ .../dts/overlays/spi-gpio40-45-overlay.dts | 36 +++++++++++++++++++
+ 3 files changed, 43 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/spi-gpio40-45-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -135,6 +135,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ smi-dev.dtbo \
+ smi-nand.dtbo \
+ spi-gpio35-39.dtbo \
++ spi-gpio40-45.dtbo \
+ spi-rtc.dtbo \
+ spi0-cs.dtbo \
+ spi0-hw-cs.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1967,6 +1967,12 @@ Load: dtoverlay=spi-gpio35-39
+ Params: <None>
+
+
++Name: spi-gpio40-45
++Info: Move SPI function block to GPIOs 40 to 45
++Load: dtoverlay=spi-gpio40-45
++Params: <None>
++
++
+ Name: spi-rtc
+ Info: Adds support for a number of SPI Real Time Clock devices
+ Load: dtoverlay=spi-rtc,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/spi-gpio40-45-overlay.dts
+@@ -0,0 +1,36 @@
++/*
++ * Boot EEPROM overlay
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ cs-gpios = <&gpio 43 1>, <&gpio 44 1>, <&gpio 45 1>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&spi0_cs_pins>;
++ __overlay__ {
++ brcm,pins = <45 44 43>;
++ brcm,function = <1>; /* output */
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0_pins>;
++ __overlay__ {
++ brcm,pins = <40 41 42>;
++ brcm,function = <3>; /* alt4 */
++ status = "okay";
++ };
++ };
++};
--- /dev/null
+From 0e8ed7a892a510383017cdddee7b772473f1f7c8 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Sep 2018 11:50:25 +0100
+Subject: [PATCH] config: Permit LPAE and PCIE_BRCMSTB on BCM2835
+
+---
+ arch/arm/mach-bcm/Kconfig | 4 ++++
+ drivers/pci/controller/Kconfig | 4 ++--
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/mach-bcm/Kconfig
++++ b/arch/arm/mach-bcm/Kconfig
+@@ -161,6 +161,7 @@ config ARCH_BCM2835
+ select GPIOLIB
+ select ARM_AMBA
+ select ARM_ERRATA_411920 if ARCH_MULTI_V6
++ select ARM_GIC
+ select ARM_TIMER_SP804
+ select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
+ select TIMER_OF
+@@ -169,6 +170,9 @@ config ARCH_BCM2835
+ select PINCTRL
+ select PINCTRL_BCM2835
+ select MFD_SYSCON if ARCH_MULTI_V7
++ select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
++ select ZONE_DMA if ARM_LPAE
++ select MFD_CORE
+ help
+ This enables support for the Broadcom BCM2835 and BCM2836 SoCs.
+ This SoC is used in the Raspberry Pi and Roku 2 devices.
+--- a/drivers/pci/controller/Kconfig
++++ b/drivers/pci/controller/Kconfig
+@@ -280,9 +280,9 @@ config VMD
+
+ config PCIE_BRCMSTB
+ tristate "Broadcom Brcmstb PCIe platform host driver"
+- depends on ARCH_BRCMSTB || BMIPS_GENERIC
++ depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM2835
+ depends on OF
+- depends on SOC_BRCMSTB
++ depends on SOC_BRCMSTB || ARCH_BCM2835
+ default ARCH_BRCMSTB || BMIPS_GENERIC
+ help
+ Adds support for Broadcom Settop Box PCIe host controller.
+++ /dev/null
-From a4ea446a07d7ba010c3c32286a22dc89cffa1e54 Mon Sep 17 00:00:00 2001
-Date: Sun, 12 May 2019 16:17:08 +0000
-Subject: [PATCH] spi: devicetree: add overlays for spi 3 to 6
-
----
- arch/arm/boot/dts/overlays/Makefile | 8 ++
- arch/arm/boot/dts/overlays/README | 104 ++++++++++++++++++
- .../boot/dts/overlays/spi3-1cs-overlay.dts | 44 ++++++++
- .../boot/dts/overlays/spi3-2cs-overlay.dts | 56 ++++++++++
- .../boot/dts/overlays/spi4-1cs-overlay.dts | 44 ++++++++
- .../boot/dts/overlays/spi4-2cs-overlay.dts | 56 ++++++++++
- .../boot/dts/overlays/spi5-1cs-overlay.dts | 44 ++++++++
- .../boot/dts/overlays/spi5-2cs-overlay.dts | 56 ++++++++++
- .../boot/dts/overlays/spi6-1cs-overlay.dts | 44 ++++++++
- .../boot/dts/overlays/spi6-2cs-overlay.dts | 56 ++++++++++
- 10 files changed, 512 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -144,6 +144,14 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- spi2-1cs.dtbo \
- spi2-2cs.dtbo \
- spi2-3cs.dtbo \
-+ spi3-1cs.dtbo \
-+ spi3-2cs.dtbo \
-+ spi4-1cs.dtbo \
-+ spi4-2cs.dtbo \
-+ spi5-1cs.dtbo \
-+ spi5-2cs.dtbo \
-+ spi6-1cs.dtbo \
-+ spi6-2cs.dtbo \
- ssd1306.dtbo \
- superaudioboard.dtbo \
- sx150x.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -2085,6 +2085,110 @@ Params: cs0_pin GPIO pin
- is 'okay' or enabled).
-
-
-+Name: spi3-1cs
-+Info: Enables spi3 with a single chip select (CS) line and associated spidev
-+ dev node. The gpio pin number for the CS line and spidev device node
-+ creation are configurable.
-+Load: dtoverlay=spi3-1cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 0 - BCM SPI3_CE0).
-+ cs0_spidev Set to 'off' to prevent the creation of a
-+ userspace device node /dev/spidev3.0 (default
-+ is 'on' or enabled).
-+
-+
-+Name: spi3-2cs
-+Info: Enables spi3 with two chip select (CS) lines and associated spidev
-+ dev nodes. The gpio pin numbers for the CS lines and spidev device node
-+ creation are configurable.
-+Load: dtoverlay=spi3-2cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 0 - BCM SPI3_CE0).
-+ cs1_pin GPIO pin for CS1 (default 24 - BCM SPI3_CE1).
-+ cs0_spidev Set to 'off' to prevent the creation of a
-+ userspace device node /dev/spidev3.0 (default
-+ is 'on' or enabled).
-+ cs1_spidev Set to 'off' to prevent the creation of a
-+ userspace device node /dev/spidev3.1 (default
-+ is 'on' or enabled).
-+
-+
-+Name: spi4-1cs
-+Info: Enables spi4 with a single chip select (CS) line and associated spidev
-+ dev node. The gpio pin number for the CS line and spidev device node
-+ creation are configurable.
-+Load: dtoverlay=spi4-1cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 4 - BCM SPI4_CE0).
-+ cs0_spidev Set to 'off' to prevent the creation of a
-+ userspace device node /dev/spidev4.0 (default
-+ is 'on' or enabled).
-+
-+
-+Name: spi4-2cs
-+Info: Enables spi4 with two chip select (CS) lines and associated spidev
-+ dev nodes. The gpio pin numbers for the CS lines and spidev device node
-+ creation are configurable.
-+Load: dtoverlay=spi4-2cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 4 - BCM SPI4_CE0).
-+ cs1_pin GPIO pin for CS1 (default 25 - BCM SPI4_CE1).
-+ cs0_spidev Set to 'off' to prevent the creation of a
-+ userspace device node /dev/spidev4.0 (default
-+ is 'on' or enabled).
-+ cs1_spidev Set to 'off' to prevent the creation of a
-+ userspace device node /dev/spidev4.1 (default
-+ is 'on' or enabled).
-+
-+
-+Name: spi5-1cs
-+Info: Enables spi5 with a single chip select (CS) line and associated spidev
-+ dev node. The gpio pin numbers for the CS lines and spidev device node
-+ creation are configurable.
-+Load: dtoverlay=spi5-1cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 12 - BCM SPI5_CE0).
-+ cs0_spidev Set to 'off' to prevent the creation of a
-+ userspace device node /dev/spidev5.0 (default
-+ is 'on' or enabled).
-+
-+
-+Name: spi5-2cs
-+Info: Enables spi5 with two chip select (CS) lines and associated spidev
-+ dev nodes. The gpio pin numbers for the CS lines and spidev device node
-+ creation are configurable.
-+Load: dtoverlay=spi5-2cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 12 - BCM SPI5_CE0).
-+ cs1_pin GPIO pin for CS1 (default 26 - BCM SPI5_CE1).
-+ cs0_spidev Set to 'off' to prevent the creation of a
-+ userspace device node /dev/spidev5.0 (default
-+ is 'on' or enabled).
-+ cs1_spidev Set to 'off' to prevent the creation of a
-+ userspace device node /dev/spidev5.1 (default
-+ is 'on' or enabled).
-+
-+
-+Name: spi6-1cs
-+Info: Enables spi6 with a single chip select (CS) line and associated spidev
-+ dev node. The gpio pin number for the CS line and spidev device node
-+ creation are configurable.
-+Load: dtoverlay=spi6-1cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI6_CE0).
-+ cs0_spidev Set to 'off' to prevent the creation of a
-+ userspace device node /dev/spidev6.0 (default
-+ is 'on' or enabled).
-+
-+
-+Name: spi6-2cs
-+Info: Enables spi6 with two chip select (CS) lines and associated spidev
-+ dev nodes. The gpio pin numbers for the CS lines and spidev device node
-+ creation are configurable.
-+Load: dtoverlay=spi6-2cs,<param>=<val>
-+Params: cs0_pin GPIO pin for CS0 (default 18 - BCM SPI6_CE0).
-+ cs1_pin GPIO pin for CS1 (default 27 - BCM SPI6_CE1).
-+ cs0_spidev Set to 'off' to prevent the creation of a
-+ userspace device node /dev/spidev6.0 (default
-+ is 'on' or enabled).
-+ cs1_spidev Set to 'off' to prevent the creation of a
-+ userspace device node /dev/spidev6.1 (default
-+ is 'on' or enabled).
-+
-+
- Name: ssd1306
- Info: Overlay for activation of SSD1306 over I2C OLED display framebuffer.
- Load: dtoverlay=ssd1306,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts
-@@ -0,0 +1,44 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&spi3_cs_pins>;
-+ frag0: __overlay__ {
-+ brcm,pins = <0>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi3>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi3_pins &spi3_cs_pins>;
-+ cs-gpios = <&gpio 0 1>;
-+ status = "okay";
-+
-+ spidev3_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&frag0>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs0_spidev = <&spidev3_0>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts
-@@ -0,0 +1,56 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&spi3_cs_pins>;
-+ frag0: __overlay__ {
-+ brcm,pins = <0 24>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi3>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi3_pins &spi3_cs_pins>;
-+ cs-gpios = <&gpio 0 1>, <&gpio 24 1>;
-+ status = "okay";
-+
-+ spidev3_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ status = "okay";
-+ };
-+
-+ spidev3_1: spidev@1 {
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&frag0>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs1_pin = <&frag0>,"brcm,pins:4",
-+ <&frag1>,"cs-gpios:16";
-+ cs0_spidev = <&spidev3_0>,"status";
-+ cs1_spidev = <&spidev3_1>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts
-@@ -0,0 +1,44 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&spi4_cs_pins>;
-+ frag0: __overlay__ {
-+ brcm,pins = <4>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi4>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi4_pins &spi4_cs_pins>;
-+ cs-gpios = <&gpio 4 1>;
-+ status = "okay";
-+
-+ spidev4_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&frag0>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs0_spidev = <&spidev4_0>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts
-@@ -0,0 +1,56 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&spi4_cs_pins>;
-+ frag0: __overlay__ {
-+ brcm,pins = <4 25>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi4>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi4_pins &spi4_cs_pins>;
-+ cs-gpios = <&gpio 4 1>, <&gpio 25 1>;
-+ status = "okay";
-+
-+ spidev4_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ status = "okay";
-+ };
-+
-+ spidev4_1: spidev@1 {
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&frag0>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs1_pin = <&frag0>,"brcm,pins:4",
-+ <&frag1>,"cs-gpios:16";
-+ cs0_spidev = <&spidev4_0>,"status";
-+ cs1_spidev = <&spidev4_1>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts
-@@ -0,0 +1,44 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&spi5_cs_pins>;
-+ frag0: __overlay__ {
-+ brcm,pins = <12>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi5>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi5_pins &spi5_cs_pins>;
-+ cs-gpios = <&gpio 12 1>;
-+ status = "okay";
-+
-+ spidev5_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&frag0>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs0_spidev = <&spidev5_0>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts
-@@ -0,0 +1,56 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&spi5_cs_pins>;
-+ frag0: __overlay__ {
-+ brcm,pins = <12 26>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi5>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi5_pins &spi5_cs_pins>;
-+ cs-gpios = <&gpio 12 1>, <&gpio 26 1>;
-+ status = "okay";
-+
-+ spidev5_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ status = "okay";
-+ };
-+
-+ spidev5_1: spidev@1 {
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&frag0>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs1_pin = <&frag0>,"brcm,pins:4",
-+ <&frag1>,"cs-gpios:16";
-+ cs0_spidev = <&spidev5_0>,"status";
-+ cs1_spidev = <&spidev5_1>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts
-@@ -0,0 +1,44 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&spi6_cs_pins>;
-+ frag0: __overlay__ {
-+ brcm,pins = <18>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi6>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi6_pins &spi6_cs_pins>;
-+ cs-gpios = <&gpio 18 1>;
-+ status = "okay";
-+
-+ spidev6_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&frag0>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs0_spidev = <&spidev6_0>,"status";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts
-@@ -0,0 +1,56 @@
-+/dts-v1/;
-+/plugin/;
-+
-+
-+/ {
-+ compatible = "brcm,bcm2838";
-+
-+ fragment@0 {
-+ target = <&spi6_cs_pins>;
-+ frag0: __overlay__ {
-+ brcm,pins = <18 27>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi6>;
-+ frag1: __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi6_pins &spi6_cs_pins>;
-+ cs-gpios = <&gpio 18 1>, <&gpio 27 1>;
-+ status = "okay";
-+
-+ spidev6_0: spidev@0 {
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ status = "okay";
-+ };
-+
-+ spidev6_1: spidev@1 {
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ cs0_pin = <&frag0>,"brcm,pins:0",
-+ <&frag1>,"cs-gpios:4";
-+ cs1_pin = <&frag0>,"brcm,pins:4",
-+ <&frag1>,"cs-gpios:16";
-+ cs0_spidev = <&spidev6_0>,"status";
-+ cs1_spidev = <&spidev6_1>,"status";
-+ };
-+};
--- /dev/null
+From 0e7db01b8ce2c2fb5596e7a9b7104e9947e5c269 Mon Sep 17 00:00:00 2001
+Date: Fri, 8 Mar 2019 21:12:39 +0000
+Subject: [PATCH] 2711: Add basic 64-bit support
+
+This commit adds initial support for 64-bit 2711 builds. However,
+it will only work as much as it does if the Pi4 RAM is limited to
+1GB - more than that and several things break (SD card, coherent
+allocations, etc.)
+
+---
+ arch/arm64/boot/dts/broadcom/Makefile | 1 +
+ .../boot/dts/broadcom/bcm2711-rpi-4-b.dts | 3 +
+ 3 files changed, 1295 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts
+
+--- a/arch/arm64/boot/dts/broadcom/Makefile
++++ b/arch/arm64/boot/dts/broadcom/Makefile
+@@ -3,6 +3,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rp
+ bcm2837-rpi-3-b-plus.dtb
+ dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-3-b.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b.dtb
++dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-4-b.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b-plus.dtb
+ dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-cm3.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-cm3.dtb
+--- /dev/null
++++ b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts
+@@ -0,0 +1,3 @@
++#define RPI364
++
++#include "../../../../arm/boot/dts/bcm2711-rpi-4-b.dts"
+++ /dev/null
-From 726da40b8c272d181a41686195f91b914363167b Mon Sep 17 00:00:00 2001
-Date: Tue, 22 Jan 2019 10:49:41 +0000
-Subject: [PATCH] overlays: Add the spi-gpio40-45 overlay
-
-The 2711 B0 boot EEPROM is programmed via SPI0 on GPIO
-pins 40-43 CS0. Add a device tree overlay to optionally
-change the SPI0 pinmux from the external GPIO pins to
-the boot EEPROM pins.
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 6 ++++
- .../dts/overlays/spi-gpio40-45-overlay.dts | 36 +++++++++++++++++++
- 3 files changed, 43 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/spi-gpio40-45-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -135,6 +135,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- smi-dev.dtbo \
- smi-nand.dtbo \
- spi-gpio35-39.dtbo \
-+ spi-gpio40-45.dtbo \
- spi-rtc.dtbo \
- spi0-cs.dtbo \
- spi0-hw-cs.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1967,6 +1967,12 @@ Load: dtoverlay=spi-gpio35-39
- Params: <None>
-
-
-+Name: spi-gpio40-45
-+Info: Move SPI function block to GPIOs 40 to 45
-+Load: dtoverlay=spi-gpio40-45
-+Params: <None>
-+
-+
- Name: spi-rtc
- Info: Adds support for a number of SPI Real Time Clock devices
- Load: dtoverlay=spi-rtc,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/spi-gpio40-45-overlay.dts
-@@ -0,0 +1,36 @@
-+/*
-+ * Boot EEPROM overlay
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ cs-gpios = <&gpio 43 1>, <&gpio 44 1>, <&gpio 45 1>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spi0_cs_pins>;
-+ __overlay__ {
-+ brcm,pins = <45 44 43>;
-+ brcm,function = <1>; /* output */
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0_pins>;
-+ __overlay__ {
-+ brcm,pins = <40 41 42>;
-+ brcm,function = <3>; /* alt4 */
-+ status = "okay";
-+ };
-+ };
-+};
--- /dev/null
+From 91aa97cc3a193cfd29962e328f9d1da0d8e0aaff Mon Sep 17 00:00:00 2001
+Date: Wed, 30 Jan 2019 14:22:03 +0000
+Subject: [PATCH] ARM: dts: bcm283x: Correct vchiq compatible string
+ (#2840)
+
+commit 499770ede3f829e80539f46b59b5f460dc327aa6 upstream.
+
+To allow VCHIQ to determine the correct cache line size, use the new
+"brcm,bcm2836-vchiq" compatible string on BCM2836 and BCM2837.
+
+---
+ arch/arm/boot/dts/bcm2835-rpi.dtsi | 2 +-
+ arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 2 +-
+ arch/arm/boot/dts/bcm2836-rpi.dtsi | 6 ++++++
+ arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts | 2 +-
+ arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 2 +-
+ 5 files changed, 10 insertions(+), 4 deletions(-)
+ create mode 100644 arch/arm/boot/dts/bcm2836-rpi.dtsi
+
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -30,7 +30,7 @@
+ #power-domain-cells = <1>;
+ };
+
+- mailbox@7e00b840 {
++ vchiq: mailbox@7e00b840 {
+ compatible = "brcm,bcm2835-vchiq";
+ reg = <0x7e00b840 0x3c>;
+ interrupts = <0 2>;
+--- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
++++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /dts-v1/;
+ #include "bcm2836.dtsi"
+-#include "bcm2835-rpi.dtsi"
++#include "bcm2836-rpi.dtsi"
+ #include "bcm283x-rpi-smsc9514.dtsi"
+ #include "bcm283x-rpi-usb-host.dtsi"
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2836-rpi.dtsi
+@@ -0,0 +1,6 @@
++// SPDX-License-Identifier: GPL-2.0
++#include "bcm2835-rpi.dtsi"
++
++&vchiq {
++ compatible = "brcm,bcm2836-vchiq", "brcm,bcm2835-vchiq";
++};
+--- a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /dts-v1/;
+ #include "bcm2837.dtsi"
+-#include "bcm2835-rpi.dtsi"
++#include "bcm2836-rpi.dtsi"
+ #include "bcm283x-rpi-lan7515.dtsi"
+ #include "bcm283x-rpi-usb-host.dtsi"
+
+--- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /dts-v1/;
+ #include "bcm2837.dtsi"
+-#include "bcm2835-rpi.dtsi"
++#include "bcm2836-rpi.dtsi"
+ #include "bcm283x-rpi-smsc9514.dtsi"
+ #include "bcm283x-rpi-usb-host.dtsi"
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+++ /dev/null
-From 0e8ed7a892a510383017cdddee7b772473f1f7c8 Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Sep 2018 11:50:25 +0100
-Subject: [PATCH] config: Permit LPAE and PCIE_BRCMSTB on BCM2835
-
----
- arch/arm/mach-bcm/Kconfig | 4 ++++
- drivers/pci/controller/Kconfig | 4 ++--
- 2 files changed, 6 insertions(+), 2 deletions(-)
-
---- a/arch/arm/mach-bcm/Kconfig
-+++ b/arch/arm/mach-bcm/Kconfig
-@@ -161,6 +161,7 @@ config ARCH_BCM2835
- select GPIOLIB
- select ARM_AMBA
- select ARM_ERRATA_411920 if ARCH_MULTI_V6
-+ select ARM_GIC
- select ARM_TIMER_SP804
- select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
- select TIMER_OF
-@@ -169,6 +170,9 @@ config ARCH_BCM2835
- select PINCTRL
- select PINCTRL_BCM2835
- select MFD_SYSCON if ARCH_MULTI_V7
-+ select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
-+ select ZONE_DMA if ARM_LPAE
-+ select MFD_CORE
- help
- This enables support for the Broadcom BCM2835 and BCM2836 SoCs.
- This SoC is used in the Raspberry Pi and Roku 2 devices.
---- a/drivers/pci/controller/Kconfig
-+++ b/drivers/pci/controller/Kconfig
-@@ -280,9 +280,9 @@ config VMD
-
- config PCIE_BRCMSTB
- tristate "Broadcom Brcmstb PCIe platform host driver"
-- depends on ARCH_BRCMSTB || BMIPS_GENERIC
-+ depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM2835
- depends on OF
-- depends on SOC_BRCMSTB
-+ depends on SOC_BRCMSTB || ARCH_BCM2835
- default ARCH_BRCMSTB || BMIPS_GENERIC
- help
- Adds support for Broadcom Settop Box PCIe host controller.
+++ /dev/null
-From 0e7db01b8ce2c2fb5596e7a9b7104e9947e5c269 Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Mar 2019 21:12:39 +0000
-Subject: [PATCH] 2711: Add basic 64-bit support
-
-This commit adds initial support for 64-bit 2711 builds. However,
-it will only work as much as it does if the Pi4 RAM is limited to
-1GB - more than that and several things break (SD card, coherent
-allocations, etc.)
-
----
- arch/arm64/boot/dts/broadcom/Makefile | 1 +
- .../boot/dts/broadcom/bcm2711-rpi-4-b.dts | 3 +
- 3 files changed, 1295 insertions(+)
- create mode 100644 arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts
-
---- a/arch/arm64/boot/dts/broadcom/Makefile
-+++ b/arch/arm64/boot/dts/broadcom/Makefile
-@@ -3,6 +3,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rp
- bcm2837-rpi-3-b-plus.dtb
- dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-3-b.dtb
- dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b.dtb
-+dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-4-b.dtb
- dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b-plus.dtb
- dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-cm3.dtb
- dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-cm3.dtb
---- /dev/null
-+++ b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts
-@@ -0,0 +1,3 @@
-+#define RPI364
-+
-+#include "../../../../arm/boot/dts/bcm2711-rpi-4-b.dts"
--- /dev/null
+From 00d8817ab207a9f60e94e87acf4f170155aecd48 Mon Sep 17 00:00:00 2001
+Date: Wed, 6 Feb 2019 20:45:16 +0000
+Subject: [PATCH] arm: dts: Change downstream vchiq compatible string
+
+The new cache line size mechanism requires a different vchiq compatible
+string on BCM2836 and BCM2837, but the downstream dts files didn't
+inherit the upstream changes.
+
+See: https://github.com/raspberrypi/linux/issues/2643
+
+---
+ arch/arm/boot/dts/bcm2708-rpi.dtsi | 2 +-
+ arch/arm/boot/dts/bcm2709-rpi.dtsi | 5 +++++
+ arch/arm/boot/dts/bcm2709.dtsi | 2 +-
+ arch/arm/boot/dts/bcm2710.dtsi | 2 +-
+ 4 files changed, 8 insertions(+), 3 deletions(-)
+ create mode 100644 arch/arm/boot/dts/bcm2709-rpi.dtsi
+
+--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
+@@ -68,7 +68,7 @@
+ status = "disabled";
+ };
+
+- mailbox@7e00b840 {
++ vchiq: mailbox@7e00b840 {
+ compatible = "brcm,bcm2835-vchiq";
+ reg = <0x7e00b840 0x3c>;
+ interrupts = <0 2>;
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2709-rpi.dtsi
+@@ -0,0 +1,5 @@
++#include "bcm2708-rpi.dtsi"
++
++&vchiq {
++ compatible = "brcm,bcm2836-vchiq", "brcm,bcm2835-vchiq";
++};
+--- a/arch/arm/boot/dts/bcm2709.dtsi
++++ b/arch/arm/boot/dts/bcm2709.dtsi
+@@ -1,6 +1,6 @@
+ #include "bcm2836.dtsi"
+ #include "bcm270x.dtsi"
+-#include "bcm2708-rpi.dtsi"
++#include "bcm2709-rpi.dtsi"
+
+ / {
+ soc {
+--- a/arch/arm/boot/dts/bcm2710.dtsi
++++ b/arch/arm/boot/dts/bcm2710.dtsi
+@@ -1,6 +1,6 @@
+ #include "bcm2837.dtsi"
+ #include "bcm270x.dtsi"
+-#include "bcm2708-rpi.dtsi"
++#include "bcm2709-rpi.dtsi"
+
+ / {
+ compatible = "brcm,bcm2837", "brcm,bcm2836";
+++ /dev/null
-From 91aa97cc3a193cfd29962e328f9d1da0d8e0aaff Mon Sep 17 00:00:00 2001
-Date: Wed, 30 Jan 2019 14:22:03 +0000
-Subject: [PATCH] ARM: dts: bcm283x: Correct vchiq compatible string
- (#2840)
-
-commit 499770ede3f829e80539f46b59b5f460dc327aa6 upstream.
-
-To allow VCHIQ to determine the correct cache line size, use the new
-"brcm,bcm2836-vchiq" compatible string on BCM2836 and BCM2837.
-
----
- arch/arm/boot/dts/bcm2835-rpi.dtsi | 2 +-
- arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 2 +-
- arch/arm/boot/dts/bcm2836-rpi.dtsi | 6 ++++++
- arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts | 2 +-
- arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 2 +-
- 5 files changed, 10 insertions(+), 4 deletions(-)
- create mode 100644 arch/arm/boot/dts/bcm2836-rpi.dtsi
-
---- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
-@@ -30,7 +30,7 @@
- #power-domain-cells = <1>;
- };
-
-- mailbox@7e00b840 {
-+ vchiq: mailbox@7e00b840 {
- compatible = "brcm,bcm2835-vchiq";
- reg = <0x7e00b840 0x3c>;
- interrupts = <0 2>;
---- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-+++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-@@ -1,7 +1,7 @@
- // SPDX-License-Identifier: GPL-2.0
- /dts-v1/;
- #include "bcm2836.dtsi"
--#include "bcm2835-rpi.dtsi"
-+#include "bcm2836-rpi.dtsi"
- #include "bcm283x-rpi-smsc9514.dtsi"
- #include "bcm283x-rpi-usb-host.dtsi"
- #include "bcm283x-rpi-csi1-2lane.dtsi"
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2836-rpi.dtsi
-@@ -0,0 +1,6 @@
-+// SPDX-License-Identifier: GPL-2.0
-+#include "bcm2835-rpi.dtsi"
-+
-+&vchiq {
-+ compatible = "brcm,bcm2836-vchiq", "brcm,bcm2835-vchiq";
-+};
---- a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
-@@ -1,7 +1,7 @@
- // SPDX-License-Identifier: GPL-2.0
- /dts-v1/;
- #include "bcm2837.dtsi"
--#include "bcm2835-rpi.dtsi"
-+#include "bcm2836-rpi.dtsi"
- #include "bcm283x-rpi-lan7515.dtsi"
- #include "bcm283x-rpi-usb-host.dtsi"
-
---- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
-+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
-@@ -1,7 +1,7 @@
- // SPDX-License-Identifier: GPL-2.0
- /dts-v1/;
- #include "bcm2837.dtsi"
--#include "bcm2835-rpi.dtsi"
-+#include "bcm2836-rpi.dtsi"
- #include "bcm283x-rpi-smsc9514.dtsi"
- #include "bcm283x-rpi-usb-host.dtsi"
- #include "bcm283x-rpi-csi1-2lane.dtsi"
--- /dev/null
+From 621fb1606217c3e72feda69255ae6cb6a7ccfec2 Mon Sep 17 00:00:00 2001
+Date: Thu, 4 Apr 2019 13:33:47 +0100
+Subject: [PATCH] bcm2835-dma: Add proper 40-bit DMA support
+
+The 40-bit additions are not fully tested, but it should be
+capable of supporting both 40-bit memcpy on BCM2711 and regular
+Lite channels on BCM2835.
+
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 33 +-
+ drivers/dma/bcm2835-dma.c | 426 ++++++++++++++-----
+ drivers/pci/controller/pcie-brcmstb-bounce.c | 30 +-
+ drivers/pci/controller/pcie-brcmstb-bounce.h | 21 +-
+ drivers/pci/controller/pcie-brcmstb.c | 23 +-
+ 5 files changed, 395 insertions(+), 138 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -372,6 +372,23 @@
+ };
+ };
+
++ dma40: dma@7e007b00 {
++ compatible = "brcm,bcm2838-dma";
++ reg = <0x0 0x7e007b00 0x400>;
++ interrupts =
++ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
++ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 12 */
++ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, /* dma4 13 */
++ <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; /* dma4 14 */
++ interrupt-names = "dma11",
++ "dma12",
++ "dma13",
++ "dma14";
++ #dma-cells = <1>;
++ brcm,dma-channel-mask = <0x7000>;
++ };
++ /* DMA4 - 40 bit DMA engines */
++
+ xhci: xhci@7e9c0000 {
+ compatible = "generic-xhci";
+ status = "disabled";
+@@ -689,6 +706,7 @@
+ };
+
+ &dma {
++ reg = <0x7e007000 0xb00>;
+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+@@ -699,12 +717,7 @@
+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 7 */
+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 8 */
+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 9 */
+- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 10 */
+- /* DMA4 - 40 bit DMA engines */
+- <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
+- <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 12 */
+- <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, /* dma4 13 */
+- <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; /* dma4 14 */
++ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>; /* dmalite 10 */
+ interrupt-names = "dma0",
+ "dma1",
+ "dma2",
+@@ -715,10 +728,6 @@
+ "dma7",
+ "dma8",
+ "dma9",
+- "dma10",
+- "dma11",
+- "dma12",
+- "dma13",
+- "dma14";
+- brcm,dma-channel-mask = <0x7ef5>;
++ "dma10";
++ brcm,dma-channel-mask = <0x01f5>;
+ };
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -50,12 +50,18 @@
+ #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
+ #define BCM2835_DMA_CHAN_NAME_SIZE 8
+ #define BCM2835_DMA_BULK_MASK BIT(0)
++#define BCM2838_DMA_MEMCPY_CHAN 14
++
++struct bcm2835_dma_cfg_data {
++ u32 chan_40bit_mask;
++};
+
+ struct bcm2835_dmadev {
+ struct dma_device ddev;
+ spinlock_t lock;
+ void __iomem *base;
+ struct device_dma_parameters dma_parms;
++ const struct bcm2835_dma_cfg_data *cfg_data;
+ };
+
+ struct bcm2835_dma_cb {
+@@ -100,6 +106,7 @@ struct bcm2835_chan {
+ unsigned int irq_flags;
+
+ bool is_lite_channel;
++ bool is_40bit_channel;
+ };
+
+ struct bcm2835_desc {
+@@ -189,7 +196,8 @@ struct bcm2835_desc {
+ #define BCM2835_DMA_DATA_TYPE_S128 16
+
+ /* Valid only for channels 0 - 14, 15 has its own base address */
+-#define BCM2835_DMA_CHAN(n) ((n) << 8) /* Base address */
++#define BCM2835_DMA_CHAN_SIZE 0x100
++#define BCM2835_DMA_CHAN(n) ((n) * BCM2835_DMA_CHAN_SIZE) /* Base address */
+ #define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n))
+
+ /* the max dma length for different channels */
+@@ -200,7 +208,7 @@ struct bcm2835_desc {
+ #define BCM2838_DMA40_CS 0x00
+ #define BCM2838_DMA40_CB 0x04
+ #define BCM2838_DMA40_DEBUG 0x0c
+-#define BCM2858_DMA40_TI 0x10
++#define BCM2838_DMA40_TI 0x10
+ #define BCM2838_DMA40_SRC 0x14
+ #define BCM2838_DMA40_SRCI 0x18
+ #define BCM2838_DMA40_DEST 0x1c
+@@ -209,32 +217,97 @@ struct bcm2835_desc {
+ #define BCM2838_DMA40_NEXT_CB 0x28
+ #define BCM2838_DMA40_DEBUG2 0x2c
+
+-#define BCM2838_DMA40_CS_ACTIVE BIT(0)
+-#define BCM2838_DMA40_CS_END BIT(1)
++#define BCM2838_DMA40_ACTIVE BIT(0)
++#define BCM2838_DMA40_END BIT(1)
++#define BCM2838_DMA40_INT BIT(2)
++#define BCM2838_DMA40_DREQ BIT(3) /* DREQ state */
++#define BCM2838_DMA40_RD_PAUSED BIT(4) /* Reading is paused */
++#define BCM2838_DMA40_WR_PAUSED BIT(5) /* Writing is paused */
++#define BCM2838_DMA40_DREQ_PAUSED BIT(6) /* Is paused by DREQ flow control */
++#define BCM2838_DMA40_WAITING_FOR_WRITES BIT(7) /* Waiting for last write */
++#define BCM2838_DMA40_ERR BIT(10)
++#define BCM2838_DMA40_QOS(x) (((x) & 0x1f) << 16)
++#define BCM2838_DMA40_PANIC_QOS(x) (((x) & 0x1f) << 20)
++#define BCM2838_DMA40_WAIT_FOR_WRITES BIT(28)
++#define BCM2838_DMA40_DISDEBUG BIT(29)
++#define BCM2838_DMA40_ABORT BIT(30)
++#define BCM2838_DMA40_HALT BIT(31)
++#define BCM2838_DMA40_CS_FLAGS(x) (x & (BCM2838_DMA40_QOS(15) | \
++ BCM2838_DMA40_PANIC_QOS(15) | \
++ BCM2838_DMA40_WAIT_FOR_WRITES | \
++ BCM2838_DMA40_DISDEBUG))
++
++/* Transfer information bits */
++#define BCM2838_DMA40_INTEN BIT(0)
++#define BCM2838_DMA40_TDMODE BIT(1) /* 2D-Mode */
++#define BCM2838_DMA40_WAIT_RESP BIT(2) /* wait for AXI write to be acked */
++#define BCM2838_DMA40_WAIT_RD_RESP BIT(3) /* wait for AXI read to complete */
++#define BCM2838_DMA40_PER_MAP(x) ((x & 31) << 9) /* REQ source */
++#define BCM2838_DMA40_S_DREQ BIT(14) /* enable SREQ for source */
++#define BCM2838_DMA40_D_DREQ BIT(15) /* enable DREQ for destination */
++#define BCM2838_DMA40_S_WAIT(x) ((x & 0xff) << 16) /* add DMA read-wait cycles */
++#define BCM2838_DMA40_D_WAIT(x) ((x & 0xff) << 24) /* add DMA write-wait cycles */
+
+-#define BCM2838_DMA40_CS_QOS(x) (((x) & 0x1f) << 16)
+-#define BCM2838_DMA40_CS_PANIC_QOS(x) (((x) & 0x1f) << 20)
+-#define BCM2838_DMA40_CS_WRITE_WAIT BIT(28)
++/* debug register bits */
++#define BCM2838_DMA40_DEBUG_WRITE_ERR BIT(0)
++#define BCM2838_DMA40_DEBUG_FIFO_ERR BIT(1)
++#define BCM2838_DMA40_DEBUG_READ_ERR BIT(2)
++#define BCM2838_DMA40_DEBUG_READ_CB_ERR BIT(3)
++#define BCM2838_DMA40_DEBUG_IN_ON_ERR BIT(8)
++#define BCM2838_DMA40_DEBUG_ABORT_ON_ERR BIT(9)
++#define BCM2838_DMA40_DEBUG_HALT_ON_ERR BIT(10)
++#define BCM2838_DMA40_DEBUG_DISABLE_CLK_GATE BIT(11)
++#define BCM2838_DMA40_DEBUG_RSTATE_SHIFT 14
++#define BCM2838_DMA40_DEBUG_RSTATE_BITS 4
++#define BCM2838_DMA40_DEBUG_WSTATE_SHIFT 18
++#define BCM2838_DMA40_DEBUG_WSTATE_BITS 4
++#define BCM2838_DMA40_DEBUG_RESET BIT(23)
++#define BCM2838_DMA40_DEBUG_ID_SHIFT 24
++#define BCM2838_DMA40_DEBUG_ID_BITS 4
++#define BCM2838_DMA40_DEBUG_VERSION_SHIFT 28
++#define BCM2838_DMA40_DEBUG_VERSION_BITS 4
++
++/* Valid only for channels 0 - 3 (11 - 14) */
++#define BCM2838_DMA40_CHAN(n) (((n) + 11) << 8) /* Base address */
++#define BCM2838_DMA40_CHANIO(base, n) ((base) + BCM2838_DMA_CHAN(n))
+
+-#define BCM2838_DMA40_BURST_LEN(x) ((((x) - 1) & 0xf) << 8)
+-#define BCM2838_DMA40_INC BIT(12)
+-#define BCM2838_DMA40_SIZE_128 (2 << 13)
++/* the max dma length for different channels */
++#define MAX_DMA40_LEN SZ_1G
+
+-#define BCM2838_DMA40_MEMCPY_QOS \
+- (BCM2838_DMA40_CS_QOS(0x0) | \
+- BCM2838_DMA40_CS_PANIC_QOS(0x0) | \
+- BCM2838_DMA40_CS_WRITE_WAIT)
++#define BCM2838_DMA40_BURST_LEN(x) ((min(x,16) - 1) << 8)
++#define BCM2838_DMA40_INC BIT(12)
++#define BCM2838_DMA40_SIZE_32 (0 << 13)
++#define BCM2838_DMA40_SIZE_64 (1 << 13)
++#define BCM2838_DMA40_SIZE_128 (2 << 13)
++#define BCM2838_DMA40_SIZE_256 (3 << 13)
++#define BCM2838_DMA40_IGNORE BIT(15)
++#define BCM2838_DMA40_STRIDE(x) ((x) << 16) /* For 2D mode */
++
++#define BCM2838_DMA40_MEMCPY_FLAGS \
++ (BCM2838_DMA40_QOS(0) | \
++ BCM2838_DMA40_PANIC_QOS(0) | \
++ BCM2838_DMA40_WAIT_FOR_WRITES | \
++ BCM2838_DMA40_DISDEBUG)
+
+ #define BCM2838_DMA40_MEMCPY_XFER_INFO \
+ (BCM2838_DMA40_SIZE_128 | \
+ BCM2838_DMA40_INC | \
+ BCM2838_DMA40_BURST_LEN(16))
+
++struct bcm2835_dmadev *memcpy_parent;
+ static void __iomem *memcpy_chan;
+ static struct bcm2838_dma40_scb *memcpy_scb;
+ static dma_addr_t memcpy_scb_dma;
+ DEFINE_SPINLOCK(memcpy_lock);
+
++static const struct bcm2835_dma_cfg_data bcm2835_dma_cfg = {
++ .chan_40bit_mask = 0,
++};
++
++static const struct bcm2835_dma_cfg_data bcm2838_dma_cfg = {
++ .chan_40bit_mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
++};
++
+ static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
+ {
+ /* lite and normal channels have different max frame length */
+@@ -264,6 +337,32 @@ static inline struct bcm2835_desc *to_bc
+ return container_of(t, struct bcm2835_desc, vd.tx);
+ }
+
++static inline uint32_t to_bcm2838_ti(uint32_t info)
++{
++ return ((info & BCM2835_DMA_INT_EN) ? BCM2838_DMA40_INTEN : 0) |
++ ((info & BCM2835_DMA_WAIT_RESP) ? BCM2838_DMA40_WAIT_RESP : 0) |
++ ((info & BCM2835_DMA_S_DREQ) ?
++ (BCM2838_DMA40_S_DREQ | BCM2838_DMA40_WAIT_RD_RESP) : 0) |
++ ((info & BCM2835_DMA_D_DREQ) ? BCM2838_DMA40_D_DREQ : 0) |
++ BCM2838_DMA40_PER_MAP((info >> 16) & 0x1f);
++}
++
++static inline uint32_t to_bcm2838_srci(uint32_t info)
++{
++ return ((info & BCM2835_DMA_S_INC) ? BCM2838_DMA40_INC : 0);
++}
++
++static inline uint32_t to_bcm2838_dsti(uint32_t info)
++{
++ return ((info & BCM2835_DMA_D_INC) ? BCM2838_DMA40_INC : 0);
++}
++
++static inline uint32_t to_bcm2838_cbaddr(dma_addr_t addr)
++{
++ BUG_ON(addr & 0x1f);
++ return (addr >> 5);
++}
++
+ static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
+ {
+ size_t i;
+@@ -282,45 +381,53 @@ static void bcm2835_dma_desc_free(struct
+ }
+
+ static void bcm2835_dma_create_cb_set_length(
+- struct bcm2835_chan *chan,
++ struct bcm2835_chan *c,
+ struct bcm2835_dma_cb *control_block,
+ size_t len,
+ size_t period_len,
+ size_t *total_len,
+ u32 finalextrainfo)
+ {
+- size_t max_len = bcm2835_dma_max_frame_length(chan);
++ size_t max_len = bcm2835_dma_max_frame_length(c);
++ uint32_t cb_len;
+
+ /* set the length taking lite-channel limitations into account */
+- control_block->length = min_t(u32, len, max_len);
++ cb_len = min_t(u32, len, max_len);
+
+- /* finished if we have no period_length */
+- if (!period_len)
+- return;
++ if (period_len) {
++ /*
++ * period_len means: that we need to generate
++ * transfers that are terminating at every
++ * multiple of period_len - this is typically
++ * used to set the interrupt flag in info
++ * which is required during cyclic transfers
++ */
+
+- /*
+- * period_len means: that we need to generate
+- * transfers that are terminating at every
+- * multiple of period_len - this is typically
+- * used to set the interrupt flag in info
+- * which is required during cyclic transfers
+- */
++ /* have we filled in period_length yet? */
++ if (*total_len + cb_len < period_len) {
++ /* update number of bytes in this period so far */
++ *total_len += cb_len;
++ } else {
++ /* calculate the length that remains to reach period_len */
++ cb_len = period_len - *total_len;
+
+- /* have we filled in period_length yet? */
+- if (*total_len + control_block->length < period_len) {
+- /* update number of bytes in this period so far */
+- *total_len += control_block->length;
+- return;
++ /* reset total_length for next period */
++ *total_len = 0;
++ }
+ }
+
+- /* calculate the length that remains to reach period_length */
+- control_block->length = period_len - *total_len;
+-
+- /* reset total_length for next period */
+- *total_len = 0;
+-
+- /* add extrainfo bits in info */
+- control_block->info |= finalextrainfo;
++ if (c->is_40bit_channel) {
++ struct bcm2838_dma40_scb *scb =
++ (struct bcm2838_dma40_scb *)control_block;
++
++ scb->len = cb_len;
++ /* add extrainfo bits to ti */
++ scb->ti |= to_bcm2838_ti(finalextrainfo);
++ } else {
++ control_block->length = cb_len;
++ /* add extrainfo bits to info */
++ control_block->info |= finalextrainfo;
++ }
+ }
+
+ static inline size_t bcm2835_dma_count_frames_for_sg(
+@@ -343,7 +450,7 @@ static inline size_t bcm2835_dma_count_f
+ /**
+ * bcm2835_dma_create_cb_chain - create a control block and fills data in
+ *
+- * @chan: the @dma_chan for which we run this
++ * @c: the @bcm2835_chan for which we run this
+ * @direction: the direction in which we transfer
+ * @cyclic: it is a cyclic transfer
+ * @info: the default info bits to apply per controlblock
+@@ -361,12 +468,11 @@ static inline size_t bcm2835_dma_count_f
+ * @gfp: the GFP flag to use for allocation
+ */
+ static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
+- struct dma_chan *chan, enum dma_transfer_direction direction,
++ struct bcm2835_chan *c, enum dma_transfer_direction direction,
+ bool cyclic, u32 info, u32 finalextrainfo, size_t frames,
+ dma_addr_t src, dma_addr_t dst, size_t buf_len,
+ size_t period_len, gfp_t gfp)
+ {
+- struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+ size_t len = buf_len, total_len;
+ size_t frame;
+ struct bcm2835_desc *d;
+@@ -399,11 +505,23 @@ static struct bcm2835_desc *bcm2835_dma_
+
+ /* fill in the control block */
+ control_block = cb_entry->cb;
+- control_block->info = info;
+- control_block->src = src;
+- control_block->dst = dst;
+- control_block->stride = 0;
+- control_block->next = 0;
++ if (c->is_40bit_channel) {
++ struct bcm2838_dma40_scb *scb =
++ (struct bcm2838_dma40_scb *)control_block;
++ scb->ti = to_bcm2838_ti(info);
++ scb->src = lower_32_bits(src);
++ scb->srci= upper_32_bits(src) | to_bcm2838_srci(info);
++ scb->dst = lower_32_bits(dst);
++ scb->dsti = upper_32_bits(dst) | to_bcm2838_dsti(info);
++ scb->next_cb = 0;
++ } else {
++ control_block->info = info;
++ control_block->src = src;
++ control_block->dst = dst;
++ control_block->stride = 0;
++ control_block->next = 0;
++ }
++
+ /* set up length in control_block if requested */
+ if (buf_len) {
+ /* calculate length honoring period_length */
+@@ -417,7 +535,10 @@ static struct bcm2835_desc *bcm2835_dma_
+ }
+
+ /* link this the last controlblock */
+- if (frame)
++ if (frame && c->is_40bit_channel)
++ d->cb_list[frame - 1].cb->next =
++ to_bcm2838_cbaddr(cb_entry->paddr);
++ if (frame && !c->is_40bit_channel)
+ d->cb_list[frame - 1].cb->next = cb_entry->paddr;
+
+ /* update src and dst and length */
+@@ -431,7 +552,14 @@ static struct bcm2835_desc *bcm2835_dma_
+ }
+
+ /* the last frame requires extra flags */
+- d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
++ if (c->is_40bit_channel) {
++ struct bcm2838_dma40_scb *scb =
++ (struct bcm2838_dma40_scb *)d->cb_list[d->frames-1].cb;
++
++ scb->ti |= to_bcm2838_ti(finalextrainfo);
++ } else {
++ d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
++ }
+
+ /* detect a size missmatch */
+ if (buf_len && (d->size != buf_len))
+@@ -445,28 +573,51 @@ error_cb:
+ }
+
+ static void bcm2835_dma_fill_cb_chain_with_sg(
+- struct dma_chan *chan,
++ struct bcm2835_chan *c,
+ enum dma_transfer_direction direction,
+ struct bcm2835_cb_entry *cb,
+ struct scatterlist *sgl,
+ unsigned int sg_len)
+ {
+- struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+ size_t len, max_len;
+ unsigned int i;
+ dma_addr_t addr;
+ struct scatterlist *sgent;
+
++ pr_err("dma_fill_chain_with_sg(ch %d, dir %d):\n", c->ch, direction);
++
+ max_len = bcm2835_dma_max_frame_length(c);
+ for_each_sg(sgl, sgent, sg_len, i) {
+- for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent);
+- len > 0;
+- addr += cb->cb->length, len -= cb->cb->length, cb++) {
+- if (direction == DMA_DEV_TO_MEM)
+- cb->cb->dst = addr;
+- else
+- cb->cb->src = addr;
+- cb->cb->length = min(len, max_len);
++ if (c->is_40bit_channel) {
++ struct bcm2838_dma40_scb *scb =
++ (struct bcm2838_dma40_scb *)cb->cb;
++ for (addr = sg_dma_address(sgent),
++ len = sg_dma_len(sgent);
++ len > 0;
++ addr += scb->len, len -= scb->len, scb++) {
++ if (direction == DMA_DEV_TO_MEM) {
++ scb->dst = lower_32_bits(addr);
++ scb->dsti = upper_32_bits(addr) | BCM2838_DMA40_INC;
++ } else {
++ scb->src = lower_32_bits(addr);
++ scb->srci = upper_32_bits(addr) | BCM2838_DMA40_INC;
++ }
++ scb->len = min(len, max_len);
++ pr_err(" %llx, %x\n", (u64)addr, scb->len);
++ }
++ } else {
++ for (addr = sg_dma_address(sgent),
++ len = sg_dma_len(sgent);
++ len > 0;
++ addr += cb->cb->length, len -= cb->cb->length,
++ cb++) {
++ if (direction == DMA_DEV_TO_MEM)
++ cb->cb->dst = addr;
++ else
++ cb->cb->src = addr;
++ cb->cb->length = min(len, max_len);
++ pr_err(" %llx, %x\n", (u64)addr, cb->cb->length);
++ }
+ }
+ }
+ }
+@@ -475,6 +626,10 @@ static int bcm2835_dma_abort(struct bcm2
+ {
+ void __iomem *chan_base = c->chan_base;
+ long int timeout = 10000;
++ u32 wait_mask = BCM2835_DMA_WAITING_FOR_WRITES;
++
++ if (c->is_40bit_channel)
++ wait_mask = BCM2838_DMA40_WAITING_FOR_WRITES;
+
+ /*
+ * A zero control block address means the channel is idle.
+@@ -487,8 +642,7 @@ static int bcm2835_dma_abort(struct bcm2
+ writel(0, chan_base + BCM2835_DMA_CS);
+
+ /* Wait for any current AXI transfer to complete */
+- while ((readl(chan_base + BCM2835_DMA_CS) &
+- BCM2835_DMA_WAITING_FOR_WRITES) && --timeout)
++ while ((readl(chan_base + BCM2835_DMA_CS) & wait_mask) && --timeout)
+ cpu_relax();
+
+ /* Peripheral might be stuck and fail to signal AXI write responses */
+@@ -505,6 +659,7 @@ static void bcm2835_dma_start_desc(struc
+ struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
+ struct bcm2835_desc *d;
+
++ pr_err("dma_start_desc(%px)\n", vd);
+ if (!vd) {
+ c->desc = NULL;
+ return;
+@@ -514,9 +669,16 @@ static void bcm2835_dma_start_desc(struc
+
+ c->desc = d = to_bcm2835_dma_desc(&vd->tx);
+
+- writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
+- writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
+- c->chan_base + BCM2835_DMA_CS);
++ if (c->is_40bit_channel) {
++ writel(to_bcm2838_cbaddr(d->cb_list[0].paddr),
++ c->chan_base + BCM2838_DMA40_CB);
++ writel(BCM2838_DMA40_ACTIVE | BCM2838_DMA40_CS_FLAGS(c->dreq),
++ c->chan_base + BCM2838_DMA40_CS);
++ } else {
++ writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
++ writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
++ c->chan_base + BCM2835_DMA_CS);
++ }
+ }
+
+ static irqreturn_t bcm2835_dma_callback(int irq, void *data)
+@@ -544,7 +706,8 @@ static irqreturn_t bcm2835_dma_callback(
+ * will remain idle despite the ACTIVE flag being set.
+ */
+ writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE |
+- BCM2835_DMA_CS_FLAGS(c->dreq),
++ (c->is_40bit_channel ? BCM2838_DMA40_CS_FLAGS(c->dreq) :
++ BCM2835_DMA_CS_FLAGS(c->dreq)),
+ c->chan_base + BCM2835_DMA_CS);
+
+ d = c->desc;
+@@ -643,9 +806,17 @@ static enum dma_status bcm2835_dma_tx_st
+ struct bcm2835_desc *d = c->desc;
+ dma_addr_t pos;
+
+- if (d->dir == DMA_MEM_TO_DEV)
++ if (d->dir == DMA_MEM_TO_DEV && c->is_40bit_channel)
++ pos = readl(c->chan_base + BCM2838_DMA40_SRC) +
++ ((readl(c->chan_base + BCM2838_DMA40_SRCI) &
++ 0xff) << 8);
++ else if (d->dir == DMA_MEM_TO_DEV && !c->is_40bit_channel)
+ pos = readl(c->chan_base + BCM2835_DMA_SOURCE_AD);
+- else if (d->dir == DMA_DEV_TO_MEM)
++ else if (d->dir == DMA_DEV_TO_MEM && c->is_40bit_channel)
++ pos = readl(c->chan_base + BCM2838_DMA40_DEST) +
++ ((readl(c->chan_base + BCM2838_DMA40_DESTI) &
++ 0xff) << 8);
++ else if (d->dir == DMA_DEV_TO_MEM && !c->is_40bit_channel)
+ pos = readl(c->chan_base + BCM2835_DMA_DEST_AD);
+ else
+ pos = 0;
+@@ -691,7 +862,7 @@ static struct dma_async_tx_descriptor *b
+ frames = bcm2835_dma_frames_for_length(len, max_len);
+
+ /* allocate the CB chain - this also fills in the pointers */
+- d = bcm2835_dma_create_cb_chain(chan, DMA_MEM_TO_MEM, false,
++ d = bcm2835_dma_create_cb_chain(c, DMA_MEM_TO_MEM, false,
+ info, extra, frames,
+ src, dst, len, 0, GFP_KERNEL);
+ if (!d)
+@@ -726,11 +897,21 @@ static struct dma_async_tx_descriptor *b
+ if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
+ return NULL;
+ src = c->cfg.src_addr;
++ /*
++ * One would think it ought to be possible to get the physical
++ * to dma address mapping information from the dma-ranges DT
++ * property, but I've not found a way yet that doesn't involve
++ * open-coding the whole thing.
++ */
++ if (c->is_40bit_channel)
++ src |= 0x400000000ull;
+ info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
+ } else {
+ if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
+ return NULL;
+ dst = c->cfg.dst_addr;
++ if (c->is_40bit_channel)
++ dst |= 0x400000000ull;
+ info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
+ }
+
+@@ -738,7 +919,7 @@ static struct dma_async_tx_descriptor *b
+ frames = bcm2835_dma_count_frames_for_sg(c, sgl, sg_len);
+
+ /* allocate the CB chain */
+- d = bcm2835_dma_create_cb_chain(chan, direction, false,
++ d = bcm2835_dma_create_cb_chain(c, direction, false,
+ info, extra,
+ frames, src, dst, 0, 0,
+ GFP_KERNEL);
+@@ -746,7 +927,7 @@ static struct dma_async_tx_descriptor *b
+ return NULL;
+
+ /* fill in frames with scatterlist pointers */
+- bcm2835_dma_fill_cb_chain_with_sg(chan, direction, d->cb_list,
++ bcm2835_dma_fill_cb_chain_with_sg(c, direction, d->cb_list,
+ sgl, sg_len);
+
+ return vchan_tx_prep(&c->vc, &d->vd, flags);
+@@ -815,7 +996,7 @@ static struct dma_async_tx_descriptor *b
+ * note that we need to use GFP_NOWAIT, as the ALSA i2s dmaengine
+ * implementation calls prep_dma_cyclic with interrupts disabled.
+ */
+- d = bcm2835_dma_create_cb_chain(chan, direction, true,
++ d = bcm2835_dma_create_cb_chain(c, direction, true,
+ info, extra,
+ frames, src, dst, buf_len,
+ period_len, GFP_NOWAIT);
+@@ -823,7 +1004,8 @@ static struct dma_async_tx_descriptor *b
+ return NULL;
+
+ /* wrap around into a loop */
+- d->cb_list[d->frames - 1].cb->next = d->cb_list[0].paddr;
++ d->cb_list[d->frames - 1].cb->next = c->is_40bit_channel ?
++ to_bcm2838_cbaddr(d->cb_list[0].paddr) : d->cb_list[0].paddr;
+
+ return vchan_tx_prep(&c->vc, &d->vd, flags);
+ }
+@@ -899,9 +1081,11 @@ static int bcm2835_dma_chan_init(struct
+ c->irq_number = irq;
+ c->irq_flags = irq_flags;
+
+- /* check in DEBUG register if this is a LITE channel */
+- if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
+- BCM2835_DMA_DEBUG_LITE)
++ /* check for 40bit and lite channels */
++ if (d->cfg_data->chan_40bit_mask & BIT(chan_id))
++ c->is_40bit_channel = true;
++ else if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
++ BCM2835_DMA_DEBUG_LITE)
+ c->is_lite_channel = true;
+
+ return 0;
+@@ -918,18 +1102,16 @@ static void bcm2835_dma_free(struct bcm2
+ }
+ }
+
+-int bcm2838_dma40_memcpy_init(struct device *dev)
++int bcm2838_dma40_memcpy_init(void)
+ {
+- if (memcpy_scb)
+- return 0;
++ if (!memcpy_parent)
++ return -EPROBE_DEFER;
+
+- memcpy_scb = dma_alloc_coherent(dev, sizeof(*memcpy_scb),
+- &memcpy_scb_dma, GFP_KERNEL);
++ if (!memcpy_chan)
++ return -EINVAL;
+
+- if (!memcpy_scb) {
+- pr_err("bcm2838_dma40_memcpy_init failed!\n");
++ if (!memcpy_scb)
+ return -ENOMEM;
+- }
+
+ return 0;
+ }
+@@ -956,20 +1138,22 @@ void bcm2838_dma40_memcpy(dma_addr_t dst
+ scb->next_cb = 0;
+
+ writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2838_DMA40_CB);
+- writel(BCM2838_DMA40_MEMCPY_QOS + BCM2838_DMA40_CS_ACTIVE,
++ writel(BCM2838_DMA40_MEMCPY_FLAGS + BCM2838_DMA40_ACTIVE,
+ memcpy_chan + BCM2838_DMA40_CS);
++
+ /* Poll for completion */
+- while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_CS_END))
++ while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_END))
+ cpu_relax();
+
+- writel(BCM2838_DMA40_CS_END, memcpy_chan + BCM2838_DMA40_CS);
++ writel(BCM2838_DMA40_END, memcpy_chan + BCM2838_DMA40_CS);
+
+ spin_unlock_irqrestore(&memcpy_lock, flags);
+ }
+ EXPORT_SYMBOL(bcm2838_dma40_memcpy);
+
+ static const struct of_device_id bcm2835_dma_of_match[] = {
+- { .compatible = "brcm,bcm2835-dma", },
++ { .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_cfg },
++ { .compatible = "brcm,bcm2838-dma", .data = &bcm2838_dma_cfg },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
+@@ -1001,6 +1185,8 @@ static int bcm2835_dma_probe(struct plat
+ int irq_flags;
+ uint32_t chans_available;
+ char chan_name[BCM2835_DMA_CHAN_NAME_SIZE];
++ const struct of_device_id *of_id;
++ int chan_count, chan_start, chan_end;
+
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+@@ -1022,9 +1208,13 @@ static int bcm2835_dma_probe(struct plat
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+- rc = bcm_dmaman_probe(pdev, base, BCM2835_DMA_BULK_MASK);
+- if (rc)
+- dev_err(&pdev->dev, "Failed to initialize the legacy API\n");
++
++ /* The set of channels can be split across multiple instances. */
++ chan_start = ((u32)base / BCM2835_DMA_CHAN_SIZE) & 0xf;
++ base -= BCM2835_DMA_CHAN(chan_start);
++ chan_count = resource_size(res) / BCM2835_DMA_CHAN_SIZE;
++ chan_end = min(chan_start + chan_count,
++ BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED + 1);
+
+ od->base = base;
+
+@@ -1054,6 +1244,14 @@ static int bcm2835_dma_probe(struct plat
+
+ platform_set_drvdata(pdev, od);
+
++ of_id = of_match_node(bcm2835_dma_of_match, pdev->dev.of_node);
++ if (!of_id) {
++ dev_err(&pdev->dev, "Failed to match compatible string\n");
++ return -EINVAL;
++ }
++
++ od->cfg_data = of_id->data;
++
+ /* Request DMA channel mask from device tree */
+ if (of_property_read_u32(pdev->dev.of_node,
+ "brcm,dma-channel-mask",
+@@ -1063,18 +1261,34 @@ static int bcm2835_dma_probe(struct plat
+ goto err_no_dma;
+ }
+
+- /* Channel 0 is used by the legacy API */
+- chans_available &= ~BCM2835_DMA_BULK_MASK;
++ /* One channel is reserved for the legacy API */
++ if (chans_available & BCM2835_DMA_BULK_MASK) {
++ rc = bcm_dmaman_probe(pdev, base,
++ chans_available & BCM2835_DMA_BULK_MASK);
++ if (rc)
++ dev_err(&pdev->dev,
++ "Failed to initialize the legacy API\n");
++
++ chans_available &= ~BCM2835_DMA_BULK_MASK;
++ }
+
+- /* We can't use channels 11-13 yet */
+- chans_available &= ~(BIT(11) | BIT(12) | BIT(13));
++ /* And possibly one for the 40-bit DMA memcpy API */
++ if (chans_available & od->cfg_data->chan_40bit_mask &
++ BIT(BCM2838_DMA_MEMCPY_CHAN)) {
++ memcpy_parent = od;
++ memcpy_chan = BCM2835_DMA_CHANIO(base, BCM2838_DMA_MEMCPY_CHAN);
++ memcpy_scb = dma_alloc_coherent(memcpy_parent->ddev.dev,
++ sizeof(*memcpy_scb),
++ &memcpy_scb_dma, GFP_KERNEL);
++ if (!memcpy_scb)
++ dev_warn(&pdev->dev,
++ "Failed to allocated memcpy scb\n");
+
+- /* Grab channel 14 for the 40-bit DMA memcpy */
+- chans_available &= ~BIT(14);
+- memcpy_chan = BCM2835_DMA_CHANIO(base, 14);
++ chans_available &= ~BIT(BCM2838_DMA_MEMCPY_CHAN);
++ }
+
+ /* get irqs for each channel that we support */
+- for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
++ for (i = chan_start; i < chan_end; i++) {
+ /* skip masked out channels */
+ if (!(chans_available & (1 << i))) {
+ irq[i] = -1;
+@@ -1097,13 +1311,17 @@ static int bcm2835_dma_probe(struct plat
+ irq[i] = platform_get_irq(pdev, i < 11 ? i : 11);
+ }
+
++ chan_count = 0;
++
+ /* get irqs for each channel */
+- for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
++ for (i = chan_start; i < chan_end; i++) {
+ /* skip channels without irq */
+ if (irq[i] < 0)
+ continue;
+
+ /* check if there are other channels that also use this irq */
++ /* FIXME: This will fail if interrupts are shared across
++ instances */
+ irq_flags = 0;
+ for (j = 0; j <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; j++)
+ if ((i != j) && (irq[j] == irq[i])) {
+@@ -1115,9 +1333,10 @@ static int bcm2835_dma_probe(struct plat
+ rc = bcm2835_dma_chan_init(od, i, irq[i], irq_flags);
+ if (rc)
+ goto err_no_dma;
++ chan_count++;
+ }
+
+- dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i);
++ dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", chan_count);
+
+ /* Device-tree DMA controller registration */
+ rc = of_dma_controller_register(pdev->dev.of_node,
+@@ -1149,6 +1368,13 @@ static int bcm2835_dma_remove(struct pla
+
+ bcm_dmaman_remove(pdev);
+ dma_async_device_unregister(&od->ddev);
++ if (memcpy_parent == od) {
++ dma_free_coherent(&pdev->dev, sizeof(*memcpy_scb), memcpy_scb,
++ memcpy_scb_dma);
++ memcpy_parent = NULL;
++ memcpy_scb = NULL;
++ memcpy_chan = NULL;
++ }
+ bcm2835_dma_free(od);
+
+ return 0;
+--- a/drivers/pci/controller/pcie-brcmstb-bounce.c
++++ b/drivers/pci/controller/pcie-brcmstb-bounce.c
+@@ -91,7 +91,7 @@ struct dmabounce_device_info {
+
+ static struct dmabounce_device_info *g_dmabounce_device_info;
+
+-extern int bcm2838_dma40_memcpy_init(struct device *dev);
++extern int bcm2838_dma40_memcpy_init(void);
+ extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
+
+ #ifdef STATS
+@@ -471,9 +471,9 @@ static const struct dma_map_ops dmabounc
+ .mapping_error = dmabounce_mapping_error,
+ };
+
+-int brcm_pcie_bounce_register_dev(struct device *dev,
+- unsigned long buffer_size,
+- dma_addr_t threshold)
++int brcm_pcie_bounce_init(struct device *dev,
++ unsigned long buffer_size,
++ dma_addr_t threshold)
+ {
+ struct dmabounce_device_info *device_info;
+ int ret;
+@@ -482,9 +482,9 @@ int brcm_pcie_bounce_register_dev(struct
+ if (g_dmabounce_device_info)
+ return -EBUSY;
+
+- ret = bcm2838_dma40_memcpy_init(dev);
++ ret = bcm2838_dma40_memcpy_init();
+ if (ret)
+- return ret;
++ return ret;
+
+ device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
+ if (!device_info) {
+@@ -515,9 +515,8 @@ int brcm_pcie_bounce_register_dev(struct
+ device_create_file(dev, &dev_attr_dmabounce_stats));
+
+ g_dmabounce_device_info = device_info;
+- set_dma_ops(dev, &dmabounce_ops);
+
+- dev_info(dev, "dmabounce: registered device - %ld kB, threshold %pad\n",
++ dev_info(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
+ buffer_size / 1024, &threshold);
+
+ return 0;
+@@ -526,14 +525,13 @@ int brcm_pcie_bounce_register_dev(struct
+ kfree(device_info);
+ return ret;
+ }
+-EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
++EXPORT_SYMBOL(brcm_pcie_bounce_init);
+
+-void brcm_pcie_bounce_unregister_dev(struct device *dev)
++void brcm_pcie_bounce_uninit(struct device *dev)
+ {
+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
+
+ g_dmabounce_device_info = NULL;
+- set_dma_ops(dev, NULL);
+
+ if (!device_info) {
+ dev_warn(dev,
+@@ -554,10 +552,16 @@ void brcm_pcie_bounce_unregister_dev(str
+ device_remove_file(dev, &dev_attr_dmabounce_stats));
+
+ kfree(device_info);
++}
++EXPORT_SYMBOL(brcm_pcie_bounce_uninit);
++
++int brcm_pcie_bounce_register_dev(struct device *dev)
++{
++ set_dma_ops(dev, &dmabounce_ops);
+
+- dev_info(dev, "dmabounce: device unregistered\n");
++ return 0;
+ }
+-EXPORT_SYMBOL(brcm_pcie_bounce_unregister_dev);
++EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
+
+ MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
+--- a/drivers/pci/controller/pcie-brcmstb-bounce.h
++++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
+@@ -8,21 +8,26 @@
+
+ #ifdef CONFIG_ARM
+
+-int brcm_pcie_bounce_register_dev(struct device *dev, unsigned long buffer_size,
+- dma_addr_t threshold);
+-
+-int brcm_pcie_bounce_unregister_dev(struct device *dev);
++int brcm_pcie_bounce_init(struct device *dev, unsigned long buffer_size,
++ dma_addr_t threshold);
++int brcm_pcie_bounce_uninit(struct device *dev);
++int brcm_pcie_bounce_register_dev(struct device *dev);
+
+ #else
+
+-static inline int brcm_pcie_bounce_register_dev(struct device *dev,
+- unsigned long buffer_size,
+- dma_addr_t threshold)
++static inline int brcm_pcie_bounce_init(struct device *dev,
++ unsigned long buffer_size,
++ dma_addr_t threshold)
++{
++ return 0;
++}
++
++static inline int brcm_pcie_bounce_uninit(struct device *dev)
+ {
+ return 0;
+ }
+
+-static inline int brcm_pcie_bounce_unregister_dev(struct device *dev)
++static inline int brcm_pcie_bounce_register_dev(struct device *dev)
+ {
+ return 0;
+ }
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -650,6 +650,7 @@ static void brcm_set_dma_ops(struct devi
+
+ static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
+ unsigned int val);
++
+ static int brcmstb_platform_notifier(struct notifier_block *nb,
+ unsigned long event, void *__dev)
+ {
+@@ -663,12 +664,11 @@ static int brcmstb_platform_notifier(str
+ strcmp(dev->kobj.name, rc_name)) {
+ int ret;
+
+- ret = brcm_pcie_bounce_register_dev(dev, bounce_buffer,
+- (dma_addr_t)bounce_threshold);
++ ret = brcm_pcie_bounce_register_dev(dev);
+ if (ret) {
+ dev_err(dev,
+ "brcm_pcie_bounce_register_dev() failed: %d\n",
+- ret);
++ ret);
+ return ret;
+ }
+ }
+@@ -681,8 +681,6 @@ static int brcmstb_platform_notifier(str
+ brcm_pcie_perst_set(g_pcie, 1);
+ msleep(100);
+ brcm_pcie_perst_set(g_pcie, 0);
+- } else if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
+- brcm_pcie_bounce_unregister_dev(dev);
+ }
+ return NOTIFY_OK;
+
+@@ -1718,6 +1716,7 @@ static int brcm_pcie_probe(struct platfo
+ void __iomem *base;
+ struct pci_host_bridge *bridge;
+ struct pci_bus *child;
++ extern unsigned long max_pfn;
+
+ bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
+ if (!bridge)
+@@ -1753,6 +1752,20 @@ static int brcm_pcie_probe(struct platfo
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
++ /* To Do: Add hardware check if this ever gets fixed */
++ if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
++ int ret;
++ ret = brcm_pcie_bounce_init(&pdev->dev, bounce_buffer,
++ (dma_addr_t)bounce_threshold);
++ if (ret) {
++ if (ret != -EPROBE_DEFER)
++ dev_err(&pdev->dev,
++ "could not init bounce buffers: %d\n",
++ ret);
++ return ret;
++ }
++ }
++
+ pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
+ if (IS_ERR(pcie->clk)) {
+ dev_warn(&pdev->dev, "could not get clock\n");
--- /dev/null
+From db81536216256cdd4b8a17879e6628be47c74414 Mon Sep 17 00:00:00 2001
+Date: Wed, 5 Jun 2019 21:32:03 +0100
+Subject: [PATCH] BCM270X_DT: Leave bulk channel in dma channel mask
+
+The updated bcm2835-dma driver does not require the BULK channel
+to be removed from the set of available channels, as provided by
+dma-channel-mask.
+
+---
+ arch/arm/boot/dts/bcm2708-rpi.dtsi | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
+@@ -124,10 +124,6 @@
+ };
+ };
+
+-&dma {
+- brcm,dma-channel-mask = <0x7f34>;
+-};
+-
+ &hdmi {
+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
+ };
+++ /dev/null
-From 00d8817ab207a9f60e94e87acf4f170155aecd48 Mon Sep 17 00:00:00 2001
-Date: Wed, 6 Feb 2019 20:45:16 +0000
-Subject: [PATCH] arm: dts: Change downstream vchiq compatible string
-
-The new cache line size mechanism requires a different vchiq compatible
-string on BCM2836 and BCM2837, but the downstream dts files didn't
-inherit the upstream changes.
-
-See: https://github.com/raspberrypi/linux/issues/2643
-
----
- arch/arm/boot/dts/bcm2708-rpi.dtsi | 2 +-
- arch/arm/boot/dts/bcm2709-rpi.dtsi | 5 +++++
- arch/arm/boot/dts/bcm2709.dtsi | 2 +-
- arch/arm/boot/dts/bcm2710.dtsi | 2 +-
- 4 files changed, 8 insertions(+), 3 deletions(-)
- create mode 100644 arch/arm/boot/dts/bcm2709-rpi.dtsi
-
---- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
-@@ -68,7 +68,7 @@
- status = "disabled";
- };
-
-- mailbox@7e00b840 {
-+ vchiq: mailbox@7e00b840 {
- compatible = "brcm,bcm2835-vchiq";
- reg = <0x7e00b840 0x3c>;
- interrupts = <0 2>;
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2709-rpi.dtsi
-@@ -0,0 +1,5 @@
-+#include "bcm2708-rpi.dtsi"
-+
-+&vchiq {
-+ compatible = "brcm,bcm2836-vchiq", "brcm,bcm2835-vchiq";
-+};
---- a/arch/arm/boot/dts/bcm2709.dtsi
-+++ b/arch/arm/boot/dts/bcm2709.dtsi
-@@ -1,6 +1,6 @@
- #include "bcm2836.dtsi"
- #include "bcm270x.dtsi"
--#include "bcm2708-rpi.dtsi"
-+#include "bcm2709-rpi.dtsi"
-
- / {
- soc {
---- a/arch/arm/boot/dts/bcm2710.dtsi
-+++ b/arch/arm/boot/dts/bcm2710.dtsi
-@@ -1,6 +1,6 @@
- #include "bcm2837.dtsi"
- #include "bcm270x.dtsi"
--#include "bcm2708-rpi.dtsi"
-+#include "bcm2709-rpi.dtsi"
-
- / {
- compatible = "brcm,bcm2837", "brcm,bcm2836";
--- /dev/null
+From eecf4b8568f0a0d6b90364299eed6b12ce63c245 Mon Sep 17 00:00:00 2001
+Date: Thu, 6 Jun 2019 09:35:08 +0100
+Subject: [PATCH] SQUASH: bcm2835-dma: Remove debugging
+
+---
+ drivers/dma/bcm2835-dma.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -584,8 +584,6 @@ static void bcm2835_dma_fill_cb_chain_wi
+ dma_addr_t addr;
+ struct scatterlist *sgent;
+
+- pr_err("dma_fill_chain_with_sg(ch %d, dir %d):\n", c->ch, direction);
+-
+ max_len = bcm2835_dma_max_frame_length(c);
+ for_each_sg(sgl, sgent, sg_len, i) {
+ if (c->is_40bit_channel) {
+@@ -603,7 +601,6 @@ static void bcm2835_dma_fill_cb_chain_wi
+ scb->srci = upper_32_bits(addr) | BCM2838_DMA40_INC;
+ }
+ scb->len = min(len, max_len);
+- pr_err(" %llx, %x\n", (u64)addr, scb->len);
+ }
+ } else {
+ for (addr = sg_dma_address(sgent),
+@@ -616,7 +613,6 @@ static void bcm2835_dma_fill_cb_chain_wi
+ else
+ cb->cb->src = addr;
+ cb->cb->length = min(len, max_len);
+- pr_err(" %llx, %x\n", (u64)addr, cb->cb->length);
+ }
+ }
+ }
+@@ -659,7 +655,6 @@ static void bcm2835_dma_start_desc(struc
+ struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
+ struct bcm2835_desc *d;
+
+- pr_err("dma_start_desc(%px)\n", vd);
+ if (!vd) {
+ c->desc = NULL;
+ return;
+++ /dev/null
-From 621fb1606217c3e72feda69255ae6cb6a7ccfec2 Mon Sep 17 00:00:00 2001
-Date: Thu, 4 Apr 2019 13:33:47 +0100
-Subject: [PATCH] bcm2835-dma: Add proper 40-bit DMA support
-
-The 40-bit additions are not fully tested, but it should be
-capable of supporting both 40-bit memcpy on BCM2711 and regular
-Lite channels on BCM2835.
-
----
- arch/arm/boot/dts/bcm2838.dtsi | 33 +-
- drivers/dma/bcm2835-dma.c | 426 ++++++++++++++-----
- drivers/pci/controller/pcie-brcmstb-bounce.c | 30 +-
- drivers/pci/controller/pcie-brcmstb-bounce.h | 21 +-
- drivers/pci/controller/pcie-brcmstb.c | 23 +-
- 5 files changed, 395 insertions(+), 138 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -372,6 +372,23 @@
- };
- };
-
-+ dma40: dma@7e007b00 {
-+ compatible = "brcm,bcm2838-dma";
-+ reg = <0x0 0x7e007b00 0x400>;
-+ interrupts =
-+ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
-+ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 12 */
-+ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, /* dma4 13 */
-+ <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; /* dma4 14 */
-+ interrupt-names = "dma11",
-+ "dma12",
-+ "dma13",
-+ "dma14";
-+ #dma-cells = <1>;
-+ brcm,dma-channel-mask = <0x7000>;
-+ };
-+ /* DMA4 - 40 bit DMA engines */
-+
- xhci: xhci@7e9c0000 {
- compatible = "generic-xhci";
- status = "disabled";
-@@ -689,6 +706,7 @@
- };
-
- &dma {
-+ reg = <0x7e007000 0xb00>;
- interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
-@@ -699,12 +717,7 @@
- <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 7 */
- <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 8 */
- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 9 */
-- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 10 */
-- /* DMA4 - 40 bit DMA engines */
-- <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
-- <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 12 */
-- <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, /* dma4 13 */
-- <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; /* dma4 14 */
-+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>; /* dmalite 10 */
- interrupt-names = "dma0",
- "dma1",
- "dma2",
-@@ -715,10 +728,6 @@
- "dma7",
- "dma8",
- "dma9",
-- "dma10",
-- "dma11",
-- "dma12",
-- "dma13",
-- "dma14";
-- brcm,dma-channel-mask = <0x7ef5>;
-+ "dma10";
-+ brcm,dma-channel-mask = <0x01f5>;
- };
---- a/drivers/dma/bcm2835-dma.c
-+++ b/drivers/dma/bcm2835-dma.c
-@@ -50,12 +50,18 @@
- #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
- #define BCM2835_DMA_CHAN_NAME_SIZE 8
- #define BCM2835_DMA_BULK_MASK BIT(0)
-+#define BCM2838_DMA_MEMCPY_CHAN 14
-+
-+struct bcm2835_dma_cfg_data {
-+ u32 chan_40bit_mask;
-+};
-
- struct bcm2835_dmadev {
- struct dma_device ddev;
- spinlock_t lock;
- void __iomem *base;
- struct device_dma_parameters dma_parms;
-+ const struct bcm2835_dma_cfg_data *cfg_data;
- };
-
- struct bcm2835_dma_cb {
-@@ -100,6 +106,7 @@ struct bcm2835_chan {
- unsigned int irq_flags;
-
- bool is_lite_channel;
-+ bool is_40bit_channel;
- };
-
- struct bcm2835_desc {
-@@ -189,7 +196,8 @@ struct bcm2835_desc {
- #define BCM2835_DMA_DATA_TYPE_S128 16
-
- /* Valid only for channels 0 - 14, 15 has its own base address */
--#define BCM2835_DMA_CHAN(n) ((n) << 8) /* Base address */
-+#define BCM2835_DMA_CHAN_SIZE 0x100
-+#define BCM2835_DMA_CHAN(n) ((n) * BCM2835_DMA_CHAN_SIZE) /* Base address */
- #define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n))
-
- /* the max dma length for different channels */
-@@ -200,7 +208,7 @@ struct bcm2835_desc {
- #define BCM2838_DMA40_CS 0x00
- #define BCM2838_DMA40_CB 0x04
- #define BCM2838_DMA40_DEBUG 0x0c
--#define BCM2858_DMA40_TI 0x10
-+#define BCM2838_DMA40_TI 0x10
- #define BCM2838_DMA40_SRC 0x14
- #define BCM2838_DMA40_SRCI 0x18
- #define BCM2838_DMA40_DEST 0x1c
-@@ -209,32 +217,97 @@ struct bcm2835_desc {
- #define BCM2838_DMA40_NEXT_CB 0x28
- #define BCM2838_DMA40_DEBUG2 0x2c
-
--#define BCM2838_DMA40_CS_ACTIVE BIT(0)
--#define BCM2838_DMA40_CS_END BIT(1)
-+#define BCM2838_DMA40_ACTIVE BIT(0)
-+#define BCM2838_DMA40_END BIT(1)
-+#define BCM2838_DMA40_INT BIT(2)
-+#define BCM2838_DMA40_DREQ BIT(3) /* DREQ state */
-+#define BCM2838_DMA40_RD_PAUSED BIT(4) /* Reading is paused */
-+#define BCM2838_DMA40_WR_PAUSED BIT(5) /* Writing is paused */
-+#define BCM2838_DMA40_DREQ_PAUSED BIT(6) /* Is paused by DREQ flow control */
-+#define BCM2838_DMA40_WAITING_FOR_WRITES BIT(7) /* Waiting for last write */
-+#define BCM2838_DMA40_ERR BIT(10)
-+#define BCM2838_DMA40_QOS(x) (((x) & 0x1f) << 16)
-+#define BCM2838_DMA40_PANIC_QOS(x) (((x) & 0x1f) << 20)
-+#define BCM2838_DMA40_WAIT_FOR_WRITES BIT(28)
-+#define BCM2838_DMA40_DISDEBUG BIT(29)
-+#define BCM2838_DMA40_ABORT BIT(30)
-+#define BCM2838_DMA40_HALT BIT(31)
-+#define BCM2838_DMA40_CS_FLAGS(x) (x & (BCM2838_DMA40_QOS(15) | \
-+ BCM2838_DMA40_PANIC_QOS(15) | \
-+ BCM2838_DMA40_WAIT_FOR_WRITES | \
-+ BCM2838_DMA40_DISDEBUG))
-+
-+/* Transfer information bits */
-+#define BCM2838_DMA40_INTEN BIT(0)
-+#define BCM2838_DMA40_TDMODE BIT(1) /* 2D-Mode */
-+#define BCM2838_DMA40_WAIT_RESP BIT(2) /* wait for AXI write to be acked */
-+#define BCM2838_DMA40_WAIT_RD_RESP BIT(3) /* wait for AXI read to complete */
-+#define BCM2838_DMA40_PER_MAP(x) ((x & 31) << 9) /* REQ source */
-+#define BCM2838_DMA40_S_DREQ BIT(14) /* enable SREQ for source */
-+#define BCM2838_DMA40_D_DREQ BIT(15) /* enable DREQ for destination */
-+#define BCM2838_DMA40_S_WAIT(x) ((x & 0xff) << 16) /* add DMA read-wait cycles */
-+#define BCM2838_DMA40_D_WAIT(x) ((x & 0xff) << 24) /* add DMA write-wait cycles */
-
--#define BCM2838_DMA40_CS_QOS(x) (((x) & 0x1f) << 16)
--#define BCM2838_DMA40_CS_PANIC_QOS(x) (((x) & 0x1f) << 20)
--#define BCM2838_DMA40_CS_WRITE_WAIT BIT(28)
-+/* debug register bits */
-+#define BCM2838_DMA40_DEBUG_WRITE_ERR BIT(0)
-+#define BCM2838_DMA40_DEBUG_FIFO_ERR BIT(1)
-+#define BCM2838_DMA40_DEBUG_READ_ERR BIT(2)
-+#define BCM2838_DMA40_DEBUG_READ_CB_ERR BIT(3)
-+#define BCM2838_DMA40_DEBUG_IN_ON_ERR BIT(8)
-+#define BCM2838_DMA40_DEBUG_ABORT_ON_ERR BIT(9)
-+#define BCM2838_DMA40_DEBUG_HALT_ON_ERR BIT(10)
-+#define BCM2838_DMA40_DEBUG_DISABLE_CLK_GATE BIT(11)
-+#define BCM2838_DMA40_DEBUG_RSTATE_SHIFT 14
-+#define BCM2838_DMA40_DEBUG_RSTATE_BITS 4
-+#define BCM2838_DMA40_DEBUG_WSTATE_SHIFT 18
-+#define BCM2838_DMA40_DEBUG_WSTATE_BITS 4
-+#define BCM2838_DMA40_DEBUG_RESET BIT(23)
-+#define BCM2838_DMA40_DEBUG_ID_SHIFT 24
-+#define BCM2838_DMA40_DEBUG_ID_BITS 4
-+#define BCM2838_DMA40_DEBUG_VERSION_SHIFT 28
-+#define BCM2838_DMA40_DEBUG_VERSION_BITS 4
-+
-+/* Valid only for channels 0 - 3 (11 - 14) */
-+#define BCM2838_DMA40_CHAN(n) (((n) + 11) << 8) /* Base address */
-+#define BCM2838_DMA40_CHANIO(base, n) ((base) + BCM2838_DMA_CHAN(n))
-
--#define BCM2838_DMA40_BURST_LEN(x) ((((x) - 1) & 0xf) << 8)
--#define BCM2838_DMA40_INC BIT(12)
--#define BCM2838_DMA40_SIZE_128 (2 << 13)
-+/* the max dma length for different channels */
-+#define MAX_DMA40_LEN SZ_1G
-
--#define BCM2838_DMA40_MEMCPY_QOS \
-- (BCM2838_DMA40_CS_QOS(0x0) | \
-- BCM2838_DMA40_CS_PANIC_QOS(0x0) | \
-- BCM2838_DMA40_CS_WRITE_WAIT)
-+#define BCM2838_DMA40_BURST_LEN(x) ((min(x,16) - 1) << 8)
-+#define BCM2838_DMA40_INC BIT(12)
-+#define BCM2838_DMA40_SIZE_32 (0 << 13)
-+#define BCM2838_DMA40_SIZE_64 (1 << 13)
-+#define BCM2838_DMA40_SIZE_128 (2 << 13)
-+#define BCM2838_DMA40_SIZE_256 (3 << 13)
-+#define BCM2838_DMA40_IGNORE BIT(15)
-+#define BCM2838_DMA40_STRIDE(x) ((x) << 16) /* For 2D mode */
-+
-+#define BCM2838_DMA40_MEMCPY_FLAGS \
-+ (BCM2838_DMA40_QOS(0) | \
-+ BCM2838_DMA40_PANIC_QOS(0) | \
-+ BCM2838_DMA40_WAIT_FOR_WRITES | \
-+ BCM2838_DMA40_DISDEBUG)
-
- #define BCM2838_DMA40_MEMCPY_XFER_INFO \
- (BCM2838_DMA40_SIZE_128 | \
- BCM2838_DMA40_INC | \
- BCM2838_DMA40_BURST_LEN(16))
-
-+struct bcm2835_dmadev *memcpy_parent;
- static void __iomem *memcpy_chan;
- static struct bcm2838_dma40_scb *memcpy_scb;
- static dma_addr_t memcpy_scb_dma;
- DEFINE_SPINLOCK(memcpy_lock);
-
-+static const struct bcm2835_dma_cfg_data bcm2835_dma_cfg = {
-+ .chan_40bit_mask = 0,
-+};
-+
-+static const struct bcm2835_dma_cfg_data bcm2838_dma_cfg = {
-+ .chan_40bit_mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
-+};
-+
- static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
- {
- /* lite and normal channels have different max frame length */
-@@ -264,6 +337,32 @@ static inline struct bcm2835_desc *to_bc
- return container_of(t, struct bcm2835_desc, vd.tx);
- }
-
-+static inline uint32_t to_bcm2838_ti(uint32_t info)
-+{
-+ return ((info & BCM2835_DMA_INT_EN) ? BCM2838_DMA40_INTEN : 0) |
-+ ((info & BCM2835_DMA_WAIT_RESP) ? BCM2838_DMA40_WAIT_RESP : 0) |
-+ ((info & BCM2835_DMA_S_DREQ) ?
-+ (BCM2838_DMA40_S_DREQ | BCM2838_DMA40_WAIT_RD_RESP) : 0) |
-+ ((info & BCM2835_DMA_D_DREQ) ? BCM2838_DMA40_D_DREQ : 0) |
-+ BCM2838_DMA40_PER_MAP((info >> 16) & 0x1f);
-+}
-+
-+static inline uint32_t to_bcm2838_srci(uint32_t info)
-+{
-+ return ((info & BCM2835_DMA_S_INC) ? BCM2838_DMA40_INC : 0);
-+}
-+
-+static inline uint32_t to_bcm2838_dsti(uint32_t info)
-+{
-+ return ((info & BCM2835_DMA_D_INC) ? BCM2838_DMA40_INC : 0);
-+}
-+
-+static inline uint32_t to_bcm2838_cbaddr(dma_addr_t addr)
-+{
-+ BUG_ON(addr & 0x1f);
-+ return (addr >> 5);
-+}
-+
- static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
- {
- size_t i;
-@@ -282,45 +381,53 @@ static void bcm2835_dma_desc_free(struct
- }
-
- static void bcm2835_dma_create_cb_set_length(
-- struct bcm2835_chan *chan,
-+ struct bcm2835_chan *c,
- struct bcm2835_dma_cb *control_block,
- size_t len,
- size_t period_len,
- size_t *total_len,
- u32 finalextrainfo)
- {
-- size_t max_len = bcm2835_dma_max_frame_length(chan);
-+ size_t max_len = bcm2835_dma_max_frame_length(c);
-+ uint32_t cb_len;
-
- /* set the length taking lite-channel limitations into account */
-- control_block->length = min_t(u32, len, max_len);
-+ cb_len = min_t(u32, len, max_len);
-
-- /* finished if we have no period_length */
-- if (!period_len)
-- return;
-+ if (period_len) {
-+ /*
-+ * period_len means: that we need to generate
-+ * transfers that are terminating at every
-+ * multiple of period_len - this is typically
-+ * used to set the interrupt flag in info
-+ * which is required during cyclic transfers
-+ */
-
-- /*
-- * period_len means: that we need to generate
-- * transfers that are terminating at every
-- * multiple of period_len - this is typically
-- * used to set the interrupt flag in info
-- * which is required during cyclic transfers
-- */
-+ /* have we filled in period_length yet? */
-+ if (*total_len + cb_len < period_len) {
-+ /* update number of bytes in this period so far */
-+ *total_len += cb_len;
-+ } else {
-+ /* calculate the length that remains to reach period_len */
-+ cb_len = period_len - *total_len;
-
-- /* have we filled in period_length yet? */
-- if (*total_len + control_block->length < period_len) {
-- /* update number of bytes in this period so far */
-- *total_len += control_block->length;
-- return;
-+ /* reset total_length for next period */
-+ *total_len = 0;
-+ }
- }
-
-- /* calculate the length that remains to reach period_length */
-- control_block->length = period_len - *total_len;
--
-- /* reset total_length for next period */
-- *total_len = 0;
--
-- /* add extrainfo bits in info */
-- control_block->info |= finalextrainfo;
-+ if (c->is_40bit_channel) {
-+ struct bcm2838_dma40_scb *scb =
-+ (struct bcm2838_dma40_scb *)control_block;
-+
-+ scb->len = cb_len;
-+ /* add extrainfo bits to ti */
-+ scb->ti |= to_bcm2838_ti(finalextrainfo);
-+ } else {
-+ control_block->length = cb_len;
-+ /* add extrainfo bits to info */
-+ control_block->info |= finalextrainfo;
-+ }
- }
-
- static inline size_t bcm2835_dma_count_frames_for_sg(
-@@ -343,7 +450,7 @@ static inline size_t bcm2835_dma_count_f
- /**
- * bcm2835_dma_create_cb_chain - create a control block and fills data in
- *
-- * @chan: the @dma_chan for which we run this
-+ * @c: the @bcm2835_chan for which we run this
- * @direction: the direction in which we transfer
- * @cyclic: it is a cyclic transfer
- * @info: the default info bits to apply per controlblock
-@@ -361,12 +468,11 @@ static inline size_t bcm2835_dma_count_f
- * @gfp: the GFP flag to use for allocation
- */
- static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
-- struct dma_chan *chan, enum dma_transfer_direction direction,
-+ struct bcm2835_chan *c, enum dma_transfer_direction direction,
- bool cyclic, u32 info, u32 finalextrainfo, size_t frames,
- dma_addr_t src, dma_addr_t dst, size_t buf_len,
- size_t period_len, gfp_t gfp)
- {
-- struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
- size_t len = buf_len, total_len;
- size_t frame;
- struct bcm2835_desc *d;
-@@ -399,11 +505,23 @@ static struct bcm2835_desc *bcm2835_dma_
-
- /* fill in the control block */
- control_block = cb_entry->cb;
-- control_block->info = info;
-- control_block->src = src;
-- control_block->dst = dst;
-- control_block->stride = 0;
-- control_block->next = 0;
-+ if (c->is_40bit_channel) {
-+ struct bcm2838_dma40_scb *scb =
-+ (struct bcm2838_dma40_scb *)control_block;
-+ scb->ti = to_bcm2838_ti(info);
-+ scb->src = lower_32_bits(src);
-+ scb->srci= upper_32_bits(src) | to_bcm2838_srci(info);
-+ scb->dst = lower_32_bits(dst);
-+ scb->dsti = upper_32_bits(dst) | to_bcm2838_dsti(info);
-+ scb->next_cb = 0;
-+ } else {
-+ control_block->info = info;
-+ control_block->src = src;
-+ control_block->dst = dst;
-+ control_block->stride = 0;
-+ control_block->next = 0;
-+ }
-+
- /* set up length in control_block if requested */
- if (buf_len) {
- /* calculate length honoring period_length */
-@@ -417,7 +535,10 @@ static struct bcm2835_desc *bcm2835_dma_
- }
-
- /* link this the last controlblock */
-- if (frame)
-+ if (frame && c->is_40bit_channel)
-+ d->cb_list[frame - 1].cb->next =
-+ to_bcm2838_cbaddr(cb_entry->paddr);
-+ if (frame && !c->is_40bit_channel)
- d->cb_list[frame - 1].cb->next = cb_entry->paddr;
-
- /* update src and dst and length */
-@@ -431,7 +552,14 @@ static struct bcm2835_desc *bcm2835_dma_
- }
-
- /* the last frame requires extra flags */
-- d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
-+ if (c->is_40bit_channel) {
-+ struct bcm2838_dma40_scb *scb =
-+ (struct bcm2838_dma40_scb *)d->cb_list[d->frames-1].cb;
-+
-+ scb->ti |= to_bcm2838_ti(finalextrainfo);
-+ } else {
-+ d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
-+ }
-
- /* detect a size missmatch */
- if (buf_len && (d->size != buf_len))
-@@ -445,28 +573,51 @@ error_cb:
- }
-
- static void bcm2835_dma_fill_cb_chain_with_sg(
-- struct dma_chan *chan,
-+ struct bcm2835_chan *c,
- enum dma_transfer_direction direction,
- struct bcm2835_cb_entry *cb,
- struct scatterlist *sgl,
- unsigned int sg_len)
- {
-- struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
- size_t len, max_len;
- unsigned int i;
- dma_addr_t addr;
- struct scatterlist *sgent;
-
-+ pr_err("dma_fill_chain_with_sg(ch %d, dir %d):\n", c->ch, direction);
-+
- max_len = bcm2835_dma_max_frame_length(c);
- for_each_sg(sgl, sgent, sg_len, i) {
-- for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent);
-- len > 0;
-- addr += cb->cb->length, len -= cb->cb->length, cb++) {
-- if (direction == DMA_DEV_TO_MEM)
-- cb->cb->dst = addr;
-- else
-- cb->cb->src = addr;
-- cb->cb->length = min(len, max_len);
-+ if (c->is_40bit_channel) {
-+ struct bcm2838_dma40_scb *scb =
-+ (struct bcm2838_dma40_scb *)cb->cb;
-+ for (addr = sg_dma_address(sgent),
-+ len = sg_dma_len(sgent);
-+ len > 0;
-+ addr += scb->len, len -= scb->len, scb++) {
-+ if (direction == DMA_DEV_TO_MEM) {
-+ scb->dst = lower_32_bits(addr);
-+ scb->dsti = upper_32_bits(addr) | BCM2838_DMA40_INC;
-+ } else {
-+ scb->src = lower_32_bits(addr);
-+ scb->srci = upper_32_bits(addr) | BCM2838_DMA40_INC;
-+ }
-+ scb->len = min(len, max_len);
-+ pr_err(" %llx, %x\n", (u64)addr, scb->len);
-+ }
-+ } else {
-+ for (addr = sg_dma_address(sgent),
-+ len = sg_dma_len(sgent);
-+ len > 0;
-+ addr += cb->cb->length, len -= cb->cb->length,
-+ cb++) {
-+ if (direction == DMA_DEV_TO_MEM)
-+ cb->cb->dst = addr;
-+ else
-+ cb->cb->src = addr;
-+ cb->cb->length = min(len, max_len);
-+ pr_err(" %llx, %x\n", (u64)addr, cb->cb->length);
-+ }
- }
- }
- }
-@@ -475,6 +626,10 @@ static int bcm2835_dma_abort(struct bcm2
- {
- void __iomem *chan_base = c->chan_base;
- long int timeout = 10000;
-+ u32 wait_mask = BCM2835_DMA_WAITING_FOR_WRITES;
-+
-+ if (c->is_40bit_channel)
-+ wait_mask = BCM2838_DMA40_WAITING_FOR_WRITES;
-
- /*
- * A zero control block address means the channel is idle.
-@@ -487,8 +642,7 @@ static int bcm2835_dma_abort(struct bcm2
- writel(0, chan_base + BCM2835_DMA_CS);
-
- /* Wait for any current AXI transfer to complete */
-- while ((readl(chan_base + BCM2835_DMA_CS) &
-- BCM2835_DMA_WAITING_FOR_WRITES) && --timeout)
-+ while ((readl(chan_base + BCM2835_DMA_CS) & wait_mask) && --timeout)
- cpu_relax();
-
- /* Peripheral might be stuck and fail to signal AXI write responses */
-@@ -505,6 +659,7 @@ static void bcm2835_dma_start_desc(struc
- struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
- struct bcm2835_desc *d;
-
-+ pr_err("dma_start_desc(%px)\n", vd);
- if (!vd) {
- c->desc = NULL;
- return;
-@@ -514,9 +669,16 @@ static void bcm2835_dma_start_desc(struc
-
- c->desc = d = to_bcm2835_dma_desc(&vd->tx);
-
-- writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
-- writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
-- c->chan_base + BCM2835_DMA_CS);
-+ if (c->is_40bit_channel) {
-+ writel(to_bcm2838_cbaddr(d->cb_list[0].paddr),
-+ c->chan_base + BCM2838_DMA40_CB);
-+ writel(BCM2838_DMA40_ACTIVE | BCM2838_DMA40_CS_FLAGS(c->dreq),
-+ c->chan_base + BCM2838_DMA40_CS);
-+ } else {
-+ writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
-+ writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
-+ c->chan_base + BCM2835_DMA_CS);
-+ }
- }
-
- static irqreturn_t bcm2835_dma_callback(int irq, void *data)
-@@ -544,7 +706,8 @@ static irqreturn_t bcm2835_dma_callback(
- * will remain idle despite the ACTIVE flag being set.
- */
- writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE |
-- BCM2835_DMA_CS_FLAGS(c->dreq),
-+ (c->is_40bit_channel ? BCM2838_DMA40_CS_FLAGS(c->dreq) :
-+ BCM2835_DMA_CS_FLAGS(c->dreq)),
- c->chan_base + BCM2835_DMA_CS);
-
- d = c->desc;
-@@ -643,9 +806,17 @@ static enum dma_status bcm2835_dma_tx_st
- struct bcm2835_desc *d = c->desc;
- dma_addr_t pos;
-
-- if (d->dir == DMA_MEM_TO_DEV)
-+ if (d->dir == DMA_MEM_TO_DEV && c->is_40bit_channel)
-+ pos = readl(c->chan_base + BCM2838_DMA40_SRC) +
-+ ((readl(c->chan_base + BCM2838_DMA40_SRCI) &
-+ 0xff) << 8);
-+ else if (d->dir == DMA_MEM_TO_DEV && !c->is_40bit_channel)
- pos = readl(c->chan_base + BCM2835_DMA_SOURCE_AD);
-- else if (d->dir == DMA_DEV_TO_MEM)
-+ else if (d->dir == DMA_DEV_TO_MEM && c->is_40bit_channel)
-+ pos = readl(c->chan_base + BCM2838_DMA40_DEST) +
-+ ((readl(c->chan_base + BCM2838_DMA40_DESTI) &
-+ 0xff) << 8);
-+ else if (d->dir == DMA_DEV_TO_MEM && !c->is_40bit_channel)
- pos = readl(c->chan_base + BCM2835_DMA_DEST_AD);
- else
- pos = 0;
-@@ -691,7 +862,7 @@ static struct dma_async_tx_descriptor *b
- frames = bcm2835_dma_frames_for_length(len, max_len);
-
- /* allocate the CB chain - this also fills in the pointers */
-- d = bcm2835_dma_create_cb_chain(chan, DMA_MEM_TO_MEM, false,
-+ d = bcm2835_dma_create_cb_chain(c, DMA_MEM_TO_MEM, false,
- info, extra, frames,
- src, dst, len, 0, GFP_KERNEL);
- if (!d)
-@@ -726,11 +897,21 @@ static struct dma_async_tx_descriptor *b
- if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
- return NULL;
- src = c->cfg.src_addr;
-+ /*
-+ * One would think it ought to be possible to get the physical
-+ * to dma address mapping information from the dma-ranges DT
-+ * property, but I've not found a way yet that doesn't involve
-+ * open-coding the whole thing.
-+ */
-+ if (c->is_40bit_channel)
-+ src |= 0x400000000ull;
- info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
- } else {
- if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
- return NULL;
- dst = c->cfg.dst_addr;
-+ if (c->is_40bit_channel)
-+ dst |= 0x400000000ull;
- info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
- }
-
-@@ -738,7 +919,7 @@ static struct dma_async_tx_descriptor *b
- frames = bcm2835_dma_count_frames_for_sg(c, sgl, sg_len);
-
- /* allocate the CB chain */
-- d = bcm2835_dma_create_cb_chain(chan, direction, false,
-+ d = bcm2835_dma_create_cb_chain(c, direction, false,
- info, extra,
- frames, src, dst, 0, 0,
- GFP_KERNEL);
-@@ -746,7 +927,7 @@ static struct dma_async_tx_descriptor *b
- return NULL;
-
- /* fill in frames with scatterlist pointers */
-- bcm2835_dma_fill_cb_chain_with_sg(chan, direction, d->cb_list,
-+ bcm2835_dma_fill_cb_chain_with_sg(c, direction, d->cb_list,
- sgl, sg_len);
-
- return vchan_tx_prep(&c->vc, &d->vd, flags);
-@@ -815,7 +996,7 @@ static struct dma_async_tx_descriptor *b
- * note that we need to use GFP_NOWAIT, as the ALSA i2s dmaengine
- * implementation calls prep_dma_cyclic with interrupts disabled.
- */
-- d = bcm2835_dma_create_cb_chain(chan, direction, true,
-+ d = bcm2835_dma_create_cb_chain(c, direction, true,
- info, extra,
- frames, src, dst, buf_len,
- period_len, GFP_NOWAIT);
-@@ -823,7 +1004,8 @@ static struct dma_async_tx_descriptor *b
- return NULL;
-
- /* wrap around into a loop */
-- d->cb_list[d->frames - 1].cb->next = d->cb_list[0].paddr;
-+ d->cb_list[d->frames - 1].cb->next = c->is_40bit_channel ?
-+ to_bcm2838_cbaddr(d->cb_list[0].paddr) : d->cb_list[0].paddr;
-
- return vchan_tx_prep(&c->vc, &d->vd, flags);
- }
-@@ -899,9 +1081,11 @@ static int bcm2835_dma_chan_init(struct
- c->irq_number = irq;
- c->irq_flags = irq_flags;
-
-- /* check in DEBUG register if this is a LITE channel */
-- if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
-- BCM2835_DMA_DEBUG_LITE)
-+ /* check for 40bit and lite channels */
-+ if (d->cfg_data->chan_40bit_mask & BIT(chan_id))
-+ c->is_40bit_channel = true;
-+ else if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
-+ BCM2835_DMA_DEBUG_LITE)
- c->is_lite_channel = true;
-
- return 0;
-@@ -918,18 +1102,16 @@ static void bcm2835_dma_free(struct bcm2
- }
- }
-
--int bcm2838_dma40_memcpy_init(struct device *dev)
-+int bcm2838_dma40_memcpy_init(void)
- {
-- if (memcpy_scb)
-- return 0;
-+ if (!memcpy_parent)
-+ return -EPROBE_DEFER;
-
-- memcpy_scb = dma_alloc_coherent(dev, sizeof(*memcpy_scb),
-- &memcpy_scb_dma, GFP_KERNEL);
-+ if (!memcpy_chan)
-+ return -EINVAL;
-
-- if (!memcpy_scb) {
-- pr_err("bcm2838_dma40_memcpy_init failed!\n");
-+ if (!memcpy_scb)
- return -ENOMEM;
-- }
-
- return 0;
- }
-@@ -956,20 +1138,22 @@ void bcm2838_dma40_memcpy(dma_addr_t dst
- scb->next_cb = 0;
-
- writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2838_DMA40_CB);
-- writel(BCM2838_DMA40_MEMCPY_QOS + BCM2838_DMA40_CS_ACTIVE,
-+ writel(BCM2838_DMA40_MEMCPY_FLAGS + BCM2838_DMA40_ACTIVE,
- memcpy_chan + BCM2838_DMA40_CS);
-+
- /* Poll for completion */
-- while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_CS_END))
-+ while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_END))
- cpu_relax();
-
-- writel(BCM2838_DMA40_CS_END, memcpy_chan + BCM2838_DMA40_CS);
-+ writel(BCM2838_DMA40_END, memcpy_chan + BCM2838_DMA40_CS);
-
- spin_unlock_irqrestore(&memcpy_lock, flags);
- }
- EXPORT_SYMBOL(bcm2838_dma40_memcpy);
-
- static const struct of_device_id bcm2835_dma_of_match[] = {
-- { .compatible = "brcm,bcm2835-dma", },
-+ { .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_cfg },
-+ { .compatible = "brcm,bcm2838-dma", .data = &bcm2838_dma_cfg },
- {},
- };
- MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
-@@ -1001,6 +1185,8 @@ static int bcm2835_dma_probe(struct plat
- int irq_flags;
- uint32_t chans_available;
- char chan_name[BCM2835_DMA_CHAN_NAME_SIZE];
-+ const struct of_device_id *of_id;
-+ int chan_count, chan_start, chan_end;
-
- if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
-@@ -1022,9 +1208,13 @@ static int bcm2835_dma_probe(struct plat
- base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-- rc = bcm_dmaman_probe(pdev, base, BCM2835_DMA_BULK_MASK);
-- if (rc)
-- dev_err(&pdev->dev, "Failed to initialize the legacy API\n");
-+
-+ /* The set of channels can be split across multiple instances. */
-+ chan_start = ((u32)base / BCM2835_DMA_CHAN_SIZE) & 0xf;
-+ base -= BCM2835_DMA_CHAN(chan_start);
-+ chan_count = resource_size(res) / BCM2835_DMA_CHAN_SIZE;
-+ chan_end = min(chan_start + chan_count,
-+ BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED + 1);
-
- od->base = base;
-
-@@ -1054,6 +1244,14 @@ static int bcm2835_dma_probe(struct plat
-
- platform_set_drvdata(pdev, od);
-
-+ of_id = of_match_node(bcm2835_dma_of_match, pdev->dev.of_node);
-+ if (!of_id) {
-+ dev_err(&pdev->dev, "Failed to match compatible string\n");
-+ return -EINVAL;
-+ }
-+
-+ od->cfg_data = of_id->data;
-+
- /* Request DMA channel mask from device tree */
- if (of_property_read_u32(pdev->dev.of_node,
- "brcm,dma-channel-mask",
-@@ -1063,18 +1261,34 @@ static int bcm2835_dma_probe(struct plat
- goto err_no_dma;
- }
-
-- /* Channel 0 is used by the legacy API */
-- chans_available &= ~BCM2835_DMA_BULK_MASK;
-+ /* One channel is reserved for the legacy API */
-+ if (chans_available & BCM2835_DMA_BULK_MASK) {
-+ rc = bcm_dmaman_probe(pdev, base,
-+ chans_available & BCM2835_DMA_BULK_MASK);
-+ if (rc)
-+ dev_err(&pdev->dev,
-+ "Failed to initialize the legacy API\n");
-+
-+ chans_available &= ~BCM2835_DMA_BULK_MASK;
-+ }
-
-- /* We can't use channels 11-13 yet */
-- chans_available &= ~(BIT(11) | BIT(12) | BIT(13));
-+ /* And possibly one for the 40-bit DMA memcpy API */
-+ if (chans_available & od->cfg_data->chan_40bit_mask &
-+ BIT(BCM2838_DMA_MEMCPY_CHAN)) {
-+ memcpy_parent = od;
-+ memcpy_chan = BCM2835_DMA_CHANIO(base, BCM2838_DMA_MEMCPY_CHAN);
-+ memcpy_scb = dma_alloc_coherent(memcpy_parent->ddev.dev,
-+ sizeof(*memcpy_scb),
-+ &memcpy_scb_dma, GFP_KERNEL);
-+ if (!memcpy_scb)
-+ dev_warn(&pdev->dev,
-+ "Failed to allocated memcpy scb\n");
-
-- /* Grab channel 14 for the 40-bit DMA memcpy */
-- chans_available &= ~BIT(14);
-- memcpy_chan = BCM2835_DMA_CHANIO(base, 14);
-+ chans_available &= ~BIT(BCM2838_DMA_MEMCPY_CHAN);
-+ }
-
- /* get irqs for each channel that we support */
-- for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
-+ for (i = chan_start; i < chan_end; i++) {
- /* skip masked out channels */
- if (!(chans_available & (1 << i))) {
- irq[i] = -1;
-@@ -1097,13 +1311,17 @@ static int bcm2835_dma_probe(struct plat
- irq[i] = platform_get_irq(pdev, i < 11 ? i : 11);
- }
-
-+ chan_count = 0;
-+
- /* get irqs for each channel */
-- for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
-+ for (i = chan_start; i < chan_end; i++) {
- /* skip channels without irq */
- if (irq[i] < 0)
- continue;
-
- /* check if there are other channels that also use this irq */
-+ /* FIXME: This will fail if interrupts are shared across
-+ instances */
- irq_flags = 0;
- for (j = 0; j <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; j++)
- if ((i != j) && (irq[j] == irq[i])) {
-@@ -1115,9 +1333,10 @@ static int bcm2835_dma_probe(struct plat
- rc = bcm2835_dma_chan_init(od, i, irq[i], irq_flags);
- if (rc)
- goto err_no_dma;
-+ chan_count++;
- }
-
-- dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i);
-+ dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", chan_count);
-
- /* Device-tree DMA controller registration */
- rc = of_dma_controller_register(pdev->dev.of_node,
-@@ -1149,6 +1368,13 @@ static int bcm2835_dma_remove(struct pla
-
- bcm_dmaman_remove(pdev);
- dma_async_device_unregister(&od->ddev);
-+ if (memcpy_parent == od) {
-+ dma_free_coherent(&pdev->dev, sizeof(*memcpy_scb), memcpy_scb,
-+ memcpy_scb_dma);
-+ memcpy_parent = NULL;
-+ memcpy_scb = NULL;
-+ memcpy_chan = NULL;
-+ }
- bcm2835_dma_free(od);
-
- return 0;
---- a/drivers/pci/controller/pcie-brcmstb-bounce.c
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.c
-@@ -91,7 +91,7 @@ struct dmabounce_device_info {
-
- static struct dmabounce_device_info *g_dmabounce_device_info;
-
--extern int bcm2838_dma40_memcpy_init(struct device *dev);
-+extern int bcm2838_dma40_memcpy_init(void);
- extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-
- #ifdef STATS
-@@ -471,9 +471,9 @@ static const struct dma_map_ops dmabounc
- .mapping_error = dmabounce_mapping_error,
- };
-
--int brcm_pcie_bounce_register_dev(struct device *dev,
-- unsigned long buffer_size,
-- dma_addr_t threshold)
-+int brcm_pcie_bounce_init(struct device *dev,
-+ unsigned long buffer_size,
-+ dma_addr_t threshold)
- {
- struct dmabounce_device_info *device_info;
- int ret;
-@@ -482,9 +482,9 @@ int brcm_pcie_bounce_register_dev(struct
- if (g_dmabounce_device_info)
- return -EBUSY;
-
-- ret = bcm2838_dma40_memcpy_init(dev);
-+ ret = bcm2838_dma40_memcpy_init();
- if (ret)
-- return ret;
-+ return ret;
-
- device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
- if (!device_info) {
-@@ -515,9 +515,8 @@ int brcm_pcie_bounce_register_dev(struct
- device_create_file(dev, &dev_attr_dmabounce_stats));
-
- g_dmabounce_device_info = device_info;
-- set_dma_ops(dev, &dmabounce_ops);
-
-- dev_info(dev, "dmabounce: registered device - %ld kB, threshold %pad\n",
-+ dev_info(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
- buffer_size / 1024, &threshold);
-
- return 0;
-@@ -526,14 +525,13 @@ int brcm_pcie_bounce_register_dev(struct
- kfree(device_info);
- return ret;
- }
--EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
-+EXPORT_SYMBOL(brcm_pcie_bounce_init);
-
--void brcm_pcie_bounce_unregister_dev(struct device *dev)
-+void brcm_pcie_bounce_uninit(struct device *dev)
- {
- struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-
- g_dmabounce_device_info = NULL;
-- set_dma_ops(dev, NULL);
-
- if (!device_info) {
- dev_warn(dev,
-@@ -554,10 +552,16 @@ void brcm_pcie_bounce_unregister_dev(str
- device_remove_file(dev, &dev_attr_dmabounce_stats));
-
- kfree(device_info);
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_uninit);
-+
-+int brcm_pcie_bounce_register_dev(struct device *dev)
-+{
-+ set_dma_ops(dev, &dmabounce_ops);
-
-- dev_info(dev, "dmabounce: device unregistered\n");
-+ return 0;
- }
--EXPORT_SYMBOL(brcm_pcie_bounce_unregister_dev);
-+EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
-
- MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
---- a/drivers/pci/controller/pcie-brcmstb-bounce.h
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
-@@ -8,21 +8,26 @@
-
- #ifdef CONFIG_ARM
-
--int brcm_pcie_bounce_register_dev(struct device *dev, unsigned long buffer_size,
-- dma_addr_t threshold);
--
--int brcm_pcie_bounce_unregister_dev(struct device *dev);
-+int brcm_pcie_bounce_init(struct device *dev, unsigned long buffer_size,
-+ dma_addr_t threshold);
-+int brcm_pcie_bounce_uninit(struct device *dev);
-+int brcm_pcie_bounce_register_dev(struct device *dev);
-
- #else
-
--static inline int brcm_pcie_bounce_register_dev(struct device *dev,
-- unsigned long buffer_size,
-- dma_addr_t threshold)
-+static inline int brcm_pcie_bounce_init(struct device *dev,
-+ unsigned long buffer_size,
-+ dma_addr_t threshold)
-+{
-+ return 0;
-+}
-+
-+static inline int brcm_pcie_bounce_uninit(struct device *dev)
- {
- return 0;
- }
-
--static inline int brcm_pcie_bounce_unregister_dev(struct device *dev)
-+static inline int brcm_pcie_bounce_register_dev(struct device *dev)
- {
- return 0;
- }
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -650,6 +650,7 @@ static void brcm_set_dma_ops(struct devi
-
- static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
- unsigned int val);
-+
- static int brcmstb_platform_notifier(struct notifier_block *nb,
- unsigned long event, void *__dev)
- {
-@@ -663,12 +664,11 @@ static int brcmstb_platform_notifier(str
- strcmp(dev->kobj.name, rc_name)) {
- int ret;
-
-- ret = brcm_pcie_bounce_register_dev(dev, bounce_buffer,
-- (dma_addr_t)bounce_threshold);
-+ ret = brcm_pcie_bounce_register_dev(dev);
- if (ret) {
- dev_err(dev,
- "brcm_pcie_bounce_register_dev() failed: %d\n",
-- ret);
-+ ret);
- return ret;
- }
- }
-@@ -681,8 +681,6 @@ static int brcmstb_platform_notifier(str
- brcm_pcie_perst_set(g_pcie, 1);
- msleep(100);
- brcm_pcie_perst_set(g_pcie, 0);
-- } else if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-- brcm_pcie_bounce_unregister_dev(dev);
- }
- return NOTIFY_OK;
-
-@@ -1718,6 +1716,7 @@ static int brcm_pcie_probe(struct platfo
- void __iomem *base;
- struct pci_host_bridge *bridge;
- struct pci_bus *child;
-+ extern unsigned long max_pfn;
-
- bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
- if (!bridge)
-@@ -1753,6 +1752,20 @@ static int brcm_pcie_probe(struct platfo
- if (IS_ERR(base))
- return PTR_ERR(base);
-
-+ /* To Do: Add hardware check if this ever gets fixed */
-+ if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-+ int ret;
-+ ret = brcm_pcie_bounce_init(&pdev->dev, bounce_buffer,
-+ (dma_addr_t)bounce_threshold);
-+ if (ret) {
-+ if (ret != -EPROBE_DEFER)
-+ dev_err(&pdev->dev,
-+ "could not init bounce buffers: %d\n",
-+ ret);
-+ return ret;
-+ }
-+ }
-+
- pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
- if (IS_ERR(pcie->clk)) {
- dev_warn(&pdev->dev, "could not get clock\n");
+++ /dev/null
-From db81536216256cdd4b8a17879e6628be47c74414 Mon Sep 17 00:00:00 2001
-Date: Wed, 5 Jun 2019 21:32:03 +0100
-Subject: [PATCH] BCM270X_DT: Leave bulk channel in dma channel mask
-
-The updated bcm2835-dma driver does not require the BULK channel
-to be removed from the set of available channels, as provided by
-dma-channel-mask.
-
----
- arch/arm/boot/dts/bcm2708-rpi.dtsi | 4 ----
- 1 file changed, 4 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
-@@ -124,10 +124,6 @@
- };
- };
-
--&dma {
-- brcm,dma-channel-mask = <0x7f34>;
--};
--
- &hdmi {
- power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
- };
--- /dev/null
+From 2fcb94a04778708b13b6d36390000e97063460e6 Mon Sep 17 00:00:00 2001
+Date: Fri, 31 May 2019 17:57:26 +0100
+Subject: [PATCH] dts: Include CSI lane config for csi1
+
+Without the include the peripheral is configured to have 0
+data lanes, which doesn't allow much data to be passed.
+
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -1,6 +1,7 @@
+ /dts-v1/;
+
+ #include "bcm2711.dtsi"
++#include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+ compatible = "raspberrypi,4-model-b", "brcm,bcm2838", "brcm,bcm2837";
+++ /dev/null
-From eecf4b8568f0a0d6b90364299eed6b12ce63c245 Mon Sep 17 00:00:00 2001
-Date: Thu, 6 Jun 2019 09:35:08 +0100
-Subject: [PATCH] SQUASH: bcm2835-dma: Remove debugging
-
----
- drivers/dma/bcm2835-dma.c | 5 -----
- 1 file changed, 5 deletions(-)
-
---- a/drivers/dma/bcm2835-dma.c
-+++ b/drivers/dma/bcm2835-dma.c
-@@ -584,8 +584,6 @@ static void bcm2835_dma_fill_cb_chain_wi
- dma_addr_t addr;
- struct scatterlist *sgent;
-
-- pr_err("dma_fill_chain_with_sg(ch %d, dir %d):\n", c->ch, direction);
--
- max_len = bcm2835_dma_max_frame_length(c);
- for_each_sg(sgl, sgent, sg_len, i) {
- if (c->is_40bit_channel) {
-@@ -603,7 +601,6 @@ static void bcm2835_dma_fill_cb_chain_wi
- scb->srci = upper_32_bits(addr) | BCM2838_DMA40_INC;
- }
- scb->len = min(len, max_len);
-- pr_err(" %llx, %x\n", (u64)addr, scb->len);
- }
- } else {
- for (addr = sg_dma_address(sgent),
-@@ -616,7 +613,6 @@ static void bcm2835_dma_fill_cb_chain_wi
- else
- cb->cb->src = addr;
- cb->cb->length = min(len, max_len);
-- pr_err(" %llx, %x\n", (u64)addr, cb->cb->length);
- }
- }
- }
-@@ -659,7 +655,6 @@ static void bcm2835_dma_start_desc(struc
- struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
- struct bcm2835_desc *d;
-
-- pr_err("dma_start_desc(%px)\n", vd);
- if (!vd) {
- c->desc = NULL;
- return;
--- /dev/null
+From ba21a5129def696c154c84df087f07bc748abe7d Mon Sep 17 00:00:00 2001
+Date: Fri, 7 Jun 2019 11:31:21 +0100
+Subject: [PATCH] drm/vc4: Fix T-format modifiers in FKMS.
+
+The wrong vc_image formats were being checked for in the switch
+statement. Correct these.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -458,10 +458,10 @@ static void vc4_plane_atomic_update(stru
+ switch (fb->modifier) {
+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+ switch (mb->plane.vc_image_type) {
+- case VC_IMAGE_RGBX32:
++ case VC_IMAGE_XRGB8888:
+ mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32;
+ break;
+- case VC_IMAGE_RGBA32:
++ case VC_IMAGE_ARGB8888:
+ mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
+ break;
+ case VC_IMAGE_RGB565:
--- /dev/null
+From 27fc1dbeee2a58abcb80ffc1c8f161d3abfeac9a Mon Sep 17 00:00:00 2001
+Date: Mon, 10 Jun 2019 17:22:44 +0100
+Subject: [PATCH] bcm2711 dts: Disable the v3d node by default
+
+---
+ arch/arm/boot/dts/bcm2711.dtsi | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2711.dtsi
++++ b/arch/arm/boot/dts/bcm2711.dtsi
+@@ -13,6 +13,10 @@
+ };
+ };
+
++&v3d {
++ status = "disabled";
++};
++
+ &dma {
+ brcm,dma-channel-mask = <0x7ef5>;
+ };
+++ /dev/null
-From 2fcb94a04778708b13b6d36390000e97063460e6 Mon Sep 17 00:00:00 2001
-Date: Fri, 31 May 2019 17:57:26 +0100
-Subject: [PATCH] dts: Include CSI lane config for csi1
-
-Without the include the peripheral is configured to have 0
-data lanes, which doesn't allow much data to be passed.
-
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -1,6 +1,7 @@
- /dts-v1/;
-
- #include "bcm2711.dtsi"
-+#include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
- compatible = "raspberrypi,4-model-b", "brcm,bcm2838", "brcm,bcm2837";
+++ /dev/null
-From ba21a5129def696c154c84df087f07bc748abe7d Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Jun 2019 11:31:21 +0100
-Subject: [PATCH] drm/vc4: Fix T-format modifiers in FKMS.
-
-The wrong vc_image formats were being checked for in the switch
-statement. Correct these.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -458,10 +458,10 @@ static void vc4_plane_atomic_update(stru
- switch (fb->modifier) {
- case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
- switch (mb->plane.vc_image_type) {
-- case VC_IMAGE_RGBX32:
-+ case VC_IMAGE_XRGB8888:
- mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32;
- break;
-- case VC_IMAGE_RGBA32:
-+ case VC_IMAGE_ARGB8888:
- mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
- break;
- case VC_IMAGE_RGB565:
--- /dev/null
+From d4a180e5b67c3ca9b8559d4f926f22b6c6705082 Mon Sep 17 00:00:00 2001
+Date: Mon, 10 Jun 2019 16:32:51 +0100
+Subject: [PATCH] drm/vc4: Remove 340MHz clock limit from FKMS now
+ scrambling issues resolved
+
+Firmware TMDS scrambling is now being correctly configured, so
+we can use it.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -830,12 +830,6 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ break;
+ }
+
+- /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling
+- * working.
+- */
+- if (mode->clock > 340000)
+- return MODE_CLOCK_HIGH;
+-
+ return MODE_OK;
+ }
+
+++ /dev/null
-From 27fc1dbeee2a58abcb80ffc1c8f161d3abfeac9a Mon Sep 17 00:00:00 2001
-Date: Mon, 10 Jun 2019 17:22:44 +0100
-Subject: [PATCH] bcm2711 dts: Disable the v3d node by default
-
----
- arch/arm/boot/dts/bcm2711.dtsi | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/arch/arm/boot/dts/bcm2711.dtsi
-+++ b/arch/arm/boot/dts/bcm2711.dtsi
-@@ -13,6 +13,10 @@
- };
- };
-
-+&v3d {
-+ status = "disabled";
-+};
-+
- &dma {
- brcm,dma-channel-mask = <0x7ef5>;
- };
--- /dev/null
+From f9c01b35ec7ea3f981c414af38c92c508487671a Mon Sep 17 00:00:00 2001
+Date: Tue, 11 Jun 2019 10:55:00 +0100
+Subject: [PATCH] usb: add plumbing for updating interrupt endpoint
+ interval state
+
+xHCI caches device and endpoint data after the interface is configured,
+so an explicit command needs to be issued for any device driver wanting
+to alter the polling interval of an endpoint.
+
+Add usb_fixup_endpoint() to allow drivers to do this. The fixup must be
+called after calculating endpoint bandwidth requirements but before any
+URBs are submitted.
+
+If polling intervals are shortened, any bandwidth reservations are no
+longer valid but in practice polling intervals are only ever relaxed.
+
+Limit the scope to interrupt transfers for now.
+
+---
+ drivers/usb/core/hcd.c | 10 ++++++++++
+ drivers/usb/core/message.c | 15 +++++++++++++++
+ include/linux/usb.h | 2 ++
+ include/linux/usb/hcd.h | 7 +++++++
+ 4 files changed, 34 insertions(+)
+
+--- a/drivers/usb/core/hcd.c
++++ b/drivers/usb/core/hcd.c
+@@ -2071,6 +2071,16 @@ reset:
+ return ret;
+ }
+
++void usb_hcd_fixup_endpoint(struct usb_device *udev,
++ struct usb_host_endpoint *ep, int interval)
++{
++ struct usb_hcd *hcd;
++
++ hcd = bus_to_hcd(udev->bus);
++ if (hcd->driver->fixup_endpoint)
++ hcd->driver->fixup_endpoint(hcd, udev, ep, interval);
++}
++
+ /* Disables the endpoint: synchronizes with the hcd to make sure all
+ * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
+ * have been called previously. Use for set_configuration, set_interface,
+--- a/drivers/usb/core/message.c
++++ b/drivers/usb/core/message.c
+@@ -1113,6 +1113,21 @@ static void remove_intf_ep_devs(struct u
+ intf->ep_devs_created = 0;
+ }
+
++void usb_fixup_endpoint(struct usb_device *dev, int epaddr, int interval)
++{
++ unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
++ struct usb_host_endpoint *ep;
++
++ if (usb_endpoint_out(epaddr))
++ ep = dev->ep_out[epnum];
++ else
++ ep = dev->ep_in[epnum];
++
++ if (ep && usb_endpoint_xfer_int(&ep->desc))
++ usb_hcd_fixup_endpoint(dev, ep, interval);
++}
++EXPORT_SYMBOL_GPL(usb_fixup_endpoint);
++
+ /**
+ * usb_disable_endpoint -- Disable an endpoint by address
+ * @dev: the device whose endpoint is being disabled
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -1809,6 +1809,8 @@ extern int usb_clear_halt(struct usb_dev
+ extern int usb_reset_configuration(struct usb_device *dev);
+ extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
+ extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr);
++extern void usb_fixup_endpoint(struct usb_device *dev, int epaddr,
++ int interval);
+
+ /* this request isn't really synchronous, but it belongs with the others */
+ extern int usb_driver_set_configuration(struct usb_device *udev, int config);
+--- a/include/linux/usb/hcd.h
++++ b/include/linux/usb/hcd.h
+@@ -379,6 +379,11 @@ struct hc_driver {
+ * or bandwidth constraints.
+ */
+ void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
++ /* Override the endpoint-derived interval
++ * (if there is any cached hardware state).
++ */
++ void (*fixup_endpoint)(struct usb_hcd *hcd, struct usb_device *udev,
++ struct usb_host_endpoint *ep, int interval);
+ /* Returns the hardware-chosen device address */
+ int (*address_device)(struct usb_hcd *, struct usb_device *udev);
+ /* prepares the hardware to send commands to the device */
+@@ -435,6 +440,8 @@ extern void usb_hcd_unmap_urb_setup_for_
+ extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *, struct urb *);
+ extern void usb_hcd_flush_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep);
++extern void usb_hcd_fixup_endpoint(struct usb_device *udev,
++ struct usb_host_endpoint *ep, int interval);
+ extern void usb_hcd_disable_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+ extern void usb_hcd_reset_endpoint(struct usb_device *udev,
+++ /dev/null
-From d4a180e5b67c3ca9b8559d4f926f22b6c6705082 Mon Sep 17 00:00:00 2001
-Date: Mon, 10 Jun 2019 16:32:51 +0100
-Subject: [PATCH] drm/vc4: Remove 340MHz clock limit from FKMS now
- scrambling issues resolved
-
-Firmware TMDS scrambling is now being correctly configured, so
-we can use it.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 ------
- 1 file changed, 6 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -830,12 +830,6 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
- break;
- }
-
-- /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling
-- * working.
-- */
-- if (mode->clock > 340000)
-- return MODE_CLOCK_HIGH;
--
- return MODE_OK;
- }
-
--- /dev/null
+From 903af89ac9a9b82b6e736ab04e3848672a0ab364 Mon Sep 17 00:00:00 2001
+Date: Tue, 11 Jun 2019 11:33:39 +0100
+Subject: [PATCH] xhci: implement xhci_fixup_endpoint for interval
+ adjustments
+
+Must be called in a non-atomic context, after the endpoint
+has been registered with the hardware via xhci_add_endpoint
+and before the first URB is submitted for the endpoint.
+
+---
+ drivers/usb/host/xhci.c | 98 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 98 insertions(+)
+
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -1425,6 +1425,103 @@ command_cleanup:
+ }
+
+ /*
++ * RPI: Fixup endpoint intervals when requested
++ * - Check interval versus the (cached) endpoint context
++ * - set the endpoint interval to the new value
++ * - force an endpoint configure command
++ * XXX: bandwidth is not recalculated. We should probably do that.
++ */
++static void xhci_fixup_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
++ struct usb_host_endpoint *ep, int interval)
++{
++ struct xhci_hcd *xhci;
++ struct xhci_ep_ctx *ep_ctx_out, *ep_ctx_in;
++ struct xhci_command *command;
++ struct xhci_input_control_ctx *ctrl_ctx;
++ struct xhci_virt_device *vdev;
++ int xhci_interval;
++ int ret;
++ int ep_index;
++ unsigned long flags;
++ u32 ep_info_tmp;
++
++ xhci = hcd_to_xhci(hcd);
++ ep_index = xhci_get_endpoint_index(&ep->desc);
++
++ /* FS/LS interval translations */
++ if ((udev->speed == USB_SPEED_FULL ||
++ udev->speed == USB_SPEED_LOW))
++ interval *= 8;
++
++ mutex_lock(&xhci->mutex);
++
++ spin_lock_irqsave(&xhci->lock, flags);
++
++ vdev = xhci->devs[udev->slot_id];
++ /* Get context-derived endpoint interval */
++ ep_ctx_out = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index);
++ ep_ctx_in = xhci_get_ep_ctx(xhci, vdev->in_ctx, ep_index);
++ xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx_out->ep_info));
++
++ if (interval == xhci_interval) {
++ spin_unlock_irqrestore(&xhci->lock, flags);
++ mutex_unlock(&xhci->mutex);
++ return;
++ }
++
++ xhci_dbg(xhci, "Fixup interval=%d xhci_interval=%d\n",
++ interval, xhci_interval);
++ command = xhci_alloc_command_with_ctx(xhci, true, GFP_ATOMIC);
++ if (!command) {
++ /* Failure here is benign, poll at the original rate */
++ spin_unlock_irqrestore(&xhci->lock, flags);
++ mutex_unlock(&xhci->mutex);
++ return;
++ }
++
++ /* xHCI uses exponents for intervals... */
++ xhci_interval = fls(interval) - 1;
++ xhci_interval = clamp_val(xhci_interval, 3, 10);
++ ep_info_tmp = le32_to_cpu(ep_ctx_out->ep_info);
++ ep_info_tmp &= ~EP_INTERVAL(255);
++ ep_info_tmp |= EP_INTERVAL(xhci_interval);
++
++ /* Keep the endpoint context up-to-date while issuing the command. */
++ xhci_endpoint_copy(xhci, vdev->in_ctx,
++ vdev->out_ctx, ep_index);
++ ep_ctx_in->ep_info = cpu_to_le32(ep_info_tmp);
++
++ /*
++ * We need to drop the lock, so take an explicit copy
++ * of the ep context.
++ */
++ xhci_endpoint_copy(xhci, command->in_ctx, vdev->in_ctx, ep_index);
++
++ ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
++ if (!ctrl_ctx) {
++ xhci_warn(xhci,
++ "%s: Could not get input context, bad type.\n",
++ __func__);
++ spin_unlock_irqrestore(&xhci->lock, flags);
++ xhci_free_command(xhci, command);
++ mutex_unlock(&xhci->mutex);
++ return;
++ }
++ ctrl_ctx->add_flags = xhci_get_endpoint_flag_from_index(ep_index);
++ ctrl_ctx->drop_flags = 0;
++
++ spin_unlock_irqrestore(&xhci->lock, flags);
++
++ ret = xhci_configure_endpoint(xhci, udev, command,
++ false, false);
++ if (ret)
++ xhci_warn(xhci, "%s: Configure endpoint failed: %d\n",
++ __func__, ret);
++ xhci_free_command(xhci, command);
++ mutex_unlock(&xhci->mutex);
++}
++
++/*
+ * non-error returns are a promise to giveback() the urb later
+ * we drop ownership so next owner (or urb unlink) can get it
+ */
+@@ -5217,6 +5314,7 @@ static const struct hc_driver xhci_hc_dr
+ .endpoint_reset = xhci_endpoint_reset,
+ .check_bandwidth = xhci_check_bandwidth,
+ .reset_bandwidth = xhci_reset_bandwidth,
++ .fixup_endpoint = xhci_fixup_endpoint,
+ .address_device = xhci_address_device,
+ .enable_device = xhci_enable_device,
+ .update_hub_device = xhci_update_hub_device,
+++ /dev/null
-From f9c01b35ec7ea3f981c414af38c92c508487671a Mon Sep 17 00:00:00 2001
-Date: Tue, 11 Jun 2019 10:55:00 +0100
-Subject: [PATCH] usb: add plumbing for updating interrupt endpoint
- interval state
-
-xHCI caches device and endpoint data after the interface is configured,
-so an explicit command needs to be issued for any device driver wanting
-to alter the polling interval of an endpoint.
-
-Add usb_fixup_endpoint() to allow drivers to do this. The fixup must be
-called after calculating endpoint bandwidth requirements but before any
-URBs are submitted.
-
-If polling intervals are shortened, any bandwidth reservations are no
-longer valid but in practice polling intervals are only ever relaxed.
-
-Limit the scope to interrupt transfers for now.
-
----
- drivers/usb/core/hcd.c | 10 ++++++++++
- drivers/usb/core/message.c | 15 +++++++++++++++
- include/linux/usb.h | 2 ++
- include/linux/usb/hcd.h | 7 +++++++
- 4 files changed, 34 insertions(+)
-
---- a/drivers/usb/core/hcd.c
-+++ b/drivers/usb/core/hcd.c
-@@ -2071,6 +2071,16 @@ reset:
- return ret;
- }
-
-+void usb_hcd_fixup_endpoint(struct usb_device *udev,
-+ struct usb_host_endpoint *ep, int interval)
-+{
-+ struct usb_hcd *hcd;
-+
-+ hcd = bus_to_hcd(udev->bus);
-+ if (hcd->driver->fixup_endpoint)
-+ hcd->driver->fixup_endpoint(hcd, udev, ep, interval);
-+}
-+
- /* Disables the endpoint: synchronizes with the hcd to make sure all
- * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
- * have been called previously. Use for set_configuration, set_interface,
---- a/drivers/usb/core/message.c
-+++ b/drivers/usb/core/message.c
-@@ -1113,6 +1113,21 @@ static void remove_intf_ep_devs(struct u
- intf->ep_devs_created = 0;
- }
-
-+void usb_fixup_endpoint(struct usb_device *dev, int epaddr, int interval)
-+{
-+ unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
-+ struct usb_host_endpoint *ep;
-+
-+ if (usb_endpoint_out(epaddr))
-+ ep = dev->ep_out[epnum];
-+ else
-+ ep = dev->ep_in[epnum];
-+
-+ if (ep && usb_endpoint_xfer_int(&ep->desc))
-+ usb_hcd_fixup_endpoint(dev, ep, interval);
-+}
-+EXPORT_SYMBOL_GPL(usb_fixup_endpoint);
-+
- /**
- * usb_disable_endpoint -- Disable an endpoint by address
- * @dev: the device whose endpoint is being disabled
---- a/include/linux/usb.h
-+++ b/include/linux/usb.h
-@@ -1809,6 +1809,8 @@ extern int usb_clear_halt(struct usb_dev
- extern int usb_reset_configuration(struct usb_device *dev);
- extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
- extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr);
-+extern void usb_fixup_endpoint(struct usb_device *dev, int epaddr,
-+ int interval);
-
- /* this request isn't really synchronous, but it belongs with the others */
- extern int usb_driver_set_configuration(struct usb_device *udev, int config);
---- a/include/linux/usb/hcd.h
-+++ b/include/linux/usb/hcd.h
-@@ -379,6 +379,11 @@ struct hc_driver {
- * or bandwidth constraints.
- */
- void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
-+ /* Override the endpoint-derived interval
-+ * (if there is any cached hardware state).
-+ */
-+ void (*fixup_endpoint)(struct usb_hcd *hcd, struct usb_device *udev,
-+ struct usb_host_endpoint *ep, int interval);
- /* Returns the hardware-chosen device address */
- int (*address_device)(struct usb_hcd *, struct usb_device *udev);
- /* prepares the hardware to send commands to the device */
-@@ -435,6 +440,8 @@ extern void usb_hcd_unmap_urb_setup_for_
- extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *, struct urb *);
- extern void usb_hcd_flush_endpoint(struct usb_device *udev,
- struct usb_host_endpoint *ep);
-+extern void usb_hcd_fixup_endpoint(struct usb_device *udev,
-+ struct usb_host_endpoint *ep, int interval);
- extern void usb_hcd_disable_endpoint(struct usb_device *udev,
- struct usb_host_endpoint *ep);
- extern void usb_hcd_reset_endpoint(struct usb_device *udev,
--- /dev/null
+From f2c46d48d1aa0f7b87b179434162eac6624122f7 Mon Sep 17 00:00:00 2001
+Date: Tue, 11 Jun 2019 11:42:03 +0100
+Subject: [PATCH] usbhid: call usb_fixup_endpoint after mangling
+ intervals
+
+Lets the mousepoll override mechanism work with xhci.
+
+---
+ drivers/hid/usbhid/hid-core.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/hid/usbhid/hid-core.c
++++ b/drivers/hid/usbhid/hid-core.c
+@@ -1118,6 +1118,7 @@ static int usbhid_start(struct hid_devic
+ interval = hid_kbpoll_interval;
+ break;
+ }
++ usb_fixup_endpoint(dev, endpoint->bEndpointAddress, interval);
+
+ ret = -ENOMEM;
+ if (usb_endpoint_dir_in(endpoint)) {
--- /dev/null
+From 77ae227664bc2460a5341be765044d0b8fb184ac Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Jun 2019 12:14:30 +0100
+Subject: [PATCH] drm: vc4: Add status of which display is updated
+ through vblank
+
+Previously multiple displays were slaved off the same SMI
+interrupt, triggered by HVS channel 1 (HDMI0).
+This doesn't work if you only have a DPI or DSI screen (HVS channel
+0), and gives slightly erroneous results with dual HDMI as the
+events for HDMI1 are incorrect.
+
+Use SMIDSW0 and SMIDSW1 registers to denote which display has
+triggered the vblank.
+Handling should be backwards compatible with older firmware.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 41 ++++++++++++++++++++++----
+ 1 file changed, 36 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -230,8 +230,13 @@ static const struct vc_image_format *vc4
+ * hardware, which has only this one register.
+ */
+ #define SMICS 0x0
++#define SMIDSW0 0x14
++#define SMIDSW1 0x1C
+ #define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11))
+
++/* Flag to denote that the firmware is giving multiple display callbacks */
++#define SMI_NEW 0xabcd0000
++
+ #define vc4_crtc vc4_kms_crtc
+ #define to_vc4_crtc to_vc4_kms_crtc
+ struct vc4_crtc {
+@@ -884,16 +889,42 @@ static irqreturn_t vc4_crtc_irq_handler(
+ int i;
+ u32 stat = readl(crtc_list[0]->regs + SMICS);
+ irqreturn_t ret = IRQ_NONE;
++ u32 chan;
+
+ if (stat & SMICS_INTERRUPTS) {
+ writel(0, crtc_list[0]->regs + SMICS);
+
+- for (i = 0; crtc_list[i]; i++) {
+- if (crtc_list[i]->vblank_enabled)
+- drm_crtc_handle_vblank(&crtc_list[i]->base);
+- vc4_crtc_handle_page_flip(crtc_list[i]);
+- ret = IRQ_HANDLED;
++ chan = readl(crtc_list[0]->regs + SMIDSW0);
++
++ if ((chan & 0xFFFF0000) != SMI_NEW) {
++ /* Older firmware. Treat the one interrupt as vblank/
++ * complete for all crtcs.
++ */
++ for (i = 0; crtc_list[i]; i++) {
++ if (crtc_list[i]->vblank_enabled)
++ drm_crtc_handle_vblank(&crtc_list[i]->base);
++ vc4_crtc_handle_page_flip(crtc_list[i]);
++ }
++ } else {
++ if (chan & 1) {
++ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW0);
++ if (crtc_list[0]->vblank_enabled)
++ drm_crtc_handle_vblank(&crtc_list[0]->base);
++ vc4_crtc_handle_page_flip(crtc_list[0]);
++ }
++
++ /* Check for the secondary display too */
++ chan = readl(crtc_list[0]->regs + SMIDSW1);
++
++ if (chan & 1) {
++ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
++ if (crtc_list[1]->vblank_enabled)
++ drm_crtc_handle_vblank(&crtc_list[1]->base);
++ vc4_crtc_handle_page_flip(crtc_list[1]);
++ }
+ }
++
++ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+++ /dev/null
-From 903af89ac9a9b82b6e736ab04e3848672a0ab364 Mon Sep 17 00:00:00 2001
-Date: Tue, 11 Jun 2019 11:33:39 +0100
-Subject: [PATCH] xhci: implement xhci_fixup_endpoint for interval
- adjustments
-
-Must be called in a non-atomic context, after the endpoint
-has been registered with the hardware via xhci_add_endpoint
-and before the first URB is submitted for the endpoint.
-
----
- drivers/usb/host/xhci.c | 98 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 98 insertions(+)
-
---- a/drivers/usb/host/xhci.c
-+++ b/drivers/usb/host/xhci.c
-@@ -1425,6 +1425,103 @@ command_cleanup:
- }
-
- /*
-+ * RPI: Fixup endpoint intervals when requested
-+ * - Check interval versus the (cached) endpoint context
-+ * - set the endpoint interval to the new value
-+ * - force an endpoint configure command
-+ * XXX: bandwidth is not recalculated. We should probably do that.
-+ */
-+static void xhci_fixup_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
-+ struct usb_host_endpoint *ep, int interval)
-+{
-+ struct xhci_hcd *xhci;
-+ struct xhci_ep_ctx *ep_ctx_out, *ep_ctx_in;
-+ struct xhci_command *command;
-+ struct xhci_input_control_ctx *ctrl_ctx;
-+ struct xhci_virt_device *vdev;
-+ int xhci_interval;
-+ int ret;
-+ int ep_index;
-+ unsigned long flags;
-+ u32 ep_info_tmp;
-+
-+ xhci = hcd_to_xhci(hcd);
-+ ep_index = xhci_get_endpoint_index(&ep->desc);
-+
-+ /* FS/LS interval translations */
-+ if ((udev->speed == USB_SPEED_FULL ||
-+ udev->speed == USB_SPEED_LOW))
-+ interval *= 8;
-+
-+ mutex_lock(&xhci->mutex);
-+
-+ spin_lock_irqsave(&xhci->lock, flags);
-+
-+ vdev = xhci->devs[udev->slot_id];
-+ /* Get context-derived endpoint interval */
-+ ep_ctx_out = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index);
-+ ep_ctx_in = xhci_get_ep_ctx(xhci, vdev->in_ctx, ep_index);
-+ xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx_out->ep_info));
-+
-+ if (interval == xhci_interval) {
-+ spin_unlock_irqrestore(&xhci->lock, flags);
-+ mutex_unlock(&xhci->mutex);
-+ return;
-+ }
-+
-+ xhci_dbg(xhci, "Fixup interval=%d xhci_interval=%d\n",
-+ interval, xhci_interval);
-+ command = xhci_alloc_command_with_ctx(xhci, true, GFP_ATOMIC);
-+ if (!command) {
-+ /* Failure here is benign, poll at the original rate */
-+ spin_unlock_irqrestore(&xhci->lock, flags);
-+ mutex_unlock(&xhci->mutex);
-+ return;
-+ }
-+
-+ /* xHCI uses exponents for intervals... */
-+ xhci_interval = fls(interval) - 1;
-+ xhci_interval = clamp_val(xhci_interval, 3, 10);
-+ ep_info_tmp = le32_to_cpu(ep_ctx_out->ep_info);
-+ ep_info_tmp &= ~EP_INTERVAL(255);
-+ ep_info_tmp |= EP_INTERVAL(xhci_interval);
-+
-+ /* Keep the endpoint context up-to-date while issuing the command. */
-+ xhci_endpoint_copy(xhci, vdev->in_ctx,
-+ vdev->out_ctx, ep_index);
-+ ep_ctx_in->ep_info = cpu_to_le32(ep_info_tmp);
-+
-+ /*
-+ * We need to drop the lock, so take an explicit copy
-+ * of the ep context.
-+ */
-+ xhci_endpoint_copy(xhci, command->in_ctx, vdev->in_ctx, ep_index);
-+
-+ ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
-+ if (!ctrl_ctx) {
-+ xhci_warn(xhci,
-+ "%s: Could not get input context, bad type.\n",
-+ __func__);
-+ spin_unlock_irqrestore(&xhci->lock, flags);
-+ xhci_free_command(xhci, command);
-+ mutex_unlock(&xhci->mutex);
-+ return;
-+ }
-+ ctrl_ctx->add_flags = xhci_get_endpoint_flag_from_index(ep_index);
-+ ctrl_ctx->drop_flags = 0;
-+
-+ spin_unlock_irqrestore(&xhci->lock, flags);
-+
-+ ret = xhci_configure_endpoint(xhci, udev, command,
-+ false, false);
-+ if (ret)
-+ xhci_warn(xhci, "%s: Configure endpoint failed: %d\n",
-+ __func__, ret);
-+ xhci_free_command(xhci, command);
-+ mutex_unlock(&xhci->mutex);
-+}
-+
-+/*
- * non-error returns are a promise to giveback() the urb later
- * we drop ownership so next owner (or urb unlink) can get it
- */
-@@ -5217,6 +5314,7 @@ static const struct hc_driver xhci_hc_dr
- .endpoint_reset = xhci_endpoint_reset,
- .check_bandwidth = xhci_check_bandwidth,
- .reset_bandwidth = xhci_reset_bandwidth,
-+ .fixup_endpoint = xhci_fixup_endpoint,
- .address_device = xhci_address_device,
- .enable_device = xhci_enable_device,
- .update_hub_device = xhci_update_hub_device,
--- /dev/null
+From 5643e47700d3c1b2a8a1aca56629f12e90df407c Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Jun 2019 17:13:21 +0100
+Subject: [PATCH] drm/vc4: In FKMS look at the modifiers correctly for
+ SAND
+
+Incorrect masking was used in the switch for the modifier,
+therefore for SAND (which puts the column pitch in the
+modifier) it didn't match.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -460,7 +460,7 @@ static void vc4_plane_atomic_update(stru
+ }
+ mb->plane.planes[3] = 0;
+
+- switch (fb->modifier) {
++ switch (fourcc_mod_broadcom_mod(fb->modifier)) {
+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+ switch (mb->plane.vc_image_type) {
+ case VC_IMAGE_XRGB8888:
+@@ -476,6 +476,9 @@ static void vc4_plane_atomic_update(stru
+ break;
+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
+ mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
++ /* Note that the column pitch is passed across in lines, not
++ * bytes.
++ */
+ mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
+ break;
+ }
+++ /dev/null
-From f2c46d48d1aa0f7b87b179434162eac6624122f7 Mon Sep 17 00:00:00 2001
-Date: Tue, 11 Jun 2019 11:42:03 +0100
-Subject: [PATCH] usbhid: call usb_fixup_endpoint after mangling
- intervals
-
-Lets the mousepoll override mechanism work with xhci.
-
----
- drivers/hid/usbhid/hid-core.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/hid/usbhid/hid-core.c
-+++ b/drivers/hid/usbhid/hid-core.c
-@@ -1118,6 +1118,7 @@ static int usbhid_start(struct hid_devic
- interval = hid_kbpoll_interval;
- break;
- }
-+ usb_fixup_endpoint(dev, endpoint->bEndpointAddress, interval);
-
- ret = -ENOMEM;
- if (usb_endpoint_dir_in(endpoint)) {
--- /dev/null
+From 4d4d714061ee6f54dc5feeaeda4389e2346386aa Mon Sep 17 00:00:00 2001
+Date: Mon, 17 Jun 2019 10:06:55 +0100
+Subject: [PATCH] arm: dts: Fix Pi4 PWR LED configuration
+
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -126,13 +126,13 @@
+ act_led: act {
+ label = "led0";
+ linux,default-trigger = "mmc0";
+- gpios = <&gpio 42 0>;
++ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+ };
+
+ pwr_led: pwr {
+ label = "led1";
+- linux,default-trigger = "input";
+- gpios = <&expgpio 2 0>;
++ linux,default-trigger = "default-on";
++ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+++ /dev/null
-From 77ae227664bc2460a5341be765044d0b8fb184ac Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Jun 2019 12:14:30 +0100
-Subject: [PATCH] drm: vc4: Add status of which display is updated
- through vblank
-
-Previously multiple displays were slaved off the same SMI
-interrupt, triggered by HVS channel 1 (HDMI0).
-This doesn't work if you only have a DPI or DSI screen (HVS channel
-0), and gives slightly erroneous results with dual HDMI as the
-events for HDMI1 are incorrect.
-
-Use SMIDSW0 and SMIDSW1 registers to denote which display has
-triggered the vblank.
-Handling should be backwards compatible with older firmware.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 41 ++++++++++++++++++++++----
- 1 file changed, 36 insertions(+), 5 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -230,8 +230,13 @@ static const struct vc_image_format *vc4
- * hardware, which has only this one register.
- */
- #define SMICS 0x0
-+#define SMIDSW0 0x14
-+#define SMIDSW1 0x1C
- #define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11))
-
-+/* Flag to denote that the firmware is giving multiple display callbacks */
-+#define SMI_NEW 0xabcd0000
-+
- #define vc4_crtc vc4_kms_crtc
- #define to_vc4_crtc to_vc4_kms_crtc
- struct vc4_crtc {
-@@ -884,16 +889,42 @@ static irqreturn_t vc4_crtc_irq_handler(
- int i;
- u32 stat = readl(crtc_list[0]->regs + SMICS);
- irqreturn_t ret = IRQ_NONE;
-+ u32 chan;
-
- if (stat & SMICS_INTERRUPTS) {
- writel(0, crtc_list[0]->regs + SMICS);
-
-- for (i = 0; crtc_list[i]; i++) {
-- if (crtc_list[i]->vblank_enabled)
-- drm_crtc_handle_vblank(&crtc_list[i]->base);
-- vc4_crtc_handle_page_flip(crtc_list[i]);
-- ret = IRQ_HANDLED;
-+ chan = readl(crtc_list[0]->regs + SMIDSW0);
-+
-+ if ((chan & 0xFFFF0000) != SMI_NEW) {
-+ /* Older firmware. Treat the one interrupt as vblank/
-+ * complete for all crtcs.
-+ */
-+ for (i = 0; crtc_list[i]; i++) {
-+ if (crtc_list[i]->vblank_enabled)
-+ drm_crtc_handle_vblank(&crtc_list[i]->base);
-+ vc4_crtc_handle_page_flip(crtc_list[i]);
-+ }
-+ } else {
-+ if (chan & 1) {
-+ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW0);
-+ if (crtc_list[0]->vblank_enabled)
-+ drm_crtc_handle_vblank(&crtc_list[0]->base);
-+ vc4_crtc_handle_page_flip(crtc_list[0]);
-+ }
-+
-+ /* Check for the secondary display too */
-+ chan = readl(crtc_list[0]->regs + SMIDSW1);
-+
-+ if (chan & 1) {
-+ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
-+ if (crtc_list[1]->vblank_enabled)
-+ drm_crtc_handle_vblank(&crtc_list[1]->base);
-+ vc4_crtc_handle_page_flip(crtc_list[1]);
-+ }
- }
-+
-+ ret = IRQ_HANDLED;
- }
-
- return ret;
--- /dev/null
+From 43420c9bb90d4290e02bbcaa40c19e00fb347615 Mon Sep 17 00:00:00 2001
+Date: Sat, 15 Jun 2019 18:19:50 +0100
+Subject: [PATCH] bcm2838.dtsi : Correct gic400 memory address ranges
+
+It appears to me the addresses for the gic400 are slightly wrong . See section 3.2 https://static.docs.arm.com/ddi0471/a/DDI0471A_gic400_r0p0_trm.pdf
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -30,8 +30,8 @@
+ compatible = "arm,gic-400";
+ reg = <0x40041000 0x1000>,
+ <0x40042000 0x2000>,
+- <0x40046000 0x2000>,
+- <0x40048000 0x2000>;
++ <0x40044000 0x2000>,
++ <0x40046000 0x2000>;
+ };
+
+ thermal: thermal@7d5d2200 {
+++ /dev/null
-From 5643e47700d3c1b2a8a1aca56629f12e90df407c Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Jun 2019 17:13:21 +0100
-Subject: [PATCH] drm/vc4: In FKMS look at the modifiers correctly for
- SAND
-
-Incorrect masking was used in the switch for the modifier,
-therefore for SAND (which puts the column pitch in the
-modifier) it didn't match.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -460,7 +460,7 @@ static void vc4_plane_atomic_update(stru
- }
- mb->plane.planes[3] = 0;
-
-- switch (fb->modifier) {
-+ switch (fourcc_mod_broadcom_mod(fb->modifier)) {
- case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
- switch (mb->plane.vc_image_type) {
- case VC_IMAGE_XRGB8888:
-@@ -476,6 +476,9 @@ static void vc4_plane_atomic_update(stru
- break;
- case DRM_FORMAT_MOD_BROADCOM_SAND128:
- mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
-+ /* Note that the column pitch is passed across in lines, not
-+ * bytes.
-+ */
- mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
- break;
- }
+++ /dev/null
-From 4d4d714061ee6f54dc5feeaeda4389e2346386aa Mon Sep 17 00:00:00 2001
-Date: Mon, 17 Jun 2019 10:06:55 +0100
-Subject: [PATCH] arm: dts: Fix Pi4 PWR LED configuration
-
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -126,13 +126,13 @@
- act_led: act {
- label = "led0";
- linux,default-trigger = "mmc0";
-- gpios = <&gpio 42 0>;
-+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
- };
-
- pwr_led: pwr {
- label = "led1";
-- linux,default-trigger = "input";
-- gpios = <&expgpio 2 0>;
-+ linux,default-trigger = "default-on";
-+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
- };
- };
-
--- /dev/null
+From 65a5b304668ed6cb4568ac1a0ffbeabb28208b38 Mon Sep 17 00:00:00 2001
+Date: Tue, 18 Jun 2019 12:15:50 +0100
+Subject: [PATCH] staging: vchiq: Use the old dma controller for OF
+ config on platform devices
+
+vchiq on Pi4 is no longer under the soc node, therefore it
+doesn't get the dma-ranges for the VPU.
+
+Switch to using the configuration of the old dma controller as
+that will set the dma-ranges correctly.
+
+---
+ .../interface/vchiq_arm/vchiq_arm.c | 17 ++++++++++++++---
+ 1 file changed, 14 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -3599,6 +3599,7 @@ vchiq_register_child(struct platform_dev
+ {
+ struct platform_device_info pdevinfo;
+ struct platform_device *new_dev;
++ struct device_node *np;
+
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+
+@@ -3612,10 +3613,20 @@ vchiq_register_child(struct platform_dev
+ return NULL;
+
+ /*
+- * We want the dma-ranges etc to be copied from the parent VCHIQ device
+- * to be passed on to the children too.
++ * We want the dma-ranges etc to be copied from a device with the
++ * correct dma-ranges for the VPU.
++ * VCHIQ on Pi4 is now under scb which doesn't get those dma-ranges.
++ * Take the "dma" node as going to be suitable as it sees the world
++ * through the same eyes as the VPU.
+ */
+- of_dma_configure(&new_dev->dev, pdev->dev.of_node, true);
++ np = of_find_node_by_path("dma");
++ if (!np)
++ np = pdev->dev.of_node;
++
++ of_dma_configure(&new_dev->dev, np, true);
++
++ if (np != pdev->dev.of_node)
++ of_node_put(np);
+
+ return new_dev;
+ }
+++ /dev/null
-From 43420c9bb90d4290e02bbcaa40c19e00fb347615 Mon Sep 17 00:00:00 2001
-Date: Sat, 15 Jun 2019 18:19:50 +0100
-Subject: [PATCH] bcm2838.dtsi : Correct gic400 memory address ranges
-
-It appears to me the addresses for the gic400 are slightly wrong . See section 3.2 https://static.docs.arm.com/ddi0471/a/DDI0471A_gic400_r0p0_trm.pdf
----
- arch/arm/boot/dts/bcm2838.dtsi | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -30,8 +30,8 @@
- compatible = "arm,gic-400";
- reg = <0x40041000 0x1000>,
- <0x40042000 0x2000>,
-- <0x40046000 0x2000>,
-- <0x40048000 0x2000>;
-+ <0x40044000 0x2000>,
-+ <0x40046000 0x2000>;
- };
-
- thermal: thermal@7d5d2200 {
--- /dev/null
+From 06a0e398e7dcd6ba0a61713596c32ec6d43b47c8 Mon Sep 17 00:00:00 2001
+Date: Tue, 18 Jun 2019 21:37:45 +0100
+Subject: [PATCH] drm/vc4: Limit fkms to modes <= 85Hz
+
+Selecting 1080p100 and 120 has very limited gain, but don't want
+to block VGA85 and similar.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -822,6 +822,10 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ return MODE_NO_DBLESCAN;
+ }
+
++ /* Disable refresh rates > 85Hz as limited gain from them */
++ if (drm_mode_vrefresh(mode) > 85)
++ return MODE_BAD_VVALUE;
++
+ /* Limit the pixel clock based on the HDMI clock limits from the
+ * firmware
+ */
--- /dev/null
+From aca60a3944ff6a4da66e96d9ae54f4bca271b600 Mon Sep 17 00:00:00 2001
+Date: Tue, 11 Jun 2019 17:38:28 +0100
+Subject: [PATCH] arm: bcm2835: Add bcm2838 compatible string.
+
+---
+ arch/arm/mach-bcm/board_bcm2835.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -118,6 +118,7 @@ static const char * const bcm2835_compat
+ #ifdef CONFIG_ARCH_MULTI_V7
+ "brcm,bcm2836",
+ "brcm,bcm2837",
++ "brcm,bcm2838",
+ #endif
+ NULL
+ };
+++ /dev/null
-From 65a5b304668ed6cb4568ac1a0ffbeabb28208b38 Mon Sep 17 00:00:00 2001
-Date: Tue, 18 Jun 2019 12:15:50 +0100
-Subject: [PATCH] staging: vchiq: Use the old dma controller for OF
- config on platform devices
-
-vchiq on Pi4 is no longer under the soc node, therefore it
-doesn't get the dma-ranges for the VPU.
-
-Switch to using the configuration of the old dma controller as
-that will set the dma-ranges correctly.
-
----
- .../interface/vchiq_arm/vchiq_arm.c | 17 ++++++++++++++---
- 1 file changed, 14 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -3599,6 +3599,7 @@ vchiq_register_child(struct platform_dev
- {
- struct platform_device_info pdevinfo;
- struct platform_device *new_dev;
-+ struct device_node *np;
-
- memset(&pdevinfo, 0, sizeof(pdevinfo));
-
-@@ -3612,10 +3613,20 @@ vchiq_register_child(struct platform_dev
- return NULL;
-
- /*
-- * We want the dma-ranges etc to be copied from the parent VCHIQ device
-- * to be passed on to the children too.
-+ * We want the dma-ranges etc to be copied from a device with the
-+ * correct dma-ranges for the VPU.
-+ * VCHIQ on Pi4 is now under scb which doesn't get those dma-ranges.
-+ * Take the "dma" node as going to be suitable as it sees the world
-+ * through the same eyes as the VPU.
- */
-- of_dma_configure(&new_dev->dev, pdev->dev.of_node, true);
-+ np = of_find_node_by_path("dma");
-+ if (!np)
-+ np = pdev->dev.of_node;
-+
-+ of_dma_configure(&new_dev->dev, np, true);
-+
-+ if (np != pdev->dev.of_node)
-+ of_node_put(np);
-
- return new_dev;
- }
--- /dev/null
+From d27f2b90df0b787859c2f5665feaecbe87e6b1ff Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Jun 2019 16:22:22 +0100
+Subject: [PATCH] arm: dts: Improve the bcm27xx inclusion hierarchy
+
+1) The top-level .dts files now include parallel chains of bcm27xx.dtsi
+ and bcm27xx-rpi.dtsi files, with no cross-inclusion between the two
+ chains.
+
+2) Move definitions and deletions to the point of maximum commonality
+ to reduce redundancy.
+
+---
+ arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 1 +
+ arch/arm/boot/dts/bcm2708-rpi-b.dts | 1 +
+ arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 1 +
+ arch/arm/boot/dts/bcm2708-rpi-zero-w.dts | 1 +
+ arch/arm/boot/dts/bcm2708-rpi-zero.dts | 1 +
+ arch/arm/boot/dts/bcm2708-rpi.dtsi | 63 +++++++---------------
+ arch/arm/boot/dts/bcm2708.dtsi | 1 -
+ arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 1 +
+ arch/arm/boot/dts/bcm2709.dtsi | 1 -
+ arch/arm/boot/dts/bcm270x.dtsi | 18 +------
+ arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 1 +
+ arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 1 +
+ arch/arm/boot/dts/bcm2710-rpi-cm3.dts | 1 +
+ arch/arm/boot/dts/bcm2710.dtsi | 1 -
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 15 ++++--
+ arch/arm/boot/dts/bcm2711-rpi.dtsi | 7 +++
+ arch/arm/boot/dts/bcm2711.dtsi | 10 ----
+ arch/arm/boot/dts/bcm2835-rpi.dtsi | 16 ++++++
+ arch/arm/boot/dts/bcm2838.dtsi | 33 ++++++++----
+ arch/arm/boot/dts/bcm283x.dtsi | 2 +-
+ 20 files changed, 86 insertions(+), 90 deletions(-)
+ create mode 100644 arch/arm/boot/dts/bcm2711-rpi.dtsi
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
+@@ -1,6 +1,7 @@
+ /dts-v1/;
+
+ #include "bcm2708.dtsi"
++#include "bcm2708-rpi.dtsi"
+ #include "bcm283x-rpi-smsc9514.dtsi"
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
+@@ -1,6 +1,7 @@
+ /dts-v1/;
+
+ #include "bcm2708.dtsi"
++#include "bcm2708-rpi.dtsi"
+ #include "bcm283x-rpi-smsc9512.dtsi"
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
+@@ -1,4 +1,5 @@
+ #include "bcm2708.dtsi"
++#include "bcm2708-rpi.dtsi"
+
+ &leds {
+ act_led: act {
+--- a/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts
+@@ -1,6 +1,7 @@
+ /dts-v1/;
+
+ #include "bcm2708.dtsi"
++#include "bcm2708-rpi.dtsi"
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+--- a/arch/arm/boot/dts/bcm2708-rpi-zero.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-zero.dts
+@@ -1,6 +1,7 @@
+ /dts-v1/;
+
+ #include "bcm2708.dtsi"
++#include "bcm2708-rpi.dtsi"
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
+@@ -1,6 +1,6 @@
+-/* Downstream version of bcm2835-rpi.dtsi */
++/* Downstream modifications to bcm2835-rpi.dtsi */
+
+-#include <dt-bindings/power/raspberrypi-power.h>
++#include "bcm2835-rpi.dtsi"
+
+ / {
+ memory {
+@@ -49,29 +49,10 @@
+ reg = <0x7e200000 0x1000>;
+ };
+
+- firmware: firmware {
+- compatible = "raspberrypi,bcm2835-firmware", "simple-bus";
+- #address-cells = <0>;
+- #size-cells = <0>;
+- mboxes = <&mailbox>;
+- };
+-
+- power: power {
+- compatible = "raspberrypi,bcm2835-power";
+- firmware = <&firmware>;
+- #power-domain-cells = <1>;
+- };
+-
+ fb: fb {
+ compatible = "brcm,bcm2708-fb";
+ firmware = <&firmware>;
+- status = "disabled";
+- };
+-
+- vchiq: mailbox@7e00b840 {
+- compatible = "brcm,bcm2835-vchiq";
+- reg = <0x7e00b840 0x3c>;
+- interrupts = <0 2>;
++ status = "okay";
+ };
+
+ vcsm: vcsm {
+@@ -91,10 +72,6 @@
+ sound: sound {
+ status = "disabled";
+ };
+-
+- txp: txp@7e004000 {
+- status = "disabled";
+- };
+ };
+
+ __overrides__ {
+@@ -125,11 +102,23 @@
+ };
+
+ &hdmi {
+- power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "disabled";
+ };
+
+-&usb {
+- power-domains = <&power RPI_POWER_DOMAIN_USB>;
++&txp {
++ status = "disabled";
++};
++
++&i2c0 {
++ status = "disabled";
++};
++
++&i2c1 {
++ status = "disabled";
++};
++
++&i2c2 {
++ status = "disabled";
+ };
+
+ &clocks {
+@@ -141,16 +130,8 @@ sdhost_pins: &sdhost_gpio48 {
+ };
+
+ &sdhost {
+- pinctrl-names = "default";
+- pinctrl-0 = <&sdhost_gpio48>;
+- bus-width = <4>;
+ brcm,overclock-50 = <0>;
+ brcm,pio-limit = <1>;
+- status = "okay";
+-};
+-
+-&fb {
+- status = "okay";
+ };
+
+ &cpu_thermal {
+@@ -160,11 +141,3 @@ sdhost_pins: &sdhost_gpio48 {
+ &vec {
+ status = "disabled";
+ };
+-
+-&csi0 {
+- power-domains = <&power RPI_POWER_DOMAIN_UNICAM0>;
+-};
+-
+-&csi1 {
+- power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>;
+-};
+--- a/arch/arm/boot/dts/bcm2708.dtsi
++++ b/arch/arm/boot/dts/bcm2708.dtsi
+@@ -1,6 +1,5 @@
+ #include "bcm2835.dtsi"
+ #include "bcm270x.dtsi"
+-#include "bcm2708-rpi.dtsi"
+
+ / {
+ /delete-node/ cpus;
+--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
++++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
+@@ -1,6 +1,7 @@
+ /dts-v1/;
+
+ #include "bcm2709.dtsi"
++#include "bcm2709-rpi.dtsi"
+ #include "bcm283x-rpi-smsc9514.dtsi"
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+
+--- a/arch/arm/boot/dts/bcm2709.dtsi
++++ b/arch/arm/boot/dts/bcm2709.dtsi
+@@ -1,6 +1,5 @@
+ #include "bcm2836.dtsi"
+ #include "bcm270x.dtsi"
+-#include "bcm2709-rpi.dtsi"
+
+ / {
+ soc {
+--- a/arch/arm/boot/dts/bcm270x.dtsi
++++ b/arch/arm/boot/dts/bcm270x.dtsi
+@@ -68,7 +68,7 @@
+
+ /delete-node/ sdhci@7e300000;
+
+- mmc: mmc@7e300000 {
++ sdhci: mmc: mmc@7e300000 {
+ compatible = "brcm,bcm2835-mmc", "brcm,bcm2835-sdhci";
+ reg = <0x7e300000 0x100>;
+ interrupts = <2 30>;
+@@ -152,22 +152,6 @@
+ };
+ };
+
+- vdd_5v0_reg: fixedregulator_5v0 {
+- compatible = "regulator-fixed";
+- regulator-name = "5v0";
+- regulator-min-microvolt = <5000000>;
+- regulator-max-microvolt = <5000000>;
+- regulator-always-on;
+- };
+-
+- vdd_3v3_reg: fixedregulator_3v3 {
+- compatible = "regulator-fixed";
+- regulator-name = "3v3";
+- regulator-min-microvolt = <3300000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-always-on;
+- };
+-
+ __overrides__ {
+ cam0-pwdn-ctrl;
+ cam0-pwdn;
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
+@@ -1,6 +1,7 @@
+ /dts-v1/;
+
+ #include "bcm2710.dtsi"
++#include "bcm2709-rpi.dtsi"
+ #include "bcm283x-rpi-lan7515.dtsi"
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
+@@ -1,6 +1,7 @@
+ /dts-v1/;
+
+ #include "bcm2710.dtsi"
++#include "bcm2709-rpi.dtsi"
+ #include "bcm283x-rpi-smsc9514.dtsi"
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+
+--- a/arch/arm/boot/dts/bcm2710-rpi-cm3.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-cm3.dts
+@@ -1,6 +1,7 @@
+ /dts-v1/;
+
+ #include "bcm2710.dtsi"
++#include "bcm2709-rpi.dtsi"
+ #include "bcm283x-rpi-csi0-2lane.dtsi"
+ #include "bcm283x-rpi-csi1-4lane.dtsi"
+
+--- a/arch/arm/boot/dts/bcm2710.dtsi
++++ b/arch/arm/boot/dts/bcm2710.dtsi
+@@ -1,6 +1,5 @@
+ #include "bcm2837.dtsi"
+ #include "bcm270x.dtsi"
+-#include "bcm2709-rpi.dtsi"
+
+ / {
+ compatible = "brcm,bcm2837", "brcm,bcm2836";
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -1,13 +1,12 @@
+ /dts-v1/;
+
+ #include "bcm2711.dtsi"
++#include "bcm2711-rpi.dtsi"
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+- compatible = "raspberrypi,4-model-b", "brcm,bcm2838", "brcm,bcm2837";
++ compatible = "raspberrypi,4-model-b", "brcm,bcm2838";
+ model = "Raspberry Pi 4 Model B";
+- #address-cells = <2>;
+- #size-cells = <1>;
+
+ memory {
+ device_type = "memory";
+@@ -48,10 +47,18 @@
+ };
+
+ &firmware {
+- expgpio: expgpio {
++ expgpio: gpio {
+ compatible = "raspberrypi,firmware-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
++ gpio-line-names = "BT_ON",
++ "WL_ON",
++ "PWR_LED_OFF",
++ "GLOBAL_RESET",
++ "VDD_SD_IO_SEL",
++ "CAM_GPIO",
++ "",
++ "";
+ status = "okay";
+ };
+ };
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi
+@@ -0,0 +1,7 @@
++#include "bcm2708-rpi.dtsi"
++#include "bcm2838-rpi.dtsi"
++
++&v3d {
++ /* Undo the overwriting by bcm270x.dtsi */
++ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
++};
+--- a/arch/arm/boot/dts/bcm2711.dtsi
++++ b/arch/arm/boot/dts/bcm2711.dtsi
+@@ -1,10 +1,8 @@
+ #include "bcm2838.dtsi"
+ #include "bcm270x.dtsi"
+-#include "bcm2708-rpi.dtsi"
+
+ / {
+ soc {
+- /delete-node/ mailbox@7e00b840;
+ /delete-node/ v3d@7ec00000;
+ };
+
+@@ -17,14 +15,6 @@
+ status = "disabled";
+ };
+
+-&dma {
+- brcm,dma-channel-mask = <0x7ef5>;
+-};
+-
+-&txp {
+- interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+ &firmwarekms {
+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+ };
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -36,6 +36,22 @@
+ interrupts = <0 2>;
+ };
+ };
++
++ vdd_3v3_reg: fixedregulator_3v3 {
++ compatible = "regulator-fixed";
++ regulator-name = "3v3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++
++ vdd_5v0_reg: fixedregulator_5v0 {
++ compatible = "regulator-fixed";
++ regulator-name = "5v0";
++ regulator-min-microvolt = <5000000>;
++ regulator-max-microvolt = <5000000>;
++ regulator-always-on;
++ };
+ };
+
+ &gpio {
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -5,7 +5,10 @@
+ #include <dt-bindings/soc/bcm2835-pm.h>
+
+ / {
+- compatible = "brcm,bcm2838", "brcm,bcm2837";
++ compatible = "brcm,bcm2838";
++
++ #address-cells = <2>;
++ #size-cells = <1>;
+
+ interrupt-parent = <&gicv2>;
+
+@@ -16,8 +19,8 @@
+ /* Emulate a contiguous 30-bit address range for DMA */
+ dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
+
+- /delete-node/ mailbox@7e00b840;
+ /delete-node/ interrupt-controller@7e00f300;
++ /delete-node/ v3d@7ec00000;
+
+ local_intc: local_intc@40000000 {
+ compatible = "brcm,bcm2836-l1-intc";
+@@ -191,6 +194,16 @@
+ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
++ pwm1: pwm@7e20c800 {
++ compatible = "brcm,bcm2835-pwm";
++ reg = <0x7e20c800 0x28>;
++ clocks = <&clocks BCM2835_CLOCK_PWM>;
++ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
++ assigned-clock-rates = <10000000>;
++ #pwm-cells = <2>;
++ status = "disabled";
++ };
++
+ emmc2: emmc2@7e340000 {
+ compatible = "brcm,bcm2711-emmc2";
+ status = "okay";
+@@ -385,7 +398,7 @@
+ "dma13",
+ "dma14";
+ #dma-cells = <1>;
+- brcm,dma-channel-mask = <0x7000>;
++ brcm,dma-channel-mask = <0x7800>;
+ };
+ /* DMA4 - 40 bit DMA engines */
+
+@@ -396,12 +409,6 @@
+ interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+- vchiq: mailbox@7e00b840 {
+- compatible = "brcm,bcm2838-vchiq";
+- reg = <0 0x7e00b840 0x3c>;
+- interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+- };
+-
+ hevc-decoder@7eb00000 {
+ compatible = "raspberrypi,argon-hevc-decoder";
+ reg = <0x0 0x7eb00000 0x10000>;
+@@ -450,6 +457,8 @@
+ };
+
+ &gpio {
++ compatible = "brcm,bcm2838-gpio", "brcm,bcm2835-gpio";
++
+ gpclk0_gpio49: gpclk0_gpio49 {
+ brcm,pins = <49>;
+ brcm,function = <BCM2835_FSEL_ALT1>;
+@@ -729,5 +738,9 @@
+ "dma8",
+ "dma9",
+ "dma10";
+- brcm,dma-channel-mask = <0x01f5>;
++ brcm,dma-channel-mask = <0x07f5>;
++};
++
++&txp {
++ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ };
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -55,7 +55,7 @@
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+- txp@7e004000 {
++ txp: txp@7e004000 {
+ compatible = "brcm,bcm2835-txp";
+ reg = <0x7e004000 0x20>;
+ interrupts = <1 11>;
+++ /dev/null
-From 06a0e398e7dcd6ba0a61713596c32ec6d43b47c8 Mon Sep 17 00:00:00 2001
-Date: Tue, 18 Jun 2019 21:37:45 +0100
-Subject: [PATCH] drm/vc4: Limit fkms to modes <= 85Hz
-
-Selecting 1080p100 and 120 has very limited gain, but don't want
-to block VGA85 and similar.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -822,6 +822,10 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
- return MODE_NO_DBLESCAN;
- }
-
-+ /* Disable refresh rates > 85Hz as limited gain from them */
-+ if (drm_mode_vrefresh(mode) > 85)
-+ return MODE_BAD_VVALUE;
-+
- /* Limit the pixel clock based on the HDMI clock limits from the
- * firmware
- */
+++ /dev/null
-From aca60a3944ff6a4da66e96d9ae54f4bca271b600 Mon Sep 17 00:00:00 2001
-Date: Tue, 11 Jun 2019 17:38:28 +0100
-Subject: [PATCH] arm: bcm2835: Add bcm2838 compatible string.
-
----
- arch/arm/mach-bcm/board_bcm2835.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm/mach-bcm/board_bcm2835.c
-+++ b/arch/arm/mach-bcm/board_bcm2835.c
-@@ -118,6 +118,7 @@ static const char * const bcm2835_compat
- #ifdef CONFIG_ARCH_MULTI_V7
- "brcm,bcm2836",
- "brcm,bcm2837",
-+ "brcm,bcm2838",
- #endif
- NULL
- };
--- /dev/null
+From 5216bb8a1257a8216362affe4757a96a36b60b32 Mon Sep 17 00:00:00 2001
+Date: Tue, 11 Jun 2019 18:08:05 +0100
+Subject: [PATCH] arm: dts: First draft of upstream Pi4 DTS
+
+I've attempted to follow the upstream conventions in the DT commits,
+but this is just presented here initially as a talking point.
+
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 118 ++++++++++++++++++++++++++
+ arch/arm/boot/dts/bcm2838-rpi.dtsi | 25 ++++++
+ 3 files changed, 144 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm2838-rpi-4-b.dts
+ create mode 100644 arch/arm/boot/dts/bcm2838-rpi.dtsi
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -94,6 +94,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2836-rpi-2-b.dtb \
+ bcm2837-rpi-3-b.dtb \
+ bcm2837-rpi-3-b-plus.dtb \
++ bcm2838-rpi-4-b.dtb \
+ bcm2835-rpi-zero.dtb \
+ bcm2835-rpi-zero-w.dtb
+ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
+@@ -0,0 +1,118 @@
++// SPDX-License-Identifier: GPL-2.0
++/dts-v1/;
++#include "bcm2838.dtsi"
++#include "bcm2835-rpi.dtsi"
++#include "bcm2838-rpi.dtsi"
++
++/ {
++ compatible = "raspberrypi,4-model-b", "brcm,bcm2838";
++ model = "Raspberry Pi 4 Model B";
++
++ chosen {
++ /* 8250 auxiliary UART instead of pl011 */
++ stdout-path = "serial1:115200n8";
++ };
++
++ memory {
++ reg = <0 0 0x40000000>;
++ };
++
++ leds {
++ act {
++ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
++ };
++
++ pwr {
++ label = "PWR";
++ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
++ };
++ };
++
++ wifi_pwrseq: wifi-pwrseq {
++ compatible = "mmc-pwrseq-simple";
++ reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
++ };
++
++ sd_io_1v8_reg: sd_io_1v8_reg {
++ status = "okay";
++ compatible = "regulator-gpio";
++ vin-supply = <&vdd_5v0_reg>;
++ regulator-name = "vdd-sd-io";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ regulator-settling-time-us = <5000>;
++
++ gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
++ states = <1800000 0x1
++ 3300000 0x0>;
++ };
++};
++
++&firmware {
++ expgpio: gpio {
++ compatible = "raspberrypi,firmware-gpio";
++ gpio-controller;
++ #gpio-cells = <2>;
++ gpio-line-names = "BT_ON",
++ "WL_ON",
++ "PWR_LED_OFF",
++ "GLOBAL_RESET",
++ "VDD_SD_IO_SEL",
++ "CAM_GPIO",
++ "",
++ "";
++ status = "okay";
++ };
++};
++
++&pwm1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio41>;
++ status = "okay";
++};
++
++/* SDHCI is used to control the SDIO for wireless */
++&sdhci {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_gpio34>;
++ status = "okay";
++ bus-width = <4>;
++ non-removable;
++ mmc-pwrseq = <&wifi_pwrseq>;
++
++ brcmf: wifi@1 {
++ reg = <1>;
++ compatible = "brcm,bcm4329-fmac";
++ };
++};
++
++/* EMMC2 is used to drive the SD card */
++&emmc2 {
++ status = "okay";
++ broken-cd;
++ vqmmc-supply = <&sd_io_1v8_reg>;
++};
++
++/* uart0 communicates with the BT module */
++&uart0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32 &gpclk2_gpio43>;
++ status = "okay";
++
++ bluetooth {
++ compatible = "brcm,bcm43438-bt";
++ max-speed = <2000000>;
++ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
++ };
++};
++
++/* uart1 is mapped to the pin header */
++&uart1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart1_gpio14>;
++ status = "okay";
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2838-rpi.dtsi
+@@ -0,0 +1,25 @@
++// SPDX-License-Identifier: GPL-2.0
++
++/ {
++ soc {
++ /delete-node/ mailbox@7e00b840;
++ };
++};
++
++&scb {
++ vchiq: mailbox@7e00b840 {
++ compatible = "brcm,bcm2838-vchiq";
++ reg = <0 0x7e00b840 0x3c>;
++ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
++ };
++};
++
++&dma {
++ /* The VPU firmware uses DMA channel 11 for VCHIQ */
++ brcm,dma-channel-mask = <0x1f5>;
++};
++
++&dma40 {
++ /* The VPU firmware DMA channel 11 for VCHIQ */
++ brcm,dma-channel-mask = <0x7000>;
++};
+++ /dev/null
-From d27f2b90df0b787859c2f5665feaecbe87e6b1ff Mon Sep 17 00:00:00 2001
-Date: Tue, 4 Jun 2019 16:22:22 +0100
-Subject: [PATCH] arm: dts: Improve the bcm27xx inclusion hierarchy
-
-1) The top-level .dts files now include parallel chains of bcm27xx.dtsi
- and bcm27xx-rpi.dtsi files, with no cross-inclusion between the two
- chains.
-
-2) Move definitions and deletions to the point of maximum commonality
- to reduce redundancy.
-
----
- arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 1 +
- arch/arm/boot/dts/bcm2708-rpi-b.dts | 1 +
- arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 1 +
- arch/arm/boot/dts/bcm2708-rpi-zero-w.dts | 1 +
- arch/arm/boot/dts/bcm2708-rpi-zero.dts | 1 +
- arch/arm/boot/dts/bcm2708-rpi.dtsi | 63 +++++++---------------
- arch/arm/boot/dts/bcm2708.dtsi | 1 -
- arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 1 +
- arch/arm/boot/dts/bcm2709.dtsi | 1 -
- arch/arm/boot/dts/bcm270x.dtsi | 18 +------
- arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 1 +
- arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 1 +
- arch/arm/boot/dts/bcm2710-rpi-cm3.dts | 1 +
- arch/arm/boot/dts/bcm2710.dtsi | 1 -
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 15 ++++--
- arch/arm/boot/dts/bcm2711-rpi.dtsi | 7 +++
- arch/arm/boot/dts/bcm2711.dtsi | 10 ----
- arch/arm/boot/dts/bcm2835-rpi.dtsi | 16 ++++++
- arch/arm/boot/dts/bcm2838.dtsi | 33 ++++++++----
- arch/arm/boot/dts/bcm283x.dtsi | 2 +-
- 20 files changed, 86 insertions(+), 90 deletions(-)
- create mode 100644 arch/arm/boot/dts/bcm2711-rpi.dtsi
-
---- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
-@@ -1,6 +1,7 @@
- /dts-v1/;
-
- #include "bcm2708.dtsi"
-+#include "bcm2708-rpi.dtsi"
- #include "bcm283x-rpi-smsc9514.dtsi"
- #include "bcm283x-rpi-csi1-2lane.dtsi"
-
---- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
-+++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
-@@ -1,6 +1,7 @@
- /dts-v1/;
-
- #include "bcm2708.dtsi"
-+#include "bcm2708-rpi.dtsi"
- #include "bcm283x-rpi-smsc9512.dtsi"
- #include "bcm283x-rpi-csi1-2lane.dtsi"
-
---- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
-+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
-@@ -1,4 +1,5 @@
- #include "bcm2708.dtsi"
-+#include "bcm2708-rpi.dtsi"
-
- &leds {
- act_led: act {
---- a/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts
-+++ b/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts
-@@ -1,6 +1,7 @@
- /dts-v1/;
-
- #include "bcm2708.dtsi"
-+#include "bcm2708-rpi.dtsi"
- #include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
---- a/arch/arm/boot/dts/bcm2708-rpi-zero.dts
-+++ b/arch/arm/boot/dts/bcm2708-rpi-zero.dts
-@@ -1,6 +1,7 @@
- /dts-v1/;
-
- #include "bcm2708.dtsi"
-+#include "bcm2708-rpi.dtsi"
- #include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
---- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
-@@ -1,6 +1,6 @@
--/* Downstream version of bcm2835-rpi.dtsi */
-+/* Downstream modifications to bcm2835-rpi.dtsi */
-
--#include <dt-bindings/power/raspberrypi-power.h>
-+#include "bcm2835-rpi.dtsi"
-
- / {
- memory {
-@@ -49,29 +49,10 @@
- reg = <0x7e200000 0x1000>;
- };
-
-- firmware: firmware {
-- compatible = "raspberrypi,bcm2835-firmware", "simple-bus";
-- #address-cells = <0>;
-- #size-cells = <0>;
-- mboxes = <&mailbox>;
-- };
--
-- power: power {
-- compatible = "raspberrypi,bcm2835-power";
-- firmware = <&firmware>;
-- #power-domain-cells = <1>;
-- };
--
- fb: fb {
- compatible = "brcm,bcm2708-fb";
- firmware = <&firmware>;
-- status = "disabled";
-- };
--
-- vchiq: mailbox@7e00b840 {
-- compatible = "brcm,bcm2835-vchiq";
-- reg = <0x7e00b840 0x3c>;
-- interrupts = <0 2>;
-+ status = "okay";
- };
-
- vcsm: vcsm {
-@@ -91,10 +72,6 @@
- sound: sound {
- status = "disabled";
- };
--
-- txp: txp@7e004000 {
-- status = "disabled";
-- };
- };
-
- __overrides__ {
-@@ -125,11 +102,23 @@
- };
-
- &hdmi {
-- power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "disabled";
- };
-
--&usb {
-- power-domains = <&power RPI_POWER_DOMAIN_USB>;
-+&txp {
-+ status = "disabled";
-+};
-+
-+&i2c0 {
-+ status = "disabled";
-+};
-+
-+&i2c1 {
-+ status = "disabled";
-+};
-+
-+&i2c2 {
-+ status = "disabled";
- };
-
- &clocks {
-@@ -141,16 +130,8 @@ sdhost_pins: &sdhost_gpio48 {
- };
-
- &sdhost {
-- pinctrl-names = "default";
-- pinctrl-0 = <&sdhost_gpio48>;
-- bus-width = <4>;
- brcm,overclock-50 = <0>;
- brcm,pio-limit = <1>;
-- status = "okay";
--};
--
--&fb {
-- status = "okay";
- };
-
- &cpu_thermal {
-@@ -160,11 +141,3 @@ sdhost_pins: &sdhost_gpio48 {
- &vec {
- status = "disabled";
- };
--
--&csi0 {
-- power-domains = <&power RPI_POWER_DOMAIN_UNICAM0>;
--};
--
--&csi1 {
-- power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>;
--};
---- a/arch/arm/boot/dts/bcm2708.dtsi
-+++ b/arch/arm/boot/dts/bcm2708.dtsi
-@@ -1,6 +1,5 @@
- #include "bcm2835.dtsi"
- #include "bcm270x.dtsi"
--#include "bcm2708-rpi.dtsi"
-
- / {
- /delete-node/ cpus;
---- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
-+++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
-@@ -1,6 +1,7 @@
- /dts-v1/;
-
- #include "bcm2709.dtsi"
-+#include "bcm2709-rpi.dtsi"
- #include "bcm283x-rpi-smsc9514.dtsi"
- #include "bcm283x-rpi-csi1-2lane.dtsi"
-
---- a/arch/arm/boot/dts/bcm2709.dtsi
-+++ b/arch/arm/boot/dts/bcm2709.dtsi
-@@ -1,6 +1,5 @@
- #include "bcm2836.dtsi"
- #include "bcm270x.dtsi"
--#include "bcm2709-rpi.dtsi"
-
- / {
- soc {
---- a/arch/arm/boot/dts/bcm270x.dtsi
-+++ b/arch/arm/boot/dts/bcm270x.dtsi
-@@ -68,7 +68,7 @@
-
- /delete-node/ sdhci@7e300000;
-
-- mmc: mmc@7e300000 {
-+ sdhci: mmc: mmc@7e300000 {
- compatible = "brcm,bcm2835-mmc", "brcm,bcm2835-sdhci";
- reg = <0x7e300000 0x100>;
- interrupts = <2 30>;
-@@ -152,22 +152,6 @@
- };
- };
-
-- vdd_5v0_reg: fixedregulator_5v0 {
-- compatible = "regulator-fixed";
-- regulator-name = "5v0";
-- regulator-min-microvolt = <5000000>;
-- regulator-max-microvolt = <5000000>;
-- regulator-always-on;
-- };
--
-- vdd_3v3_reg: fixedregulator_3v3 {
-- compatible = "regulator-fixed";
-- regulator-name = "3v3";
-- regulator-min-microvolt = <3300000>;
-- regulator-max-microvolt = <3300000>;
-- regulator-always-on;
-- };
--
- __overrides__ {
- cam0-pwdn-ctrl;
- cam0-pwdn;
---- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
-@@ -1,6 +1,7 @@
- /dts-v1/;
-
- #include "bcm2710.dtsi"
-+#include "bcm2709-rpi.dtsi"
- #include "bcm283x-rpi-lan7515.dtsi"
- #include "bcm283x-rpi-csi1-2lane.dtsi"
-
---- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
-@@ -1,6 +1,7 @@
- /dts-v1/;
-
- #include "bcm2710.dtsi"
-+#include "bcm2709-rpi.dtsi"
- #include "bcm283x-rpi-smsc9514.dtsi"
- #include "bcm283x-rpi-csi1-2lane.dtsi"
-
---- a/arch/arm/boot/dts/bcm2710-rpi-cm3.dts
-+++ b/arch/arm/boot/dts/bcm2710-rpi-cm3.dts
-@@ -1,6 +1,7 @@
- /dts-v1/;
-
- #include "bcm2710.dtsi"
-+#include "bcm2709-rpi.dtsi"
- #include "bcm283x-rpi-csi0-2lane.dtsi"
- #include "bcm283x-rpi-csi1-4lane.dtsi"
-
---- a/arch/arm/boot/dts/bcm2710.dtsi
-+++ b/arch/arm/boot/dts/bcm2710.dtsi
-@@ -1,6 +1,5 @@
- #include "bcm2837.dtsi"
- #include "bcm270x.dtsi"
--#include "bcm2709-rpi.dtsi"
-
- / {
- compatible = "brcm,bcm2837", "brcm,bcm2836";
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -1,13 +1,12 @@
- /dts-v1/;
-
- #include "bcm2711.dtsi"
-+#include "bcm2711-rpi.dtsi"
- #include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
-- compatible = "raspberrypi,4-model-b", "brcm,bcm2838", "brcm,bcm2837";
-+ compatible = "raspberrypi,4-model-b", "brcm,bcm2838";
- model = "Raspberry Pi 4 Model B";
-- #address-cells = <2>;
-- #size-cells = <1>;
-
- memory {
- device_type = "memory";
-@@ -48,10 +47,18 @@
- };
-
- &firmware {
-- expgpio: expgpio {
-+ expgpio: gpio {
- compatible = "raspberrypi,firmware-gpio";
- gpio-controller;
- #gpio-cells = <2>;
-+ gpio-line-names = "BT_ON",
-+ "WL_ON",
-+ "PWR_LED_OFF",
-+ "GLOBAL_RESET",
-+ "VDD_SD_IO_SEL",
-+ "CAM_GPIO",
-+ "",
-+ "";
- status = "okay";
- };
- };
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi
-@@ -0,0 +1,7 @@
-+#include "bcm2708-rpi.dtsi"
-+#include "bcm2838-rpi.dtsi"
-+
-+&v3d {
-+ /* Undo the overwriting by bcm270x.dtsi */
-+ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
-+};
---- a/arch/arm/boot/dts/bcm2711.dtsi
-+++ b/arch/arm/boot/dts/bcm2711.dtsi
-@@ -1,10 +1,8 @@
- #include "bcm2838.dtsi"
- #include "bcm270x.dtsi"
--#include "bcm2708-rpi.dtsi"
-
- / {
- soc {
-- /delete-node/ mailbox@7e00b840;
- /delete-node/ v3d@7ec00000;
- };
-
-@@ -17,14 +15,6 @@
- status = "disabled";
- };
-
--&dma {
-- brcm,dma-channel-mask = <0x7ef5>;
--};
--
--&txp {
-- interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
--};
--
- &firmwarekms {
- interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
- };
---- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
-@@ -36,6 +36,22 @@
- interrupts = <0 2>;
- };
- };
-+
-+ vdd_3v3_reg: fixedregulator_3v3 {
-+ compatible = "regulator-fixed";
-+ regulator-name = "3v3";
-+ regulator-min-microvolt = <3300000>;
-+ regulator-max-microvolt = <3300000>;
-+ regulator-always-on;
-+ };
-+
-+ vdd_5v0_reg: fixedregulator_5v0 {
-+ compatible = "regulator-fixed";
-+ regulator-name = "5v0";
-+ regulator-min-microvolt = <5000000>;
-+ regulator-max-microvolt = <5000000>;
-+ regulator-always-on;
-+ };
- };
-
- &gpio {
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -5,7 +5,10 @@
- #include <dt-bindings/soc/bcm2835-pm.h>
-
- / {
-- compatible = "brcm,bcm2838", "brcm,bcm2837";
-+ compatible = "brcm,bcm2838";
-+
-+ #address-cells = <2>;
-+ #size-cells = <1>;
-
- interrupt-parent = <&gicv2>;
-
-@@ -16,8 +19,8 @@
- /* Emulate a contiguous 30-bit address range for DMA */
- dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
-
-- /delete-node/ mailbox@7e00b840;
- /delete-node/ interrupt-controller@7e00f300;
-+ /delete-node/ v3d@7ec00000;
-
- local_intc: local_intc@40000000 {
- compatible = "brcm,bcm2836-l1-intc";
-@@ -191,6 +194,16 @@
- interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
- };
-
-+ pwm1: pwm@7e20c800 {
-+ compatible = "brcm,bcm2835-pwm";
-+ reg = <0x7e20c800 0x28>;
-+ clocks = <&clocks BCM2835_CLOCK_PWM>;
-+ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
-+ assigned-clock-rates = <10000000>;
-+ #pwm-cells = <2>;
-+ status = "disabled";
-+ };
-+
- emmc2: emmc2@7e340000 {
- compatible = "brcm,bcm2711-emmc2";
- status = "okay";
-@@ -385,7 +398,7 @@
- "dma13",
- "dma14";
- #dma-cells = <1>;
-- brcm,dma-channel-mask = <0x7000>;
-+ brcm,dma-channel-mask = <0x7800>;
- };
- /* DMA4 - 40 bit DMA engines */
-
-@@ -396,12 +409,6 @@
- interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
- };
-
-- vchiq: mailbox@7e00b840 {
-- compatible = "brcm,bcm2838-vchiq";
-- reg = <0 0x7e00b840 0x3c>;
-- interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
-- };
--
- hevc-decoder@7eb00000 {
- compatible = "raspberrypi,argon-hevc-decoder";
- reg = <0x0 0x7eb00000 0x10000>;
-@@ -450,6 +457,8 @@
- };
-
- &gpio {
-+ compatible = "brcm,bcm2838-gpio", "brcm,bcm2835-gpio";
-+
- gpclk0_gpio49: gpclk0_gpio49 {
- brcm,pins = <49>;
- brcm,function = <BCM2835_FSEL_ALT1>;
-@@ -729,5 +738,9 @@
- "dma8",
- "dma9",
- "dma10";
-- brcm,dma-channel-mask = <0x01f5>;
-+ brcm,dma-channel-mask = <0x07f5>;
-+};
-+
-+&txp {
-+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
- };
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -55,7 +55,7 @@
- #address-cells = <1>;
- #size-cells = <1>;
-
-- txp@7e004000 {
-+ txp: txp@7e004000 {
- compatible = "brcm,bcm2835-txp";
- reg = <0x7e004000 0x20>;
- interrupts = <1 11>;
--- /dev/null
+From 4a5715f95d8865c817c9a747f28f38b234f5df42 Mon Sep 17 00:00:00 2001
+Date: Mon, 17 Jun 2019 14:36:12 +0100
+Subject: [PATCH] overlays: Fix compatible string for ds1307 RTC
+
+Kernels since 4.19 have required the correct manufacture name in the
+compatible string for I2C devices, and unfortunately the one for the
+Dallas/Maxim DS1307 should have been "dallas,ds1307" and not
+"maxim,ds1307".
+
+See: https://github.com/raspberrypi/linux/issues/3013
+
+---
+ arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+@@ -30,7 +30,7 @@
+ status = "okay";
+
+ ds1307: ds1307@68 {
+- compatible = "maxim,ds1307";
++ compatible = "dallas,ds1307";
+ reg = <0x68>;
+ status = "okay";
+ };
+++ /dev/null
-From 5216bb8a1257a8216362affe4757a96a36b60b32 Mon Sep 17 00:00:00 2001
-Date: Tue, 11 Jun 2019 18:08:05 +0100
-Subject: [PATCH] arm: dts: First draft of upstream Pi4 DTS
-
-I've attempted to follow the upstream conventions in the DT commits,
-but this is just presented here initially as a talking point.
-
----
- arch/arm/boot/dts/Makefile | 1 +
- arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 118 ++++++++++++++++++++++++++
- arch/arm/boot/dts/bcm2838-rpi.dtsi | 25 ++++++
- 3 files changed, 144 insertions(+)
- create mode 100644 arch/arm/boot/dts/bcm2838-rpi-4-b.dts
- create mode 100644 arch/arm/boot/dts/bcm2838-rpi.dtsi
-
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -94,6 +94,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
- bcm2836-rpi-2-b.dtb \
- bcm2837-rpi-3-b.dtb \
- bcm2837-rpi-3-b-plus.dtb \
-+ bcm2838-rpi-4-b.dtb \
- bcm2835-rpi-zero.dtb \
- bcm2835-rpi-zero-w.dtb
- dtb-$(CONFIG_ARCH_BCM_5301X) += \
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-@@ -0,0 +1,118 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/dts-v1/;
-+#include "bcm2838.dtsi"
-+#include "bcm2835-rpi.dtsi"
-+#include "bcm2838-rpi.dtsi"
-+
-+/ {
-+ compatible = "raspberrypi,4-model-b", "brcm,bcm2838";
-+ model = "Raspberry Pi 4 Model B";
-+
-+ chosen {
-+ /* 8250 auxiliary UART instead of pl011 */
-+ stdout-path = "serial1:115200n8";
-+ };
-+
-+ memory {
-+ reg = <0 0 0x40000000>;
-+ };
-+
-+ leds {
-+ act {
-+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
-+ };
-+
-+ pwr {
-+ label = "PWR";
-+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
-+ };
-+ };
-+
-+ wifi_pwrseq: wifi-pwrseq {
-+ compatible = "mmc-pwrseq-simple";
-+ reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
-+ };
-+
-+ sd_io_1v8_reg: sd_io_1v8_reg {
-+ status = "okay";
-+ compatible = "regulator-gpio";
-+ vin-supply = <&vdd_5v0_reg>;
-+ regulator-name = "vdd-sd-io";
-+ regulator-min-microvolt = <1800000>;
-+ regulator-max-microvolt = <3300000>;
-+ regulator-boot-on;
-+ regulator-always-on;
-+ regulator-settling-time-us = <5000>;
-+
-+ gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
-+ states = <1800000 0x1
-+ 3300000 0x0>;
-+ };
-+};
-+
-+&firmware {
-+ expgpio: gpio {
-+ compatible = "raspberrypi,firmware-gpio";
-+ gpio-controller;
-+ #gpio-cells = <2>;
-+ gpio-line-names = "BT_ON",
-+ "WL_ON",
-+ "PWR_LED_OFF",
-+ "GLOBAL_RESET",
-+ "VDD_SD_IO_SEL",
-+ "CAM_GPIO",
-+ "",
-+ "";
-+ status = "okay";
-+ };
-+};
-+
-+&pwm1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio41>;
-+ status = "okay";
-+};
-+
-+/* SDHCI is used to control the SDIO for wireless */
-+&sdhci {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&emmc_gpio34>;
-+ status = "okay";
-+ bus-width = <4>;
-+ non-removable;
-+ mmc-pwrseq = <&wifi_pwrseq>;
-+
-+ brcmf: wifi@1 {
-+ reg = <1>;
-+ compatible = "brcm,bcm4329-fmac";
-+ };
-+};
-+
-+/* EMMC2 is used to drive the SD card */
-+&emmc2 {
-+ status = "okay";
-+ broken-cd;
-+ vqmmc-supply = <&sd_io_1v8_reg>;
-+};
-+
-+/* uart0 communicates with the BT module */
-+&uart0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32 &gpclk2_gpio43>;
-+ status = "okay";
-+
-+ bluetooth {
-+ compatible = "brcm,bcm43438-bt";
-+ max-speed = <2000000>;
-+ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
-+ };
-+};
-+
-+/* uart1 is mapped to the pin header */
-+&uart1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart1_gpio14>;
-+ status = "okay";
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2838-rpi.dtsi
-@@ -0,0 +1,25 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/ {
-+ soc {
-+ /delete-node/ mailbox@7e00b840;
-+ };
-+};
-+
-+&scb {
-+ vchiq: mailbox@7e00b840 {
-+ compatible = "brcm,bcm2838-vchiq";
-+ reg = <0 0x7e00b840 0x3c>;
-+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+};
-+
-+&dma {
-+ /* The VPU firmware uses DMA channel 11 for VCHIQ */
-+ brcm,dma-channel-mask = <0x1f5>;
-+};
-+
-+&dma40 {
-+ /* The VPU firmware DMA channel 11 for VCHIQ */
-+ brcm,dma-channel-mask = <0x7000>;
-+};
--- /dev/null
+From ff25f8c70fd995e4f76a3c1245556cc0ec3db19d Mon Sep 17 00:00:00 2001
+Date: Tue, 18 Jun 2019 11:16:13 +0100
+Subject: [PATCH] overlays: Fix further maxim,ds1307 references
+
+See: https://github.com/raspberrypi/linux/issues/3013
+
+---
+ arch/arm/boot/dts/overlays/balena-fin-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/tinylcd35-overlay.dts | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
++++ b/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
+@@ -84,7 +84,7 @@
+
+ // rtc clock
+ ds1307: ds1307@68 {
+- compatible = "maxim,ds1307";
++ compatible = "dallas,ds1307";
+ reg = <0x68>;
+ status = "okay";
+ };
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
+@@ -46,7 +46,7 @@
+ status = "okay";
+
+ ds1307: ds1307@68 {
+- compatible = "maxim,ds1307";
++ compatible = "dallas,ds1307";
+ reg = <0x68>;
+ status = "okay";
+ };
+--- a/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
++++ b/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
+@@ -155,7 +155,7 @@
+ status = "okay";
+
+ ds1307: ds1307@68 {
+- compatible = "maxim,ds1307";
++ compatible = "dallas,ds1307";
+ reg = <0x68>;
+ status = "okay";
+ };
--- /dev/null
+From ce7469a397da34a19112b8d14eb283e02088755b Mon Sep 17 00:00:00 2001
+Date: Tue, 18 Jun 2019 11:19:59 +0100
+Subject: [PATCH] overlays: Cosmetic change to upstream overlay
+
+The dwc2 overlay no longer uses the dwc2_usb label, and the latest
+ovmerge (which generates the upstream overlay) removes unused labels.
+Update the checked-in version to match.
+
+---
+ arch/arm/boot/dts/overlays/upstream-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/upstream-overlay.dts
++++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts
+@@ -113,7 +113,7 @@
+ target = <&usb>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+- dwc2_usb: __overlay__ {
++ __overlay__ {
+ compatible = "brcm,bcm2835-usb";
+ dr_mode = "otg";
+ g-np-tx-fifo-size = <32>;
+++ /dev/null
-From 4a5715f95d8865c817c9a747f28f38b234f5df42 Mon Sep 17 00:00:00 2001
-Date: Mon, 17 Jun 2019 14:36:12 +0100
-Subject: [PATCH] overlays: Fix compatible string for ds1307 RTC
-
-Kernels since 4.19 have required the correct manufacture name in the
-compatible string for I2C devices, and unfortunately the one for the
-Dallas/Maxim DS1307 should have been "dallas,ds1307" and not
-"maxim,ds1307".
-
-See: https://github.com/raspberrypi/linux/issues/3013
-
----
- arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-@@ -30,7 +30,7 @@
- status = "okay";
-
- ds1307: ds1307@68 {
-- compatible = "maxim,ds1307";
-+ compatible = "dallas,ds1307";
- reg = <0x68>;
- status = "okay";
- };
+++ /dev/null
-From ff25f8c70fd995e4f76a3c1245556cc0ec3db19d Mon Sep 17 00:00:00 2001
-Date: Tue, 18 Jun 2019 11:16:13 +0100
-Subject: [PATCH] overlays: Fix further maxim,ds1307 references
-
-See: https://github.com/raspberrypi/linux/issues/3013
-
----
- arch/arm/boot/dts/overlays/balena-fin-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/tinylcd35-overlay.dts | 2 +-
- 3 files changed, 3 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/balena-fin-overlay.dts
-@@ -84,7 +84,7 @@
-
- // rtc clock
- ds1307: ds1307@68 {
-- compatible = "maxim,ds1307";
-+ compatible = "dallas,ds1307";
- reg = <0x68>;
- status = "okay";
- };
---- a/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
-@@ -46,7 +46,7 @@
- status = "okay";
-
- ds1307: ds1307@68 {
-- compatible = "maxim,ds1307";
-+ compatible = "dallas,ds1307";
- reg = <0x68>;
- status = "okay";
- };
---- a/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/tinylcd35-overlay.dts
-@@ -155,7 +155,7 @@
- status = "okay";
-
- ds1307: ds1307@68 {
-- compatible = "maxim,ds1307";
-+ compatible = "dallas,ds1307";
- reg = <0x68>;
- status = "okay";
- };
--- /dev/null
+From 4f1fd30b76c1bec76069483b88747783a0654f38 Mon Sep 17 00:00:00 2001
+Date: Sat, 25 May 2019 10:45:38 +0200
+Subject: [PATCH] w1: ds2805: rename w1_family struct, fixing c-p typo
+
+commit 0e3743d870711ae4daf1e7170c8d9381564e244d upstream.
+
+The ds2805 has a structure named: w1_family_2d, which surely
+comes from a w1_ds2431 module. This commit fixes this name to
+prevent confusion and mark a correct family name.
+
+---
+ drivers/w1/slaves/w1_ds2805.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/w1/slaves/w1_ds2805.c
++++ b/drivers/w1/slaves/w1_ds2805.c
+@@ -288,7 +288,7 @@ static struct w1_family_ops w1_f0d_fops
+ .remove_slave = w1_f0d_remove_slave,
+ };
+
+-static struct w1_family w1_family_2d = {
++static struct w1_family w1_family_0d = {
+ .fid = W1_EEPROM_DS2805,
+ .fops = &w1_f0d_fops,
+ };
+@@ -296,13 +296,13 @@ static struct w1_family w1_family_2d = {
+ static int __init w1_f0d_init(void)
+ {
+ pr_info("%s()\n", __func__);
+- return w1_register_family(&w1_family_2d);
++ return w1_register_family(&w1_family_0d);
+ }
+
+ static void __exit w1_f0d_fini(void)
+ {
+ pr_info("%s()\n", __func__);
+- w1_unregister_family(&w1_family_2d);
++ w1_unregister_family(&w1_family_0d);
+ }
+
+ module_init(w1_f0d_init);
+++ /dev/null
-From ce7469a397da34a19112b8d14eb283e02088755b Mon Sep 17 00:00:00 2001
-Date: Tue, 18 Jun 2019 11:19:59 +0100
-Subject: [PATCH] overlays: Cosmetic change to upstream overlay
-
-The dwc2 overlay no longer uses the dwc2_usb label, and the latest
-ovmerge (which generates the upstream overlay) removes unused labels.
-Update the checked-in version to match.
-
----
- arch/arm/boot/dts/overlays/upstream-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/upstream-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts
-@@ -113,7 +113,7 @@
- target = <&usb>;
- #address-cells = <1>;
- #size-cells = <1>;
-- dwc2_usb: __overlay__ {
-+ __overlay__ {
- compatible = "brcm,bcm2835-usb";
- dr_mode = "otg";
- g-np-tx-fifo-size = <32>;
--- /dev/null
+From 3280ce5f5483a351f49e84b48ad98df87989346a Mon Sep 17 00:00:00 2001
+Date: Mon, 20 May 2019 09:05:55 +0200
+Subject: [PATCH] w1: ds2413: output_write() cosmetic fixes / simplify
+
+commit ae2ee27aa985232f66421d7cd1c7f4b87c7dba7d upstream.
+
+Make the output_write simpler.
+Based on Jean-Francois Dagenais code from:
+49695ac46861 ("w1: ds2408: reset on output_write retry with readback")
+
+---
+ drivers/w1/slaves/w1_ds2413.c | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+--- a/drivers/w1/slaves/w1_ds2413.c
++++ b/drivers/w1/slaves/w1_ds2413.c
+@@ -69,6 +69,7 @@ static ssize_t output_write(struct file
+ struct w1_slave *sl = kobj_to_w1_slave(kobj);
+ u8 w1_buf[3];
+ unsigned int retries = W1_F3A_RETRIES;
++ ssize_t bytes_written = -EIO;
+
+ if (count != 1 || off != 0)
+ return -EFAULT;
+@@ -78,7 +79,7 @@ static ssize_t output_write(struct file
+ dev_dbg(&sl->dev, "mutex locked");
+
+ if (w1_reset_select_slave(sl))
+- goto error;
++ goto out;
+
+ /* according to the DS2413 datasheet the most significant 6 bits
+ should be set to "1"s, so do it now */
+@@ -91,18 +92,20 @@ static ssize_t output_write(struct file
+ w1_write_block(sl->master, w1_buf, 3);
+
+ if (w1_read_8(sl->master) == W1_F3A_SUCCESS_CONFIRM_BYTE) {
+- mutex_unlock(&sl->master->bus_mutex);
+- dev_dbg(&sl->dev, "mutex unlocked, retries:%d", retries);
+- return 1;
++ bytes_written = 1;
++ goto out;
+ }
+ if (w1_reset_resume_command(sl->master))
+- goto error;
++ goto out; /* unrecoverable error */
++
++ dev_warn(&sl->dev, "PIO_ACCESS_WRITE error, retries left: %d\n", retries);
+ }
+
+-error:
++out:
+ mutex_unlock(&sl->master->bus_mutex);
+- dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
+- return -EIO;
++ dev_dbg(&sl->dev, "%s, mutex unlocked, retries: %d\n",
++ (bytes_written > 0) ? "succeeded" : "error", retries);
++ return bytes_written;
+ }
+
+ static BIN_ATTR(output, S_IRUGO | S_IWUSR | S_IWGRP, NULL, output_write, 1);
--- /dev/null
+From 91e443597cdd8f89d2b68ea5bf0f0823d1853ab7 Mon Sep 17 00:00:00 2001
+Date: Mon, 20 May 2019 09:05:56 +0200
+Subject: [PATCH] w1: ds2413: add retry support to state_read()
+
+commit c50d09a86172073f55ebac0b92ad5a75907d64e7 upstream.
+
+The state_read() was calling PIO_ACCESS_READ once and bail out if it
+failed for this first time.
+This commit is improving this to trying more times before it give up,
+similarly as the write call is currently doing.
+
+---
+ drivers/w1/slaves/w1_ds2413.c | 37 +++++++++++++++++++++++------------
+ 1 file changed, 24 insertions(+), 13 deletions(-)
+
+--- a/drivers/w1/slaves/w1_ds2413.c
++++ b/drivers/w1/slaves/w1_ds2413.c
+@@ -30,6 +30,9 @@ static ssize_t state_read(struct file *f
+ size_t count)
+ {
+ struct w1_slave *sl = kobj_to_w1_slave(kobj);
++ unsigned int retries = W1_F3A_RETRIES;
++ ssize_t bytes_read = -EIO;
++
+ dev_dbg(&sl->dev,
+ "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
+ bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
+@@ -42,22 +45,30 @@ static ssize_t state_read(struct file *f
+ mutex_lock(&sl->master->bus_mutex);
+ dev_dbg(&sl->dev, "mutex locked");
+
+- if (w1_reset_select_slave(sl)) {
+- mutex_unlock(&sl->master->bus_mutex);
+- return -EIO;
+- }
++ if (w1_reset_select_slave(sl))
++ goto out;
+
+- w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
+- *buf = w1_read_8(sl->master);
++ while (retries--) {
++ w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
+
+- mutex_unlock(&sl->master->bus_mutex);
+- dev_dbg(&sl->dev, "mutex unlocked");
++ *buf = w1_read_8(sl->master);
++ /* check for correct complement */
++ if ((*buf & 0x0F) == ((~*buf >> 4) & 0x0F)) {
++ bytes_read = 1;
++ goto out;
++ }
++
++ if (w1_reset_resume_command(sl->master))
++ goto out; /* unrecoverable error */
+
+- /* check for correct complement */
+- if ((*buf & 0x0F) != ((~*buf >> 4) & 0x0F))
+- return -EIO;
+- else
+- return 1;
++ dev_warn(&sl->dev, "PIO_ACCESS_READ error, retries left: %d\n", retries);
++ }
++
++out:
++ mutex_unlock(&sl->master->bus_mutex);
++ dev_dbg(&sl->dev, "%s, mutex unlocked, retries: %d\n",
++ (bytes_read > 0) ? "succeeded" : "error", retries);
++ return bytes_read;
+ }
+
+ static BIN_ATTR_RO(state, 1);
+++ /dev/null
-From 4f1fd30b76c1bec76069483b88747783a0654f38 Mon Sep 17 00:00:00 2001
-Date: Sat, 25 May 2019 10:45:38 +0200
-Subject: [PATCH] w1: ds2805: rename w1_family struct, fixing c-p typo
-
-commit 0e3743d870711ae4daf1e7170c8d9381564e244d upstream.
-
-The ds2805 has a structure named: w1_family_2d, which surely
-comes from a w1_ds2431 module. This commit fixes this name to
-prevent confusion and mark a correct family name.
-
----
- drivers/w1/slaves/w1_ds2805.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/w1/slaves/w1_ds2805.c
-+++ b/drivers/w1/slaves/w1_ds2805.c
-@@ -288,7 +288,7 @@ static struct w1_family_ops w1_f0d_fops
- .remove_slave = w1_f0d_remove_slave,
- };
-
--static struct w1_family w1_family_2d = {
-+static struct w1_family w1_family_0d = {
- .fid = W1_EEPROM_DS2805,
- .fops = &w1_f0d_fops,
- };
-@@ -296,13 +296,13 @@ static struct w1_family w1_family_2d = {
- static int __init w1_f0d_init(void)
- {
- pr_info("%s()\n", __func__);
-- return w1_register_family(&w1_family_2d);
-+ return w1_register_family(&w1_family_0d);
- }
-
- static void __exit w1_f0d_fini(void)
- {
- pr_info("%s()\n", __func__);
-- w1_unregister_family(&w1_family_2d);
-+ w1_unregister_family(&w1_family_0d);
- }
-
- module_init(w1_f0d_init);
+++ /dev/null
-From 3280ce5f5483a351f49e84b48ad98df87989346a Mon Sep 17 00:00:00 2001
-Date: Mon, 20 May 2019 09:05:55 +0200
-Subject: [PATCH] w1: ds2413: output_write() cosmetic fixes / simplify
-
-commit ae2ee27aa985232f66421d7cd1c7f4b87c7dba7d upstream.
-
-Make the output_write simpler.
-Based on Jean-Francois Dagenais code from:
-49695ac46861 ("w1: ds2408: reset on output_write retry with readback")
-
----
- drivers/w1/slaves/w1_ds2413.c | 19 +++++++++++--------
- 1 file changed, 11 insertions(+), 8 deletions(-)
-
---- a/drivers/w1/slaves/w1_ds2413.c
-+++ b/drivers/w1/slaves/w1_ds2413.c
-@@ -69,6 +69,7 @@ static ssize_t output_write(struct file
- struct w1_slave *sl = kobj_to_w1_slave(kobj);
- u8 w1_buf[3];
- unsigned int retries = W1_F3A_RETRIES;
-+ ssize_t bytes_written = -EIO;
-
- if (count != 1 || off != 0)
- return -EFAULT;
-@@ -78,7 +79,7 @@ static ssize_t output_write(struct file
- dev_dbg(&sl->dev, "mutex locked");
-
- if (w1_reset_select_slave(sl))
-- goto error;
-+ goto out;
-
- /* according to the DS2413 datasheet the most significant 6 bits
- should be set to "1"s, so do it now */
-@@ -91,18 +92,20 @@ static ssize_t output_write(struct file
- w1_write_block(sl->master, w1_buf, 3);
-
- if (w1_read_8(sl->master) == W1_F3A_SUCCESS_CONFIRM_BYTE) {
-- mutex_unlock(&sl->master->bus_mutex);
-- dev_dbg(&sl->dev, "mutex unlocked, retries:%d", retries);
-- return 1;
-+ bytes_written = 1;
-+ goto out;
- }
- if (w1_reset_resume_command(sl->master))
-- goto error;
-+ goto out; /* unrecoverable error */
-+
-+ dev_warn(&sl->dev, "PIO_ACCESS_WRITE error, retries left: %d\n", retries);
- }
-
--error:
-+out:
- mutex_unlock(&sl->master->bus_mutex);
-- dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
-- return -EIO;
-+ dev_dbg(&sl->dev, "%s, mutex unlocked, retries: %d\n",
-+ (bytes_written > 0) ? "succeeded" : "error", retries);
-+ return bytes_written;
- }
-
- static BIN_ATTR(output, S_IRUGO | S_IWUSR | S_IWGRP, NULL, output_write, 1);
--- /dev/null
+From c84676e57896fedb47a69739fb82bb9941f624c4 Mon Sep 17 00:00:00 2001
+Date: Wed, 22 May 2019 12:40:53 +0200
+Subject: [PATCH] w1: ds2413: when the slave is not responding during
+ read, select it again
+
+commit 3856032a0628e6b94badb9131a706dda185e071d upstream.
+
+The protocol is not allowing to obtain a byte of 0xff for PIO_ACCESS_READ
+call. It is very likely that the slave was not addressed properly and
+it is just not respoding (leaving the bus in logic high state) during
+the read of sampled PIO value.
+We cannot just call w1_reset_resume_command() because the problem will
+persist, instead try selecting (addressing) the slave again.
+
+---
+ drivers/w1/slaves/w1_ds2413.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/w1/slaves/w1_ds2413.c
++++ b/drivers/w1/slaves/w1_ds2413.c
+@@ -24,6 +24,7 @@
+ #define W1_F3A_FUNC_PIO_ACCESS_READ 0xF5
+ #define W1_F3A_FUNC_PIO_ACCESS_WRITE 0x5A
+ #define W1_F3A_SUCCESS_CONFIRM_BYTE 0xAA
++#define W1_F3A_INVALID_PIO_STATE 0xFF
+
+ static ssize_t state_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf, loff_t off,
+@@ -45,6 +46,7 @@ static ssize_t state_read(struct file *f
+ mutex_lock(&sl->master->bus_mutex);
+ dev_dbg(&sl->dev, "mutex locked");
+
++next:
+ if (w1_reset_select_slave(sl))
+ goto out;
+
+@@ -52,10 +54,15 @@ static ssize_t state_read(struct file *f
+ w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
+
+ *buf = w1_read_8(sl->master);
+- /* check for correct complement */
+ if ((*buf & 0x0F) == ((~*buf >> 4) & 0x0F)) {
++ /* complement is correct */
+ bytes_read = 1;
+ goto out;
++ } else if (*buf == W1_F3A_INVALID_PIO_STATE) {
++ /* slave didn't respond, try to select it again */
++ dev_warn(&sl->dev, "slave device did not respond to PIO_ACCESS_READ, " \
++ "reselecting, retries left: %d\n", retries);
++ goto next;
+ }
+
+ if (w1_reset_resume_command(sl->master))
+++ /dev/null
-From 91e443597cdd8f89d2b68ea5bf0f0823d1853ab7 Mon Sep 17 00:00:00 2001
-Date: Mon, 20 May 2019 09:05:56 +0200
-Subject: [PATCH] w1: ds2413: add retry support to state_read()
-
-commit c50d09a86172073f55ebac0b92ad5a75907d64e7 upstream.
-
-The state_read() was calling PIO_ACCESS_READ once and bail out if it
-failed for this first time.
-This commit is improving this to trying more times before it give up,
-similarly as the write call is currently doing.
-
----
- drivers/w1/slaves/w1_ds2413.c | 37 +++++++++++++++++++++++------------
- 1 file changed, 24 insertions(+), 13 deletions(-)
-
---- a/drivers/w1/slaves/w1_ds2413.c
-+++ b/drivers/w1/slaves/w1_ds2413.c
-@@ -30,6 +30,9 @@ static ssize_t state_read(struct file *f
- size_t count)
- {
- struct w1_slave *sl = kobj_to_w1_slave(kobj);
-+ unsigned int retries = W1_F3A_RETRIES;
-+ ssize_t bytes_read = -EIO;
-+
- dev_dbg(&sl->dev,
- "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
- bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
-@@ -42,22 +45,30 @@ static ssize_t state_read(struct file *f
- mutex_lock(&sl->master->bus_mutex);
- dev_dbg(&sl->dev, "mutex locked");
-
-- if (w1_reset_select_slave(sl)) {
-- mutex_unlock(&sl->master->bus_mutex);
-- return -EIO;
-- }
-+ if (w1_reset_select_slave(sl))
-+ goto out;
-
-- w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
-- *buf = w1_read_8(sl->master);
-+ while (retries--) {
-+ w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
-
-- mutex_unlock(&sl->master->bus_mutex);
-- dev_dbg(&sl->dev, "mutex unlocked");
-+ *buf = w1_read_8(sl->master);
-+ /* check for correct complement */
-+ if ((*buf & 0x0F) == ((~*buf >> 4) & 0x0F)) {
-+ bytes_read = 1;
-+ goto out;
-+ }
-+
-+ if (w1_reset_resume_command(sl->master))
-+ goto out; /* unrecoverable error */
-
-- /* check for correct complement */
-- if ((*buf & 0x0F) != ((~*buf >> 4) & 0x0F))
-- return -EIO;
-- else
-- return 1;
-+ dev_warn(&sl->dev, "PIO_ACCESS_READ error, retries left: %d\n", retries);
-+ }
-+
-+out:
-+ mutex_unlock(&sl->master->bus_mutex);
-+ dev_dbg(&sl->dev, "%s, mutex unlocked, retries: %d\n",
-+ (bytes_read > 0) ? "succeeded" : "error", retries);
-+ return bytes_read;
- }
-
- static BIN_ATTR_RO(state, 1);
--- /dev/null
+From 38ca046063ee6fcef66c9c3bec5844a65f9d48d9 Mon Sep 17 00:00:00 2001
+Date: Thu, 30 May 2019 09:51:25 +0200
+Subject: [PATCH] w1: ds2413: fix state byte comparision
+
+commit aacd152ecd7b18af5d2d96dea9e7284c1c93abea upstream.
+
+This commit is fixing a smatch warning:
+drivers/w1/slaves/w1_ds2413.c:61 state_read() warn: impossible condition '(*buf == 255) => ((-128)-127 == 255)'
+by creating additional u8 variable for the bus reading and comparision
+
+Fixes: 3856032a0628 ("w1: ds2413: when the slave is not responding during read, select it again")
+---
+ drivers/w1/slaves/w1_ds2413.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/w1/slaves/w1_ds2413.c
++++ b/drivers/w1/slaves/w1_ds2413.c
+@@ -33,6 +33,7 @@ static ssize_t state_read(struct file *f
+ struct w1_slave *sl = kobj_to_w1_slave(kobj);
+ unsigned int retries = W1_F3A_RETRIES;
+ ssize_t bytes_read = -EIO;
++ u8 state;
+
+ dev_dbg(&sl->dev,
+ "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
+@@ -53,12 +54,13 @@ next:
+ while (retries--) {
+ w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
+
+- *buf = w1_read_8(sl->master);
+- if ((*buf & 0x0F) == ((~*buf >> 4) & 0x0F)) {
++ state = w1_read_8(sl->master);
++ if ((state & 0x0F) == ((~state >> 4) & 0x0F)) {
+ /* complement is correct */
++ *buf = state;
+ bytes_read = 1;
+ goto out;
+- } else if (*buf == W1_F3A_INVALID_PIO_STATE) {
++ } else if (state == W1_F3A_INVALID_PIO_STATE) {
+ /* slave didn't respond, try to select it again */
+ dev_warn(&sl->dev, "slave device did not respond to PIO_ACCESS_READ, " \
+ "reselecting, retries left: %d\n", retries);
--- /dev/null
+From 496b26b154da9a962a5310641d8f4b73200fe590 Mon Sep 17 00:00:00 2001
+Date: Wed, 26 Jun 2019 10:40:30 +0100
+Subject: [PATCH] drm: vc4_dsi: Fix DMA channel and memory leak in vc4
+ (#3012)
+
+---
+ drivers/gpu/drm/vc4/vc4_dsi.c | 35 ++++++++++++++++++++++++-----------
+ 1 file changed, 24 insertions(+), 11 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_dsi.c
++++ b/drivers/gpu/drm/vc4/vc4_dsi.c
+@@ -1536,9 +1536,11 @@ static int vc4_dsi_bind(struct device *d
+ /* DSI1 has a broken AXI slave that doesn't respond to writes
+ * from the ARM. It does handle writes from the DMA engine,
+ * so set up a channel for talking to it.
++ * Where possible managed resource providers are used, but the DMA channel
++ * must - if acquired - be explicitly released prior to taking an error exit path.
+ */
+ if (dsi->port == 1) {
+- dsi->reg_dma_mem = dma_alloc_coherent(dev, 4,
++ dsi->reg_dma_mem = dmam_alloc_coherent(dev, 4,
+ &dsi->reg_dma_paddr,
+ GFP_KERNEL);
+ if (!dsi->reg_dma_mem) {
+@@ -1557,6 +1559,8 @@ static int vc4_dsi_bind(struct device *d
+ return ret;
+ }
+
++ /* From here on, any error exits must release the dma channel */
++
+ /* Get the physical address of the device's registers. The
+ * struct resource for the regs gives us the bus address
+ * instead.
+@@ -1583,7 +1587,7 @@ static int vc4_dsi_bind(struct device *d
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get interrupt: %d\n", ret);
+- return ret;
++ goto rel_dma_exit;
+ }
+
+ dsi->escape_clock = devm_clk_get(dev, "escape");
+@@ -1591,7 +1595,7 @@ static int vc4_dsi_bind(struct device *d
+ ret = PTR_ERR(dsi->escape_clock);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get escape clock: %d\n", ret);
+- return ret;
++ goto rel_dma_exit;
+ }
+
+ dsi->pll_phy_clock = devm_clk_get(dev, "phy");
+@@ -1599,7 +1603,7 @@ static int vc4_dsi_bind(struct device *d
+ ret = PTR_ERR(dsi->pll_phy_clock);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get phy clock: %d\n", ret);
+- return ret;
++ goto rel_dma_exit;
+ }
+
+ dsi->pixel_clock = devm_clk_get(dev, "pixel");
+@@ -1607,7 +1611,7 @@ static int vc4_dsi_bind(struct device *d
+ ret = PTR_ERR(dsi->pixel_clock);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get pixel clock: %d\n", ret);
+- return ret;
++ goto rel_dma_exit;
+ }
+
+ ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
+@@ -1622,26 +1626,28 @@ static int vc4_dsi_bind(struct device *d
+ if (ret == -ENODEV)
+ return 0;
+
+- return ret;
++ goto rel_dma_exit;
+ }
+
+ if (panel) {
+ dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
+ DRM_MODE_CONNECTOR_DSI);
+- if (IS_ERR(dsi->bridge))
+- return PTR_ERR(dsi->bridge);
++ if (IS_ERR(dsi->bridge)){
++ ret = PTR_ERR(dsi->bridge);
++ goto rel_dma_exit;
++ }
+ }
+
+ /* The esc clock rate is supposed to always be 100Mhz. */
+ ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
+ if (ret) {
+ dev_err(dev, "Failed to set esc clock: %d\n", ret);
+- return ret;
++ goto rel_dma_exit;
+ }
+
+ ret = vc4_dsi_init_phy_clocks(dsi);
+ if (ret)
+- return ret;
++ goto rel_dma_exit;
+
+ if (dsi->port == 1)
+ vc4->dsi1 = dsi;
+@@ -1653,7 +1659,7 @@ static int vc4_dsi_bind(struct device *d
+ ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
+ if (ret) {
+ dev_err(dev, "bridge attach failed: %d\n", ret);
+- return ret;
++ goto rel_dma_exit;
+ }
+ /* Disable the atomic helper calls into the bridge. We
+ * manually call the bridge pre_enable / enable / etc. calls
+@@ -1665,6 +1671,11 @@ static int vc4_dsi_bind(struct device *d
+ pm_runtime_enable(dev);
+
+ return 0;
++
++rel_dma_exit:
++ dma_release_channel(dsi->reg_dma_chan);
++
++ return ret;
+ }
+
+ static void vc4_dsi_unbind(struct device *dev, struct device *master,
+@@ -1679,6 +1690,8 @@ static void vc4_dsi_unbind(struct device
+
+ vc4_dsi_encoder_destroy(dsi->encoder);
+
++ dma_release_channel(dsi->reg_dma_chan);
++
+ if (dsi->port == 1)
+ vc4->dsi1 = NULL;
+ }
+++ /dev/null
-From c84676e57896fedb47a69739fb82bb9941f624c4 Mon Sep 17 00:00:00 2001
-Date: Wed, 22 May 2019 12:40:53 +0200
-Subject: [PATCH] w1: ds2413: when the slave is not responding during
- read, select it again
-
-commit 3856032a0628e6b94badb9131a706dda185e071d upstream.
-
-The protocol is not allowing to obtain a byte of 0xff for PIO_ACCESS_READ
-call. It is very likely that the slave was not addressed properly and
-it is just not respoding (leaving the bus in logic high state) during
-the read of sampled PIO value.
-We cannot just call w1_reset_resume_command() because the problem will
-persist, instead try selecting (addressing) the slave again.
-
----
- drivers/w1/slaves/w1_ds2413.c | 9 ++++++++-
- 1 file changed, 8 insertions(+), 1 deletion(-)
-
---- a/drivers/w1/slaves/w1_ds2413.c
-+++ b/drivers/w1/slaves/w1_ds2413.c
-@@ -24,6 +24,7 @@
- #define W1_F3A_FUNC_PIO_ACCESS_READ 0xF5
- #define W1_F3A_FUNC_PIO_ACCESS_WRITE 0x5A
- #define W1_F3A_SUCCESS_CONFIRM_BYTE 0xAA
-+#define W1_F3A_INVALID_PIO_STATE 0xFF
-
- static ssize_t state_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr, char *buf, loff_t off,
-@@ -45,6 +46,7 @@ static ssize_t state_read(struct file *f
- mutex_lock(&sl->master->bus_mutex);
- dev_dbg(&sl->dev, "mutex locked");
-
-+next:
- if (w1_reset_select_slave(sl))
- goto out;
-
-@@ -52,10 +54,15 @@ static ssize_t state_read(struct file *f
- w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
-
- *buf = w1_read_8(sl->master);
-- /* check for correct complement */
- if ((*buf & 0x0F) == ((~*buf >> 4) & 0x0F)) {
-+ /* complement is correct */
- bytes_read = 1;
- goto out;
-+ } else if (*buf == W1_F3A_INVALID_PIO_STATE) {
-+ /* slave didn't respond, try to select it again */
-+ dev_warn(&sl->dev, "slave device did not respond to PIO_ACCESS_READ, " \
-+ "reselecting, retries left: %d\n", retries);
-+ goto next;
- }
-
- if (w1_reset_resume_command(sl->master))
--- /dev/null
+From b3fe618a47d770f6c9808ade14360fd81a599789 Mon Sep 17 00:00:00 2001
+Date: Wed, 19 Jun 2019 03:55:50 +0100
+Subject: [PATCH] video/bcm2708_fb: Revert cma allocation attempt
+
+"4600e91 Pulled in the multi frame buffer support from the Pi3 repo"
+pulled back in the code for allocating the framebuffer from the CMA
+heap.
+Revert it again.
+
+---
+ drivers/video/fbdev/bcm2708_fb.c | 101 +++------------------
+ include/soc/bcm2835/raspberrypi-firmware.h | 1 -
+ 2 files changed, 13 insertions(+), 89 deletions(-)
+
+--- a/drivers/video/fbdev/bcm2708_fb.c
++++ b/drivers/video/fbdev/bcm2708_fb.c
+@@ -112,9 +112,6 @@ struct bcm2708_fb {
+ struct vc4_display_settings_t display_settings;
+ struct debugfs_regset32 screeninfo_regset;
+ struct bcm2708_fb_dev *fbdev;
+- unsigned int image_size;
+- dma_addr_t dma_addr;
+- void *cpuaddr;
+ };
+
+ #define MAX_FRAMEBUFFERS 3
+@@ -377,12 +374,12 @@ static int bcm2708_fb_set_par(struct fb_
+ .xoffset = info->var.xoffset,
+ .yoffset = info->var.yoffset,
+ .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
+- /* base and screen_size will be initialised later */
+- .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
+- /* pitch will be initialised later */
++ .base = 0,
++ .screen_size = 0,
++ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH, 4, 0 },
++ .pitch = 0,
+ };
+- int ret, image_size;
+-
++ int ret;
+
+ print_debug("%s(%p) %dx%d (%dx%d), %d, %d (display %d)\n", __func__,
+ info,
+@@ -397,76 +394,12 @@ static int bcm2708_fb_set_par(struct fb_
+ */
+ set_display_num(fb);
+
+- /* Try allocating our own buffer. We can specify all the parameters */
+- image_size = ((info->var.xres * info->var.yres) *
+- info->var.bits_per_pixel) >> 3;
+-
+- if (!fb->fbdev->disable_arm_alloc &&
+- (image_size != fb->image_size || !fb->dma_addr)) {
+- if (fb->dma_addr) {
+- dma_free_coherent(info->device, fb->image_size,
+- fb->cpuaddr, fb->dma_addr);
+- fb->image_size = 0;
+- fb->cpuaddr = NULL;
+- fb->dma_addr = 0;
+- }
+-
+- fb->cpuaddr = dma_alloc_coherent(info->device, image_size,
+- &fb->dma_addr, GFP_KERNEL);
+-
+- if (!fb->cpuaddr) {
+- fb->dma_addr = 0;
+- fb->fbdev->disable_arm_alloc = true;
+- } else {
+- fb->image_size = image_size;
+- }
+- }
+-
+- if (fb->cpuaddr) {
+- fbinfo.base = fb->dma_addr;
+- fbinfo.screen_size = image_size;
+- fbinfo.pitch = (info->var.xres * info->var.bits_per_pixel) >> 3;
+-
+- ret = rpi_firmware_property_list(fb->fbdev->fw, &fbinfo,
+- sizeof(fbinfo));
+- if (ret || fbinfo.base != fb->dma_addr) {
+- /* Firmware either failed, or assigned a different base
+- * address (ie it doesn't support being passed an FB
+- * allocation).
+- * Destroy the allocation, and don't try again.
+- */
+- dma_free_coherent(info->device, fb->image_size,
+- fb->cpuaddr, fb->dma_addr);
+- fb->image_size = 0;
+- fb->cpuaddr = NULL;
+- fb->dma_addr = 0;
+- fb->fbdev->disable_arm_alloc = true;
+- }
+- } else {
+- /* Our allocation failed - drop into the old scheme of
+- * allocation by the VPU.
+- */
+- ret = -ENOMEM;
+- }
+-
++ ret = rpi_firmware_property_list(fb->fbdev->fw, &fbinfo,
++ sizeof(fbinfo));
+ if (ret) {
+- /* Old scheme:
+- * - FRAMEBUFFER_ALLOCATE passes 0 for base and screen_size.
+- * - GET_PITCH instead of SET_PITCH.
+- */
+- fbinfo.base = 0;
+- fbinfo.screen_size = 0;
+- fbinfo.tag6.tag = RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH;
+- fbinfo.pitch = 0;
+-
+- ret = rpi_firmware_property_list(fb->fbdev->fw, &fbinfo,
+- sizeof(fbinfo));
+- if (ret) {
+- dev_err(info->device,
+- "Failed to allocate GPU framebuffer (%d)\n",
+- ret);
+- return ret;
+- }
++ dev_err(info->device,
++ "Failed to allocate GPU framebuffer (%d)\n", ret);
++ return ret;
+ }
+
+ if (info->var.bits_per_pixel <= 8)
+@@ -481,17 +414,9 @@ static int bcm2708_fb_set_par(struct fb_
+ fb->fb.fix.smem_start = fbinfo.base;
+ fb->fb.fix.smem_len = fbinfo.pitch * fbinfo.yres_virtual;
+ fb->fb.screen_size = fbinfo.screen_size;
+-
+- if (!fb->dma_addr) {
+- if (fb->fb.screen_base)
+- iounmap(fb->fb.screen_base);
+-
+- fb->fb.screen_base = ioremap_wc(fbinfo.base,
+- fb->fb.screen_size);
+- } else {
+- fb->fb.screen_base = fb->cpuaddr;
+- }
+-
++ if (fb->fb.screen_base)
++ iounmap(fb->fb.screen_base);
++ fb->fb.screen_base = ioremap_wc(fbinfo.base, fb->fb.screen_size);
+ if (!fb->fb.screen_base) {
+ /* the console may currently be locked */
+ console_trylock();
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -138,7 +138,6 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007,
+- RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH = 0x00048008,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
+++ /dev/null
-From 38ca046063ee6fcef66c9c3bec5844a65f9d48d9 Mon Sep 17 00:00:00 2001
-Date: Thu, 30 May 2019 09:51:25 +0200
-Subject: [PATCH] w1: ds2413: fix state byte comparision
-
-commit aacd152ecd7b18af5d2d96dea9e7284c1c93abea upstream.
-
-This commit is fixing a smatch warning:
-drivers/w1/slaves/w1_ds2413.c:61 state_read() warn: impossible condition '(*buf == 255) => ((-128)-127 == 255)'
-by creating additional u8 variable for the bus reading and comparision
-
-Fixes: 3856032a0628 ("w1: ds2413: when the slave is not responding during read, select it again")
----
- drivers/w1/slaves/w1_ds2413.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/drivers/w1/slaves/w1_ds2413.c
-+++ b/drivers/w1/slaves/w1_ds2413.c
-@@ -33,6 +33,7 @@ static ssize_t state_read(struct file *f
- struct w1_slave *sl = kobj_to_w1_slave(kobj);
- unsigned int retries = W1_F3A_RETRIES;
- ssize_t bytes_read = -EIO;
-+ u8 state;
-
- dev_dbg(&sl->dev,
- "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
-@@ -53,12 +54,13 @@ next:
- while (retries--) {
- w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
-
-- *buf = w1_read_8(sl->master);
-- if ((*buf & 0x0F) == ((~*buf >> 4) & 0x0F)) {
-+ state = w1_read_8(sl->master);
-+ if ((state & 0x0F) == ((~state >> 4) & 0x0F)) {
- /* complement is correct */
-+ *buf = state;
- bytes_read = 1;
- goto out;
-- } else if (*buf == W1_F3A_INVALID_PIO_STATE) {
-+ } else if (state == W1_F3A_INVALID_PIO_STATE) {
- /* slave didn't respond, try to select it again */
- dev_warn(&sl->dev, "slave device did not respond to PIO_ACCESS_READ, " \
- "reselecting, retries left: %d\n", retries);
--- /dev/null
+From ee96684cb2f528ad1036ae9a9126c9118a80dfbe Mon Sep 17 00:00:00 2001
+Date: Mon, 24 Jun 2019 02:29:40 +0100
+Subject: [PATCH] drm/vc4: Add support for color encoding on YUV planes
+
+Adds signalling for BT601/709/2020, and limited/full range
+(on BT601).
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 32 +++++++++++++++++++++++++-
+ drivers/gpu/drm/vc4/vc_image_types.h | 28 ++++++++++++++++++++++
+ 2 files changed, 59 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -66,7 +66,7 @@ struct set_plane {
+ u8 alpha;
+ u8 num_planes;
+ u8 is_vu;
+- u8 padding;
++ u8 color_encoding;
+
+ u32 planes[4]; /* DMA address of each plane */
+
+@@ -454,6 +454,28 @@ static void vc4_plane_atomic_update(stru
+ if (num_planes == 3 &&
+ (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1])
+ mb->plane.vc_image_type = VC_IMAGE_YUV420_S;
++
++ switch (state->color_encoding) {
++ default:
++ case DRM_COLOR_YCBCR_BT601:
++ if (state->color_range == DRM_COLOR_YCBCR_LIMITED_RANGE)
++ mb->plane.color_encoding =
++ VC_IMAGE_YUVINFO_CSC_ITUR_BT601;
++ else
++ mb->plane.color_encoding =
++ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF;
++ break;
++ case DRM_COLOR_YCBCR_BT709:
++ /* Currently no support for a full range BT709 */
++ mb->plane.color_encoding =
++ VC_IMAGE_YUVINFO_CSC_ITUR_BT709;
++ break;
++ case DRM_COLOR_YCBCR_BT2020:
++ /* Currently no support for a full range BT2020 */
++ mb->plane.color_encoding =
++ VC_IMAGE_YUVINFO_CSC_REC_2020;
++ break;
++ }
+ } else {
+ mb->plane.planes[1] = 0;
+ mb->plane.planes[2] = 0;
+@@ -643,6 +665,14 @@ static struct drm_plane *vc4_fkms_plane_
+ drm_plane_create_alpha_property(plane);
+ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
+ SUPPORTED_ROTATIONS);
++ drm_plane_create_color_properties(plane,
++ BIT(DRM_COLOR_YCBCR_BT601) |
++ BIT(DRM_COLOR_YCBCR_BT709) |
++ BIT(DRM_COLOR_YCBCR_BT2020),
++ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
++ BIT(DRM_COLOR_YCBCR_FULL_RANGE),
++ DRM_COLOR_YCBCR_BT709,
++ DRM_COLOR_YCBCR_LIMITED_RANGE);
+
+ /*
+ * Default frame buffer setup is with FB on -127, and raspistill etc
+--- a/drivers/gpu/drm/vc4/vc_image_types.h
++++ b/drivers/gpu/drm/vc4/vc_image_types.h
+@@ -4,6 +4,8 @@
+ *
+ * Values taken from vc_image_types.h released by Broadcom at
+ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h
++ * and vc_image_structs.h at
++ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_structs.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+@@ -141,3 +143,29 @@ enum {
+ VC_IMAGE_MAX, /* bounds for error checking */
+ VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
+ };
++
++enum {
++ /* Unknown or unset - defaults to BT601 interstitial */
++ VC_IMAGE_YUVINFO_UNSPECIFIED = 0,
++
++ /* colour-space conversions data [4 bits] */
++
++ /* ITU-R BT.601-5 [SDTV] (compatible with VideoCore-II) */
++ VC_IMAGE_YUVINFO_CSC_ITUR_BT601 = 1,
++ /* ITU-R BT.709-3 [HDTV] */
++ VC_IMAGE_YUVINFO_CSC_ITUR_BT709 = 2,
++ /* JPEG JFIF */
++ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF = 3,
++ /* Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
++ VC_IMAGE_YUVINFO_CSC_FCC = 4,
++ /* Society of Motion Picture and Television Engineers 240M (1999) */
++ VC_IMAGE_YUVINFO_CSC_SMPTE_240M = 5,
++ /* ITU-R BT.470-2 System M */
++ VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_M = 6,
++ /* ITU-R BT.470-2 System B,G */
++ VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_BG = 7,
++ /* JPEG JFIF, but with 16..255 luma */
++ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF_Y16_255 = 8,
++ /* Rec 2020 */
++ VC_IMAGE_YUVINFO_CSC_REC_2020 = 9,
++};
+++ /dev/null
-From 496b26b154da9a962a5310641d8f4b73200fe590 Mon Sep 17 00:00:00 2001
-Date: Wed, 26 Jun 2019 10:40:30 +0100
-Subject: [PATCH] drm: vc4_dsi: Fix DMA channel and memory leak in vc4
- (#3012)
-
----
- drivers/gpu/drm/vc4/vc4_dsi.c | 35 ++++++++++++++++++++++++-----------
- 1 file changed, 24 insertions(+), 11 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_dsi.c
-+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
-@@ -1536,9 +1536,11 @@ static int vc4_dsi_bind(struct device *d
- /* DSI1 has a broken AXI slave that doesn't respond to writes
- * from the ARM. It does handle writes from the DMA engine,
- * so set up a channel for talking to it.
-+ * Where possible managed resource providers are used, but the DMA channel
-+ * must - if acquired - be explicitly released prior to taking an error exit path.
- */
- if (dsi->port == 1) {
-- dsi->reg_dma_mem = dma_alloc_coherent(dev, 4,
-+ dsi->reg_dma_mem = dmam_alloc_coherent(dev, 4,
- &dsi->reg_dma_paddr,
- GFP_KERNEL);
- if (!dsi->reg_dma_mem) {
-@@ -1557,6 +1559,8 @@ static int vc4_dsi_bind(struct device *d
- return ret;
- }
-
-+ /* From here on, any error exits must release the dma channel */
-+
- /* Get the physical address of the device's registers. The
- * struct resource for the regs gives us the bus address
- * instead.
-@@ -1583,7 +1587,7 @@ static int vc4_dsi_bind(struct device *d
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Failed to get interrupt: %d\n", ret);
-- return ret;
-+ goto rel_dma_exit;
- }
-
- dsi->escape_clock = devm_clk_get(dev, "escape");
-@@ -1591,7 +1595,7 @@ static int vc4_dsi_bind(struct device *d
- ret = PTR_ERR(dsi->escape_clock);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Failed to get escape clock: %d\n", ret);
-- return ret;
-+ goto rel_dma_exit;
- }
-
- dsi->pll_phy_clock = devm_clk_get(dev, "phy");
-@@ -1599,7 +1603,7 @@ static int vc4_dsi_bind(struct device *d
- ret = PTR_ERR(dsi->pll_phy_clock);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Failed to get phy clock: %d\n", ret);
-- return ret;
-+ goto rel_dma_exit;
- }
-
- dsi->pixel_clock = devm_clk_get(dev, "pixel");
-@@ -1607,7 +1611,7 @@ static int vc4_dsi_bind(struct device *d
- ret = PTR_ERR(dsi->pixel_clock);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Failed to get pixel clock: %d\n", ret);
-- return ret;
-+ goto rel_dma_exit;
- }
-
- ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
-@@ -1622,26 +1626,28 @@ static int vc4_dsi_bind(struct device *d
- if (ret == -ENODEV)
- return 0;
-
-- return ret;
-+ goto rel_dma_exit;
- }
-
- if (panel) {
- dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
- DRM_MODE_CONNECTOR_DSI);
-- if (IS_ERR(dsi->bridge))
-- return PTR_ERR(dsi->bridge);
-+ if (IS_ERR(dsi->bridge)){
-+ ret = PTR_ERR(dsi->bridge);
-+ goto rel_dma_exit;
-+ }
- }
-
- /* The esc clock rate is supposed to always be 100Mhz. */
- ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
- if (ret) {
- dev_err(dev, "Failed to set esc clock: %d\n", ret);
-- return ret;
-+ goto rel_dma_exit;
- }
-
- ret = vc4_dsi_init_phy_clocks(dsi);
- if (ret)
-- return ret;
-+ goto rel_dma_exit;
-
- if (dsi->port == 1)
- vc4->dsi1 = dsi;
-@@ -1653,7 +1659,7 @@ static int vc4_dsi_bind(struct device *d
- ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
- if (ret) {
- dev_err(dev, "bridge attach failed: %d\n", ret);
-- return ret;
-+ goto rel_dma_exit;
- }
- /* Disable the atomic helper calls into the bridge. We
- * manually call the bridge pre_enable / enable / etc. calls
-@@ -1665,6 +1671,11 @@ static int vc4_dsi_bind(struct device *d
- pm_runtime_enable(dev);
-
- return 0;
-+
-+rel_dma_exit:
-+ dma_release_channel(dsi->reg_dma_chan);
-+
-+ return ret;
- }
-
- static void vc4_dsi_unbind(struct device *dev, struct device *master,
-@@ -1679,6 +1690,8 @@ static void vc4_dsi_unbind(struct device
-
- vc4_dsi_encoder_destroy(dsi->encoder);
-
-+ dma_release_channel(dsi->reg_dma_chan);
-+
- if (dsi->port == 1)
- vc4->dsi1 = NULL;
- }
--- /dev/null
+From f9dfd577dcc8e3173ddce79bca535eeee0fad1a4 Mon Sep 17 00:00:00 2001
+Date: Tue, 2 Jul 2019 17:13:05 +0100
+Subject: [PATCH] arm: dts: Add coherent_pool=1M to Pi 4 bootargs
+
+Downstream Raspberry Pi dts files add "coherent_pool=1M" to the kernel
+command line to aid the dwc_otg driver, but this excluded Pi 4 which
+uses a new XCHI interface instead. UAS also benefits from a larger
+coherent_pool value, so replicate the addition in bcm2711-rpi-4-b.dts.
+
+See: https://github.com/raspberrypi/linux/pull/3040
+
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -14,7 +14,7 @@
+ };
+
+ chosen {
+- bootargs = "8250.nr_uarts=1 cma=64M";
++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 cma=64M";
+ };
+
+ aliases {
+++ /dev/null
-From b3fe618a47d770f6c9808ade14360fd81a599789 Mon Sep 17 00:00:00 2001
-Date: Wed, 19 Jun 2019 03:55:50 +0100
-Subject: [PATCH] video/bcm2708_fb: Revert cma allocation attempt
-
-"4600e91 Pulled in the multi frame buffer support from the Pi3 repo"
-pulled back in the code for allocating the framebuffer from the CMA
-heap.
-Revert it again.
-
----
- drivers/video/fbdev/bcm2708_fb.c | 101 +++------------------
- include/soc/bcm2835/raspberrypi-firmware.h | 1 -
- 2 files changed, 13 insertions(+), 89 deletions(-)
-
---- a/drivers/video/fbdev/bcm2708_fb.c
-+++ b/drivers/video/fbdev/bcm2708_fb.c
-@@ -112,9 +112,6 @@ struct bcm2708_fb {
- struct vc4_display_settings_t display_settings;
- struct debugfs_regset32 screeninfo_regset;
- struct bcm2708_fb_dev *fbdev;
-- unsigned int image_size;
-- dma_addr_t dma_addr;
-- void *cpuaddr;
- };
-
- #define MAX_FRAMEBUFFERS 3
-@@ -377,12 +374,12 @@ static int bcm2708_fb_set_par(struct fb_
- .xoffset = info->var.xoffset,
- .yoffset = info->var.yoffset,
- .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
-- /* base and screen_size will be initialised later */
-- .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
-- /* pitch will be initialised later */
-+ .base = 0,
-+ .screen_size = 0,
-+ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH, 4, 0 },
-+ .pitch = 0,
- };
-- int ret, image_size;
--
-+ int ret;
-
- print_debug("%s(%p) %dx%d (%dx%d), %d, %d (display %d)\n", __func__,
- info,
-@@ -397,76 +394,12 @@ static int bcm2708_fb_set_par(struct fb_
- */
- set_display_num(fb);
-
-- /* Try allocating our own buffer. We can specify all the parameters */
-- image_size = ((info->var.xres * info->var.yres) *
-- info->var.bits_per_pixel) >> 3;
--
-- if (!fb->fbdev->disable_arm_alloc &&
-- (image_size != fb->image_size || !fb->dma_addr)) {
-- if (fb->dma_addr) {
-- dma_free_coherent(info->device, fb->image_size,
-- fb->cpuaddr, fb->dma_addr);
-- fb->image_size = 0;
-- fb->cpuaddr = NULL;
-- fb->dma_addr = 0;
-- }
--
-- fb->cpuaddr = dma_alloc_coherent(info->device, image_size,
-- &fb->dma_addr, GFP_KERNEL);
--
-- if (!fb->cpuaddr) {
-- fb->dma_addr = 0;
-- fb->fbdev->disable_arm_alloc = true;
-- } else {
-- fb->image_size = image_size;
-- }
-- }
--
-- if (fb->cpuaddr) {
-- fbinfo.base = fb->dma_addr;
-- fbinfo.screen_size = image_size;
-- fbinfo.pitch = (info->var.xres * info->var.bits_per_pixel) >> 3;
--
-- ret = rpi_firmware_property_list(fb->fbdev->fw, &fbinfo,
-- sizeof(fbinfo));
-- if (ret || fbinfo.base != fb->dma_addr) {
-- /* Firmware either failed, or assigned a different base
-- * address (ie it doesn't support being passed an FB
-- * allocation).
-- * Destroy the allocation, and don't try again.
-- */
-- dma_free_coherent(info->device, fb->image_size,
-- fb->cpuaddr, fb->dma_addr);
-- fb->image_size = 0;
-- fb->cpuaddr = NULL;
-- fb->dma_addr = 0;
-- fb->fbdev->disable_arm_alloc = true;
-- }
-- } else {
-- /* Our allocation failed - drop into the old scheme of
-- * allocation by the VPU.
-- */
-- ret = -ENOMEM;
-- }
--
-+ ret = rpi_firmware_property_list(fb->fbdev->fw, &fbinfo,
-+ sizeof(fbinfo));
- if (ret) {
-- /* Old scheme:
-- * - FRAMEBUFFER_ALLOCATE passes 0 for base and screen_size.
-- * - GET_PITCH instead of SET_PITCH.
-- */
-- fbinfo.base = 0;
-- fbinfo.screen_size = 0;
-- fbinfo.tag6.tag = RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH;
-- fbinfo.pitch = 0;
--
-- ret = rpi_firmware_property_list(fb->fbdev->fw, &fbinfo,
-- sizeof(fbinfo));
-- if (ret) {
-- dev_err(info->device,
-- "Failed to allocate GPU framebuffer (%d)\n",
-- ret);
-- return ret;
-- }
-+ dev_err(info->device,
-+ "Failed to allocate GPU framebuffer (%d)\n", ret);
-+ return ret;
- }
-
- if (info->var.bits_per_pixel <= 8)
-@@ -481,17 +414,9 @@ static int bcm2708_fb_set_par(struct fb_
- fb->fb.fix.smem_start = fbinfo.base;
- fb->fb.fix.smem_len = fbinfo.pitch * fbinfo.yres_virtual;
- fb->fb.screen_size = fbinfo.screen_size;
--
-- if (!fb->dma_addr) {
-- if (fb->fb.screen_base)
-- iounmap(fb->fb.screen_base);
--
-- fb->fb.screen_base = ioremap_wc(fbinfo.base,
-- fb->fb.screen_size);
-- } else {
-- fb->fb.screen_base = fb->cpuaddr;
-- }
--
-+ if (fb->fb.screen_base)
-+ iounmap(fb->fb.screen_base);
-+ fb->fb.screen_base = ioremap_wc(fbinfo.base, fb->fb.screen_size);
- if (!fb->fb.screen_base) {
- /* the console may currently be locked */
- console_trylock();
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -138,7 +138,6 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
- RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006,
- RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007,
-- RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH = 0x00048008,
- RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
- RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
- RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
+++ /dev/null
-From ee96684cb2f528ad1036ae9a9126c9118a80dfbe Mon Sep 17 00:00:00 2001
-Date: Mon, 24 Jun 2019 02:29:40 +0100
-Subject: [PATCH] drm/vc4: Add support for color encoding on YUV planes
-
-Adds signalling for BT601/709/2020, and limited/full range
-(on BT601).
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 32 +++++++++++++++++++++++++-
- drivers/gpu/drm/vc4/vc_image_types.h | 28 ++++++++++++++++++++++
- 2 files changed, 59 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -66,7 +66,7 @@ struct set_plane {
- u8 alpha;
- u8 num_planes;
- u8 is_vu;
-- u8 padding;
-+ u8 color_encoding;
-
- u32 planes[4]; /* DMA address of each plane */
-
-@@ -454,6 +454,28 @@ static void vc4_plane_atomic_update(stru
- if (num_planes == 3 &&
- (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1])
- mb->plane.vc_image_type = VC_IMAGE_YUV420_S;
-+
-+ switch (state->color_encoding) {
-+ default:
-+ case DRM_COLOR_YCBCR_BT601:
-+ if (state->color_range == DRM_COLOR_YCBCR_LIMITED_RANGE)
-+ mb->plane.color_encoding =
-+ VC_IMAGE_YUVINFO_CSC_ITUR_BT601;
-+ else
-+ mb->plane.color_encoding =
-+ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF;
-+ break;
-+ case DRM_COLOR_YCBCR_BT709:
-+ /* Currently no support for a full range BT709 */
-+ mb->plane.color_encoding =
-+ VC_IMAGE_YUVINFO_CSC_ITUR_BT709;
-+ break;
-+ case DRM_COLOR_YCBCR_BT2020:
-+ /* Currently no support for a full range BT2020 */
-+ mb->plane.color_encoding =
-+ VC_IMAGE_YUVINFO_CSC_REC_2020;
-+ break;
-+ }
- } else {
- mb->plane.planes[1] = 0;
- mb->plane.planes[2] = 0;
-@@ -643,6 +665,14 @@ static struct drm_plane *vc4_fkms_plane_
- drm_plane_create_alpha_property(plane);
- drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
- SUPPORTED_ROTATIONS);
-+ drm_plane_create_color_properties(plane,
-+ BIT(DRM_COLOR_YCBCR_BT601) |
-+ BIT(DRM_COLOR_YCBCR_BT709) |
-+ BIT(DRM_COLOR_YCBCR_BT2020),
-+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
-+ BIT(DRM_COLOR_YCBCR_FULL_RANGE),
-+ DRM_COLOR_YCBCR_BT709,
-+ DRM_COLOR_YCBCR_LIMITED_RANGE);
-
- /*
- * Default frame buffer setup is with FB on -127, and raspistill etc
---- a/drivers/gpu/drm/vc4/vc_image_types.h
-+++ b/drivers/gpu/drm/vc4/vc_image_types.h
-@@ -4,6 +4,8 @@
- *
- * Values taken from vc_image_types.h released by Broadcom at
- * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h
-+ * and vc_image_structs.h at
-+ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_structs.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
-@@ -141,3 +143,29 @@ enum {
- VC_IMAGE_MAX, /* bounds for error checking */
- VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
- };
-+
-+enum {
-+ /* Unknown or unset - defaults to BT601 interstitial */
-+ VC_IMAGE_YUVINFO_UNSPECIFIED = 0,
-+
-+ /* colour-space conversions data [4 bits] */
-+
-+ /* ITU-R BT.601-5 [SDTV] (compatible with VideoCore-II) */
-+ VC_IMAGE_YUVINFO_CSC_ITUR_BT601 = 1,
-+ /* ITU-R BT.709-3 [HDTV] */
-+ VC_IMAGE_YUVINFO_CSC_ITUR_BT709 = 2,
-+ /* JPEG JFIF */
-+ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF = 3,
-+ /* Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
-+ VC_IMAGE_YUVINFO_CSC_FCC = 4,
-+ /* Society of Motion Picture and Television Engineers 240M (1999) */
-+ VC_IMAGE_YUVINFO_CSC_SMPTE_240M = 5,
-+ /* ITU-R BT.470-2 System M */
-+ VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_M = 6,
-+ /* ITU-R BT.470-2 System B,G */
-+ VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_BG = 7,
-+ /* JPEG JFIF, but with 16..255 luma */
-+ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF_Y16_255 = 8,
-+ /* Rec 2020 */
-+ VC_IMAGE_YUVINFO_CSC_REC_2020 = 9,
-+};
--- /dev/null
+From 21e4c9306bd20ab4e02f90cd452d90bc4e4a0a98 Mon Sep 17 00:00:00 2001
+Date: Wed, 3 Jul 2019 20:37:14 +0100
+Subject: [PATCH] overlays: Correct gpio-fan gpio flags for 4.19
+
+The gpio-fan overlay was submitted for the 4.14 kernel where the second
+value in the Device Tree gpios declaration was ignored (thanks to an
+old-style driver), allowing the fan-control output to be active-high
+even though the declaration appears to request it be active-low.
+The gpio-fan driver in 4.19 uses GPIO descriptors and honours the
+active-low flag that the overlay (accidentally?) supplies.
+
+Change/correct the flags field to mark the GPIO as active-high.
+
+---
+ arch/arm/boot/dts/overlays/gpio-fan-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts
+@@ -45,7 +45,7 @@
+ __overlay__ {
+ fan0: gpio-fan@0 {
+ compatible = "gpio-fan";
+- gpios = <&gpio 12 1>;
++ gpios = <&gpio 12 0>;
+ gpio-fan,speed-map = <0 0>,
+ <5000 1>;
+ #cooling-cells = <2>;
+++ /dev/null
-From f9dfd577dcc8e3173ddce79bca535eeee0fad1a4 Mon Sep 17 00:00:00 2001
-Date: Tue, 2 Jul 2019 17:13:05 +0100
-Subject: [PATCH] arm: dts: Add coherent_pool=1M to Pi 4 bootargs
-
-Downstream Raspberry Pi dts files add "coherent_pool=1M" to the kernel
-command line to aid the dwc_otg driver, but this excluded Pi 4 which
-uses a new XCHI interface instead. UAS also benefits from a larger
-coherent_pool value, so replicate the addition in bcm2711-rpi-4-b.dts.
-
-See: https://github.com/raspberrypi/linux/pull/3040
-
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -14,7 +14,7 @@
- };
-
- chosen {
-- bootargs = "8250.nr_uarts=1 cma=64M";
-+ bootargs = "coherent_pool=1M 8250.nr_uarts=1 cma=64M";
- };
-
- aliases {
--- /dev/null
+From b30537425b4bf90311b8d43c95484d9d339be25f Mon Sep 17 00:00:00 2001
+Date: Tue, 25 Jun 2019 00:29:44 +0100
+Subject: [PATCH] staging: vcsm-cma: Remove cache manipulation ioctl
+ from ARM64
+
+The cache flushing ioctls are used by the Pi3 HEVC hw-assisted
+decoder as it needs finer grained flushing control than dma_ops
+allow.
+These cache calls are not present for ARM64, therefore disable
+them. We are not actively supporting 64bit kernels at present,
+and the use case of the HEVC decoder is fairly limited.
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -1259,6 +1259,7 @@ error:
+ return ret;
+ }
+
++#ifndef CONFIG_ARM64
+ /* Converts VCSM_CACHE_OP_* to an operating function. */
+ static void (*cache_op_to_func(const unsigned int cache_op))
+ (const void*, const void*)
+@@ -1351,6 +1352,7 @@ out:
+
+ return ret;
+ }
++#endif
+
+ static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+@@ -1448,6 +1450,7 @@ static long vc_sm_cma_ioctl(struct file
+ break;
+ }
+
++#ifndef CONFIG_ARM64
+ /*
+ * Flush/Invalidate the cache for a given mapping.
+ * Blocks must be pinned (i.e. accessed) before this call.
+@@ -1455,6 +1458,7 @@ static long vc_sm_cma_ioctl(struct file
+ case VC_SM_CMA_CMD_CLEAN_INVALID2:
+ ret = vc_sm_cma_clean_invalid2(cmdnr, arg);
+ break;
++#endif
+
+ default:
+ pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
+@@ -1467,6 +1471,7 @@ static long vc_sm_cma_ioctl(struct file
+ return ret;
+ }
+
++#ifndef CONFIG_ARM64
+ #ifdef CONFIG_COMPAT
+ struct vc_sm_cma_ioctl_clean_invalid2_32 {
+ u32 op_count;
+@@ -1496,14 +1501,17 @@ static long vc_sm_cma_compat_ioctl(struc
+ }
+ }
+ #endif
++#endif
+
+ /* Device operations that we managed in this driver. */
+ static const struct file_operations vc_sm_ops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = vc_sm_cma_ioctl,
++#ifndef CONFIG_ARM64
+ #ifdef CONFIG_COMPAT
+ .compat_ioctl = vc_sm_cma_compat_ioctl,
+ #endif
++#endif
+ .open = vc_sm_cma_open,
+ .release = vc_sm_cma_release,
+ };
+++ /dev/null
-From 21e4c9306bd20ab4e02f90cd452d90bc4e4a0a98 Mon Sep 17 00:00:00 2001
-Date: Wed, 3 Jul 2019 20:37:14 +0100
-Subject: [PATCH] overlays: Correct gpio-fan gpio flags for 4.19
-
-The gpio-fan overlay was submitted for the 4.14 kernel where the second
-value in the Device Tree gpios declaration was ignored (thanks to an
-old-style driver), allowing the fan-control output to be active-high
-even though the declaration appears to request it be active-low.
-The gpio-fan driver in 4.19 uses GPIO descriptors and honours the
-active-low flag that the overlay (accidentally?) supplies.
-
-Change/correct the flags field to mark the GPIO as active-high.
-
----
- arch/arm/boot/dts/overlays/gpio-fan-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts
-@@ -45,7 +45,7 @@
- __overlay__ {
- fan0: gpio-fan@0 {
- compatible = "gpio-fan";
-- gpios = <&gpio 12 1>;
-+ gpios = <&gpio 12 0>;
- gpio-fan,speed-map = <0 0>,
- <5000 1>;
- #cooling-cells = <2>;
--- /dev/null
+From e4cb138abe457a6ab9b98458660a1c8e548fab7f Mon Sep 17 00:00:00 2001
+Date: Mon, 1 Jul 2019 11:57:25 +0100
+Subject: [PATCH] staging: vcsm-cma: Rework to use dma APIs, not CMA
+
+Due to a misunderstanding of the DMA mapping APIs, I made
+the wrong decision on how to implement this.
+
+Rework to use dma_alloc_coherent instead of the CMA
+API. This also allows it to be built as a module easily.
+
+---
+ .../staging/vc04_services/vc-sm-cma/Kconfig | 4 +-
+ .../staging/vc04_services/vc-sm-cma/Makefile | 2 +-
+ .../staging/vc04_services/vc-sm-cma/vc_sm.c | 291 ++++++++++--------
+ .../staging/vc04_services/vc-sm-cma/vc_sm.h | 13 +-
+ .../vc04_services/vc-sm-cma/vc_sm_cma.c | 98 ------
+ .../vc04_services/vc-sm-cma/vc_sm_cma.h | 39 ---
+ 6 files changed, 168 insertions(+), 279 deletions(-)
+ delete mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
+ delete mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/Kconfig
++++ b/drivers/staging/vc04_services/vc-sm-cma/Kconfig
+@@ -1,6 +1,6 @@
+ config BCM_VC_SM_CMA
+- bool "VideoCore Shared Memory (CMA) driver"
+- depends on BCM2835_VCHIQ && DMA_CMA
++ tristate "VideoCore Shared Memory (CMA) driver"
++ depends on BCM2835_VCHIQ
+ select RBTREE
+ select DMA_SHARED_BUFFER
+ help
+--- a/drivers/staging/vc04_services/vc-sm-cma/Makefile
++++ b/drivers/staging/vc04_services/vc-sm-cma/Makefile
+@@ -3,6 +3,6 @@ ccflags-y += -Idrivers/staging/vc04_serv
+ ccflags-y += -D__VCCOREVER__=0
+
+ vc-sm-cma-$(CONFIG_BCM_VC_SM_CMA) := \
+- vc_sm.o vc_sm_cma_vchi.o vc_sm_cma.o
++ vc_sm.o vc_sm_cma_vchi.o
+
+ obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma.o
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -6,8 +6,8 @@
+ *
+ * Based on vmcs_sm driver from Broadcom Corporation for some API,
+- * and taking some code for CMA/dmabuf handling from the Android Ion
+- * driver (Google/Linaro).
++ * and taking some code for buffer allocation and dmabuf handling from
++ * videobuf2.
+ *
+ *
+ * This driver has 3 main uses:
+@@ -52,7 +52,6 @@
+ #include "vc_sm_cma_vchi.h"
+
+ #include "vc_sm.h"
+-#include "vc_sm_cma.h"
+ #include "vc_sm_knl.h"
+ #include <linux/broadcom/vc_sm_cma_ioctl.h>
+
+@@ -89,7 +88,6 @@ struct sm_state_t {
+ struct miscdevice misc_dev;
+
+ struct sm_instance *sm_handle; /* Handle for videocore service. */
+- struct cma *cma_heap;
+
+ spinlock_t kernelid_map_lock; /* Spinlock protecting kernelid_map */
+ struct idr kernelid_map;
+@@ -110,8 +108,9 @@ struct sm_state_t {
+
+ struct vc_sm_dma_buf_attachment {
+ struct device *dev;
+- struct sg_table *table;
++ struct sg_table sg_table;
+ struct list_head list;
++ enum dma_data_direction dma_dir;
+ };
+
+ /* ---- Private Variables ----------------------------------------------- */
+@@ -202,9 +201,10 @@ static int vc_sm_cma_global_state_show(s
+ resource->import.attach);
+ seq_printf(s, " SGT %p\n",
+ resource->import.sgt);
++ } else {
++ seq_printf(s, " SGT %p\n",
++ resource->alloc.sg_table);
+ }
+- seq_printf(s, " SG_TABLE %p\n",
+- resource->sg_table);
+ seq_printf(s, " DMA_ADDR %pad\n",
+ &resource->dma_addr);
+ seq_printf(s, " VC_HANDLE %08x\n",
+@@ -296,8 +296,9 @@ static void vc_sm_vpu_free(struct vc_sm_
+ */
+ static void vc_sm_release_resource(struct vc_sm_buffer *buffer)
+ {
+- pr_debug("[%s]: buffer %p (name %s, size %zu)\n",
+- __func__, buffer, buffer->name, buffer->size);
++ pr_debug("[%s]: buffer %p (name %s, size %zu), imported %u\n",
++ __func__, buffer, buffer->name, buffer->size,
++ buffer->imported);
+
+ if (buffer->vc_handle) {
+ /* We've sent the unmap request but not had the response. */
+@@ -313,8 +314,6 @@ static void vc_sm_release_resource(struc
+
+ /* Release the allocation (whether imported dmabuf or CMA allocation) */
+ if (buffer->imported) {
+- pr_debug("%s: Release imported dmabuf %p\n", __func__,
+- buffer->import.dma_buf);
+ if (buffer->import.dma_buf)
+ dma_buf_put(buffer->import.dma_buf);
+ else
+@@ -322,16 +321,8 @@ static void vc_sm_release_resource(struc
+ __func__, buffer);
+ buffer->import.dma_buf = NULL;
+ } else {
+- if (buffer->sg_table) {
+- /* Our own allocation that we need to dma_unmap_sg */
+- dma_unmap_sg(&sm_state->pdev->dev,
+- buffer->sg_table->sgl,
+- buffer->sg_table->nents,
+- DMA_BIDIRECTIONAL);
+- }
+- pr_debug("%s: Release our allocation\n", __func__);
+- vc_sm_cma_buffer_free(&buffer->alloc);
+- pr_debug("%s: Release our allocation - done\n", __func__);
++ dma_free_coherent(&sm_state->pdev->dev, buffer->size,
++ buffer->cookie, buffer->dma_addr);
+ }
+
+
+@@ -371,38 +362,6 @@ static struct vc_sm_privdata_t *vc_sm_cm
+ return file_data;
+ }
+
+-static struct sg_table *dup_sg_table(struct sg_table *table)
+-{
+- struct sg_table *new_table;
+- int ret, i;
+- struct scatterlist *sg, *new_sg;
+-
+- new_table = kzalloc(sizeof(*new_table), GFP_KERNEL);
+- if (!new_table)
+- return ERR_PTR(-ENOMEM);
+-
+- ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
+- if (ret) {
+- kfree(new_table);
+- return ERR_PTR(ret);
+- }
+-
+- new_sg = new_table->sgl;
+- for_each_sg(table->sgl, sg, table->nents, i) {
+- memcpy(new_sg, sg, sizeof(*sg));
+- sg->dma_address = 0;
+- new_sg = sg_next(new_sg);
+- }
+-
+- return new_table;
+-}
+-
+-static void free_duped_table(struct sg_table *table)
+-{
+- sg_free_table(table);
+- kfree(table);
+-}
+-
+ /* Dma buf operations for use with our own allocations */
+
+ static int vc_sm_dma_buf_attach(struct dma_buf *dmabuf,
+@@ -410,28 +369,45 @@ static int vc_sm_dma_buf_attach(struct d
+
+ {
+ struct vc_sm_dma_buf_attachment *a;
+- struct sg_table *table;
++ struct sg_table *sgt;
+ struct vc_sm_buffer *buf = dmabuf->priv;
++ struct scatterlist *rd, *wr;
++ int ret, i;
+
+ a = kzalloc(sizeof(*a), GFP_KERNEL);
+ if (!a)
+ return -ENOMEM;
+
+- table = dup_sg_table(buf->sg_table);
+- if (IS_ERR(table)) {
++ pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
++
++ mutex_lock(&buf->lock);
++
++ INIT_LIST_HEAD(&a->list);
++
++ sgt = &a->sg_table;
++
++ /* Copy the buf->base_sgt scatter list to the attachment, as we can't
++ * map the same scatter list to multiple attachments at the same time.
++ */
++ ret = sg_alloc_table(sgt, buf->alloc.sg_table->orig_nents, GFP_KERNEL);
++ if (ret) {
+ kfree(a);
+- return PTR_ERR(table);
++ return -ENOMEM;
+ }
+
+- a->table = table;
+- INIT_LIST_HEAD(&a->list);
++ rd = buf->alloc.sg_table->sgl;
++ wr = sgt->sgl;
++ for (i = 0; i < sgt->orig_nents; ++i) {
++ sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
++ rd = sg_next(rd);
++ wr = sg_next(wr);
++ }
+
++ a->dma_dir = DMA_NONE;
+ attachment->priv = a;
+
+- mutex_lock(&buf->lock);
+ list_add(&a->list, &buf->attachments);
+ mutex_unlock(&buf->lock);
+- pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
+
+ return 0;
+ }
+@@ -441,9 +417,20 @@ static void vc_sm_dma_buf_detach(struct
+ {
+ struct vc_sm_dma_buf_attachment *a = attachment->priv;
+ struct vc_sm_buffer *buf = dmabuf->priv;
++ struct sg_table *sgt;
+
+ pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
+- free_duped_table(a->table);
++ if (!a)
++ return;
++
++ sgt = &a->sg_table;
++
++ /* release the scatterlist cache */
++ if (a->dma_dir != DMA_NONE)
++ dma_unmap_sg(attachment->dev, sgt->sgl, sgt->orig_nents,
++ a->dma_dir);
++ sg_free_table(sgt);
++
+ mutex_lock(&buf->lock);
+ list_del(&a->list);
+ mutex_unlock(&buf->lock);
+@@ -455,13 +442,38 @@ static struct sg_table *vc_sm_map_dma_bu
+ enum dma_data_direction direction)
+ {
+ struct vc_sm_dma_buf_attachment *a = attachment->priv;
++ /* stealing dmabuf mutex to serialize map/unmap operations */
++ struct mutex *lock = &attachment->dmabuf->lock;
+ struct sg_table *table;
+
+- table = a->table;
++ mutex_lock(lock);
++ pr_debug("%s attachment %p\n", __func__, attachment);
++ table = &a->sg_table;
++
++ /* return previously mapped sg table */
++ if (a->dma_dir == direction) {
++ mutex_unlock(lock);
++ return table;
++ }
++
++ /* release any previous cache */
++ if (a->dma_dir != DMA_NONE) {
++ dma_unmap_sg(attachment->dev, table->sgl, table->orig_nents,
++ a->dma_dir);
++ a->dma_dir = DMA_NONE;
++ }
++
++ /* mapping to the client with new direction */
++ table->nents = dma_map_sg(attachment->dev, table->sgl,
++ table->orig_nents, direction);
++ if (!table->nents) {
++ pr_err("failed to map scatterlist\n");
++ mutex_unlock(lock);
++ return ERR_PTR(-EIO);
++ }
+
+- if (!dma_map_sg(attachment->dev, table->sgl, table->nents,
+- direction))
+- return ERR_PTR(-ENOMEM);
++ a->dma_dir = direction;
++ mutex_unlock(lock);
+
+ pr_debug("%s attachment %p\n", __func__, attachment);
+ return table;
+@@ -478,41 +490,26 @@ static void vc_sm_unmap_dma_buf(struct d
+ static int vc_sm_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
+ {
+ struct vc_sm_buffer *buf = dmabuf->priv;
+- struct sg_table *table = buf->sg_table;
+- unsigned long addr = vma->vm_start;
+- unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
+- struct scatterlist *sg;
+- int i;
+- int ret = 0;
++ int ret;
+
+ pr_debug("%s dmabuf %p, buf %p, vm_start %08lX\n", __func__, dmabuf,
+- buf, addr);
++ buf, vma->vm_start);
+
+ mutex_lock(&buf->lock);
+
+ /* now map it to userspace */
+- for_each_sg(table->sgl, sg, table->nents, i) {
+- struct page *page = sg_page(sg);
+- unsigned long remainder = vma->vm_end - addr;
+- unsigned long len = sg->length;
++ vma->vm_pgoff = 0;
+
+- if (offset >= sg->length) {
+- offset -= sg->length;
+- continue;
+- } else if (offset) {
+- page += offset / PAGE_SIZE;
+- len = sg->length - offset;
+- offset = 0;
+- }
+- len = min(len, remainder);
+- ret = remap_pfn_range(vma, addr, page_to_pfn(page), len,
+- vma->vm_page_prot);
+- if (ret)
+- break;
+- addr += len;
+- if (addr >= vma->vm_end)
+- break;
++ ret = dma_mmap_coherent(&sm_state->pdev->dev, vma, buf->cookie,
++ buf->dma_addr, buf->size);
++
++ if (ret) {
++ pr_err("Remapping memory failed, error: %d\n", ret);
++ return ret;
+ }
++
++ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
++
+ mutex_unlock(&buf->lock);
+
+ if (ret)
+@@ -570,8 +567,8 @@ static int vc_sm_dma_buf_begin_cpu_acces
+ mutex_lock(&buf->lock);
+
+ list_for_each_entry(a, &buf->attachments, list) {
+- dma_sync_sg_for_cpu(a->dev, a->table->sgl, a->table->nents,
+- direction);
++ dma_sync_sg_for_cpu(a->dev, a->sg_table.sgl,
++ a->sg_table.nents, direction);
+ }
+ mutex_unlock(&buf->lock);
+
+@@ -593,8 +590,8 @@ static int vc_sm_dma_buf_end_cpu_access(
+ mutex_lock(&buf->lock);
+
+ list_for_each_entry(a, &buf->attachments, list) {
+- dma_sync_sg_for_device(a->dev, a->table->sgl, a->table->nents,
+- direction);
++ dma_sync_sg_for_device(a->dev, a->sg_table.sgl,
++ a->sg_table.nents, direction);
+ }
+ mutex_unlock(&buf->lock);
+
+@@ -625,7 +622,9 @@ static const struct dma_buf_ops dma_buf_
+ .map = vc_sm_dma_buf_kmap,
+ .unmap = vc_sm_dma_buf_kunmap,
+ };
++
+ /* Dma_buf operations for chaining through to an imported dma_buf */
++
+ static
+ int vc_sm_import_dma_buf_attach(struct dma_buf *dmabuf,
+ struct dma_buf_attachment *attachment)
+@@ -819,7 +818,7 @@ vc_sm_cma_import_dmabuf_internal(struct
+
+ import.type = VC_SM_ALLOC_NON_CACHED;
+ dma_addr = sg_dma_address(sgt->sgl);
+- import.addr = (uint32_t)dma_addr;
++ import.addr = (u32)dma_addr;
+ if ((import.addr & 0xC0000000) != 0xC0000000) {
+ pr_err("%s: Expecting an uncached alias for dma_addr %pad\n",
+ __func__, &dma_addr);
+@@ -911,11 +910,12 @@ error:
+ return ret;
+ }
+
+-static int vc_sm_cma_vpu_alloc(u32 size, uint32_t align, const char *name,
++static int vc_sm_cma_vpu_alloc(u32 size, u32 align, const char *name,
+ u32 mem_handle, struct vc_sm_buffer **ret_buffer)
+ {
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+ struct vc_sm_buffer *buffer = NULL;
++ struct sg_table *sgt;
+ int aligned_size;
+ int ret = 0;
+
+@@ -938,23 +938,34 @@ static int vc_sm_cma_vpu_alloc(u32 size,
+ */
+ mutex_lock(&buffer->lock);
+
+- if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
+- aligned_size)) {
+- pr_err("[%s]: cma alloc of %d bytes failed\n",
++ buffer->cookie = dma_alloc_coherent(&sm_state->pdev->dev,
++ aligned_size, &buffer->dma_addr,
++ GFP_KERNEL);
++ if (!buffer->cookie) {
++ pr_err("[%s]: dma_alloc_coherent alloc of %d bytes failed\n",
+ __func__, aligned_size);
+ ret = -ENOMEM;
+ goto error;
+ }
+- buffer->sg_table = buffer->alloc.sg_table;
+
+- pr_debug("[%s]: cma alloc of %d bytes success\n",
++ pr_debug("[%s]: alloc of %d bytes success\n",
+ __func__, aligned_size);
+
+- if (dma_map_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
+- buffer->sg_table->nents, DMA_BIDIRECTIONAL) <= 0) {
+- pr_err("[%s]: dma_map_sg failed\n", __func__);
++ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
++ if (!sgt) {
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ ret = dma_get_sgtable(&sm_state->pdev->dev, sgt, buffer->cookie,
++ buffer->dma_addr, buffer->size);
++ if (ret < 0) {
++ pr_err("failed to get scatterlist from DMA API\n");
++ kfree(sgt);
++ ret = -ENOMEM;
+ goto error;
+ }
++ buffer->alloc.sg_table = sgt;
+
+ INIT_LIST_HEAD(&buffer->attachments);
+
+@@ -971,10 +982,10 @@ static int vc_sm_cma_vpu_alloc(u32 size,
+ ret = PTR_ERR(buffer->dma_buf);
+ goto error;
+ }
+- buffer->dma_addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
++ buffer->dma_addr = (u32)sg_dma_address(buffer->alloc.sg_table->sgl);
+ if ((buffer->dma_addr & 0xC0000000) != 0xC0000000) {
+- pr_err("%s: Expecting an uncached alias for dma_addr %pad\n",
+- __func__, &buffer->dma_addr);
++ pr_warn_once("%s: Expecting an uncached alias for dma_addr %pad\n",
++ __func__, &buffer->dma_addr);
+ buffer->dma_addr |= 0xC0000000;
+ }
+ buffer->private = sm_state->vpu_allocs;
+@@ -1145,6 +1156,7 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
+ struct vc_sm_import import = { 0 };
+ struct vc_sm_import_result result = { 0 };
+ struct dma_buf *dmabuf = NULL;
++ struct sg_table *sgt;
+ int aligned_size;
+ int ret = 0;
+ int status;
+@@ -1162,18 +1174,13 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
+ goto error;
+ }
+
+- if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
+- aligned_size)) {
+- pr_err("[%s]: cma alloc of %d bytes failed\n",
++ buffer->cookie = dma_alloc_coherent(&sm_state->pdev->dev,
++ aligned_size,
++ &buffer->dma_addr,
++ GFP_KERNEL);
++ if (!buffer->cookie) {
++ pr_err("[%s]: dma_alloc_coherent alloc of %d bytes failed\n",
+ __func__, aligned_size);
+- kfree(buffer);
+- return -ENOMEM;
+- }
+- buffer->sg_table = buffer->alloc.sg_table;
+-
+- if (dma_map_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
+- buffer->sg_table->nents, DMA_BIDIRECTIONAL) <= 0) {
+- pr_err("[%s]: dma_map_sg failed\n", __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+@@ -1204,7 +1211,7 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
+ }
+ buffer->dma_buf = dmabuf;
+
+- import.addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
++ import.addr = buffer->dma_addr;
+ import.size = aligned_size;
+ import.kernel_id = get_kernel_id(buffer);
+
+@@ -1229,10 +1236,25 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
+ buffer->private = private;
+ buffer->vc_handle = result.res_handle;
+ buffer->size = import.size;
+- buffer->dma_addr = import.addr;
+ buffer->vpu_state = VPU_MAPPED;
+ buffer->kernel_id = import.kernel_id;
+- //buffer->res_cached = ioparam->cached;
++
++ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
++ if (!sgt) {
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ ret = dma_get_sgtable(&sm_state->pdev->dev, sgt, buffer->cookie,
++ buffer->dma_addr, buffer->size);
++ if (ret < 0) {
++ /* FIXME: error handling */
++ pr_err("failed to get scatterlist from DMA API\n");
++ kfree(sgt);
++ ret = -ENOMEM;
++ goto error;
++ }
++ buffer->alloc.sg_table = sgt;
+
+ fd = dma_buf_fd(dmabuf, O_CLOEXEC);
+ if (fd < 0)
+@@ -1250,11 +1272,19 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
+ return 0;
+
+ error:
+- if (buffer) {
+- pr_err("[%s]: something failed - cleanup. ret %d\n", __func__,
+- ret);
++ pr_err("[%s]: something failed - cleanup. ret %d\n", __func__, ret);
+
++ if (dmabuf) {
++ /* dmabuf has been exported, therefore allow dmabuf cleanup to
++ * deal with this
++ */
+ dma_buf_put(dmabuf);
++ } else {
++ /* No dmabuf, therefore just free the buffer here */
++ if (buffer->cookie)
++ dma_free_coherent(&sm_state->pdev->dev, buffer->size,
++ buffer->cookie, buffer->dma_addr);
++ kfree(buffer);
+ }
+ return ret;
+ }
+@@ -1527,13 +1557,6 @@ static void vc_sm_connected_init(void)
+
+ pr_info("[%s]: start\n", __func__);
+
+- vc_sm_cma_add_heaps(&sm_state->cma_heap);
+- if (!sm_state->cma_heap) {
+- pr_err("[%s]: failed to initialise CMA heap\n",
+- __func__);
+- return;
+- }
+-
+ /*
+ * Initialize and create a VCHI connection for the shared memory service
+ * running on videocore.
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
+@@ -21,8 +21,6 @@
+ #include <linux/types.h>
+ #include <linux/miscdevice.h>
+
+-#include "vc_sm_cma.h"
+-
+ #define VC_SM_MAX_NAME_LEN 32
+
+ enum vc_sm_vpu_mapping_state {
+@@ -31,6 +29,12 @@ enum vc_sm_vpu_mapping_state {
+ VPU_UNMAPPING
+ };
+
++struct vc_sm_alloc_data {
++ unsigned long num_pages;
++ void *priv_virt;
++ struct sg_table *sg_table;
++};
++
+ struct vc_sm_imported {
+ struct dma_buf *dma_buf;
+ struct dma_buf_attachment *attach;
+@@ -56,8 +60,6 @@ struct vc_sm_buffer {
+ int in_use:1; /* Kernel is still using this resource */
+ int imported:1; /* Imported dmabuf */
+
+- struct sg_table *sg_table;
+-
+ enum vc_sm_vpu_mapping_state vpu_state;
+ u32 vc_handle; /* VideoCore handle for this buffer */
+ int vpu_allocated; /*
+@@ -69,11 +71,12 @@ struct vc_sm_buffer {
+ /* DMABUF related fields */
+ struct dma_buf *dma_buf;
+ dma_addr_t dma_addr;
++ void *cookie;
+
+ struct vc_sm_privdata_t *private;
+
+ union {
+- struct vc_sm_cma_alloc_data alloc;
++ struct vc_sm_alloc_data alloc;
+ struct vc_sm_imported import;
+ };
+ };
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
++++ /dev/null
+@@ -1,98 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/*
+- * VideoCore Shared Memory CMA allocator
+- *
+- * Copyright: 2018, Raspberry Pi (Trading) Ltd
+- *
+- * Based on the Android ION allocator
+- * Copyright (C) Linaro 2012
+- *
+- */
+-
+-#include <linux/slab.h>
+-#include <linux/errno.h>
+-#include <linux/err.h>
+-#include <linux/cma.h>
+-#include <linux/scatterlist.h>
+-
+-#include "vc_sm_cma.h"
+-
+-/* CMA heap operations functions */
+-int vc_sm_cma_buffer_allocate(struct cma *cma_heap,
+- struct vc_sm_cma_alloc_data *buffer,
+- unsigned long len)
+-{
+- /* len should already be page aligned */
+- unsigned long num_pages = len / PAGE_SIZE;
+- struct sg_table *table;
+- struct page *pages;
+- int ret;
+-
+- pages = cma_alloc(cma_heap, num_pages, 0, GFP_KERNEL);
+- if (!pages)
+- return -ENOMEM;
+-
+- table = kmalloc(sizeof(*table), GFP_KERNEL);
+- if (!table)
+- goto err;
+-
+- ret = sg_alloc_table(table, 1, GFP_KERNEL);
+- if (ret)
+- goto free_mem;
+-
+- sg_set_page(table->sgl, pages, len, 0);
+-
+- buffer->priv_virt = pages;
+- buffer->sg_table = table;
+- buffer->cma_heap = cma_heap;
+- buffer->num_pages = num_pages;
+- return 0;
+-
+-free_mem:
+- kfree(table);
+-err:
+- cma_release(cma_heap, pages, num_pages);
+- return -ENOMEM;
+-}
+-
+-void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer)
+-{
+- struct cma *cma_heap = buffer->cma_heap;
+- struct page *pages = buffer->priv_virt;
+-
+- /* release memory */
+- if (cma_heap)
+- cma_release(cma_heap, pages, buffer->num_pages);
+-
+- /* release sg table */
+- if (buffer->sg_table) {
+- sg_free_table(buffer->sg_table);
+- kfree(buffer->sg_table);
+- buffer->sg_table = NULL;
+- }
+-}
+-
+-int __vc_sm_cma_add_heaps(struct cma *cma, void *priv)
+-{
+- struct cma **heap = (struct cma **)priv;
+- const char *name = cma_get_name(cma);
+-
+- if (!(*heap)) {
+- phys_addr_t phys_addr = cma_get_base(cma);
+-
+- pr_debug("%s: Adding cma heap %s (start %pap, size %lu) for use by vcsm\n",
+- __func__, name, &phys_addr, cma_get_size(cma));
+- *heap = cma;
+- } else {
+- pr_err("%s: Ignoring heap %s as already set\n",
+- __func__, name);
+- }
+-
+- return 0;
+-}
+-
+-void vc_sm_cma_add_heaps(struct cma **cma_heap)
+-{
+- cma_for_each_area(__vc_sm_cma_add_heaps, cma_heap);
+-}
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
++++ /dev/null
+@@ -1,39 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-
+-/*
+- * VideoCore Shared Memory CMA allocator
+- *
+- * Copyright: 2018, Raspberry Pi (Trading) Ltd
+- *
+- * Based on the Android ION allocator
+- * Copyright (C) Linaro 2012
+- *
+- * This software is licensed under the terms of the GNU General Public
+- * License version 2, as published by the Free Software Foundation, and
+- * may be copied, distributed, and modified under those terms.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- */
+-#ifndef VC_SM_CMA_H
+-#define VC_SM_CMA_H
+-
+-struct vc_sm_cma_alloc_data {
+- struct cma *cma_heap;
+- unsigned long num_pages;
+- void *priv_virt;
+- struct sg_table *sg_table;
+-};
+-
+-int vc_sm_cma_buffer_allocate(struct cma *cma_heap,
+- struct vc_sm_cma_alloc_data *buffer,
+- unsigned long len);
+-void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer);
+-
+-void vc_sm_cma_add_heaps(struct cma **cma_heap);
+-
+-#endif
--- /dev/null
+From 38ae4957840ff9578a497422a8ca758549f734d5 Mon Sep 17 00:00:00 2001
+Date: Tue, 2 Jul 2019 17:19:04 +0100
+Subject: [PATCH] staging: vc-sm-cma: Fix the few remaining coding
+ style issues
+
+Fix a few minor checkpatch complaints to make the driver clean
+
+---
+ .../staging/vc04_services/vc-sm-cma/vc_sm.c | 6 +-
+ .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 128 +++++++++---------
+ 2 files changed, 65 insertions(+), 69 deletions(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -325,7 +325,6 @@ static void vc_sm_release_resource(struc
+ buffer->cookie, buffer->dma_addr);
+ }
+
+-
+ /* Free our buffer. Start by removing it from the list */
+ mutex_lock(&sm_state->map_lock);
+ list_del(&buffer->global_buffer_list);
+@@ -1365,7 +1364,8 @@ static int vc_sm_cma_clean_invalid2(unsi
+ }
+
+ for (i = 0; i < ioparam.op_count; i++) {
+- const struct vc_sm_cma_ioctl_clean_invalid_block * const op = block + i;
++ const struct vc_sm_cma_ioctl_clean_invalid_block * const op =
++ block + i;
+
+ if (op->invalidate_mode == VC_SM_CACHE_OP_NOP)
+ continue;
+@@ -1637,8 +1637,6 @@ err_remove_misc_dev:
+ err_remove_debugfs:
+ debugfs_remove_recursive(sm_state->dir_root);
+ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
+-
+- return;
+ }
+
+ /* Driver loading. */
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
+@@ -188,79 +188,77 @@ static int vc_sm_cma_vchi_videocore_io(v
+ if (svc_use)
+ vchi_service_release(instance->vchi_handle[0]);
+ svc_use = 0;
+- if (!wait_for_completion_interruptible(&instance->io_cmplt)) {
+- vchi_service_use(instance->vchi_handle[0]);
+- svc_use = 1;
+-
+- do {
+- /*
+- * Get new command and move it to response list
+- */
+- mutex_lock(&instance->lock);
+- if (list_empty(&instance->cmd_list)) {
+- /* no more commands to process */
+- mutex_unlock(&instance->lock);
+- break;
+- }
+- cmd =
+- list_first_entry(&instance->cmd_list,
+- struct sm_cmd_rsp_blk,
+- head);
+- list_move(&cmd->head, &instance->rsp_list);
+- cmd->sent = 1;
+- mutex_unlock(&instance->lock);
+
+- /* Send the command */
+- status = bcm2835_vchi_msg_queue(
+- instance->vchi_handle[0],
+- cmd->msg, cmd->length);
+- if (status) {
+- pr_err("%s: failed to queue message (%d)",
+- __func__, status);
+- }
+-
+- /* If no reply is needed then we're done */
+- if (!cmd->wait) {
+- mutex_lock(&instance->lock);
+- list_del(&cmd->head);
+- mutex_unlock(&instance->lock);
+- vc_vchi_cmd_delete(instance, cmd);
+- continue;
+- }
+-
+- if (status) {
+- complete(&cmd->cmplt);
+- continue;
+- }
+-
+- } while (1);
+-
+- while (!vchi_msg_peek(instance->vchi_handle[0],
+- (void **)&reply, &reply_len,
+- VCHI_FLAGS_NONE)) {
+- if (reply->trans_id & 0x80000000) {
+- /* Async event or cmd from the VPU */
+- if (instance->vpu_event)
+- instance->vpu_event(
+- instance, reply,
+- reply_len);
+- } else {
+- vc_sm_cma_vchi_rx_ack(instance, cmd,
+- reply, reply_len);
+- }
++ if (wait_for_completion_interruptible(&instance->io_cmplt))
++ continue;
+
+- vchi_msg_remove(instance->vchi_handle[0]);
+- }
++ vchi_service_use(instance->vchi_handle[0]);
++ svc_use = 1;
+
+- /* Go through the dead list and free them */
++ do {
++ /*
++ * Get new command and move it to response list
++ */
+ mutex_lock(&instance->lock);
+- list_for_each_entry_safe(cmd, cmd_tmp,
+- &instance->dead_list, head) {
++ if (list_empty(&instance->cmd_list)) {
++ /* no more commands to process */
++ mutex_unlock(&instance->lock);
++ break;
++ }
++ cmd = list_first_entry(&instance->cmd_list,
++ struct sm_cmd_rsp_blk, head);
++ list_move(&cmd->head, &instance->rsp_list);
++ cmd->sent = 1;
++ mutex_unlock(&instance->lock);
++
++ /* Send the command */
++ status =
++ bcm2835_vchi_msg_queue(instance->vchi_handle[0],
++ cmd->msg, cmd->length);
++ if (status) {
++ pr_err("%s: failed to queue message (%d)",
++ __func__, status);
++ }
++
++ /* If no reply is needed then we're done */
++ if (!cmd->wait) {
++ mutex_lock(&instance->lock);
+ list_del(&cmd->head);
++ mutex_unlock(&instance->lock);
+ vc_vchi_cmd_delete(instance, cmd);
++ continue;
+ }
+- mutex_unlock(&instance->lock);
++
++ if (status) {
++ complete(&cmd->cmplt);
++ continue;
++ }
++
++ } while (1);
++
++ while (!vchi_msg_peek(instance->vchi_handle[0], (void **)&reply,
++ &reply_len, VCHI_FLAGS_NONE)) {
++ if (reply->trans_id & 0x80000000) {
++ /* Async event or cmd from the VPU */
++ if (instance->vpu_event)
++ instance->vpu_event(instance, reply,
++ reply_len);
++ } else {
++ vc_sm_cma_vchi_rx_ack(instance, cmd, reply,
++ reply_len);
++ }
++
++ vchi_msg_remove(instance->vchi_handle[0]);
++ }
++
++ /* Go through the dead list and free them */
++ mutex_lock(&instance->lock);
++ list_for_each_entry_safe(cmd, cmd_tmp, &instance->dead_list,
++ head) {
++ list_del(&cmd->head);
++ vc_vchi_cmd_delete(instance, cmd);
+ }
++ mutex_unlock(&instance->lock);
+ }
+
+ return 0;
+++ /dev/null
-From b30537425b4bf90311b8d43c95484d9d339be25f Mon Sep 17 00:00:00 2001
-Date: Tue, 25 Jun 2019 00:29:44 +0100
-Subject: [PATCH] staging: vcsm-cma: Remove cache manipulation ioctl
- from ARM64
-
-The cache flushing ioctls are used by the Pi3 HEVC hw-assisted
-decoder as it needs finer grained flushing control than dma_ops
-allow.
-These cache calls are not present for ARM64, therefore disable
-them. We are not actively supporting 64bit kernels at present,
-and the use case of the HEVC decoder is fairly limited.
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -1259,6 +1259,7 @@ error:
- return ret;
- }
-
-+#ifndef CONFIG_ARM64
- /* Converts VCSM_CACHE_OP_* to an operating function. */
- static void (*cache_op_to_func(const unsigned int cache_op))
- (const void*, const void*)
-@@ -1351,6 +1352,7 @@ out:
-
- return ret;
- }
-+#endif
-
- static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-@@ -1448,6 +1450,7 @@ static long vc_sm_cma_ioctl(struct file
- break;
- }
-
-+#ifndef CONFIG_ARM64
- /*
- * Flush/Invalidate the cache for a given mapping.
- * Blocks must be pinned (i.e. accessed) before this call.
-@@ -1455,6 +1458,7 @@ static long vc_sm_cma_ioctl(struct file
- case VC_SM_CMA_CMD_CLEAN_INVALID2:
- ret = vc_sm_cma_clean_invalid2(cmdnr, arg);
- break;
-+#endif
-
- default:
- pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
-@@ -1467,6 +1471,7 @@ static long vc_sm_cma_ioctl(struct file
- return ret;
- }
-
-+#ifndef CONFIG_ARM64
- #ifdef CONFIG_COMPAT
- struct vc_sm_cma_ioctl_clean_invalid2_32 {
- u32 op_count;
-@@ -1496,14 +1501,17 @@ static long vc_sm_cma_compat_ioctl(struc
- }
- }
- #endif
-+#endif
-
- /* Device operations that we managed in this driver. */
- static const struct file_operations vc_sm_ops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = vc_sm_cma_ioctl,
-+#ifndef CONFIG_ARM64
- #ifdef CONFIG_COMPAT
- .compat_ioctl = vc_sm_cma_compat_ioctl,
- #endif
-+#endif
- .open = vc_sm_cma_open,
- .release = vc_sm_cma_release,
- };
--- /dev/null
+From ebd995296afa99a5c53f164e595f7a6d41d32a01 Mon Sep 17 00:00:00 2001
+Date: Thu, 23 Aug 2018 09:56:22 -0400
+Subject: [PATCH] media: videodev2.h: add new capabilities for buffer
+ types
+
+Upstream commit f35f5d72e70e6b91389eb98fcabf43b79f40587f
+
+VIDIOC_REQBUFS and VIDIOC_CREATE_BUFFERS will return capabilities
+telling userspace what the given buffer type is capable of.
+
+---
+ .../media/uapi/v4l/vidioc-create-bufs.rst | 14 ++++++-
+ .../media/uapi/v4l/vidioc-reqbufs.rst | 42 ++++++++++++++++++-
+ include/uapi/linux/videodev2.h | 13 +++++-
+ 3 files changed, 65 insertions(+), 4 deletions(-)
+
+--- a/Documentation/media/uapi/v4l/vidioc-create-bufs.rst
++++ b/Documentation/media/uapi/v4l/vidioc-create-bufs.rst
+@@ -102,7 +102,19 @@ than the number requested.
+ - ``format``
+ - Filled in by the application, preserved by the driver.
+ * - __u32
+- - ``reserved``\ [8]
++ - ``capabilities``
++ - Set by the driver. If 0, then the driver doesn't support
++ capabilities. In that case all you know is that the driver is
++ guaranteed to support ``V4L2_MEMORY_MMAP`` and *might* support
++ other :c:type:`v4l2_memory` types. It will not support any others
++ capabilities. See :ref:`here <v4l2-buf-capabilities>` for a list of the
++ capabilities.
++
++ If you want to just query the capabilities without making any
++ other changes, then set ``count`` to 0, ``memory`` to
++ ``V4L2_MEMORY_MMAP`` and ``format.type`` to the buffer type.
++ * - __u32
++ - ``reserved``\ [7]
+ - A place holder for future extensions. Drivers and applications
+ must set the array to zero.
+
+--- a/Documentation/media/uapi/v4l/vidioc-reqbufs.rst
++++ b/Documentation/media/uapi/v4l/vidioc-reqbufs.rst
+@@ -88,10 +88,50 @@ any DMA in progress, an implicit
+ ``V4L2_MEMORY_DMABUF`` or ``V4L2_MEMORY_USERPTR``. See
+ :c:type:`v4l2_memory`.
+ * - __u32
+- - ``reserved``\ [2]
++ - ``capabilities``
++ - Set by the driver. If 0, then the driver doesn't support
++ capabilities. In that case all you know is that the driver is
++ guaranteed to support ``V4L2_MEMORY_MMAP`` and *might* support
++ other :c:type:`v4l2_memory` types. It will not support any others
++ capabilities.
++
++ If you want to query the capabilities with a minimum of side-effects,
++ then this can be called with ``count`` set to 0, ``memory`` set to
++ ``V4L2_MEMORY_MMAP`` and ``type`` set to the buffer type. This will
++ free any previously allocated buffers, so this is typically something
++ that will be done at the start of the application.
++ * - __u32
++ - ``reserved``\ [1]
+ - A place holder for future extensions. Drivers and applications
+ must set the array to zero.
+
++.. tabularcolumns:: |p{6.1cm}|p{2.2cm}|p{8.7cm}|
++
++.. _v4l2-buf-capabilities:
++.. _V4L2-BUF-CAP-SUPPORTS-MMAP:
++.. _V4L2-BUF-CAP-SUPPORTS-USERPTR:
++.. _V4L2-BUF-CAP-SUPPORTS-DMABUF:
++.. _V4L2-BUF-CAP-SUPPORTS-REQUESTS:
++
++.. cssclass:: longtable
++
++.. flat-table:: V4L2 Buffer Capabilities Flags
++ :header-rows: 0
++ :stub-columns: 0
++ :widths: 3 1 4
++
++ * - ``V4L2_BUF_CAP_SUPPORTS_MMAP``
++ - 0x00000001
++ - This buffer type supports the ``V4L2_MEMORY_MMAP`` streaming mode.
++ * - ``V4L2_BUF_CAP_SUPPORTS_USERPTR``
++ - 0x00000002
++ - This buffer type supports the ``V4L2_MEMORY_USERPTR`` streaming mode.
++ * - ``V4L2_BUF_CAP_SUPPORTS_DMABUF``
++ - 0x00000004
++ - This buffer type supports the ``V4L2_MEMORY_DMABUF`` streaming mode.
++ * - ``V4L2_BUF_CAP_SUPPORTS_REQUESTS``
++ - 0x00000008
++ - This buffer type supports :ref:`requests <media-request-api>`.
+
+ Return Value
+ ============
+--- a/include/uapi/linux/videodev2.h
++++ b/include/uapi/linux/videodev2.h
+@@ -872,9 +872,16 @@ struct v4l2_requestbuffers {
+ __u32 count;
+ __u32 type; /* enum v4l2_buf_type */
+ __u32 memory; /* enum v4l2_memory */
+- __u32 reserved[2];
++ __u32 capabilities;
++ __u32 reserved[1];
+ };
+
++/* capabilities for struct v4l2_requestbuffers and v4l2_create_buffers */
++#define V4L2_BUF_CAP_SUPPORTS_MMAP (1 << 0)
++#define V4L2_BUF_CAP_SUPPORTS_USERPTR (1 << 1)
++#define V4L2_BUF_CAP_SUPPORTS_DMABUF (1 << 2)
++#define V4L2_BUF_CAP_SUPPORTS_REQUESTS (1 << 3)
++
+ /**
+ * struct v4l2_plane - plane info for multi-planar buffers
+ * @bytesused: number of bytes occupied by data in the plane (payload)
+@@ -2318,6 +2325,7 @@ struct v4l2_dbg_chip_info {
+ * return: number of created buffers
+ * @memory: enum v4l2_memory; buffer memory type
+ * @format: frame format, for which buffers are requested
++ * @capabilities: capabilities of this buffer type.
+ * @reserved: future extensions
+ */
+ struct v4l2_create_buffers {
+@@ -2325,7 +2333,8 @@ struct v4l2_create_buffers {
+ __u32 count;
+ __u32 memory;
+ struct v4l2_format format;
+- __u32 reserved[8];
++ __u32 capabilities;
++ __u32 reserved[7];
+ };
+
+ /*
+++ /dev/null
-From e4cb138abe457a6ab9b98458660a1c8e548fab7f Mon Sep 17 00:00:00 2001
-Date: Mon, 1 Jul 2019 11:57:25 +0100
-Subject: [PATCH] staging: vcsm-cma: Rework to use dma APIs, not CMA
-
-Due to a misunderstanding of the DMA mapping APIs, I made
-the wrong decision on how to implement this.
-
-Rework to use dma_alloc_coherent instead of the CMA
-API. This also allows it to be built as a module easily.
-
----
- .../staging/vc04_services/vc-sm-cma/Kconfig | 4 +-
- .../staging/vc04_services/vc-sm-cma/Makefile | 2 +-
- .../staging/vc04_services/vc-sm-cma/vc_sm.c | 291 ++++++++++--------
- .../staging/vc04_services/vc-sm-cma/vc_sm.h | 13 +-
- .../vc04_services/vc-sm-cma/vc_sm_cma.c | 98 ------
- .../vc04_services/vc-sm-cma/vc_sm_cma.h | 39 ---
- 6 files changed, 168 insertions(+), 279 deletions(-)
- delete mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
- delete mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
-
---- a/drivers/staging/vc04_services/vc-sm-cma/Kconfig
-+++ b/drivers/staging/vc04_services/vc-sm-cma/Kconfig
-@@ -1,6 +1,6 @@
- config BCM_VC_SM_CMA
-- bool "VideoCore Shared Memory (CMA) driver"
-- depends on BCM2835_VCHIQ && DMA_CMA
-+ tristate "VideoCore Shared Memory (CMA) driver"
-+ depends on BCM2835_VCHIQ
- select RBTREE
- select DMA_SHARED_BUFFER
- help
---- a/drivers/staging/vc04_services/vc-sm-cma/Makefile
-+++ b/drivers/staging/vc04_services/vc-sm-cma/Makefile
-@@ -3,6 +3,6 @@ ccflags-y += -Idrivers/staging/vc04_serv
- ccflags-y += -D__VCCOREVER__=0
-
- vc-sm-cma-$(CONFIG_BCM_VC_SM_CMA) := \
-- vc_sm.o vc_sm_cma_vchi.o vc_sm_cma.o
-+ vc_sm.o vc_sm_cma_vchi.o
-
- obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma.o
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -6,8 +6,8 @@
- *
- * Based on vmcs_sm driver from Broadcom Corporation for some API,
-- * and taking some code for CMA/dmabuf handling from the Android Ion
-- * driver (Google/Linaro).
-+ * and taking some code for buffer allocation and dmabuf handling from
-+ * videobuf2.
- *
- *
- * This driver has 3 main uses:
-@@ -52,7 +52,6 @@
- #include "vc_sm_cma_vchi.h"
-
- #include "vc_sm.h"
--#include "vc_sm_cma.h"
- #include "vc_sm_knl.h"
- #include <linux/broadcom/vc_sm_cma_ioctl.h>
-
-@@ -89,7 +88,6 @@ struct sm_state_t {
- struct miscdevice misc_dev;
-
- struct sm_instance *sm_handle; /* Handle for videocore service. */
-- struct cma *cma_heap;
-
- spinlock_t kernelid_map_lock; /* Spinlock protecting kernelid_map */
- struct idr kernelid_map;
-@@ -110,8 +108,9 @@ struct sm_state_t {
-
- struct vc_sm_dma_buf_attachment {
- struct device *dev;
-- struct sg_table *table;
-+ struct sg_table sg_table;
- struct list_head list;
-+ enum dma_data_direction dma_dir;
- };
-
- /* ---- Private Variables ----------------------------------------------- */
-@@ -202,9 +201,10 @@ static int vc_sm_cma_global_state_show(s
- resource->import.attach);
- seq_printf(s, " SGT %p\n",
- resource->import.sgt);
-+ } else {
-+ seq_printf(s, " SGT %p\n",
-+ resource->alloc.sg_table);
- }
-- seq_printf(s, " SG_TABLE %p\n",
-- resource->sg_table);
- seq_printf(s, " DMA_ADDR %pad\n",
- &resource->dma_addr);
- seq_printf(s, " VC_HANDLE %08x\n",
-@@ -296,8 +296,9 @@ static void vc_sm_vpu_free(struct vc_sm_
- */
- static void vc_sm_release_resource(struct vc_sm_buffer *buffer)
- {
-- pr_debug("[%s]: buffer %p (name %s, size %zu)\n",
-- __func__, buffer, buffer->name, buffer->size);
-+ pr_debug("[%s]: buffer %p (name %s, size %zu), imported %u\n",
-+ __func__, buffer, buffer->name, buffer->size,
-+ buffer->imported);
-
- if (buffer->vc_handle) {
- /* We've sent the unmap request but not had the response. */
-@@ -313,8 +314,6 @@ static void vc_sm_release_resource(struc
-
- /* Release the allocation (whether imported dmabuf or CMA allocation) */
- if (buffer->imported) {
-- pr_debug("%s: Release imported dmabuf %p\n", __func__,
-- buffer->import.dma_buf);
- if (buffer->import.dma_buf)
- dma_buf_put(buffer->import.dma_buf);
- else
-@@ -322,16 +321,8 @@ static void vc_sm_release_resource(struc
- __func__, buffer);
- buffer->import.dma_buf = NULL;
- } else {
-- if (buffer->sg_table) {
-- /* Our own allocation that we need to dma_unmap_sg */
-- dma_unmap_sg(&sm_state->pdev->dev,
-- buffer->sg_table->sgl,
-- buffer->sg_table->nents,
-- DMA_BIDIRECTIONAL);
-- }
-- pr_debug("%s: Release our allocation\n", __func__);
-- vc_sm_cma_buffer_free(&buffer->alloc);
-- pr_debug("%s: Release our allocation - done\n", __func__);
-+ dma_free_coherent(&sm_state->pdev->dev, buffer->size,
-+ buffer->cookie, buffer->dma_addr);
- }
-
-
-@@ -371,38 +362,6 @@ static struct vc_sm_privdata_t *vc_sm_cm
- return file_data;
- }
-
--static struct sg_table *dup_sg_table(struct sg_table *table)
--{
-- struct sg_table *new_table;
-- int ret, i;
-- struct scatterlist *sg, *new_sg;
--
-- new_table = kzalloc(sizeof(*new_table), GFP_KERNEL);
-- if (!new_table)
-- return ERR_PTR(-ENOMEM);
--
-- ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
-- if (ret) {
-- kfree(new_table);
-- return ERR_PTR(ret);
-- }
--
-- new_sg = new_table->sgl;
-- for_each_sg(table->sgl, sg, table->nents, i) {
-- memcpy(new_sg, sg, sizeof(*sg));
-- sg->dma_address = 0;
-- new_sg = sg_next(new_sg);
-- }
--
-- return new_table;
--}
--
--static void free_duped_table(struct sg_table *table)
--{
-- sg_free_table(table);
-- kfree(table);
--}
--
- /* Dma buf operations for use with our own allocations */
-
- static int vc_sm_dma_buf_attach(struct dma_buf *dmabuf,
-@@ -410,28 +369,45 @@ static int vc_sm_dma_buf_attach(struct d
-
- {
- struct vc_sm_dma_buf_attachment *a;
-- struct sg_table *table;
-+ struct sg_table *sgt;
- struct vc_sm_buffer *buf = dmabuf->priv;
-+ struct scatterlist *rd, *wr;
-+ int ret, i;
-
- a = kzalloc(sizeof(*a), GFP_KERNEL);
- if (!a)
- return -ENOMEM;
-
-- table = dup_sg_table(buf->sg_table);
-- if (IS_ERR(table)) {
-+ pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
-+
-+ mutex_lock(&buf->lock);
-+
-+ INIT_LIST_HEAD(&a->list);
-+
-+ sgt = &a->sg_table;
-+
-+ /* Copy the buf->base_sgt scatter list to the attachment, as we can't
-+ * map the same scatter list to multiple attachments at the same time.
-+ */
-+ ret = sg_alloc_table(sgt, buf->alloc.sg_table->orig_nents, GFP_KERNEL);
-+ if (ret) {
- kfree(a);
-- return PTR_ERR(table);
-+ return -ENOMEM;
- }
-
-- a->table = table;
-- INIT_LIST_HEAD(&a->list);
-+ rd = buf->alloc.sg_table->sgl;
-+ wr = sgt->sgl;
-+ for (i = 0; i < sgt->orig_nents; ++i) {
-+ sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
-+ rd = sg_next(rd);
-+ wr = sg_next(wr);
-+ }
-
-+ a->dma_dir = DMA_NONE;
- attachment->priv = a;
-
-- mutex_lock(&buf->lock);
- list_add(&a->list, &buf->attachments);
- mutex_unlock(&buf->lock);
-- pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
-
- return 0;
- }
-@@ -441,9 +417,20 @@ static void vc_sm_dma_buf_detach(struct
- {
- struct vc_sm_dma_buf_attachment *a = attachment->priv;
- struct vc_sm_buffer *buf = dmabuf->priv;
-+ struct sg_table *sgt;
-
- pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment);
-- free_duped_table(a->table);
-+ if (!a)
-+ return;
-+
-+ sgt = &a->sg_table;
-+
-+ /* release the scatterlist cache */
-+ if (a->dma_dir != DMA_NONE)
-+ dma_unmap_sg(attachment->dev, sgt->sgl, sgt->orig_nents,
-+ a->dma_dir);
-+ sg_free_table(sgt);
-+
- mutex_lock(&buf->lock);
- list_del(&a->list);
- mutex_unlock(&buf->lock);
-@@ -455,13 +442,38 @@ static struct sg_table *vc_sm_map_dma_bu
- enum dma_data_direction direction)
- {
- struct vc_sm_dma_buf_attachment *a = attachment->priv;
-+ /* stealing dmabuf mutex to serialize map/unmap operations */
-+ struct mutex *lock = &attachment->dmabuf->lock;
- struct sg_table *table;
-
-- table = a->table;
-+ mutex_lock(lock);
-+ pr_debug("%s attachment %p\n", __func__, attachment);
-+ table = &a->sg_table;
-+
-+ /* return previously mapped sg table */
-+ if (a->dma_dir == direction) {
-+ mutex_unlock(lock);
-+ return table;
-+ }
-+
-+ /* release any previous cache */
-+ if (a->dma_dir != DMA_NONE) {
-+ dma_unmap_sg(attachment->dev, table->sgl, table->orig_nents,
-+ a->dma_dir);
-+ a->dma_dir = DMA_NONE;
-+ }
-+
-+ /* mapping to the client with new direction */
-+ table->nents = dma_map_sg(attachment->dev, table->sgl,
-+ table->orig_nents, direction);
-+ if (!table->nents) {
-+ pr_err("failed to map scatterlist\n");
-+ mutex_unlock(lock);
-+ return ERR_PTR(-EIO);
-+ }
-
-- if (!dma_map_sg(attachment->dev, table->sgl, table->nents,
-- direction))
-- return ERR_PTR(-ENOMEM);
-+ a->dma_dir = direction;
-+ mutex_unlock(lock);
-
- pr_debug("%s attachment %p\n", __func__, attachment);
- return table;
-@@ -478,41 +490,26 @@ static void vc_sm_unmap_dma_buf(struct d
- static int vc_sm_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
- {
- struct vc_sm_buffer *buf = dmabuf->priv;
-- struct sg_table *table = buf->sg_table;
-- unsigned long addr = vma->vm_start;
-- unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
-- struct scatterlist *sg;
-- int i;
-- int ret = 0;
-+ int ret;
-
- pr_debug("%s dmabuf %p, buf %p, vm_start %08lX\n", __func__, dmabuf,
-- buf, addr);
-+ buf, vma->vm_start);
-
- mutex_lock(&buf->lock);
-
- /* now map it to userspace */
-- for_each_sg(table->sgl, sg, table->nents, i) {
-- struct page *page = sg_page(sg);
-- unsigned long remainder = vma->vm_end - addr;
-- unsigned long len = sg->length;
-+ vma->vm_pgoff = 0;
-
-- if (offset >= sg->length) {
-- offset -= sg->length;
-- continue;
-- } else if (offset) {
-- page += offset / PAGE_SIZE;
-- len = sg->length - offset;
-- offset = 0;
-- }
-- len = min(len, remainder);
-- ret = remap_pfn_range(vma, addr, page_to_pfn(page), len,
-- vma->vm_page_prot);
-- if (ret)
-- break;
-- addr += len;
-- if (addr >= vma->vm_end)
-- break;
-+ ret = dma_mmap_coherent(&sm_state->pdev->dev, vma, buf->cookie,
-+ buf->dma_addr, buf->size);
-+
-+ if (ret) {
-+ pr_err("Remapping memory failed, error: %d\n", ret);
-+ return ret;
- }
-+
-+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
-+
- mutex_unlock(&buf->lock);
-
- if (ret)
-@@ -570,8 +567,8 @@ static int vc_sm_dma_buf_begin_cpu_acces
- mutex_lock(&buf->lock);
-
- list_for_each_entry(a, &buf->attachments, list) {
-- dma_sync_sg_for_cpu(a->dev, a->table->sgl, a->table->nents,
-- direction);
-+ dma_sync_sg_for_cpu(a->dev, a->sg_table.sgl,
-+ a->sg_table.nents, direction);
- }
- mutex_unlock(&buf->lock);
-
-@@ -593,8 +590,8 @@ static int vc_sm_dma_buf_end_cpu_access(
- mutex_lock(&buf->lock);
-
- list_for_each_entry(a, &buf->attachments, list) {
-- dma_sync_sg_for_device(a->dev, a->table->sgl, a->table->nents,
-- direction);
-+ dma_sync_sg_for_device(a->dev, a->sg_table.sgl,
-+ a->sg_table.nents, direction);
- }
- mutex_unlock(&buf->lock);
-
-@@ -625,7 +622,9 @@ static const struct dma_buf_ops dma_buf_
- .map = vc_sm_dma_buf_kmap,
- .unmap = vc_sm_dma_buf_kunmap,
- };
-+
- /* Dma_buf operations for chaining through to an imported dma_buf */
-+
- static
- int vc_sm_import_dma_buf_attach(struct dma_buf *dmabuf,
- struct dma_buf_attachment *attachment)
-@@ -819,7 +818,7 @@ vc_sm_cma_import_dmabuf_internal(struct
-
- import.type = VC_SM_ALLOC_NON_CACHED;
- dma_addr = sg_dma_address(sgt->sgl);
-- import.addr = (uint32_t)dma_addr;
-+ import.addr = (u32)dma_addr;
- if ((import.addr & 0xC0000000) != 0xC0000000) {
- pr_err("%s: Expecting an uncached alias for dma_addr %pad\n",
- __func__, &dma_addr);
-@@ -911,11 +910,12 @@ error:
- return ret;
- }
-
--static int vc_sm_cma_vpu_alloc(u32 size, uint32_t align, const char *name,
-+static int vc_sm_cma_vpu_alloc(u32 size, u32 align, const char *name,
- u32 mem_handle, struct vc_sm_buffer **ret_buffer)
- {
- DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
- struct vc_sm_buffer *buffer = NULL;
-+ struct sg_table *sgt;
- int aligned_size;
- int ret = 0;
-
-@@ -938,23 +938,34 @@ static int vc_sm_cma_vpu_alloc(u32 size,
- */
- mutex_lock(&buffer->lock);
-
-- if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
-- aligned_size)) {
-- pr_err("[%s]: cma alloc of %d bytes failed\n",
-+ buffer->cookie = dma_alloc_coherent(&sm_state->pdev->dev,
-+ aligned_size, &buffer->dma_addr,
-+ GFP_KERNEL);
-+ if (!buffer->cookie) {
-+ pr_err("[%s]: dma_alloc_coherent alloc of %d bytes failed\n",
- __func__, aligned_size);
- ret = -ENOMEM;
- goto error;
- }
-- buffer->sg_table = buffer->alloc.sg_table;
-
-- pr_debug("[%s]: cma alloc of %d bytes success\n",
-+ pr_debug("[%s]: alloc of %d bytes success\n",
- __func__, aligned_size);
-
-- if (dma_map_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
-- buffer->sg_table->nents, DMA_BIDIRECTIONAL) <= 0) {
-- pr_err("[%s]: dma_map_sg failed\n", __func__);
-+ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
-+ if (!sgt) {
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ ret = dma_get_sgtable(&sm_state->pdev->dev, sgt, buffer->cookie,
-+ buffer->dma_addr, buffer->size);
-+ if (ret < 0) {
-+ pr_err("failed to get scatterlist from DMA API\n");
-+ kfree(sgt);
-+ ret = -ENOMEM;
- goto error;
- }
-+ buffer->alloc.sg_table = sgt;
-
- INIT_LIST_HEAD(&buffer->attachments);
-
-@@ -971,10 +982,10 @@ static int vc_sm_cma_vpu_alloc(u32 size,
- ret = PTR_ERR(buffer->dma_buf);
- goto error;
- }
-- buffer->dma_addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
-+ buffer->dma_addr = (u32)sg_dma_address(buffer->alloc.sg_table->sgl);
- if ((buffer->dma_addr & 0xC0000000) != 0xC0000000) {
-- pr_err("%s: Expecting an uncached alias for dma_addr %pad\n",
-- __func__, &buffer->dma_addr);
-+ pr_warn_once("%s: Expecting an uncached alias for dma_addr %pad\n",
-+ __func__, &buffer->dma_addr);
- buffer->dma_addr |= 0xC0000000;
- }
- buffer->private = sm_state->vpu_allocs;
-@@ -1145,6 +1156,7 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
- struct vc_sm_import import = { 0 };
- struct vc_sm_import_result result = { 0 };
- struct dma_buf *dmabuf = NULL;
-+ struct sg_table *sgt;
- int aligned_size;
- int ret = 0;
- int status;
-@@ -1162,18 +1174,13 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
- goto error;
- }
-
-- if (vc_sm_cma_buffer_allocate(sm_state->cma_heap, &buffer->alloc,
-- aligned_size)) {
-- pr_err("[%s]: cma alloc of %d bytes failed\n",
-+ buffer->cookie = dma_alloc_coherent(&sm_state->pdev->dev,
-+ aligned_size,
-+ &buffer->dma_addr,
-+ GFP_KERNEL);
-+ if (!buffer->cookie) {
-+ pr_err("[%s]: dma_alloc_coherent alloc of %d bytes failed\n",
- __func__, aligned_size);
-- kfree(buffer);
-- return -ENOMEM;
-- }
-- buffer->sg_table = buffer->alloc.sg_table;
--
-- if (dma_map_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
-- buffer->sg_table->nents, DMA_BIDIRECTIONAL) <= 0) {
-- pr_err("[%s]: dma_map_sg failed\n", __func__);
- ret = -ENOMEM;
- goto error;
- }
-@@ -1204,7 +1211,7 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
- }
- buffer->dma_buf = dmabuf;
-
-- import.addr = (uint32_t)sg_dma_address(buffer->sg_table->sgl);
-+ import.addr = buffer->dma_addr;
- import.size = aligned_size;
- import.kernel_id = get_kernel_id(buffer);
-
-@@ -1229,10 +1236,25 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
- buffer->private = private;
- buffer->vc_handle = result.res_handle;
- buffer->size = import.size;
-- buffer->dma_addr = import.addr;
- buffer->vpu_state = VPU_MAPPED;
- buffer->kernel_id = import.kernel_id;
-- //buffer->res_cached = ioparam->cached;
-+
-+ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
-+ if (!sgt) {
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ ret = dma_get_sgtable(&sm_state->pdev->dev, sgt, buffer->cookie,
-+ buffer->dma_addr, buffer->size);
-+ if (ret < 0) {
-+ /* FIXME: error handling */
-+ pr_err("failed to get scatterlist from DMA API\n");
-+ kfree(sgt);
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+ buffer->alloc.sg_table = sgt;
-
- fd = dma_buf_fd(dmabuf, O_CLOEXEC);
- if (fd < 0)
-@@ -1250,11 +1272,19 @@ int vc_sm_cma_ioctl_alloc(struct vc_sm_p
- return 0;
-
- error:
-- if (buffer) {
-- pr_err("[%s]: something failed - cleanup. ret %d\n", __func__,
-- ret);
-+ pr_err("[%s]: something failed - cleanup. ret %d\n", __func__, ret);
-
-+ if (dmabuf) {
-+ /* dmabuf has been exported, therefore allow dmabuf cleanup to
-+ * deal with this
-+ */
- dma_buf_put(dmabuf);
-+ } else {
-+ /* No dmabuf, therefore just free the buffer here */
-+ if (buffer->cookie)
-+ dma_free_coherent(&sm_state->pdev->dev, buffer->size,
-+ buffer->cookie, buffer->dma_addr);
-+ kfree(buffer);
- }
- return ret;
- }
-@@ -1527,13 +1557,6 @@ static void vc_sm_connected_init(void)
-
- pr_info("[%s]: start\n", __func__);
-
-- vc_sm_cma_add_heaps(&sm_state->cma_heap);
-- if (!sm_state->cma_heap) {
-- pr_err("[%s]: failed to initialise CMA heap\n",
-- __func__);
-- return;
-- }
--
- /*
- * Initialize and create a VCHI connection for the shared memory service
- * running on videocore.
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
-@@ -21,8 +21,6 @@
- #include <linux/types.h>
- #include <linux/miscdevice.h>
-
--#include "vc_sm_cma.h"
--
- #define VC_SM_MAX_NAME_LEN 32
-
- enum vc_sm_vpu_mapping_state {
-@@ -31,6 +29,12 @@ enum vc_sm_vpu_mapping_state {
- VPU_UNMAPPING
- };
-
-+struct vc_sm_alloc_data {
-+ unsigned long num_pages;
-+ void *priv_virt;
-+ struct sg_table *sg_table;
-+};
-+
- struct vc_sm_imported {
- struct dma_buf *dma_buf;
- struct dma_buf_attachment *attach;
-@@ -56,8 +60,6 @@ struct vc_sm_buffer {
- int in_use:1; /* Kernel is still using this resource */
- int imported:1; /* Imported dmabuf */
-
-- struct sg_table *sg_table;
--
- enum vc_sm_vpu_mapping_state vpu_state;
- u32 vc_handle; /* VideoCore handle for this buffer */
- int vpu_allocated; /*
-@@ -69,11 +71,12 @@ struct vc_sm_buffer {
- /* DMABUF related fields */
- struct dma_buf *dma_buf;
- dma_addr_t dma_addr;
-+ void *cookie;
-
- struct vc_sm_privdata_t *private;
-
- union {
-- struct vc_sm_cma_alloc_data alloc;
-+ struct vc_sm_alloc_data alloc;
- struct vc_sm_imported import;
- };
- };
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.c
-+++ /dev/null
-@@ -1,98 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0
--/*
-- * VideoCore Shared Memory CMA allocator
-- *
-- * Copyright: 2018, Raspberry Pi (Trading) Ltd
-- *
-- * Based on the Android ION allocator
-- * Copyright (C) Linaro 2012
-- *
-- */
--
--#include <linux/slab.h>
--#include <linux/errno.h>
--#include <linux/err.h>
--#include <linux/cma.h>
--#include <linux/scatterlist.h>
--
--#include "vc_sm_cma.h"
--
--/* CMA heap operations functions */
--int vc_sm_cma_buffer_allocate(struct cma *cma_heap,
-- struct vc_sm_cma_alloc_data *buffer,
-- unsigned long len)
--{
-- /* len should already be page aligned */
-- unsigned long num_pages = len / PAGE_SIZE;
-- struct sg_table *table;
-- struct page *pages;
-- int ret;
--
-- pages = cma_alloc(cma_heap, num_pages, 0, GFP_KERNEL);
-- if (!pages)
-- return -ENOMEM;
--
-- table = kmalloc(sizeof(*table), GFP_KERNEL);
-- if (!table)
-- goto err;
--
-- ret = sg_alloc_table(table, 1, GFP_KERNEL);
-- if (ret)
-- goto free_mem;
--
-- sg_set_page(table->sgl, pages, len, 0);
--
-- buffer->priv_virt = pages;
-- buffer->sg_table = table;
-- buffer->cma_heap = cma_heap;
-- buffer->num_pages = num_pages;
-- return 0;
--
--free_mem:
-- kfree(table);
--err:
-- cma_release(cma_heap, pages, num_pages);
-- return -ENOMEM;
--}
--
--void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer)
--{
-- struct cma *cma_heap = buffer->cma_heap;
-- struct page *pages = buffer->priv_virt;
--
-- /* release memory */
-- if (cma_heap)
-- cma_release(cma_heap, pages, buffer->num_pages);
--
-- /* release sg table */
-- if (buffer->sg_table) {
-- sg_free_table(buffer->sg_table);
-- kfree(buffer->sg_table);
-- buffer->sg_table = NULL;
-- }
--}
--
--int __vc_sm_cma_add_heaps(struct cma *cma, void *priv)
--{
-- struct cma **heap = (struct cma **)priv;
-- const char *name = cma_get_name(cma);
--
-- if (!(*heap)) {
-- phys_addr_t phys_addr = cma_get_base(cma);
--
-- pr_debug("%s: Adding cma heap %s (start %pap, size %lu) for use by vcsm\n",
-- __func__, name, &phys_addr, cma_get_size(cma));
-- *heap = cma;
-- } else {
-- pr_err("%s: Ignoring heap %s as already set\n",
-- __func__, name);
-- }
--
-- return 0;
--}
--
--void vc_sm_cma_add_heaps(struct cma **cma_heap)
--{
-- cma_for_each_area(__vc_sm_cma_add_heaps, cma_heap);
--}
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma.h
-+++ /dev/null
-@@ -1,39 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0 */
--
--/*
-- * VideoCore Shared Memory CMA allocator
-- *
-- * Copyright: 2018, Raspberry Pi (Trading) Ltd
-- *
-- * Based on the Android ION allocator
-- * Copyright (C) Linaro 2012
-- *
-- * This software is licensed under the terms of the GNU General Public
-- * License version 2, as published by the Free Software Foundation, and
-- * may be copied, distributed, and modified under those terms.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- * GNU General Public License for more details.
-- *
-- */
--#ifndef VC_SM_CMA_H
--#define VC_SM_CMA_H
--
--struct vc_sm_cma_alloc_data {
-- struct cma *cma_heap;
-- unsigned long num_pages;
-- void *priv_virt;
-- struct sg_table *sg_table;
--};
--
--int vc_sm_cma_buffer_allocate(struct cma *cma_heap,
-- struct vc_sm_cma_alloc_data *buffer,
-- unsigned long len);
--void vc_sm_cma_buffer_free(struct vc_sm_cma_alloc_data *buffer);
--
--void vc_sm_cma_add_heaps(struct cma **cma_heap);
--
--#endif
--- /dev/null
+From 7410e35a4936b89f2e227c52058c11f1574bbfca Mon Sep 17 00:00:00 2001
+Date: Thu, 23 Aug 2018 10:18:35 -0400
+Subject: [PATCH] media: vb2: set reqbufs/create_bufs capabilities
+
+Upstream commit e5079cf11373e4cc98be8b1072aece429eb2d4d2.
+
+Set the capabilities field of v4l2_requestbuffers and v4l2_create_buffers.
+
+The various mapping modes were easy, but for signaling the request capability
+a new 'supports_requests' bitfield was added to videobuf2-core.h (and set in
+vim2m and vivid). Drivers have to set this bitfield for any queue where
+requests are supported.
+
+
+Minor modifications required on the backport
+---
+ drivers/media/common/videobuf2/videobuf2-v4l2.c | 17 +++++++++++++++++
+ drivers/media/platform/vim2m.c | 1 +
+ drivers/media/platform/vivid/vivid-core.c | 5 +++++
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 +++-
+ drivers/media/v4l2-core/v4l2-ioctl.c | 4 ++--
+ include/media/videobuf2-core.h | 2 ++
+ 6 files changed, 30 insertions(+), 3 deletions(-)
+
+--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
++++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
+@@ -482,10 +482,24 @@ int vb2_querybuf(struct vb2_queue *q, st
+ }
+ EXPORT_SYMBOL(vb2_querybuf);
+
++static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
++{
++ *caps = 0;
++ if (q->io_modes & VB2_MMAP)
++ *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
++ if (q->io_modes & VB2_USERPTR)
++ *caps |= V4L2_BUF_CAP_SUPPORTS_USERPTR;
++ if (q->io_modes & VB2_DMABUF)
++ *caps |= V4L2_BUF_CAP_SUPPORTS_DMABUF;
++ if (q->supports_requests)
++ *caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS;
++}
++
+ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
+ {
+ int ret = vb2_verify_memory_type(q, req->memory, req->type);
+
++ fill_buf_caps(q, &req->capabilities);
+ return ret ? ret : vb2_core_reqbufs(q, req->memory, &req->count);
+ }
+ EXPORT_SYMBOL_GPL(vb2_reqbufs);
+@@ -513,6 +527,7 @@ int vb2_create_bufs(struct vb2_queue *q,
+ int ret = vb2_verify_memory_type(q, create->memory, f->type);
+ unsigned i;
+
++ fill_buf_caps(q, &create->capabilities);
+ create->index = q->num_buffers;
+ if (create->count == 0)
+ return ret != -EBUSY ? ret : 0;
+@@ -713,6 +728,7 @@ int vb2_ioctl_reqbufs(struct file *file,
+ struct video_device *vdev = video_devdata(file);
+ int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type);
+
++ fill_buf_caps(vdev->queue, &p->capabilities);
+ if (res)
+ return res;
+ if (vb2_queue_is_busy(vdev, file))
+@@ -734,6 +750,7 @@ int vb2_ioctl_create_bufs(struct file *f
+ p->format.type);
+
+ p->index = vdev->queue->num_buffers;
++ fill_buf_caps(vdev->queue, &p->capabilities);
+ /*
+ * If count == 0, then just check if memory and type are valid.
+ * Any -EBUSY result from vb2_verify_memory_type can be mapped to 0.
+--- a/drivers/media/platform/vim2m.c
++++ b/drivers/media/platform/vim2m.c
+@@ -840,6 +840,7 @@ static int queue_init(void *priv, struct
+ src_vq->mem_ops = &vb2_vmalloc_memops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->dev->dev_mutex;
++ src_vq->supports_requests = true;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+--- a/drivers/media/platform/vivid/vivid-core.c
++++ b/drivers/media/platform/vivid/vivid-core.c
+@@ -1060,6 +1060,7 @@ static int vivid_create_instance(struct
+ q->min_buffers_needed = 2;
+ q->lock = &dev->mutex;
+ q->dev = dev->v4l2_dev.dev;
++ q->supports_requests = true;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+@@ -1080,6 +1081,7 @@ static int vivid_create_instance(struct
+ q->min_buffers_needed = 2;
+ q->lock = &dev->mutex;
+ q->dev = dev->v4l2_dev.dev;
++ q->supports_requests = true;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+@@ -1100,6 +1102,7 @@ static int vivid_create_instance(struct
+ q->min_buffers_needed = 2;
+ q->lock = &dev->mutex;
+ q->dev = dev->v4l2_dev.dev;
++ q->supports_requests = true;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+@@ -1120,6 +1123,7 @@ static int vivid_create_instance(struct
+ q->min_buffers_needed = 2;
+ q->lock = &dev->mutex;
+ q->dev = dev->v4l2_dev.dev;
++ q->supports_requests = true;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+@@ -1139,6 +1143,7 @@ static int vivid_create_instance(struct
+ q->min_buffers_needed = 8;
+ q->lock = &dev->mutex;
+ q->dev = dev->v4l2_dev.dev;
++ q->supports_requests = true;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -251,7 +251,8 @@ struct v4l2_create_buffers32 {
+ __u32 count;
+ __u32 memory; /* enum v4l2_memory */
+ struct v4l2_format32 format;
+- __u32 reserved[8];
++ __u32 capabilities;
++ __u32 reserved[7];
+ };
+
+ static int __bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size)
+@@ -411,6 +412,7 @@ static int put_v4l2_create32(struct v4l2
+ if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
+ copy_in_user(p32, p64,
+ offsetof(struct v4l2_create_buffers32, format)) ||
++ assign_in_user(&p32->capabilities, &p64->capabilities) ||
+ copy_in_user(p32->reserved, p64->reserved, sizeof(p64->reserved)))
+ return -EFAULT;
+ return __put_v4l2_format32(&p64->format, &p32->format);
+--- a/drivers/media/v4l2-core/v4l2-ioctl.c
++++ b/drivers/media/v4l2-core/v4l2-ioctl.c
+@@ -1882,7 +1882,7 @@ static int v4l_reqbufs(const struct v4l2
+ if (ret)
+ return ret;
+
+- CLEAR_AFTER_FIELD(p, memory);
++ CLEAR_AFTER_FIELD(p, capabilities);
+
+ return ops->vidioc_reqbufs(file, fh, p);
+ }
+@@ -1923,7 +1923,7 @@ static int v4l_create_bufs(const struct
+ if (ret)
+ return ret;
+
+- CLEAR_AFTER_FIELD(create, format);
++ CLEAR_AFTER_FIELD(create, capabilities);
+
+ v4l_sanitize_format(&create->format);
+
+--- a/include/media/videobuf2-core.h
++++ b/include/media/videobuf2-core.h
+@@ -449,6 +449,7 @@ struct vb2_buf_ops {
+ * @quirk_poll_must_check_waiting_for_buffers: Return %EPOLLERR at poll when QBUF
+ * has not been called. This is a vb1 idiom that has been adopted
+ * also by vb2.
++ * @supports_requests: this queue supports the Request API.
+ * @lock: pointer to a mutex that protects the &struct vb2_queue. The
+ * driver can set this to a mutex to let the v4l2 core serialize
+ * the queuing ioctls. If the driver wants to handle locking
+@@ -516,6 +517,7 @@ struct vb2_queue {
+ unsigned fileio_write_immediately:1;
+ unsigned allow_zero_bytesused:1;
+ unsigned quirk_poll_must_check_waiting_for_buffers:1;
++ unsigned supports_requests:1;
+
+ struct mutex *lock;
+ void *owner;
+++ /dev/null
-From 38ae4957840ff9578a497422a8ca758549f734d5 Mon Sep 17 00:00:00 2001
-Date: Tue, 2 Jul 2019 17:19:04 +0100
-Subject: [PATCH] staging: vc-sm-cma: Fix the few remaining coding
- style issues
-
-Fix a few minor checkpatch complaints to make the driver clean
-
----
- .../staging/vc04_services/vc-sm-cma/vc_sm.c | 6 +-
- .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 128 +++++++++---------
- 2 files changed, 65 insertions(+), 69 deletions(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -325,7 +325,6 @@ static void vc_sm_release_resource(struc
- buffer->cookie, buffer->dma_addr);
- }
-
--
- /* Free our buffer. Start by removing it from the list */
- mutex_lock(&sm_state->map_lock);
- list_del(&buffer->global_buffer_list);
-@@ -1365,7 +1364,8 @@ static int vc_sm_cma_clean_invalid2(unsi
- }
-
- for (i = 0; i < ioparam.op_count; i++) {
-- const struct vc_sm_cma_ioctl_clean_invalid_block * const op = block + i;
-+ const struct vc_sm_cma_ioctl_clean_invalid_block * const op =
-+ block + i;
-
- if (op->invalidate_mode == VC_SM_CACHE_OP_NOP)
- continue;
-@@ -1637,8 +1637,6 @@ err_remove_misc_dev:
- err_remove_debugfs:
- debugfs_remove_recursive(sm_state->dir_root);
- vc_sm_cma_vchi_stop(&sm_state->sm_handle);
--
-- return;
- }
-
- /* Driver loading. */
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
-@@ -188,79 +188,77 @@ static int vc_sm_cma_vchi_videocore_io(v
- if (svc_use)
- vchi_service_release(instance->vchi_handle[0]);
- svc_use = 0;
-- if (!wait_for_completion_interruptible(&instance->io_cmplt)) {
-- vchi_service_use(instance->vchi_handle[0]);
-- svc_use = 1;
--
-- do {
-- /*
-- * Get new command and move it to response list
-- */
-- mutex_lock(&instance->lock);
-- if (list_empty(&instance->cmd_list)) {
-- /* no more commands to process */
-- mutex_unlock(&instance->lock);
-- break;
-- }
-- cmd =
-- list_first_entry(&instance->cmd_list,
-- struct sm_cmd_rsp_blk,
-- head);
-- list_move(&cmd->head, &instance->rsp_list);
-- cmd->sent = 1;
-- mutex_unlock(&instance->lock);
-
-- /* Send the command */
-- status = bcm2835_vchi_msg_queue(
-- instance->vchi_handle[0],
-- cmd->msg, cmd->length);
-- if (status) {
-- pr_err("%s: failed to queue message (%d)",
-- __func__, status);
-- }
--
-- /* If no reply is needed then we're done */
-- if (!cmd->wait) {
-- mutex_lock(&instance->lock);
-- list_del(&cmd->head);
-- mutex_unlock(&instance->lock);
-- vc_vchi_cmd_delete(instance, cmd);
-- continue;
-- }
--
-- if (status) {
-- complete(&cmd->cmplt);
-- continue;
-- }
--
-- } while (1);
--
-- while (!vchi_msg_peek(instance->vchi_handle[0],
-- (void **)&reply, &reply_len,
-- VCHI_FLAGS_NONE)) {
-- if (reply->trans_id & 0x80000000) {
-- /* Async event or cmd from the VPU */
-- if (instance->vpu_event)
-- instance->vpu_event(
-- instance, reply,
-- reply_len);
-- } else {
-- vc_sm_cma_vchi_rx_ack(instance, cmd,
-- reply, reply_len);
-- }
-+ if (wait_for_completion_interruptible(&instance->io_cmplt))
-+ continue;
-
-- vchi_msg_remove(instance->vchi_handle[0]);
-- }
-+ vchi_service_use(instance->vchi_handle[0]);
-+ svc_use = 1;
-
-- /* Go through the dead list and free them */
-+ do {
-+ /*
-+ * Get new command and move it to response list
-+ */
- mutex_lock(&instance->lock);
-- list_for_each_entry_safe(cmd, cmd_tmp,
-- &instance->dead_list, head) {
-+ if (list_empty(&instance->cmd_list)) {
-+ /* no more commands to process */
-+ mutex_unlock(&instance->lock);
-+ break;
-+ }
-+ cmd = list_first_entry(&instance->cmd_list,
-+ struct sm_cmd_rsp_blk, head);
-+ list_move(&cmd->head, &instance->rsp_list);
-+ cmd->sent = 1;
-+ mutex_unlock(&instance->lock);
-+
-+ /* Send the command */
-+ status =
-+ bcm2835_vchi_msg_queue(instance->vchi_handle[0],
-+ cmd->msg, cmd->length);
-+ if (status) {
-+ pr_err("%s: failed to queue message (%d)",
-+ __func__, status);
-+ }
-+
-+ /* If no reply is needed then we're done */
-+ if (!cmd->wait) {
-+ mutex_lock(&instance->lock);
- list_del(&cmd->head);
-+ mutex_unlock(&instance->lock);
- vc_vchi_cmd_delete(instance, cmd);
-+ continue;
- }
-- mutex_unlock(&instance->lock);
-+
-+ if (status) {
-+ complete(&cmd->cmplt);
-+ continue;
-+ }
-+
-+ } while (1);
-+
-+ while (!vchi_msg_peek(instance->vchi_handle[0], (void **)&reply,
-+ &reply_len, VCHI_FLAGS_NONE)) {
-+ if (reply->trans_id & 0x80000000) {
-+ /* Async event or cmd from the VPU */
-+ if (instance->vpu_event)
-+ instance->vpu_event(instance, reply,
-+ reply_len);
-+ } else {
-+ vc_sm_cma_vchi_rx_ack(instance, cmd, reply,
-+ reply_len);
-+ }
-+
-+ vchi_msg_remove(instance->vchi_handle[0]);
-+ }
-+
-+ /* Go through the dead list and free them */
-+ mutex_lock(&instance->lock);
-+ list_for_each_entry_safe(cmd, cmd_tmp, &instance->dead_list,
-+ head) {
-+ list_del(&cmd->head);
-+ vc_vchi_cmd_delete(instance, cmd);
- }
-+ mutex_unlock(&instance->lock);
- }
-
- return 0;
--- /dev/null
+From 16cf378051d7fff6772a7acaecbacddec7822330 Mon Sep 17 00:00:00 2001
+Date: Thu, 15 Nov 2018 10:57:16 -0500
+Subject: [PATCH] media: vb2: Allow reqbufs(0) with "in use" MMAP
+ buffers
+
+Upstream commit d644cca50f366cd109845ae92e37c09ed79adf81
+
+Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
+buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
+considered "in use". This is different behavior than for other memory
+types and prevents us from deallocating buffers in following two cases:
+
+1) There are outstanding mmap()ed views on the buffer. However even if
+ we put the buffer in reqbufs(0), there will be remaining references,
+ due to vma .open/close() adjusting vb2 buffer refcount appropriately.
+ This means that the buffer will be in fact freed only when the last
+ mmap()ed view is unmapped.
+
+2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
+ is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
+ get and decremented on DMABUF release. This means that the buffer
+ will be alive until all importers release it.
+
+Considering both cases above, there does not seem to be any need to
+prevent reqbufs(0) operation, because buffer lifetime is already
+properly managed by both mmap() and DMABUF code paths. Let's remove it
+and allow userspace freeing the queue (and potentially allocating a new
+one) even though old buffers might be still in processing.
+
+To let userspace know that the kernel now supports orphaning buffers
+that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
+to be set by reqbufs and create_bufs.
+
+ updated documentation, and added back debug message]
+
+---
+ Documentation/media/uapi/v4l/vidioc-reqbufs.rst | 17 ++++++++++++++---
+ drivers/media/common/videobuf2/videobuf2-core.c | 8 +++-----
+ drivers/media/common/videobuf2/videobuf2-v4l2.c | 2 +-
+ include/uapi/linux/videodev2.h | 1 +
+ 4 files changed, 19 insertions(+), 9 deletions(-)
+
+--- a/Documentation/media/uapi/v4l/vidioc-reqbufs.rst
++++ b/Documentation/media/uapi/v4l/vidioc-reqbufs.rst
+@@ -59,9 +59,14 @@ When the I/O method is not supported the
+ code.
+
+ Applications can call :ref:`VIDIOC_REQBUFS` again to change the number of
+-buffers, however this cannot succeed when any buffers are still mapped.
+-A ``count`` value of zero frees all buffers, after aborting or finishing
+-any DMA in progress, an implicit
++buffers. Note that if any buffers are still mapped or exported via DMABUF,
++then :ref:`VIDIOC_REQBUFS` can only succeed if the
++``V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS`` capability is set. Otherwise
++:ref:`VIDIOC_REQBUFS` will return the ``EBUSY`` error code.
++If ``V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS`` is set, then these buffers are
++orphaned and will be freed when they are unmapped or when the exported DMABUF
++fds are closed. A ``count`` value of zero frees or orphans all buffers, after
++aborting or finishing any DMA in progress, an implicit
+ :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>`.
+
+
+@@ -112,6 +117,7 @@ any DMA in progress, an implicit
+ .. _V4L2-BUF-CAP-SUPPORTS-USERPTR:
+ .. _V4L2-BUF-CAP-SUPPORTS-DMABUF:
+ .. _V4L2-BUF-CAP-SUPPORTS-REQUESTS:
++.. _V4L2-BUF-CAP-SUPPORTS-ORPHANED-BUFS:
+
+ .. cssclass:: longtable
+
+@@ -132,6 +138,11 @@ any DMA in progress, an implicit
+ * - ``V4L2_BUF_CAP_SUPPORTS_REQUESTS``
+ - 0x00000008
+ - This buffer type supports :ref:`requests <media-request-api>`.
++ * - ``V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS``
++ - 0x00000010
++ - The kernel allows calling :ref:`VIDIOC_REQBUFS` while buffers are still
++ mapped or exported via DMABUF. These orphaned buffers will be freed
++ when they are unmapped or when the exported DMABUF fds are closed.
+
+ Return Value
+ ============
+--- a/drivers/media/common/videobuf2/videobuf2-core.c
++++ b/drivers/media/common/videobuf2/videobuf2-core.c
+@@ -684,11 +684,9 @@ int vb2_core_reqbufs(struct vb2_queue *q
+ * are not in use and can be freed.
+ */
+ mutex_lock(&q->mmap_lock);
+- if (q->memory == VB2_MEMORY_MMAP && __buffers_in_use(q)) {
+- mutex_unlock(&q->mmap_lock);
+- dprintk(1, "memory in use, cannot free\n");
+- return -EBUSY;
+- }
++ if (debug && q->memory == VB2_MEMORY_MMAP &&
++ __buffers_in_use(q))
++ dprintk(1, "memory in use, orphaning buffers\n");
+
+ /*
+ * Call queue_cancel to clean up any buffers in the PREPARED or
+--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
++++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
+@@ -484,7 +484,7 @@ EXPORT_SYMBOL(vb2_querybuf);
+
+ static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
+ {
+- *caps = 0;
++ *caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
+ if (q->io_modes & VB2_MMAP)
+ *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
+ if (q->io_modes & VB2_USERPTR)
+--- a/include/uapi/linux/videodev2.h
++++ b/include/uapi/linux/videodev2.h
+@@ -881,6 +881,7 @@ struct v4l2_requestbuffers {
+ #define V4L2_BUF_CAP_SUPPORTS_USERPTR (1 << 1)
+ #define V4L2_BUF_CAP_SUPPORTS_DMABUF (1 << 2)
+ #define V4L2_BUF_CAP_SUPPORTS_REQUESTS (1 << 3)
++#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4)
+
+ /**
+ * struct v4l2_plane - plane info for multi-planar buffers
+++ /dev/null
-From ebd995296afa99a5c53f164e595f7a6d41d32a01 Mon Sep 17 00:00:00 2001
-Date: Thu, 23 Aug 2018 09:56:22 -0400
-Subject: [PATCH] media: videodev2.h: add new capabilities for buffer
- types
-
-Upstream commit f35f5d72e70e6b91389eb98fcabf43b79f40587f
-
-VIDIOC_REQBUFS and VIDIOC_CREATE_BUFFERS will return capabilities
-telling userspace what the given buffer type is capable of.
-
----
- .../media/uapi/v4l/vidioc-create-bufs.rst | 14 ++++++-
- .../media/uapi/v4l/vidioc-reqbufs.rst | 42 ++++++++++++++++++-
- include/uapi/linux/videodev2.h | 13 +++++-
- 3 files changed, 65 insertions(+), 4 deletions(-)
-
---- a/Documentation/media/uapi/v4l/vidioc-create-bufs.rst
-+++ b/Documentation/media/uapi/v4l/vidioc-create-bufs.rst
-@@ -102,7 +102,19 @@ than the number requested.
- - ``format``
- - Filled in by the application, preserved by the driver.
- * - __u32
-- - ``reserved``\ [8]
-+ - ``capabilities``
-+ - Set by the driver. If 0, then the driver doesn't support
-+ capabilities. In that case all you know is that the driver is
-+ guaranteed to support ``V4L2_MEMORY_MMAP`` and *might* support
-+ other :c:type:`v4l2_memory` types. It will not support any others
-+ capabilities. See :ref:`here <v4l2-buf-capabilities>` for a list of the
-+ capabilities.
-+
-+ If you want to just query the capabilities without making any
-+ other changes, then set ``count`` to 0, ``memory`` to
-+ ``V4L2_MEMORY_MMAP`` and ``format.type`` to the buffer type.
-+ * - __u32
-+ - ``reserved``\ [7]
- - A place holder for future extensions. Drivers and applications
- must set the array to zero.
-
---- a/Documentation/media/uapi/v4l/vidioc-reqbufs.rst
-+++ b/Documentation/media/uapi/v4l/vidioc-reqbufs.rst
-@@ -88,10 +88,50 @@ any DMA in progress, an implicit
- ``V4L2_MEMORY_DMABUF`` or ``V4L2_MEMORY_USERPTR``. See
- :c:type:`v4l2_memory`.
- * - __u32
-- - ``reserved``\ [2]
-+ - ``capabilities``
-+ - Set by the driver. If 0, then the driver doesn't support
-+ capabilities. In that case all you know is that the driver is
-+ guaranteed to support ``V4L2_MEMORY_MMAP`` and *might* support
-+ other :c:type:`v4l2_memory` types. It will not support any others
-+ capabilities.
-+
-+ If you want to query the capabilities with a minimum of side-effects,
-+ then this can be called with ``count`` set to 0, ``memory`` set to
-+ ``V4L2_MEMORY_MMAP`` and ``type`` set to the buffer type. This will
-+ free any previously allocated buffers, so this is typically something
-+ that will be done at the start of the application.
-+ * - __u32
-+ - ``reserved``\ [1]
- - A place holder for future extensions. Drivers and applications
- must set the array to zero.
-
-+.. tabularcolumns:: |p{6.1cm}|p{2.2cm}|p{8.7cm}|
-+
-+.. _v4l2-buf-capabilities:
-+.. _V4L2-BUF-CAP-SUPPORTS-MMAP:
-+.. _V4L2-BUF-CAP-SUPPORTS-USERPTR:
-+.. _V4L2-BUF-CAP-SUPPORTS-DMABUF:
-+.. _V4L2-BUF-CAP-SUPPORTS-REQUESTS:
-+
-+.. cssclass:: longtable
-+
-+.. flat-table:: V4L2 Buffer Capabilities Flags
-+ :header-rows: 0
-+ :stub-columns: 0
-+ :widths: 3 1 4
-+
-+ * - ``V4L2_BUF_CAP_SUPPORTS_MMAP``
-+ - 0x00000001
-+ - This buffer type supports the ``V4L2_MEMORY_MMAP`` streaming mode.
-+ * - ``V4L2_BUF_CAP_SUPPORTS_USERPTR``
-+ - 0x00000002
-+ - This buffer type supports the ``V4L2_MEMORY_USERPTR`` streaming mode.
-+ * - ``V4L2_BUF_CAP_SUPPORTS_DMABUF``
-+ - 0x00000004
-+ - This buffer type supports the ``V4L2_MEMORY_DMABUF`` streaming mode.
-+ * - ``V4L2_BUF_CAP_SUPPORTS_REQUESTS``
-+ - 0x00000008
-+ - This buffer type supports :ref:`requests <media-request-api>`.
-
- Return Value
- ============
---- a/include/uapi/linux/videodev2.h
-+++ b/include/uapi/linux/videodev2.h
-@@ -872,9 +872,16 @@ struct v4l2_requestbuffers {
- __u32 count;
- __u32 type; /* enum v4l2_buf_type */
- __u32 memory; /* enum v4l2_memory */
-- __u32 reserved[2];
-+ __u32 capabilities;
-+ __u32 reserved[1];
- };
-
-+/* capabilities for struct v4l2_requestbuffers and v4l2_create_buffers */
-+#define V4L2_BUF_CAP_SUPPORTS_MMAP (1 << 0)
-+#define V4L2_BUF_CAP_SUPPORTS_USERPTR (1 << 1)
-+#define V4L2_BUF_CAP_SUPPORTS_DMABUF (1 << 2)
-+#define V4L2_BUF_CAP_SUPPORTS_REQUESTS (1 << 3)
-+
- /**
- * struct v4l2_plane - plane info for multi-planar buffers
- * @bytesused: number of bytes occupied by data in the plane (payload)
-@@ -2318,6 +2325,7 @@ struct v4l2_dbg_chip_info {
- * return: number of created buffers
- * @memory: enum v4l2_memory; buffer memory type
- * @format: frame format, for which buffers are requested
-+ * @capabilities: capabilities of this buffer type.
- * @reserved: future extensions
- */
- struct v4l2_create_buffers {
-@@ -2325,7 +2333,8 @@ struct v4l2_create_buffers {
- __u32 count;
- __u32 memory;
- struct v4l2_format format;
-- __u32 reserved[8];
-+ __u32 capabilities;
-+ __u32 reserved[7];
- };
-
- /*
+++ /dev/null
-From 7410e35a4936b89f2e227c52058c11f1574bbfca Mon Sep 17 00:00:00 2001
-Date: Thu, 23 Aug 2018 10:18:35 -0400
-Subject: [PATCH] media: vb2: set reqbufs/create_bufs capabilities
-
-Upstream commit e5079cf11373e4cc98be8b1072aece429eb2d4d2.
-
-Set the capabilities field of v4l2_requestbuffers and v4l2_create_buffers.
-
-The various mapping modes were easy, but for signaling the request capability
-a new 'supports_requests' bitfield was added to videobuf2-core.h (and set in
-vim2m and vivid). Drivers have to set this bitfield for any queue where
-requests are supported.
-
-
-Minor modifications required on the backport
----
- drivers/media/common/videobuf2/videobuf2-v4l2.c | 17 +++++++++++++++++
- drivers/media/platform/vim2m.c | 1 +
- drivers/media/platform/vivid/vivid-core.c | 5 +++++
- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 +++-
- drivers/media/v4l2-core/v4l2-ioctl.c | 4 ++--
- include/media/videobuf2-core.h | 2 ++
- 6 files changed, 30 insertions(+), 3 deletions(-)
-
---- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
-+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
-@@ -482,10 +482,24 @@ int vb2_querybuf(struct vb2_queue *q, st
- }
- EXPORT_SYMBOL(vb2_querybuf);
-
-+static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
-+{
-+ *caps = 0;
-+ if (q->io_modes & VB2_MMAP)
-+ *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
-+ if (q->io_modes & VB2_USERPTR)
-+ *caps |= V4L2_BUF_CAP_SUPPORTS_USERPTR;
-+ if (q->io_modes & VB2_DMABUF)
-+ *caps |= V4L2_BUF_CAP_SUPPORTS_DMABUF;
-+ if (q->supports_requests)
-+ *caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS;
-+}
-+
- int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
- {
- int ret = vb2_verify_memory_type(q, req->memory, req->type);
-
-+ fill_buf_caps(q, &req->capabilities);
- return ret ? ret : vb2_core_reqbufs(q, req->memory, &req->count);
- }
- EXPORT_SYMBOL_GPL(vb2_reqbufs);
-@@ -513,6 +527,7 @@ int vb2_create_bufs(struct vb2_queue *q,
- int ret = vb2_verify_memory_type(q, create->memory, f->type);
- unsigned i;
-
-+ fill_buf_caps(q, &create->capabilities);
- create->index = q->num_buffers;
- if (create->count == 0)
- return ret != -EBUSY ? ret : 0;
-@@ -713,6 +728,7 @@ int vb2_ioctl_reqbufs(struct file *file,
- struct video_device *vdev = video_devdata(file);
- int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type);
-
-+ fill_buf_caps(vdev->queue, &p->capabilities);
- if (res)
- return res;
- if (vb2_queue_is_busy(vdev, file))
-@@ -734,6 +750,7 @@ int vb2_ioctl_create_bufs(struct file *f
- p->format.type);
-
- p->index = vdev->queue->num_buffers;
-+ fill_buf_caps(vdev->queue, &p->capabilities);
- /*
- * If count == 0, then just check if memory and type are valid.
- * Any -EBUSY result from vb2_verify_memory_type can be mapped to 0.
---- a/drivers/media/platform/vim2m.c
-+++ b/drivers/media/platform/vim2m.c
-@@ -840,6 +840,7 @@ static int queue_init(void *priv, struct
- src_vq->mem_ops = &vb2_vmalloc_memops;
- src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- src_vq->lock = &ctx->dev->dev_mutex;
-+ src_vq->supports_requests = true;
-
- ret = vb2_queue_init(src_vq);
- if (ret)
---- a/drivers/media/platform/vivid/vivid-core.c
-+++ b/drivers/media/platform/vivid/vivid-core.c
-@@ -1060,6 +1060,7 @@ static int vivid_create_instance(struct
- q->min_buffers_needed = 2;
- q->lock = &dev->mutex;
- q->dev = dev->v4l2_dev.dev;
-+ q->supports_requests = true;
-
- ret = vb2_queue_init(q);
- if (ret)
-@@ -1080,6 +1081,7 @@ static int vivid_create_instance(struct
- q->min_buffers_needed = 2;
- q->lock = &dev->mutex;
- q->dev = dev->v4l2_dev.dev;
-+ q->supports_requests = true;
-
- ret = vb2_queue_init(q);
- if (ret)
-@@ -1100,6 +1102,7 @@ static int vivid_create_instance(struct
- q->min_buffers_needed = 2;
- q->lock = &dev->mutex;
- q->dev = dev->v4l2_dev.dev;
-+ q->supports_requests = true;
-
- ret = vb2_queue_init(q);
- if (ret)
-@@ -1120,6 +1123,7 @@ static int vivid_create_instance(struct
- q->min_buffers_needed = 2;
- q->lock = &dev->mutex;
- q->dev = dev->v4l2_dev.dev;
-+ q->supports_requests = true;
-
- ret = vb2_queue_init(q);
- if (ret)
-@@ -1139,6 +1143,7 @@ static int vivid_create_instance(struct
- q->min_buffers_needed = 8;
- q->lock = &dev->mutex;
- q->dev = dev->v4l2_dev.dev;
-+ q->supports_requests = true;
-
- ret = vb2_queue_init(q);
- if (ret)
---- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
-+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
-@@ -251,7 +251,8 @@ struct v4l2_create_buffers32 {
- __u32 count;
- __u32 memory; /* enum v4l2_memory */
- struct v4l2_format32 format;
-- __u32 reserved[8];
-+ __u32 capabilities;
-+ __u32 reserved[7];
- };
-
- static int __bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size)
-@@ -411,6 +412,7 @@ static int put_v4l2_create32(struct v4l2
- if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
- copy_in_user(p32, p64,
- offsetof(struct v4l2_create_buffers32, format)) ||
-+ assign_in_user(&p32->capabilities, &p64->capabilities) ||
- copy_in_user(p32->reserved, p64->reserved, sizeof(p64->reserved)))
- return -EFAULT;
- return __put_v4l2_format32(&p64->format, &p32->format);
---- a/drivers/media/v4l2-core/v4l2-ioctl.c
-+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
-@@ -1882,7 +1882,7 @@ static int v4l_reqbufs(const struct v4l2
- if (ret)
- return ret;
-
-- CLEAR_AFTER_FIELD(p, memory);
-+ CLEAR_AFTER_FIELD(p, capabilities);
-
- return ops->vidioc_reqbufs(file, fh, p);
- }
-@@ -1923,7 +1923,7 @@ static int v4l_create_bufs(const struct
- if (ret)
- return ret;
-
-- CLEAR_AFTER_FIELD(create, format);
-+ CLEAR_AFTER_FIELD(create, capabilities);
-
- v4l_sanitize_format(&create->format);
-
---- a/include/media/videobuf2-core.h
-+++ b/include/media/videobuf2-core.h
-@@ -449,6 +449,7 @@ struct vb2_buf_ops {
- * @quirk_poll_must_check_waiting_for_buffers: Return %EPOLLERR at poll when QBUF
- * has not been called. This is a vb1 idiom that has been adopted
- * also by vb2.
-+ * @supports_requests: this queue supports the Request API.
- * @lock: pointer to a mutex that protects the &struct vb2_queue. The
- * driver can set this to a mutex to let the v4l2 core serialize
- * the queuing ioctls. If the driver wants to handle locking
-@@ -516,6 +517,7 @@ struct vb2_queue {
- unsigned fileio_write_immediately:1;
- unsigned allow_zero_bytesused:1;
- unsigned quirk_poll_must_check_waiting_for_buffers:1;
-+ unsigned supports_requests:1;
-
- struct mutex *lock;
- void *owner;
--- /dev/null
+From a11b6221e69ba4177ee428e2cb6fb4e4bd68c5f4 Mon Sep 17 00:00:00 2001
+Date: Fri, 5 Jul 2019 09:22:10 +0100
+Subject: [PATCH] overlays: Add real parameters to the rpi-poe overlay
+
+As a result of being loaded by the POE HAT EEPROM, the rpi-poe overlay
+doesn't expose parameters in the usual way; instead it adds them to
+the base Device Tree, and the user is expected to use "dtparam=..."
+to access them.
+
+To make the documentation correct and to protect users who load the
+overlay explicitly, expecting to be able to use the parameters, add
+real parameters to the overlay as well.
+
+---
+ arch/arm/boot/dts/overlays/rpi-poe-overlay.dts | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts
+@@ -60,4 +60,11 @@
+ poe_fan_temp1_hyst = <&trip1>,"hysteresis:0";
+ };
+ };
++
++ __overrides__ {
++ poe_fan_temp0 = <&trip0>,"temperature:0";
++ poe_fan_temp0_hyst = <&trip0>,"hysteresis:0";
++ poe_fan_temp1 = <&trip1>,"temperature:0";
++ poe_fan_temp1_hyst = <&trip1>,"hysteresis:0";
++ };
+ };
+++ /dev/null
-From 16cf378051d7fff6772a7acaecbacddec7822330 Mon Sep 17 00:00:00 2001
-Date: Thu, 15 Nov 2018 10:57:16 -0500
-Subject: [PATCH] media: vb2: Allow reqbufs(0) with "in use" MMAP
- buffers
-
-Upstream commit d644cca50f366cd109845ae92e37c09ed79adf81
-
-Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
-buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
-considered "in use". This is different behavior than for other memory
-types and prevents us from deallocating buffers in following two cases:
-
-1) There are outstanding mmap()ed views on the buffer. However even if
- we put the buffer in reqbufs(0), there will be remaining references,
- due to vma .open/close() adjusting vb2 buffer refcount appropriately.
- This means that the buffer will be in fact freed only when the last
- mmap()ed view is unmapped.
-
-2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
- is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
- get and decremented on DMABUF release. This means that the buffer
- will be alive until all importers release it.
-
-Considering both cases above, there does not seem to be any need to
-prevent reqbufs(0) operation, because buffer lifetime is already
-properly managed by both mmap() and DMABUF code paths. Let's remove it
-and allow userspace freeing the queue (and potentially allocating a new
-one) even though old buffers might be still in processing.
-
-To let userspace know that the kernel now supports orphaning buffers
-that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
-to be set by reqbufs and create_bufs.
-
- updated documentation, and added back debug message]
-
----
- Documentation/media/uapi/v4l/vidioc-reqbufs.rst | 17 ++++++++++++++---
- drivers/media/common/videobuf2/videobuf2-core.c | 8 +++-----
- drivers/media/common/videobuf2/videobuf2-v4l2.c | 2 +-
- include/uapi/linux/videodev2.h | 1 +
- 4 files changed, 19 insertions(+), 9 deletions(-)
-
---- a/Documentation/media/uapi/v4l/vidioc-reqbufs.rst
-+++ b/Documentation/media/uapi/v4l/vidioc-reqbufs.rst
-@@ -59,9 +59,14 @@ When the I/O method is not supported the
- code.
-
- Applications can call :ref:`VIDIOC_REQBUFS` again to change the number of
--buffers, however this cannot succeed when any buffers are still mapped.
--A ``count`` value of zero frees all buffers, after aborting or finishing
--any DMA in progress, an implicit
-+buffers. Note that if any buffers are still mapped or exported via DMABUF,
-+then :ref:`VIDIOC_REQBUFS` can only succeed if the
-+``V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS`` capability is set. Otherwise
-+:ref:`VIDIOC_REQBUFS` will return the ``EBUSY`` error code.
-+If ``V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS`` is set, then these buffers are
-+orphaned and will be freed when they are unmapped or when the exported DMABUF
-+fds are closed. A ``count`` value of zero frees or orphans all buffers, after
-+aborting or finishing any DMA in progress, an implicit
- :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>`.
-
-
-@@ -112,6 +117,7 @@ any DMA in progress, an implicit
- .. _V4L2-BUF-CAP-SUPPORTS-USERPTR:
- .. _V4L2-BUF-CAP-SUPPORTS-DMABUF:
- .. _V4L2-BUF-CAP-SUPPORTS-REQUESTS:
-+.. _V4L2-BUF-CAP-SUPPORTS-ORPHANED-BUFS:
-
- .. cssclass:: longtable
-
-@@ -132,6 +138,11 @@ any DMA in progress, an implicit
- * - ``V4L2_BUF_CAP_SUPPORTS_REQUESTS``
- - 0x00000008
- - This buffer type supports :ref:`requests <media-request-api>`.
-+ * - ``V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS``
-+ - 0x00000010
-+ - The kernel allows calling :ref:`VIDIOC_REQBUFS` while buffers are still
-+ mapped or exported via DMABUF. These orphaned buffers will be freed
-+ when they are unmapped or when the exported DMABUF fds are closed.
-
- Return Value
- ============
---- a/drivers/media/common/videobuf2/videobuf2-core.c
-+++ b/drivers/media/common/videobuf2/videobuf2-core.c
-@@ -684,11 +684,9 @@ int vb2_core_reqbufs(struct vb2_queue *q
- * are not in use and can be freed.
- */
- mutex_lock(&q->mmap_lock);
-- if (q->memory == VB2_MEMORY_MMAP && __buffers_in_use(q)) {
-- mutex_unlock(&q->mmap_lock);
-- dprintk(1, "memory in use, cannot free\n");
-- return -EBUSY;
-- }
-+ if (debug && q->memory == VB2_MEMORY_MMAP &&
-+ __buffers_in_use(q))
-+ dprintk(1, "memory in use, orphaning buffers\n");
-
- /*
- * Call queue_cancel to clean up any buffers in the PREPARED or
---- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
-+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
-@@ -484,7 +484,7 @@ EXPORT_SYMBOL(vb2_querybuf);
-
- static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
- {
-- *caps = 0;
-+ *caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
- if (q->io_modes & VB2_MMAP)
- *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
- if (q->io_modes & VB2_USERPTR)
---- a/include/uapi/linux/videodev2.h
-+++ b/include/uapi/linux/videodev2.h
-@@ -881,6 +881,7 @@ struct v4l2_requestbuffers {
- #define V4L2_BUF_CAP_SUPPORTS_USERPTR (1 << 1)
- #define V4L2_BUF_CAP_SUPPORTS_DMABUF (1 << 2)
- #define V4L2_BUF_CAP_SUPPORTS_REQUESTS (1 << 3)
-+#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4)
-
- /**
- * struct v4l2_plane - plane info for multi-planar buffers
--- /dev/null
+From c46811a3b0e0fb76015ac956172e40bce4e6d9b3 Mon Sep 17 00:00:00 2001
+Date: Fri, 5 Jul 2019 14:49:22 +0100
+Subject: [PATCH] overlays: Rename pi3- overlays to be less
+ model-specific (#3052)
+
+Rename the various pi3- overlays to be more generic, listing
+the devices they apply to in the README. The original names are
+retained for backwards compatibility as files that just include
+the new versions - the README marks them as being deprecated.
+
+See: https://github.com/raspberrypi/firmware/issues/1174
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 4 +
+ arch/arm/boot/dts/overlays/README | 97 ++++++++++++-------
+ .../arm/boot/dts/overlays/act-led-overlay.dts | 27 ++++++
+ .../boot/dts/overlays/disable-bt-overlay.dts | 55 +++++++++++
+ .../dts/overlays/disable-wifi-overlay.dts | 20 ++++
+ .../boot/dts/overlays/miniuart-bt-overlay.dts | 74 ++++++++++++++
+ .../boot/dts/overlays/pi3-act-led-overlay.dts | 28 +-----
+ .../dts/overlays/pi3-disable-bt-overlay.dts | 56 +----------
+ .../dts/overlays/pi3-disable-wifi-overlay.dts | 21 +---
+ .../dts/overlays/pi3-miniuart-bt-overlay.dts | 75 +-------------
+ 10 files changed, 246 insertions(+), 211 deletions(-)
+ create mode 100644 arch/arm/boot/dts/overlays/act-led-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/disable-bt-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/disable-wifi-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/miniuart-bt-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -1,6 +1,7 @@
+ # Overlays for the Raspberry Pi platform
+
+ dtbo-$(CONFIG_ARCH_BCM2835) += \
++ act-led.dtbo \
+ adau1977-adc.dtbo \
+ adau7002-simple.dtbo \
+ ads1015.dtbo \
+@@ -26,6 +27,8 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ dht11.dtbo \
+ dionaudio-loco.dtbo \
+ dionaudio-loco-v2.dtbo \
++ disable-bt.dtbo \
++ disable-wifi.dtbo \
+ dpi18.dtbo \
+ dpi24.dtbo \
+ draws.dtbo \
+@@ -91,6 +94,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ media-center.dtbo \
+ midi-uart0.dtbo \
+ midi-uart1.dtbo \
++ miniuart-bt.dtbo \
+ mmc.dtbo \
+ mpu6050.dtbo \
+ mz61581.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -180,14 +180,16 @@ Params:
+
+ act_led_activelow Set to "on" to invert the sense of the LED
+ (default "off")
+- N.B. For Pi3 see pi3-act-led overlay.
++ N.B. For Pi 3B, 3B+, 3A+ and 4B, use the act-led
++ overlay.
+
+ act_led_gpio Set which GPIO to use for the activity LED
+ (in case you want to connect it to an external
+ device)
+ (default "16" on a non-Plus board, "47" on a
+ Plus or Pi 2)
+- N.B. For Pi3 see pi3-act-led overlay.
++ N.B. For Pi 3B, 3B+, 3A+ and 4B, use the act-led
++ overlay.
+
+ pwr_led_trigger
+ pwr_led_activelow
+@@ -205,6 +207,23 @@ Params:
+ and the other i2c baudrate parameters.
+
+
++Name: act-led
++Info: Pi 3B, 3B+, 3A+ and 4B use a GPIO expander to drive the LEDs which can
++ only be accessed from the VPU. There is a special driver for this with a
++ separate DT node, which has the unfortunate consequence of breaking the
++ act_led_gpio and act_led_activelow dtparams.
++ This overlay changes the GPIO controller back to the standard one and
++ restores the dtparams.
++Load: dtoverlay=act-led,<param>=<val>
++Params: activelow Set to "on" to invert the sense of the LED
++ (default "off")
++
++ gpio Set which GPIO to use for the activity LED
++ (in case you want to connect it to an external
++ device)
++ REQUIRED
++
++
+ Name: adau1977-adc
+ Info: Overlay for activation of ADAU1977 ADC codec over I2C for control
+ and I2S for data.
+@@ -509,6 +528,21 @@ Params: 24db_digital_gain Allow ga
+ that does not result in clipping/distortion!)
+
+
++Name: disable-bt
++Info: Disable onboard Bluetooth on Pi 3B, 3B+, 3A+, 4B and Zero W, restoring
++ UART0/ttyAMA0 over GPIOs 14 & 15.
++ N.B. To disable the systemd service that initialises the modem so it
++ doesn't use the UART, use 'sudo systemctl disable hciuart'.
++Load: dtoverlay=disable-bt
++Params: <None>
++
++
++Name: disable-wifi
++Info: Disable onboard WiFi on Pi 3B, 3B+, 3A+, 4B and Zero W.
++Load: dtoverlay=disable-wifi
++Params: <None>
++
++
+ Name: dpi18
+ Info: Overlay for a generic 18-bit DPI display
+ This uses GPIOs 0-21 (so no I2C, uart etc.), and activates the output
+@@ -1447,6 +1481,20 @@ Load: dtoverlay=midi-uart1
+ Params: <None>
+
+
++Name: miniuart-bt
++Info: Switch the onboard Bluetooth function on Pi 3B, 3B+, 3A+, 4B and Zero W
++ to use the mini-UART (ttyS0) and restore UART0/ttyAMA0 over GPIOs 14 &
++ 15. Note that this may reduce the maximum usable baudrate.
++ N.B. It is also necessary to edit /lib/systemd/system/hciuart.service
++ and replace ttyAMA0 with ttyS0, unless using Raspbian or another
++ distribution with udev rules that create /dev/serial0 and /dev/serial1,
++ in which case use /dev/serial1 instead because it will always be
++ correct. Furthermore, you must also set core_freq and core_freq_min to
++ the same value in config.txt or the miniuart will not work.
++Load: dtoverlay=miniuart-bt
++Params: <None>
++
++
+ Name: mmc
+ Info: Selects the bcm2835-mmc SD/MMC driver, optionally with overclock
+ Load: dtoverlay=mmc,<param>=<val>
+@@ -1509,48 +1557,27 @@ Params: panel Display
+
+
+ Name: pi3-act-led
+-Info: Pi3 uses a GPIO expander to drive the LEDs which can only be accessed
+- from the VPU. There is a special driver for this with a separate DT
+- node, which has the unfortunate consequence of breaking the
+- act_led_gpio and act_led_activelow dtparams.
+- This overlay changes the GPIO controller back to the standard one and
+- restores the dtparams.
+-Load: dtoverlay=pi3-act-led,<param>=<val>
+-Params: activelow Set to "on" to invert the sense of the LED
+- (default "off")
+-
+- gpio Set which GPIO to use for the activity LED
+- (in case you want to connect it to an external
+- device)
+- REQUIRED
++Info: This overlay has been renamed act-led, keeping pi3-act-led as an alias
++ for backwards compatibility.
++Load: <Deprecated>
+
+
+ Name: pi3-disable-bt
+-Info: Disable Pi3 Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15
+- N.B. To disable the systemd service that initialises the modem so it
+- doesn't use the UART, use 'sudo systemctl disable hciuart'.
+-Load: dtoverlay=pi3-disable-bt
+-Params: <None>
++Info: This overlay has been renamed disable-bt, keeping pi3-disable-bt as an
++ alias for backwards compatibility.
++Load: <Deprecated>
+
+
+ Name: pi3-disable-wifi
+-Info: Disable Pi3 onboard WiFi
+-Load: dtoverlay=pi3-disable-wifi
+-Params: <None>
++Info: This overlay has been renamed disable-wifi, keeping pi3-disable-wifi as
++ an alias for backwards compatibility.
++Load: <Deprecated>
+
+
+ Name: pi3-miniuart-bt
+-Info: Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
+- UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
+- usable baudrate.
+- N.B. It is also necessary to edit /lib/systemd/system/hciuart.service
+- and replace ttyAMA0 with ttyS0, unless you have a system with udev rules
+- that create /dev/serial0 and /dev/serial1, in which case use
+- /dev/serial1 instead because it will always be correct. Furthermore,
+- you must also set core_freq=250 in config.txt or the miniuart will not
+- work.
+-Load: dtoverlay=pi3-miniuart-bt
+-Params: <None>
++Info: This overlay has been renamed miniuart-bt, keeping pi3-miniuart-bt as
++ an alias for backwards compatibility.
++Load: <Deprecated>
+
+
+ Name: pibell
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/act-led-overlay.dts
+@@ -0,0 +1,27 @@
++/dts-v1/;
++/plugin/;
++
++/* Pi3 uses a GPIO expander to drive the LEDs which can only be accessed
++ from the VPU. There is a special driver for this with a separate DT node,
++ which has the unfortunate consequence of breaking the act_led_gpio and
++ act_led_activelow dtparams.
++
++ This overlay changes the GPIO controller back to the standard one and
++ restores the dtparams.
++*/
++
++/{
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&act_led>;
++ frag0: __overlay__ {
++ gpios = <&gpio 0 0>;
++ };
++ };
++
++ __overrides__ {
++ gpio = <&frag0>,"gpios:4";
++ activelow = <&frag0>,"gpios:8";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/disable-bt-overlay.dts
+@@ -0,0 +1,55 @@
++/dts-v1/;
++/plugin/;
++
++/* Disable Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15.
++ To disable the systemd service that initialises the modem so it doesn't use
++ the UART:
++
++ sudo systemctl disable hciuart
++*/
++
++/{
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&uart1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@1 {
++ target = <&uart0>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart0_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&uart0_pins>;
++ __overlay__ {
++ brcm,pins;
++ brcm,function;
++ brcm,pull;
++ };
++ };
++
++ fragment@3 {
++ target = <&bt_pins>;
++ __overlay__ {
++ brcm,pins;
++ brcm,function;
++ brcm,pull;
++ };
++ };
++
++ fragment@4 {
++ target-path = "/aliases";
++ __overlay__ {
++ serial0 = "/soc/serial@7e201000";
++ serial1 = "/soc/serial@7e215040";
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/disable-wifi-overlay.dts
+@@ -0,0 +1,20 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&mmc>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@1 {
++ target = <&mmcnr>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/miniuart-bt-overlay.dts
+@@ -0,0 +1,74 @@
++/dts-v1/;
++/plugin/;
++
++/* Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
++ UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
++ usable baudrate.
++
++ It is also necessary to edit /lib/systemd/system/hciuart.service and
++ replace ttyAMA0 with ttyS0, unless you have a system with udev rules
++ that create /dev/serial0 and /dev/serial1, in which case use /dev/serial1
++ instead because it will always be correct.
++
++ If cmdline.txt uses the alias serial0 to refer to the user-accessable port
++ then the firmware will replace with the appropriate port whether or not
++ this overlay is used.
++*/
++
++/{
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&uart0>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart0_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&uart1>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart1_pins &bt_pins &fake_bt_cts>;
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&uart0_pins>;
++ __overlay__ {
++ brcm,pins;
++ brcm,function;
++ brcm,pull;
++ };
++ };
++
++ fragment@3 {
++ target = <&uart1_pins>;
++ __overlay__ {
++ brcm,pins = <32 33>;
++ brcm,function = <2>; /* alt5=UART1 */
++ brcm,pull = <0 2>;
++ };
++ };
++
++ fragment@4 {
++ target = <&gpio>;
++ __overlay__ {
++ fake_bt_cts: fake_bt_cts {
++ brcm,pins = <31>;
++ brcm,function = <1>; /* output */
++ };
++ };
++ };
++
++ fragment@5 {
++ target-path = "/aliases";
++ __overlay__ {
++ serial0 = "/soc/serial@7e201000";
++ serial1 = "/soc/serial@7e215040";
++ };
++ };
++};
+--- a/arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts
+@@ -1,27 +1 @@
+-/dts-v1/;
+-/plugin/;
+-
+-/* Pi3 uses a GPIO expander to drive the LEDs which can only be accessed
+- from the VPU. There is a special driver for this with a separate DT node,
+- which has the unfortunate consequence of breaking the act_led_gpio and
+- act_led_activelow dtparams.
+-
+- This overlay changes the GPIO controller back to the standard one and
+- restores the dtparams.
+-*/
+-
+-/{
+- compatible = "brcm,bcm2835";
+-
+- fragment@0 {
+- target = <&act_led>;
+- frag0: __overlay__ {
+- gpios = <&gpio 0 0>;
+- };
+- };
+-
+- __overrides__ {
+- gpio = <&frag0>,"gpios:4";
+- activelow = <&frag0>,"gpios:8";
+- };
+-};
++#include "act-led-overlay.dts"
+--- a/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
+@@ -1,55 +1 @@
+-/dts-v1/;
+-/plugin/;
+-
+-/* Disable Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15.
+- To disable the systemd service that initialises the modem so it doesn't use
+- the UART:
+-
+- sudo systemctl disable hciuart
+-*/
+-
+-/{
+- compatible = "brcm,bcm2835";
+-
+- fragment@0 {
+- target = <&uart1>;
+- __overlay__ {
+- status = "disabled";
+- };
+- };
+-
+- fragment@1 {
+- target = <&uart0>;
+- __overlay__ {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart0_pins>;
+- status = "okay";
+- };
+- };
+-
+- fragment@2 {
+- target = <&uart0_pins>;
+- __overlay__ {
+- brcm,pins;
+- brcm,function;
+- brcm,pull;
+- };
+- };
+-
+- fragment@3 {
+- target = <&bt_pins>;
+- __overlay__ {
+- brcm,pins;
+- brcm,function;
+- brcm,pull;
+- };
+- };
+-
+- fragment@4 {
+- target-path = "/aliases";
+- __overlay__ {
+- serial0 = "/soc/serial@7e201000";
+- serial1 = "/soc/serial@7e215040";
+- };
+- };
+-};
++#include "disable-bt-overlay.dts"
+--- a/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts
+@@ -1,20 +1 @@
+-/dts-v1/;
+-/plugin/;
+-
+-/{
+- compatible = "brcm,bcm2835";
+-
+- fragment@0 {
+- target = <&mmc>;
+- __overlay__ {
+- status = "disabled";
+- };
+- };
+-
+- fragment@1 {
+- target = <&mmcnr>;
+- __overlay__ {
+- status = "disabled";
+- };
+- };
+-};
++#include "disable-wifi-overlay.dts"
+--- a/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
+@@ -1,74 +1 @@
+-/dts-v1/;
+-/plugin/;
+-
+-/* Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
+- UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
+- usable baudrate.
+-
+- It is also necessary to edit /lib/systemd/system/hciuart.service and
+- replace ttyAMA0 with ttyS0, unless you have a system with udev rules
+- that create /dev/serial0 and /dev/serial1, in which case use /dev/serial1
+- instead because it will always be correct.
+-
+- If cmdline.txt uses the alias serial0 to refer to the user-accessable port
+- then the firmware will replace with the appropriate port whether or not
+- this overlay is used.
+-*/
+-
+-/{
+- compatible = "brcm,bcm2835";
+-
+- fragment@0 {
+- target = <&uart0>;
+- __overlay__ {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart0_pins>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+- target = <&uart1>;
+- __overlay__ {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart1_pins &bt_pins &fake_bt_cts>;
+- status = "okay";
+- };
+- };
+-
+- fragment@2 {
+- target = <&uart0_pins>;
+- __overlay__ {
+- brcm,pins;
+- brcm,function;
+- brcm,pull;
+- };
+- };
+-
+- fragment@3 {
+- target = <&uart1_pins>;
+- __overlay__ {
+- brcm,pins = <32 33>;
+- brcm,function = <2>; /* alt5=UART1 */
+- brcm,pull = <0 2>;
+- };
+- };
+-
+- fragment@4 {
+- target = <&gpio>;
+- __overlay__ {
+- fake_bt_cts: fake_bt_cts {
+- brcm,pins = <31>;
+- brcm,function = <1>; /* output */
+- };
+- };
+- };
+-
+- fragment@5 {
+- target-path = "/aliases";
+- __overlay__ {
+- serial0 = "/soc/serial@7e201000";
+- serial1 = "/soc/serial@7e215040";
+- };
+- };
+-};
++#include "miniuart-bt-overlay.dts"
--- /dev/null
+From 614cade3a68f7214939e1c72acd5fcc9d49beeef Mon Sep 17 00:00:00 2001
+Date: Fri, 21 Jun 2019 03:52:49 -0700
+Subject: [PATCH] i2c: bcm2835: Move IRQ request after clock code in
+ probe
+
+Commit 4a5cfa39465cad25dd736d7ceba8a5d32eea4ecc upstream.
+
+If any of the clock code in the probe fails and returns, the IRQ
+will not be freed. Moving the IRQ request to last allows it to
+be freed on any errors further up in the probe function. devm_
+calls can apparently not be used because there are some potential
+race conditions that will arise.
+
+Fixes: bebff81fb8b9 ("i2c: bcm2835: Model Divider in CCF")
+---
+ drivers/i2c/busses/i2c-bcm2835.c | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-bcm2835.c
++++ b/drivers/i2c/busses/i2c-bcm2835.c
+@@ -521,20 +521,6 @@ static int bcm2835_i2c_probe(struct plat
+ if (IS_ERR(i2c_dev->regs))
+ return PTR_ERR(i2c_dev->regs);
+
+- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+- if (!irq) {
+- dev_err(&pdev->dev, "No IRQ resource\n");
+- return -ENODEV;
+- }
+- i2c_dev->irq = irq->start;
+-
+- ret = request_irq(i2c_dev->irq, bcm2835_i2c_isr, IRQF_SHARED,
+- dev_name(&pdev->dev), i2c_dev);
+- if (ret) {
+- dev_err(&pdev->dev, "Could not request IRQ\n");
+- return -ENODEV;
+- }
+-
+ mclk_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
+
+ bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk_name, i2c_dev);
+@@ -564,6 +550,20 @@ static int bcm2835_i2c_probe(struct plat
+ return ret;
+ }
+
++ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (!irq) {
++ dev_err(&pdev->dev, "No IRQ resource\n");
++ return -ENODEV;
++ }
++ i2c_dev->irq = irq->start;
++
++ ret = request_irq(i2c_dev->irq, bcm2835_i2c_isr, IRQF_SHARED,
++ dev_name(&pdev->dev), i2c_dev);
++ if (ret) {
++ dev_err(&pdev->dev, "Could not request IRQ\n");
++ return -ENODEV;
++ }
++
+ adap = &i2c_dev->adapter;
+ i2c_set_adapdata(adap, i2c_dev);
+ adap->owner = THIS_MODULE;
+++ /dev/null
-From a11b6221e69ba4177ee428e2cb6fb4e4bd68c5f4 Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Jul 2019 09:22:10 +0100
-Subject: [PATCH] overlays: Add real parameters to the rpi-poe overlay
-
-As a result of being loaded by the POE HAT EEPROM, the rpi-poe overlay
-doesn't expose parameters in the usual way; instead it adds them to
-the base Device Tree, and the user is expected to use "dtparam=..."
-to access them.
-
-To make the documentation correct and to protect users who load the
-overlay explicitly, expecting to be able to use the parameters, add
-real parameters to the overlay as well.
-
----
- arch/arm/boot/dts/overlays/rpi-poe-overlay.dts | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts
-@@ -60,4 +60,11 @@
- poe_fan_temp1_hyst = <&trip1>,"hysteresis:0";
- };
- };
-+
-+ __overrides__ {
-+ poe_fan_temp0 = <&trip0>,"temperature:0";
-+ poe_fan_temp0_hyst = <&trip0>,"hysteresis:0";
-+ poe_fan_temp1 = <&trip1>,"temperature:0";
-+ poe_fan_temp1_hyst = <&trip1>,"hysteresis:0";
-+ };
- };
--- /dev/null
+From 1a5122f1756ef4fc5779324ad26b6a04142166b5 Mon Sep 17 00:00:00 2001
+Date: Fri, 21 Jun 2019 03:52:50 -0700
+Subject: [PATCH] i2c: bcm2835: Ensure clock exists when probing
+
+Commit 9de93b04df16b055824e3f1f13fedb90fbcf2e4f upstream.
+
+Probe function fails to recognize that upstream clock actually
+doesn't yet exist because clock driver has not been initialized.
+Actually try to go get the clock and test for its existence
+before trying to set up a downstream clock based upon it.
+
+This fixes a bug that causes the i2c driver not to work with
+monolithic kernels.
+
+Fixes: bebff81fb8b9 ("i2c: bcm2835: Model Divider in CCF")
+---
+ drivers/i2c/busses/i2c-bcm2835.c | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-bcm2835.c
++++ b/drivers/i2c/busses/i2c-bcm2835.c
+@@ -244,15 +244,18 @@ static const struct clk_ops clk_bcm2835_
+ };
+
+ static struct clk *bcm2835_i2c_register_div(struct device *dev,
+- const char *mclk_name,
++ struct clk *mclk,
+ struct bcm2835_i2c_dev *i2c_dev)
+ {
+ struct clk_init_data init;
+ struct clk_bcm2835_i2c *priv;
+ char name[32];
++ const char *mclk_name;
+
+ snprintf(name, sizeof(name), "%s_div", dev_name(dev));
+
++ mclk_name = __clk_get_name(mclk);
++
+ init.ops = &clk_bcm2835_i2c_ops;
+ init.name = name;
+ init.parent_names = (const char* []) { mclk_name };
+@@ -505,8 +508,8 @@ static int bcm2835_i2c_probe(struct plat
+ struct resource *mem, *irq;
+ int ret;
+ struct i2c_adapter *adap;
+- const char *mclk_name;
+ struct clk *bus_clk;
++ struct clk *mclk;
+ u32 bus_clk_rate;
+
+ i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+@@ -521,9 +524,14 @@ static int bcm2835_i2c_probe(struct plat
+ if (IS_ERR(i2c_dev->regs))
+ return PTR_ERR(i2c_dev->regs);
+
+- mclk_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
++ mclk = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(mclk)) {
++ if (PTR_ERR(mclk) != -EPROBE_DEFER)
++ dev_err(&pdev->dev, "Could not get clock\n");
++ return PTR_ERR(mclk);
++ }
+
+- bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk_name, i2c_dev);
++ bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk, i2c_dev);
+
+ if (IS_ERR(bus_clk)) {
+ dev_err(&pdev->dev, "Could not register clock\n");
+++ /dev/null
-From c46811a3b0e0fb76015ac956172e40bce4e6d9b3 Mon Sep 17 00:00:00 2001
-Date: Fri, 5 Jul 2019 14:49:22 +0100
-Subject: [PATCH] overlays: Rename pi3- overlays to be less
- model-specific (#3052)
-
-Rename the various pi3- overlays to be more generic, listing
-the devices they apply to in the README. The original names are
-retained for backwards compatibility as files that just include
-the new versions - the README marks them as being deprecated.
-
-See: https://github.com/raspberrypi/firmware/issues/1174
-
----
- arch/arm/boot/dts/overlays/Makefile | 4 +
- arch/arm/boot/dts/overlays/README | 97 ++++++++++++-------
- .../arm/boot/dts/overlays/act-led-overlay.dts | 27 ++++++
- .../boot/dts/overlays/disable-bt-overlay.dts | 55 +++++++++++
- .../dts/overlays/disable-wifi-overlay.dts | 20 ++++
- .../boot/dts/overlays/miniuart-bt-overlay.dts | 74 ++++++++++++++
- .../boot/dts/overlays/pi3-act-led-overlay.dts | 28 +-----
- .../dts/overlays/pi3-disable-bt-overlay.dts | 56 +----------
- .../dts/overlays/pi3-disable-wifi-overlay.dts | 21 +---
- .../dts/overlays/pi3-miniuart-bt-overlay.dts | 75 +-------------
- 10 files changed, 246 insertions(+), 211 deletions(-)
- create mode 100644 arch/arm/boot/dts/overlays/act-led-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/disable-bt-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/disable-wifi-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/miniuart-bt-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -1,6 +1,7 @@
- # Overlays for the Raspberry Pi platform
-
- dtbo-$(CONFIG_ARCH_BCM2835) += \
-+ act-led.dtbo \
- adau1977-adc.dtbo \
- adau7002-simple.dtbo \
- ads1015.dtbo \
-@@ -26,6 +27,8 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- dht11.dtbo \
- dionaudio-loco.dtbo \
- dionaudio-loco-v2.dtbo \
-+ disable-bt.dtbo \
-+ disable-wifi.dtbo \
- dpi18.dtbo \
- dpi24.dtbo \
- draws.dtbo \
-@@ -91,6 +94,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- media-center.dtbo \
- midi-uart0.dtbo \
- midi-uart1.dtbo \
-+ miniuart-bt.dtbo \
- mmc.dtbo \
- mpu6050.dtbo \
- mz61581.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -180,14 +180,16 @@ Params:
-
- act_led_activelow Set to "on" to invert the sense of the LED
- (default "off")
-- N.B. For Pi3 see pi3-act-led overlay.
-+ N.B. For Pi 3B, 3B+, 3A+ and 4B, use the act-led
-+ overlay.
-
- act_led_gpio Set which GPIO to use for the activity LED
- (in case you want to connect it to an external
- device)
- (default "16" on a non-Plus board, "47" on a
- Plus or Pi 2)
-- N.B. For Pi3 see pi3-act-led overlay.
-+ N.B. For Pi 3B, 3B+, 3A+ and 4B, use the act-led
-+ overlay.
-
- pwr_led_trigger
- pwr_led_activelow
-@@ -205,6 +207,23 @@ Params:
- and the other i2c baudrate parameters.
-
-
-+Name: act-led
-+Info: Pi 3B, 3B+, 3A+ and 4B use a GPIO expander to drive the LEDs which can
-+ only be accessed from the VPU. There is a special driver for this with a
-+ separate DT node, which has the unfortunate consequence of breaking the
-+ act_led_gpio and act_led_activelow dtparams.
-+ This overlay changes the GPIO controller back to the standard one and
-+ restores the dtparams.
-+Load: dtoverlay=act-led,<param>=<val>
-+Params: activelow Set to "on" to invert the sense of the LED
-+ (default "off")
-+
-+ gpio Set which GPIO to use for the activity LED
-+ (in case you want to connect it to an external
-+ device)
-+ REQUIRED
-+
-+
- Name: adau1977-adc
- Info: Overlay for activation of ADAU1977 ADC codec over I2C for control
- and I2S for data.
-@@ -509,6 +528,21 @@ Params: 24db_digital_gain Allow ga
- that does not result in clipping/distortion!)
-
-
-+Name: disable-bt
-+Info: Disable onboard Bluetooth on Pi 3B, 3B+, 3A+, 4B and Zero W, restoring
-+ UART0/ttyAMA0 over GPIOs 14 & 15.
-+ N.B. To disable the systemd service that initialises the modem so it
-+ doesn't use the UART, use 'sudo systemctl disable hciuart'.
-+Load: dtoverlay=disable-bt
-+Params: <None>
-+
-+
-+Name: disable-wifi
-+Info: Disable onboard WiFi on Pi 3B, 3B+, 3A+, 4B and Zero W.
-+Load: dtoverlay=disable-wifi
-+Params: <None>
-+
-+
- Name: dpi18
- Info: Overlay for a generic 18-bit DPI display
- This uses GPIOs 0-21 (so no I2C, uart etc.), and activates the output
-@@ -1447,6 +1481,20 @@ Load: dtoverlay=midi-uart1
- Params: <None>
-
-
-+Name: miniuart-bt
-+Info: Switch the onboard Bluetooth function on Pi 3B, 3B+, 3A+, 4B and Zero W
-+ to use the mini-UART (ttyS0) and restore UART0/ttyAMA0 over GPIOs 14 &
-+ 15. Note that this may reduce the maximum usable baudrate.
-+ N.B. It is also necessary to edit /lib/systemd/system/hciuart.service
-+ and replace ttyAMA0 with ttyS0, unless using Raspbian or another
-+ distribution with udev rules that create /dev/serial0 and /dev/serial1,
-+ in which case use /dev/serial1 instead because it will always be
-+ correct. Furthermore, you must also set core_freq and core_freq_min to
-+ the same value in config.txt or the miniuart will not work.
-+Load: dtoverlay=miniuart-bt
-+Params: <None>
-+
-+
- Name: mmc
- Info: Selects the bcm2835-mmc SD/MMC driver, optionally with overclock
- Load: dtoverlay=mmc,<param>=<val>
-@@ -1509,48 +1557,27 @@ Params: panel Display
-
-
- Name: pi3-act-led
--Info: Pi3 uses a GPIO expander to drive the LEDs which can only be accessed
-- from the VPU. There is a special driver for this with a separate DT
-- node, which has the unfortunate consequence of breaking the
-- act_led_gpio and act_led_activelow dtparams.
-- This overlay changes the GPIO controller back to the standard one and
-- restores the dtparams.
--Load: dtoverlay=pi3-act-led,<param>=<val>
--Params: activelow Set to "on" to invert the sense of the LED
-- (default "off")
--
-- gpio Set which GPIO to use for the activity LED
-- (in case you want to connect it to an external
-- device)
-- REQUIRED
-+Info: This overlay has been renamed act-led, keeping pi3-act-led as an alias
-+ for backwards compatibility.
-+Load: <Deprecated>
-
-
- Name: pi3-disable-bt
--Info: Disable Pi3 Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15
-- N.B. To disable the systemd service that initialises the modem so it
-- doesn't use the UART, use 'sudo systemctl disable hciuart'.
--Load: dtoverlay=pi3-disable-bt
--Params: <None>
-+Info: This overlay has been renamed disable-bt, keeping pi3-disable-bt as an
-+ alias for backwards compatibility.
-+Load: <Deprecated>
-
-
- Name: pi3-disable-wifi
--Info: Disable Pi3 onboard WiFi
--Load: dtoverlay=pi3-disable-wifi
--Params: <None>
-+Info: This overlay has been renamed disable-wifi, keeping pi3-disable-wifi as
-+ an alias for backwards compatibility.
-+Load: <Deprecated>
-
-
- Name: pi3-miniuart-bt
--Info: Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
-- UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
-- usable baudrate.
-- N.B. It is also necessary to edit /lib/systemd/system/hciuart.service
-- and replace ttyAMA0 with ttyS0, unless you have a system with udev rules
-- that create /dev/serial0 and /dev/serial1, in which case use
-- /dev/serial1 instead because it will always be correct. Furthermore,
-- you must also set core_freq=250 in config.txt or the miniuart will not
-- work.
--Load: dtoverlay=pi3-miniuart-bt
--Params: <None>
-+Info: This overlay has been renamed miniuart-bt, keeping pi3-miniuart-bt as
-+ an alias for backwards compatibility.
-+Load: <Deprecated>
-
-
- Name: pibell
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/act-led-overlay.dts
-@@ -0,0 +1,27 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/* Pi3 uses a GPIO expander to drive the LEDs which can only be accessed
-+ from the VPU. There is a special driver for this with a separate DT node,
-+ which has the unfortunate consequence of breaking the act_led_gpio and
-+ act_led_activelow dtparams.
-+
-+ This overlay changes the GPIO controller back to the standard one and
-+ restores the dtparams.
-+*/
-+
-+/{
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&act_led>;
-+ frag0: __overlay__ {
-+ gpios = <&gpio 0 0>;
-+ };
-+ };
-+
-+ __overrides__ {
-+ gpio = <&frag0>,"gpios:4";
-+ activelow = <&frag0>,"gpios:8";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/disable-bt-overlay.dts
-@@ -0,0 +1,55 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/* Disable Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15.
-+ To disable the systemd service that initialises the modem so it doesn't use
-+ the UART:
-+
-+ sudo systemctl disable hciuart
-+*/
-+
-+/{
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&uart1>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&uart0>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart0_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&uart0_pins>;
-+ __overlay__ {
-+ brcm,pins;
-+ brcm,function;
-+ brcm,pull;
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&bt_pins>;
-+ __overlay__ {
-+ brcm,pins;
-+ brcm,function;
-+ brcm,pull;
-+ };
-+ };
-+
-+ fragment@4 {
-+ target-path = "/aliases";
-+ __overlay__ {
-+ serial0 = "/soc/serial@7e201000";
-+ serial1 = "/soc/serial@7e215040";
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/disable-wifi-overlay.dts
-@@ -0,0 +1,20 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&mmc>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&mmcnr>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/miniuart-bt-overlay.dts
-@@ -0,0 +1,74 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/* Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
-+ UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
-+ usable baudrate.
-+
-+ It is also necessary to edit /lib/systemd/system/hciuart.service and
-+ replace ttyAMA0 with ttyS0, unless you have a system with udev rules
-+ that create /dev/serial0 and /dev/serial1, in which case use /dev/serial1
-+ instead because it will always be correct.
-+
-+ If cmdline.txt uses the alias serial0 to refer to the user-accessable port
-+ then the firmware will replace with the appropriate port whether or not
-+ this overlay is used.
-+*/
-+
-+/{
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&uart0>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart0_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&uart1>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart1_pins &bt_pins &fake_bt_cts>;
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&uart0_pins>;
-+ __overlay__ {
-+ brcm,pins;
-+ brcm,function;
-+ brcm,pull;
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&uart1_pins>;
-+ __overlay__ {
-+ brcm,pins = <32 33>;
-+ brcm,function = <2>; /* alt5=UART1 */
-+ brcm,pull = <0 2>;
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ fake_bt_cts: fake_bt_cts {
-+ brcm,pins = <31>;
-+ brcm,function = <1>; /* output */
-+ };
-+ };
-+ };
-+
-+ fragment@5 {
-+ target-path = "/aliases";
-+ __overlay__ {
-+ serial0 = "/soc/serial@7e201000";
-+ serial1 = "/soc/serial@7e215040";
-+ };
-+ };
-+};
---- a/arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts
-@@ -1,27 +1 @@
--/dts-v1/;
--/plugin/;
--
--/* Pi3 uses a GPIO expander to drive the LEDs which can only be accessed
-- from the VPU. There is a special driver for this with a separate DT node,
-- which has the unfortunate consequence of breaking the act_led_gpio and
-- act_led_activelow dtparams.
--
-- This overlay changes the GPIO controller back to the standard one and
-- restores the dtparams.
--*/
--
--/{
-- compatible = "brcm,bcm2835";
--
-- fragment@0 {
-- target = <&act_led>;
-- frag0: __overlay__ {
-- gpios = <&gpio 0 0>;
-- };
-- };
--
-- __overrides__ {
-- gpio = <&frag0>,"gpios:4";
-- activelow = <&frag0>,"gpios:8";
-- };
--};
-+#include "act-led-overlay.dts"
---- a/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts
-@@ -1,55 +1 @@
--/dts-v1/;
--/plugin/;
--
--/* Disable Bluetooth and restore UART0/ttyAMA0 over GPIOs 14 & 15.
-- To disable the systemd service that initialises the modem so it doesn't use
-- the UART:
--
-- sudo systemctl disable hciuart
--*/
--
--/{
-- compatible = "brcm,bcm2835";
--
-- fragment@0 {
-- target = <&uart1>;
-- __overlay__ {
-- status = "disabled";
-- };
-- };
--
-- fragment@1 {
-- target = <&uart0>;
-- __overlay__ {
-- pinctrl-names = "default";
-- pinctrl-0 = <&uart0_pins>;
-- status = "okay";
-- };
-- };
--
-- fragment@2 {
-- target = <&uart0_pins>;
-- __overlay__ {
-- brcm,pins;
-- brcm,function;
-- brcm,pull;
-- };
-- };
--
-- fragment@3 {
-- target = <&bt_pins>;
-- __overlay__ {
-- brcm,pins;
-- brcm,function;
-- brcm,pull;
-- };
-- };
--
-- fragment@4 {
-- target-path = "/aliases";
-- __overlay__ {
-- serial0 = "/soc/serial@7e201000";
-- serial1 = "/soc/serial@7e215040";
-- };
-- };
--};
-+#include "disable-bt-overlay.dts"
---- a/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts
-@@ -1,20 +1 @@
--/dts-v1/;
--/plugin/;
--
--/{
-- compatible = "brcm,bcm2835";
--
-- fragment@0 {
-- target = <&mmc>;
-- __overlay__ {
-- status = "disabled";
-- };
-- };
--
-- fragment@1 {
-- target = <&mmcnr>;
-- __overlay__ {
-- status = "disabled";
-- };
-- };
--};
-+#include "disable-wifi-overlay.dts"
---- a/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts
-@@ -1,74 +1 @@
--/dts-v1/;
--/plugin/;
--
--/* Switch Pi3 Bluetooth function to use the mini-UART (ttyS0) and restore
-- UART0/ttyAMA0 over GPIOs 14 & 15. Note that this may reduce the maximum
-- usable baudrate.
--
-- It is also necessary to edit /lib/systemd/system/hciuart.service and
-- replace ttyAMA0 with ttyS0, unless you have a system with udev rules
-- that create /dev/serial0 and /dev/serial1, in which case use /dev/serial1
-- instead because it will always be correct.
--
-- If cmdline.txt uses the alias serial0 to refer to the user-accessable port
-- then the firmware will replace with the appropriate port whether or not
-- this overlay is used.
--*/
--
--/{
-- compatible = "brcm,bcm2835";
--
-- fragment@0 {
-- target = <&uart0>;
-- __overlay__ {
-- pinctrl-names = "default";
-- pinctrl-0 = <&uart0_pins>;
-- status = "okay";
-- };
-- };
--
-- fragment@1 {
-- target = <&uart1>;
-- __overlay__ {
-- pinctrl-names = "default";
-- pinctrl-0 = <&uart1_pins &bt_pins &fake_bt_cts>;
-- status = "okay";
-- };
-- };
--
-- fragment@2 {
-- target = <&uart0_pins>;
-- __overlay__ {
-- brcm,pins;
-- brcm,function;
-- brcm,pull;
-- };
-- };
--
-- fragment@3 {
-- target = <&uart1_pins>;
-- __overlay__ {
-- brcm,pins = <32 33>;
-- brcm,function = <2>; /* alt5=UART1 */
-- brcm,pull = <0 2>;
-- };
-- };
--
-- fragment@4 {
-- target = <&gpio>;
-- __overlay__ {
-- fake_bt_cts: fake_bt_cts {
-- brcm,pins = <31>;
-- brcm,function = <1>; /* output */
-- };
-- };
-- };
--
-- fragment@5 {
-- target-path = "/aliases";
-- __overlay__ {
-- serial0 = "/soc/serial@7e201000";
-- serial1 = "/soc/serial@7e215040";
-- };
-- };
--};
-+#include "miniuart-bt-overlay.dts"
+++ /dev/null
-From 614cade3a68f7214939e1c72acd5fcc9d49beeef Mon Sep 17 00:00:00 2001
-Date: Fri, 21 Jun 2019 03:52:49 -0700
-Subject: [PATCH] i2c: bcm2835: Move IRQ request after clock code in
- probe
-
-Commit 4a5cfa39465cad25dd736d7ceba8a5d32eea4ecc upstream.
-
-If any of the clock code in the probe fails and returns, the IRQ
-will not be freed. Moving the IRQ request to last allows it to
-be freed on any errors further up in the probe function. devm_
-calls can apparently not be used because there are some potential
-race conditions that will arise.
-
-Fixes: bebff81fb8b9 ("i2c: bcm2835: Model Divider in CCF")
----
- drivers/i2c/busses/i2c-bcm2835.c | 28 ++++++++++++++--------------
- 1 file changed, 14 insertions(+), 14 deletions(-)
-
---- a/drivers/i2c/busses/i2c-bcm2835.c
-+++ b/drivers/i2c/busses/i2c-bcm2835.c
-@@ -521,20 +521,6 @@ static int bcm2835_i2c_probe(struct plat
- if (IS_ERR(i2c_dev->regs))
- return PTR_ERR(i2c_dev->regs);
-
-- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-- if (!irq) {
-- dev_err(&pdev->dev, "No IRQ resource\n");
-- return -ENODEV;
-- }
-- i2c_dev->irq = irq->start;
--
-- ret = request_irq(i2c_dev->irq, bcm2835_i2c_isr, IRQF_SHARED,
-- dev_name(&pdev->dev), i2c_dev);
-- if (ret) {
-- dev_err(&pdev->dev, "Could not request IRQ\n");
-- return -ENODEV;
-- }
--
- mclk_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
-
- bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk_name, i2c_dev);
-@@ -564,6 +550,20 @@ static int bcm2835_i2c_probe(struct plat
- return ret;
- }
-
-+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-+ if (!irq) {
-+ dev_err(&pdev->dev, "No IRQ resource\n");
-+ return -ENODEV;
-+ }
-+ i2c_dev->irq = irq->start;
-+
-+ ret = request_irq(i2c_dev->irq, bcm2835_i2c_isr, IRQF_SHARED,
-+ dev_name(&pdev->dev), i2c_dev);
-+ if (ret) {
-+ dev_err(&pdev->dev, "Could not request IRQ\n");
-+ return -ENODEV;
-+ }
-+
- adap = &i2c_dev->adapter;
- i2c_set_adapdata(adap, i2c_dev);
- adap->owner = THIS_MODULE;
--- /dev/null
+From d562b2187263b40aacc1a50d3f25db2cf28696d6 Mon Sep 17 00:00:00 2001
+Date: Tue, 9 Jul 2019 10:32:40 +0100
+Subject: [PATCH] overlays: i2c-gpio: Fix the "bus" parameter
+
+The "bus" parameter has two functions - providing unique names for
+multiple instances of the overlay, and allowing the number of the bus
+(i.e. "i2c-<bus>") to be specified. The second function hasn't worked
+as intended because the overlay doesn't include a "reg" property and
+the firmware intentionally won't create a "reg" property if one doesn't
+already exist.
+
+Allow the bus numbering scheme to work as intended by providing a "reg"
+with a default value that means "the next available one".
+
+See: https://github.com/raspberrypi/linux/issues/3062
+
+---
+ arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
+@@ -7,8 +7,10 @@
+
+ fragment@0 {
+ target-path = "/";
++
+ __overlay__ {
+ i2c_gpio: i2c@0 {
++ reg = <0xffffffff>;
+ compatible = "i2c-gpio";
+ gpios = <&gpio 23 0 /* sda */
+ &gpio 24 0 /* scl */
+++ /dev/null
-From 1a5122f1756ef4fc5779324ad26b6a04142166b5 Mon Sep 17 00:00:00 2001
-Date: Fri, 21 Jun 2019 03:52:50 -0700
-Subject: [PATCH] i2c: bcm2835: Ensure clock exists when probing
-
-Commit 9de93b04df16b055824e3f1f13fedb90fbcf2e4f upstream.
-
-Probe function fails to recognize that upstream clock actually
-doesn't yet exist because clock driver has not been initialized.
-Actually try to go get the clock and test for its existence
-before trying to set up a downstream clock based upon it.
-
-This fixes a bug that causes the i2c driver not to work with
-monolithic kernels.
-
-Fixes: bebff81fb8b9 ("i2c: bcm2835: Model Divider in CCF")
----
- drivers/i2c/busses/i2c-bcm2835.c | 16 ++++++++++++----
- 1 file changed, 12 insertions(+), 4 deletions(-)
-
---- a/drivers/i2c/busses/i2c-bcm2835.c
-+++ b/drivers/i2c/busses/i2c-bcm2835.c
-@@ -244,15 +244,18 @@ static const struct clk_ops clk_bcm2835_
- };
-
- static struct clk *bcm2835_i2c_register_div(struct device *dev,
-- const char *mclk_name,
-+ struct clk *mclk,
- struct bcm2835_i2c_dev *i2c_dev)
- {
- struct clk_init_data init;
- struct clk_bcm2835_i2c *priv;
- char name[32];
-+ const char *mclk_name;
-
- snprintf(name, sizeof(name), "%s_div", dev_name(dev));
-
-+ mclk_name = __clk_get_name(mclk);
-+
- init.ops = &clk_bcm2835_i2c_ops;
- init.name = name;
- init.parent_names = (const char* []) { mclk_name };
-@@ -505,8 +508,8 @@ static int bcm2835_i2c_probe(struct plat
- struct resource *mem, *irq;
- int ret;
- struct i2c_adapter *adap;
-- const char *mclk_name;
- struct clk *bus_clk;
-+ struct clk *mclk;
- u32 bus_clk_rate;
-
- i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-@@ -521,9 +524,14 @@ static int bcm2835_i2c_probe(struct plat
- if (IS_ERR(i2c_dev->regs))
- return PTR_ERR(i2c_dev->regs);
-
-- mclk_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
-+ mclk = devm_clk_get(&pdev->dev, NULL);
-+ if (IS_ERR(mclk)) {
-+ if (PTR_ERR(mclk) != -EPROBE_DEFER)
-+ dev_err(&pdev->dev, "Could not get clock\n");
-+ return PTR_ERR(mclk);
-+ }
-
-- bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk_name, i2c_dev);
-+ bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk, i2c_dev);
-
- if (IS_ERR(bus_clk)) {
- dev_err(&pdev->dev, "Could not register clock\n");
--- /dev/null
+From 3e3c13488e4efa0236c47a98ee5e759bf1f7c757 Mon Sep 17 00:00:00 2001
+Date: Thu, 11 Jul 2019 13:13:39 +0100
+Subject: [PATCH] tty: amba-pl011: Make TX optimisation conditional
+
+pl011_tx_chars takes a "from_irq" parameter to reduce the number of
+register accesses. When from_irq is true the function assumes that the
+FIFO is half empty and writes up to half a FIFO's worth of bytes
+without polling the FIFO status register, the reasoning being that
+the function is being called as a result of the TX interrupt being
+raised. This logic would work were it not for the fact that
+pl011_rx_chars, called from pl011_int before pl011_tx_chars, releases
+the spinlock before calling tty_flip_buffer_push.
+
+A user thread writing to the UART claims the spinlock and ultimately
+calls pl011_tx_chars with from_irq set to false. This reverts to the
+older logic that polls the FIFO status register before sending every
+byte. If this happen on an SMP system during the section of the IRQ
+handler where the spinlock has been released, then by the time the TX
+interrupt handler is called, the FIFO may already be full, and any
+further writes are likely to be lost.
+
+The fix involves adding a per-port flag that is true iff running from
+within the interrupt handler and the spinlock has not yet been released.
+This flag is then used as the value for the from_irq parameter of
+pl011_tx_chars, causing polling to be used in the unsafe case.
+
+Fixes: 1e84d22322ce ("serial/amba-pl011: Refactor and simplify TX FIFO handling")
+
+---
+ drivers/tty/serial/amba-pl011.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -270,6 +270,7 @@ struct uart_amba_port {
+ unsigned int old_cr; /* state during shutdown */
+ unsigned int fixed_baud; /* vendor-set fixed baud rate */
+ char type[12];
++ bool irq_locked; /* in irq, unreleased lock */
+ #ifdef CONFIG_DMA_ENGINE
+ /* DMA stuff */
+ bool using_tx_dma;
+@@ -813,6 +814,7 @@ __acquires(&uap->port.lock)
+ if (!uap->using_tx_dma)
+ return;
+
++ uap->irq_locked = 0;
+ dmaengine_terminate_async(uap->dmatx.chan);
+
+ if (uap->dmatx.queued) {
+@@ -939,6 +941,7 @@ static void pl011_dma_rx_chars(struct ua
+ fifotaken = pl011_fifo_to_tty(uap);
+ }
+
++ uap->irq_locked = 0;
+ spin_unlock(&uap->port.lock);
+ dev_vdbg(uap->port.dev,
+ "Took %d chars from DMA buffer and %d chars from the FIFO\n",
+@@ -1347,6 +1350,7 @@ __acquires(&uap->port.lock)
+ {
+ pl011_fifo_to_tty(uap);
+
++ uap->irq_locked = 0;
+ spin_unlock(&uap->port.lock);
+ tty_flip_buffer_push(&uap->port.state->port);
+ /*
+@@ -1482,6 +1486,7 @@ static irqreturn_t pl011_int(int irq, vo
+ int handled = 0;
+
+ spin_lock_irqsave(&uap->port.lock, flags);
++ uap->irq_locked = 1;
+ status = pl011_read(uap, REG_RIS) & uap->im;
+ if (status) {
+ do {
+@@ -1501,7 +1506,7 @@ static irqreturn_t pl011_int(int irq, vo
+ UART011_CTSMIS|UART011_RIMIS))
+ pl011_modem_status(uap);
+ if (status & UART011_TXIS)
+- pl011_tx_chars(uap, true);
++ pl011_tx_chars(uap, uap->irq_locked);
+
+ if (pass_counter-- == 0)
+ break;
+++ /dev/null
-From d562b2187263b40aacc1a50d3f25db2cf28696d6 Mon Sep 17 00:00:00 2001
-Date: Tue, 9 Jul 2019 10:32:40 +0100
-Subject: [PATCH] overlays: i2c-gpio: Fix the "bus" parameter
-
-The "bus" parameter has two functions - providing unique names for
-multiple instances of the overlay, and allowing the number of the bus
-(i.e. "i2c-<bus>") to be specified. The second function hasn't worked
-as intended because the overlay doesn't include a "reg" property and
-the firmware intentionally won't create a "reg" property if one doesn't
-already exist.
-
-Allow the bus numbering scheme to work as intended by providing a "reg"
-with a default value that means "the next available one".
-
-See: https://github.com/raspberrypi/linux/issues/3062
-
----
- arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
-@@ -7,8 +7,10 @@
-
- fragment@0 {
- target-path = "/";
-+
- __overlay__ {
- i2c_gpio: i2c@0 {
-+ reg = <0xffffffff>;
- compatible = "i2c-gpio";
- gpios = <&gpio 23 0 /* sda */
- &gpio 24 0 /* scl */
--- /dev/null
+From 705bc230789927f96d6c9c70dc5475ebaf08aa54 Mon Sep 17 00:00:00 2001
+Date: Thu, 11 Jul 2019 17:55:43 +0100
+Subject: [PATCH] xhci: add quirk for host controllers that don't
+ update endpoint DCS
+
+Seen on a VLI VL805 PCIe to USB controller. For non-stream endpoints
+at least, if the xHC halts on a particular TRB due to an error then
+the DCS field in the Out Endpoint Context maintained by the hardware
+is not updated with the current cycle state.
+
+Using the quirk XHCI_EP_CTX_BROKEN_DCS and instead fetch the DCS bit
+from the TRB that the xHC stopped on.
+
+See: https://github.com/raspberrypi/linux/issues/3060
+
+---
+ drivers/usb/host/xhci-pci.c | 4 +++-
+ drivers/usb/host/xhci-ring.c | 26 +++++++++++++++++++++++++-
+ drivers/usb/host/xhci.h | 1 +
+ 3 files changed, 29 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -223,8 +223,10 @@ static void xhci_pci_quirks(struct devic
+ xhci->quirks |= XHCI_BROKEN_STREAMS;
+
+ if (pdev->vendor == PCI_VENDOR_ID_VIA &&
+- pdev->device == 0x3483)
++ pdev->device == 0x3483) {
+ xhci->quirks |= XHCI_LPM_SUPPORT;
++ xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS;
++ }
+
+ if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+ pdev->device == 0x1042)
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -520,7 +520,10 @@ void xhci_find_new_dequeue_state(struct
+ struct xhci_virt_ep *ep = &dev->eps[ep_index];
+ struct xhci_ring *ep_ring;
+ struct xhci_segment *new_seg;
++ struct xhci_segment *halted_seg = NULL;
+ union xhci_trb *new_deq;
++ union xhci_trb *halted_trb;
++ int index = 0;
+ dma_addr_t addr;
+ u64 hw_dequeue;
+ bool cycle_found = false;
+@@ -541,7 +544,28 @@ void xhci_find_new_dequeue_state(struct
+ hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id);
+ new_seg = ep_ring->deq_seg;
+ new_deq = ep_ring->dequeue;
+- state->new_cycle_state = hw_dequeue & 0x1;
++
++ /*
++ * Quirk: xHC write-back of the DCS field in the hardware dequeue
++ * pointer is wrong - use the cycle state of the TRB pointed to by
++ * the dequeue pointer.
++ */
++ if (xhci->quirks & XHCI_EP_CTX_BROKEN_DCS &&
++ !(ep->ep_state & EP_HAS_STREAMS))
++ halted_seg = trb_in_td(xhci, cur_td->start_seg,
++ cur_td->first_trb, cur_td->last_trb,
++ hw_dequeue & ~0xf, false);
++ if (halted_seg) {
++ index = ((dma_addr_t)(hw_dequeue & ~0xf) - halted_seg->dma) /
++ sizeof(*halted_trb);
++ halted_trb = &halted_seg->trbs[index];
++ state->new_cycle_state = halted_trb->generic.field[3] & 0x1;
++ xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n",
++ (u8)(hw_dequeue & 0x1), index,
++ state->new_cycle_state);
++ } else {
++ state->new_cycle_state = hw_dequeue & 0x1;
++ }
+ state->stream_id = stream_id;
+
+ /*
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1865,6 +1865,7 @@ struct xhci_hcd {
+ #define XHCI_ZERO_64B_REGS BIT_ULL(32)
+ #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
+ #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
++#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(36)
+
+ unsigned int num_active_eps;
+ unsigned int limit_active_eps;
--- /dev/null
+From 8d453e2193951057db696e37b9c10e7e35c18cb0 Mon Sep 17 00:00:00 2001
+Date: Fri, 12 Jul 2019 15:38:35 +0100
+Subject: [PATCH] i2c: bcm2835: Set clock-stretch timeout to 35ms
+
+The BCM2835 I2C blocks have a register to set the clock-stretch
+timeout - how long the device is allowed to hold SCL low - in bus
+cycles. The current driver doesn't write to the register, therefore
+the default value of 64 cycles is being used for all devices.
+
+Set the timeout to the value recommended for SMBus - 35ms.
+
+See: https://github.com/raspberrypi/linux/issues/3064
+
+---
+ drivers/i2c/busses/i2c-bcm2835.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/i2c/busses/i2c-bcm2835.c
++++ b/drivers/i2c/busses/i2c-bcm2835.c
+@@ -194,6 +194,7 @@ static int clk_bcm2835_i2c_set_rate(stru
+ {
+ struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
+ u32 redl, fedl;
++ u32 clk_tout;
+ u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate);
+
+ if (divider == -EINVAL)
+@@ -217,6 +218,17 @@ static int clk_bcm2835_i2c_set_rate(stru
+ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL,
+ (fedl << BCM2835_I2C_FEDL_SHIFT) |
+ (redl << BCM2835_I2C_REDL_SHIFT));
++
++ /*
++ * Set the clock stretch timeout to the SMBUs-recommended 35ms.
++ */
++ if (rate > 0xffff*1000/35)
++ clk_tout = 0xffff;
++ else
++ clk_tout = 35*rate/1000;
++
++ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_CLKT, clk_tout);
++
+ return 0;
+ }
+
+++ /dev/null
-From 3e3c13488e4efa0236c47a98ee5e759bf1f7c757 Mon Sep 17 00:00:00 2001
-Date: Thu, 11 Jul 2019 13:13:39 +0100
-Subject: [PATCH] tty: amba-pl011: Make TX optimisation conditional
-
-pl011_tx_chars takes a "from_irq" parameter to reduce the number of
-register accesses. When from_irq is true the function assumes that the
-FIFO is half empty and writes up to half a FIFO's worth of bytes
-without polling the FIFO status register, the reasoning being that
-the function is being called as a result of the TX interrupt being
-raised. This logic would work were it not for the fact that
-pl011_rx_chars, called from pl011_int before pl011_tx_chars, releases
-the spinlock before calling tty_flip_buffer_push.
-
-A user thread writing to the UART claims the spinlock and ultimately
-calls pl011_tx_chars with from_irq set to false. This reverts to the
-older logic that polls the FIFO status register before sending every
-byte. If this happen on an SMP system during the section of the IRQ
-handler where the spinlock has been released, then by the time the TX
-interrupt handler is called, the FIFO may already be full, and any
-further writes are likely to be lost.
-
-The fix involves adding a per-port flag that is true iff running from
-within the interrupt handler and the spinlock has not yet been released.
-This flag is then used as the value for the from_irq parameter of
-pl011_tx_chars, causing polling to be used in the unsafe case.
-
-Fixes: 1e84d22322ce ("serial/amba-pl011: Refactor and simplify TX FIFO handling")
-
----
- drivers/tty/serial/amba-pl011.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
---- a/drivers/tty/serial/amba-pl011.c
-+++ b/drivers/tty/serial/amba-pl011.c
-@@ -270,6 +270,7 @@ struct uart_amba_port {
- unsigned int old_cr; /* state during shutdown */
- unsigned int fixed_baud; /* vendor-set fixed baud rate */
- char type[12];
-+ bool irq_locked; /* in irq, unreleased lock */
- #ifdef CONFIG_DMA_ENGINE
- /* DMA stuff */
- bool using_tx_dma;
-@@ -813,6 +814,7 @@ __acquires(&uap->port.lock)
- if (!uap->using_tx_dma)
- return;
-
-+ uap->irq_locked = 0;
- dmaengine_terminate_async(uap->dmatx.chan);
-
- if (uap->dmatx.queued) {
-@@ -939,6 +941,7 @@ static void pl011_dma_rx_chars(struct ua
- fifotaken = pl011_fifo_to_tty(uap);
- }
-
-+ uap->irq_locked = 0;
- spin_unlock(&uap->port.lock);
- dev_vdbg(uap->port.dev,
- "Took %d chars from DMA buffer and %d chars from the FIFO\n",
-@@ -1347,6 +1350,7 @@ __acquires(&uap->port.lock)
- {
- pl011_fifo_to_tty(uap);
-
-+ uap->irq_locked = 0;
- spin_unlock(&uap->port.lock);
- tty_flip_buffer_push(&uap->port.state->port);
- /*
-@@ -1482,6 +1486,7 @@ static irqreturn_t pl011_int(int irq, vo
- int handled = 0;
-
- spin_lock_irqsave(&uap->port.lock, flags);
-+ uap->irq_locked = 1;
- status = pl011_read(uap, REG_RIS) & uap->im;
- if (status) {
- do {
-@@ -1501,7 +1506,7 @@ static irqreturn_t pl011_int(int irq, vo
- UART011_CTSMIS|UART011_RIMIS))
- pl011_modem_status(uap);
- if (status & UART011_TXIS)
-- pl011_tx_chars(uap, true);
-+ pl011_tx_chars(uap, uap->irq_locked);
-
- if (pass_counter-- == 0)
- break;
--- /dev/null
+From 39964e4a3a2ea18b48be5c31d7980895f0bdd99c Mon Sep 17 00:00:00 2001
+Date: Fri, 8 Mar 2019 13:02:16 -0800
+Subject: [PATCH] arm64: bcm2835: Add missing dependency on MFD_CORE.
+
+commit 7a9b6be9fe58194d9a349159176e8cc0d8f10ef8 upstream.
+
+When adding the MFD dependency for power domains and WDT in bcm2835, I
+added it only on the arm32 side and missed it for arm64.
+
+Fixes: 5e6acc3e678e ("bcm2835-pm: Move bcm2835-watchdog's DT probe to an MFD.")
+---
+ arch/arm64/Kconfig.platforms | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm64/Kconfig.platforms
++++ b/arch/arm64/Kconfig.platforms
+@@ -20,6 +20,7 @@ config ARCH_BCM2835
+ bool "Broadcom BCM2835 family"
+ select TIMER_OF
+ select GPIOLIB
++ select MFD_CORE
+ select PINCTRL
+ select PINCTRL_BCM2835
+ select ARM_AMBA
+++ /dev/null
-From 705bc230789927f96d6c9c70dc5475ebaf08aa54 Mon Sep 17 00:00:00 2001
-Date: Thu, 11 Jul 2019 17:55:43 +0100
-Subject: [PATCH] xhci: add quirk for host controllers that don't
- update endpoint DCS
-
-Seen on a VLI VL805 PCIe to USB controller. For non-stream endpoints
-at least, if the xHC halts on a particular TRB due to an error then
-the DCS field in the Out Endpoint Context maintained by the hardware
-is not updated with the current cycle state.
-
-Using the quirk XHCI_EP_CTX_BROKEN_DCS and instead fetch the DCS bit
-from the TRB that the xHC stopped on.
-
-See: https://github.com/raspberrypi/linux/issues/3060
-
----
- drivers/usb/host/xhci-pci.c | 4 +++-
- drivers/usb/host/xhci-ring.c | 26 +++++++++++++++++++++++++-
- drivers/usb/host/xhci.h | 1 +
- 3 files changed, 29 insertions(+), 2 deletions(-)
-
---- a/drivers/usb/host/xhci-pci.c
-+++ b/drivers/usb/host/xhci-pci.c
-@@ -223,8 +223,10 @@ static void xhci_pci_quirks(struct devic
- xhci->quirks |= XHCI_BROKEN_STREAMS;
-
- if (pdev->vendor == PCI_VENDOR_ID_VIA &&
-- pdev->device == 0x3483)
-+ pdev->device == 0x3483) {
- xhci->quirks |= XHCI_LPM_SUPPORT;
-+ xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS;
-+ }
-
- if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
- pdev->device == 0x1042)
---- a/drivers/usb/host/xhci-ring.c
-+++ b/drivers/usb/host/xhci-ring.c
-@@ -520,7 +520,10 @@ void xhci_find_new_dequeue_state(struct
- struct xhci_virt_ep *ep = &dev->eps[ep_index];
- struct xhci_ring *ep_ring;
- struct xhci_segment *new_seg;
-+ struct xhci_segment *halted_seg = NULL;
- union xhci_trb *new_deq;
-+ union xhci_trb *halted_trb;
-+ int index = 0;
- dma_addr_t addr;
- u64 hw_dequeue;
- bool cycle_found = false;
-@@ -541,7 +544,28 @@ void xhci_find_new_dequeue_state(struct
- hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id);
- new_seg = ep_ring->deq_seg;
- new_deq = ep_ring->dequeue;
-- state->new_cycle_state = hw_dequeue & 0x1;
-+
-+ /*
-+ * Quirk: xHC write-back of the DCS field in the hardware dequeue
-+ * pointer is wrong - use the cycle state of the TRB pointed to by
-+ * the dequeue pointer.
-+ */
-+ if (xhci->quirks & XHCI_EP_CTX_BROKEN_DCS &&
-+ !(ep->ep_state & EP_HAS_STREAMS))
-+ halted_seg = trb_in_td(xhci, cur_td->start_seg,
-+ cur_td->first_trb, cur_td->last_trb,
-+ hw_dequeue & ~0xf, false);
-+ if (halted_seg) {
-+ index = ((dma_addr_t)(hw_dequeue & ~0xf) - halted_seg->dma) /
-+ sizeof(*halted_trb);
-+ halted_trb = &halted_seg->trbs[index];
-+ state->new_cycle_state = halted_trb->generic.field[3] & 0x1;
-+ xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n",
-+ (u8)(hw_dequeue & 0x1), index,
-+ state->new_cycle_state);
-+ } else {
-+ state->new_cycle_state = hw_dequeue & 0x1;
-+ }
- state->stream_id = stream_id;
-
- /*
---- a/drivers/usb/host/xhci.h
-+++ b/drivers/usb/host/xhci.h
-@@ -1865,6 +1865,7 @@ struct xhci_hcd {
- #define XHCI_ZERO_64B_REGS BIT_ULL(32)
- #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
- #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
-+#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(36)
-
- unsigned int num_active_eps;
- unsigned int limit_active_eps;
+++ /dev/null
-From 8d453e2193951057db696e37b9c10e7e35c18cb0 Mon Sep 17 00:00:00 2001
-Date: Fri, 12 Jul 2019 15:38:35 +0100
-Subject: [PATCH] i2c: bcm2835: Set clock-stretch timeout to 35ms
-
-The BCM2835 I2C blocks have a register to set the clock-stretch
-timeout - how long the device is allowed to hold SCL low - in bus
-cycles. The current driver doesn't write to the register, therefore
-the default value of 64 cycles is being used for all devices.
-
-Set the timeout to the value recommended for SMBus - 35ms.
-
-See: https://github.com/raspberrypi/linux/issues/3064
-
----
- drivers/i2c/busses/i2c-bcm2835.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/drivers/i2c/busses/i2c-bcm2835.c
-+++ b/drivers/i2c/busses/i2c-bcm2835.c
-@@ -194,6 +194,7 @@ static int clk_bcm2835_i2c_set_rate(stru
- {
- struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
- u32 redl, fedl;
-+ u32 clk_tout;
- u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate);
-
- if (divider == -EINVAL)
-@@ -217,6 +218,17 @@ static int clk_bcm2835_i2c_set_rate(stru
- bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL,
- (fedl << BCM2835_I2C_FEDL_SHIFT) |
- (redl << BCM2835_I2C_REDL_SHIFT));
-+
-+ /*
-+ * Set the clock stretch timeout to the SMBUs-recommended 35ms.
-+ */
-+ if (rate > 0xffff*1000/35)
-+ clk_tout = 0xffff;
-+ else
-+ clk_tout = 35*rate/1000;
-+
-+ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_CLKT, clk_tout);
-+
- return 0;
- }
-
--- /dev/null
+From 2308f60bb68de69306c542de3983be0007cad37b Mon Sep 17 00:00:00 2001
+Date: Mon, 15 Jul 2019 10:39:05 +0100
+Subject: [PATCH] overlays: Add PCF2129 RTC
+
+Add support for the PCF2129 RTC to i2c-rtc and i2c-rtc-gpio overlays.
+Also add rv3028 to i2c-rtc-gpio (it was missed previously), and don't
+attempt to set an alternate address for the PCF2127.
+
+---
+ arch/arm/boot/dts/overlays/README | 11 ++++-
+ .../dts/overlays/i2c-rtc-gpio-overlay.dts | 41 +++++++++++++++++--
+ .../arm/boot/dts/overlays/i2c-rtc-overlay.dts | 19 ++++++++-
+ 3 files changed, 64 insertions(+), 7 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1022,6 +1022,8 @@ Params: abx80x Select o
+
+ pcf2127 Select the PCF2127 device
+
++ pcf2129 Select the PCF2129 device
++
+ pcf8523 Select the PCF8523 device
+
+ pcf8563 Select the PCF8563 device
+@@ -1067,10 +1069,14 @@ Params: abx80x Select o
+
+ pcf2127 Select the PCF2127 device
+
++ pcf2129 Select the PCF2129 device
++
+ pcf8523 Select the PCF8523 device
+
+ pcf8563 Select the PCF8563 device
+
++ rv3028 Select the Micro Crystal RV3028 device
++
+ addr Sets the address for the RTC. Note that the
+ device must be configured to use the specified
+ address.
+@@ -1079,11 +1085,14 @@ Params: abx80x Select o
+ "schottky" (ABx80x only)
+
+ trickle-resistor-ohms Resistor value for trickle charge (DS1339,
+- ABx80x)
++ ABx80x, RV3028)
+
+ wakeup-source Specify that the RTC can be used as a wakeup
+ source
+
++ backup-switchover-mode Backup power supply switch mode. Must be 0 for
++ off or 1 for Vdd < VBackup (RV3028 only)
++
+ i2c_gpio_sda GPIO used for I2C data (default "23")
+
+ i2c_gpio_scl GPIO used for I2C clock (default "24")
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
+@@ -121,7 +121,7 @@
+ #size-cells = <0>;
+ status = "okay";
+
+- pcf2127: pcf2127@51 {
++ pcf2127@51 {
+ compatible = "nxp,pcf2127";
+ reg = <0x51>;
+ status = "okay";
+@@ -174,6 +174,36 @@
+ };
+ };
+
++ fragment@11 {
++ target = <&i2c_gpio>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ rv3028: rv3028@52 {
++ compatible = "microcrystal,rv3028";
++ reg = <0x52>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@12 {
++ target = <&i2c_gpio>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcf2129@51 {
++ compatible = "nxp,pcf2129";
++ reg = <0x51>;
++ status = "okay";
++ };
++ };
++ };
++
+ __overrides__ {
+ abx80x = <0>,"+1";
+ ds1307 = <0>,"+2";
+@@ -185,6 +215,8 @@
+ pcf8523 = <0>,"+8";
+ pcf8563 = <0>,"+9";
+ m41t62 = <0>,"+10";
++ rv3028 = <0>,"+11";
++ pcf2129 = <0>,"+12";
+
+ addr = <&abx80x>, "reg:0",
+ <&ds1307>, "reg:0",
+@@ -192,18 +224,19 @@
+ <&ds3231>, "reg:0",
+ <&mcp7940x>, "reg:0",
+ <&mcp7941x>, "reg:0",
+- <&pcf2127>, "reg:0",
+ <&pcf8523>, "reg:0",
+ <&pcf8563>, "reg:0",
+ <&m41t62>, "reg:0";
+
+ trickle-diode-type = <&abx80x>,"abracon,tc-diode";
+ trickle-resistor-ohms = <&ds1339>,"trickle-resistor-ohms:0",
+- <&abx80x>,"abracon,tc-resistor";
++ <&abx80x>,"abracon,tc-resistor",
++ <&rv3028>,"trickle-resistor-ohms:0";
++ backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0";
+ wakeup-source = <&ds1339>,"wakeup-source?",
+ <&ds3231>,"wakeup-source?",
+ <&mcp7940x>,"wakeup-source?",
+- <&mcp7941x>,"wakeup-source?";
++ <&mcp7941x>,"wakeup-source?";
+ i2c_gpio_sda = <&i2c_gpio>,"gpios:4";
+ i2c_gpio_scl = <&i2c_gpio>,"gpios:16";
+ i2c_gpio_delay_us = <&i2c_gpio>,"i2c-gpio,delay-us:0";
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+@@ -105,7 +105,7 @@
+ #size-cells = <0>;
+ status = "okay";
+
+- pcf2127: pcf2127@51 {
++ pcf2127@51 {
+ compatible = "nxp,pcf2127";
+ reg = <0x51>;
+ status = "okay";
+@@ -173,6 +173,21 @@
+ };
+ };
+
++ fragment@11 {
++ target = <&i2c_arm>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcf2129@51 {
++ compatible = "nxp,pcf2129";
++ reg = <0x51>;
++ status = "okay";
++ };
++ };
++ };
++
+ __overrides__ {
+ abx80x = <0>,"+0";
+ ds1307 = <0>,"+1";
+@@ -185,6 +200,7 @@
+ pcf8563 = <0>,"+8";
+ m41t62 = <0>,"+9";
+ rv3028 = <0>,"+10";
++ pcf2129 = <0>,"+11";
+
+ addr = <&abx80x>, "reg:0",
+ <&ds1307>, "reg:0",
+@@ -192,7 +208,6 @@
+ <&ds3231>, "reg:0",
+ <&mcp7940x>, "reg:0",
+ <&mcp7941x>, "reg:0",
+- <&pcf2127>, "reg:0",
+ <&pcf8523>, "reg:0",
+ <&pcf8563>, "reg:0",
+ <&m41t62>, "reg:0";
+++ /dev/null
-From 39964e4a3a2ea18b48be5c31d7980895f0bdd99c Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Mar 2019 13:02:16 -0800
-Subject: [PATCH] arm64: bcm2835: Add missing dependency on MFD_CORE.
-
-commit 7a9b6be9fe58194d9a349159176e8cc0d8f10ef8 upstream.
-
-When adding the MFD dependency for power domains and WDT in bcm2835, I
-added it only on the arm32 side and missed it for arm64.
-
-Fixes: 5e6acc3e678e ("bcm2835-pm: Move bcm2835-watchdog's DT probe to an MFD.")
----
- arch/arm64/Kconfig.platforms | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm64/Kconfig.platforms
-+++ b/arch/arm64/Kconfig.platforms
-@@ -20,6 +20,7 @@ config ARCH_BCM2835
- bool "Broadcom BCM2835 family"
- select TIMER_OF
- select GPIOLIB
-+ select MFD_CORE
- select PINCTRL
- select PINCTRL_BCM2835
- select ARM_AMBA
--- /dev/null
+From a5e0d604116189331d5608c9d128f37df17db2e3 Mon Sep 17 00:00:00 2001
+Date: Tue, 16 Jul 2019 15:24:12 +0100
+Subject: [PATCH] overlays: dpi18 and dpi24 vc4 compatibility
+
+The dpi overlays use the fb device tree node as a place to hang the
+necessary pinctrl changes. With one of the VC4 overlays loaded, the
+fb node is disabled so the changes have no effect.
+
+Modify the overlays to also use the vc4 node, to cover both use
+cases.
+
+---
+ arch/arm/boot/dts/overlays/dpi18-overlay.dts | 8 ++++++++
+ arch/arm/boot/dts/overlays/dpi24-overlay.dts | 8 ++++++++
+ 2 files changed, 16 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/dpi18-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dpi18-overlay.dts
+@@ -17,6 +17,14 @@
+ };
+
+ fragment@1 {
++ target = <&vc4>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&dpi18_pins>;
++ };
++ };
++
++ fragment@2 {
+ target = <&gpio>;
+ __overlay__ {
+ dpi18_pins: dpi18_pins {
+--- a/arch/arm/boot/dts/overlays/dpi24-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dpi24-overlay.dts
+@@ -17,6 +17,14 @@
+ };
+
+ fragment@1 {
++ target = <&vc4>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&dpi24_pins>;
++ };
++ };
++
++ fragment@2 {
+ target = <&gpio>;
+ __overlay__ {
+ dpi24_pins: dpi24_pins {
+++ /dev/null
-From 2308f60bb68de69306c542de3983be0007cad37b Mon Sep 17 00:00:00 2001
-Date: Mon, 15 Jul 2019 10:39:05 +0100
-Subject: [PATCH] overlays: Add PCF2129 RTC
-
-Add support for the PCF2129 RTC to i2c-rtc and i2c-rtc-gpio overlays.
-Also add rv3028 to i2c-rtc-gpio (it was missed previously), and don't
-attempt to set an alternate address for the PCF2127.
-
----
- arch/arm/boot/dts/overlays/README | 11 ++++-
- .../dts/overlays/i2c-rtc-gpio-overlay.dts | 41 +++++++++++++++++--
- .../arm/boot/dts/overlays/i2c-rtc-overlay.dts | 19 ++++++++-
- 3 files changed, 64 insertions(+), 7 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1022,6 +1022,8 @@ Params: abx80x Select o
-
- pcf2127 Select the PCF2127 device
-
-+ pcf2129 Select the PCF2129 device
-+
- pcf8523 Select the PCF8523 device
-
- pcf8563 Select the PCF8563 device
-@@ -1067,10 +1069,14 @@ Params: abx80x Select o
-
- pcf2127 Select the PCF2127 device
-
-+ pcf2129 Select the PCF2129 device
-+
- pcf8523 Select the PCF8523 device
-
- pcf8563 Select the PCF8563 device
-
-+ rv3028 Select the Micro Crystal RV3028 device
-+
- addr Sets the address for the RTC. Note that the
- device must be configured to use the specified
- address.
-@@ -1079,11 +1085,14 @@ Params: abx80x Select o
- "schottky" (ABx80x only)
-
- trickle-resistor-ohms Resistor value for trickle charge (DS1339,
-- ABx80x)
-+ ABx80x, RV3028)
-
- wakeup-source Specify that the RTC can be used as a wakeup
- source
-
-+ backup-switchover-mode Backup power supply switch mode. Must be 0 for
-+ off or 1 for Vdd < VBackup (RV3028 only)
-+
- i2c_gpio_sda GPIO used for I2C data (default "23")
-
- i2c_gpio_scl GPIO used for I2C clock (default "24")
---- a/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-rtc-gpio-overlay.dts
-@@ -121,7 +121,7 @@
- #size-cells = <0>;
- status = "okay";
-
-- pcf2127: pcf2127@51 {
-+ pcf2127@51 {
- compatible = "nxp,pcf2127";
- reg = <0x51>;
- status = "okay";
-@@ -174,6 +174,36 @@
- };
- };
-
-+ fragment@11 {
-+ target = <&i2c_gpio>;
-+ __dormant__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ rv3028: rv3028@52 {
-+ compatible = "microcrystal,rv3028";
-+ reg = <0x52>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@12 {
-+ target = <&i2c_gpio>;
-+ __dormant__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ pcf2129@51 {
-+ compatible = "nxp,pcf2129";
-+ reg = <0x51>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
- __overrides__ {
- abx80x = <0>,"+1";
- ds1307 = <0>,"+2";
-@@ -185,6 +215,8 @@
- pcf8523 = <0>,"+8";
- pcf8563 = <0>,"+9";
- m41t62 = <0>,"+10";
-+ rv3028 = <0>,"+11";
-+ pcf2129 = <0>,"+12";
-
- addr = <&abx80x>, "reg:0",
- <&ds1307>, "reg:0",
-@@ -192,18 +224,19 @@
- <&ds3231>, "reg:0",
- <&mcp7940x>, "reg:0",
- <&mcp7941x>, "reg:0",
-- <&pcf2127>, "reg:0",
- <&pcf8523>, "reg:0",
- <&pcf8563>, "reg:0",
- <&m41t62>, "reg:0";
-
- trickle-diode-type = <&abx80x>,"abracon,tc-diode";
- trickle-resistor-ohms = <&ds1339>,"trickle-resistor-ohms:0",
-- <&abx80x>,"abracon,tc-resistor";
-+ <&abx80x>,"abracon,tc-resistor",
-+ <&rv3028>,"trickle-resistor-ohms:0";
-+ backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0";
- wakeup-source = <&ds1339>,"wakeup-source?",
- <&ds3231>,"wakeup-source?",
- <&mcp7940x>,"wakeup-source?",
-- <&mcp7941x>,"wakeup-source?";
-+ <&mcp7941x>,"wakeup-source?";
- i2c_gpio_sda = <&i2c_gpio>,"gpios:4";
- i2c_gpio_scl = <&i2c_gpio>,"gpios:16";
- i2c_gpio_delay_us = <&i2c_gpio>,"i2c-gpio,delay-us:0";
---- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-@@ -105,7 +105,7 @@
- #size-cells = <0>;
- status = "okay";
-
-- pcf2127: pcf2127@51 {
-+ pcf2127@51 {
- compatible = "nxp,pcf2127";
- reg = <0x51>;
- status = "okay";
-@@ -173,6 +173,21 @@
- };
- };
-
-+ fragment@11 {
-+ target = <&i2c_arm>;
-+ __dormant__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ pcf2129@51 {
-+ compatible = "nxp,pcf2129";
-+ reg = <0x51>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
- __overrides__ {
- abx80x = <0>,"+0";
- ds1307 = <0>,"+1";
-@@ -185,6 +200,7 @@
- pcf8563 = <0>,"+8";
- m41t62 = <0>,"+9";
- rv3028 = <0>,"+10";
-+ pcf2129 = <0>,"+11";
-
- addr = <&abx80x>, "reg:0",
- <&ds1307>, "reg:0",
-@@ -192,7 +208,6 @@
- <&ds3231>, "reg:0",
- <&mcp7940x>, "reg:0",
- <&mcp7941x>, "reg:0",
-- <&pcf2127>, "reg:0",
- <&pcf8523>, "reg:0",
- <&pcf8563>, "reg:0",
- <&m41t62>, "reg:0";
--- /dev/null
+From 9c0f4b3e3b197d5c81f4bd6679f2c2456ab45c9e Mon Sep 17 00:00:00 2001
+Date: Wed, 17 Jul 2019 10:08:55 +0100
+Subject: [PATCH] overlays: Add i2c0 and i2c1 for regularity
+
+The new i2c overlays for pi4 (i2c3, i2c4, i2c5, i2c6) have a
+standardised interface that allows pin groups to be chosen
+atomically rather than as individual pins. Add i2c0 and i2c1
+overlays to fit the naming scheme and parameter usage, deprecating
+i2c0-bcm2708 and i2c1-bcm2708.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 2 +
+ arch/arm/boot/dts/overlays/README | 33 +++++---
+ .../dts/overlays/i2c0-bcm2708-overlay.dts | 77 +++----------------
+ arch/arm/boot/dts/overlays/i2c0-overlay.dts | 61 +++++++++++++++
+ .../dts/overlays/i2c1-bcm2708-overlay.dts | 46 ++---------
+ arch/arm/boot/dts/overlays/i2c1-overlay.dts | 44 +++++++++++
+ 6 files changed, 147 insertions(+), 116 deletions(-)
+ create mode 100644 arch/arm/boot/dts/overlays/i2c0-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/i2c1-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -66,7 +66,9 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ i2c-rtc.dtbo \
+ i2c-rtc-gpio.dtbo \
+ i2c-sensor.dtbo \
++ i2c0.dtbo \
+ i2c0-bcm2708.dtbo \
++ i2c1.dtbo \
+ i2c1-bcm2708.dtbo \
+ i2c3.dtbo \
+ i2c4.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1151,14 +1151,12 @@ Params: addr Set the
+ sensor
+
+
+-Name: i2c0-bcm2708
++Name: i2c0
+ Info: Change i2c0 pin usage. Not all pin combinations are usable on all
+ platforms - platforms other then Compute Modules can only use this
+ to disable transaction combining.
+-Load: dtoverlay=i2c0-bcm2708,<param>=<val>
+-Params: sda0_pin GPIO pin for SDA0 (deprecated - use pins_*)
+- scl0_pin GPIO pin for SCL0 (deprecated - use pins_*)
+- pins_0_1 Use pins 0 and 1 (default)
++Load: dtoverlay=i2c0,<param>=<val>
++Params: pins_0_1 Use pins 0 and 1 (default)
+ pins_28_29 Use pins 28 and 29
+ pins_44_45 Use pins 44 and 45
+ pins_46_47 Use pins 46 and 47
+@@ -1166,18 +1164,33 @@ Params: sda0_pin GPIO pin
+ "yes")
+
+
+-Name: i2c1-bcm2708
++Name: i2c0-bcm2708
++Info: Deprecated, legacy version of i2c0, from which it inherits its
++ parameters, just adding the explicit individual pin specifiers.
++Load: <Deprecated>
++Params: sda0_pin GPIO pin for SDA0 (deprecated - use pins_*)
++ scl0_pin GPIO pin for SCL0 (deprecated - use pins_*)
++
++
++Name: i2c1
+ Info: Change i2c1 pin usage. Not all pin combinations are usable on all
+ platforms - platforms other then Compute Modules can only use this
+ to disable transaction combining.
+-Info: Enable the i2c_bcm2708 driver for the i2c1 bus
+-Load: dtoverlay=i2c1-bcm2708,<param>=<val>
++Load: dtoverlay=i2c1,<param>=<val>
++Params: pins_2_3 Use pins 2 and 3 (default)
++ pins_44_45 Use pins 44 and 45
++ combine Allow transactions to be combined (default
++ "yes")
++
++
++Name: i2c1-bcm2708
++Info: Deprecated, legacy version of i2c1, from which it inherits its
++ parameters, just adding the explicit individual pin specifiers.
++Load: <Deprecated>
+ Params: sda1_pin GPIO pin for SDA1 (2 or 44 - default 2)
+ scl1_pin GPIO pin for SCL1 (3 or 45 - default 3)
+ pin_func Alternative pin function (4 (alt0), 6 (alt2) -
+ default 4)
+- combine Allow transactions to be combined (default
+- "yes")
+
+
+ Name: i2c3
+--- a/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
+@@ -1,69 +1,14 @@
+-/*
+- * Device tree overlay for i2c_bcm2708, i2c0 bus
+- *
+- * Compile:
+- * dtc -@ -I dts -O dtb -o i2c0-bcm2708-overlay.dtb i2c0-bcm2708-overlay.dts
+- */
+-
+-/dts-v1/;
+-/plugin/;
++#include "i2c0-overlay.dts"
+
+ /{
+- compatible = "brcm,bcm2835";
+-
+- fragment@0 {
+- target = <&i2c0>;
+- __overlay__ {
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+- target = <&i2c0_pins>;
+- frag1: __overlay__ {
+- brcm,pins = <0 1>;
+- brcm,function = <4>; /* alt0 */
+- };
+- };
+-
+- fragment@2 {
+- target = <&i2c0_pins>;
+- __dormant__ {
+- brcm,pins = <28 29>;
+- brcm,function = <4>; /* alt0 */
+- };
+- };
+-
+- fragment@3 {
+- target = <&i2c0_pins>;
+- __dormant__ {
+- brcm,pins = <44 45>;
+- brcm,function = <5>; /* alt1 */
+- };
+- };
+-
+- fragment@4 {
+- target = <&i2c0_pins>;
+- __dormant__ {
+- brcm,pins = <46 47>;
+- brcm,function = <4>; /* alt0 */
+- };
+- };
+-
+- fragment@5 {
+- target = <&i2c0>;
+- __dormant__ {
+- compatible = "brcm,bcm2708-i2c";
+- };
+- };
+-
+- __overrides__ {
+- sda0_pin = <&frag1>,"brcm,pins:0";
+- scl0_pin = <&frag1>,"brcm,pins:4";
+- pins_0_1 = <0>,"+1-2-3-4";
+- pins_28_29 = <0>,"-1+2-3-4";
+- pins_44_45 = <0>,"-1-2+3-4";
+- pins_46_47 = <0>,"-1-2-3+4";
+- combine = <0>, "!5";
+- };
++ __overrides__ {
++ sda0_pin = <&pins1>,"brcm,pins:0",
++ <&pins2>,"brcm,pins:0",
++ <&pins3>,"brcm,pins:0",
++ <&pins4>,"brcm,pins:0";
++ scl0_pin = <&pins1>,"brcm,pins:4",
++ <&pins2>,"brcm,pins:4",
++ <&pins3>,"brcm,pins:4",
++ <&pins4>,"brcm,pins:4";
++ };
+ };
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c0-overlay.dts
+@@ -0,0 +1,61 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&i2c0>;
++ __overlay__ {
++ status = "okay";
++ pinctrl-0 = <&i2c0_pins>;
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c0_pins>;
++ pins1: __overlay__ {
++ brcm,pins = <0 1>;
++ brcm,function = <4>; /* alt0 */
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c0_pins>;
++ pins2: __dormant__ {
++ brcm,pins = <28 29>;
++ brcm,function = <4>; /* alt0 */
++ };
++ };
++
++ fragment@3 {
++ target = <&i2c0_pins>;
++ pins3: __dormant__ {
++ brcm,pins = <44 45>;
++ brcm,function = <5>; /* alt1 */
++ };
++ };
++
++ fragment@4 {
++ target = <&i2c0_pins>;
++ pins4: __dormant__ {
++ brcm,pins = <46 47>;
++ brcm,function = <4>; /* alt0 */
++ };
++ };
++
++ fragment@5 {
++ target = <&i2c0>;
++ __dormant__ {
++ compatible = "brcm,bcm2708-i2c";
++ };
++ };
++
++ __overrides__ {
++ pins_0_1 = <0>,"+1-2-3-4";
++ pins_28_29 = <0>,"-1+2-3-4";
++ pins_44_45 = <0>,"-1-2+3-4";
++ pins_46_47 = <0>,"-1-2-3+4";
++ combine = <0>, "!5";
++ };
++};
+--- a/arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts
+@@ -1,43 +1,9 @@
+-/*
+- * Device tree overlay for i2c_bcm2708, i2c1 bus
+- *
+- * Compile:
+- * dtc -@ -I dts -O dtb -o i2c1-bcm2708-overlay.dtb i2c1-bcm2708-overlay.dts
+- */
+-
+-/dts-v1/;
+-/plugin/;
++#include "i2c1-overlay.dts"
+
+ /{
+- compatible = "brcm,bcm2835";
+-
+- fragment@0 {
+- target = <&i2c1>;
+- __overlay__ {
+- pinctrl-0 = <&i2c1_pins>;
+- status = "okay";
+- };
+- };
+-
+- fragment@1 {
+- target = <&i2c1_pins>;
+- pins: __overlay__ {
+- brcm,pins = <2 3>;
+- brcm,function = <4>; /* alt 0 */
+- };
+- };
+-
+- fragment@2 {
+- target = <&i2c1>;
+- __dormant__ {
+- compatible = "brcm,bcm2708-i2c";
+- };
+- };
+-
+- __overrides__ {
+- sda1_pin = <&pins>,"brcm,pins:0";
+- scl1_pin = <&pins>,"brcm,pins:4";
+- pin_func = <&pins>,"brcm,function:0";
+- combine = <0>, "!2";
+- };
++ __overrides__ {
++ sda1_pin = <&pins1>,"brcm,pins:0", <&pins2>,"brcm,pins:0";
++ scl1_pin = <&pins1>,"brcm,pins:4", <&pins1>,"brcm,pins:4";
++ pin_func = <&pins1>,"brcm,function:0", <&pins2>,"brcm,function:0";
++ };
+ };
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/i2c1-overlay.dts
+@@ -0,0 +1,44 @@
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&i2c1>;
++ __overlay__ {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c1_pins>;
++ pins1: __overlay__ {
++ brcm,pins = <2 3>;
++ brcm,function = <4>; /* alt 0 */
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1_pins>;
++ pins2: __dormant__ {
++ brcm,pins = <44 45>;
++ brcm,function = <6>; /* alt 2 */
++ };
++ };
++
++ fragment@3 {
++ target = <&i2c1>;
++ __dormant__ {
++ compatible = "brcm,bcm2708-i2c";
++ };
++ };
++
++ __overrides__ {
++ pins_2_3 = <0>,"=1!2";
++ pins_44_45 = <0>,"!1=2";
++ combine = <0>, "!3";
++ };
++};
--- /dev/null
+From ace4e8240d581e6053f0165b2682a2db745d49dc Mon Sep 17 00:00:00 2001
+Date: Fri, 12 Jul 2019 17:45:55 +0300
+Subject: [PATCH] Pisound: Remove spinlock usage around spi_sync
+
+---
+ sound/soc/bcm/pisound.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+--- a/sound/soc/bcm/pisound.c
++++ b/sound/soc/bcm/pisound.c
+@@ -286,9 +286,6 @@ static irqreturn_t data_available_interr
+ return IRQ_HANDLED;
+ }
+
+-static DEFINE_SPINLOCK(spilock);
+-static unsigned long spilockflags;
+-
+ static uint16_t spi_transfer16(uint16_t val)
+ {
+ uint8_t txbuf[2];
+@@ -333,9 +330,7 @@ static void spi_transfer(const uint8_t *
+ transfer.delay_usecs = 10;
+ spi_message_add_tail(&transfer, &msg);
+
+- spin_lock_irqsave(&spilock, spilockflags);
+ err = spi_sync(pisnd_spi_device, &msg);
+- spin_unlock_irqrestore(&spilock, spilockflags);
+
+ if (err < 0) {
+ printe("spi_sync error %d\n", err);
+++ /dev/null
-From a5e0d604116189331d5608c9d128f37df17db2e3 Mon Sep 17 00:00:00 2001
-Date: Tue, 16 Jul 2019 15:24:12 +0100
-Subject: [PATCH] overlays: dpi18 and dpi24 vc4 compatibility
-
-The dpi overlays use the fb device tree node as a place to hang the
-necessary pinctrl changes. With one of the VC4 overlays loaded, the
-fb node is disabled so the changes have no effect.
-
-Modify the overlays to also use the vc4 node, to cover both use
-cases.
-
----
- arch/arm/boot/dts/overlays/dpi18-overlay.dts | 8 ++++++++
- arch/arm/boot/dts/overlays/dpi24-overlay.dts | 8 ++++++++
- 2 files changed, 16 insertions(+)
-
---- a/arch/arm/boot/dts/overlays/dpi18-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dpi18-overlay.dts
-@@ -17,6 +17,14 @@
- };
-
- fragment@1 {
-+ target = <&vc4>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&dpi18_pins>;
-+ };
-+ };
-+
-+ fragment@2 {
- target = <&gpio>;
- __overlay__ {
- dpi18_pins: dpi18_pins {
---- a/arch/arm/boot/dts/overlays/dpi24-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dpi24-overlay.dts
-@@ -17,6 +17,14 @@
- };
-
- fragment@1 {
-+ target = <&vc4>;
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&dpi24_pins>;
-+ };
-+ };
-+
-+ fragment@2 {
- target = <&gpio>;
- __overlay__ {
- dpi24_pins: dpi24_pins {
--- /dev/null
+From 2722f08c4c59901bd506184e2dcbbbd532aef0b3 Mon Sep 17 00:00:00 2001
+Date: Tue, 16 Jul 2019 13:28:22 +0100
+Subject: [PATCH] arm64/mm: Limit the DMA zone for arm64
+
+On RaspberryPi, only the first 1Gb can be used for DMA[1].
+
+[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2019-July/665986.html
+
+---
+ arch/arm64/mm/init.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/mm/init.c
++++ b/arch/arm64/mm/init.c
+@@ -224,7 +224,7 @@ static void __init reserve_elfcorehdr(vo
+ static phys_addr_t __init max_zone_dma_phys(void)
+ {
+ phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
+- return min(offset + (1ULL << 32), memblock_end_of_DRAM());
++ return min(offset + (1ULL << 30), memblock_end_of_DRAM());
+ }
+
+ #ifdef CONFIG_NUMA
+++ /dev/null
-From 9c0f4b3e3b197d5c81f4bd6679f2c2456ab45c9e Mon Sep 17 00:00:00 2001
-Date: Wed, 17 Jul 2019 10:08:55 +0100
-Subject: [PATCH] overlays: Add i2c0 and i2c1 for regularity
-
-The new i2c overlays for pi4 (i2c3, i2c4, i2c5, i2c6) have a
-standardised interface that allows pin groups to be chosen
-atomically rather than as individual pins. Add i2c0 and i2c1
-overlays to fit the naming scheme and parameter usage, deprecating
-i2c0-bcm2708 and i2c1-bcm2708.
-
----
- arch/arm/boot/dts/overlays/Makefile | 2 +
- arch/arm/boot/dts/overlays/README | 33 +++++---
- .../dts/overlays/i2c0-bcm2708-overlay.dts | 77 +++----------------
- arch/arm/boot/dts/overlays/i2c0-overlay.dts | 61 +++++++++++++++
- .../dts/overlays/i2c1-bcm2708-overlay.dts | 46 ++---------
- arch/arm/boot/dts/overlays/i2c1-overlay.dts | 44 +++++++++++
- 6 files changed, 147 insertions(+), 116 deletions(-)
- create mode 100644 arch/arm/boot/dts/overlays/i2c0-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/i2c1-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -66,7 +66,9 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- i2c-rtc.dtbo \
- i2c-rtc-gpio.dtbo \
- i2c-sensor.dtbo \
-+ i2c0.dtbo \
- i2c0-bcm2708.dtbo \
-+ i2c1.dtbo \
- i2c1-bcm2708.dtbo \
- i2c3.dtbo \
- i2c4.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1151,14 +1151,12 @@ Params: addr Set the
- sensor
-
-
--Name: i2c0-bcm2708
-+Name: i2c0
- Info: Change i2c0 pin usage. Not all pin combinations are usable on all
- platforms - platforms other then Compute Modules can only use this
- to disable transaction combining.
--Load: dtoverlay=i2c0-bcm2708,<param>=<val>
--Params: sda0_pin GPIO pin for SDA0 (deprecated - use pins_*)
-- scl0_pin GPIO pin for SCL0 (deprecated - use pins_*)
-- pins_0_1 Use pins 0 and 1 (default)
-+Load: dtoverlay=i2c0,<param>=<val>
-+Params: pins_0_1 Use pins 0 and 1 (default)
- pins_28_29 Use pins 28 and 29
- pins_44_45 Use pins 44 and 45
- pins_46_47 Use pins 46 and 47
-@@ -1166,18 +1164,33 @@ Params: sda0_pin GPIO pin
- "yes")
-
-
--Name: i2c1-bcm2708
-+Name: i2c0-bcm2708
-+Info: Deprecated, legacy version of i2c0, from which it inherits its
-+ parameters, just adding the explicit individual pin specifiers.
-+Load: <Deprecated>
-+Params: sda0_pin GPIO pin for SDA0 (deprecated - use pins_*)
-+ scl0_pin GPIO pin for SCL0 (deprecated - use pins_*)
-+
-+
-+Name: i2c1
- Info: Change i2c1 pin usage. Not all pin combinations are usable on all
- platforms - platforms other then Compute Modules can only use this
- to disable transaction combining.
--Info: Enable the i2c_bcm2708 driver for the i2c1 bus
--Load: dtoverlay=i2c1-bcm2708,<param>=<val>
-+Load: dtoverlay=i2c1,<param>=<val>
-+Params: pins_2_3 Use pins 2 and 3 (default)
-+ pins_44_45 Use pins 44 and 45
-+ combine Allow transactions to be combined (default
-+ "yes")
-+
-+
-+Name: i2c1-bcm2708
-+Info: Deprecated, legacy version of i2c1, from which it inherits its
-+ parameters, just adding the explicit individual pin specifiers.
-+Load: <Deprecated>
- Params: sda1_pin GPIO pin for SDA1 (2 or 44 - default 2)
- scl1_pin GPIO pin for SCL1 (3 or 45 - default 3)
- pin_func Alternative pin function (4 (alt0), 6 (alt2) -
- default 4)
-- combine Allow transactions to be combined (default
-- "yes")
-
-
- Name: i2c3
---- a/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts
-@@ -1,69 +1,14 @@
--/*
-- * Device tree overlay for i2c_bcm2708, i2c0 bus
-- *
-- * Compile:
-- * dtc -@ -I dts -O dtb -o i2c0-bcm2708-overlay.dtb i2c0-bcm2708-overlay.dts
-- */
--
--/dts-v1/;
--/plugin/;
-+#include "i2c0-overlay.dts"
-
- /{
-- compatible = "brcm,bcm2835";
--
-- fragment@0 {
-- target = <&i2c0>;
-- __overlay__ {
-- status = "okay";
-- };
-- };
--
-- fragment@1 {
-- target = <&i2c0_pins>;
-- frag1: __overlay__ {
-- brcm,pins = <0 1>;
-- brcm,function = <4>; /* alt0 */
-- };
-- };
--
-- fragment@2 {
-- target = <&i2c0_pins>;
-- __dormant__ {
-- brcm,pins = <28 29>;
-- brcm,function = <4>; /* alt0 */
-- };
-- };
--
-- fragment@3 {
-- target = <&i2c0_pins>;
-- __dormant__ {
-- brcm,pins = <44 45>;
-- brcm,function = <5>; /* alt1 */
-- };
-- };
--
-- fragment@4 {
-- target = <&i2c0_pins>;
-- __dormant__ {
-- brcm,pins = <46 47>;
-- brcm,function = <4>; /* alt0 */
-- };
-- };
--
-- fragment@5 {
-- target = <&i2c0>;
-- __dormant__ {
-- compatible = "brcm,bcm2708-i2c";
-- };
-- };
--
-- __overrides__ {
-- sda0_pin = <&frag1>,"brcm,pins:0";
-- scl0_pin = <&frag1>,"brcm,pins:4";
-- pins_0_1 = <0>,"+1-2-3-4";
-- pins_28_29 = <0>,"-1+2-3-4";
-- pins_44_45 = <0>,"-1-2+3-4";
-- pins_46_47 = <0>,"-1-2-3+4";
-- combine = <0>, "!5";
-- };
-+ __overrides__ {
-+ sda0_pin = <&pins1>,"brcm,pins:0",
-+ <&pins2>,"brcm,pins:0",
-+ <&pins3>,"brcm,pins:0",
-+ <&pins4>,"brcm,pins:0";
-+ scl0_pin = <&pins1>,"brcm,pins:4",
-+ <&pins2>,"brcm,pins:4",
-+ <&pins3>,"brcm,pins:4",
-+ <&pins4>,"brcm,pins:4";
-+ };
- };
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/i2c0-overlay.dts
-@@ -0,0 +1,61 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&i2c0>;
-+ __overlay__ {
-+ status = "okay";
-+ pinctrl-0 = <&i2c0_pins>;
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2c0_pins>;
-+ pins1: __overlay__ {
-+ brcm,pins = <0 1>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c0_pins>;
-+ pins2: __dormant__ {
-+ brcm,pins = <28 29>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&i2c0_pins>;
-+ pins3: __dormant__ {
-+ brcm,pins = <44 45>;
-+ brcm,function = <5>; /* alt1 */
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&i2c0_pins>;
-+ pins4: __dormant__ {
-+ brcm,pins = <46 47>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+ };
-+
-+ fragment@5 {
-+ target = <&i2c0>;
-+ __dormant__ {
-+ compatible = "brcm,bcm2708-i2c";
-+ };
-+ };
-+
-+ __overrides__ {
-+ pins_0_1 = <0>,"+1-2-3-4";
-+ pins_28_29 = <0>,"-1+2-3-4";
-+ pins_44_45 = <0>,"-1-2+3-4";
-+ pins_46_47 = <0>,"-1-2-3+4";
-+ combine = <0>, "!5";
-+ };
-+};
---- a/arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts
-@@ -1,43 +1,9 @@
--/*
-- * Device tree overlay for i2c_bcm2708, i2c1 bus
-- *
-- * Compile:
-- * dtc -@ -I dts -O dtb -o i2c1-bcm2708-overlay.dtb i2c1-bcm2708-overlay.dts
-- */
--
--/dts-v1/;
--/plugin/;
-+#include "i2c1-overlay.dts"
-
- /{
-- compatible = "brcm,bcm2835";
--
-- fragment@0 {
-- target = <&i2c1>;
-- __overlay__ {
-- pinctrl-0 = <&i2c1_pins>;
-- status = "okay";
-- };
-- };
--
-- fragment@1 {
-- target = <&i2c1_pins>;
-- pins: __overlay__ {
-- brcm,pins = <2 3>;
-- brcm,function = <4>; /* alt 0 */
-- };
-- };
--
-- fragment@2 {
-- target = <&i2c1>;
-- __dormant__ {
-- compatible = "brcm,bcm2708-i2c";
-- };
-- };
--
-- __overrides__ {
-- sda1_pin = <&pins>,"brcm,pins:0";
-- scl1_pin = <&pins>,"brcm,pins:4";
-- pin_func = <&pins>,"brcm,function:0";
-- combine = <0>, "!2";
-- };
-+ __overrides__ {
-+ sda1_pin = <&pins1>,"brcm,pins:0", <&pins2>,"brcm,pins:0";
-+ scl1_pin = <&pins1>,"brcm,pins:4", <&pins1>,"brcm,pins:4";
-+ pin_func = <&pins1>,"brcm,function:0", <&pins2>,"brcm,function:0";
-+ };
- };
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/i2c1-overlay.dts
-@@ -0,0 +1,44 @@
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ status = "okay";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c1_pins>;
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2c1_pins>;
-+ pins1: __overlay__ {
-+ brcm,pins = <2 3>;
-+ brcm,function = <4>; /* alt 0 */
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1_pins>;
-+ pins2: __dormant__ {
-+ brcm,pins = <44 45>;
-+ brcm,function = <6>; /* alt 2 */
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&i2c1>;
-+ __dormant__ {
-+ compatible = "brcm,bcm2708-i2c";
-+ };
-+ };
-+
-+ __overrides__ {
-+ pins_2_3 = <0>,"=1!2";
-+ pins_44_45 = <0>,"!1=2";
-+ combine = <0>, "!3";
-+ };
-+};
+++ /dev/null
-From ace4e8240d581e6053f0165b2682a2db745d49dc Mon Sep 17 00:00:00 2001
-Date: Fri, 12 Jul 2019 17:45:55 +0300
-Subject: [PATCH] Pisound: Remove spinlock usage around spi_sync
-
----
- sound/soc/bcm/pisound.c | 5 -----
- 1 file changed, 5 deletions(-)
-
---- a/sound/soc/bcm/pisound.c
-+++ b/sound/soc/bcm/pisound.c
-@@ -286,9 +286,6 @@ static irqreturn_t data_available_interr
- return IRQ_HANDLED;
- }
-
--static DEFINE_SPINLOCK(spilock);
--static unsigned long spilockflags;
--
- static uint16_t spi_transfer16(uint16_t val)
- {
- uint8_t txbuf[2];
-@@ -333,9 +330,7 @@ static void spi_transfer(const uint8_t *
- transfer.delay_usecs = 10;
- spi_message_add_tail(&transfer, &msg);
-
-- spin_lock_irqsave(&spilock, spilockflags);
- err = spi_sync(pisnd_spi_device, &msg);
-- spin_unlock_irqrestore(&spilock, spilockflags);
-
- if (err < 0) {
- printe("spi_sync error %d\n", err);
--- /dev/null
+From 5620f5eda349027a6e00e23391bc59617d25b449 Mon Sep 17 00:00:00 2001
+Date: Wed, 3 Jul 2019 17:44:53 +0100
+Subject: [PATCH] drm/vc4: Query firmware for custom HDMI mode
+
+Allow custom HDMI modes to be specified from config.txt,
+and these then override EDID parsing.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 142 ++++++++++++++-----------
+ 1 file changed, 81 insertions(+), 61 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1035,6 +1035,58 @@ vc4_fkms_connector_detect(struct drm_con
+ return connector_status_connected;
+ }
+
++/* Queries the firmware to populate a drm_mode structure for this display */
++static int vc4_fkms_get_fw_mode(struct vc4_fkms_connector *fkms_connector,
++ struct drm_display_mode *mode)
++{
++ struct vc4_dev *vc4 = fkms_connector->vc4_dev;
++ struct set_timings timings = { 0 };
++ int ret;
++
++ timings.display = fkms_connector->display_number;
++
++ ret = rpi_firmware_property(vc4->firmware,
++ RPI_FIRMWARE_GET_DISPLAY_TIMING, &timings,
++ sizeof(timings));
++ if (ret || !timings.clock)
++ /* No mode returned - abort */
++ return -1;
++
++ /* Equivalent to DRM_MODE macro. */
++ memset(mode, 0, sizeof(*mode));
++ strncpy(mode->name, "FIXED_MODE", sizeof(mode->name));
++ mode->status = 0;
++ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
++ mode->clock = timings.clock;
++ mode->hdisplay = timings.hdisplay;
++ mode->hsync_start = timings.hsync_start;
++ mode->hsync_end = timings.hsync_end;
++ mode->htotal = timings.htotal;
++ mode->hskew = 0;
++ mode->vdisplay = timings.vdisplay;
++ mode->vsync_start = timings.vsync_start;
++ mode->vsync_end = timings.vsync_end;
++ mode->vtotal = timings.vtotal;
++ mode->vscan = timings.vscan;
++
++ if (timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
++ mode->flags |= DRM_MODE_FLAG_PHSYNC;
++ else
++ mode->flags |= DRM_MODE_FLAG_NHSYNC;
++
++ if (timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
++ mode->flags |= DRM_MODE_FLAG_PVSYNC;
++ else
++ mode->flags |= DRM_MODE_FLAG_NVSYNC;
++
++ if (timings.flags & TIMINGS_FLAGS_INTERLACE)
++ mode->flags |= DRM_MODE_FLAG_INTERLACE;
++
++ mode->base.type = DRM_MODE_OBJECT_MODE;
++
++ return 0;
++}
++
+ static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
+ size_t len)
+ {
+@@ -1063,30 +1115,40 @@ static int vc4_fkms_connector_get_modes(
+ to_vc4_fkms_connector(connector);
+ struct drm_encoder *encoder = fkms_connector->encoder;
+ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
+- int ret = 0;
++ struct drm_display_mode fw_mode;
++ struct drm_display_mode *mode;
+ struct edid *edid;
++ int num_modes;
+
+- edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
+- fkms_connector);
++ if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode)) {
++ drm_mode_debug_printmodeline(&fw_mode);
++ mode = drm_mode_duplicate(connector->dev,
++ &fw_mode);
++ drm_mode_probed_add(connector, mode);
++ num_modes = 1; /* 1 mode */
++ } else {
++ edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
++ fkms_connector);
+
+- /* FIXME: Can we do CEC?
+- * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
+- * if (!edid)
+- * return -ENODEV;
+- */
+-
+- vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
+-
+- if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
+- vc4_encoder->rgb_range_selectable =
+- drm_rgb_quant_range_selectable(edid);
++ /* FIXME: Can we do CEC?
++ * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
++ * if (!edid)
++ * return -ENODEV;
++ */
++
++ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
++
++ if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
++ vc4_encoder->rgb_range_selectable =
++ drm_rgb_quant_range_selectable(edid);
++ }
++
++ drm_connector_update_edid_property(connector, edid);
++ num_modes = drm_add_edid_modes(connector, edid);
++ kfree(edid);
+ }
+
+- drm_connector_update_edid_property(connector, edid);
+- ret = drm_add_edid_modes(connector, edid);
+- kfree(edid);
+-
+- return ret;
++ return num_modes;
+ }
+
+ /* This is the DSI panel resolution. Use this as a default should the firmware
+@@ -1104,57 +1166,15 @@ static int vc4_fkms_lcd_connector_get_mo
+ {
+ struct vc4_fkms_connector *fkms_connector =
+ to_vc4_fkms_connector(connector);
+- struct vc4_dev *vc4 = fkms_connector->vc4_dev;
+ struct drm_display_mode *mode;
+- struct mailbox_set_mode mb = {
+- .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING,
+- sizeof(struct set_timings), 0},
+- .timings = { .display = fkms_connector->display_number },
+- };
+ struct drm_display_mode fw_mode;
+- int ret = 0;
+-
+- ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
+- if (!ret) {
+- /* Equivalent to DRM_MODE macro. */
+- memset(&fw_mode, 0, sizeof(fw_mode));
+- strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name));
+- fw_mode.status = 0;
+- fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+- fw_mode.clock = mb.timings.clock;
+- fw_mode.hdisplay = mb.timings.hdisplay;
+- fw_mode.hsync_start = mb.timings.hsync_start;
+- fw_mode.hsync_end = mb.timings.hsync_end;
+- fw_mode.htotal = mb.timings.htotal;
+- fw_mode.hskew = 0;
+- fw_mode.vdisplay = mb.timings.vdisplay;
+- fw_mode.vsync_start = mb.timings.vsync_start;
+- fw_mode.vsync_end = mb.timings.vsync_end;
+- fw_mode.vtotal = mb.timings.vtotal;
+- fw_mode.vscan = mb.timings.vscan;
+- if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
+- fw_mode.flags |= DRM_MODE_FLAG_PHSYNC;
+- else
+- fw_mode.flags |= DRM_MODE_FLAG_NHSYNC;
+- if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
+- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
+- else
+- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
+- if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
+- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
+- else
+- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
+- if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE)
+- fw_mode.flags |= DRM_MODE_FLAG_INTERLACE;
+-
+- fw_mode.base.type = DRM_MODE_OBJECT_MODE;
+
++ if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode) && fw_mode.clock)
+ mode = drm_mode_duplicate(connector->dev,
+ &fw_mode);
+- } else {
++ else
+ mode = drm_mode_duplicate(connector->dev,
+ &lcd_mode);
+- }
+
+ if (!mode) {
+ DRM_ERROR("Failed to create a new display mode\n");
+++ /dev/null
-From 2722f08c4c59901bd506184e2dcbbbd532aef0b3 Mon Sep 17 00:00:00 2001
-Date: Tue, 16 Jul 2019 13:28:22 +0100
-Subject: [PATCH] arm64/mm: Limit the DMA zone for arm64
-
-On RaspberryPi, only the first 1Gb can be used for DMA[1].
-
-[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2019-July/665986.html
-
----
- arch/arm64/mm/init.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm64/mm/init.c
-+++ b/arch/arm64/mm/init.c
-@@ -224,7 +224,7 @@ static void __init reserve_elfcorehdr(vo
- static phys_addr_t __init max_zone_dma_phys(void)
- {
- phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
-- return min(offset + (1ULL << 32), memblock_end_of_DRAM());
-+ return min(offset + (1ULL << 30), memblock_end_of_DRAM());
- }
-
- #ifdef CONFIG_NUMA
--- /dev/null
+From 2c0bfade955e4e660941db287020d06c9e22267f Mon Sep 17 00:00:00 2001
+Date: Thu, 11 Jul 2019 15:12:05 +0100
+Subject: [PATCH] drm/vc4: Pass the drm vrefresh to the firmware on
+ mode set
+
+More for completeness than need, but use drm_mode_vrefresh
+to compute the vrefresh value, and pass that down to the
+firmware on mode set.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -737,8 +737,8 @@ static void vc4_crtc_mode_set_nofb(struc
+ mode->hdisplay, mode->hsync_start, mode->hsync_end,
+ mode->htotal, mode->hskew, mode->vdisplay,
+ mode->vsync_start, mode->vsync_end, mode->vtotal,
+- mode->vscan, mode->vrefresh, mode->picture_aspect_ratio,
+- mode->flags);
++ mode->vscan, drm_mode_vrefresh(mode),
++ mode->picture_aspect_ratio, mode->flags);
+ mb.timings.display = vc4_crtc->display_number;
+
+ mb.timings.video_id_code = frame.avi.video_code;
+@@ -754,7 +754,7 @@ static void vc4_crtc_mode_set_nofb(struc
+ mb.timings.vsync_end = mode->vsync_end;
+ mb.timings.vtotal = mode->vtotal;
+ mb.timings.vscan = mode->vscan;
+- mb.timings.vrefresh = 0;
++ mb.timings.vrefresh = drm_mode_vrefresh(mode);
+ mb.timings.flags = 0;
+ if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+ mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS;
+++ /dev/null
-From 5620f5eda349027a6e00e23391bc59617d25b449 Mon Sep 17 00:00:00 2001
-Date: Wed, 3 Jul 2019 17:44:53 +0100
-Subject: [PATCH] drm/vc4: Query firmware for custom HDMI mode
-
-Allow custom HDMI modes to be specified from config.txt,
-and these then override EDID parsing.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 142 ++++++++++++++-----------
- 1 file changed, 81 insertions(+), 61 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1035,6 +1035,58 @@ vc4_fkms_connector_detect(struct drm_con
- return connector_status_connected;
- }
-
-+/* Queries the firmware to populate a drm_mode structure for this display */
-+static int vc4_fkms_get_fw_mode(struct vc4_fkms_connector *fkms_connector,
-+ struct drm_display_mode *mode)
-+{
-+ struct vc4_dev *vc4 = fkms_connector->vc4_dev;
-+ struct set_timings timings = { 0 };
-+ int ret;
-+
-+ timings.display = fkms_connector->display_number;
-+
-+ ret = rpi_firmware_property(vc4->firmware,
-+ RPI_FIRMWARE_GET_DISPLAY_TIMING, &timings,
-+ sizeof(timings));
-+ if (ret || !timings.clock)
-+ /* No mode returned - abort */
-+ return -1;
-+
-+ /* Equivalent to DRM_MODE macro. */
-+ memset(mode, 0, sizeof(*mode));
-+ strncpy(mode->name, "FIXED_MODE", sizeof(mode->name));
-+ mode->status = 0;
-+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-+ mode->clock = timings.clock;
-+ mode->hdisplay = timings.hdisplay;
-+ mode->hsync_start = timings.hsync_start;
-+ mode->hsync_end = timings.hsync_end;
-+ mode->htotal = timings.htotal;
-+ mode->hskew = 0;
-+ mode->vdisplay = timings.vdisplay;
-+ mode->vsync_start = timings.vsync_start;
-+ mode->vsync_end = timings.vsync_end;
-+ mode->vtotal = timings.vtotal;
-+ mode->vscan = timings.vscan;
-+
-+ if (timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
-+ mode->flags |= DRM_MODE_FLAG_PHSYNC;
-+ else
-+ mode->flags |= DRM_MODE_FLAG_NHSYNC;
-+
-+ if (timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
-+ mode->flags |= DRM_MODE_FLAG_PVSYNC;
-+ else
-+ mode->flags |= DRM_MODE_FLAG_NVSYNC;
-+
-+ if (timings.flags & TIMINGS_FLAGS_INTERLACE)
-+ mode->flags |= DRM_MODE_FLAG_INTERLACE;
-+
-+ mode->base.type = DRM_MODE_OBJECT_MODE;
-+
-+ return 0;
-+}
-+
- static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
- size_t len)
- {
-@@ -1063,30 +1115,40 @@ static int vc4_fkms_connector_get_modes(
- to_vc4_fkms_connector(connector);
- struct drm_encoder *encoder = fkms_connector->encoder;
- struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
-- int ret = 0;
-+ struct drm_display_mode fw_mode;
-+ struct drm_display_mode *mode;
- struct edid *edid;
-+ int num_modes;
-
-- edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
-- fkms_connector);
-+ if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode)) {
-+ drm_mode_debug_printmodeline(&fw_mode);
-+ mode = drm_mode_duplicate(connector->dev,
-+ &fw_mode);
-+ drm_mode_probed_add(connector, mode);
-+ num_modes = 1; /* 1 mode */
-+ } else {
-+ edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
-+ fkms_connector);
-
-- /* FIXME: Can we do CEC?
-- * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
-- * if (!edid)
-- * return -ENODEV;
-- */
--
-- vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
--
-- if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
-- vc4_encoder->rgb_range_selectable =
-- drm_rgb_quant_range_selectable(edid);
-+ /* FIXME: Can we do CEC?
-+ * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
-+ * if (!edid)
-+ * return -ENODEV;
-+ */
-+
-+ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
-+
-+ if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
-+ vc4_encoder->rgb_range_selectable =
-+ drm_rgb_quant_range_selectable(edid);
-+ }
-+
-+ drm_connector_update_edid_property(connector, edid);
-+ num_modes = drm_add_edid_modes(connector, edid);
-+ kfree(edid);
- }
-
-- drm_connector_update_edid_property(connector, edid);
-- ret = drm_add_edid_modes(connector, edid);
-- kfree(edid);
--
-- return ret;
-+ return num_modes;
- }
-
- /* This is the DSI panel resolution. Use this as a default should the firmware
-@@ -1104,57 +1166,15 @@ static int vc4_fkms_lcd_connector_get_mo
- {
- struct vc4_fkms_connector *fkms_connector =
- to_vc4_fkms_connector(connector);
-- struct vc4_dev *vc4 = fkms_connector->vc4_dev;
- struct drm_display_mode *mode;
-- struct mailbox_set_mode mb = {
-- .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING,
-- sizeof(struct set_timings), 0},
-- .timings = { .display = fkms_connector->display_number },
-- };
- struct drm_display_mode fw_mode;
-- int ret = 0;
--
-- ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
-- if (!ret) {
-- /* Equivalent to DRM_MODE macro. */
-- memset(&fw_mode, 0, sizeof(fw_mode));
-- strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name));
-- fw_mode.status = 0;
-- fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-- fw_mode.clock = mb.timings.clock;
-- fw_mode.hdisplay = mb.timings.hdisplay;
-- fw_mode.hsync_start = mb.timings.hsync_start;
-- fw_mode.hsync_end = mb.timings.hsync_end;
-- fw_mode.htotal = mb.timings.htotal;
-- fw_mode.hskew = 0;
-- fw_mode.vdisplay = mb.timings.vdisplay;
-- fw_mode.vsync_start = mb.timings.vsync_start;
-- fw_mode.vsync_end = mb.timings.vsync_end;
-- fw_mode.vtotal = mb.timings.vtotal;
-- fw_mode.vscan = mb.timings.vscan;
-- if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
-- fw_mode.flags |= DRM_MODE_FLAG_PHSYNC;
-- else
-- fw_mode.flags |= DRM_MODE_FLAG_NHSYNC;
-- if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
-- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
-- else
-- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
-- if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
-- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
-- else
-- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
-- if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE)
-- fw_mode.flags |= DRM_MODE_FLAG_INTERLACE;
--
-- fw_mode.base.type = DRM_MODE_OBJECT_MODE;
-
-+ if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode) && fw_mode.clock)
- mode = drm_mode_duplicate(connector->dev,
- &fw_mode);
-- } else {
-+ else
- mode = drm_mode_duplicate(connector->dev,
- &lcd_mode);
-- }
-
- if (!mode) {
- DRM_ERROR("Failed to create a new display mode\n");
--- /dev/null
+From f42cc245e1f3e586f1a26550e5760489b6c329ab Mon Sep 17 00:00:00 2001
+Date: Tue, 23 Jul 2019 12:55:07 +0100
+Subject: [PATCH] overlays: audremap: Support GPIOs 18 & 19
+
+PWM audio can also be used on GPIOs 18 and 19, so add the pins_18_19
+parameter to select that location. pins_12_13 explicitly chooses GPIOs
+12 and 13, although this is the default behaviour so is there only for
+completeness.
+
+See: https://github.com/raspberrypi/firmware/issues/1178
+
+---
+ arch/arm/boot/dts/overlays/README | 4 +++-
+ arch/arm/boot/dts/overlays/audremap-overlay.dts | 16 ++++++++++++++++
+ 2 files changed, 19 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -475,12 +475,14 @@ Params: <None>
+
+
+ Name: audremap
+-Info: Switches PWM sound output to pins 12 (Right) & 13 (Left)
++Info: Switches PWM sound output to GPIOs on the 40-pin header
+ Load: dtoverlay=audremap,<param>=<val>
+ Params: swap_lr Reverse the channel allocation, which will also
+ swap the audio jack outputs (default off)
+ enable_jack Don't switch off the audio jack output
+ (default off)
++ pins_12_13 Select GPIOs 12 & 13 (default)
++ pins_18_19 Select GPIOs 18 & 19
+
+
+ Name: balena-fin
+--- a/arch/arm/boot/dts/overlays/audremap-overlay.dts
++++ b/arch/arm/boot/dts/overlays/audremap-overlay.dts
+@@ -7,13 +7,29 @@
+ fragment@0 {
+ target = <&audio_pins>;
+ frag0: __overlay__ {
++ };
++ };
++
++ fragment@1 {
++ target = <&audio_pins>;
++ __overlay__ {
+ brcm,pins = < 12 13 >;
+ brcm,function = < 4 >; /* alt0 alt0 */
+ };
+ };
+
++ fragment@2 {
++ target = <&audio_pins>;
++ __dormant__ {
++ brcm,pins = < 18 19 >;
++ brcm,function = < 2 >; /* alt5 alt5 */
++ };
++ };
++
+ __overrides__ {
+ swap_lr = <&frag0>, "swap_lr?";
+ enable_jack = <&frag0>, "enable_jack?";
++ pins_12_13 = <0>,"+1-2";
++ pins_18_19 = <0>,"-1+2";
+ };
+ };
--- /dev/null
+From ce5c3d732efb5e3da50119ed876f0d6661f08b84 Mon Sep 17 00:00:00 2001
+Date: Thu, 6 Dec 2018 15:24:35 +0100
+Subject: [PATCH] drm/connector: Fix drm_mode_create_tv_properties()
+ doc
+
+Commit eda6887f1961e0d2fb866b1a520b2de5b3828de5 upstream.
+
+The in the kernel-doc header did not match the function name.
+
+---
+ drivers/gpu/drm/drm_connector.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/drm_connector.c
++++ b/drivers/gpu/drm/drm_connector.c
+@@ -1110,7 +1110,7 @@ void drm_hdmi_avi_infoframe_content_type
+ EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type);
+
+ /**
+- * drm_create_tv_properties - create TV specific connector properties
++ * drm_mode_create_tv_properties - create TV specific connector properties
+ * @dev: DRM device
+ * @num_modes: number of different TV formats (modes) supported
+ * @modes: array of pointers to strings containing name of each format
+++ /dev/null
-From 2c0bfade955e4e660941db287020d06c9e22267f Mon Sep 17 00:00:00 2001
-Date: Thu, 11 Jul 2019 15:12:05 +0100
-Subject: [PATCH] drm/vc4: Pass the drm vrefresh to the firmware on
- mode set
-
-More for completeness than need, but use drm_mode_vrefresh
-to compute the vrefresh value, and pass that down to the
-firmware on mode set.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -737,8 +737,8 @@ static void vc4_crtc_mode_set_nofb(struc
- mode->hdisplay, mode->hsync_start, mode->hsync_end,
- mode->htotal, mode->hskew, mode->vdisplay,
- mode->vsync_start, mode->vsync_end, mode->vtotal,
-- mode->vscan, mode->vrefresh, mode->picture_aspect_ratio,
-- mode->flags);
-+ mode->vscan, drm_mode_vrefresh(mode),
-+ mode->picture_aspect_ratio, mode->flags);
- mb.timings.display = vc4_crtc->display_number;
-
- mb.timings.video_id_code = frame.avi.video_code;
-@@ -754,7 +754,7 @@ static void vc4_crtc_mode_set_nofb(struc
- mb.timings.vsync_end = mode->vsync_end;
- mb.timings.vtotal = mode->vtotal;
- mb.timings.vscan = mode->vscan;
-- mb.timings.vrefresh = 0;
-+ mb.timings.vrefresh = drm_mode_vrefresh(mode);
- mb.timings.flags = 0;
- if (mode->flags & DRM_MODE_FLAG_PHSYNC)
- mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS;
--- /dev/null
+From 4589a8a086094061e7476d41578e31349accc190 Mon Sep 17 00:00:00 2001
+Date: Thu, 6 Dec 2018 15:24:36 +0100
+Subject: [PATCH] drm/connector: Clarify the unit of TV margins
+
+Commit 56406e15b5e83256151ef74eb1a219cbf13d91c8 upstream.
+
+All margins are expressed in pixels. Clarify that in the doc.
+
+---
+ include/drm/drm_connector.h | 2 +-
+ include/drm/drm_mode_config.h | 8 ++++----
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/include/drm/drm_connector.h
++++ b/include/drm/drm_connector.h
+@@ -346,7 +346,7 @@ int drm_display_info_set_bus_formats(str
+ /**
+ * struct drm_tv_connector_state - TV connector related states
+ * @subconnector: selected subconnector
+- * @margins: margins
++ * @margins: margins (all margins are expressed in pixels)
+ * @margins.left: left margin
+ * @margins.right: right margin
+ * @margins.top: top margin
+--- a/include/drm/drm_mode_config.h
++++ b/include/drm/drm_mode_config.h
+@@ -668,22 +668,22 @@ struct drm_mode_config {
+ struct drm_property *tv_mode_property;
+ /**
+ * @tv_left_margin_property: Optional TV property to set the left
+- * margin.
++ * margin (expressed in pixels).
+ */
+ struct drm_property *tv_left_margin_property;
+ /**
+ * @tv_right_margin_property: Optional TV property to set the right
+- * margin.
++ * margin (expressed in pixels).
+ */
+ struct drm_property *tv_right_margin_property;
+ /**
+ * @tv_top_margin_property: Optional TV property to set the right
+- * margin.
++ * margin (expressed in pixels).
+ */
+ struct drm_property *tv_top_margin_property;
+ /**
+ * @tv_bottom_margin_property: Optional TV property to set the right
+- * margin.
++ * margin (expressed in pixels).
+ */
+ struct drm_property *tv_bottom_margin_property;
+ /**
+++ /dev/null
-From f42cc245e1f3e586f1a26550e5760489b6c329ab Mon Sep 17 00:00:00 2001
-Date: Tue, 23 Jul 2019 12:55:07 +0100
-Subject: [PATCH] overlays: audremap: Support GPIOs 18 & 19
-
-PWM audio can also be used on GPIOs 18 and 19, so add the pins_18_19
-parameter to select that location. pins_12_13 explicitly chooses GPIOs
-12 and 13, although this is the default behaviour so is there only for
-completeness.
-
-See: https://github.com/raspberrypi/firmware/issues/1178
-
----
- arch/arm/boot/dts/overlays/README | 4 +++-
- arch/arm/boot/dts/overlays/audremap-overlay.dts | 16 ++++++++++++++++
- 2 files changed, 19 insertions(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -475,12 +475,14 @@ Params: <None>
-
-
- Name: audremap
--Info: Switches PWM sound output to pins 12 (Right) & 13 (Left)
-+Info: Switches PWM sound output to GPIOs on the 40-pin header
- Load: dtoverlay=audremap,<param>=<val>
- Params: swap_lr Reverse the channel allocation, which will also
- swap the audio jack outputs (default off)
- enable_jack Don't switch off the audio jack output
- (default off)
-+ pins_12_13 Select GPIOs 12 & 13 (default)
-+ pins_18_19 Select GPIOs 18 & 19
-
-
- Name: balena-fin
---- a/arch/arm/boot/dts/overlays/audremap-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/audremap-overlay.dts
-@@ -7,13 +7,29 @@
- fragment@0 {
- target = <&audio_pins>;
- frag0: __overlay__ {
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&audio_pins>;
-+ __overlay__ {
- brcm,pins = < 12 13 >;
- brcm,function = < 4 >; /* alt0 alt0 */
- };
- };
-
-+ fragment@2 {
-+ target = <&audio_pins>;
-+ __dormant__ {
-+ brcm,pins = < 18 19 >;
-+ brcm,function = < 2 >; /* alt5 alt5 */
-+ };
-+ };
-+
- __overrides__ {
- swap_lr = <&frag0>, "swap_lr?";
- enable_jack = <&frag0>, "enable_jack?";
-+ pins_12_13 = <0>,"+1-2";
-+ pins_18_19 = <0>,"-1+2";
- };
- };
--- /dev/null
+From 4f2277b18d6bbb6fac50b751c4e513619849b23c Mon Sep 17 00:00:00 2001
+Date: Thu, 6 Dec 2018 15:24:37 +0100
+Subject: [PATCH] drm/connector: Allow creation of margin props alone
+
+Commit 6c4f52dca36f5e3e2354c30591d38e92f4657ed9 upstream.
+
+TV margins properties can only be added as part of the SDTV TV
+connector properties creation, but we might need those props for HDMI
+TVs too, so let's move the margins props creation in a separate
+function and expose it to drivers.
+
+We also add an helper to attach margins props to a connector.
+
+---
+ drivers/gpu/drm/drm_connector.c | 83 ++++++++++++++++++++++++++-------
+ include/drm/drm_connector.h | 2 +
+ 2 files changed, 67 insertions(+), 18 deletions(-)
+
+--- a/drivers/gpu/drm/drm_connector.c
++++ b/drivers/gpu/drm/drm_connector.c
+@@ -1110,6 +1110,70 @@ void drm_hdmi_avi_infoframe_content_type
+ EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type);
+
+ /**
++ * drm_mode_attach_tv_margin_properties - attach TV connector margin properties
++ * @connector: DRM connector
++ *
++ * Called by a driver when it needs to attach TV margin props to a connector.
++ * Typically used on SDTV and HDMI connectors.
++ */
++void drm_connector_attach_tv_margin_properties(struct drm_connector *connector)
++{
++ struct drm_device *dev = connector->dev;
++
++ drm_object_attach_property(&connector->base,
++ dev->mode_config.tv_left_margin_property,
++ 0);
++ drm_object_attach_property(&connector->base,
++ dev->mode_config.tv_right_margin_property,
++ 0);
++ drm_object_attach_property(&connector->base,
++ dev->mode_config.tv_top_margin_property,
++ 0);
++ drm_object_attach_property(&connector->base,
++ dev->mode_config.tv_bottom_margin_property,
++ 0);
++}
++EXPORT_SYMBOL(drm_connector_attach_tv_margin_properties);
++
++/**
++ * drm_mode_create_tv_margin_properties - create TV connector margin properties
++ * @dev: DRM device
++ *
++ * Called by a driver's HDMI connector initialization routine, this function
++ * creates the TV margin properties for a given device. No need to call this
++ * function for an SDTV connector, it's already called from
++ * drm_mode_create_tv_properties().
++ */
++int drm_mode_create_tv_margin_properties(struct drm_device *dev)
++{
++ if (dev->mode_config.tv_left_margin_property)
++ return 0;
++
++ dev->mode_config.tv_left_margin_property =
++ drm_property_create_range(dev, 0, "left margin", 0, 100);
++ if (!dev->mode_config.tv_left_margin_property)
++ return -ENOMEM;
++
++ dev->mode_config.tv_right_margin_property =
++ drm_property_create_range(dev, 0, "right margin", 0, 100);
++ if (!dev->mode_config.tv_right_margin_property)
++ return -ENOMEM;
++
++ dev->mode_config.tv_top_margin_property =
++ drm_property_create_range(dev, 0, "top margin", 0, 100);
++ if (!dev->mode_config.tv_top_margin_property)
++ return -ENOMEM;
++
++ dev->mode_config.tv_bottom_margin_property =
++ drm_property_create_range(dev, 0, "bottom margin", 0, 100);
++ if (!dev->mode_config.tv_bottom_margin_property)
++ return -ENOMEM;
++
++ return 0;
++}
++EXPORT_SYMBOL(drm_mode_create_tv_margin_properties);
++
++/**
+ * drm_mode_create_tv_properties - create TV specific connector properties
+ * @dev: DRM device
+ * @num_modes: number of different TV formats (modes) supported
+@@ -1155,24 +1219,7 @@ int drm_mode_create_tv_properties(struct
+ /*
+ * Other, TV specific properties: margins & TV modes.
+ */
+- dev->mode_config.tv_left_margin_property =
+- drm_property_create_range(dev, 0, "left margin", 0, 100);
+- if (!dev->mode_config.tv_left_margin_property)
+- goto nomem;
+-
+- dev->mode_config.tv_right_margin_property =
+- drm_property_create_range(dev, 0, "right margin", 0, 100);
+- if (!dev->mode_config.tv_right_margin_property)
+- goto nomem;
+-
+- dev->mode_config.tv_top_margin_property =
+- drm_property_create_range(dev, 0, "top margin", 0, 100);
+- if (!dev->mode_config.tv_top_margin_property)
+- goto nomem;
+-
+- dev->mode_config.tv_bottom_margin_property =
+- drm_property_create_range(dev, 0, "bottom margin", 0, 100);
+- if (!dev->mode_config.tv_bottom_margin_property)
++ if (drm_mode_create_tv_margin_properties(dev))
+ goto nomem;
+
+ dev->mode_config.tv_mode_property =
+--- a/include/drm/drm_connector.h
++++ b/include/drm/drm_connector.h
+@@ -1175,9 +1175,11 @@ const char *drm_get_tv_select_name(int v
+ const char *drm_get_content_protection_name(int val);
+
+ int drm_mode_create_dvi_i_properties(struct drm_device *dev);
++int drm_mode_create_tv_margin_properties(struct drm_device *dev);
+ int drm_mode_create_tv_properties(struct drm_device *dev,
+ unsigned int num_modes,
+ const char * const modes[]);
++void drm_connector_attach_tv_margin_properties(struct drm_connector *conn);
+ int drm_mode_create_scaling_mode_property(struct drm_device *dev);
+ int drm_connector_attach_content_type_property(struct drm_connector *dev);
+ int drm_connector_attach_scaling_mode_property(struct drm_connector *connector,
+++ /dev/null
-From ce5c3d732efb5e3da50119ed876f0d6661f08b84 Mon Sep 17 00:00:00 2001
-Date: Thu, 6 Dec 2018 15:24:35 +0100
-Subject: [PATCH] drm/connector: Fix drm_mode_create_tv_properties()
- doc
-
-Commit eda6887f1961e0d2fb866b1a520b2de5b3828de5 upstream.
-
-The in the kernel-doc header did not match the function name.
-
----
- drivers/gpu/drm/drm_connector.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/drm_connector.c
-+++ b/drivers/gpu/drm/drm_connector.c
-@@ -1110,7 +1110,7 @@ void drm_hdmi_avi_infoframe_content_type
- EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type);
-
- /**
-- * drm_create_tv_properties - create TV specific connector properties
-+ * drm_mode_create_tv_properties - create TV specific connector properties
- * @dev: DRM device
- * @num_modes: number of different TV formats (modes) supported
- * @modes: array of pointers to strings containing name of each format
+++ /dev/null
-From 4589a8a086094061e7476d41578e31349accc190 Mon Sep 17 00:00:00 2001
-Date: Thu, 6 Dec 2018 15:24:36 +0100
-Subject: [PATCH] drm/connector: Clarify the unit of TV margins
-
-Commit 56406e15b5e83256151ef74eb1a219cbf13d91c8 upstream.
-
-All margins are expressed in pixels. Clarify that in the doc.
-
----
- include/drm/drm_connector.h | 2 +-
- include/drm/drm_mode_config.h | 8 ++++----
- 2 files changed, 5 insertions(+), 5 deletions(-)
-
---- a/include/drm/drm_connector.h
-+++ b/include/drm/drm_connector.h
-@@ -346,7 +346,7 @@ int drm_display_info_set_bus_formats(str
- /**
- * struct drm_tv_connector_state - TV connector related states
- * @subconnector: selected subconnector
-- * @margins: margins
-+ * @margins: margins (all margins are expressed in pixels)
- * @margins.left: left margin
- * @margins.right: right margin
- * @margins.top: top margin
---- a/include/drm/drm_mode_config.h
-+++ b/include/drm/drm_mode_config.h
-@@ -668,22 +668,22 @@ struct drm_mode_config {
- struct drm_property *tv_mode_property;
- /**
- * @tv_left_margin_property: Optional TV property to set the left
-- * margin.
-+ * margin (expressed in pixels).
- */
- struct drm_property *tv_left_margin_property;
- /**
- * @tv_right_margin_property: Optional TV property to set the right
-- * margin.
-+ * margin (expressed in pixels).
- */
- struct drm_property *tv_right_margin_property;
- /**
- * @tv_top_margin_property: Optional TV property to set the right
-- * margin.
-+ * margin (expressed in pixels).
- */
- struct drm_property *tv_top_margin_property;
- /**
- * @tv_bottom_margin_property: Optional TV property to set the right
-- * margin.
-+ * margin (expressed in pixels).
- */
- struct drm_property *tv_bottom_margin_property;
- /**
--- /dev/null
+From 0d592a7685e41d0bb1816a4fedb11d3570474417 Mon Sep 17 00:00:00 2001
+Date: Thu, 6 Dec 2018 15:24:38 +0100
+Subject: [PATCH] drm/vc4: Take margin setup into account when updating
+ planes
+
+Commit 666e73587f90f42d90385c1bea1009a650bf73f4 upstream.
+
+Applyin margins is just a matter of scaling all planes appropriately
+and adjusting the CRTC X/Y offset to account for the
+left/right/top/bottom borders.
+
+Create a vc4_plane_margins_adj() function doing that and call it from
+vc4_plane_setup_clipping_and_scaling() so that we are ready to attach
+margins properties to the HDMI connector.
+
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 43 +++++++++++++++++++++++++++
+ drivers/gpu/drm/vc4/vc4_drv.h | 3 ++
+ drivers/gpu/drm/vc4/vc4_plane.c | 51 +++++++++++++++++++++++++++++++++
+ 3 files changed, 97 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -48,6 +48,13 @@ struct vc4_crtc_state {
+ struct drm_mm_node mm;
+ bool feed_txp;
+ bool txp_armed;
++
++ struct {
++ unsigned int left;
++ unsigned int right;
++ unsigned int top;
++ unsigned int bottom;
++ } margins;
+ };
+
+ static inline struct vc4_crtc_state *
+@@ -623,6 +630,37 @@ static enum drm_mode_status vc4_crtc_mod
+ return MODE_OK;
+ }
+
++void vc4_crtc_get_margins(struct drm_crtc_state *state,
++ unsigned int *left, unsigned int *right,
++ unsigned int *top, unsigned int *bottom)
++{
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++ struct drm_connector_state *conn_state;
++ struct drm_connector *conn;
++ int i;
++
++ *left = vc4_state->margins.left;
++ *right = vc4_state->margins.right;
++ *top = vc4_state->margins.top;
++ *bottom = vc4_state->margins.bottom;
++
++ /* We have to interate over all new connector states because
++ * vc4_crtc_get_margins() might be called before
++ * vc4_crtc_atomic_check() which means margins info in vc4_crtc_state
++ * might be outdated.
++ */
++ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
++ if (conn_state->crtc != state->crtc)
++ continue;
++
++ *left = conn_state->tv.margins.left;
++ *right = conn_state->tv.margins.right;
++ *top = conn_state->tv.margins.top;
++ *bottom = conn_state->tv.margins.bottom;
++ break;
++ }
++}
++
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+ {
+@@ -670,6 +708,10 @@ static int vc4_crtc_atomic_check(struct
+ vc4_state->feed_txp = false;
+ }
+
++ vc4_state->margins.left = conn_state->tv.margins.left;
++ vc4_state->margins.right = conn_state->tv.margins.right;
++ vc4_state->margins.top = conn_state->tv.margins.top;
++ vc4_state->margins.bottom = conn_state->tv.margins.bottom;
+ break;
+ }
+
+@@ -971,6 +1013,7 @@ static struct drm_crtc_state *vc4_crtc_d
+
+ 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;
+
+ __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
+ return &vc4_state->base;
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -705,6 +705,9 @@ bool vc4_crtc_get_scanoutpos(struct drm_
+ const struct drm_display_mode *mode);
+ void vc4_crtc_handle_vblank(struct vc4_crtc *crtc);
+ void vc4_crtc_txp_armed(struct drm_crtc_state *state);
++void vc4_crtc_get_margins(struct drm_crtc_state *state,
++ unsigned int *right, unsigned int *left,
++ unsigned int *top, unsigned int *bottom);
+
+ /* vc4_debugfs.c */
+ int vc4_debugfs_init(struct drm_minor *minor);
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -258,6 +258,52 @@ static u32 vc4_get_scl_field(struct drm_
+ }
+ }
+
++static int vc4_plane_margins_adj(struct drm_plane_state *pstate)
++{
++ struct vc4_plane_state *vc4_pstate = to_vc4_plane_state(pstate);
++ unsigned int left, right, top, bottom, adjhdisplay, adjvdisplay;
++ struct drm_crtc_state *crtc_state;
++
++ crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
++ pstate->crtc);
++
++ vc4_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
++ if (!left && !right && !top && !bottom)
++ return 0;
++
++ if (left + right >= crtc_state->mode.hdisplay ||
++ top + bottom >= crtc_state->mode.vdisplay)
++ return -EINVAL;
++
++ adjhdisplay = crtc_state->mode.hdisplay - (left + right);
++ vc4_pstate->crtc_x = DIV_ROUND_CLOSEST(vc4_pstate->crtc_x *
++ adjhdisplay,
++ crtc_state->mode.hdisplay);
++ vc4_pstate->crtc_x += left;
++ if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - left)
++ vc4_pstate->crtc_x = crtc_state->mode.hdisplay - left;
++
++ adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
++ vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y *
++ adjvdisplay,
++ crtc_state->mode.vdisplay);
++ vc4_pstate->crtc_y += top;
++ if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - top)
++ vc4_pstate->crtc_y = crtc_state->mode.vdisplay - top;
++
++ vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w *
++ adjhdisplay,
++ crtc_state->mode.hdisplay);
++ vc4_pstate->crtc_h = DIV_ROUND_CLOSEST(vc4_pstate->crtc_h *
++ adjvdisplay,
++ crtc_state->mode.vdisplay);
++
++ if (!vc4_pstate->crtc_w || !vc4_pstate->crtc_h)
++ return -EINVAL;
++
++ return 0;
++}
++
+ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
+ {
+ struct drm_plane *plane = state->plane;
+@@ -269,6 +315,7 @@ static int vc4_plane_setup_clipping_and_
+ int num_planes = fb->format->num_planes;
+ u32 h_subsample = 1;
+ u32 v_subsample = 1;
++ int ret;
+ int i;
+
+ for (i = 0; i < num_planes; i++)
+@@ -292,6 +339,10 @@ static int vc4_plane_setup_clipping_and_
+ vc4_state->crtc_w = state->crtc_w;
+ vc4_state->crtc_h = state->crtc_h;
+
++ ret = vc4_plane_margins_adj(state);
++ if (ret)
++ return ret;
++
+ vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
+ vc4_state->crtc_w);
+ vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
+++ /dev/null
-From 4f2277b18d6bbb6fac50b751c4e513619849b23c Mon Sep 17 00:00:00 2001
-Date: Thu, 6 Dec 2018 15:24:37 +0100
-Subject: [PATCH] drm/connector: Allow creation of margin props alone
-
-Commit 6c4f52dca36f5e3e2354c30591d38e92f4657ed9 upstream.
-
-TV margins properties can only be added as part of the SDTV TV
-connector properties creation, but we might need those props for HDMI
-TVs too, so let's move the margins props creation in a separate
-function and expose it to drivers.
-
-We also add an helper to attach margins props to a connector.
-
----
- drivers/gpu/drm/drm_connector.c | 83 ++++++++++++++++++++++++++-------
- include/drm/drm_connector.h | 2 +
- 2 files changed, 67 insertions(+), 18 deletions(-)
-
---- a/drivers/gpu/drm/drm_connector.c
-+++ b/drivers/gpu/drm/drm_connector.c
-@@ -1110,6 +1110,70 @@ void drm_hdmi_avi_infoframe_content_type
- EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type);
-
- /**
-+ * drm_mode_attach_tv_margin_properties - attach TV connector margin properties
-+ * @connector: DRM connector
-+ *
-+ * Called by a driver when it needs to attach TV margin props to a connector.
-+ * Typically used on SDTV and HDMI connectors.
-+ */
-+void drm_connector_attach_tv_margin_properties(struct drm_connector *connector)
-+{
-+ struct drm_device *dev = connector->dev;
-+
-+ drm_object_attach_property(&connector->base,
-+ dev->mode_config.tv_left_margin_property,
-+ 0);
-+ drm_object_attach_property(&connector->base,
-+ dev->mode_config.tv_right_margin_property,
-+ 0);
-+ drm_object_attach_property(&connector->base,
-+ dev->mode_config.tv_top_margin_property,
-+ 0);
-+ drm_object_attach_property(&connector->base,
-+ dev->mode_config.tv_bottom_margin_property,
-+ 0);
-+}
-+EXPORT_SYMBOL(drm_connector_attach_tv_margin_properties);
-+
-+/**
-+ * drm_mode_create_tv_margin_properties - create TV connector margin properties
-+ * @dev: DRM device
-+ *
-+ * Called by a driver's HDMI connector initialization routine, this function
-+ * creates the TV margin properties for a given device. No need to call this
-+ * function for an SDTV connector, it's already called from
-+ * drm_mode_create_tv_properties().
-+ */
-+int drm_mode_create_tv_margin_properties(struct drm_device *dev)
-+{
-+ if (dev->mode_config.tv_left_margin_property)
-+ return 0;
-+
-+ dev->mode_config.tv_left_margin_property =
-+ drm_property_create_range(dev, 0, "left margin", 0, 100);
-+ if (!dev->mode_config.tv_left_margin_property)
-+ return -ENOMEM;
-+
-+ dev->mode_config.tv_right_margin_property =
-+ drm_property_create_range(dev, 0, "right margin", 0, 100);
-+ if (!dev->mode_config.tv_right_margin_property)
-+ return -ENOMEM;
-+
-+ dev->mode_config.tv_top_margin_property =
-+ drm_property_create_range(dev, 0, "top margin", 0, 100);
-+ if (!dev->mode_config.tv_top_margin_property)
-+ return -ENOMEM;
-+
-+ dev->mode_config.tv_bottom_margin_property =
-+ drm_property_create_range(dev, 0, "bottom margin", 0, 100);
-+ if (!dev->mode_config.tv_bottom_margin_property)
-+ return -ENOMEM;
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(drm_mode_create_tv_margin_properties);
-+
-+/**
- * drm_mode_create_tv_properties - create TV specific connector properties
- * @dev: DRM device
- * @num_modes: number of different TV formats (modes) supported
-@@ -1155,24 +1219,7 @@ int drm_mode_create_tv_properties(struct
- /*
- * Other, TV specific properties: margins & TV modes.
- */
-- dev->mode_config.tv_left_margin_property =
-- drm_property_create_range(dev, 0, "left margin", 0, 100);
-- if (!dev->mode_config.tv_left_margin_property)
-- goto nomem;
--
-- dev->mode_config.tv_right_margin_property =
-- drm_property_create_range(dev, 0, "right margin", 0, 100);
-- if (!dev->mode_config.tv_right_margin_property)
-- goto nomem;
--
-- dev->mode_config.tv_top_margin_property =
-- drm_property_create_range(dev, 0, "top margin", 0, 100);
-- if (!dev->mode_config.tv_top_margin_property)
-- goto nomem;
--
-- dev->mode_config.tv_bottom_margin_property =
-- drm_property_create_range(dev, 0, "bottom margin", 0, 100);
-- if (!dev->mode_config.tv_bottom_margin_property)
-+ if (drm_mode_create_tv_margin_properties(dev))
- goto nomem;
-
- dev->mode_config.tv_mode_property =
---- a/include/drm/drm_connector.h
-+++ b/include/drm/drm_connector.h
-@@ -1175,9 +1175,11 @@ const char *drm_get_tv_select_name(int v
- const char *drm_get_content_protection_name(int val);
-
- int drm_mode_create_dvi_i_properties(struct drm_device *dev);
-+int drm_mode_create_tv_margin_properties(struct drm_device *dev);
- int drm_mode_create_tv_properties(struct drm_device *dev,
- unsigned int num_modes,
- const char * const modes[]);
-+void drm_connector_attach_tv_margin_properties(struct drm_connector *conn);
- int drm_mode_create_scaling_mode_property(struct drm_device *dev);
- int drm_connector_attach_content_type_property(struct drm_connector *dev);
- int drm_connector_attach_scaling_mode_property(struct drm_connector *connector,
--- /dev/null
+From efd1df5cd92e4436f863730f666117494613693b Mon Sep 17 00:00:00 2001
+Date: Thu, 6 Dec 2018 15:24:39 +0100
+Subject: [PATCH] drm/vc4: Attach margin props to the HDMI connector
+
+Commit db999538fdb0679629d90652f8a1437df1e85a7d upstream.
+
+Now that the plane code takes the margins setup into account, we can
+safely attach margin props to the HDMI connector.
+
+We also take care of filling AVI infoframes correctly to expose the
+top/botton/left/right bar.
+
+Note that those margin props match pretty well the
+overscan_{left,right,top,bottom} properties defined in config.txt and
+parsed by the VC4 firmware.
+
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -310,6 +310,7 @@ static struct drm_connector *vc4_hdmi_co
+ {
+ struct drm_connector *connector;
+ struct vc4_hdmi_connector *hdmi_connector;
++ int ret;
+
+ hdmi_connector = devm_kzalloc(dev->dev, sizeof(*hdmi_connector),
+ GFP_KERNEL);
+@@ -323,6 +324,13 @@ static struct drm_connector *vc4_hdmi_co
+ DRM_MODE_CONNECTOR_HDMIA);
+ drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
+
++ /* Create and attach TV margin props to this connector. */
++ ret = drm_mode_create_tv_margin_properties(dev);
++ if (ret)
++ return ERR_PTR(ret);
++
++ drm_connector_attach_tv_margin_properties(connector);
++
+ connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT);
+
+@@ -408,6 +416,9 @@ static void vc4_hdmi_write_infoframe(str
+ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+ {
+ struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
++ struct vc4_dev *vc4 = encoder->dev->dev_private;
++ struct vc4_hdmi *hdmi = vc4->hdmi;
++ struct drm_connector_state *cstate = hdmi->connector->state;
+ struct drm_crtc *crtc = encoder->crtc;
+ const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+ union hdmi_infoframe frame;
+@@ -426,6 +437,11 @@ static void vc4_hdmi_set_avi_infoframe(s
+ vc4_encoder->rgb_range_selectable,
+ false);
+
++ frame.avi.right_bar = cstate->tv.margins.right;
++ frame.avi.left_bar = cstate->tv.margins.left;
++ frame.avi.top_bar = cstate->tv.margins.top;
++ frame.avi.bottom_bar = cstate->tv.margins.bottom;
++
+ vc4_hdmi_write_infoframe(encoder, &frame);
+ }
+
--- /dev/null
+From a4e8051901a5d858a69732a3f9734835afc00af5 Mon Sep 17 00:00:00 2001
+Date: Fri, 19 Jul 2019 15:35:13 +0100
+Subject: [PATCH] drm/vc4: Add support for margins to fkms
+
+Allows for overscan to be configured under FKMS.
+NB This is rescaling the planes, not reducing the size of the
+display mode.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 241 +++++++++++++++++++------
+ 1 file changed, 190 insertions(+), 51 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -256,6 +256,23 @@ static inline struct vc4_crtc *to_vc4_cr
+ return container_of(crtc, struct vc4_crtc, base);
+ }
+
++struct vc4_crtc_state {
++ struct drm_crtc_state base;
++
++ struct {
++ unsigned int left;
++ unsigned int right;
++ unsigned int top;
++ unsigned int bottom;
++ } margins;
++};
++
++static inline struct vc4_crtc_state *
++to_vc4_crtc_state(struct drm_crtc_state *crtc_state)
++{
++ return (struct vc4_crtc_state *)crtc_state;
++}
++
+ struct vc4_fkms_encoder {
+ struct drm_encoder base;
+ bool hdmi_monitor;
+@@ -365,17 +382,127 @@ static int vc4_plane_set_blank(struct dr
+ return ret;
+ }
+
++static void vc4_fkms_crtc_get_margins(struct drm_crtc_state *state,
++ unsigned int *left, unsigned int *right,
++ unsigned int *top, unsigned int *bottom)
++{
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++ struct drm_connector_state *conn_state;
++ struct drm_connector *conn;
++ int i;
++
++ *left = vc4_state->margins.left;
++ *right = vc4_state->margins.right;
++ *top = vc4_state->margins.top;
++ *bottom = vc4_state->margins.bottom;
++
++ /* We have to interate over all new connector states because
++ * vc4_fkms_crtc_get_margins() might be called before
++ * vc4_fkms_crtc_atomic_check() which means margins info in
++ * vc4_crtc_state might be outdated.
++ */
++ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
++ if (conn_state->crtc != state->crtc)
++ continue;
++
++ *left = conn_state->tv.margins.left;
++ *right = conn_state->tv.margins.right;
++ *top = conn_state->tv.margins.top;
++ *bottom = conn_state->tv.margins.bottom;
++ break;
++ }
++}
++
++static int vc4_fkms_margins_adj(struct drm_plane_state *pstate,
++ struct set_plane *plane)
++{
++ unsigned int left, right, top, bottom;
++ int adjhdisplay, adjvdisplay;
++ struct drm_crtc_state *crtc_state;
++
++ crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
++ pstate->crtc);
++
++ vc4_fkms_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
++
++ if (!left && !right && !top && !bottom)
++ return 0;
++
++ if (left + right >= crtc_state->mode.hdisplay ||
++ top + bottom >= crtc_state->mode.vdisplay)
++ return -EINVAL;
++
++ adjhdisplay = crtc_state->mode.hdisplay - (left + right);
++ plane->dst_x = DIV_ROUND_CLOSEST(plane->dst_x * adjhdisplay,
++ (int)crtc_state->mode.hdisplay);
++ plane->dst_x += left;
++ if (plane->dst_x > (int)(crtc_state->mode.hdisplay - left))
++ plane->dst_x = crtc_state->mode.hdisplay - left;
++
++ adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
++ plane->dst_y = DIV_ROUND_CLOSEST(plane->dst_y * adjvdisplay,
++ (int)crtc_state->mode.vdisplay);
++ plane->dst_y += top;
++ if (plane->dst_y > (int)(crtc_state->mode.vdisplay - top))
++ plane->dst_y = crtc_state->mode.vdisplay - top;
++
++ plane->dst_w = DIV_ROUND_CLOSEST(plane->dst_w * adjhdisplay,
++ crtc_state->mode.hdisplay);
++ plane->dst_h = DIV_ROUND_CLOSEST(plane->dst_h * adjvdisplay,
++ crtc_state->mode.vdisplay);
++
++ if (!plane->dst_w || !plane->dst_h)
++ return -EINVAL;
++
++ return 0;
++}
++
+ static void vc4_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+ {
+ struct drm_plane_state *state = plane->state;
++
++ /*
++ * Do NOT set now, as we haven't checked if the crtc is active or not.
++ * Set from vc4_plane_set_blank instead.
++ *
++ * If the CRTC is on (or going to be on) and we're enabled,
++ * then unblank. Otherwise, stay blank until CRTC enable.
++ */
++ if (state->crtc->state->active)
++ vc4_plane_set_blank(plane, false);
++}
++
++static void vc4_plane_atomic_disable(struct drm_plane *plane,
++ struct drm_plane_state *old_state)
++{
++ struct drm_plane_state *state = plane->state;
++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
++
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
++ plane->base.id, plane->name,
++ state->crtc_w,
++ state->crtc_h,
++ vc4_plane->mb.plane.vc_image_type,
++ state->crtc_x,
++ state->crtc_y);
++ vc4_plane_set_blank(plane, true);
++}
++
++static bool plane_enabled(struct drm_plane_state *state)
++{
++ return state->fb && state->crtc;
++}
++
++static int vc4_plane_to_mb(struct drm_plane *plane,
++ struct mailbox_set_plane *mb,
++ struct drm_plane_state *state)
++{
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+ const struct drm_format_info *drm_fmt = fb->format;
+ const struct vc_image_format *vc_fmt =
+ vc4_get_vc_image_fmt(drm_fmt->format);
+- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+- struct mailbox_set_plane *mb = &vc4_plane->mb;
+ int num_planes = fb->format->num_planes;
+ struct drm_display_mode *mode = &state->crtc->mode;
+ unsigned int rotation = SUPPORTED_ROTATIONS;
+@@ -417,25 +544,7 @@ static void vc4_plane_atomic_update(stru
+ break;
+ }
+
+- /* FIXME: If the dest rect goes off screen then clip the src rect so we
+- * don't have off-screen pixels.
+- */
+- if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+- /* There is no scaling on the cursor plane, therefore the calcs
+- * to alter the source crop as the cursor goes off the screen
+- * are simple.
+- */
+- if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) {
+- mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x;
+- mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x)
+- << 16;
+- }
+- if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) {
+- mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y;
+- mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y)
+- << 16;
+- }
+- }
++ vc4_fkms_margins_adj(state, &mb->plane);
+
+ if (num_planes > 1) {
+ /* Assume this must be YUV */
+@@ -525,38 +634,19 @@ static void vc4_plane_atomic_update(stru
+ state->alpha,
+ state->normalized_zpos);
+
+- /*
+- * Do NOT set now, as we haven't checked if the crtc is active or not.
+- * Set from vc4_plane_set_blank instead.
+- *
+- * If the CRTC is on (or going to be on) and we're enabled,
+- * then unblank. Otherwise, stay blank until CRTC enable.
+- */
+- if (state->crtc->state->active)
+- vc4_plane_set_blank(plane, false);
++ return 0;
+ }
+
+-static void vc4_plane_atomic_disable(struct drm_plane *plane,
+- struct drm_plane_state *old_state)
++static int vc4_plane_atomic_check(struct drm_plane *plane,
++ struct drm_plane_state *state)
+ {
+- //struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+- struct drm_plane_state *state = plane->state;
+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
+- plane->base.id, plane->name,
+- state->crtc_w,
+- state->crtc_h,
+- vc4_plane->mb.plane.vc_image_type,
+- state->crtc_x,
+- state->crtc_y);
+- vc4_plane_set_blank(plane, true);
+-}
++ if (!plane_enabled(state))
++ return 0;
++
++ return vc4_plane_to_mb(plane, &vc4_plane->mb, state);
+
+-static int vc4_plane_atomic_check(struct drm_plane *plane,
+- struct drm_plane_state *state)
+-{
+- return 0;
+ }
+
+ static void vc4_plane_destroy(struct drm_plane *plane)
+@@ -878,8 +968,23 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+ {
+- DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n",
+- crtc->base.id);
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++ struct drm_connector *conn;
++ struct drm_connector_state *conn_state;
++ int i;
++
++ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", crtc->base.id);
++
++ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
++ if (conn_state->crtc != crtc)
++ continue;
++
++ vc4_state->margins.left = conn_state->tv.margins.left;
++ vc4_state->margins.right = conn_state->tv.margins.right;
++ vc4_state->margins.top = conn_state->tv.margins.top;
++ vc4_state->margins.bottom = conn_state->tv.margins.bottom;
++ break;
++ }
+ return 0;
+ }
+
+@@ -980,6 +1085,33 @@ static int vc4_page_flip(struct drm_crtc
+ return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx);
+ }
+
++static struct drm_crtc_state *
++vc4_crtc_duplicate_state(struct drm_crtc *crtc)
++{
++ struct vc4_crtc_state *vc4_state, *old_vc4_state;
++
++ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
++ if (!vc4_state)
++ return NULL;
++
++ old_vc4_state = to_vc4_crtc_state(crtc->state);
++ vc4_state->margins = old_vc4_state->margins;
++
++ __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
++ return &vc4_state->base;
++}
++
++static void
++vc4_crtc_reset(struct drm_crtc *crtc)
++{
++ if (crtc->state)
++ __drm_atomic_helper_crtc_destroy_state(crtc->state);
++
++ crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
++ if (crtc->state)
++ crtc->state->crtc = crtc;
++}
++
+ static int vc4_fkms_enable_vblank(struct drm_crtc *crtc)
+ {
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+@@ -1007,8 +1139,8 @@ static const struct drm_crtc_funcs vc4_c
+ .set_property = NULL,
+ .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
+ .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
+- .reset = drm_atomic_helper_crtc_reset,
+- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
++ .reset = vc4_crtc_reset,
++ .atomic_duplicate_state = vc4_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .enable_vblank = vc4_fkms_enable_vblank,
+ .disable_vblank = vc4_fkms_disable_vblank,
+@@ -1267,6 +1399,13 @@ vc4_fkms_connector_init(struct drm_devic
+ connector->interlace_allowed = 0;
+ }
+
++ /* Create and attach TV margin props to this connector. */
++ ret = drm_mode_create_tv_margin_properties(dev);
++ if (ret)
++ return ERR_PTR(ret);
++
++ drm_connector_attach_tv_margin_properties(connector);
++
+ connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT);
+
+++ /dev/null
-From 0d592a7685e41d0bb1816a4fedb11d3570474417 Mon Sep 17 00:00:00 2001
-Date: Thu, 6 Dec 2018 15:24:38 +0100
-Subject: [PATCH] drm/vc4: Take margin setup into account when updating
- planes
-
-Commit 666e73587f90f42d90385c1bea1009a650bf73f4 upstream.
-
-Applyin margins is just a matter of scaling all planes appropriately
-and adjusting the CRTC X/Y offset to account for the
-left/right/top/bottom borders.
-
-Create a vc4_plane_margins_adj() function doing that and call it from
-vc4_plane_setup_clipping_and_scaling() so that we are ready to attach
-margins properties to the HDMI connector.
-
----
- drivers/gpu/drm/vc4/vc4_crtc.c | 43 +++++++++++++++++++++++++++
- drivers/gpu/drm/vc4/vc4_drv.h | 3 ++
- drivers/gpu/drm/vc4/vc4_plane.c | 51 +++++++++++++++++++++++++++++++++
- 3 files changed, 97 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_crtc.c
-+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
-@@ -48,6 +48,13 @@ struct vc4_crtc_state {
- struct drm_mm_node mm;
- bool feed_txp;
- bool txp_armed;
-+
-+ struct {
-+ unsigned int left;
-+ unsigned int right;
-+ unsigned int top;
-+ unsigned int bottom;
-+ } margins;
- };
-
- static inline struct vc4_crtc_state *
-@@ -623,6 +630,37 @@ static enum drm_mode_status vc4_crtc_mod
- return MODE_OK;
- }
-
-+void vc4_crtc_get_margins(struct drm_crtc_state *state,
-+ unsigned int *left, unsigned int *right,
-+ unsigned int *top, unsigned int *bottom)
-+{
-+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
-+ struct drm_connector_state *conn_state;
-+ struct drm_connector *conn;
-+ int i;
-+
-+ *left = vc4_state->margins.left;
-+ *right = vc4_state->margins.right;
-+ *top = vc4_state->margins.top;
-+ *bottom = vc4_state->margins.bottom;
-+
-+ /* We have to interate over all new connector states because
-+ * vc4_crtc_get_margins() might be called before
-+ * vc4_crtc_atomic_check() which means margins info in vc4_crtc_state
-+ * might be outdated.
-+ */
-+ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
-+ if (conn_state->crtc != state->crtc)
-+ continue;
-+
-+ *left = conn_state->tv.margins.left;
-+ *right = conn_state->tv.margins.right;
-+ *top = conn_state->tv.margins.top;
-+ *bottom = conn_state->tv.margins.bottom;
-+ break;
-+ }
-+}
-+
- static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_crtc_state *state)
- {
-@@ -670,6 +708,10 @@ static int vc4_crtc_atomic_check(struct
- vc4_state->feed_txp = false;
- }
-
-+ vc4_state->margins.left = conn_state->tv.margins.left;
-+ vc4_state->margins.right = conn_state->tv.margins.right;
-+ vc4_state->margins.top = conn_state->tv.margins.top;
-+ vc4_state->margins.bottom = conn_state->tv.margins.bottom;
- break;
- }
-
-@@ -971,6 +1013,7 @@ static struct drm_crtc_state *vc4_crtc_d
-
- 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;
-
- __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
- return &vc4_state->base;
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -705,6 +705,9 @@ bool vc4_crtc_get_scanoutpos(struct drm_
- const struct drm_display_mode *mode);
- void vc4_crtc_handle_vblank(struct vc4_crtc *crtc);
- void vc4_crtc_txp_armed(struct drm_crtc_state *state);
-+void vc4_crtc_get_margins(struct drm_crtc_state *state,
-+ unsigned int *right, unsigned int *left,
-+ unsigned int *top, unsigned int *bottom);
-
- /* vc4_debugfs.c */
- int vc4_debugfs_init(struct drm_minor *minor);
---- a/drivers/gpu/drm/vc4/vc4_plane.c
-+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -258,6 +258,52 @@ static u32 vc4_get_scl_field(struct drm_
- }
- }
-
-+static int vc4_plane_margins_adj(struct drm_plane_state *pstate)
-+{
-+ struct vc4_plane_state *vc4_pstate = to_vc4_plane_state(pstate);
-+ unsigned int left, right, top, bottom, adjhdisplay, adjvdisplay;
-+ struct drm_crtc_state *crtc_state;
-+
-+ crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
-+ pstate->crtc);
-+
-+ vc4_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
-+ if (!left && !right && !top && !bottom)
-+ return 0;
-+
-+ if (left + right >= crtc_state->mode.hdisplay ||
-+ top + bottom >= crtc_state->mode.vdisplay)
-+ return -EINVAL;
-+
-+ adjhdisplay = crtc_state->mode.hdisplay - (left + right);
-+ vc4_pstate->crtc_x = DIV_ROUND_CLOSEST(vc4_pstate->crtc_x *
-+ adjhdisplay,
-+ crtc_state->mode.hdisplay);
-+ vc4_pstate->crtc_x += left;
-+ if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - left)
-+ vc4_pstate->crtc_x = crtc_state->mode.hdisplay - left;
-+
-+ adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
-+ vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y *
-+ adjvdisplay,
-+ crtc_state->mode.vdisplay);
-+ vc4_pstate->crtc_y += top;
-+ if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - top)
-+ vc4_pstate->crtc_y = crtc_state->mode.vdisplay - top;
-+
-+ vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w *
-+ adjhdisplay,
-+ crtc_state->mode.hdisplay);
-+ vc4_pstate->crtc_h = DIV_ROUND_CLOSEST(vc4_pstate->crtc_h *
-+ adjvdisplay,
-+ crtc_state->mode.vdisplay);
-+
-+ if (!vc4_pstate->crtc_w || !vc4_pstate->crtc_h)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
- static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
- {
- struct drm_plane *plane = state->plane;
-@@ -269,6 +315,7 @@ static int vc4_plane_setup_clipping_and_
- int num_planes = fb->format->num_planes;
- u32 h_subsample = 1;
- u32 v_subsample = 1;
-+ int ret;
- int i;
-
- for (i = 0; i < num_planes; i++)
-@@ -292,6 +339,10 @@ static int vc4_plane_setup_clipping_and_
- vc4_state->crtc_w = state->crtc_w;
- vc4_state->crtc_h = state->crtc_h;
-
-+ ret = vc4_plane_margins_adj(state);
-+ if (ret)
-+ return ret;
-+
- vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
- vc4_state->crtc_w);
- vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
+++ /dev/null
-From efd1df5cd92e4436f863730f666117494613693b Mon Sep 17 00:00:00 2001
-Date: Thu, 6 Dec 2018 15:24:39 +0100
-Subject: [PATCH] drm/vc4: Attach margin props to the HDMI connector
-
-Commit db999538fdb0679629d90652f8a1437df1e85a7d upstream.
-
-Now that the plane code takes the margins setup into account, we can
-safely attach margin props to the HDMI connector.
-
-We also take care of filling AVI infoframes correctly to expose the
-top/botton/left/right bar.
-
-Note that those margin props match pretty well the
-overscan_{left,right,top,bottom} properties defined in config.txt and
-parsed by the VC4 firmware.
-
----
- drivers/gpu/drm/vc4/vc4_hdmi.c | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_hdmi.c
-+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
-@@ -310,6 +310,7 @@ static struct drm_connector *vc4_hdmi_co
- {
- struct drm_connector *connector;
- struct vc4_hdmi_connector *hdmi_connector;
-+ int ret;
-
- hdmi_connector = devm_kzalloc(dev->dev, sizeof(*hdmi_connector),
- GFP_KERNEL);
-@@ -323,6 +324,13 @@ static struct drm_connector *vc4_hdmi_co
- DRM_MODE_CONNECTOR_HDMIA);
- drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
-
-+ /* Create and attach TV margin props to this connector. */
-+ ret = drm_mode_create_tv_margin_properties(dev);
-+ if (ret)
-+ return ERR_PTR(ret);
-+
-+ drm_connector_attach_tv_margin_properties(connector);
-+
- connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
- DRM_CONNECTOR_POLL_DISCONNECT);
-
-@@ -408,6 +416,9 @@ static void vc4_hdmi_write_infoframe(str
- static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
- {
- struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
-+ struct vc4_dev *vc4 = encoder->dev->dev_private;
-+ struct vc4_hdmi *hdmi = vc4->hdmi;
-+ struct drm_connector_state *cstate = hdmi->connector->state;
- struct drm_crtc *crtc = encoder->crtc;
- const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
- union hdmi_infoframe frame;
-@@ -426,6 +437,11 @@ static void vc4_hdmi_set_avi_infoframe(s
- vc4_encoder->rgb_range_selectable,
- false);
-
-+ frame.avi.right_bar = cstate->tv.margins.right;
-+ frame.avi.left_bar = cstate->tv.margins.left;
-+ frame.avi.top_bar = cstate->tv.margins.top;
-+ frame.avi.bottom_bar = cstate->tv.margins.bottom;
-+
- vc4_hdmi_write_infoframe(encoder, &frame);
- }
-
--- /dev/null
+From cf80e05ebb55c121c1567ac42b9e1a885fc346a3 Mon Sep 17 00:00:00 2001
+Date: Fri, 19 Jul 2019 17:49:00 +0100
+Subject: [PATCH] drm/vc4: Ensure zpos is always initialised
+
+The compiler is warning that default_zpos can be used
+uninitialised as there is no default case to catch all plane
+types.
+No other plane types should ever be presented to vc4_fkms_plane_init,
+but add a default case regardless.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -773,6 +773,7 @@ static struct drm_plane *vc4_fkms_plane_
+ * other layers as requested by KMS.
+ */
+ switch (type) {
++ default:
+ case DRM_PLANE_TYPE_PRIMARY:
+ default_zpos = 0;
+ break;
+++ /dev/null
-From a4e8051901a5d858a69732a3f9734835afc00af5 Mon Sep 17 00:00:00 2001
-Date: Fri, 19 Jul 2019 15:35:13 +0100
-Subject: [PATCH] drm/vc4: Add support for margins to fkms
-
-Allows for overscan to be configured under FKMS.
-NB This is rescaling the planes, not reducing the size of the
-display mode.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 241 +++++++++++++++++++------
- 1 file changed, 190 insertions(+), 51 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -256,6 +256,23 @@ static inline struct vc4_crtc *to_vc4_cr
- return container_of(crtc, struct vc4_crtc, base);
- }
-
-+struct vc4_crtc_state {
-+ struct drm_crtc_state base;
-+
-+ struct {
-+ unsigned int left;
-+ unsigned int right;
-+ unsigned int top;
-+ unsigned int bottom;
-+ } margins;
-+};
-+
-+static inline struct vc4_crtc_state *
-+to_vc4_crtc_state(struct drm_crtc_state *crtc_state)
-+{
-+ return (struct vc4_crtc_state *)crtc_state;
-+}
-+
- struct vc4_fkms_encoder {
- struct drm_encoder base;
- bool hdmi_monitor;
-@@ -365,17 +382,127 @@ static int vc4_plane_set_blank(struct dr
- return ret;
- }
-
-+static void vc4_fkms_crtc_get_margins(struct drm_crtc_state *state,
-+ unsigned int *left, unsigned int *right,
-+ unsigned int *top, unsigned int *bottom)
-+{
-+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
-+ struct drm_connector_state *conn_state;
-+ struct drm_connector *conn;
-+ int i;
-+
-+ *left = vc4_state->margins.left;
-+ *right = vc4_state->margins.right;
-+ *top = vc4_state->margins.top;
-+ *bottom = vc4_state->margins.bottom;
-+
-+ /* We have to interate over all new connector states because
-+ * vc4_fkms_crtc_get_margins() might be called before
-+ * vc4_fkms_crtc_atomic_check() which means margins info in
-+ * vc4_crtc_state might be outdated.
-+ */
-+ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
-+ if (conn_state->crtc != state->crtc)
-+ continue;
-+
-+ *left = conn_state->tv.margins.left;
-+ *right = conn_state->tv.margins.right;
-+ *top = conn_state->tv.margins.top;
-+ *bottom = conn_state->tv.margins.bottom;
-+ break;
-+ }
-+}
-+
-+static int vc4_fkms_margins_adj(struct drm_plane_state *pstate,
-+ struct set_plane *plane)
-+{
-+ unsigned int left, right, top, bottom;
-+ int adjhdisplay, adjvdisplay;
-+ struct drm_crtc_state *crtc_state;
-+
-+ crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
-+ pstate->crtc);
-+
-+ vc4_fkms_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
-+
-+ if (!left && !right && !top && !bottom)
-+ return 0;
-+
-+ if (left + right >= crtc_state->mode.hdisplay ||
-+ top + bottom >= crtc_state->mode.vdisplay)
-+ return -EINVAL;
-+
-+ adjhdisplay = crtc_state->mode.hdisplay - (left + right);
-+ plane->dst_x = DIV_ROUND_CLOSEST(plane->dst_x * adjhdisplay,
-+ (int)crtc_state->mode.hdisplay);
-+ plane->dst_x += left;
-+ if (plane->dst_x > (int)(crtc_state->mode.hdisplay - left))
-+ plane->dst_x = crtc_state->mode.hdisplay - left;
-+
-+ adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
-+ plane->dst_y = DIV_ROUND_CLOSEST(plane->dst_y * adjvdisplay,
-+ (int)crtc_state->mode.vdisplay);
-+ plane->dst_y += top;
-+ if (plane->dst_y > (int)(crtc_state->mode.vdisplay - top))
-+ plane->dst_y = crtc_state->mode.vdisplay - top;
-+
-+ plane->dst_w = DIV_ROUND_CLOSEST(plane->dst_w * adjhdisplay,
-+ crtc_state->mode.hdisplay);
-+ plane->dst_h = DIV_ROUND_CLOSEST(plane->dst_h * adjvdisplay,
-+ crtc_state->mode.vdisplay);
-+
-+ if (!plane->dst_w || !plane->dst_h)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
- static void vc4_plane_atomic_update(struct drm_plane *plane,
- struct drm_plane_state *old_state)
- {
- struct drm_plane_state *state = plane->state;
-+
-+ /*
-+ * Do NOT set now, as we haven't checked if the crtc is active or not.
-+ * Set from vc4_plane_set_blank instead.
-+ *
-+ * If the CRTC is on (or going to be on) and we're enabled,
-+ * then unblank. Otherwise, stay blank until CRTC enable.
-+ */
-+ if (state->crtc->state->active)
-+ vc4_plane_set_blank(plane, false);
-+}
-+
-+static void vc4_plane_atomic_disable(struct drm_plane *plane,
-+ struct drm_plane_state *old_state)
-+{
-+ struct drm_plane_state *state = plane->state;
-+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
-+
-+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
-+ plane->base.id, plane->name,
-+ state->crtc_w,
-+ state->crtc_h,
-+ vc4_plane->mb.plane.vc_image_type,
-+ state->crtc_x,
-+ state->crtc_y);
-+ vc4_plane_set_blank(plane, true);
-+}
-+
-+static bool plane_enabled(struct drm_plane_state *state)
-+{
-+ return state->fb && state->crtc;
-+}
-+
-+static int vc4_plane_to_mb(struct drm_plane *plane,
-+ struct mailbox_set_plane *mb,
-+ struct drm_plane_state *state)
-+{
- struct drm_framebuffer *fb = state->fb;
- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
- const struct drm_format_info *drm_fmt = fb->format;
- const struct vc_image_format *vc_fmt =
- vc4_get_vc_image_fmt(drm_fmt->format);
-- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
-- struct mailbox_set_plane *mb = &vc4_plane->mb;
- int num_planes = fb->format->num_planes;
- struct drm_display_mode *mode = &state->crtc->mode;
- unsigned int rotation = SUPPORTED_ROTATIONS;
-@@ -417,25 +544,7 @@ static void vc4_plane_atomic_update(stru
- break;
- }
-
-- /* FIXME: If the dest rect goes off screen then clip the src rect so we
-- * don't have off-screen pixels.
-- */
-- if (plane->type == DRM_PLANE_TYPE_CURSOR) {
-- /* There is no scaling on the cursor plane, therefore the calcs
-- * to alter the source crop as the cursor goes off the screen
-- * are simple.
-- */
-- if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) {
-- mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x;
-- mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x)
-- << 16;
-- }
-- if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) {
-- mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y;
-- mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y)
-- << 16;
-- }
-- }
-+ vc4_fkms_margins_adj(state, &mb->plane);
-
- if (num_planes > 1) {
- /* Assume this must be YUV */
-@@ -525,38 +634,19 @@ static void vc4_plane_atomic_update(stru
- state->alpha,
- state->normalized_zpos);
-
-- /*
-- * Do NOT set now, as we haven't checked if the crtc is active or not.
-- * Set from vc4_plane_set_blank instead.
-- *
-- * If the CRTC is on (or going to be on) and we're enabled,
-- * then unblank. Otherwise, stay blank until CRTC enable.
-- */
-- if (state->crtc->state->active)
-- vc4_plane_set_blank(plane, false);
-+ return 0;
- }
-
--static void vc4_plane_atomic_disable(struct drm_plane *plane,
-- struct drm_plane_state *old_state)
-+static int vc4_plane_atomic_check(struct drm_plane *plane,
-+ struct drm_plane_state *state)
- {
-- //struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
-- struct drm_plane_state *state = plane->state;
- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
-
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
-- plane->base.id, plane->name,
-- state->crtc_w,
-- state->crtc_h,
-- vc4_plane->mb.plane.vc_image_type,
-- state->crtc_x,
-- state->crtc_y);
-- vc4_plane_set_blank(plane, true);
--}
-+ if (!plane_enabled(state))
-+ return 0;
-+
-+ return vc4_plane_to_mb(plane, &vc4_plane->mb, state);
-
--static int vc4_plane_atomic_check(struct drm_plane *plane,
-- struct drm_plane_state *state)
--{
-- return 0;
- }
-
- static void vc4_plane_destroy(struct drm_plane *plane)
-@@ -878,8 +968,23 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
- static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_crtc_state *state)
- {
-- DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n",
-- crtc->base.id);
-+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
-+ struct drm_connector *conn;
-+ struct drm_connector_state *conn_state;
-+ int i;
-+
-+ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", crtc->base.id);
-+
-+ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
-+ if (conn_state->crtc != crtc)
-+ continue;
-+
-+ vc4_state->margins.left = conn_state->tv.margins.left;
-+ vc4_state->margins.right = conn_state->tv.margins.right;
-+ vc4_state->margins.top = conn_state->tv.margins.top;
-+ vc4_state->margins.bottom = conn_state->tv.margins.bottom;
-+ break;
-+ }
- return 0;
- }
-
-@@ -980,6 +1085,33 @@ static int vc4_page_flip(struct drm_crtc
- return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx);
- }
-
-+static struct drm_crtc_state *
-+vc4_crtc_duplicate_state(struct drm_crtc *crtc)
-+{
-+ struct vc4_crtc_state *vc4_state, *old_vc4_state;
-+
-+ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
-+ if (!vc4_state)
-+ return NULL;
-+
-+ old_vc4_state = to_vc4_crtc_state(crtc->state);
-+ vc4_state->margins = old_vc4_state->margins;
-+
-+ __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
-+ return &vc4_state->base;
-+}
-+
-+static void
-+vc4_crtc_reset(struct drm_crtc *crtc)
-+{
-+ if (crtc->state)
-+ __drm_atomic_helper_crtc_destroy_state(crtc->state);
-+
-+ crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
-+ if (crtc->state)
-+ crtc->state->crtc = crtc;
-+}
-+
- static int vc4_fkms_enable_vblank(struct drm_crtc *crtc)
- {
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-@@ -1007,8 +1139,8 @@ static const struct drm_crtc_funcs vc4_c
- .set_property = NULL,
- .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
- .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
-- .reset = drm_atomic_helper_crtc_reset,
-- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
-+ .reset = vc4_crtc_reset,
-+ .atomic_duplicate_state = vc4_crtc_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
- .enable_vblank = vc4_fkms_enable_vblank,
- .disable_vblank = vc4_fkms_disable_vblank,
-@@ -1267,6 +1399,13 @@ vc4_fkms_connector_init(struct drm_devic
- connector->interlace_allowed = 0;
- }
-
-+ /* Create and attach TV margin props to this connector. */
-+ ret = drm_mode_create_tv_margin_properties(dev);
-+ if (ret)
-+ return ERR_PTR(ret);
-+
-+ drm_connector_attach_tv_margin_properties(connector);
-+
- connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
- DRM_CONNECTOR_POLL_DISCONNECT);
-
--- /dev/null
+From a78d4d81c585a5de61e7fc7d574e6e3f769c18a6 Mon Sep 17 00:00:00 2001
+Date: Wed, 24 Jul 2019 14:36:53 +0100
+Subject: [PATCH] dts: bcm2838: add missing properties for pmu and gic
+ nodes
+
+The GIC has a virtual interface maintenance interrupt and the PMU
+interrupts need affinity mappings as they are wired to generic SPIs.
+
+Also, delete incorrect PMU compatible string.
+
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -35,6 +35,8 @@
+ <0x40042000 0x2000>,
+ <0x40044000 0x2000>,
+ <0x40046000 0x2000>;
++ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_HIGH)>;
+ };
+
+ thermal: thermal@7d5d2200 {
+@@ -222,15 +224,12 @@
+ };
+
+ arm-pmu {
+- /*
+- * N.B. the A72 PMU support only exists in arch/arm64, hence
+- * the fallback to the A53 version.
+- */
+- compatible = "arm,cortex-a72-pmu", "arm,cortex-a53-pmu";
++ compatible = "arm,cortex-a72-pmu";
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+ };
+
+ timer {
--- /dev/null
+From bab5f8832c6b2859caea1cb5af1ffcb6276c2f74 Mon Sep 17 00:00:00 2001
+Date: Tue, 23 Jul 2019 16:57:35 +0200
+Subject: [PATCH] adds the Hifiberry DAC+ADC PRO version
+
+This adds the driver for the DAC+ADC PRO version of the Hifiberry soundcard with software controlled PCM1863 ADC
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 21 +
+ .../hifiberry-dacplusadcpro-overlay.dts | 64 +++
+ sound/soc/bcm/Kconfig | 8 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/hifiberry_dacplusadcpro.c | 538 ++++++++++++++++++
+ 9 files changed, 637 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
+ create mode 100644 sound/soc/bcm/hifiberry_dacplusadcpro.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -53,6 +53,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ hifiberry-dac.dtbo \
+ hifiberry-dacplus.dtbo \
+ hifiberry-dacplusadc.dtbo \
++ hifiberry-dacplusadcpro.dtbo \
+ hifiberry-digi.dtbo \
+ hifiberry-digi-pro.dtbo \
+ hy28a.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -883,6 +883,27 @@ Params: 24db_digital_gain Allow ga
+ master for bit clock and frame clock.
+
+
++Name: hifiberry-dacplusadcpro
++Info: Configures the HifiBerry DAC+ADC PRO audio card
++Load: dtoverlay=hifiberry-dacplusadcpro,<param>=<val>
++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
++ Digital volume control. Enable with
++ "dtoverlay=hifiberry-dacplusadcpro,24db_digital_gain"
++ (The default behaviour is that the Digital
++ volume control is limited to a maximum of
++ 0dB. ie. it can attenuate but not provide
++ gain. For most users, this will be desired
++ as it will prevent clipping. By appending
++ the 24dB_digital_gain parameter, the Digital
++ volume control will allow up to 24dB of
++ gain. If this parameter is enabled, it is the
++ responsibility of the user to ensure that
++ the Digital volume control is set to a value
++ that does not result in clipping/distortion!)
++ slave Force DAC+ADC Pro into slave mode, using Pi as
++ master for bit clock and frame clock.
++
++
+ Name: hifiberry-digi
+ Info: Configures the HifiBerry Digi and Digi+ audio card
+ Load: dtoverlay=hifiberry-digi
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
+@@ -0,0 +1,64 @@
++// Definitions for HiFiBerry DAC+ADC PRO
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target-path = "/clocks";
++ __overlay__ {
++ dacpro_osc: dacpro_osc {
++ compatible = "hifiberry,dacpro-clk";
++ #clock-cells = <0>;
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ hb_dac: pcm5122@4d {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm5122";
++ reg = <0x4d>;
++ clocks = <&dacpro_osc>;
++ status = "okay";
++ };
++ hb_adc: pcm186x@4a {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm1863";
++ reg = <0x4a>;
++ clocks = <&dacpro_osc>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&sound>;
++ hifiberry_dacplusadcpro: __overlay__ {
++ compatible = "hifiberry,hifiberry-dacplusadcpro";
++ audio-codec = <&hb_dac &hb_adc>;
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ 24db_digital_gain =
++ <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,24db_digital_gain?";
++ slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?";
++ };
++};
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -48,6 +48,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
+ help
+ Say Y or M if you want to add support for HifiBerry DAC+ADC.
+
++config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO
++ tristate "Support for HifiBerry DAC+ADC PRO"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_PCM512x_I2C
++ select SND_SOC_PCM186X_I2C
++ help
++ Say Y or M if you want to add support for HifiBerry DAC+ADC PRO.
++
+ config SND_BCM2708_SOC_HIFIBERRY_DIGI
+ tristate "Support for HifiBerry Digi"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -14,6 +14,7 @@ snd-soc-googlevoicehat-codec-objs := goo
+ # BCM2708 Machine Support
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
+ snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
++snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
+ snd-soc-justboom-dac-objs := justboom-dac.o
+ snd-soc-rpi-cirrus-objs := rpi-cirrus.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+@@ -38,6 +39,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi
+ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
+ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+--- /dev/null
++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
+@@ -0,0 +1,538 @@
++/*
++ * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC PRO Version (SW control)
++ *
++ * Copyright 2014-2015
++ * Copyright 2018-19
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/kernel.h>
++#include <linux/clk.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++#include <sound/tlv.h>
++
++#include "../codecs/pcm512x.h"
++#include "../codecs/pcm186x.h"
++
++#define HIFIBERRY_DACPRO_NOCLOCK 0
++#define HIFIBERRY_DACPRO_CLK44EN 1
++#define HIFIBERRY_DACPRO_CLK48EN 2
++
++struct pcm512x_priv {
++ struct regmap *regmap;
++ struct clk *sclk;
++};
++
++/* Clock rate of CLK44EN attached to GPIO6 pin */
++#define CLK_44EN_RATE 22579200UL
++/* Clock rate of CLK48EN attached to GPIO3 pin */
++#define CLK_48EN_RATE 24576000UL
++
++static bool slave;
++static bool snd_rpi_hifiberry_is_dacpro;
++static bool digital_gain_0db_limit = true;
++
++static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
++ 0x00, 0x01, 0x02, 0x03, 0x10
++};
++
++static const char * const pcm186x_adcl_input_channel_sel_text[] = {
++ "No Select",
++ "VINL1[SE]", /* Default for ADCL */
++ "VINL2[SE]",
++ "VINL2[SE] + VINL1[SE]",
++ "{VIN1P, VIN1M}[DIFF]"
++};
++
++static const char * const pcm186x_adcr_input_channel_sel_text[] = {
++ "No Select",
++ "VINR1[SE]", /* Default for ADCR */
++ "VINR2[SE]",
++ "VINR2[SE] + VINR1[SE]",
++ "{VIN2P, VIN2M}[DIFF]"
++};
++
++static const struct soc_enum pcm186x_adc_input_channel_sel[] = {
++ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0,
++ PCM186X_ADC_INPUT_SEL_MASK,
++ ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
++ pcm186x_adcl_input_channel_sel_text,
++ pcm186x_adc_input_channel_sel_value),
++ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0,
++ PCM186X_ADC_INPUT_SEL_MASK,
++ ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
++ pcm186x_adcr_input_channel_sel_text,
++ pcm186x_adc_input_channel_sel_value),
++};
++
++static const unsigned int pcm186x_mic_bias_sel_value[] = {
++ 0x00, 0x01, 0x11
++};
++
++static const char * const pcm186x_mic_bias_sel_text[] = {
++ "Mic Bias off",
++ "Mic Bias on",
++ "Mic Bias with Bypass Resistor"
++};
++
++static const struct soc_enum pcm186x_mic_bias_sel[] = {
++ SOC_VALUE_ENUM_SINGLE(PCM186X_MIC_BIAS_CTRL, 0,
++ GENMASK(4, 0),
++ ARRAY_SIZE(pcm186x_mic_bias_sel_text),
++ pcm186x_mic_bias_sel_text,
++ pcm186x_mic_bias_sel_value),
++};
++
++static const unsigned int pcm186x_gain_sel_value[] = {
++ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
++ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
++ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
++ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
++ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
++ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
++ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
++ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
++ 0x50
++};
++
++static const char * const pcm186x_gain_sel_text[] = {
++ "-12.0dB", "-11.5dB", "-11.0dB", "-10.5dB", "-10.0dB", "-9.5dB",
++ "-9.0dB", "-8.5dB", "-8.0dB", "-7.5dB", "-7.0dB", "-6.5dB",
++ "-6.0dB", "-5.5dB", "-5.0dB", "-4.5dB", "-4.0dB", "-3.5dB",
++ "-3.0dB", "-2.5dB", "-2.0dB", "-1.5dB", "-1.0dB", "-0.5dB",
++ "0.0dB", "0.5dB", "1.0dB", "1.5dB", "2.0dB", "2.5dB",
++ "3.0dB", "3.5dB", "4.0dB", "4.5dB", "5.0dB", "5.5dB",
++ "6.0dB", "6.5dB", "7.0dB", "7.5dB", "8.0dB", "8.5dB",
++ "9.0dB", "9.5dB", "10.0dB", "10.5dB", "11.0dB", "11.5dB",
++ "12.0dB", "12.5dB", "13.0dB", "13.5dB", "14.0dB", "14.5dB",
++ "15.0dB", "15.5dB", "16.0dB", "16.5dB", "17.0dB", "17.5dB",
++ "18.0dB", "18.5dB", "19.0dB", "19.5dB", "20.0dB", "20.5dB",
++ "21.0dB", "21.5dB", "22.0dB", "22.5dB", "23.0dB", "23.5dB",
++ "24.0dB", "24.5dB", "25.0dB", "25.5dB", "26.0dB", "26.5dB",
++ "27.0dB", "27.5dB", "28.0dB", "28.5dB", "29.0dB", "29.5dB",
++ "30.0dB", "30.5dB", "31.0dB", "31.5dB", "32.0dB", "32.5dB",
++ "33.0dB", "33.5dB", "34.0dB", "34.5dB", "35.0dB", "35.5dB",
++ "36.0dB", "36.5dB", "37.0dB", "37.5dB", "38.0dB", "38.5dB",
++ "39.0dB", "39.5dB", "40.0dB"};
++
++static const struct soc_enum pcm186x_gain_sel[] = {
++ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_L, 0,
++ 0xff,
++ ARRAY_SIZE(pcm186x_gain_sel_text),
++ pcm186x_gain_sel_text,
++ pcm186x_gain_sel_value),
++ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_R, 0,
++ 0xff,
++ ARRAY_SIZE(pcm186x_gain_sel_text),
++ pcm186x_gain_sel_text,
++ pcm186x_gain_sel_value),
++};
++
++static const struct snd_kcontrol_new pcm1863_snd_controls_card[] = {
++ SOC_ENUM("ADC Left Input", pcm186x_adc_input_channel_sel[0]),
++ SOC_ENUM("ADC Right Input", pcm186x_adc_input_channel_sel[1]),
++ SOC_ENUM("ADC Mic Bias", pcm186x_mic_bias_sel),
++ SOC_ENUM("PGA Gain Left", pcm186x_gain_sel[0]),
++ SOC_ENUM("PGA Gain Right", pcm186x_gain_sel[1]),
++};
++
++static int pcm1863_add_controls(struct snd_soc_component *component)
++{
++ snd_soc_add_component_controls(component,
++ pcm1863_snd_controls_card,
++ ARRAY_SIZE(pcm1863_snd_controls_card));
++ return 0;
++}
++
++static void snd_rpi_hifiberry_dacplusadcpro_select_clk(
++ struct snd_soc_component *component, int clk_id)
++{
++ switch (clk_id) {
++ case HIFIBERRY_DACPRO_NOCLOCK:
++ snd_soc_component_update_bits(component,
++ PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
++ break;
++ case HIFIBERRY_DACPRO_CLK44EN:
++ snd_soc_component_update_bits(component,
++ PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
++ break;
++ case HIFIBERRY_DACPRO_CLK48EN:
++ snd_soc_component_update_bits(component,
++ PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
++ break;
++ }
++}
++
++static void snd_rpi_hifiberry_dacplusadcpro_clk_gpio(struct snd_soc_component *component)
++{
++ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24);
++ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
++ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
++}
++
++static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk(struct snd_soc_component *component)
++{
++ unsigned int sck;
++
++ snd_soc_component_read(component, PCM512x_RATE_DET_4, &sck);
++ return (!(sck & 0x40));
++}
++
++static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(
++ struct snd_soc_component *component)
++{
++ msleep(2);
++ return snd_rpi_hifiberry_dacplusadcpro_is_sclk(component);
++}
++
++static bool snd_rpi_hifiberry_dacplusadcpro_is_pro_card(struct snd_soc_component *component)
++{
++ bool isClk44EN, isClk48En, isNoClk;
++
++ snd_rpi_hifiberry_dacplusadcpro_clk_gpio(component);
++
++ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK44EN);
++ isClk44EN = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component);
++
++ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK);
++ isNoClk = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component);
++
++ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK48EN);
++ isClk48En = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component);
++
++ return (isClk44EN && isClk48En && !isNoClk);
++}
++
++static int snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(int sample_rate)
++{
++ int type;
++
++ switch (sample_rate) {
++ case 11025:
++ case 22050:
++ case 44100:
++ case 88200:
++ case 176400:
++ case 352800:
++ type = HIFIBERRY_DACPRO_CLK44EN;
++ break;
++ default:
++ type = HIFIBERRY_DACPRO_CLK48EN;
++ break;
++ }
++ return type;
++}
++
++static void snd_rpi_hifiberry_dacplusadcpro_set_sclk(struct snd_soc_component *component,
++ int sample_rate)
++{
++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
++
++ if (!IS_ERR(pcm512x->sclk)) {
++ int ctype;
++
++ ctype = snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(sample_rate);
++ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN)
++ ? CLK_44EN_RATE : CLK_48EN_RATE);
++ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, ctype);
++ }
++}
++
++static int snd_rpi_hifiberry_dacplusadcpro_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
++ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
++ struct snd_soc_dai_driver *adc_driver = rtd->codec_dais[1]->driver;
++ struct pcm512x_priv *priv;
++ int ret;
++
++ if (slave)
++ snd_rpi_hifiberry_is_dacpro = false;
++ else
++ snd_rpi_hifiberry_is_dacpro =
++ snd_rpi_hifiberry_dacplusadcpro_is_pro_card(dac);
++
++ if (snd_rpi_hifiberry_is_dacpro) {
++ struct snd_soc_dai_link *dai = rtd->dai_link;
++
++ dai->name = "HiFiBerry DAC+ADC Pro";
++ dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi";
++
++ // set DAC DAI configuration
++ ret = snd_soc_dai_set_fmt(rtd->codec_dais[0],
++ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBM_CFM);
++ if (ret < 0)
++ return ret;
++
++ // set ADC DAI configuration
++ ret = snd_soc_dai_set_fmt(rtd->codec_dais[1],
++ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBS_CFS);
++ if (ret < 0)
++ return ret;
++
++ // set CPU DAI configuration
++ ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
++ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ if (ret < 0)
++ return ret;
++
++ snd_soc_component_update_bits(dac, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
++ snd_soc_component_update_bits(dac, PCM512x_MASTER_MODE, 0x03, 0x03);
++ snd_soc_component_update_bits(dac, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
++ } else {
++ priv = snd_soc_component_get_drvdata(dac);
++ priv->sclk = ERR_PTR(-ENOENT);
++ }
++
++ /* disable 24bit mode as long as I2S module does not have sign extension fixed */
++ adc_driver->capture.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE;
++
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++
++ ret = pcm1863_add_controls(adc);
++ if (ret < 0)
++ dev_warn(rtd->dev, "Failed to add pcm1863 controls: %d\n",
++ ret);
++
++ /* set GPIO2 to output, GPIO3 input */
++ snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00);
++ snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04);
++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
++
++ if (digital_gain_0db_limit) {
++ int ret;
++ struct snd_soc_card *card = rtd->card;
++
++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
++ }
++
++ return 0;
++}
++
++static int snd_rpi_hifiberry_dacplusadcpro_update_rate_den(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *component = rtd->codec_dais[0]->component; /* only use DAC */
++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
++ struct snd_ratnum *rats_no_pll;
++ unsigned int num = 0, den = 0;
++ int err;
++
++ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
++ if (!rats_no_pll)
++ return -ENOMEM;
++
++ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
++ rats_no_pll->den_min = 1;
++ rats_no_pll->den_max = 128;
++ rats_no_pll->den_step = 1;
++
++ err = snd_interval_ratnum(hw_param_interval(params,
++ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
++ if (err >= 0 && den) {
++ params->rate_num = num;
++ params->rate_den = den;
++ }
++
++ devm_kfree(rtd->dev, rats_no_pll);
++ return 0;
++}
++
++static int snd_rpi_hifiberry_dacplusadcpro_hw_params(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ int ret = 0;
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ int channels = params_channels(params);
++ int width = 32;
++ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
++
++ if (snd_rpi_hifiberry_is_dacpro) {
++
++ width = snd_pcm_format_physical_width(params_format(params));
++
++ snd_rpi_hifiberry_dacplusadcpro_set_sclk(dac,
++ params_rate(params));
++
++ ret = snd_rpi_hifiberry_dacplusadcpro_update_rate_den(
++ substream, params);
++ if (ret)
++ return ret;
++ }
++
++ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x03, 0x03,
++ channels, width);
++ if (ret)
++ return ret;
++ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[0], 0x03, 0x03,
++ channels, width);
++ if (ret)
++ return ret;
++ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x03, 0x03,
++ channels, width);
++ return ret;
++}
++
++static int snd_rpi_hifiberry_dacplusadcpro_startup(
++ struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
++ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
++
++ /* switch on respective LED */
++ if (!substream->stream)
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++ else
++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
++ return 0;
++}
++
++static void snd_rpi_hifiberry_dacplusadcpro_shutdown(
++ struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
++ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
++
++ /* switch off respective LED */
++ if (!substream->stream)
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++ else
++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00);
++}
++
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_hifiberry_dacplusadcpro_ops = {
++ .hw_params = snd_rpi_hifiberry_dacplusadcpro_hw_params,
++ .startup = snd_rpi_hifiberry_dacplusadcpro_startup,
++ .shutdown = snd_rpi_hifiberry_dacplusadcpro_shutdown,
++};
++
++static struct snd_soc_dai_link_component snd_rpi_hifiberry_dacplusadcpro_codecs[] = {
++ {
++ .name = "pcm512x.1-004d",
++ .dai_name = "pcm512x-hifi",
++ },
++ {
++ .name = "pcm186x.1-004a",
++ .dai_name = "pcm1863-aif",
++ },
++};
++
++static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadcpro_dai[] = {
++{
++ .name = "HiFiBerry DAC+ADC PRO",
++ .stream_name = "HiFiBerry DAC+ADC PRO HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .platform_name = "bcm2708-i2s.0",
++ .codecs = snd_rpi_hifiberry_dacplusadcpro_codecs,
++ .num_codecs = 2,
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_hifiberry_dacplusadcpro_ops,
++ .init = snd_rpi_hifiberry_dacplusadcpro_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_hifiberry_dacplusadcpro = {
++ .name = "snd_rpi_hifiberry_dacplusadcpro",
++ .driver_name = "HifiberryDacpAdcPro",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_hifiberry_dacplusadcpro_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplusadcpro_dai),
++};
++
++static int snd_rpi_hifiberry_dacplusadcpro_probe(struct platform_device *pdev)
++{
++ int ret = 0, i = 0;
++ struct snd_soc_card *card = &snd_rpi_hifiberry_dacplusadcpro;
++
++ snd_rpi_hifiberry_dacplusadcpro.dev = &pdev->dev;
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai;
++
++ dai = &snd_rpi_hifiberry_dacplusadcpro_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++ if (i2s_node) {
++ for (i = 0; i < card->num_links; i++) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++ }
++ digital_gain_0db_limit = !of_property_read_bool(
++ pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain");
++ slave = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplusadcpro,slave");
++ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro);
++ if (ret && ret != -EPROBE_DEFER)
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++
++ return ret;
++}
++
++static const struct of_device_id snd_rpi_hifiberry_dacplusadcpro_of_match[] = {
++ { .compatible = "hifiberry,hifiberry-dacplusadcpro", },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplusadcpro_of_match);
++
++static struct platform_driver snd_rpi_hifiberry_dacplusadcpro_driver = {
++ .driver = {
++ .name = "snd-rpi-hifiberry-dacplusadcpro",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_hifiberry_dacplusadcpro_of_match,
++ },
++ .probe = snd_rpi_hifiberry_dacplusadcpro_probe,
++};
++
++module_platform_driver(snd_rpi_hifiberry_dacplusadcpro_driver);
++
++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ADC");
++MODULE_LICENSE("GPL v2");
+++ /dev/null
-From cf80e05ebb55c121c1567ac42b9e1a885fc346a3 Mon Sep 17 00:00:00 2001
-Date: Fri, 19 Jul 2019 17:49:00 +0100
-Subject: [PATCH] drm/vc4: Ensure zpos is always initialised
-
-The compiler is warning that default_zpos can be used
-uninitialised as there is no default case to catch all plane
-types.
-No other plane types should ever be presented to vc4_fkms_plane_init,
-but add a default case regardless.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -773,6 +773,7 @@ static struct drm_plane *vc4_fkms_plane_
- * other layers as requested by KMS.
- */
- switch (type) {
-+ default:
- case DRM_PLANE_TYPE_PRIMARY:
- default_zpos = 0;
- break;
--- /dev/null
+From 43866e3396623775215943f3062a98c642fcae95 Mon Sep 17 00:00:00 2001
+Date: Mon, 29 Jul 2019 15:06:57 +0530
+Subject: [PATCH] codecs: Correct Katana minimum volume
+
+Update Katana minimum volume to get the exact 0.5 dB value in each step.
+
+---
+ sound/soc/bcm/allo-katana-codec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/bcm/allo-katana-codec.c
++++ b/sound/soc/bcm/allo-katana-codec.c
+@@ -126,7 +126,7 @@ static SOC_VALUE_ENUM_SINGLE_DECL(katana
+ katana_codec_deemphasis_texts,
+ katana_codec_deemphasis_values);
+
+-static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(master_tlv, -12700, 0);
++static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(master_tlv, -12750, 0);
+
+ static const struct snd_kcontrol_new katana_codec_controls[] = {
+ SOC_DOUBLE_R_TLV("Master Playback Volume", KATANA_CODEC_VOLUME_1,
+++ /dev/null
-From a78d4d81c585a5de61e7fc7d574e6e3f769c18a6 Mon Sep 17 00:00:00 2001
-Date: Wed, 24 Jul 2019 14:36:53 +0100
-Subject: [PATCH] dts: bcm2838: add missing properties for pmu and gic
- nodes
-
-The GIC has a virtual interface maintenance interrupt and the PMU
-interrupts need affinity mappings as they are wired to generic SPIs.
-
-Also, delete incorrect PMU compatible string.
-
----
- arch/arm/boot/dts/bcm2838.dtsi | 9 ++++-----
- 1 file changed, 4 insertions(+), 5 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -35,6 +35,8 @@
- <0x40042000 0x2000>,
- <0x40044000 0x2000>,
- <0x40046000 0x2000>;
-+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_HIGH)>;
- };
-
- thermal: thermal@7d5d2200 {
-@@ -222,15 +224,12 @@
- };
-
- arm-pmu {
-- /*
-- * N.B. the A72 PMU support only exists in arch/arm64, hence
-- * the fallback to the A53 version.
-- */
-- compatible = "arm,cortex-a72-pmu", "arm,cortex-a53-pmu";
-+ compatible = "arm,cortex-a72-pmu";
- interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
- };
-
- timer {
+++ /dev/null
-From bab5f8832c6b2859caea1cb5af1ffcb6276c2f74 Mon Sep 17 00:00:00 2001
-Date: Tue, 23 Jul 2019 16:57:35 +0200
-Subject: [PATCH] adds the Hifiberry DAC+ADC PRO version
-
-This adds the driver for the DAC+ADC PRO version of the Hifiberry soundcard with software controlled PCM1863 ADC
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 21 +
- .../hifiberry-dacplusadcpro-overlay.dts | 64 +++
- sound/soc/bcm/Kconfig | 8 +
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/hifiberry_dacplusadcpro.c | 538 ++++++++++++++++++
- 9 files changed, 637 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
- create mode 100644 sound/soc/bcm/hifiberry_dacplusadcpro.c
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -53,6 +53,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- hifiberry-dac.dtbo \
- hifiberry-dacplus.dtbo \
- hifiberry-dacplusadc.dtbo \
-+ hifiberry-dacplusadcpro.dtbo \
- hifiberry-digi.dtbo \
- hifiberry-digi-pro.dtbo \
- hy28a.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -883,6 +883,27 @@ Params: 24db_digital_gain Allow ga
- master for bit clock and frame clock.
-
-
-+Name: hifiberry-dacplusadcpro
-+Info: Configures the HifiBerry DAC+ADC PRO audio card
-+Load: dtoverlay=hifiberry-dacplusadcpro,<param>=<val>
-+Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
-+ Digital volume control. Enable with
-+ "dtoverlay=hifiberry-dacplusadcpro,24db_digital_gain"
-+ (The default behaviour is that the Digital
-+ volume control is limited to a maximum of
-+ 0dB. ie. it can attenuate but not provide
-+ gain. For most users, this will be desired
-+ as it will prevent clipping. By appending
-+ the 24dB_digital_gain parameter, the Digital
-+ volume control will allow up to 24dB of
-+ gain. If this parameter is enabled, it is the
-+ responsibility of the user to ensure that
-+ the Digital volume control is set to a value
-+ that does not result in clipping/distortion!)
-+ slave Force DAC+ADC Pro into slave mode, using Pi as
-+ master for bit clock and frame clock.
-+
-+
- Name: hifiberry-digi
- Info: Configures the HifiBerry Digi and Digi+ audio card
- Load: dtoverlay=hifiberry-digi
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
-@@ -0,0 +1,64 @@
-+// Definitions for HiFiBerry DAC+ADC PRO
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2708";
-+
-+ fragment@0 {
-+ target-path = "/clocks";
-+ __overlay__ {
-+ dacpro_osc: dacpro_osc {
-+ compatible = "hifiberry,dacpro-clk";
-+ #clock-cells = <0>;
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ hb_dac: pcm5122@4d {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,pcm5122";
-+ reg = <0x4d>;
-+ clocks = <&dacpro_osc>;
-+ status = "okay";
-+ };
-+ hb_adc: pcm186x@4a {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,pcm1863";
-+ reg = <0x4a>;
-+ clocks = <&dacpro_osc>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&sound>;
-+ hifiberry_dacplusadcpro: __overlay__ {
-+ compatible = "hifiberry,hifiberry-dacplusadcpro";
-+ audio-codec = <&hb_dac &hb_adc>;
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ 24db_digital_gain =
-+ <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,24db_digital_gain?";
-+ slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?";
-+ };
-+};
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -48,6 +48,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
- help
- Say Y or M if you want to add support for HifiBerry DAC+ADC.
-
-+config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO
-+ tristate "Support for HifiBerry DAC+ADC PRO"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_PCM512x_I2C
-+ select SND_SOC_PCM186X_I2C
-+ help
-+ Say Y or M if you want to add support for HifiBerry DAC+ADC PRO.
-+
- config SND_BCM2708_SOC_HIFIBERRY_DIGI
- tristate "Support for HifiBerry Digi"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -14,6 +14,7 @@ snd-soc-googlevoicehat-codec-objs := goo
- # BCM2708 Machine Support
- snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
- snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
-+snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
- snd-soc-justboom-dac-objs := justboom-dac.o
- snd-soc-rpi-cirrus-objs := rpi-cirrus.o
- snd-soc-rpi-proto-objs := rpi-proto.o
-@@ -38,6 +39,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi
- obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
-+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
- obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
---- /dev/null
-+++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
-@@ -0,0 +1,538 @@
-+/*
-+ * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC PRO Version (SW control)
-+ *
-+ * Copyright 2014-2015
-+ * Copyright 2018-19
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/kernel.h>
-+#include <linux/clk.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+#include <sound/tlv.h>
-+
-+#include "../codecs/pcm512x.h"
-+#include "../codecs/pcm186x.h"
-+
-+#define HIFIBERRY_DACPRO_NOCLOCK 0
-+#define HIFIBERRY_DACPRO_CLK44EN 1
-+#define HIFIBERRY_DACPRO_CLK48EN 2
-+
-+struct pcm512x_priv {
-+ struct regmap *regmap;
-+ struct clk *sclk;
-+};
-+
-+/* Clock rate of CLK44EN attached to GPIO6 pin */
-+#define CLK_44EN_RATE 22579200UL
-+/* Clock rate of CLK48EN attached to GPIO3 pin */
-+#define CLK_48EN_RATE 24576000UL
-+
-+static bool slave;
-+static bool snd_rpi_hifiberry_is_dacpro;
-+static bool digital_gain_0db_limit = true;
-+
-+static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
-+ 0x00, 0x01, 0x02, 0x03, 0x10
-+};
-+
-+static const char * const pcm186x_adcl_input_channel_sel_text[] = {
-+ "No Select",
-+ "VINL1[SE]", /* Default for ADCL */
-+ "VINL2[SE]",
-+ "VINL2[SE] + VINL1[SE]",
-+ "{VIN1P, VIN1M}[DIFF]"
-+};
-+
-+static const char * const pcm186x_adcr_input_channel_sel_text[] = {
-+ "No Select",
-+ "VINR1[SE]", /* Default for ADCR */
-+ "VINR2[SE]",
-+ "VINR2[SE] + VINR1[SE]",
-+ "{VIN2P, VIN2M}[DIFF]"
-+};
-+
-+static const struct soc_enum pcm186x_adc_input_channel_sel[] = {
-+ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0,
-+ PCM186X_ADC_INPUT_SEL_MASK,
-+ ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
-+ pcm186x_adcl_input_channel_sel_text,
-+ pcm186x_adc_input_channel_sel_value),
-+ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0,
-+ PCM186X_ADC_INPUT_SEL_MASK,
-+ ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
-+ pcm186x_adcr_input_channel_sel_text,
-+ pcm186x_adc_input_channel_sel_value),
-+};
-+
-+static const unsigned int pcm186x_mic_bias_sel_value[] = {
-+ 0x00, 0x01, 0x11
-+};
-+
-+static const char * const pcm186x_mic_bias_sel_text[] = {
-+ "Mic Bias off",
-+ "Mic Bias on",
-+ "Mic Bias with Bypass Resistor"
-+};
-+
-+static const struct soc_enum pcm186x_mic_bias_sel[] = {
-+ SOC_VALUE_ENUM_SINGLE(PCM186X_MIC_BIAS_CTRL, 0,
-+ GENMASK(4, 0),
-+ ARRAY_SIZE(pcm186x_mic_bias_sel_text),
-+ pcm186x_mic_bias_sel_text,
-+ pcm186x_mic_bias_sel_value),
-+};
-+
-+static const unsigned int pcm186x_gain_sel_value[] = {
-+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
-+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
-+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
-+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
-+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
-+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
-+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
-+ 0x50
-+};
-+
-+static const char * const pcm186x_gain_sel_text[] = {
-+ "-12.0dB", "-11.5dB", "-11.0dB", "-10.5dB", "-10.0dB", "-9.5dB",
-+ "-9.0dB", "-8.5dB", "-8.0dB", "-7.5dB", "-7.0dB", "-6.5dB",
-+ "-6.0dB", "-5.5dB", "-5.0dB", "-4.5dB", "-4.0dB", "-3.5dB",
-+ "-3.0dB", "-2.5dB", "-2.0dB", "-1.5dB", "-1.0dB", "-0.5dB",
-+ "0.0dB", "0.5dB", "1.0dB", "1.5dB", "2.0dB", "2.5dB",
-+ "3.0dB", "3.5dB", "4.0dB", "4.5dB", "5.0dB", "5.5dB",
-+ "6.0dB", "6.5dB", "7.0dB", "7.5dB", "8.0dB", "8.5dB",
-+ "9.0dB", "9.5dB", "10.0dB", "10.5dB", "11.0dB", "11.5dB",
-+ "12.0dB", "12.5dB", "13.0dB", "13.5dB", "14.0dB", "14.5dB",
-+ "15.0dB", "15.5dB", "16.0dB", "16.5dB", "17.0dB", "17.5dB",
-+ "18.0dB", "18.5dB", "19.0dB", "19.5dB", "20.0dB", "20.5dB",
-+ "21.0dB", "21.5dB", "22.0dB", "22.5dB", "23.0dB", "23.5dB",
-+ "24.0dB", "24.5dB", "25.0dB", "25.5dB", "26.0dB", "26.5dB",
-+ "27.0dB", "27.5dB", "28.0dB", "28.5dB", "29.0dB", "29.5dB",
-+ "30.0dB", "30.5dB", "31.0dB", "31.5dB", "32.0dB", "32.5dB",
-+ "33.0dB", "33.5dB", "34.0dB", "34.5dB", "35.0dB", "35.5dB",
-+ "36.0dB", "36.5dB", "37.0dB", "37.5dB", "38.0dB", "38.5dB",
-+ "39.0dB", "39.5dB", "40.0dB"};
-+
-+static const struct soc_enum pcm186x_gain_sel[] = {
-+ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_L, 0,
-+ 0xff,
-+ ARRAY_SIZE(pcm186x_gain_sel_text),
-+ pcm186x_gain_sel_text,
-+ pcm186x_gain_sel_value),
-+ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_R, 0,
-+ 0xff,
-+ ARRAY_SIZE(pcm186x_gain_sel_text),
-+ pcm186x_gain_sel_text,
-+ pcm186x_gain_sel_value),
-+};
-+
-+static const struct snd_kcontrol_new pcm1863_snd_controls_card[] = {
-+ SOC_ENUM("ADC Left Input", pcm186x_adc_input_channel_sel[0]),
-+ SOC_ENUM("ADC Right Input", pcm186x_adc_input_channel_sel[1]),
-+ SOC_ENUM("ADC Mic Bias", pcm186x_mic_bias_sel),
-+ SOC_ENUM("PGA Gain Left", pcm186x_gain_sel[0]),
-+ SOC_ENUM("PGA Gain Right", pcm186x_gain_sel[1]),
-+};
-+
-+static int pcm1863_add_controls(struct snd_soc_component *component)
-+{
-+ snd_soc_add_component_controls(component,
-+ pcm1863_snd_controls_card,
-+ ARRAY_SIZE(pcm1863_snd_controls_card));
-+ return 0;
-+}
-+
-+static void snd_rpi_hifiberry_dacplusadcpro_select_clk(
-+ struct snd_soc_component *component, int clk_id)
-+{
-+ switch (clk_id) {
-+ case HIFIBERRY_DACPRO_NOCLOCK:
-+ snd_soc_component_update_bits(component,
-+ PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
-+ break;
-+ case HIFIBERRY_DACPRO_CLK44EN:
-+ snd_soc_component_update_bits(component,
-+ PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
-+ break;
-+ case HIFIBERRY_DACPRO_CLK48EN:
-+ snd_soc_component_update_bits(component,
-+ PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
-+ break;
-+ }
-+}
-+
-+static void snd_rpi_hifiberry_dacplusadcpro_clk_gpio(struct snd_soc_component *component)
-+{
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24);
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
-+}
-+
-+static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk(struct snd_soc_component *component)
-+{
-+ unsigned int sck;
-+
-+ snd_soc_component_read(component, PCM512x_RATE_DET_4, &sck);
-+ return (!(sck & 0x40));
-+}
-+
-+static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(
-+ struct snd_soc_component *component)
-+{
-+ msleep(2);
-+ return snd_rpi_hifiberry_dacplusadcpro_is_sclk(component);
-+}
-+
-+static bool snd_rpi_hifiberry_dacplusadcpro_is_pro_card(struct snd_soc_component *component)
-+{
-+ bool isClk44EN, isClk48En, isNoClk;
-+
-+ snd_rpi_hifiberry_dacplusadcpro_clk_gpio(component);
-+
-+ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK44EN);
-+ isClk44EN = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component);
-+
-+ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK);
-+ isNoClk = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component);
-+
-+ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK48EN);
-+ isClk48En = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component);
-+
-+ return (isClk44EN && isClk48En && !isNoClk);
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(int sample_rate)
-+{
-+ int type;
-+
-+ switch (sample_rate) {
-+ case 11025:
-+ case 22050:
-+ case 44100:
-+ case 88200:
-+ case 176400:
-+ case 352800:
-+ type = HIFIBERRY_DACPRO_CLK44EN;
-+ break;
-+ default:
-+ type = HIFIBERRY_DACPRO_CLK48EN;
-+ break;
-+ }
-+ return type;
-+}
-+
-+static void snd_rpi_hifiberry_dacplusadcpro_set_sclk(struct snd_soc_component *component,
-+ int sample_rate)
-+{
-+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
-+
-+ if (!IS_ERR(pcm512x->sclk)) {
-+ int ctype;
-+
-+ ctype = snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(sample_rate);
-+ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN)
-+ ? CLK_44EN_RATE : CLK_48EN_RATE);
-+ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, ctype);
-+ }
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadcpro_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
-+ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
-+ struct snd_soc_dai_driver *adc_driver = rtd->codec_dais[1]->driver;
-+ struct pcm512x_priv *priv;
-+ int ret;
-+
-+ if (slave)
-+ snd_rpi_hifiberry_is_dacpro = false;
-+ else
-+ snd_rpi_hifiberry_is_dacpro =
-+ snd_rpi_hifiberry_dacplusadcpro_is_pro_card(dac);
-+
-+ if (snd_rpi_hifiberry_is_dacpro) {
-+ struct snd_soc_dai_link *dai = rtd->dai_link;
-+
-+ dai->name = "HiFiBerry DAC+ADC Pro";
-+ dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi";
-+
-+ // set DAC DAI configuration
-+ ret = snd_soc_dai_set_fmt(rtd->codec_dais[0],
-+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-+ | SND_SOC_DAIFMT_CBM_CFM);
-+ if (ret < 0)
-+ return ret;
-+
-+ // set ADC DAI configuration
-+ ret = snd_soc_dai_set_fmt(rtd->codec_dais[1],
-+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-+ | SND_SOC_DAIFMT_CBS_CFS);
-+ if (ret < 0)
-+ return ret;
-+
-+ // set CPU DAI configuration
-+ ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
-+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-+ if (ret < 0)
-+ return ret;
-+
-+ snd_soc_component_update_bits(dac, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
-+ snd_soc_component_update_bits(dac, PCM512x_MASTER_MODE, 0x03, 0x03);
-+ snd_soc_component_update_bits(dac, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
-+ } else {
-+ priv = snd_soc_component_get_drvdata(dac);
-+ priv->sclk = ERR_PTR(-ENOENT);
-+ }
-+
-+ /* disable 24bit mode as long as I2S module does not have sign extension fixed */
-+ adc_driver->capture.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE;
-+
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+
-+ ret = pcm1863_add_controls(adc);
-+ if (ret < 0)
-+ dev_warn(rtd->dev, "Failed to add pcm1863 controls: %d\n",
-+ ret);
-+
-+ /* set GPIO2 to output, GPIO3 input */
-+ snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00);
-+ snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04);
-+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
-+
-+ if (digital_gain_0db_limit) {
-+ int ret;
-+ struct snd_soc_card *card = rtd->card;
-+
-+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
-+ if (ret < 0)
-+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
-+ }
-+
-+ return 0;
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadcpro_update_rate_den(
-+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *component = rtd->codec_dais[0]->component; /* only use DAC */
-+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
-+ struct snd_ratnum *rats_no_pll;
-+ unsigned int num = 0, den = 0;
-+ int err;
-+
-+ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
-+ if (!rats_no_pll)
-+ return -ENOMEM;
-+
-+ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
-+ rats_no_pll->den_min = 1;
-+ rats_no_pll->den_max = 128;
-+ rats_no_pll->den_step = 1;
-+
-+ err = snd_interval_ratnum(hw_param_interval(params,
-+ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
-+ if (err >= 0 && den) {
-+ params->rate_num = num;
-+ params->rate_den = den;
-+ }
-+
-+ devm_kfree(rtd->dev, rats_no_pll);
-+ return 0;
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadcpro_hw_params(
-+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
-+{
-+ int ret = 0;
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ int channels = params_channels(params);
-+ int width = 32;
-+ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
-+
-+ if (snd_rpi_hifiberry_is_dacpro) {
-+
-+ width = snd_pcm_format_physical_width(params_format(params));
-+
-+ snd_rpi_hifiberry_dacplusadcpro_set_sclk(dac,
-+ params_rate(params));
-+
-+ ret = snd_rpi_hifiberry_dacplusadcpro_update_rate_den(
-+ substream, params);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x03, 0x03,
-+ channels, width);
-+ if (ret)
-+ return ret;
-+ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[0], 0x03, 0x03,
-+ channels, width);
-+ if (ret)
-+ return ret;
-+ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x03, 0x03,
-+ channels, width);
-+ return ret;
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadcpro_startup(
-+ struct snd_pcm_substream *substream)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
-+ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
-+
-+ /* switch on respective LED */
-+ if (!substream->stream)
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+ else
-+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
-+ return 0;
-+}
-+
-+static void snd_rpi_hifiberry_dacplusadcpro_shutdown(
-+ struct snd_pcm_substream *substream)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
-+ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
-+
-+ /* switch off respective LED */
-+ if (!substream->stream)
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
-+ else
-+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00);
-+}
-+
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_hifiberry_dacplusadcpro_ops = {
-+ .hw_params = snd_rpi_hifiberry_dacplusadcpro_hw_params,
-+ .startup = snd_rpi_hifiberry_dacplusadcpro_startup,
-+ .shutdown = snd_rpi_hifiberry_dacplusadcpro_shutdown,
-+};
-+
-+static struct snd_soc_dai_link_component snd_rpi_hifiberry_dacplusadcpro_codecs[] = {
-+ {
-+ .name = "pcm512x.1-004d",
-+ .dai_name = "pcm512x-hifi",
-+ },
-+ {
-+ .name = "pcm186x.1-004a",
-+ .dai_name = "pcm1863-aif",
-+ },
-+};
-+
-+static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadcpro_dai[] = {
-+{
-+ .name = "HiFiBerry DAC+ADC PRO",
-+ .stream_name = "HiFiBerry DAC+ADC PRO HiFi",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codecs = snd_rpi_hifiberry_dacplusadcpro_codecs,
-+ .num_codecs = 2,
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBS_CFS,
-+ .ops = &snd_rpi_hifiberry_dacplusadcpro_ops,
-+ .init = snd_rpi_hifiberry_dacplusadcpro_init,
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_hifiberry_dacplusadcpro = {
-+ .name = "snd_rpi_hifiberry_dacplusadcpro",
-+ .driver_name = "HifiberryDacpAdcPro",
-+ .owner = THIS_MODULE,
-+ .dai_link = snd_rpi_hifiberry_dacplusadcpro_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplusadcpro_dai),
-+};
-+
-+static int snd_rpi_hifiberry_dacplusadcpro_probe(struct platform_device *pdev)
-+{
-+ int ret = 0, i = 0;
-+ struct snd_soc_card *card = &snd_rpi_hifiberry_dacplusadcpro;
-+
-+ snd_rpi_hifiberry_dacplusadcpro.dev = &pdev->dev;
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai;
-+
-+ dai = &snd_rpi_hifiberry_dacplusadcpro_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+ if (i2s_node) {
-+ for (i = 0; i < card->num_links; i++) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
-+ }
-+ }
-+ digital_gain_0db_limit = !of_property_read_bool(
-+ pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain");
-+ slave = of_property_read_bool(pdev->dev.of_node,
-+ "hifiberry-dacplusadcpro,slave");
-+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro);
-+ if (ret && ret != -EPROBE_DEFER)
-+ dev_err(&pdev->dev,
-+ "snd_soc_register_card() failed: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static const struct of_device_id snd_rpi_hifiberry_dacplusadcpro_of_match[] = {
-+ { .compatible = "hifiberry,hifiberry-dacplusadcpro", },
-+ {},
-+};
-+
-+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplusadcpro_of_match);
-+
-+static struct platform_driver snd_rpi_hifiberry_dacplusadcpro_driver = {
-+ .driver = {
-+ .name = "snd-rpi-hifiberry-dacplusadcpro",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_hifiberry_dacplusadcpro_of_match,
-+ },
-+ .probe = snd_rpi_hifiberry_dacplusadcpro_probe,
-+};
-+
-+module_platform_driver(snd_rpi_hifiberry_dacplusadcpro_driver);
-+
-+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ADC");
-+MODULE_LICENSE("GPL v2");
--- /dev/null
+From 8befbf55f2668a4dae739588ed3c0b0d06fccacd Mon Sep 17 00:00:00 2001
+Date: Wed, 31 Jul 2019 17:36:34 +0100
+Subject: [PATCH] drm/vc4: A present but empty dmas disables audio
+
+Overlays are unable to remove properties in the base DTB, but they
+can overwrite them. Allow a present but empty 'dmas' property
+to also disable the HDMI audio interface.
+
+See: https://github.com/raspberrypi/linux/issues/2489
+
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -1087,10 +1087,12 @@ static int vc4_hdmi_audio_init(struct vc
+ struct device *dev = &hdmi->pdev->dev;
+ const __be32 *addr;
+ int ret;
++ int len;
+
+- if (!of_find_property(dev->of_node, "dmas", NULL)) {
++ if (!of_find_property(dev->of_node, "dmas", &len) ||
++ len == 0) {
+ dev_warn(dev,
+- "'dmas' DT property is missing, no HDMI audio\n");
++ "'dmas' DT property is missing or empty, no HDMI audio\n");
+ return 0;
+ }
+
+++ /dev/null
-From 43866e3396623775215943f3062a98c642fcae95 Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Jul 2019 15:06:57 +0530
-Subject: [PATCH] codecs: Correct Katana minimum volume
-
-Update Katana minimum volume to get the exact 0.5 dB value in each step.
-
----
- sound/soc/bcm/allo-katana-codec.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/sound/soc/bcm/allo-katana-codec.c
-+++ b/sound/soc/bcm/allo-katana-codec.c
-@@ -126,7 +126,7 @@ static SOC_VALUE_ENUM_SINGLE_DECL(katana
- katana_codec_deemphasis_texts,
- katana_codec_deemphasis_values);
-
--static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(master_tlv, -12700, 0);
-+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(master_tlv, -12750, 0);
-
- static const struct snd_kcontrol_new katana_codec_controls[] = {
- SOC_DOUBLE_R_TLV("Master Playback Volume", KATANA_CODEC_VOLUME_1,
--- /dev/null
+From 418ca5973ad807f9d7f99e68af2bd21c7e8baa4d Mon Sep 17 00:00:00 2001
+Date: Wed, 31 Jul 2019 17:39:37 +0100
+Subject: [PATCH] overlays: Add audio parameter to vc4-kms-v3d
+
+The audio parameter to the vc4-kms-v3d overlay allows audio support
+to be disabled (it defaults to on) by adding "audio=off" to the
+dtoverlay parameters.
+
+See: https://github.com/raspberrypi/linux/issues/2489
+
+---
+ arch/arm/boot/dts/overlays/README | 1 +
+ arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 8 ++++++++
+ 2 files changed, 9 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2480,6 +2480,7 @@ Params: cma-256 CMA is 2
+ cma-128 CMA is 128MB
+ cma-96 CMA is 96MB
+ cma-64 CMA is 64MB
++ audio Enable or disable audio over HDMI (default "on")
+
+
+ Name: vga666
+--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
+@@ -134,11 +134,19 @@
+ };
+ };
+
++ fragment@17 {
++ target = <&hdmi>;
++ __dormant__ {
++ dmas;
++ };
++ };
++
+ __overrides__ {
+ cma-256 = <0>,"+0-1-2-3-4";
+ cma-192 = <0>,"-0+1-2-3-4";
+ cma-128 = <0>,"-0-1+2-3-4";
+ cma-96 = <0>,"-0-1-2+3-4";
+ cma-64 = <0>,"-0-1-2-3+4";
++ audio = <0>,"!17";
+ };
+ };
+++ /dev/null
-From 8befbf55f2668a4dae739588ed3c0b0d06fccacd Mon Sep 17 00:00:00 2001
-Date: Wed, 31 Jul 2019 17:36:34 +0100
-Subject: [PATCH] drm/vc4: A present but empty dmas disables audio
-
-Overlays are unable to remove properties in the base DTB, but they
-can overwrite them. Allow a present but empty 'dmas' property
-to also disable the HDMI audio interface.
-
-See: https://github.com/raspberrypi/linux/issues/2489
-
----
- drivers/gpu/drm/vc4/vc4_hdmi.c | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_hdmi.c
-+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
-@@ -1087,10 +1087,12 @@ static int vc4_hdmi_audio_init(struct vc
- struct device *dev = &hdmi->pdev->dev;
- const __be32 *addr;
- int ret;
-+ int len;
-
-- if (!of_find_property(dev->of_node, "dmas", NULL)) {
-+ if (!of_find_property(dev->of_node, "dmas", &len) ||
-+ len == 0) {
- dev_warn(dev,
-- "'dmas' DT property is missing, no HDMI audio\n");
-+ "'dmas' DT property is missing or empty, no HDMI audio\n");
- return 0;
- }
-
--- /dev/null
+From a14162d8da62fb570df916d7386febe51d6ed2bc Mon Sep 17 00:00:00 2001
+Date: Wed, 31 Jul 2019 17:41:47 +0100
+Subject: [PATCH] overlays: Update the upstream overlay
+
+The recent vc4-kms-v3d commit has changed the content of the
+upstream overlay (even though the extra fragment is disabled).
+
+---
+ arch/arm/boot/dts/overlays/upstream-overlay.dts | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/upstream-overlay.dts
++++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts
+@@ -110,6 +110,12 @@
+ };
+ };
+ fragment@17 {
++ target = <&hdmi>;
++ __dormant__ {
++ dmas;
++ };
++ };
++ fragment@18 {
+ target = <&usb>;
+ #address-cells = <1>;
+ #size-cells = <1>;
--- /dev/null
+From c2957d7709a43c81e5345d537feaa6980ffcc1a4 Mon Sep 17 00:00:00 2001
+Date: Mon, 29 Jul 2019 12:02:59 +0100
+Subject: [PATCH] Fixup FKMS interrupt handing for non-existent display
+
+If an errant interrupt flag was received from a non-existent display,
+a NULL pointer access was made. Protect against this by checking if a
+second display is present prior to checking the interrupt flags.
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1056,14 +1056,17 @@ static irqreturn_t vc4_crtc_irq_handler(
+ vc4_crtc_handle_page_flip(crtc_list[0]);
+ }
+
+- /* Check for the secondary display too */
+- chan = readl(crtc_list[0]->regs + SMIDSW1);
++ if (crtc_list[1]) {
++ /* Check for the secondary display too */
++ chan = readl(crtc_list[0]->regs + SMIDSW1);
+
+- if (chan & 1) {
+- writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
+- if (crtc_list[1]->vblank_enabled)
+- drm_crtc_handle_vblank(&crtc_list[1]->base);
+- vc4_crtc_handle_page_flip(crtc_list[1]);
++ if (chan & 1) {
++ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
++
++ if (crtc_list[1]->vblank_enabled)
++ drm_crtc_handle_vblank(&crtc_list[1]->base);
++ vc4_crtc_handle_page_flip(crtc_list[1]);
++ }
+ }
+ }
+
+++ /dev/null
-From 418ca5973ad807f9d7f99e68af2bd21c7e8baa4d Mon Sep 17 00:00:00 2001
-Date: Wed, 31 Jul 2019 17:39:37 +0100
-Subject: [PATCH] overlays: Add audio parameter to vc4-kms-v3d
-
-The audio parameter to the vc4-kms-v3d overlay allows audio support
-to be disabled (it defaults to on) by adding "audio=off" to the
-dtoverlay parameters.
-
-See: https://github.com/raspberrypi/linux/issues/2489
-
----
- arch/arm/boot/dts/overlays/README | 1 +
- arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 8 ++++++++
- 2 files changed, 9 insertions(+)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -2480,6 +2480,7 @@ Params: cma-256 CMA is 2
- cma-128 CMA is 128MB
- cma-96 CMA is 96MB
- cma-64 CMA is 64MB
-+ audio Enable or disable audio over HDMI (default "on")
-
-
- Name: vga666
---- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts
-@@ -134,11 +134,19 @@
- };
- };
-
-+ fragment@17 {
-+ target = <&hdmi>;
-+ __dormant__ {
-+ dmas;
-+ };
-+ };
-+
- __overrides__ {
- cma-256 = <0>,"+0-1-2-3-4";
- cma-192 = <0>,"-0+1-2-3-4";
- cma-128 = <0>,"-0-1+2-3-4";
- cma-96 = <0>,"-0-1-2+3-4";
- cma-64 = <0>,"-0-1-2-3+4";
-+ audio = <0>,"!17";
- };
- };
--- /dev/null
+From 6c8c9ca56ce6039ade09d26c069132538e4de9f0 Mon Sep 17 00:00:00 2001
+Date: Sun, 28 Jul 2019 22:22:36 +0100
+Subject: [PATCH] drivers: char: Use correct name for the Raspberry Pi
+ video decoder
+
+Replace the old code name with a more appropriate name - RPiVid.
+
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 10 +-
+ drivers/char/broadcom/Kconfig | 8 +-
+ drivers/char/broadcom/Makefile | 2 +-
+ .../broadcom/{argon-mem.c => rpivid-mem.c} | 105 +++++++++---------
+ drivers/mfd/bcm2835-pm.c | 12 +-
+ drivers/soc/bcm/bcm2835-power.c | 6 +-
+ include/linux/mfd/bcm2835-pm.h | 2 +-
+ 8 files changed, 71 insertions(+), 76 deletions(-)
+ rename drivers/char/broadcom/{argon-mem.c => rpivid-mem.c} (69%)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -409,26 +409,26 @@
+ };
+
+ hevc-decoder@7eb00000 {
+- compatible = "raspberrypi,argon-hevc-decoder";
++ compatible = "raspberrypi,rpivid-hevc-decoder";
+ reg = <0x0 0x7eb00000 0x10000>;
+ status = "okay";
+ };
+
+- argon-local-intc@7eb10000 {
+- compatible = "raspberrypi,argon-local-intc";
++ rpivid-local-intc@7eb10000 {
++ compatible = "raspberrypi,rpivid-local-intc";
+ reg = <0x0 0x7eb10000 0x1000>;
+ status = "okay";
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ h264-decoder@7eb20000 {
+- compatible = "raspberrypi,argon-h264-decoder";
++ compatible = "raspberrypi,rpivid-h264-decoder";
+ reg = <0x0 0x7eb20000 0x10000>;
+ status = "okay";
+ };
+
+ vp9-decoder@7eb30000 {
+- compatible = "raspberrypi,argon-vp9-decoder";
++ compatible = "raspberrypi,rpivid-vp9-decoder";
+ reg = <0x0 0x7eb30000 0x10000>;
+ status = "okay";
+ };
+--- a/drivers/char/broadcom/Kconfig
++++ b/drivers/char/broadcom/Kconfig
+@@ -50,10 +50,10 @@ config BCM2835_SMI_DEV
+ Broadcom's Secondary Memory interface. The low-level functionality is provided
+ by the SMI driver itself.
+
+-config ARGON_MEM
+- tristate "Character device driver for the Argon decoder hardware"
++config RPIVID_MEM
++ tristate "Character device driver for the Raspberry Pi RPIVid video decoder hardware"
+ default n
+ help
+ This driver provides a character device interface for memory-map operations
+- so userspace tools can access the control and status registers of the Argon
+- video decoder hardware.
++ so userspace tools can access the control and status registers of the
++ Raspberry Pi RPiVid video decoder hardware.
+--- a/drivers/char/broadcom/Makefile
++++ b/drivers/char/broadcom/Makefile
+@@ -4,4 +4,4 @@ obj-$(CONFIG_BCM_VC_SM) += vc_sm
+
+ obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
+ obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o
+-obj-$(CONFIG_ARGON_MEM) += argon-mem.o
++obj-$(CONFIG_RPIVID_MEM) += rpivid-mem.o
+--- a/drivers/char/broadcom/argon-mem.c
++++ /dev/null
+@@ -1,277 +0,0 @@
+-/**
+- * argon-mem.c - character device access to the Argon decoder registers
+- *
+- * Based on bcm2835-gpiomem.c. Provides IO memory access to the decoder
+- * register blocks such that ffmpeg plugins can access the hardware.
+- *
+- * Copyright (c) 2019, Raspberry Pi (Trading) Ltd.
+- *
+- * Redistribution and use in source and binary forms, with or without
+- * modification, are permitted provided that the following conditions
+- * are met:
+- * 1. Redistributions of source code must retain the above copyright
+- * notice, this list of conditions, and the following disclaimer,
+- * without modification.
+- * 2. Redistributions in binary form must reproduce the above copyright
+- * notice, this list of conditions and the following disclaimer in the
+- * documentation and/or other materials provided with the distribution.
+- * 3. The names of the above-listed copyright holders may not be used
+- * to endorse or promote products derived from this software without
+- * specific prior written permission.
+- *
+- * ALTERNATIVELY, this software may be distributed under the terms of the
+- * GNU General Public License ("GPL") version 2, as published by the Free
+- * Software Foundation.
+- *
+- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-#include <linux/platform_device.h>
+-#include <linux/mm.h>
+-#include <linux/slab.h>
+-#include <linux/cdev.h>
+-#include <linux/pagemap.h>
+-#include <linux/io.h>
+-
+-#define DRIVER_NAME "argon-mem"
+-#define DEVICE_MINOR 0
+-
+-struct argon_mem_priv {
+- dev_t devid;
+- struct class *class;
+- struct cdev argon_mem_cdev;
+- unsigned long regs_phys;
+- unsigned long mem_window_len;
+- struct device *dev;
+- const char *name;
+-};
+-
+-static int argon_mem_open(struct inode *inode, struct file *file)
+-{
+- int dev = iminor(inode);
+- int ret = 0;
+- struct argon_mem_priv *priv;
+- if (dev != DEVICE_MINOR)
+- ret = -ENXIO;
+-
+- priv = container_of(inode->i_cdev, struct argon_mem_priv,
+- argon_mem_cdev);
+- if (!priv)
+- return -EINVAL;
+- file->private_data = priv;
+- return ret;
+-}
+-
+-static int argon_mem_release(struct inode *inode, struct file *file)
+-{
+- int dev = iminor(inode);
+- int ret = 0;
+-
+- if (dev != DEVICE_MINOR)
+- ret = -ENXIO;
+-
+- return ret;
+-}
+-
+-static const struct vm_operations_struct argon_mem_vm_ops = {
+-#ifdef CONFIG_HAVE_IOREMAP_PROT
+- .access = generic_access_phys
+-#endif
+-};
+-
+-static int argon_mem_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- struct argon_mem_priv *priv;
+- unsigned long pages;
+-
+- priv = file->private_data;
+- pages = priv->regs_phys >> PAGE_SHIFT;
+- /*
+- * The address decode is far larger than the actual number of registers.
+- * Just map the whole lot in.
+- */
+- vma->vm_page_prot = phys_mem_access_prot(file, pages,
+- priv->mem_window_len,
+- vma->vm_page_prot);
+- vma->vm_ops = &argon_mem_vm_ops;
+- if (remap_pfn_range(vma, vma->vm_start,
+- pages,
+- priv->mem_window_len,
+- vma->vm_page_prot)) {
+- return -EAGAIN;
+- }
+- return 0;
+-}
+-
+-static const struct file_operations
+-argon_mem_fops = {
+- .owner = THIS_MODULE,
+- .open = argon_mem_open,
+- .release = argon_mem_release,
+- .mmap = argon_mem_mmap,
+-};
+-
+-static const struct of_device_id argon_mem_of_match[];
+-static int argon_mem_probe(struct platform_device *pdev)
+-{
+- int err;
+- void *ptr_err;
+- const struct of_device_id *id;
+- struct device *dev = &pdev->dev;
+- struct device *argon_mem_dev;
+- struct resource *ioresource;
+- struct argon_mem_priv *priv;
+-
+-
+- /* Allocate buffers and instance data */
+-
+- priv = kzalloc(sizeof(struct argon_mem_priv), GFP_KERNEL);
+-
+- if (!priv) {
+- err = -ENOMEM;
+- goto failed_inst_alloc;
+- }
+- platform_set_drvdata(pdev, priv);
+-
+- priv->dev = dev;
+- id = of_match_device(argon_mem_of_match, dev);
+- if (!id)
+- return -EINVAL;
+- priv->name = id->data;
+-
+- ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- if (ioresource) {
+- priv->regs_phys = ioresource->start;
+- priv->mem_window_len = ioresource->end - ioresource->start;
+- } else {
+- dev_err(priv->dev, "failed to get IO resource");
+- err = -ENOENT;
+- goto failed_get_resource;
+- }
+-
+- /* Create character device entries */
+-
+- err = alloc_chrdev_region(&priv->devid,
+- DEVICE_MINOR, 1, priv->name);
+- if (err != 0) {
+- dev_err(priv->dev, "unable to allocate device number");
+- goto failed_alloc_chrdev;
+- }
+- cdev_init(&priv->argon_mem_cdev, &argon_mem_fops);
+- priv->argon_mem_cdev.owner = THIS_MODULE;
+- err = cdev_add(&priv->argon_mem_cdev, priv->devid, 1);
+- if (err != 0) {
+- dev_err(priv->dev, "unable to register device");
+- goto failed_cdev_add;
+- }
+-
+- /* Create sysfs entries */
+-
+- priv->class = class_create(THIS_MODULE, priv->name);
+- ptr_err = priv->class;
+- if (IS_ERR(ptr_err))
+- goto failed_class_create;
+-
+- argon_mem_dev = device_create(priv->class, NULL,
+- priv->devid, NULL,
+- priv->name);
+- ptr_err = argon_mem_dev;
+- if (IS_ERR(ptr_err))
+- goto failed_device_create;
+-
+- dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
+- priv->name, priv->regs_phys, priv->mem_window_len);
+-
+- return 0;
+-
+-failed_device_create:
+- class_destroy(priv->class);
+-failed_class_create:
+- cdev_del(&priv->argon_mem_cdev);
+- err = PTR_ERR(ptr_err);
+-failed_cdev_add:
+- unregister_chrdev_region(priv->devid, 1);
+-failed_alloc_chrdev:
+-failed_get_resource:
+- kfree(priv);
+-failed_inst_alloc:
+- dev_err(priv->dev, "could not load argon_mem");
+- return err;
+-}
+-
+-static int argon_mem_remove(struct platform_device *pdev)
+-{
+- struct device *dev = &pdev->dev;
+- struct argon_mem_priv *priv = platform_get_drvdata(pdev);
+-
+- device_destroy(priv->class, priv->devid);
+- class_destroy(priv->class);
+- cdev_del(&priv->argon_mem_cdev);
+- unregister_chrdev_region(priv->devid, 1);
+- kfree(priv);
+-
+- dev_info(dev, "%s driver removed - OK", priv->name);
+- return 0;
+-}
+-
+-static const char argon_hevc_name[] = "argon-hevcmem";
+-static const char argon_h264_name[] = "argon-h264mem";
+-static const char argon_vp9_name[] = "argon-vp9mem";
+-static const char argon_intc_name[] = "argon-intcmem";
+-
+-static const struct of_device_id argon_mem_of_match[] = {
+- {
+- .compatible = "raspberrypi,argon-hevc-decoder",
+- .data = &argon_hevc_name,
+- },
+- {
+- .compatible = "raspberrypi,argon-h264-decoder",
+- .data = &argon_h264_name,
+- },
+- {
+- .compatible = "raspberrypi,argon-vp9-decoder",
+- .data = &argon_vp9_name,
+- },
+- /* The "intc" is included as this block of hardware contains the
+- * "frame done" status flags.
+- */
+- {
+- .compatible = "raspberrypi,argon-local-intc",
+- .data = &argon_intc_name,
+- },
+- { /* sentinel */ },
+-};
+-
+-MODULE_DEVICE_TABLE(of, argon_mem_of_match);
+-
+-static struct platform_driver argon_mem_driver = {
+- .probe = argon_mem_probe,
+- .remove = argon_mem_remove,
+- .driver = {
+- .name = DRIVER_NAME,
+- .owner = THIS_MODULE,
+- .of_match_table = argon_mem_of_match,
+- },
+-};
+-
+-module_platform_driver(argon_mem_driver);
+-
+-MODULE_ALIAS("platform:argon-mem");
+-MODULE_LICENSE("GPL");
+-MODULE_DESCRIPTION("Driver for accessing Argon decoder registers from userspace");
+--- /dev/null
++++ b/drivers/char/broadcom/rpivid-mem.c
+@@ -0,0 +1,272 @@
++/**
++ * rpivid-mem.c - character device access to the RPiVid decoder registers
++ *
++ * Based on bcm2835-gpiomem.c. Provides IO memory access to the decoder
++ * register blocks such that ffmpeg plugins can access the hardware.
++ *
++ * Copyright (c) 2019, Raspberry Pi (Trading) Ltd.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/cdev.h>
++#include <linux/pagemap.h>
++#include <linux/io.h>
++
++#define DRIVER_NAME "rpivid-mem"
++#define DEVICE_MINOR 0
++
++struct rpivid_mem_priv {
++ dev_t devid;
++ struct class *class;
++ struct cdev rpivid_mem_cdev;
++ unsigned long regs_phys;
++ unsigned long mem_window_len;
++ struct device *dev;
++ const char *name;
++};
++
++static int rpivid_mem_open(struct inode *inode, struct file *file)
++{
++ int dev = iminor(inode);
++ int ret = 0;
++ struct rpivid_mem_priv *priv;
++ if (dev != DEVICE_MINOR)
++ ret = -ENXIO;
++
++ priv = container_of(inode->i_cdev, struct rpivid_mem_priv,
++ rpivid_mem_cdev);
++ if (!priv)
++ return -EINVAL;
++ file->private_data = priv;
++ return ret;
++}
++
++static int rpivid_mem_release(struct inode *inode, struct file *file)
++{
++ int dev = iminor(inode);
++ int ret = 0;
++
++ if (dev != DEVICE_MINOR)
++ ret = -ENXIO;
++
++ return ret;
++}
++
++static const struct vm_operations_struct rpivid_mem_vm_ops = {
++#ifdef CONFIG_HAVE_IOREMAP_PROT
++ .access = generic_access_phys
++#endif
++};
++
++static int rpivid_mem_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ struct rpivid_mem_priv *priv;
++ unsigned long pages;
++
++ priv = file->private_data;
++ pages = priv->regs_phys >> PAGE_SHIFT;
++ /*
++ * The address decode is far larger than the actual number of registers.
++ * Just map the whole lot in.
++ */
++ vma->vm_page_prot = phys_mem_access_prot(file, pages,
++ priv->mem_window_len,
++ vma->vm_page_prot);
++ vma->vm_ops = &rpivid_mem_vm_ops;
++ if (remap_pfn_range(vma, vma->vm_start,
++ pages,
++ priv->mem_window_len,
++ vma->vm_page_prot)) {
++ return -EAGAIN;
++ }
++ return 0;
++}
++
++static const struct file_operations
++rpivid_mem_fops = {
++ .owner = THIS_MODULE,
++ .open = rpivid_mem_open,
++ .release = rpivid_mem_release,
++ .mmap = rpivid_mem_mmap,
++};
++
++static const struct of_device_id rpivid_mem_of_match[];
++static int rpivid_mem_probe(struct platform_device *pdev)
++{
++ int err;
++ void *ptr_err;
++ const struct of_device_id *id;
++ struct device *dev = &pdev->dev;
++ struct device *rpivid_mem_dev;
++ struct resource *ioresource;
++ struct rpivid_mem_priv *priv;
++
++
++ /* Allocate buffers and instance data */
++
++ priv = kzalloc(sizeof(struct rpivid_mem_priv), GFP_KERNEL);
++
++ if (!priv) {
++ err = -ENOMEM;
++ goto failed_inst_alloc;
++ }
++ platform_set_drvdata(pdev, priv);
++
++ priv->dev = dev;
++ id = of_match_device(rpivid_mem_of_match, dev);
++ if (!id)
++ return -EINVAL;
++ priv->name = id->data;
++
++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (ioresource) {
++ priv->regs_phys = ioresource->start;
++ priv->mem_window_len = ioresource->end - ioresource->start;
++ } else {
++ dev_err(priv->dev, "failed to get IO resource");
++ err = -ENOENT;
++ goto failed_get_resource;
++ }
++
++ /* Create character device entries */
++
++ err = alloc_chrdev_region(&priv->devid,
++ DEVICE_MINOR, 1, priv->name);
++ if (err != 0) {
++ dev_err(priv->dev, "unable to allocate device number");
++ goto failed_alloc_chrdev;
++ }
++ cdev_init(&priv->rpivid_mem_cdev, &rpivid_mem_fops);
++ priv->rpivid_mem_cdev.owner = THIS_MODULE;
++ err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 1);
++ if (err != 0) {
++ dev_err(priv->dev, "unable to register device");
++ goto failed_cdev_add;
++ }
++
++ /* Create sysfs entries */
++
++ priv->class = class_create(THIS_MODULE, priv->name);
++ ptr_err = priv->class;
++ if (IS_ERR(ptr_err))
++ goto failed_class_create;
++
++ rpivid_mem_dev = device_create(priv->class, NULL,
++ priv->devid, NULL,
++ priv->name);
++ ptr_err = rpivid_mem_dev;
++ if (IS_ERR(ptr_err))
++ goto failed_device_create;
++
++ dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
++ priv->name, priv->regs_phys, priv->mem_window_len);
++
++ return 0;
++
++failed_device_create:
++ class_destroy(priv->class);
++failed_class_create:
++ cdev_del(&priv->rpivid_mem_cdev);
++ err = PTR_ERR(ptr_err);
++failed_cdev_add:
++ unregister_chrdev_region(priv->devid, 1);
++failed_alloc_chrdev:
++failed_get_resource:
++ kfree(priv);
++failed_inst_alloc:
++ dev_err(priv->dev, "could not load rpivid_mem");
++ return err;
++}
++
++static int rpivid_mem_remove(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct rpivid_mem_priv *priv = platform_get_drvdata(pdev);
++
++ device_destroy(priv->class, priv->devid);
++ class_destroy(priv->class);
++ cdev_del(&priv->rpivid_mem_cdev);
++ unregister_chrdev_region(priv->devid, 1);
++ kfree(priv);
++
++ dev_info(dev, "%s driver removed - OK", priv->name);
++ return 0;
++}
++
++static const struct of_device_id rpivid_mem_of_match[] = {
++ {
++ .compatible = "raspberrypi,rpivid-hevc-decoder",
++ .data = "rpivid-hevcmem",
++ },
++ {
++ .compatible = "raspberrypi,rpivid-h264-decoder",
++ .data = "rpivid-h264mem",
++ },
++ {
++ .compatible = "raspberrypi,rpivid-vp9-decoder",
++ .data = "rpivid-vp9mem",
++ },
++ /* The "intc" is included as this block of hardware contains the
++ * "frame done" status flags.
++ */
++ {
++ .compatible = "raspberrypi,rpivid-local-intc",
++ .data = "rpivid-intcmem",
++ },
++ { /* sentinel */ },
++};
++
++MODULE_DEVICE_TABLE(of, rpivid_mem_of_match);
++
++static struct platform_driver rpivid_mem_driver = {
++ .probe = rpivid_mem_probe,
++ .remove = rpivid_mem_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = rpivid_mem_of_match,
++ },
++};
++
++module_platform_driver(rpivid_mem_driver);
++
++MODULE_ALIAS("platform:rpivid-mem");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Driver for accessing RPiVid decoder registers from userspace");
+--- a/drivers/mfd/bcm2835-pm.c
++++ b/drivers/mfd/bcm2835-pm.c
+@@ -50,14 +50,14 @@ static int bcm2835_pm_probe(struct platf
+ if (ret)
+ return ret;
+
+- /* Map the ARGON ASB regs if present. */
++ /* Map the RPiVid ASB regs if present. */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (res) {
+- pm->arg_asb = devm_ioremap_resource(dev, res);
+- if (IS_ERR(pm->arg_asb)) {
+- dev_err(dev, "Failed to map ARGON ASB: %ld\n",
+- PTR_ERR(pm->arg_asb));
+- return PTR_ERR(pm->arg_asb);
++ pm->rpivid_asb = devm_ioremap_resource(dev, res);
++ if (IS_ERR(pm->rpivid_asb)) {
++ dev_err(dev, "Failed to map RPiVid ASB: %ld\n",
++ PTR_ERR(pm->rpivid_asb));
++ return PTR_ERR(pm->rpivid_asb);
+ }
+ }
+
+--- a/drivers/soc/bcm/bcm2835-power.c
++++ b/drivers/soc/bcm/bcm2835-power.c
+@@ -637,15 +637,15 @@ static int bcm2835_power_probe(struct pl
+ power->base = pm->base;
+ power->asb = pm->asb;
+
+- /* 2711 hack: the new ARGON ASB took over V3D, which is our
++ /* 2711 hack: the new RPiVid ASB took over V3D, which is our
+ * only consumer of this driver so far. The old ASB seems to
+ * still be present with ISP and H264 bits but no V3D, but I
+ * don't know if that's real or not. The V3D is in the same
+ * place in the new ASB as the old one, so just poke the new
+ * one for now.
+ */
+- if (pm->arg_asb) {
+- power->asb = pm->arg_asb;
++ if (pm->rpivid_asb) {
++ power->asb = pm->rpivid_asb;
+ power->is_2711 = true;
+ }
+
+--- a/include/linux/mfd/bcm2835-pm.h
++++ b/include/linux/mfd/bcm2835-pm.h
+@@ -9,7 +9,7 @@ struct bcm2835_pm {
+ struct device *dev;
+ void __iomem *base;
+ void __iomem *asb;
+- void __iomem *arg_asb;
++ void __iomem *rpivid_asb;
+ };
+
+ #endif /* BCM2835_MFD_PM_H */
+++ /dev/null
-From a14162d8da62fb570df916d7386febe51d6ed2bc Mon Sep 17 00:00:00 2001
-Date: Wed, 31 Jul 2019 17:41:47 +0100
-Subject: [PATCH] overlays: Update the upstream overlay
-
-The recent vc4-kms-v3d commit has changed the content of the
-upstream overlay (even though the extra fragment is disabled).
-
----
- arch/arm/boot/dts/overlays/upstream-overlay.dts | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/arch/arm/boot/dts/overlays/upstream-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts
-@@ -110,6 +110,12 @@
- };
- };
- fragment@17 {
-+ target = <&hdmi>;
-+ __dormant__ {
-+ dmas;
-+ };
-+ };
-+ fragment@18 {
- target = <&usb>;
- #address-cells = <1>;
- #size-cells = <1>;
+++ /dev/null
-From c2957d7709a43c81e5345d537feaa6980ffcc1a4 Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Jul 2019 12:02:59 +0100
-Subject: [PATCH] Fixup FKMS interrupt handing for non-existent display
-
-If an errant interrupt flag was received from a non-existent display,
-a NULL pointer access was made. Protect against this by checking if a
-second display is present prior to checking the interrupt flags.
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 17 ++++++++++-------
- 1 file changed, 10 insertions(+), 7 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1056,14 +1056,17 @@ static irqreturn_t vc4_crtc_irq_handler(
- vc4_crtc_handle_page_flip(crtc_list[0]);
- }
-
-- /* Check for the secondary display too */
-- chan = readl(crtc_list[0]->regs + SMIDSW1);
-+ if (crtc_list[1]) {
-+ /* Check for the secondary display too */
-+ chan = readl(crtc_list[0]->regs + SMIDSW1);
-
-- if (chan & 1) {
-- writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
-- if (crtc_list[1]->vblank_enabled)
-- drm_crtc_handle_vblank(&crtc_list[1]->base);
-- vc4_crtc_handle_page_flip(crtc_list[1]);
-+ if (chan & 1) {
-+ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
-+
-+ if (crtc_list[1]->vblank_enabled)
-+ drm_crtc_handle_vblank(&crtc_list[1]->base);
-+ vc4_crtc_handle_page_flip(crtc_list[1]);
-+ }
- }
- }
-
--- /dev/null
+From 80c20ff00542b050733780ae6088e50663ee8d78 Mon Sep 17 00:00:00 2001
+Date: Mon, 29 Jul 2019 12:03:21 +0100
+Subject: [PATCH] driver: char: rpivid - also support legacy name
+
+Provide transitional support for the previous names of
+the character devices.
+
+---
+ drivers/char/broadcom/rpivid-mem.c | 22 ++++++++++++++++++----
+ 1 file changed, 18 insertions(+), 4 deletions(-)
+
+--- a/drivers/char/broadcom/rpivid-mem.c
++++ b/drivers/char/broadcom/rpivid-mem.c
+@@ -66,7 +66,7 @@ static int rpivid_mem_open(struct inode
+ int dev = iminor(inode);
+ int ret = 0;
+ struct rpivid_mem_priv *priv;
+- if (dev != DEVICE_MINOR)
++ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
+ ret = -ENXIO;
+
+ priv = container_of(inode->i_cdev, struct rpivid_mem_priv,
+@@ -82,7 +82,7 @@ static int rpivid_mem_release(struct ino
+ int dev = iminor(inode);
+ int ret = 0;
+
+- if (dev != DEVICE_MINOR)
++ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
+ ret = -ENXIO;
+
+ return ret;
+@@ -167,14 +167,14 @@ static int rpivid_mem_probe(struct platf
+ /* Create character device entries */
+
+ err = alloc_chrdev_region(&priv->devid,
+- DEVICE_MINOR, 1, priv->name);
++ DEVICE_MINOR, 2, priv->name);
+ if (err != 0) {
+ dev_err(priv->dev, "unable to allocate device number");
+ goto failed_alloc_chrdev;
+ }
+ cdev_init(&priv->rpivid_mem_cdev, &rpivid_mem_fops);
+ priv->rpivid_mem_cdev.owner = THIS_MODULE;
+- err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 1);
++ err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 2);
+ if (err != 0) {
+ dev_err(priv->dev, "unable to register device");
+ goto failed_cdev_add;
+@@ -194,6 +194,20 @@ static int rpivid_mem_probe(struct platf
+ if (IS_ERR(ptr_err))
+ goto failed_device_create;
+
++ /* Legacy alias */
++ {
++ char *oldname = kstrdup(priv->name, GFP_KERNEL);
++
++ oldname[1] = 'a';
++ oldname[2] = 'r';
++ oldname[3] = 'g';
++ oldname[4] = 'o';
++ oldname[5] = 'n';
++ (void)device_create(priv->class, NULL, priv->devid + 1, NULL,
++ oldname + 1);
++ kfree(oldname);
++ }
++
+ dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
+ priv->name, priv->regs_phys, priv->mem_window_len);
+
+++ /dev/null
-From 6c8c9ca56ce6039ade09d26c069132538e4de9f0 Mon Sep 17 00:00:00 2001
-Date: Sun, 28 Jul 2019 22:22:36 +0100
-Subject: [PATCH] drivers: char: Use correct name for the Raspberry Pi
- video decoder
-
-Replace the old code name with a more appropriate name - RPiVid.
-
----
- arch/arm/boot/dts/bcm2838.dtsi | 10 +-
- drivers/char/broadcom/Kconfig | 8 +-
- drivers/char/broadcom/Makefile | 2 +-
- .../broadcom/{argon-mem.c => rpivid-mem.c} | 105 +++++++++---------
- drivers/mfd/bcm2835-pm.c | 12 +-
- drivers/soc/bcm/bcm2835-power.c | 6 +-
- include/linux/mfd/bcm2835-pm.h | 2 +-
- 8 files changed, 71 insertions(+), 76 deletions(-)
- rename drivers/char/broadcom/{argon-mem.c => rpivid-mem.c} (69%)
-
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -409,26 +409,26 @@
- };
-
- hevc-decoder@7eb00000 {
-- compatible = "raspberrypi,argon-hevc-decoder";
-+ compatible = "raspberrypi,rpivid-hevc-decoder";
- reg = <0x0 0x7eb00000 0x10000>;
- status = "okay";
- };
-
-- argon-local-intc@7eb10000 {
-- compatible = "raspberrypi,argon-local-intc";
-+ rpivid-local-intc@7eb10000 {
-+ compatible = "raspberrypi,rpivid-local-intc";
- reg = <0x0 0x7eb10000 0x1000>;
- status = "okay";
- interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
- };
-
- h264-decoder@7eb20000 {
-- compatible = "raspberrypi,argon-h264-decoder";
-+ compatible = "raspberrypi,rpivid-h264-decoder";
- reg = <0x0 0x7eb20000 0x10000>;
- status = "okay";
- };
-
- vp9-decoder@7eb30000 {
-- compatible = "raspberrypi,argon-vp9-decoder";
-+ compatible = "raspberrypi,rpivid-vp9-decoder";
- reg = <0x0 0x7eb30000 0x10000>;
- status = "okay";
- };
---- a/drivers/char/broadcom/Kconfig
-+++ b/drivers/char/broadcom/Kconfig
-@@ -50,10 +50,10 @@ config BCM2835_SMI_DEV
- Broadcom's Secondary Memory interface. The low-level functionality is provided
- by the SMI driver itself.
-
--config ARGON_MEM
-- tristate "Character device driver for the Argon decoder hardware"
-+config RPIVID_MEM
-+ tristate "Character device driver for the Raspberry Pi RPIVid video decoder hardware"
- default n
- help
- This driver provides a character device interface for memory-map operations
-- so userspace tools can access the control and status registers of the Argon
-- video decoder hardware.
-+ so userspace tools can access the control and status registers of the
-+ Raspberry Pi RPiVid video decoder hardware.
---- a/drivers/char/broadcom/Makefile
-+++ b/drivers/char/broadcom/Makefile
-@@ -4,4 +4,4 @@ obj-$(CONFIG_BCM_VC_SM) += vc_sm
-
- obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
- obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o
--obj-$(CONFIG_ARGON_MEM) += argon-mem.o
-+obj-$(CONFIG_RPIVID_MEM) += rpivid-mem.o
---- a/drivers/char/broadcom/argon-mem.c
-+++ /dev/null
-@@ -1,277 +0,0 @@
--/**
-- * argon-mem.c - character device access to the Argon decoder registers
-- *
-- * Based on bcm2835-gpiomem.c. Provides IO memory access to the decoder
-- * register blocks such that ffmpeg plugins can access the hardware.
-- *
-- * Copyright (c) 2019, Raspberry Pi (Trading) Ltd.
-- *
-- * Redistribution and use in source and binary forms, with or without
-- * modification, are permitted provided that the following conditions
-- * are met:
-- * 1. Redistributions of source code must retain the above copyright
-- * notice, this list of conditions, and the following disclaimer,
-- * without modification.
-- * 2. Redistributions in binary form must reproduce the above copyright
-- * notice, this list of conditions and the following disclaimer in the
-- * documentation and/or other materials provided with the distribution.
-- * 3. The names of the above-listed copyright holders may not be used
-- * to endorse or promote products derived from this software without
-- * specific prior written permission.
-- *
-- * ALTERNATIVELY, this software may be distributed under the terms of the
-- * GNU General Public License ("GPL") version 2, as published by the Free
-- * Software Foundation.
-- *
-- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-- */
--
--#include <linux/kernel.h>
--#include <linux/module.h>
--#include <linux/of.h>
--#include <linux/of_device.h>
--#include <linux/platform_device.h>
--#include <linux/mm.h>
--#include <linux/slab.h>
--#include <linux/cdev.h>
--#include <linux/pagemap.h>
--#include <linux/io.h>
--
--#define DRIVER_NAME "argon-mem"
--#define DEVICE_MINOR 0
--
--struct argon_mem_priv {
-- dev_t devid;
-- struct class *class;
-- struct cdev argon_mem_cdev;
-- unsigned long regs_phys;
-- unsigned long mem_window_len;
-- struct device *dev;
-- const char *name;
--};
--
--static int argon_mem_open(struct inode *inode, struct file *file)
--{
-- int dev = iminor(inode);
-- int ret = 0;
-- struct argon_mem_priv *priv;
-- if (dev != DEVICE_MINOR)
-- ret = -ENXIO;
--
-- priv = container_of(inode->i_cdev, struct argon_mem_priv,
-- argon_mem_cdev);
-- if (!priv)
-- return -EINVAL;
-- file->private_data = priv;
-- return ret;
--}
--
--static int argon_mem_release(struct inode *inode, struct file *file)
--{
-- int dev = iminor(inode);
-- int ret = 0;
--
-- if (dev != DEVICE_MINOR)
-- ret = -ENXIO;
--
-- return ret;
--}
--
--static const struct vm_operations_struct argon_mem_vm_ops = {
--#ifdef CONFIG_HAVE_IOREMAP_PROT
-- .access = generic_access_phys
--#endif
--};
--
--static int argon_mem_mmap(struct file *file, struct vm_area_struct *vma)
--{
-- struct argon_mem_priv *priv;
-- unsigned long pages;
--
-- priv = file->private_data;
-- pages = priv->regs_phys >> PAGE_SHIFT;
-- /*
-- * The address decode is far larger than the actual number of registers.
-- * Just map the whole lot in.
-- */
-- vma->vm_page_prot = phys_mem_access_prot(file, pages,
-- priv->mem_window_len,
-- vma->vm_page_prot);
-- vma->vm_ops = &argon_mem_vm_ops;
-- if (remap_pfn_range(vma, vma->vm_start,
-- pages,
-- priv->mem_window_len,
-- vma->vm_page_prot)) {
-- return -EAGAIN;
-- }
-- return 0;
--}
--
--static const struct file_operations
--argon_mem_fops = {
-- .owner = THIS_MODULE,
-- .open = argon_mem_open,
-- .release = argon_mem_release,
-- .mmap = argon_mem_mmap,
--};
--
--static const struct of_device_id argon_mem_of_match[];
--static int argon_mem_probe(struct platform_device *pdev)
--{
-- int err;
-- void *ptr_err;
-- const struct of_device_id *id;
-- struct device *dev = &pdev->dev;
-- struct device *argon_mem_dev;
-- struct resource *ioresource;
-- struct argon_mem_priv *priv;
--
--
-- /* Allocate buffers and instance data */
--
-- priv = kzalloc(sizeof(struct argon_mem_priv), GFP_KERNEL);
--
-- if (!priv) {
-- err = -ENOMEM;
-- goto failed_inst_alloc;
-- }
-- platform_set_drvdata(pdev, priv);
--
-- priv->dev = dev;
-- id = of_match_device(argon_mem_of_match, dev);
-- if (!id)
-- return -EINVAL;
-- priv->name = id->data;
--
-- ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-- if (ioresource) {
-- priv->regs_phys = ioresource->start;
-- priv->mem_window_len = ioresource->end - ioresource->start;
-- } else {
-- dev_err(priv->dev, "failed to get IO resource");
-- err = -ENOENT;
-- goto failed_get_resource;
-- }
--
-- /* Create character device entries */
--
-- err = alloc_chrdev_region(&priv->devid,
-- DEVICE_MINOR, 1, priv->name);
-- if (err != 0) {
-- dev_err(priv->dev, "unable to allocate device number");
-- goto failed_alloc_chrdev;
-- }
-- cdev_init(&priv->argon_mem_cdev, &argon_mem_fops);
-- priv->argon_mem_cdev.owner = THIS_MODULE;
-- err = cdev_add(&priv->argon_mem_cdev, priv->devid, 1);
-- if (err != 0) {
-- dev_err(priv->dev, "unable to register device");
-- goto failed_cdev_add;
-- }
--
-- /* Create sysfs entries */
--
-- priv->class = class_create(THIS_MODULE, priv->name);
-- ptr_err = priv->class;
-- if (IS_ERR(ptr_err))
-- goto failed_class_create;
--
-- argon_mem_dev = device_create(priv->class, NULL,
-- priv->devid, NULL,
-- priv->name);
-- ptr_err = argon_mem_dev;
-- if (IS_ERR(ptr_err))
-- goto failed_device_create;
--
-- dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
-- priv->name, priv->regs_phys, priv->mem_window_len);
--
-- return 0;
--
--failed_device_create:
-- class_destroy(priv->class);
--failed_class_create:
-- cdev_del(&priv->argon_mem_cdev);
-- err = PTR_ERR(ptr_err);
--failed_cdev_add:
-- unregister_chrdev_region(priv->devid, 1);
--failed_alloc_chrdev:
--failed_get_resource:
-- kfree(priv);
--failed_inst_alloc:
-- dev_err(priv->dev, "could not load argon_mem");
-- return err;
--}
--
--static int argon_mem_remove(struct platform_device *pdev)
--{
-- struct device *dev = &pdev->dev;
-- struct argon_mem_priv *priv = platform_get_drvdata(pdev);
--
-- device_destroy(priv->class, priv->devid);
-- class_destroy(priv->class);
-- cdev_del(&priv->argon_mem_cdev);
-- unregister_chrdev_region(priv->devid, 1);
-- kfree(priv);
--
-- dev_info(dev, "%s driver removed - OK", priv->name);
-- return 0;
--}
--
--static const char argon_hevc_name[] = "argon-hevcmem";
--static const char argon_h264_name[] = "argon-h264mem";
--static const char argon_vp9_name[] = "argon-vp9mem";
--static const char argon_intc_name[] = "argon-intcmem";
--
--static const struct of_device_id argon_mem_of_match[] = {
-- {
-- .compatible = "raspberrypi,argon-hevc-decoder",
-- .data = &argon_hevc_name,
-- },
-- {
-- .compatible = "raspberrypi,argon-h264-decoder",
-- .data = &argon_h264_name,
-- },
-- {
-- .compatible = "raspberrypi,argon-vp9-decoder",
-- .data = &argon_vp9_name,
-- },
-- /* The "intc" is included as this block of hardware contains the
-- * "frame done" status flags.
-- */
-- {
-- .compatible = "raspberrypi,argon-local-intc",
-- .data = &argon_intc_name,
-- },
-- { /* sentinel */ },
--};
--
--MODULE_DEVICE_TABLE(of, argon_mem_of_match);
--
--static struct platform_driver argon_mem_driver = {
-- .probe = argon_mem_probe,
-- .remove = argon_mem_remove,
-- .driver = {
-- .name = DRIVER_NAME,
-- .owner = THIS_MODULE,
-- .of_match_table = argon_mem_of_match,
-- },
--};
--
--module_platform_driver(argon_mem_driver);
--
--MODULE_ALIAS("platform:argon-mem");
--MODULE_LICENSE("GPL");
--MODULE_DESCRIPTION("Driver for accessing Argon decoder registers from userspace");
---- /dev/null
-+++ b/drivers/char/broadcom/rpivid-mem.c
-@@ -0,0 +1,272 @@
-+/**
-+ * rpivid-mem.c - character device access to the RPiVid decoder registers
-+ *
-+ * Based on bcm2835-gpiomem.c. Provides IO memory access to the decoder
-+ * register blocks such that ffmpeg plugins can access the hardware.
-+ *
-+ * Copyright (c) 2019, Raspberry Pi (Trading) Ltd.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/cdev.h>
-+#include <linux/pagemap.h>
-+#include <linux/io.h>
-+
-+#define DRIVER_NAME "rpivid-mem"
-+#define DEVICE_MINOR 0
-+
-+struct rpivid_mem_priv {
-+ dev_t devid;
-+ struct class *class;
-+ struct cdev rpivid_mem_cdev;
-+ unsigned long regs_phys;
-+ unsigned long mem_window_len;
-+ struct device *dev;
-+ const char *name;
-+};
-+
-+static int rpivid_mem_open(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode);
-+ int ret = 0;
-+ struct rpivid_mem_priv *priv;
-+ if (dev != DEVICE_MINOR)
-+ ret = -ENXIO;
-+
-+ priv = container_of(inode->i_cdev, struct rpivid_mem_priv,
-+ rpivid_mem_cdev);
-+ if (!priv)
-+ return -EINVAL;
-+ file->private_data = priv;
-+ return ret;
-+}
-+
-+static int rpivid_mem_release(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode);
-+ int ret = 0;
-+
-+ if (dev != DEVICE_MINOR)
-+ ret = -ENXIO;
-+
-+ return ret;
-+}
-+
-+static const struct vm_operations_struct rpivid_mem_vm_ops = {
-+#ifdef CONFIG_HAVE_IOREMAP_PROT
-+ .access = generic_access_phys
-+#endif
-+};
-+
-+static int rpivid_mem_mmap(struct file *file, struct vm_area_struct *vma)
-+{
-+ struct rpivid_mem_priv *priv;
-+ unsigned long pages;
-+
-+ priv = file->private_data;
-+ pages = priv->regs_phys >> PAGE_SHIFT;
-+ /*
-+ * The address decode is far larger than the actual number of registers.
-+ * Just map the whole lot in.
-+ */
-+ vma->vm_page_prot = phys_mem_access_prot(file, pages,
-+ priv->mem_window_len,
-+ vma->vm_page_prot);
-+ vma->vm_ops = &rpivid_mem_vm_ops;
-+ if (remap_pfn_range(vma, vma->vm_start,
-+ pages,
-+ priv->mem_window_len,
-+ vma->vm_page_prot)) {
-+ return -EAGAIN;
-+ }
-+ return 0;
-+}
-+
-+static const struct file_operations
-+rpivid_mem_fops = {
-+ .owner = THIS_MODULE,
-+ .open = rpivid_mem_open,
-+ .release = rpivid_mem_release,
-+ .mmap = rpivid_mem_mmap,
-+};
-+
-+static const struct of_device_id rpivid_mem_of_match[];
-+static int rpivid_mem_probe(struct platform_device *pdev)
-+{
-+ int err;
-+ void *ptr_err;
-+ const struct of_device_id *id;
-+ struct device *dev = &pdev->dev;
-+ struct device *rpivid_mem_dev;
-+ struct resource *ioresource;
-+ struct rpivid_mem_priv *priv;
-+
-+
-+ /* Allocate buffers and instance data */
-+
-+ priv = kzalloc(sizeof(struct rpivid_mem_priv), GFP_KERNEL);
-+
-+ if (!priv) {
-+ err = -ENOMEM;
-+ goto failed_inst_alloc;
-+ }
-+ platform_set_drvdata(pdev, priv);
-+
-+ priv->dev = dev;
-+ id = of_match_device(rpivid_mem_of_match, dev);
-+ if (!id)
-+ return -EINVAL;
-+ priv->name = id->data;
-+
-+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (ioresource) {
-+ priv->regs_phys = ioresource->start;
-+ priv->mem_window_len = ioresource->end - ioresource->start;
-+ } else {
-+ dev_err(priv->dev, "failed to get IO resource");
-+ err = -ENOENT;
-+ goto failed_get_resource;
-+ }
-+
-+ /* Create character device entries */
-+
-+ err = alloc_chrdev_region(&priv->devid,
-+ DEVICE_MINOR, 1, priv->name);
-+ if (err != 0) {
-+ dev_err(priv->dev, "unable to allocate device number");
-+ goto failed_alloc_chrdev;
-+ }
-+ cdev_init(&priv->rpivid_mem_cdev, &rpivid_mem_fops);
-+ priv->rpivid_mem_cdev.owner = THIS_MODULE;
-+ err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 1);
-+ if (err != 0) {
-+ dev_err(priv->dev, "unable to register device");
-+ goto failed_cdev_add;
-+ }
-+
-+ /* Create sysfs entries */
-+
-+ priv->class = class_create(THIS_MODULE, priv->name);
-+ ptr_err = priv->class;
-+ if (IS_ERR(ptr_err))
-+ goto failed_class_create;
-+
-+ rpivid_mem_dev = device_create(priv->class, NULL,
-+ priv->devid, NULL,
-+ priv->name);
-+ ptr_err = rpivid_mem_dev;
-+ if (IS_ERR(ptr_err))
-+ goto failed_device_create;
-+
-+ dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
-+ priv->name, priv->regs_phys, priv->mem_window_len);
-+
-+ return 0;
-+
-+failed_device_create:
-+ class_destroy(priv->class);
-+failed_class_create:
-+ cdev_del(&priv->rpivid_mem_cdev);
-+ err = PTR_ERR(ptr_err);
-+failed_cdev_add:
-+ unregister_chrdev_region(priv->devid, 1);
-+failed_alloc_chrdev:
-+failed_get_resource:
-+ kfree(priv);
-+failed_inst_alloc:
-+ dev_err(priv->dev, "could not load rpivid_mem");
-+ return err;
-+}
-+
-+static int rpivid_mem_remove(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct rpivid_mem_priv *priv = platform_get_drvdata(pdev);
-+
-+ device_destroy(priv->class, priv->devid);
-+ class_destroy(priv->class);
-+ cdev_del(&priv->rpivid_mem_cdev);
-+ unregister_chrdev_region(priv->devid, 1);
-+ kfree(priv);
-+
-+ dev_info(dev, "%s driver removed - OK", priv->name);
-+ return 0;
-+}
-+
-+static const struct of_device_id rpivid_mem_of_match[] = {
-+ {
-+ .compatible = "raspberrypi,rpivid-hevc-decoder",
-+ .data = "rpivid-hevcmem",
-+ },
-+ {
-+ .compatible = "raspberrypi,rpivid-h264-decoder",
-+ .data = "rpivid-h264mem",
-+ },
-+ {
-+ .compatible = "raspberrypi,rpivid-vp9-decoder",
-+ .data = "rpivid-vp9mem",
-+ },
-+ /* The "intc" is included as this block of hardware contains the
-+ * "frame done" status flags.
-+ */
-+ {
-+ .compatible = "raspberrypi,rpivid-local-intc",
-+ .data = "rpivid-intcmem",
-+ },
-+ { /* sentinel */ },
-+};
-+
-+MODULE_DEVICE_TABLE(of, rpivid_mem_of_match);
-+
-+static struct platform_driver rpivid_mem_driver = {
-+ .probe = rpivid_mem_probe,
-+ .remove = rpivid_mem_remove,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = rpivid_mem_of_match,
-+ },
-+};
-+
-+module_platform_driver(rpivid_mem_driver);
-+
-+MODULE_ALIAS("platform:rpivid-mem");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Driver for accessing RPiVid decoder registers from userspace");
---- a/drivers/mfd/bcm2835-pm.c
-+++ b/drivers/mfd/bcm2835-pm.c
-@@ -50,14 +50,14 @@ static int bcm2835_pm_probe(struct platf
- if (ret)
- return ret;
-
-- /* Map the ARGON ASB regs if present. */
-+ /* Map the RPiVid ASB regs if present. */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
- if (res) {
-- pm->arg_asb = devm_ioremap_resource(dev, res);
-- if (IS_ERR(pm->arg_asb)) {
-- dev_err(dev, "Failed to map ARGON ASB: %ld\n",
-- PTR_ERR(pm->arg_asb));
-- return PTR_ERR(pm->arg_asb);
-+ pm->rpivid_asb = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(pm->rpivid_asb)) {
-+ dev_err(dev, "Failed to map RPiVid ASB: %ld\n",
-+ PTR_ERR(pm->rpivid_asb));
-+ return PTR_ERR(pm->rpivid_asb);
- }
- }
-
---- a/drivers/soc/bcm/bcm2835-power.c
-+++ b/drivers/soc/bcm/bcm2835-power.c
-@@ -637,15 +637,15 @@ static int bcm2835_power_probe(struct pl
- power->base = pm->base;
- power->asb = pm->asb;
-
-- /* 2711 hack: the new ARGON ASB took over V3D, which is our
-+ /* 2711 hack: the new RPiVid ASB took over V3D, which is our
- * only consumer of this driver so far. The old ASB seems to
- * still be present with ISP and H264 bits but no V3D, but I
- * don't know if that's real or not. The V3D is in the same
- * place in the new ASB as the old one, so just poke the new
- * one for now.
- */
-- if (pm->arg_asb) {
-- power->asb = pm->arg_asb;
-+ if (pm->rpivid_asb) {
-+ power->asb = pm->rpivid_asb;
- power->is_2711 = true;
- }
-
---- a/include/linux/mfd/bcm2835-pm.h
-+++ b/include/linux/mfd/bcm2835-pm.h
-@@ -9,7 +9,7 @@ struct bcm2835_pm {
- struct device *dev;
- void __iomem *base;
- void __iomem *asb;
-- void __iomem *arg_asb;
-+ void __iomem *rpivid_asb;
- };
-
- #endif /* BCM2835_MFD_PM_H */
--- /dev/null
+From 16c1e20b50e121f836f434bb6c22c73e2f51d29f Mon Sep 17 00:00:00 2001
+Date: Thu, 1 Aug 2019 16:41:20 +0100
+Subject: [PATCH] hid: usb: Add device quirks for Freeway Airmouse T3
+ and MX3
+
+These wireless mouse/keyboard combo remote control devices specify
+multiple "wheel" events in their report descriptors. The wheel events
+are incorrectly defined and apparently map to accelerometer data, leading
+to spurious mouse scroll events being generated at an extreme rate when
+the device is moved.
+
+As a workaround, use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE to mask
+feeding the extra wheel events to the input subsystem.
+
+See: https://github.com/raspberrypi/firmware/issues/1189
+
+---
+ drivers/hid/hid-ids.h | 6 ++++++
+ drivers/hid/hid-quirks.c | 2 ++
+ 2 files changed, 8 insertions(+)
+
+--- a/drivers/hid/hid-ids.h
++++ b/drivers/hid/hid-ids.h
+@@ -222,6 +222,9 @@
+ #define USB_VENDOR_ID_BAANTO 0x2453
+ #define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100
+
++#define USB_VENDOR_ID_BEKEN 0x25a7
++#define USB_DEVICE_ID_AIRMOUSE_T3 0x2402
++
+ #define USB_VENDOR_ID_BELKIN 0x050d
+ #define USB_DEVICE_ID_FLIP_KVM 0x3201
+
+@@ -1196,6 +1199,9 @@
+ #define USB_VENDOR_ID_XAT 0x2505
+ #define USB_DEVICE_ID_XAT_CSR 0x0220
+
++#define USB_VENDOR_ID_XENTA 0x1d57
++#define USB_DEVICE_ID_AIRMOUSE_MX3 0xad03
++
+ #define USB_VENDOR_ID_XIN_MO 0x16c0
+ #define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE 0x05e1
+ #define USB_DEVICE_ID_THT_2P_ARCADE 0x75e1
+--- a/drivers/hid/hid-quirks.c
++++ b/drivers/hid/hid-quirks.c
+@@ -43,6 +43,7 @@ static const struct hid_device_id hid_qu
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682), HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692), HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
++ { HID_USB_DEVICE(USB_VENDOR_ID_BEKEN, USB_DEVICE_ID_AIRMOUSE_T3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },
+@@ -175,6 +176,7 @@ static const struct hid_device_id hid_qu
+ { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET), HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
++ { HID_USB_DEVICE(USB_VENDOR_ID_XENTA, USB_DEVICE_ID_AIRMOUSE_MX3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT },
+
+ { 0 }
+++ /dev/null
-From 80c20ff00542b050733780ae6088e50663ee8d78 Mon Sep 17 00:00:00 2001
-Date: Mon, 29 Jul 2019 12:03:21 +0100
-Subject: [PATCH] driver: char: rpivid - also support legacy name
-
-Provide transitional support for the previous names of
-the character devices.
-
----
- drivers/char/broadcom/rpivid-mem.c | 22 ++++++++++++++++++----
- 1 file changed, 18 insertions(+), 4 deletions(-)
-
---- a/drivers/char/broadcom/rpivid-mem.c
-+++ b/drivers/char/broadcom/rpivid-mem.c
-@@ -66,7 +66,7 @@ static int rpivid_mem_open(struct inode
- int dev = iminor(inode);
- int ret = 0;
- struct rpivid_mem_priv *priv;
-- if (dev != DEVICE_MINOR)
-+ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
- ret = -ENXIO;
-
- priv = container_of(inode->i_cdev, struct rpivid_mem_priv,
-@@ -82,7 +82,7 @@ static int rpivid_mem_release(struct ino
- int dev = iminor(inode);
- int ret = 0;
-
-- if (dev != DEVICE_MINOR)
-+ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
- ret = -ENXIO;
-
- return ret;
-@@ -167,14 +167,14 @@ static int rpivid_mem_probe(struct platf
- /* Create character device entries */
-
- err = alloc_chrdev_region(&priv->devid,
-- DEVICE_MINOR, 1, priv->name);
-+ DEVICE_MINOR, 2, priv->name);
- if (err != 0) {
- dev_err(priv->dev, "unable to allocate device number");
- goto failed_alloc_chrdev;
- }
- cdev_init(&priv->rpivid_mem_cdev, &rpivid_mem_fops);
- priv->rpivid_mem_cdev.owner = THIS_MODULE;
-- err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 1);
-+ err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 2);
- if (err != 0) {
- dev_err(priv->dev, "unable to register device");
- goto failed_cdev_add;
-@@ -194,6 +194,20 @@ static int rpivid_mem_probe(struct platf
- if (IS_ERR(ptr_err))
- goto failed_device_create;
-
-+ /* Legacy alias */
-+ {
-+ char *oldname = kstrdup(priv->name, GFP_KERNEL);
-+
-+ oldname[1] = 'a';
-+ oldname[2] = 'r';
-+ oldname[3] = 'g';
-+ oldname[4] = 'o';
-+ oldname[5] = 'n';
-+ (void)device_create(priv->class, NULL, priv->devid + 1, NULL,
-+ oldname + 1);
-+ kfree(oldname);
-+ }
-+
- dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
- priv->name, priv->regs_phys, priv->mem_window_len);
-
--- /dev/null
+From b96e24487cc48a2cb593f27c24074087a21de848 Mon Sep 17 00:00:00 2001
+Date: Fri, 14 Jun 2019 10:12:07 +0100
+Subject: [PATCH] drm/vc4: Add "Broadcast RGB" connector property
+
+Some HDMI monitors do not abide by the full or limited
+(16-235) range RGB flags in the AVI infoframe. This can
+result in images looking washed out (if given limited and
+interpreting as full), or detail disappearing at the extremes
+(given full and interpreting as limited).
+
+Copy the Intel i915 driver's approach of adding an override
+property ("Broadcast RGB") to force one mode or the other.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 190 +++++++++++++++++++++++--
+ 1 file changed, 177 insertions(+), 13 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -285,6 +285,13 @@ to_vc4_fkms_encoder(struct drm_encoder *
+ return container_of(encoder, struct vc4_fkms_encoder, base);
+ }
+
++/* "Broadcast RGB" property.
++ * Allows overriding of HDMI full or limited range RGB
++ */
++#define VC4_BROADCAST_RGB_AUTO 0
++#define VC4_BROADCAST_RGB_FULL 1
++#define VC4_BROADCAST_RGB_LIMITED 2
++
+ /* VC4 FKMS connector KMS struct */
+ struct vc4_fkms_connector {
+ struct drm_connector base;
+@@ -297,6 +304,8 @@ struct vc4_fkms_connector {
+ struct vc4_dev *vc4_dev;
+ u32 display_number;
+ u32 display_type;
++
++ struct drm_property *broadcast_rgb_property;
+ };
+
+ static inline struct vc4_fkms_connector *
+@@ -305,6 +314,16 @@ to_vc4_fkms_connector(struct drm_connect
+ return container_of(connector, struct vc4_fkms_connector, base);
+ }
+
++/* VC4 FKMS connector state */
++struct vc4_fkms_connector_state {
++ struct drm_connector_state base;
++
++ int broadcast_rgb;
++};
++
++#define to_vc4_fkms_connector_state(x) \
++ container_of(x, struct vc4_fkms_connector_state, base)
++
+ static u32 vc4_get_display_type(u32 display_number)
+ {
+ const u32 display_types[] = {
+@@ -832,8 +851,6 @@ static void vc4_crtc_mode_set_nofb(struc
+ mode->picture_aspect_ratio, mode->flags);
+ mb.timings.display = vc4_crtc->display_number;
+
+- mb.timings.video_id_code = frame.avi.video_code;
+-
+ mb.timings.clock = mode->clock;
+ mb.timings.hdisplay = mode->hdisplay;
+ mb.timings.hsync_start = mode->hsync_start;
+@@ -871,11 +888,30 @@ static void vc4_crtc_mode_set_nofb(struc
+ break;
+ }
+
+- if (!vc4_encoder->hdmi_monitor)
++ if (!vc4_encoder->hdmi_monitor) {
+ mb.timings.flags |= TIMINGS_FLAGS_DVI;
+- else if (drm_default_rgb_quant_range(mode) ==
++ mb.timings.video_id_code = frame.avi.video_code;
++ } else {
++ struct vc4_fkms_connector_state *conn_state =
++ to_vc4_fkms_connector_state(vc4_crtc->connector->state);
++
++ /* Do not provide a VIC as the HDMI spec requires that we do not
++ * signal the opposite of the defined range in the AVI
++ * infoframe.
++ */
++ mb.timings.video_id_code = 0;
++
++ if (conn_state->broadcast_rgb == VC4_BROADCAST_RGB_AUTO) {
++ /* See CEA-861-E - 5.1 Default Encoding Parameters */
++ if (drm_default_rgb_quant_range(mode) ==
+ HDMI_QUANTIZATION_RANGE_LIMITED)
+- mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
++ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
++ } else {
++ if (conn_state->broadcast_rgb ==
++ VC4_BROADCAST_RGB_LIMITED)
++ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
++ }
++ }
+
+ /*
+ FIXME: To implement
+@@ -1340,13 +1376,95 @@ static void vc4_fkms_connector_destroy(s
+ drm_connector_cleanup(connector);
+ }
+
++/**
++ * vc4_connector_duplicate_state - duplicate connector state
++ * @connector: digital connector
++ *
++ * Allocates and returns a copy of the connector state (both common and
++ * digital connector specific) for the specified connector.
++ *
++ * Returns: The newly allocated connector state, or NULL on failure.
++ */
++struct drm_connector_state *
++vc4_connector_duplicate_state(struct drm_connector *connector)
++{
++ struct vc4_fkms_connector_state *state;
++
++ state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
++ if (!state)
++ return NULL;
++
++ __drm_atomic_helper_connector_duplicate_state(connector, &state->base);
++ return &state->base;
++}
++
++/**
++ * vc4_connector_atomic_get_property - hook for connector->atomic_get_property.
++ * @connector: Connector to get the property for.
++ * @state: Connector state to retrieve the property from.
++ * @property: Property to retrieve.
++ * @val: Return value for the property.
++ *
++ * Returns the atomic property value for a digital connector.
++ */
++int vc4_connector_atomic_get_property(struct drm_connector *connector,
++ const struct drm_connector_state *state,
++ struct drm_property *property,
++ uint64_t *val)
++{
++ struct vc4_fkms_connector *fkms_connector =
++ to_vc4_fkms_connector(connector);
++ struct vc4_fkms_connector_state *vc4_conn_state =
++ to_vc4_fkms_connector_state(state);
++
++ if (property == fkms_connector->broadcast_rgb_property) {
++ *val = vc4_conn_state->broadcast_rgb;
++ } else {
++ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
++ property->base.id, property->name);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/**
++ * vc4_connector_atomic_set_property - hook for connector->atomic_set_property.
++ * @connector: Connector to set the property for.
++ * @state: Connector state to set the property on.
++ * @property: Property to set.
++ * @val: New value for the property.
++ *
++ * Sets the atomic property value for a digital connector.
++ */
++int vc4_connector_atomic_set_property(struct drm_connector *connector,
++ struct drm_connector_state *state,
++ struct drm_property *property,
++ uint64_t val)
++{
++ struct vc4_fkms_connector *fkms_connector =
++ to_vc4_fkms_connector(connector);
++ struct vc4_fkms_connector_state *vc4_conn_state =
++ to_vc4_fkms_connector_state(state);
++
++ if (property == fkms_connector->broadcast_rgb_property) {
++ vc4_conn_state->broadcast_rgb = val;
++ return 0;
++ }
++
++ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
++ property->base.id, property->name);
++ return -EINVAL;
++}
++
+ static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
+ .detect = vc4_fkms_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = vc4_fkms_connector_destroy,
+- .reset = drm_atomic_helper_connector_reset,
+- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
++ .atomic_duplicate_state = vc4_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
++ .atomic_get_property = vc4_connector_atomic_get_property,
++ .atomic_set_property = vc4_connector_atomic_set_property,
+ };
+
+ static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs = {
+@@ -1359,12 +1477,40 @@ static const struct drm_connector_helper
+ .best_encoder = vc4_fkms_connector_best_encoder,
+ };
+
++static const struct drm_prop_enum_list broadcast_rgb_names[] = {
++ { VC4_BROADCAST_RGB_AUTO, "Automatic" },
++ { VC4_BROADCAST_RGB_FULL, "Full" },
++ { VC4_BROADCAST_RGB_LIMITED, "Limited 16:235" },
++};
++
++static void
++vc4_attach_broadcast_rgb_property(struct vc4_fkms_connector *fkms_connector)
++{
++ struct drm_device *dev = fkms_connector->base.dev;
++ struct drm_property *prop;
++
++ prop = fkms_connector->broadcast_rgb_property;
++ if (!prop) {
++ prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
++ "Broadcast RGB",
++ broadcast_rgb_names,
++ ARRAY_SIZE(broadcast_rgb_names));
++ if (!prop)
++ return;
++
++ fkms_connector->broadcast_rgb_property = prop;
++ }
++
++ drm_object_attach_property(&fkms_connector->base.base, prop, 0);
++}
++
+ static struct drm_connector *
+ vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
+ u32 display_num)
+ {
+ struct drm_connector *connector = NULL;
+ struct vc4_fkms_connector *fkms_connector;
++ struct vc4_fkms_connector_state *conn_state = NULL;
+ struct vc4_dev *vc4_dev = to_vc4_dev(dev);
+ int ret = 0;
+
+@@ -1373,9 +1519,18 @@ vc4_fkms_connector_init(struct drm_devic
+ fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
+ GFP_KERNEL);
+ if (!fkms_connector) {
+- ret = -ENOMEM;
+- goto fail;
++ return ERR_PTR(-ENOMEM);
++ }
++
++ /*
++ * Allocate enough memory to hold vc4_fkms_connector_state,
++ */
++ conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
++ if (!conn_state) {
++ kfree(fkms_connector);
++ return ERR_PTR(-ENOMEM);
+ }
++
+ connector = &fkms_connector->base;
+
+ fkms_connector->encoder = encoder;
+@@ -1383,6 +1538,9 @@ vc4_fkms_connector_init(struct drm_devic
+ fkms_connector->display_type = vc4_get_display_type(display_num);
+ fkms_connector->vc4_dev = vc4_dev;
+
++ __drm_atomic_helper_connector_reset(connector,
++ &conn_state->base);
++
+ if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) {
+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+@@ -1403,10 +1561,14 @@ vc4_fkms_connector_init(struct drm_devic
+ connector->interlace_allowed = 0;
+ }
+
+- /* Create and attach TV margin props to this connector. */
+- ret = drm_mode_create_tv_margin_properties(dev);
+- if (ret)
+- return ERR_PTR(ret);
++ /* Create and attach TV margin props to this connector.
++ * Already done for SDTV outputs.
++ */
++ if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) {
++ ret = drm_mode_create_tv_margin_properties(dev);
++ if (ret)
++ goto fail;
++ }
+
+ drm_connector_attach_tv_margin_properties(connector);
+
+@@ -1415,6 +1577,8 @@ vc4_fkms_connector_init(struct drm_devic
+
+ connector->doublescan_allowed = 0;
+
++ vc4_attach_broadcast_rgb_property(fkms_connector);
++
+ drm_connector_attach_encoder(connector, encoder);
+
+ return connector;
--- /dev/null
+From 7c0f4f4d81958f63abf696e71b342e8b75a6e530 Mon Sep 17 00:00:00 2001
+Date: Wed, 19 Jun 2019 12:17:48 +0200
+Subject: [PATCH] drm/connector: Add documentation for drm_cmdline_mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 772cd52c5574b04b00a97d638b2cfe94c0c1a9b6 upstream.
+
+The struct drm_cmdline_mode holds the result of the command line parsers.
+However, it wasn't documented so far, so let's do that.
+
+Link: https://patchwork.freedesktop.org/patch/msgid/963c893c16c6a25fc469b53c726f493d99bdc578.1560783090.git-series.maxime.ripard@bootlin.com
+---
+ include/drm/drm_connector.h | 86 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 84 insertions(+), 2 deletions(-)
+
+--- a/include/drm/drm_connector.h
++++ b/include/drm/drm_connector.h
+@@ -755,18 +755,100 @@ struct drm_connector_funcs {
+ const struct drm_connector_state *state);
+ };
+
+-/* mode specified on the command line */
++/**
++ * struct drm_cmdline_mode - DRM Mode passed through the kernel command-line
++ *
++ * Each connector can have an initial mode with additional options
++ * passed through the kernel command line. This structure allows to
++ * express those parameters and will be filled by the command-line
++ * parser.
++ */
+ struct drm_cmdline_mode {
++ /**
++ * @specified:
++ *
++ * Has a mode been read from the command-line?
++ */
+ bool specified;
++
++ /**
++ * @refresh_specified:
++ *
++ * Did the mode have a preferred refresh rate?
++ */
+ bool refresh_specified;
++
++ /**
++ * @bpp_specified:
++ *
++ * Did the mode have a preferred BPP?
++ */
+ bool bpp_specified;
+- int xres, yres;
++
++ /**
++ * @xres:
++ *
++ * Active resolution on the X axis, in pixels.
++ */
++ int xres;
++
++ /**
++ * @yres:
++ *
++ * Active resolution on the Y axis, in pixels.
++ */
++ int yres;
++
++ /**
++ * @bpp:
++ *
++ * Bits per pixels for the mode.
++ */
+ int bpp;
++
++ /**
++ * @refresh:
++ *
++ * Refresh rate, in Hertz.
++ */
+ int refresh;
++
++ /**
++ * @rb:
++ *
++ * Do we need to use reduced blanking?
++ */
+ bool rb;
++
++ /**
++ * @interlace:
++ *
++ * The mode is interlaced.
++ */
+ bool interlace;
++
++ /**
++ * @cvt:
++ *
++ * The timings will be calculated using the VESA Coordinated
++ * Video Timings instead of looking up the mode from a table.
++ */
+ bool cvt;
++
++ /**
++ * @margins:
++ *
++ * Add margins to the mode calculation (1.8% of xres rounded
++ * down to 8 pixels and 1.8% of yres).
++ */
+ bool margins;
++
++ /**
++ * @force:
++ *
++ * Ignore the hotplug state of the connector, and force its
++ * state to one of the DRM_FORCE_* values.
++ */
+ enum drm_connector_force force;
+ };
+
+++ /dev/null
-From 16c1e20b50e121f836f434bb6c22c73e2f51d29f Mon Sep 17 00:00:00 2001
-Date: Thu, 1 Aug 2019 16:41:20 +0100
-Subject: [PATCH] hid: usb: Add device quirks for Freeway Airmouse T3
- and MX3
-
-These wireless mouse/keyboard combo remote control devices specify
-multiple "wheel" events in their report descriptors. The wheel events
-are incorrectly defined and apparently map to accelerometer data, leading
-to spurious mouse scroll events being generated at an extreme rate when
-the device is moved.
-
-As a workaround, use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE to mask
-feeding the extra wheel events to the input subsystem.
-
-See: https://github.com/raspberrypi/firmware/issues/1189
-
----
- drivers/hid/hid-ids.h | 6 ++++++
- drivers/hid/hid-quirks.c | 2 ++
- 2 files changed, 8 insertions(+)
-
---- a/drivers/hid/hid-ids.h
-+++ b/drivers/hid/hid-ids.h
-@@ -222,6 +222,9 @@
- #define USB_VENDOR_ID_BAANTO 0x2453
- #define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100
-
-+#define USB_VENDOR_ID_BEKEN 0x25a7
-+#define USB_DEVICE_ID_AIRMOUSE_T3 0x2402
-+
- #define USB_VENDOR_ID_BELKIN 0x050d
- #define USB_DEVICE_ID_FLIP_KVM 0x3201
-
-@@ -1196,6 +1199,9 @@
- #define USB_VENDOR_ID_XAT 0x2505
- #define USB_DEVICE_ID_XAT_CSR 0x0220
-
-+#define USB_VENDOR_ID_XENTA 0x1d57
-+#define USB_DEVICE_ID_AIRMOUSE_MX3 0xad03
-+
- #define USB_VENDOR_ID_XIN_MO 0x16c0
- #define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE 0x05e1
- #define USB_DEVICE_ID_THT_2P_ARCADE 0x75e1
---- a/drivers/hid/hid-quirks.c
-+++ b/drivers/hid/hid-quirks.c
-@@ -43,6 +43,7 @@ static const struct hid_device_id hid_qu
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
-+ { HID_USB_DEVICE(USB_VENDOR_ID_BEKEN, USB_DEVICE_ID_AIRMOUSE_T3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },
-@@ -175,6 +176,7 @@ static const struct hid_device_id hid_qu
- { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
-+ { HID_USB_DEVICE(USB_VENDOR_ID_XENTA, USB_DEVICE_ID_AIRMOUSE_MX3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT },
-
- { 0 }
--- /dev/null
+From 3508a8548f13be68b6d098ad99a7bc1fc1810f76 Mon Sep 17 00:00:00 2001
+Date: Wed, 19 Jun 2019 12:17:49 +0200
+Subject: [PATCH] drm/modes: Rewrite the command line parser
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit e08ab74bd4c7a5fe311bc05f32dbb4f1e7fa3428 upstream.
+
+Rewrite the command line parser in order to get away from the state machine
+parsing the video mode lines.
+
+Hopefully, this will allow to extend it more easily to support named modes
+and / or properties set directly on the command line.
+
+Link: https://patchwork.freedesktop.org/patch/msgid/e32cd4009153b184103554009135c7bf7c9975d7.1560783090.git-series.maxime.ripard@bootlin.com
+---
+ drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++-------------
+ 1 file changed, 210 insertions(+), 115 deletions(-)
+
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -30,6 +30,7 @@
+ * authorization from the copyright holder(s) and author(s).
+ */
+
++#include <linux/ctype.h>
+ #include <linux/list.h>
+ #include <linux/list_sort.h>
+ #include <linux/export.h>
+@@ -1414,6 +1415,151 @@ void drm_connector_list_update(struct dr
+ }
+ EXPORT_SYMBOL(drm_connector_list_update);
+
++static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
++ struct drm_cmdline_mode *mode)
++{
++ unsigned int bpp;
++
++ if (str[0] != '-')
++ return -EINVAL;
++
++ str++;
++ bpp = simple_strtol(str, end_ptr, 10);
++ if (*end_ptr == str)
++ return -EINVAL;
++
++ mode->bpp = bpp;
++ mode->bpp_specified = true;
++
++ return 0;
++}
++
++static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
++ struct drm_cmdline_mode *mode)
++{
++ unsigned int refresh;
++
++ if (str[0] != '@')
++ return -EINVAL;
++
++ str++;
++ refresh = simple_strtol(str, end_ptr, 10);
++ if (*end_ptr == str)
++ return -EINVAL;
++
++ mode->refresh = refresh;
++ mode->refresh_specified = true;
++
++ return 0;
++}
++
++static int drm_mode_parse_cmdline_extra(const char *str, int length,
++ struct drm_connector *connector,
++ struct drm_cmdline_mode *mode)
++{
++ int i;
++
++ for (i = 0; i < length; i++) {
++ switch (str[i]) {
++ case 'i':
++ mode->interlace = true;
++ break;
++ case 'm':
++ mode->margins = true;
++ break;
++ case 'D':
++ if (mode->force != DRM_FORCE_UNSPECIFIED)
++ return -EINVAL;
++
++ if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
++ (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
++ mode->force = DRM_FORCE_ON;
++ else
++ mode->force = DRM_FORCE_ON_DIGITAL;
++ break;
++ case 'd':
++ if (mode->force != DRM_FORCE_UNSPECIFIED)
++ return -EINVAL;
++
++ mode->force = DRM_FORCE_OFF;
++ break;
++ case 'e':
++ if (mode->force != DRM_FORCE_UNSPECIFIED)
++ return -EINVAL;
++
++ mode->force = DRM_FORCE_ON;
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++
++ return 0;
++}
++
++static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
++ bool extras,
++ struct drm_connector *connector,
++ struct drm_cmdline_mode *mode)
++{
++ const char *str_start = str;
++ bool rb = false, cvt = false;
++ int xres = 0, yres = 0;
++ int remaining, i;
++ char *end_ptr;
++
++ xres = simple_strtol(str, &end_ptr, 10);
++ if (end_ptr == str)
++ return -EINVAL;
++
++ if (end_ptr[0] != 'x')
++ return -EINVAL;
++ end_ptr++;
++
++ str = end_ptr;
++ yres = simple_strtol(str, &end_ptr, 10);
++ if (end_ptr == str)
++ return -EINVAL;
++
++ remaining = length - (end_ptr - str_start);
++ if (remaining < 0)
++ return -EINVAL;
++
++ for (i = 0; i < remaining; i++) {
++ switch (end_ptr[i]) {
++ case 'M':
++ cvt = true;
++ break;
++ case 'R':
++ rb = true;
++ break;
++ default:
++ /*
++ * Try to pass that to our extras parsing
++ * function to handle the case where the
++ * extras are directly after the resolution
++ */
++ if (extras) {
++ int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
++ 1,
++ connector,
++ mode);
++ if (ret)
++ return ret;
++ } else {
++ return -EINVAL;
++ }
++ }
++ }
++
++ mode->xres = xres;
++ mode->yres = yres;
++ mode->cvt = cvt;
++ mode->rb = rb;
++
++ return 0;
++}
++
+ /**
+ * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
+ * @mode_option: optional per connector mode option
+@@ -1440,13 +1586,12 @@ bool drm_mode_parse_command_line_for_con
+ struct drm_cmdline_mode *mode)
+ {
+ const char *name;
+- unsigned int namelen;
+- bool res_specified = false, bpp_specified = false, refresh_specified = false;
+- unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
+- bool yres_specified = false, cvt = false, rb = false;
+- bool interlace = false, margins = false, was_digit = false;
+- int i;
+- enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
++ bool parse_extras = false;
++ unsigned int bpp_off = 0, refresh_off = 0;
++ unsigned int mode_end = 0;
++ char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
++ char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
++ int ret;
+
+ #ifdef CONFIG_FB
+ if (!mode_option)
+@@ -1459,127 +1604,77 @@ bool drm_mode_parse_command_line_for_con
+ }
+
+ name = mode_option;
+- namelen = strlen(name);
+- for (i = namelen-1; i >= 0; i--) {
+- switch (name[i]) {
+- case '@':
+- if (!refresh_specified && !bpp_specified &&
+- !yres_specified && !cvt && !rb && was_digit) {
+- refresh = simple_strtol(&name[i+1], NULL, 10);
+- refresh_specified = true;
+- was_digit = false;
+- } else
+- goto done;
+- break;
+- case '-':
+- if (!bpp_specified && !yres_specified && !cvt &&
+- !rb && was_digit) {
+- bpp = simple_strtol(&name[i+1], NULL, 10);
+- bpp_specified = true;
+- was_digit = false;
+- } else
+- goto done;
+- break;
+- case 'x':
+- if (!yres_specified && was_digit) {
+- yres = simple_strtol(&name[i+1], NULL, 10);
+- yres_specified = true;
+- was_digit = false;
+- } else
+- goto done;
+- break;
+- case '0' ... '9':
+- was_digit = true;
+- break;
+- case 'M':
+- if (yres_specified || cvt || was_digit)
+- goto done;
+- cvt = true;
+- break;
+- case 'R':
+- if (yres_specified || cvt || rb || was_digit)
+- goto done;
+- rb = true;
+- break;
+- case 'm':
+- if (cvt || yres_specified || was_digit)
+- goto done;
+- margins = true;
+- break;
+- case 'i':
+- if (cvt || yres_specified || was_digit)
+- goto done;
+- interlace = true;
+- break;
+- case 'e':
+- if (yres_specified || bpp_specified || refresh_specified ||
+- was_digit || (force != DRM_FORCE_UNSPECIFIED))
+- goto done;
+
+- force = DRM_FORCE_ON;
+- break;
+- case 'D':
+- if (yres_specified || bpp_specified || refresh_specified ||
+- was_digit || (force != DRM_FORCE_UNSPECIFIED))
+- goto done;
++ if (!isdigit(name[0]))
++ return false;
+
+- if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
+- (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
+- force = DRM_FORCE_ON;
+- else
+- force = DRM_FORCE_ON_DIGITAL;
+- break;
+- case 'd':
+- if (yres_specified || bpp_specified || refresh_specified ||
+- was_digit || (force != DRM_FORCE_UNSPECIFIED))
+- goto done;
++ /* Try to locate the bpp and refresh specifiers, if any */
++ bpp_ptr = strchr(name, '-');
++ if (bpp_ptr) {
++ bpp_off = bpp_ptr - name;
++ mode->bpp_specified = true;
++ }
+
+- force = DRM_FORCE_OFF;
+- break;
+- default:
+- goto done;
+- }
++ refresh_ptr = strchr(name, '@');
++ if (refresh_ptr) {
++ refresh_off = refresh_ptr - name;
++ mode->refresh_specified = true;
+ }
+
+- if (i < 0 && yres_specified) {
+- char *ch;
+- xres = simple_strtol(name, &ch, 10);
+- if ((ch != NULL) && (*ch == 'x'))
+- res_specified = true;
+- else
+- i = ch - name;
+- } else if (!yres_specified && was_digit) {
+- /* catch mode that begins with digits but has no 'x' */
+- i = 0;
+- }
+-done:
+- if (i >= 0) {
+- pr_warn("[drm] parse error at position %i in video mode '%s'\n",
+- i, name);
+- mode->specified = false;
+- return false;
++ /* Locate the end of the name / resolution, and parse it */
++ if (bpp_ptr && refresh_ptr) {
++ mode_end = min(bpp_off, refresh_off);
++ } else if (bpp_ptr) {
++ mode_end = bpp_off;
++ } else if (refresh_ptr) {
++ mode_end = refresh_off;
++ } else {
++ mode_end = strlen(name);
++ parse_extras = true;
+ }
+
+- if (res_specified) {
+- mode->specified = true;
+- mode->xres = xres;
+- mode->yres = yres;
++ ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
++ parse_extras,
++ connector,
++ mode);
++ if (ret)
++ return false;
++ mode->specified = true;
++
++ if (bpp_ptr) {
++ ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
++ if (ret)
++ return false;
+ }
+
+- if (refresh_specified) {
+- mode->refresh_specified = true;
+- mode->refresh = refresh;
++ if (refresh_ptr) {
++ ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
++ &refresh_end_ptr, mode);
++ if (ret)
++ return false;
+ }
+
+- if (bpp_specified) {
+- mode->bpp_specified = true;
+- mode->bpp = bpp;
++ /*
++ * Locate the end of the bpp / refresh, and parse the extras
++ * if relevant
++ */
++ if (bpp_ptr && refresh_ptr)
++ extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
++ else if (bpp_ptr)
++ extra_ptr = bpp_end_ptr;
++ else if (refresh_ptr)
++ extra_ptr = refresh_end_ptr;
++
++ if (extra_ptr) {
++ int remaining = strlen(name) - (extra_ptr - name);
++
++ /*
++ * We still have characters to process, while
++ * we shouldn't have any
++ */
++ if (remaining > 0)
++ return false;
+ }
+- mode->rb = rb;
+- mode->cvt = cvt;
+- mode->interlace = interlace;
+- mode->margins = margins;
+- mode->force = force;
+
+ return true;
+ }
+++ /dev/null
-From b96e24487cc48a2cb593f27c24074087a21de848 Mon Sep 17 00:00:00 2001
-Date: Fri, 14 Jun 2019 10:12:07 +0100
-Subject: [PATCH] drm/vc4: Add "Broadcast RGB" connector property
-
-Some HDMI monitors do not abide by the full or limited
-(16-235) range RGB flags in the AVI infoframe. This can
-result in images looking washed out (if given limited and
-interpreting as full), or detail disappearing at the extremes
-(given full and interpreting as limited).
-
-Copy the Intel i915 driver's approach of adding an override
-property ("Broadcast RGB") to force one mode or the other.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 190 +++++++++++++++++++++++--
- 1 file changed, 177 insertions(+), 13 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -285,6 +285,13 @@ to_vc4_fkms_encoder(struct drm_encoder *
- return container_of(encoder, struct vc4_fkms_encoder, base);
- }
-
-+/* "Broadcast RGB" property.
-+ * Allows overriding of HDMI full or limited range RGB
-+ */
-+#define VC4_BROADCAST_RGB_AUTO 0
-+#define VC4_BROADCAST_RGB_FULL 1
-+#define VC4_BROADCAST_RGB_LIMITED 2
-+
- /* VC4 FKMS connector KMS struct */
- struct vc4_fkms_connector {
- struct drm_connector base;
-@@ -297,6 +304,8 @@ struct vc4_fkms_connector {
- struct vc4_dev *vc4_dev;
- u32 display_number;
- u32 display_type;
-+
-+ struct drm_property *broadcast_rgb_property;
- };
-
- static inline struct vc4_fkms_connector *
-@@ -305,6 +314,16 @@ to_vc4_fkms_connector(struct drm_connect
- return container_of(connector, struct vc4_fkms_connector, base);
- }
-
-+/* VC4 FKMS connector state */
-+struct vc4_fkms_connector_state {
-+ struct drm_connector_state base;
-+
-+ int broadcast_rgb;
-+};
-+
-+#define to_vc4_fkms_connector_state(x) \
-+ container_of(x, struct vc4_fkms_connector_state, base)
-+
- static u32 vc4_get_display_type(u32 display_number)
- {
- const u32 display_types[] = {
-@@ -832,8 +851,6 @@ static void vc4_crtc_mode_set_nofb(struc
- mode->picture_aspect_ratio, mode->flags);
- mb.timings.display = vc4_crtc->display_number;
-
-- mb.timings.video_id_code = frame.avi.video_code;
--
- mb.timings.clock = mode->clock;
- mb.timings.hdisplay = mode->hdisplay;
- mb.timings.hsync_start = mode->hsync_start;
-@@ -871,11 +888,30 @@ static void vc4_crtc_mode_set_nofb(struc
- break;
- }
-
-- if (!vc4_encoder->hdmi_monitor)
-+ if (!vc4_encoder->hdmi_monitor) {
- mb.timings.flags |= TIMINGS_FLAGS_DVI;
-- else if (drm_default_rgb_quant_range(mode) ==
-+ mb.timings.video_id_code = frame.avi.video_code;
-+ } else {
-+ struct vc4_fkms_connector_state *conn_state =
-+ to_vc4_fkms_connector_state(vc4_crtc->connector->state);
-+
-+ /* Do not provide a VIC as the HDMI spec requires that we do not
-+ * signal the opposite of the defined range in the AVI
-+ * infoframe.
-+ */
-+ mb.timings.video_id_code = 0;
-+
-+ if (conn_state->broadcast_rgb == VC4_BROADCAST_RGB_AUTO) {
-+ /* See CEA-861-E - 5.1 Default Encoding Parameters */
-+ if (drm_default_rgb_quant_range(mode) ==
- HDMI_QUANTIZATION_RANGE_LIMITED)
-- mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
-+ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
-+ } else {
-+ if (conn_state->broadcast_rgb ==
-+ VC4_BROADCAST_RGB_LIMITED)
-+ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
-+ }
-+ }
-
- /*
- FIXME: To implement
-@@ -1340,13 +1376,95 @@ static void vc4_fkms_connector_destroy(s
- drm_connector_cleanup(connector);
- }
-
-+/**
-+ * vc4_connector_duplicate_state - duplicate connector state
-+ * @connector: digital connector
-+ *
-+ * Allocates and returns a copy of the connector state (both common and
-+ * digital connector specific) for the specified connector.
-+ *
-+ * Returns: The newly allocated connector state, or NULL on failure.
-+ */
-+struct drm_connector_state *
-+vc4_connector_duplicate_state(struct drm_connector *connector)
-+{
-+ struct vc4_fkms_connector_state *state;
-+
-+ state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
-+ if (!state)
-+ return NULL;
-+
-+ __drm_atomic_helper_connector_duplicate_state(connector, &state->base);
-+ return &state->base;
-+}
-+
-+/**
-+ * vc4_connector_atomic_get_property - hook for connector->atomic_get_property.
-+ * @connector: Connector to get the property for.
-+ * @state: Connector state to retrieve the property from.
-+ * @property: Property to retrieve.
-+ * @val: Return value for the property.
-+ *
-+ * Returns the atomic property value for a digital connector.
-+ */
-+int vc4_connector_atomic_get_property(struct drm_connector *connector,
-+ const struct drm_connector_state *state,
-+ struct drm_property *property,
-+ uint64_t *val)
-+{
-+ struct vc4_fkms_connector *fkms_connector =
-+ to_vc4_fkms_connector(connector);
-+ struct vc4_fkms_connector_state *vc4_conn_state =
-+ to_vc4_fkms_connector_state(state);
-+
-+ if (property == fkms_connector->broadcast_rgb_property) {
-+ *val = vc4_conn_state->broadcast_rgb;
-+ } else {
-+ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
-+ property->base.id, property->name);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * vc4_connector_atomic_set_property - hook for connector->atomic_set_property.
-+ * @connector: Connector to set the property for.
-+ * @state: Connector state to set the property on.
-+ * @property: Property to set.
-+ * @val: New value for the property.
-+ *
-+ * Sets the atomic property value for a digital connector.
-+ */
-+int vc4_connector_atomic_set_property(struct drm_connector *connector,
-+ struct drm_connector_state *state,
-+ struct drm_property *property,
-+ uint64_t val)
-+{
-+ struct vc4_fkms_connector *fkms_connector =
-+ to_vc4_fkms_connector(connector);
-+ struct vc4_fkms_connector_state *vc4_conn_state =
-+ to_vc4_fkms_connector_state(state);
-+
-+ if (property == fkms_connector->broadcast_rgb_property) {
-+ vc4_conn_state->broadcast_rgb = val;
-+ return 0;
-+ }
-+
-+ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
-+ property->base.id, property->name);
-+ return -EINVAL;
-+}
-+
- static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
- .detect = vc4_fkms_connector_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = vc4_fkms_connector_destroy,
-- .reset = drm_atomic_helper_connector_reset,
-- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-+ .atomic_duplicate_state = vc4_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-+ .atomic_get_property = vc4_connector_atomic_get_property,
-+ .atomic_set_property = vc4_connector_atomic_set_property,
- };
-
- static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs = {
-@@ -1359,12 +1477,40 @@ static const struct drm_connector_helper
- .best_encoder = vc4_fkms_connector_best_encoder,
- };
-
-+static const struct drm_prop_enum_list broadcast_rgb_names[] = {
-+ { VC4_BROADCAST_RGB_AUTO, "Automatic" },
-+ { VC4_BROADCAST_RGB_FULL, "Full" },
-+ { VC4_BROADCAST_RGB_LIMITED, "Limited 16:235" },
-+};
-+
-+static void
-+vc4_attach_broadcast_rgb_property(struct vc4_fkms_connector *fkms_connector)
-+{
-+ struct drm_device *dev = fkms_connector->base.dev;
-+ struct drm_property *prop;
-+
-+ prop = fkms_connector->broadcast_rgb_property;
-+ if (!prop) {
-+ prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
-+ "Broadcast RGB",
-+ broadcast_rgb_names,
-+ ARRAY_SIZE(broadcast_rgb_names));
-+ if (!prop)
-+ return;
-+
-+ fkms_connector->broadcast_rgb_property = prop;
-+ }
-+
-+ drm_object_attach_property(&fkms_connector->base.base, prop, 0);
-+}
-+
- static struct drm_connector *
- vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
- u32 display_num)
- {
- struct drm_connector *connector = NULL;
- struct vc4_fkms_connector *fkms_connector;
-+ struct vc4_fkms_connector_state *conn_state = NULL;
- struct vc4_dev *vc4_dev = to_vc4_dev(dev);
- int ret = 0;
-
-@@ -1373,9 +1519,18 @@ vc4_fkms_connector_init(struct drm_devic
- fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
- GFP_KERNEL);
- if (!fkms_connector) {
-- ret = -ENOMEM;
-- goto fail;
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ /*
-+ * Allocate enough memory to hold vc4_fkms_connector_state,
-+ */
-+ conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
-+ if (!conn_state) {
-+ kfree(fkms_connector);
-+ return ERR_PTR(-ENOMEM);
- }
-+
- connector = &fkms_connector->base;
-
- fkms_connector->encoder = encoder;
-@@ -1383,6 +1538,9 @@ vc4_fkms_connector_init(struct drm_devic
- fkms_connector->display_type = vc4_get_display_type(display_num);
- fkms_connector->vc4_dev = vc4_dev;
-
-+ __drm_atomic_helper_connector_reset(connector,
-+ &conn_state->base);
-+
- if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) {
- drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
- DRM_MODE_CONNECTOR_DSI);
-@@ -1403,10 +1561,14 @@ vc4_fkms_connector_init(struct drm_devic
- connector->interlace_allowed = 0;
- }
-
-- /* Create and attach TV margin props to this connector. */
-- ret = drm_mode_create_tv_margin_properties(dev);
-- if (ret)
-- return ERR_PTR(ret);
-+ /* Create and attach TV margin props to this connector.
-+ * Already done for SDTV outputs.
-+ */
-+ if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) {
-+ ret = drm_mode_create_tv_margin_properties(dev);
-+ if (ret)
-+ goto fail;
-+ }
-
- drm_connector_attach_tv_margin_properties(connector);
-
-@@ -1415,6 +1577,8 @@ vc4_fkms_connector_init(struct drm_devic
-
- connector->doublescan_allowed = 0;
-
-+ vc4_attach_broadcast_rgb_property(fkms_connector);
-+
- drm_connector_attach_encoder(connector, encoder);
-
- return connector;
+++ /dev/null
-From 7c0f4f4d81958f63abf696e71b342e8b75a6e530 Mon Sep 17 00:00:00 2001
-Date: Wed, 19 Jun 2019 12:17:48 +0200
-Subject: [PATCH] drm/connector: Add documentation for drm_cmdline_mode
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-commit 772cd52c5574b04b00a97d638b2cfe94c0c1a9b6 upstream.
-
-The struct drm_cmdline_mode holds the result of the command line parsers.
-However, it wasn't documented so far, so let's do that.
-
-Link: https://patchwork.freedesktop.org/patch/msgid/963c893c16c6a25fc469b53c726f493d99bdc578.1560783090.git-series.maxime.ripard@bootlin.com
----
- include/drm/drm_connector.h | 86 ++++++++++++++++++++++++++++++++++++-
- 1 file changed, 84 insertions(+), 2 deletions(-)
-
---- a/include/drm/drm_connector.h
-+++ b/include/drm/drm_connector.h
-@@ -755,18 +755,100 @@ struct drm_connector_funcs {
- const struct drm_connector_state *state);
- };
-
--/* mode specified on the command line */
-+/**
-+ * struct drm_cmdline_mode - DRM Mode passed through the kernel command-line
-+ *
-+ * Each connector can have an initial mode with additional options
-+ * passed through the kernel command line. This structure allows to
-+ * express those parameters and will be filled by the command-line
-+ * parser.
-+ */
- struct drm_cmdline_mode {
-+ /**
-+ * @specified:
-+ *
-+ * Has a mode been read from the command-line?
-+ */
- bool specified;
-+
-+ /**
-+ * @refresh_specified:
-+ *
-+ * Did the mode have a preferred refresh rate?
-+ */
- bool refresh_specified;
-+
-+ /**
-+ * @bpp_specified:
-+ *
-+ * Did the mode have a preferred BPP?
-+ */
- bool bpp_specified;
-- int xres, yres;
-+
-+ /**
-+ * @xres:
-+ *
-+ * Active resolution on the X axis, in pixels.
-+ */
-+ int xres;
-+
-+ /**
-+ * @yres:
-+ *
-+ * Active resolution on the Y axis, in pixels.
-+ */
-+ int yres;
-+
-+ /**
-+ * @bpp:
-+ *
-+ * Bits per pixels for the mode.
-+ */
- int bpp;
-+
-+ /**
-+ * @refresh:
-+ *
-+ * Refresh rate, in Hertz.
-+ */
- int refresh;
-+
-+ /**
-+ * @rb:
-+ *
-+ * Do we need to use reduced blanking?
-+ */
- bool rb;
-+
-+ /**
-+ * @interlace:
-+ *
-+ * The mode is interlaced.
-+ */
- bool interlace;
-+
-+ /**
-+ * @cvt:
-+ *
-+ * The timings will be calculated using the VESA Coordinated
-+ * Video Timings instead of looking up the mode from a table.
-+ */
- bool cvt;
-+
-+ /**
-+ * @margins:
-+ *
-+ * Add margins to the mode calculation (1.8% of xres rounded
-+ * down to 8 pixels and 1.8% of yres).
-+ */
- bool margins;
-+
-+ /**
-+ * @force:
-+ *
-+ * Ignore the hotplug state of the connector, and force its
-+ * state to one of the DRM_FORCE_* values.
-+ */
- enum drm_connector_force force;
- };
-
--- /dev/null
+From 2cea4924c69b6be5cfe8d976810ccf76a3991230 Mon Sep 17 00:00:00 2001
+Date: Wed, 19 Jun 2019 12:17:50 +0200
+Subject: [PATCH] drm/modes: Support modes names on the command line
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 3aeeb13d899627fe2b86bdbdcd0927cf7192234f upstream.
+Minor conflict resolution as upstream has moved functions
+from drm_fb_helper.c to a new drm_client_modeset.c
+
+The drm subsystem also uses the video= kernel parameter, and in the
+documentation refers to the fbdev documentation for that parameter.
+
+However, that documentation also says that instead of giving the mode using
+its resolution we can also give a name. However, DRM doesn't handle that
+case at the moment. Even though in most case it shouldn't make any
+difference, it might be useful for analog modes, where different standards
+might have the same resolution, but still have a few different parameters
+that are not encoded in the modes (NTSC vs NTSC-J vs PAL-M for example).
+
+Link: https://patchwork.freedesktop.org/patch/msgid/18443e0c3bdbbd16cea4ec63bc7f2079b820b43b.1560783090.git-series.maxime.ripard@bootlin.com
+---
+ drivers/gpu/drm/drm_connector.c | 3 +-
+ drivers/gpu/drm/drm_fb_helper.c | 4 +++
+ drivers/gpu/drm/drm_modes.c | 62 ++++++++++++++++++++++++---------
+ include/drm/drm_connector.h | 7 ++++
+ 4 files changed, 59 insertions(+), 17 deletions(-)
+
+--- a/drivers/gpu/drm/drm_connector.c
++++ b/drivers/gpu/drm/drm_connector.c
+@@ -135,8 +135,9 @@ static void drm_connector_get_cmdline_mo
+ connector->force = mode->force;
+ }
+
+- DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
++ DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
+ connector->name,
++ mode->name ? mode->name : "",
+ mode->xres, mode->yres,
+ mode->refresh_specified ? mode->refresh : 60,
+ mode->rb ? " reduced blanking" : "",
+--- a/drivers/gpu/drm/drm_fb_helper.c
++++ b/drivers/gpu/drm/drm_fb_helper.c
+@@ -2104,6 +2104,10 @@ struct drm_display_mode *drm_pick_cmdlin
+ prefer_non_interlace = !cmdline_mode->interlace;
+ again:
+ list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
++ /* Check (optional) mode name first */
++ if (!strcmp(mode->name, cmdline_mode->name))
++ return mode;
++
+ /* check width/height */
+ if (mode->hdisplay != cmdline_mode->xres ||
+ mode->vdisplay != cmdline_mode->yres)
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1586,7 +1586,7 @@ bool drm_mode_parse_command_line_for_con
+ struct drm_cmdline_mode *mode)
+ {
+ const char *name;
+- bool parse_extras = false;
++ bool named_mode = false, parse_extras = false;
+ unsigned int bpp_off = 0, refresh_off = 0;
+ unsigned int mode_end = 0;
+ char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
+@@ -1605,8 +1605,22 @@ bool drm_mode_parse_command_line_for_con
+
+ name = mode_option;
+
+- if (!isdigit(name[0]))
+- return false;
++ /*
++ * This is a bit convoluted. To differentiate between the
++ * named modes and poorly formatted resolutions, we need a
++ * bunch of things:
++ * - We need to make sure that the first character (which
++ * would be our resolution in X) is a digit.
++ * - However, if the X resolution is missing, then we end up
++ * with something like x<yres>, with our first character
++ * being an alpha-numerical character, which would be
++ * considered a named mode.
++ *
++ * If this isn't enough, we should add more heuristics here,
++ * and matching unit-tests.
++ */
++ if (!isdigit(name[0]) && name[0] != 'x')
++ named_mode = true;
+
+ /* Try to locate the bpp and refresh specifiers, if any */
+ bpp_ptr = strchr(name, '-');
+@@ -1617,6 +1631,9 @@ bool drm_mode_parse_command_line_for_con
+
+ refresh_ptr = strchr(name, '@');
+ if (refresh_ptr) {
++ if (named_mode)
++ return false;
++
+ refresh_off = refresh_ptr - name;
+ mode->refresh_specified = true;
+ }
+@@ -1633,12 +1650,16 @@ bool drm_mode_parse_command_line_for_con
+ parse_extras = true;
+ }
+
+- ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
+- parse_extras,
+- connector,
+- mode);
+- if (ret)
+- return false;
++ if (named_mode) {
++ strncpy(mode->name, name, mode_end);
++ } else {
++ ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
++ parse_extras,
++ connector,
++ mode);
++ if (ret)
++ return false;
++ }
+ mode->specified = true;
+
+ if (bpp_ptr) {
+@@ -1666,14 +1687,23 @@ bool drm_mode_parse_command_line_for_con
+ extra_ptr = refresh_end_ptr;
+
+ if (extra_ptr) {
+- int remaining = strlen(name) - (extra_ptr - name);
++ if (!named_mode) {
++ int len = strlen(name) - (extra_ptr - name);
+
+- /*
+- * We still have characters to process, while
+- * we shouldn't have any
+- */
+- if (remaining > 0)
+- return false;
++ ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
++ connector, mode);
++ if (ret)
++ return false;
++ } else {
++ int remaining = strlen(name) - (extra_ptr - name);
++
++ /*
++ * We still have characters to process, while
++ * we shouldn't have any
++ */
++ if (remaining > 0)
++ return false;
++ }
+ }
+
+ return true;
+--- a/include/drm/drm_connector.h
++++ b/include/drm/drm_connector.h
+@@ -765,6 +765,13 @@ struct drm_connector_funcs {
+ */
+ struct drm_cmdline_mode {
+ /**
++ * @name:
++ *
++ * Name of the mode.
++ */
++ char name[DRM_DISPLAY_MODE_LEN];
++
++ /**
+ * @specified:
+ *
+ * Has a mode been read from the command-line?
--- /dev/null
+From 5a8ccd79b6bad32e52620a94199bf1af2e19708e Mon Sep 17 00:00:00 2001
+Date: Wed, 19 Jun 2019 12:17:51 +0200
+Subject: [PATCH] drm/modes: Allow to specify rotation and reflection
+ on the commandline
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Commit 1bf4e09227c345e246062285eba4b8fe660e512e upstream.
+Minor conflict resolution as upstream has moved functions
+from drm_fb_helper.c to a new drm_client_modeset.c
+
+Rotations and reflections setup are needed in some scenarios to initialise
+properly the initial framebuffer. Some drivers already had a bunch of
+quirks to deal with this, such as either a private kernel command line
+parameter (omapdss) or on the device tree (various panels).
+
+In order to accomodate this, let's create a video mode parameter to deal
+with the rotation and reflexion.
+
+Link: https://patchwork.freedesktop.org/patch/msgid/777da16e42db757c1f5b414b5ca34507097fed5c.1560783090.git-series.maxime.ripard@bootlin.com
+---
+ Documentation/fb/modedb.txt | 12 ++++
+ drivers/gpu/drm/drm_fb_helper.c | 30 +++++++++
+ drivers/gpu/drm/drm_modes.c | 114 ++++++++++++++++++++++++++------
+ include/drm/drm_connector.h | 10 +++
+ 4 files changed, 146 insertions(+), 20 deletions(-)
+
+--- a/Documentation/fb/modedb.txt
++++ b/Documentation/fb/modedb.txt
+@@ -51,6 +51,18 @@ To force the VGA output to be enabled an
+ Specifying the option multiple times for different ports is possible, e.g.:
+ video=LVDS-1:d video=HDMI-1:D
+
++Options can also be passed after the mode, using commas as separator.
++
++ Sample usage: 720x480,rotate=180 - 720x480 mode, rotated by 180 degrees
++
++Valid options are:
++
++ - reflect_x (boolean): Perform an axial symmetry on the X axis
++ - reflect_y (boolean): Perform an axial symmetry on the Y axis
++ - rotate (integer): Rotate the initial framebuffer by x
++ degrees. Valid values are 0, 90, 180 and 270.
++
++
+ ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo *****
+
+ What is the VESA(TM) Coordinated Video Timings (CVT)?
+--- a/drivers/gpu/drm/drm_fb_helper.c
++++ b/drivers/gpu/drm/drm_fb_helper.c
+@@ -2469,6 +2469,7 @@ static void drm_setup_crtc_rotation(stru
+ struct drm_connector *connector)
+ {
+ struct drm_plane *plane = fb_crtc->mode_set.crtc->primary;
++ struct drm_cmdline_mode *cmdline;
+ uint64_t valid_mask = 0;
+ int i, rotation;
+
+@@ -2488,6 +2489,35 @@ static void drm_setup_crtc_rotation(stru
+ rotation = DRM_MODE_ROTATE_0;
+ }
+
++ /**
++ * The panel already defined the default rotation
++ * through its orientation. Whatever has been provided
++ * on the command line needs to be added to that.
++ *
++ * Unfortunately, the rotations are at different bit
++ * indices, so the math to add them up are not as
++ * trivial as they could.
++ *
++ * Reflections on the other hand are pretty trivial to deal with, a
++ * simple XOR between the two handle the addition nicely.
++ */
++ cmdline = &connector->cmdline_mode;
++ if (cmdline->specified) {
++ unsigned int cmdline_rest, panel_rest;
++ unsigned int cmdline_rot, panel_rot;
++ unsigned int sum_rot, sum_rest;
++
++ panel_rot = ilog2(rotation & DRM_MODE_ROTATE_MASK);
++ cmdline_rot = ilog2(cmdline->rotation_reflection & DRM_MODE_ROTATE_MASK);
++ sum_rot = (panel_rot + cmdline_rot) % 4;
++
++ panel_rest = rotation & ~DRM_MODE_ROTATE_MASK;
++ cmdline_rest = cmdline->rotation_reflection & ~DRM_MODE_ROTATE_MASK;
++ sum_rest = panel_rest ^ cmdline_rest;
++
++ rotation = (1 << sum_rot) | sum_rest;
++ }
++
+ /*
+ * TODO: support 90 / 270 degree hardware rotation,
+ * depending on the hardware this may require the framebuffer
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1560,6 +1560,71 @@ static int drm_mode_parse_cmdline_res_mo
+ return 0;
+ }
+
++static int drm_mode_parse_cmdline_options(char *str, size_t len,
++ struct drm_connector *connector,
++ struct drm_cmdline_mode *mode)
++{
++ unsigned int rotation = 0;
++ char *sep = str;
++
++ while ((sep = strchr(sep, ','))) {
++ char *delim, *option;
++
++ option = sep + 1;
++ delim = strchr(option, '=');
++ if (!delim) {
++ delim = strchr(option, ',');
++
++ if (!delim)
++ delim = str + len;
++ }
++
++ if (!strncmp(option, "rotate", delim - option)) {
++ const char *value = delim + 1;
++ unsigned int deg;
++
++ deg = simple_strtol(value, &sep, 10);
++
++ /* Make sure we have parsed something */
++ if (sep == value)
++ return -EINVAL;
++
++ switch (deg) {
++ case 0:
++ rotation |= DRM_MODE_ROTATE_0;
++ break;
++
++ case 90:
++ rotation |= DRM_MODE_ROTATE_90;
++ break;
++
++ case 180:
++ rotation |= DRM_MODE_ROTATE_180;
++ break;
++
++ case 270:
++ rotation |= DRM_MODE_ROTATE_270;
++ break;
++
++ default:
++ return -EINVAL;
++ }
++ } else if (!strncmp(option, "reflect_x", delim - option)) {
++ rotation |= DRM_MODE_REFLECT_X;
++ sep = delim;
++ } else if (!strncmp(option, "reflect_y", delim - option)) {
++ rotation |= DRM_MODE_REFLECT_Y;
++ sep = delim;
++ } else {
++ return -EINVAL;
++ }
++ }
++
++ mode->rotation_reflection = rotation;
++
++ return 0;
++}
++
+ /**
+ * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
+ * @mode_option: optional per connector mode option
+@@ -1575,6 +1640,10 @@ static int drm_mode_parse_cmdline_res_mo
+ *
+ * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
+ *
++ * Additionals options can be provided following the mode, using a comma to
++ * separate each option. Valid options can be found in
++ * Documentation/fb/modedb.txt.
++ *
+ * The intermediate drm_cmdline_mode structure is required to store additional
+ * options from the command line modline like the force-enable/disable flag.
+ *
+@@ -1587,9 +1656,10 @@ bool drm_mode_parse_command_line_for_con
+ {
+ const char *name;
+ bool named_mode = false, parse_extras = false;
+- unsigned int bpp_off = 0, refresh_off = 0;
++ unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
+ unsigned int mode_end = 0;
+ char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
++ char *options_ptr = NULL;
+ char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
+ int ret;
+
+@@ -1638,13 +1708,18 @@ bool drm_mode_parse_command_line_for_con
+ mode->refresh_specified = true;
+ }
+
++ /* Locate the start of named options */
++ options_ptr = strchr(name, ',');
++ if (options_ptr)
++ options_off = options_ptr - name;
++
+ /* Locate the end of the name / resolution, and parse it */
+- if (bpp_ptr && refresh_ptr) {
+- mode_end = min(bpp_off, refresh_off);
+- } else if (bpp_ptr) {
++ if (bpp_ptr) {
+ mode_end = bpp_off;
+ } else if (refresh_ptr) {
+ mode_end = refresh_off;
++ } else if (options_ptr) {
++ mode_end = options_off;
+ } else {
+ mode_end = strlen(name);
+ parse_extras = true;
+@@ -1686,24 +1761,23 @@ bool drm_mode_parse_command_line_for_con
+ else if (refresh_ptr)
+ extra_ptr = refresh_end_ptr;
+
+- if (extra_ptr) {
+- if (!named_mode) {
+- int len = strlen(name) - (extra_ptr - name);
+-
+- ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
+- connector, mode);
+- if (ret)
+- return false;
+- } else {
+- int remaining = strlen(name) - (extra_ptr - name);
++ if (extra_ptr &&
++ extra_ptr != options_ptr) {
++ int len = strlen(name) - (extra_ptr - name);
+
+- /*
+- * We still have characters to process, while
+- * we shouldn't have any
+- */
+- if (remaining > 0)
+- return false;
+- }
++ ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
++ connector, mode);
++ if (ret)
++ return false;
++ }
++
++ if (options_ptr) {
++ int len = strlen(name) - (options_ptr - name);
++
++ ret = drm_mode_parse_cmdline_options(options_ptr, len,
++ connector, mode);
++ if (ret)
++ return false;
+ }
+
+ return true;
+--- a/include/drm/drm_connector.h
++++ b/include/drm/drm_connector.h
+@@ -857,6 +857,16 @@ struct drm_cmdline_mode {
+ * state to one of the DRM_FORCE_* values.
+ */
+ enum drm_connector_force force;
++
++ /**
++ * @rotation_reflection:
++ *
++ * Initial rotation and reflection of the mode setup from the
++ * command line. See DRM_MODE_ROTATE_* and
++ * DRM_MODE_REFLECT_*. The only rotations supported are
++ * DRM_MODE_ROTATE_0 and DRM_MODE_ROTATE_180.
++ */
++ unsigned int rotation_reflection;
+ };
+
+ /**
+++ /dev/null
-From 3508a8548f13be68b6d098ad99a7bc1fc1810f76 Mon Sep 17 00:00:00 2001
-Date: Wed, 19 Jun 2019 12:17:49 +0200
-Subject: [PATCH] drm/modes: Rewrite the command line parser
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-commit e08ab74bd4c7a5fe311bc05f32dbb4f1e7fa3428 upstream.
-
-Rewrite the command line parser in order to get away from the state machine
-parsing the video mode lines.
-
-Hopefully, this will allow to extend it more easily to support named modes
-and / or properties set directly on the command line.
-
-Link: https://patchwork.freedesktop.org/patch/msgid/e32cd4009153b184103554009135c7bf7c9975d7.1560783090.git-series.maxime.ripard@bootlin.com
----
- drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++-------------
- 1 file changed, 210 insertions(+), 115 deletions(-)
-
---- a/drivers/gpu/drm/drm_modes.c
-+++ b/drivers/gpu/drm/drm_modes.c
-@@ -30,6 +30,7 @@
- * authorization from the copyright holder(s) and author(s).
- */
-
-+#include <linux/ctype.h>
- #include <linux/list.h>
- #include <linux/list_sort.h>
- #include <linux/export.h>
-@@ -1414,6 +1415,151 @@ void drm_connector_list_update(struct dr
- }
- EXPORT_SYMBOL(drm_connector_list_update);
-
-+static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
-+ struct drm_cmdline_mode *mode)
-+{
-+ unsigned int bpp;
-+
-+ if (str[0] != '-')
-+ return -EINVAL;
-+
-+ str++;
-+ bpp = simple_strtol(str, end_ptr, 10);
-+ if (*end_ptr == str)
-+ return -EINVAL;
-+
-+ mode->bpp = bpp;
-+ mode->bpp_specified = true;
-+
-+ return 0;
-+}
-+
-+static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
-+ struct drm_cmdline_mode *mode)
-+{
-+ unsigned int refresh;
-+
-+ if (str[0] != '@')
-+ return -EINVAL;
-+
-+ str++;
-+ refresh = simple_strtol(str, end_ptr, 10);
-+ if (*end_ptr == str)
-+ return -EINVAL;
-+
-+ mode->refresh = refresh;
-+ mode->refresh_specified = true;
-+
-+ return 0;
-+}
-+
-+static int drm_mode_parse_cmdline_extra(const char *str, int length,
-+ struct drm_connector *connector,
-+ struct drm_cmdline_mode *mode)
-+{
-+ int i;
-+
-+ for (i = 0; i < length; i++) {
-+ switch (str[i]) {
-+ case 'i':
-+ mode->interlace = true;
-+ break;
-+ case 'm':
-+ mode->margins = true;
-+ break;
-+ case 'D':
-+ if (mode->force != DRM_FORCE_UNSPECIFIED)
-+ return -EINVAL;
-+
-+ if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
-+ (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
-+ mode->force = DRM_FORCE_ON;
-+ else
-+ mode->force = DRM_FORCE_ON_DIGITAL;
-+ break;
-+ case 'd':
-+ if (mode->force != DRM_FORCE_UNSPECIFIED)
-+ return -EINVAL;
-+
-+ mode->force = DRM_FORCE_OFF;
-+ break;
-+ case 'e':
-+ if (mode->force != DRM_FORCE_UNSPECIFIED)
-+ return -EINVAL;
-+
-+ mode->force = DRM_FORCE_ON;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
-+ bool extras,
-+ struct drm_connector *connector,
-+ struct drm_cmdline_mode *mode)
-+{
-+ const char *str_start = str;
-+ bool rb = false, cvt = false;
-+ int xres = 0, yres = 0;
-+ int remaining, i;
-+ char *end_ptr;
-+
-+ xres = simple_strtol(str, &end_ptr, 10);
-+ if (end_ptr == str)
-+ return -EINVAL;
-+
-+ if (end_ptr[0] != 'x')
-+ return -EINVAL;
-+ end_ptr++;
-+
-+ str = end_ptr;
-+ yres = simple_strtol(str, &end_ptr, 10);
-+ if (end_ptr == str)
-+ return -EINVAL;
-+
-+ remaining = length - (end_ptr - str_start);
-+ if (remaining < 0)
-+ return -EINVAL;
-+
-+ for (i = 0; i < remaining; i++) {
-+ switch (end_ptr[i]) {
-+ case 'M':
-+ cvt = true;
-+ break;
-+ case 'R':
-+ rb = true;
-+ break;
-+ default:
-+ /*
-+ * Try to pass that to our extras parsing
-+ * function to handle the case where the
-+ * extras are directly after the resolution
-+ */
-+ if (extras) {
-+ int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
-+ 1,
-+ connector,
-+ mode);
-+ if (ret)
-+ return ret;
-+ } else {
-+ return -EINVAL;
-+ }
-+ }
-+ }
-+
-+ mode->xres = xres;
-+ mode->yres = yres;
-+ mode->cvt = cvt;
-+ mode->rb = rb;
-+
-+ return 0;
-+}
-+
- /**
- * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
- * @mode_option: optional per connector mode option
-@@ -1440,13 +1586,12 @@ bool drm_mode_parse_command_line_for_con
- struct drm_cmdline_mode *mode)
- {
- const char *name;
-- unsigned int namelen;
-- bool res_specified = false, bpp_specified = false, refresh_specified = false;
-- unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
-- bool yres_specified = false, cvt = false, rb = false;
-- bool interlace = false, margins = false, was_digit = false;
-- int i;
-- enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
-+ bool parse_extras = false;
-+ unsigned int bpp_off = 0, refresh_off = 0;
-+ unsigned int mode_end = 0;
-+ char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
-+ char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
-+ int ret;
-
- #ifdef CONFIG_FB
- if (!mode_option)
-@@ -1459,127 +1604,77 @@ bool drm_mode_parse_command_line_for_con
- }
-
- name = mode_option;
-- namelen = strlen(name);
-- for (i = namelen-1; i >= 0; i--) {
-- switch (name[i]) {
-- case '@':
-- if (!refresh_specified && !bpp_specified &&
-- !yres_specified && !cvt && !rb && was_digit) {
-- refresh = simple_strtol(&name[i+1], NULL, 10);
-- refresh_specified = true;
-- was_digit = false;
-- } else
-- goto done;
-- break;
-- case '-':
-- if (!bpp_specified && !yres_specified && !cvt &&
-- !rb && was_digit) {
-- bpp = simple_strtol(&name[i+1], NULL, 10);
-- bpp_specified = true;
-- was_digit = false;
-- } else
-- goto done;
-- break;
-- case 'x':
-- if (!yres_specified && was_digit) {
-- yres = simple_strtol(&name[i+1], NULL, 10);
-- yres_specified = true;
-- was_digit = false;
-- } else
-- goto done;
-- break;
-- case '0' ... '9':
-- was_digit = true;
-- break;
-- case 'M':
-- if (yres_specified || cvt || was_digit)
-- goto done;
-- cvt = true;
-- break;
-- case 'R':
-- if (yres_specified || cvt || rb || was_digit)
-- goto done;
-- rb = true;
-- break;
-- case 'm':
-- if (cvt || yres_specified || was_digit)
-- goto done;
-- margins = true;
-- break;
-- case 'i':
-- if (cvt || yres_specified || was_digit)
-- goto done;
-- interlace = true;
-- break;
-- case 'e':
-- if (yres_specified || bpp_specified || refresh_specified ||
-- was_digit || (force != DRM_FORCE_UNSPECIFIED))
-- goto done;
-
-- force = DRM_FORCE_ON;
-- break;
-- case 'D':
-- if (yres_specified || bpp_specified || refresh_specified ||
-- was_digit || (force != DRM_FORCE_UNSPECIFIED))
-- goto done;
-+ if (!isdigit(name[0]))
-+ return false;
-
-- if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
-- (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
-- force = DRM_FORCE_ON;
-- else
-- force = DRM_FORCE_ON_DIGITAL;
-- break;
-- case 'd':
-- if (yres_specified || bpp_specified || refresh_specified ||
-- was_digit || (force != DRM_FORCE_UNSPECIFIED))
-- goto done;
-+ /* Try to locate the bpp and refresh specifiers, if any */
-+ bpp_ptr = strchr(name, '-');
-+ if (bpp_ptr) {
-+ bpp_off = bpp_ptr - name;
-+ mode->bpp_specified = true;
-+ }
-
-- force = DRM_FORCE_OFF;
-- break;
-- default:
-- goto done;
-- }
-+ refresh_ptr = strchr(name, '@');
-+ if (refresh_ptr) {
-+ refresh_off = refresh_ptr - name;
-+ mode->refresh_specified = true;
- }
-
-- if (i < 0 && yres_specified) {
-- char *ch;
-- xres = simple_strtol(name, &ch, 10);
-- if ((ch != NULL) && (*ch == 'x'))
-- res_specified = true;
-- else
-- i = ch - name;
-- } else if (!yres_specified && was_digit) {
-- /* catch mode that begins with digits but has no 'x' */
-- i = 0;
-- }
--done:
-- if (i >= 0) {
-- pr_warn("[drm] parse error at position %i in video mode '%s'\n",
-- i, name);
-- mode->specified = false;
-- return false;
-+ /* Locate the end of the name / resolution, and parse it */
-+ if (bpp_ptr && refresh_ptr) {
-+ mode_end = min(bpp_off, refresh_off);
-+ } else if (bpp_ptr) {
-+ mode_end = bpp_off;
-+ } else if (refresh_ptr) {
-+ mode_end = refresh_off;
-+ } else {
-+ mode_end = strlen(name);
-+ parse_extras = true;
- }
-
-- if (res_specified) {
-- mode->specified = true;
-- mode->xres = xres;
-- mode->yres = yres;
-+ ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
-+ parse_extras,
-+ connector,
-+ mode);
-+ if (ret)
-+ return false;
-+ mode->specified = true;
-+
-+ if (bpp_ptr) {
-+ ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
-+ if (ret)
-+ return false;
- }
-
-- if (refresh_specified) {
-- mode->refresh_specified = true;
-- mode->refresh = refresh;
-+ if (refresh_ptr) {
-+ ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
-+ &refresh_end_ptr, mode);
-+ if (ret)
-+ return false;
- }
-
-- if (bpp_specified) {
-- mode->bpp_specified = true;
-- mode->bpp = bpp;
-+ /*
-+ * Locate the end of the bpp / refresh, and parse the extras
-+ * if relevant
-+ */
-+ if (bpp_ptr && refresh_ptr)
-+ extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
-+ else if (bpp_ptr)
-+ extra_ptr = bpp_end_ptr;
-+ else if (refresh_ptr)
-+ extra_ptr = refresh_end_ptr;
-+
-+ if (extra_ptr) {
-+ int remaining = strlen(name) - (extra_ptr - name);
-+
-+ /*
-+ * We still have characters to process, while
-+ * we shouldn't have any
-+ */
-+ if (remaining > 0)
-+ return false;
- }
-- mode->rb = rb;
-- mode->cvt = cvt;
-- mode->interlace = interlace;
-- mode->margins = margins;
-- mode->force = force;
-
- return true;
- }
--- /dev/null
+From 6261047a83258900e57a0a699ec7954360c6e7f3 Mon Sep 17 00:00:00 2001
+Date: Wed, 19 Jun 2019 12:17:51 +0200
+Subject: [PATCH] drm/connector: Introduce a TV margins structure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Commit 22045e8e52bd802f743f0471242782fc3b479707 upstream.
+
+The TV margins has been defined as a structure inside the
+drm_connector_state structure so far. However, we will need it in other
+structures as well, so let's move that structure definition so that it can
+be reused.
+
+Link: https://patchwork.freedesktop.org/patch/msgid/38b773b03f15ec7a135cdf8f7db669e5ada20cf2.1560783090.git-series.maxime.ripard@bootlin.com
+---
+ include/drm/drm_connector.h | 41 +++++++++++++++++++++++++++----------
+ 1 file changed, 30 insertions(+), 11 deletions(-)
+
+--- a/include/drm/drm_connector.h
++++ b/include/drm/drm_connector.h
+@@ -344,13 +344,37 @@ int drm_display_info_set_bus_formats(str
+ unsigned int num_formats);
+
+ /**
++ * struct drm_connector_tv_margins - TV connector related margins
++ *
++ * Describes the margins in pixels to put around the image on TV
++ * connectors to deal with overscan.
++ */
++struct drm_connector_tv_margins {
++ /**
++ * @bottom: Bottom margin in pixels.
++ */
++ unsigned int bottom;
++
++ /**
++ * @left: Left margin in pixels.
++ */
++ unsigned int left;
++
++ /**
++ * @right: Right margin in pixels.
++ */
++ unsigned int right;
++
++ /**
++ * @top: Top margin in pixels.
++ */
++ unsigned int top;
++};
++
++/**
+ * struct drm_tv_connector_state - TV connector related states
+ * @subconnector: selected subconnector
+- * @margins: margins (all margins are expressed in pixels)
+- * @margins.left: left margin
+- * @margins.right: right margin
+- * @margins.top: top margin
+- * @margins.bottom: bottom margin
++ * @margins: TV margins
+ * @mode: TV mode
+ * @brightness: brightness in percent
+ * @contrast: contrast in percent
+@@ -361,12 +385,7 @@ int drm_display_info_set_bus_formats(str
+ */
+ struct drm_tv_connector_state {
+ enum drm_mode_subconnector subconnector;
+- struct {
+- unsigned int left;
+- unsigned int right;
+- unsigned int top;
+- unsigned int bottom;
+- } margins;
++ struct drm_connector_tv_margins margins;
+ unsigned int mode;
+ unsigned int brightness;
+ unsigned int contrast;
+++ /dev/null
-From 2cea4924c69b6be5cfe8d976810ccf76a3991230 Mon Sep 17 00:00:00 2001
-Date: Wed, 19 Jun 2019 12:17:50 +0200
-Subject: [PATCH] drm/modes: Support modes names on the command line
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-commit 3aeeb13d899627fe2b86bdbdcd0927cf7192234f upstream.
-Minor conflict resolution as upstream has moved functions
-from drm_fb_helper.c to a new drm_client_modeset.c
-
-The drm subsystem also uses the video= kernel parameter, and in the
-documentation refers to the fbdev documentation for that parameter.
-
-However, that documentation also says that instead of giving the mode using
-its resolution we can also give a name. However, DRM doesn't handle that
-case at the moment. Even though in most case it shouldn't make any
-difference, it might be useful for analog modes, where different standards
-might have the same resolution, but still have a few different parameters
-that are not encoded in the modes (NTSC vs NTSC-J vs PAL-M for example).
-
-Link: https://patchwork.freedesktop.org/patch/msgid/18443e0c3bdbbd16cea4ec63bc7f2079b820b43b.1560783090.git-series.maxime.ripard@bootlin.com
----
- drivers/gpu/drm/drm_connector.c | 3 +-
- drivers/gpu/drm/drm_fb_helper.c | 4 +++
- drivers/gpu/drm/drm_modes.c | 62 ++++++++++++++++++++++++---------
- include/drm/drm_connector.h | 7 ++++
- 4 files changed, 59 insertions(+), 17 deletions(-)
-
---- a/drivers/gpu/drm/drm_connector.c
-+++ b/drivers/gpu/drm/drm_connector.c
-@@ -135,8 +135,9 @@ static void drm_connector_get_cmdline_mo
- connector->force = mode->force;
- }
-
-- DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
-+ DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
- connector->name,
-+ mode->name ? mode->name : "",
- mode->xres, mode->yres,
- mode->refresh_specified ? mode->refresh : 60,
- mode->rb ? " reduced blanking" : "",
---- a/drivers/gpu/drm/drm_fb_helper.c
-+++ b/drivers/gpu/drm/drm_fb_helper.c
-@@ -2104,6 +2104,10 @@ struct drm_display_mode *drm_pick_cmdlin
- prefer_non_interlace = !cmdline_mode->interlace;
- again:
- list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
-+ /* Check (optional) mode name first */
-+ if (!strcmp(mode->name, cmdline_mode->name))
-+ return mode;
-+
- /* check width/height */
- if (mode->hdisplay != cmdline_mode->xres ||
- mode->vdisplay != cmdline_mode->yres)
---- a/drivers/gpu/drm/drm_modes.c
-+++ b/drivers/gpu/drm/drm_modes.c
-@@ -1586,7 +1586,7 @@ bool drm_mode_parse_command_line_for_con
- struct drm_cmdline_mode *mode)
- {
- const char *name;
-- bool parse_extras = false;
-+ bool named_mode = false, parse_extras = false;
- unsigned int bpp_off = 0, refresh_off = 0;
- unsigned int mode_end = 0;
- char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
-@@ -1605,8 +1605,22 @@ bool drm_mode_parse_command_line_for_con
-
- name = mode_option;
-
-- if (!isdigit(name[0]))
-- return false;
-+ /*
-+ * This is a bit convoluted. To differentiate between the
-+ * named modes and poorly formatted resolutions, we need a
-+ * bunch of things:
-+ * - We need to make sure that the first character (which
-+ * would be our resolution in X) is a digit.
-+ * - However, if the X resolution is missing, then we end up
-+ * with something like x<yres>, with our first character
-+ * being an alpha-numerical character, which would be
-+ * considered a named mode.
-+ *
-+ * If this isn't enough, we should add more heuristics here,
-+ * and matching unit-tests.
-+ */
-+ if (!isdigit(name[0]) && name[0] != 'x')
-+ named_mode = true;
-
- /* Try to locate the bpp and refresh specifiers, if any */
- bpp_ptr = strchr(name, '-');
-@@ -1617,6 +1631,9 @@ bool drm_mode_parse_command_line_for_con
-
- refresh_ptr = strchr(name, '@');
- if (refresh_ptr) {
-+ if (named_mode)
-+ return false;
-+
- refresh_off = refresh_ptr - name;
- mode->refresh_specified = true;
- }
-@@ -1633,12 +1650,16 @@ bool drm_mode_parse_command_line_for_con
- parse_extras = true;
- }
-
-- ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
-- parse_extras,
-- connector,
-- mode);
-- if (ret)
-- return false;
-+ if (named_mode) {
-+ strncpy(mode->name, name, mode_end);
-+ } else {
-+ ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
-+ parse_extras,
-+ connector,
-+ mode);
-+ if (ret)
-+ return false;
-+ }
- mode->specified = true;
-
- if (bpp_ptr) {
-@@ -1666,14 +1687,23 @@ bool drm_mode_parse_command_line_for_con
- extra_ptr = refresh_end_ptr;
-
- if (extra_ptr) {
-- int remaining = strlen(name) - (extra_ptr - name);
-+ if (!named_mode) {
-+ int len = strlen(name) - (extra_ptr - name);
-
-- /*
-- * We still have characters to process, while
-- * we shouldn't have any
-- */
-- if (remaining > 0)
-- return false;
-+ ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
-+ connector, mode);
-+ if (ret)
-+ return false;
-+ } else {
-+ int remaining = strlen(name) - (extra_ptr - name);
-+
-+ /*
-+ * We still have characters to process, while
-+ * we shouldn't have any
-+ */
-+ if (remaining > 0)
-+ return false;
-+ }
- }
-
- return true;
---- a/include/drm/drm_connector.h
-+++ b/include/drm/drm_connector.h
-@@ -765,6 +765,13 @@ struct drm_connector_funcs {
- */
- struct drm_cmdline_mode {
- /**
-+ * @name:
-+ *
-+ * Name of the mode.
-+ */
-+ char name[DRM_DISPLAY_MODE_LEN];
-+
-+ /**
- * @specified:
- *
- * Has a mode been read from the command-line?
+++ /dev/null
-From 5a8ccd79b6bad32e52620a94199bf1af2e19708e Mon Sep 17 00:00:00 2001
-Date: Wed, 19 Jun 2019 12:17:51 +0200
-Subject: [PATCH] drm/modes: Allow to specify rotation and reflection
- on the commandline
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Commit 1bf4e09227c345e246062285eba4b8fe660e512e upstream.
-Minor conflict resolution as upstream has moved functions
-from drm_fb_helper.c to a new drm_client_modeset.c
-
-Rotations and reflections setup are needed in some scenarios to initialise
-properly the initial framebuffer. Some drivers already had a bunch of
-quirks to deal with this, such as either a private kernel command line
-parameter (omapdss) or on the device tree (various panels).
-
-In order to accomodate this, let's create a video mode parameter to deal
-with the rotation and reflexion.
-
-Link: https://patchwork.freedesktop.org/patch/msgid/777da16e42db757c1f5b414b5ca34507097fed5c.1560783090.git-series.maxime.ripard@bootlin.com
----
- Documentation/fb/modedb.txt | 12 ++++
- drivers/gpu/drm/drm_fb_helper.c | 30 +++++++++
- drivers/gpu/drm/drm_modes.c | 114 ++++++++++++++++++++++++++------
- include/drm/drm_connector.h | 10 +++
- 4 files changed, 146 insertions(+), 20 deletions(-)
-
---- a/Documentation/fb/modedb.txt
-+++ b/Documentation/fb/modedb.txt
-@@ -51,6 +51,18 @@ To force the VGA output to be enabled an
- Specifying the option multiple times for different ports is possible, e.g.:
- video=LVDS-1:d video=HDMI-1:D
-
-+Options can also be passed after the mode, using commas as separator.
-+
-+ Sample usage: 720x480,rotate=180 - 720x480 mode, rotated by 180 degrees
-+
-+Valid options are:
-+
-+ - reflect_x (boolean): Perform an axial symmetry on the X axis
-+ - reflect_y (boolean): Perform an axial symmetry on the Y axis
-+ - rotate (integer): Rotate the initial framebuffer by x
-+ degrees. Valid values are 0, 90, 180 and 270.
-+
-+
- ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo *****
-
- What is the VESA(TM) Coordinated Video Timings (CVT)?
---- a/drivers/gpu/drm/drm_fb_helper.c
-+++ b/drivers/gpu/drm/drm_fb_helper.c
-@@ -2469,6 +2469,7 @@ static void drm_setup_crtc_rotation(stru
- struct drm_connector *connector)
- {
- struct drm_plane *plane = fb_crtc->mode_set.crtc->primary;
-+ struct drm_cmdline_mode *cmdline;
- uint64_t valid_mask = 0;
- int i, rotation;
-
-@@ -2488,6 +2489,35 @@ static void drm_setup_crtc_rotation(stru
- rotation = DRM_MODE_ROTATE_0;
- }
-
-+ /**
-+ * The panel already defined the default rotation
-+ * through its orientation. Whatever has been provided
-+ * on the command line needs to be added to that.
-+ *
-+ * Unfortunately, the rotations are at different bit
-+ * indices, so the math to add them up are not as
-+ * trivial as they could.
-+ *
-+ * Reflections on the other hand are pretty trivial to deal with, a
-+ * simple XOR between the two handle the addition nicely.
-+ */
-+ cmdline = &connector->cmdline_mode;
-+ if (cmdline->specified) {
-+ unsigned int cmdline_rest, panel_rest;
-+ unsigned int cmdline_rot, panel_rot;
-+ unsigned int sum_rot, sum_rest;
-+
-+ panel_rot = ilog2(rotation & DRM_MODE_ROTATE_MASK);
-+ cmdline_rot = ilog2(cmdline->rotation_reflection & DRM_MODE_ROTATE_MASK);
-+ sum_rot = (panel_rot + cmdline_rot) % 4;
-+
-+ panel_rest = rotation & ~DRM_MODE_ROTATE_MASK;
-+ cmdline_rest = cmdline->rotation_reflection & ~DRM_MODE_ROTATE_MASK;
-+ sum_rest = panel_rest ^ cmdline_rest;
-+
-+ rotation = (1 << sum_rot) | sum_rest;
-+ }
-+
- /*
- * TODO: support 90 / 270 degree hardware rotation,
- * depending on the hardware this may require the framebuffer
---- a/drivers/gpu/drm/drm_modes.c
-+++ b/drivers/gpu/drm/drm_modes.c
-@@ -1560,6 +1560,71 @@ static int drm_mode_parse_cmdline_res_mo
- return 0;
- }
-
-+static int drm_mode_parse_cmdline_options(char *str, size_t len,
-+ struct drm_connector *connector,
-+ struct drm_cmdline_mode *mode)
-+{
-+ unsigned int rotation = 0;
-+ char *sep = str;
-+
-+ while ((sep = strchr(sep, ','))) {
-+ char *delim, *option;
-+
-+ option = sep + 1;
-+ delim = strchr(option, '=');
-+ if (!delim) {
-+ delim = strchr(option, ',');
-+
-+ if (!delim)
-+ delim = str + len;
-+ }
-+
-+ if (!strncmp(option, "rotate", delim - option)) {
-+ const char *value = delim + 1;
-+ unsigned int deg;
-+
-+ deg = simple_strtol(value, &sep, 10);
-+
-+ /* Make sure we have parsed something */
-+ if (sep == value)
-+ return -EINVAL;
-+
-+ switch (deg) {
-+ case 0:
-+ rotation |= DRM_MODE_ROTATE_0;
-+ break;
-+
-+ case 90:
-+ rotation |= DRM_MODE_ROTATE_90;
-+ break;
-+
-+ case 180:
-+ rotation |= DRM_MODE_ROTATE_180;
-+ break;
-+
-+ case 270:
-+ rotation |= DRM_MODE_ROTATE_270;
-+ break;
-+
-+ default:
-+ return -EINVAL;
-+ }
-+ } else if (!strncmp(option, "reflect_x", delim - option)) {
-+ rotation |= DRM_MODE_REFLECT_X;
-+ sep = delim;
-+ } else if (!strncmp(option, "reflect_y", delim - option)) {
-+ rotation |= DRM_MODE_REFLECT_Y;
-+ sep = delim;
-+ } else {
-+ return -EINVAL;
-+ }
-+ }
-+
-+ mode->rotation_reflection = rotation;
-+
-+ return 0;
-+}
-+
- /**
- * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
- * @mode_option: optional per connector mode option
-@@ -1575,6 +1640,10 @@ static int drm_mode_parse_cmdline_res_mo
- *
- * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
- *
-+ * Additionals options can be provided following the mode, using a comma to
-+ * separate each option. Valid options can be found in
-+ * Documentation/fb/modedb.txt.
-+ *
- * The intermediate drm_cmdline_mode structure is required to store additional
- * options from the command line modline like the force-enable/disable flag.
- *
-@@ -1587,9 +1656,10 @@ bool drm_mode_parse_command_line_for_con
- {
- const char *name;
- bool named_mode = false, parse_extras = false;
-- unsigned int bpp_off = 0, refresh_off = 0;
-+ unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
- unsigned int mode_end = 0;
- char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
-+ char *options_ptr = NULL;
- char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
- int ret;
-
-@@ -1638,13 +1708,18 @@ bool drm_mode_parse_command_line_for_con
- mode->refresh_specified = true;
- }
-
-+ /* Locate the start of named options */
-+ options_ptr = strchr(name, ',');
-+ if (options_ptr)
-+ options_off = options_ptr - name;
-+
- /* Locate the end of the name / resolution, and parse it */
-- if (bpp_ptr && refresh_ptr) {
-- mode_end = min(bpp_off, refresh_off);
-- } else if (bpp_ptr) {
-+ if (bpp_ptr) {
- mode_end = bpp_off;
- } else if (refresh_ptr) {
- mode_end = refresh_off;
-+ } else if (options_ptr) {
-+ mode_end = options_off;
- } else {
- mode_end = strlen(name);
- parse_extras = true;
-@@ -1686,24 +1761,23 @@ bool drm_mode_parse_command_line_for_con
- else if (refresh_ptr)
- extra_ptr = refresh_end_ptr;
-
-- if (extra_ptr) {
-- if (!named_mode) {
-- int len = strlen(name) - (extra_ptr - name);
--
-- ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
-- connector, mode);
-- if (ret)
-- return false;
-- } else {
-- int remaining = strlen(name) - (extra_ptr - name);
-+ if (extra_ptr &&
-+ extra_ptr != options_ptr) {
-+ int len = strlen(name) - (extra_ptr - name);
-
-- /*
-- * We still have characters to process, while
-- * we shouldn't have any
-- */
-- if (remaining > 0)
-- return false;
-- }
-+ ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
-+ connector, mode);
-+ if (ret)
-+ return false;
-+ }
-+
-+ if (options_ptr) {
-+ int len = strlen(name) - (options_ptr - name);
-+
-+ ret = drm_mode_parse_cmdline_options(options_ptr, len,
-+ connector, mode);
-+ if (ret)
-+ return false;
- }
-
- return true;
---- a/include/drm/drm_connector.h
-+++ b/include/drm/drm_connector.h
-@@ -857,6 +857,16 @@ struct drm_cmdline_mode {
- * state to one of the DRM_FORCE_* values.
- */
- enum drm_connector_force force;
-+
-+ /**
-+ * @rotation_reflection:
-+ *
-+ * Initial rotation and reflection of the mode setup from the
-+ * command line. See DRM_MODE_ROTATE_* and
-+ * DRM_MODE_REFLECT_*. The only rotations supported are
-+ * DRM_MODE_ROTATE_0 and DRM_MODE_ROTATE_180.
-+ */
-+ unsigned int rotation_reflection;
- };
-
- /**
--- /dev/null
+From 99b367ee521e48beae92bea59515dd0f08f2e55b Mon Sep 17 00:00:00 2001
+Date: Wed, 19 Jun 2019 12:17:51 +0200
+Subject: [PATCH] drm/modes: Parse overscan properties
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Commit 3d46a3007cd8f73bae502bf5c171977b91d7aacc upstream.
+
+Properly configuring the overscan properties might be needed for the
+initial setup of the framebuffer for display that still have overscan.
+Let's allow for more properties on the kernel command line to setup each
+margin.
+
+Link: https://patchwork.freedesktop.org/patch/msgid/e481f1628e3768ca49226ec2115cfa4dfcbd5e4c.1560783090.git-series.maxime.ripard@bootlin.com
+---
+ Documentation/fb/modedb.txt | 2 ++
+ drivers/gpu/drm/drm_modes.c | 44 +++++++++++++++++++++++++++++++++++++
+ include/drm/drm_connector.h | 5 +++++
+ 3 files changed, 51 insertions(+)
+
+--- a/Documentation/fb/modedb.txt
++++ b/Documentation/fb/modedb.txt
+@@ -57,6 +57,8 @@ Options can also be passed after the mod
+
+ Valid options are:
+
++ - margin_top, margin_bottom, margin_left, margin_right (integer):
++ Number of pixels in the margins, typically to deal with overscan on TVs
+ - reflect_x (boolean): Perform an axial symmetry on the X axis
+ - reflect_y (boolean): Perform an axial symmetry on the Y axis
+ - rotate (integer): Rotate the initial framebuffer by x
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1615,6 +1615,50 @@ static int drm_mode_parse_cmdline_option
+ } else if (!strncmp(option, "reflect_y", delim - option)) {
+ rotation |= DRM_MODE_REFLECT_Y;
+ sep = delim;
++ } else if (!strncmp(option, "margin_right", delim - option)) {
++ const char *value = delim + 1;
++ unsigned int margin;
++
++ margin = simple_strtol(value, &sep, 10);
++
++ /* Make sure we have parsed something */
++ if (sep == value)
++ return -EINVAL;
++
++ mode->tv_margins.right = margin;
++ } else if (!strncmp(option, "margin_left", delim - option)) {
++ const char *value = delim + 1;
++ unsigned int margin;
++
++ margin = simple_strtol(value, &sep, 10);
++
++ /* Make sure we have parsed something */
++ if (sep == value)
++ return -EINVAL;
++
++ mode->tv_margins.left = margin;
++ } else if (!strncmp(option, "margin_top", delim - option)) {
++ const char *value = delim + 1;
++ unsigned int margin;
++
++ margin = simple_strtol(value, &sep, 10);
++
++ /* Make sure we have parsed something */
++ if (sep == value)
++ return -EINVAL;
++
++ mode->tv_margins.top = margin;
++ } else if (!strncmp(option, "margin_bottom", delim - option)) {
++ const char *value = delim + 1;
++ unsigned int margin;
++
++ margin = simple_strtol(value, &sep, 10);
++
++ /* Make sure we have parsed something */
++ if (sep == value)
++ return -EINVAL;
++
++ mode->tv_margins.bottom = margin;
+ } else {
+ return -EINVAL;
+ }
+--- a/include/drm/drm_connector.h
++++ b/include/drm/drm_connector.h
+@@ -886,6 +886,11 @@ struct drm_cmdline_mode {
+ * DRM_MODE_ROTATE_0 and DRM_MODE_ROTATE_180.
+ */
+ unsigned int rotation_reflection;
++
++ /**
++ * @tv_margins: TV margins to apply to the mode.
++ */
++ struct drm_connector_tv_margins tv_margins;
+ };
+
+ /**
--- /dev/null
+From 8dd1e4d73fdbc4a533a58c2c74a72877257c558c Mon Sep 17 00:00:00 2001
+Date: Wed, 19 Jun 2019 12:17:52 +0200
+Subject: [PATCH] drm/atomic: Add a function to reset connector TV
+ properties
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Commit 731514b446fe6748d5a55a3dff202efb45c7d8df upstream.
+Reworked as functions have been moved from drm_atomic_helper.[c|h]
+to drm_atomic_state_helper.[c|h].
+
+During the connector reset, if that connector has a TV property, it needs
+to be reset to the value provided on the command line.
+
+Provide a helper to do that.
+
+Link: https://patchwork.freedesktop.org/patch/msgid/84a7b657f09303a2850e1cc79e68f623547f3fdd.1560783090.git-series.maxime.ripard@bootlin.com
+---
+ drivers/gpu/drm/drm_atomic_helper.c | 18 ++++++++++++++++++
+ include/drm/drm_atomic_helper.h | 1 +
+ 2 files changed, 19 insertions(+)
+
+--- a/drivers/gpu/drm/drm_atomic_helper.c
++++ b/drivers/gpu/drm/drm_atomic_helper.c
+@@ -3737,6 +3737,24 @@ void drm_atomic_helper_connector_reset(s
+ EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
+
+ /**
++ * drm_atomic_helper_connector_tv_reset - Resets TV connector properties
++ * @connector: DRM connector
++ *
++ * Resets the TV-related properties attached to a connector.
++ */
++void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
++{
++ struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
++ struct drm_connector_state *state = connector->state;
++
++ state->tv.margins.left = cmdline->tv_margins.left;
++ state->tv.margins.right = cmdline->tv_margins.right;
++ state->tv.margins.top = cmdline->tv_margins.top;
++ state->tv.margins.bottom = cmdline->tv_margins.bottom;
++}
++EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
++
++/**
+ * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
+ * @connector: connector object
+ * @state: atomic connector state
+--- a/include/drm/drm_atomic_helper.h
++++ b/include/drm/drm_atomic_helper.h
+@@ -168,6 +168,7 @@ void drm_atomic_helper_plane_destroy_sta
+ void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
+ struct drm_connector_state *conn_state);
+ void drm_atomic_helper_connector_reset(struct drm_connector *connector);
++void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector);
+ void
+ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
+ struct drm_connector_state *state);
+++ /dev/null
-From 6261047a83258900e57a0a699ec7954360c6e7f3 Mon Sep 17 00:00:00 2001
-Date: Wed, 19 Jun 2019 12:17:51 +0200
-Subject: [PATCH] drm/connector: Introduce a TV margins structure
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Commit 22045e8e52bd802f743f0471242782fc3b479707 upstream.
-
-The TV margins has been defined as a structure inside the
-drm_connector_state structure so far. However, we will need it in other
-structures as well, so let's move that structure definition so that it can
-be reused.
-
-Link: https://patchwork.freedesktop.org/patch/msgid/38b773b03f15ec7a135cdf8f7db669e5ada20cf2.1560783090.git-series.maxime.ripard@bootlin.com
----
- include/drm/drm_connector.h | 41 +++++++++++++++++++++++++++----------
- 1 file changed, 30 insertions(+), 11 deletions(-)
-
---- a/include/drm/drm_connector.h
-+++ b/include/drm/drm_connector.h
-@@ -344,13 +344,37 @@ int drm_display_info_set_bus_formats(str
- unsigned int num_formats);
-
- /**
-+ * struct drm_connector_tv_margins - TV connector related margins
-+ *
-+ * Describes the margins in pixels to put around the image on TV
-+ * connectors to deal with overscan.
-+ */
-+struct drm_connector_tv_margins {
-+ /**
-+ * @bottom: Bottom margin in pixels.
-+ */
-+ unsigned int bottom;
-+
-+ /**
-+ * @left: Left margin in pixels.
-+ */
-+ unsigned int left;
-+
-+ /**
-+ * @right: Right margin in pixels.
-+ */
-+ unsigned int right;
-+
-+ /**
-+ * @top: Top margin in pixels.
-+ */
-+ unsigned int top;
-+};
-+
-+/**
- * struct drm_tv_connector_state - TV connector related states
- * @subconnector: selected subconnector
-- * @margins: margins (all margins are expressed in pixels)
-- * @margins.left: left margin
-- * @margins.right: right margin
-- * @margins.top: top margin
-- * @margins.bottom: bottom margin
-+ * @margins: TV margins
- * @mode: TV mode
- * @brightness: brightness in percent
- * @contrast: contrast in percent
-@@ -361,12 +385,7 @@ int drm_display_info_set_bus_formats(str
- */
- struct drm_tv_connector_state {
- enum drm_mode_subconnector subconnector;
-- struct {
-- unsigned int left;
-- unsigned int right;
-- unsigned int top;
-- unsigned int bottom;
-- } margins;
-+ struct drm_connector_tv_margins margins;
- unsigned int mode;
- unsigned int brightness;
- unsigned int contrast;
+++ /dev/null
-From 99b367ee521e48beae92bea59515dd0f08f2e55b Mon Sep 17 00:00:00 2001
-Date: Wed, 19 Jun 2019 12:17:51 +0200
-Subject: [PATCH] drm/modes: Parse overscan properties
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Commit 3d46a3007cd8f73bae502bf5c171977b91d7aacc upstream.
-
-Properly configuring the overscan properties might be needed for the
-initial setup of the framebuffer for display that still have overscan.
-Let's allow for more properties on the kernel command line to setup each
-margin.
-
-Link: https://patchwork.freedesktop.org/patch/msgid/e481f1628e3768ca49226ec2115cfa4dfcbd5e4c.1560783090.git-series.maxime.ripard@bootlin.com
----
- Documentation/fb/modedb.txt | 2 ++
- drivers/gpu/drm/drm_modes.c | 44 +++++++++++++++++++++++++++++++++++++
- include/drm/drm_connector.h | 5 +++++
- 3 files changed, 51 insertions(+)
-
---- a/Documentation/fb/modedb.txt
-+++ b/Documentation/fb/modedb.txt
-@@ -57,6 +57,8 @@ Options can also be passed after the mod
-
- Valid options are:
-
-+ - margin_top, margin_bottom, margin_left, margin_right (integer):
-+ Number of pixels in the margins, typically to deal with overscan on TVs
- - reflect_x (boolean): Perform an axial symmetry on the X axis
- - reflect_y (boolean): Perform an axial symmetry on the Y axis
- - rotate (integer): Rotate the initial framebuffer by x
---- a/drivers/gpu/drm/drm_modes.c
-+++ b/drivers/gpu/drm/drm_modes.c
-@@ -1615,6 +1615,50 @@ static int drm_mode_parse_cmdline_option
- } else if (!strncmp(option, "reflect_y", delim - option)) {
- rotation |= DRM_MODE_REFLECT_Y;
- sep = delim;
-+ } else if (!strncmp(option, "margin_right", delim - option)) {
-+ const char *value = delim + 1;
-+ unsigned int margin;
-+
-+ margin = simple_strtol(value, &sep, 10);
-+
-+ /* Make sure we have parsed something */
-+ if (sep == value)
-+ return -EINVAL;
-+
-+ mode->tv_margins.right = margin;
-+ } else if (!strncmp(option, "margin_left", delim - option)) {
-+ const char *value = delim + 1;
-+ unsigned int margin;
-+
-+ margin = simple_strtol(value, &sep, 10);
-+
-+ /* Make sure we have parsed something */
-+ if (sep == value)
-+ return -EINVAL;
-+
-+ mode->tv_margins.left = margin;
-+ } else if (!strncmp(option, "margin_top", delim - option)) {
-+ const char *value = delim + 1;
-+ unsigned int margin;
-+
-+ margin = simple_strtol(value, &sep, 10);
-+
-+ /* Make sure we have parsed something */
-+ if (sep == value)
-+ return -EINVAL;
-+
-+ mode->tv_margins.top = margin;
-+ } else if (!strncmp(option, "margin_bottom", delim - option)) {
-+ const char *value = delim + 1;
-+ unsigned int margin;
-+
-+ margin = simple_strtol(value, &sep, 10);
-+
-+ /* Make sure we have parsed something */
-+ if (sep == value)
-+ return -EINVAL;
-+
-+ mode->tv_margins.bottom = margin;
- } else {
- return -EINVAL;
- }
---- a/include/drm/drm_connector.h
-+++ b/include/drm/drm_connector.h
-@@ -886,6 +886,11 @@ struct drm_cmdline_mode {
- * DRM_MODE_ROTATE_0 and DRM_MODE_ROTATE_180.
- */
- unsigned int rotation_reflection;
-+
-+ /**
-+ * @tv_margins: TV margins to apply to the mode.
-+ */
-+ struct drm_connector_tv_margins tv_margins;
- };
-
- /**
--- /dev/null
+From 1adef5f9443f148db0817099504df0a7fb7350dd Mon Sep 17 00:00:00 2001
+Date: Wed, 19 Jun 2019 12:17:53 +0200
+Subject: [PATCH] drm/vc4: hdmi: Set default state margin at reset
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Now that the TV margins are properly parsed and filled into
+drm_cmdline_mode, we just need to initialise the first state at reset to
+get those values and start using them.
+
+Link: https://patchwork.freedesktop.org/patch/msgid/44e24172e300be6a41578517021ef6a6e90ed682.1560783090.git-series.maxime.ripard@bootlin.com
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -292,11 +292,17 @@ static int vc4_hdmi_connector_get_modes(
+ return ret;
+ }
+
++static void vc4_hdmi_connector_reset(struct drm_connector *connector)
++{
++ drm_atomic_helper_connector_reset(connector);
++ drm_atomic_helper_connector_tv_reset(connector);
++}
++
+ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
+ .detect = vc4_hdmi_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = vc4_hdmi_connector_destroy,
+- .reset = drm_atomic_helper_connector_reset,
++ .reset = vc4_hdmi_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ };
+++ /dev/null
-From 8dd1e4d73fdbc4a533a58c2c74a72877257c558c Mon Sep 17 00:00:00 2001
-Date: Wed, 19 Jun 2019 12:17:52 +0200
-Subject: [PATCH] drm/atomic: Add a function to reset connector TV
- properties
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Commit 731514b446fe6748d5a55a3dff202efb45c7d8df upstream.
-Reworked as functions have been moved from drm_atomic_helper.[c|h]
-to drm_atomic_state_helper.[c|h].
-
-During the connector reset, if that connector has a TV property, it needs
-to be reset to the value provided on the command line.
-
-Provide a helper to do that.
-
-Link: https://patchwork.freedesktop.org/patch/msgid/84a7b657f09303a2850e1cc79e68f623547f3fdd.1560783090.git-series.maxime.ripard@bootlin.com
----
- drivers/gpu/drm/drm_atomic_helper.c | 18 ++++++++++++++++++
- include/drm/drm_atomic_helper.h | 1 +
- 2 files changed, 19 insertions(+)
-
---- a/drivers/gpu/drm/drm_atomic_helper.c
-+++ b/drivers/gpu/drm/drm_atomic_helper.c
-@@ -3737,6 +3737,24 @@ void drm_atomic_helper_connector_reset(s
- EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
-
- /**
-+ * drm_atomic_helper_connector_tv_reset - Resets TV connector properties
-+ * @connector: DRM connector
-+ *
-+ * Resets the TV-related properties attached to a connector.
-+ */
-+void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
-+{
-+ struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
-+ struct drm_connector_state *state = connector->state;
-+
-+ state->tv.margins.left = cmdline->tv_margins.left;
-+ state->tv.margins.right = cmdline->tv_margins.right;
-+ state->tv.margins.top = cmdline->tv_margins.top;
-+ state->tv.margins.bottom = cmdline->tv_margins.bottom;
-+}
-+EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
-+
-+/**
- * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
- * @connector: connector object
- * @state: atomic connector state
---- a/include/drm/drm_atomic_helper.h
-+++ b/include/drm/drm_atomic_helper.h
-@@ -168,6 +168,7 @@ void drm_atomic_helper_plane_destroy_sta
- void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
- struct drm_connector_state *conn_state);
- void drm_atomic_helper_connector_reset(struct drm_connector *connector);
-+void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector);
- void
- __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
- struct drm_connector_state *state);
--- /dev/null
+From 2cf6bd979b0a5fdb179842308b1670691f6a2ce4 Mon Sep 17 00:00:00 2001
+Date: Tue, 23 Jul 2019 11:09:26 +0100
+Subject: [PATCH] drm/vc4: fkms: Set default state margin at reset
+
+Now that the TV margins are properly parsed and filled into
+drm_cmdline_mode, we just need to initialise the first state at reset to
+get those values and start using them.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1457,10 +1457,17 @@ int vc4_connector_atomic_set_property(st
+ return -EINVAL;
+ }
+
++static void vc4_hdmi_connector_reset(struct drm_connector *connector)
++{
++ drm_atomic_helper_connector_reset(connector);
++ drm_atomic_helper_connector_tv_reset(connector);
++}
++
+ static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
+ .detect = vc4_fkms_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = vc4_fkms_connector_destroy,
++ .reset = vc4_hdmi_connector_reset,
+ .atomic_duplicate_state = vc4_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .atomic_get_property = vc4_connector_atomic_get_property,
--- /dev/null
+From 6eb9a89c28590203658c0ebcbf29d5b41eb8596a Mon Sep 17 00:00:00 2001
+Date: Tue, 23 Jul 2019 14:10:31 +0100
+Subject: [PATCH] drm/modes: Don't apply cmdline's rotation if it
+ wasn't specified
+
+Taken from the dri-devel mailing list (11/7/2019) to fixup the cmdline
+parsing, but requires changes as things have moved between 4.19 and 5.2.
+
+
+The rotation mode from cmdline shouldn't be taken into account if it
+wasn't specified in the cmdline. This fixes ignored default display
+orientation when display mode is given using cmdline without the
+rotation being specified.
+
+Fixes: 1bf4e09227c3 ("drm/modes: Allow to specify rotation and reflection on the commandline")
+---
+ drivers/gpu/drm/drm_fb_helper.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/drm_fb_helper.c
++++ b/drivers/gpu/drm/drm_fb_helper.c
+@@ -2502,7 +2502,7 @@ static void drm_setup_crtc_rotation(stru
+ * simple XOR between the two handle the addition nicely.
+ */
+ cmdline = &connector->cmdline_mode;
+- if (cmdline->specified) {
++ if (cmdline->specified && cmdline->rotation_reflection) {
+ unsigned int cmdline_rest, panel_rest;
+ unsigned int cmdline_rot, panel_rot;
+ unsigned int sum_rot, sum_rest;
+++ /dev/null
-From 1adef5f9443f148db0817099504df0a7fb7350dd Mon Sep 17 00:00:00 2001
-Date: Wed, 19 Jun 2019 12:17:53 +0200
-Subject: [PATCH] drm/vc4: hdmi: Set default state margin at reset
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Now that the TV margins are properly parsed and filled into
-drm_cmdline_mode, we just need to initialise the first state at reset to
-get those values and start using them.
-
-Link: https://patchwork.freedesktop.org/patch/msgid/44e24172e300be6a41578517021ef6a6e90ed682.1560783090.git-series.maxime.ripard@bootlin.com
----
- drivers/gpu/drm/vc4/vc4_hdmi.c | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_hdmi.c
-+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
-@@ -292,11 +292,17 @@ static int vc4_hdmi_connector_get_modes(
- return ret;
- }
-
-+static void vc4_hdmi_connector_reset(struct drm_connector *connector)
-+{
-+ drm_atomic_helper_connector_reset(connector);
-+ drm_atomic_helper_connector_tv_reset(connector);
-+}
-+
- static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
- .detect = vc4_hdmi_connector_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = vc4_hdmi_connector_destroy,
-- .reset = drm_atomic_helper_connector_reset,
-+ .reset = vc4_hdmi_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
- };
+++ /dev/null
-From 2cf6bd979b0a5fdb179842308b1670691f6a2ce4 Mon Sep 17 00:00:00 2001
-Date: Tue, 23 Jul 2019 11:09:26 +0100
-Subject: [PATCH] drm/vc4: fkms: Set default state margin at reset
-
-Now that the TV margins are properly parsed and filled into
-drm_cmdline_mode, we just need to initialise the first state at reset to
-get those values and start using them.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1457,10 +1457,17 @@ int vc4_connector_atomic_set_property(st
- return -EINVAL;
- }
-
-+static void vc4_hdmi_connector_reset(struct drm_connector *connector)
-+{
-+ drm_atomic_helper_connector_reset(connector);
-+ drm_atomic_helper_connector_tv_reset(connector);
-+}
-+
- static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
- .detect = vc4_fkms_connector_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = vc4_fkms_connector_destroy,
-+ .reset = vc4_hdmi_connector_reset,
- .atomic_duplicate_state = vc4_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
- .atomic_get_property = vc4_connector_atomic_get_property,
--- /dev/null
+From cb053a15c5c23e775647d6b65fef4c378bf34b5b Mon Sep 17 00:00:00 2001
+Date: Thu, 18 Jul 2019 17:07:05 +0800
+Subject: [PATCH] staging: bcm2835-codec: switch to multi-planar API
+
+There are two APIs for mem2mem devices, the older single-planar API and
+the newer multi-planar one. Without making things overly complex, the
+driver can only support one or the other. However the userspace libv4l2
+library has a plugin that allows multi-planar API devices to service
+single-planar consumers.
+
+Chromium supports the multi-planar API exclusively, though this is
+currently limited to ChromiumOS. It would be possible to add support
+for generic Linux.
+
+Switching to the multi-planar API would allow usage of both APIs from
+userspace.
+
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 145 +++++++++---------
+ 1 file changed, 76 insertions(+), 69 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -504,7 +504,7 @@ static struct bcm2835_codec_fmt *find_fo
+
+ for (k = 0; k < fmts->num_entries; k++) {
+ fmt = &fmts->list[k];
+- if (fmt->fourcc == f->fmt.pix.pixelformat)
++ if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
+ break;
+ }
+ if (k == fmts->num_entries)
+@@ -522,9 +522,9 @@ static struct bcm2835_codec_q_data *get_
+ enum v4l2_buf_type type)
+ {
+ switch (type) {
+- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ return &ctx->q_data[V4L2_M2M_SRC];
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ return &ctx->q_data[V4L2_M2M_DST];
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
+@@ -541,9 +541,9 @@ static struct vchiq_mmal_port *get_port_
+ return NULL;
+
+ switch (type) {
+- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ return &ctx->component->input[0];
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ return &ctx->component->output[0];
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
+@@ -752,7 +752,7 @@ static void handle_fmt_changed(struct bc
+ format->es.video.crop.width, format->es.video.crop.height,
+ format->es.video.color_space);
+
+- q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
++ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ q_data->crop_width = format->es.video.crop.width;
+ q_data->crop_height = format->es.video.crop.height;
+ q_data->bytesperline = format->es.video.crop.width;
+@@ -945,7 +945,7 @@ static int vidioc_querycap(struct file *
+ strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ MEM2MEM_NAME);
+- cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
++ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+ }
+@@ -996,16 +996,20 @@ static int vidioc_g_fmt(struct bcm2835_c
+
+ q_data = get_q_data(ctx, f->type);
+
+- f->fmt.pix.width = q_data->crop_width;
+- f->fmt.pix.height = q_data->height;
+- f->fmt.pix.field = V4L2_FIELD_NONE;
+- f->fmt.pix.pixelformat = q_data->fmt->fourcc;
+- f->fmt.pix.bytesperline = q_data->bytesperline;
+- f->fmt.pix.sizeimage = q_data->sizeimage;
+- f->fmt.pix.colorspace = ctx->colorspace;
+- f->fmt.pix.xfer_func = ctx->xfer_func;
+- f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
+- f->fmt.pix.quantization = ctx->quant;
++ f->fmt.pix_mp.width = q_data->crop_width;
++ f->fmt.pix_mp.height = q_data->height;
++ f->fmt.pix_mp.pixelformat = q_data->fmt->fourcc;
++ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
++ f->fmt.pix_mp.colorspace = ctx->colorspace;
++ f->fmt.pix_mp.plane_fmt[0].sizeimage = q_data->sizeimage;
++ f->fmt.pix_mp.plane_fmt[0].bytesperline = q_data->bytesperline;
++ f->fmt.pix_mp.num_planes = 1;
++ f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc;
++ f->fmt.pix_mp.quantization = ctx->quant;
++ f->fmt.pix_mp.xfer_func = ctx->xfer_func;
++
++ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
++ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
+
+ return 0;
+ }
+@@ -1029,17 +1033,17 @@ static int vidioc_try_fmt(struct bcm2835
+ * The V4L2 specification requires the driver to correct the format
+ * struct if any of the dimensions is unsupported
+ */
+- if (f->fmt.pix.width > MAX_W)
+- f->fmt.pix.width = MAX_W;
+- if (f->fmt.pix.height > MAX_H)
+- f->fmt.pix.height = MAX_H;
++ if (f->fmt.pix_mp.width > MAX_W)
++ f->fmt.pix_mp.width = MAX_W;
++ if (f->fmt.pix_mp.height > MAX_H)
++ f->fmt.pix_mp.height = MAX_H;
+
+ if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
+ /* Only clip min w/h on capture. Treat 0x0 as unknown. */
+- if (f->fmt.pix.width < MIN_W)
+- f->fmt.pix.width = MIN_W;
+- if (f->fmt.pix.height < MIN_H)
+- f->fmt.pix.height = MIN_H;
++ if (f->fmt.pix_mp.width < MIN_W)
++ f->fmt.pix_mp.width = MIN_W;
++ if (f->fmt.pix_mp.height < MIN_H)
++ f->fmt.pix_mp.height = MIN_H;
+
+ /*
+ * For codecs the buffer must have a vertical alignment of 16
+@@ -1048,16 +1052,18 @@ static int vidioc_try_fmt(struct bcm2835
+ * some of the pixels are active.
+ */
+ if (ctx->dev->role != ISP)
+- f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
++ f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16);
+ }
+- f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
+- fmt);
+- f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
+- f->fmt.pix.width,
+- f->fmt.pix.height,
+- fmt);
++ f->fmt.pix_mp.num_planes = 1;
++ f->fmt.pix_mp.plane_fmt[0].bytesperline =
++ get_bytesperline(f->fmt.pix_mp.width, fmt);
++ f->fmt.pix_mp.plane_fmt[0].sizeimage =
++ get_sizeimage(f->fmt.pix_mp.plane_fmt[0].bytesperline,
++ f->fmt.pix_mp.width, f->fmt.pix_mp.height, fmt);
++ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
++ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
+
+- f->fmt.pix.field = V4L2_FIELD_NONE;
++ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+
+ return 0;
+ }
+@@ -1070,8 +1076,8 @@ static int vidioc_try_fmt_vid_cap(struct
+
+ fmt = find_format(f, ctx->dev, true);
+ if (!fmt) {
+- f->fmt.pix.pixelformat = get_default_format(ctx->dev,
+- true)->fourcc;
++ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
++ true)->fourcc;
+ fmt = find_format(f, ctx->dev, true);
+ }
+
+@@ -1086,13 +1092,13 @@ static int vidioc_try_fmt_vid_out(struct
+
+ fmt = find_format(f, ctx->dev, false);
+ if (!fmt) {
+- f->fmt.pix.pixelformat = get_default_format(ctx->dev,
+- false)->fourcc;
++ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
++ false)->fourcc;
+ fmt = find_format(f, ctx->dev, false);
+ }
+
+- if (!f->fmt.pix.colorspace)
+- f->fmt.pix.colorspace = ctx->colorspace;
++ if (!f->fmt.pix_mp.colorspace)
++ f->fmt.pix_mp.colorspace = ctx->colorspace;
+
+ return vidioc_try_fmt(ctx, f, fmt);
+ }
+@@ -1106,9 +1112,10 @@ static int vidioc_s_fmt(struct bcm2835_c
+ bool update_capture_port = false;
+ int ret;
+
+- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
+- f->type, f->fmt.pix.width, f->fmt.pix.height,
+- f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
++ f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
++ f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage);
++
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+@@ -1124,9 +1131,9 @@ static int vidioc_s_fmt(struct bcm2835_c
+ }
+
+ q_data->fmt = find_format(f, ctx->dev,
+- f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
+- q_data->crop_width = f->fmt.pix.width;
+- q_data->height = f->fmt.pix.height;
++ f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
++ q_data->crop_width = f->fmt.pix_mp.width;
++ q_data->height = f->fmt.pix_mp.height;
+ if (!q_data->selection_set)
+ q_data->crop_height = requested_height;
+
+@@ -1134,21 +1141,21 @@ static int vidioc_s_fmt(struct bcm2835_c
+ * Copying the behaviour of vicodec which retains a single set of
+ * colorspace parameters for both input and output.
+ */
+- ctx->colorspace = f->fmt.pix.colorspace;
+- ctx->xfer_func = f->fmt.pix.xfer_func;
+- ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
+- ctx->quant = f->fmt.pix.quantization;
++ ctx->colorspace = f->fmt.pix_mp.colorspace;
++ ctx->xfer_func = f->fmt.pix_mp.xfer_func;
++ ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
++ ctx->quant = f->fmt.pix_mp.quantization;
+
+ /* All parameters should have been set correctly by try_fmt */
+- q_data->bytesperline = f->fmt.pix.bytesperline;
+- q_data->sizeimage = f->fmt.pix.sizeimage;
++ 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",
+ q_data->bytesperline, q_data->sizeimage);
+
+ if (ctx->dev->role == DECODE &&
+ q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
+- f->fmt.pix.width && f->fmt.pix.height) {
++ q_data->crop_width && q_data->height) {
+ /*
+ * On the decoder, if provided with a resolution on the input
+ * side, then replicate that to the output side.
+@@ -1165,7 +1172,7 @@ static int vidioc_s_fmt(struct bcm2835_c
+ q_data_dst->height = ALIGN(q_data->crop_height, 16);
+
+ q_data_dst->bytesperline =
+- get_bytesperline(f->fmt.pix.width, q_data_dst->fmt);
++ get_bytesperline(f->fmt.pix_mp.width, q_data_dst->fmt);
+ q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline,
+ q_data_dst->crop_width,
+ q_data_dst->height,
+@@ -1215,7 +1222,7 @@ static int vidioc_s_fmt(struct bcm2835_c
+ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+ {
+- unsigned int height = f->fmt.pix.height;
++ unsigned int height = f->fmt.pix_mp.height;
+ int ret;
+
+ ret = vidioc_try_fmt_vid_cap(file, priv, f);
+@@ -1228,7 +1235,7 @@ static int vidioc_s_fmt_vid_cap(struct f
+ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+ {
+- unsigned int height = f->fmt.pix.height;
++ unsigned int height = f->fmt.pix_mp.height;
+ int ret;
+
+ ret = vidioc_try_fmt_vid_out(file, priv, f);
+@@ -1244,7 +1251,7 @@ static int vidioc_g_selection(struct fil
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+ struct bcm2835_codec_q_data *q_data;
+- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
++ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
+ true : false;
+
+ if ((ctx->dev->role == DECODE && !capture_queue) ||
+@@ -1307,7 +1314,7 @@ static int vidioc_s_selection(struct fil
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+ struct bcm2835_codec_q_data *q_data = NULL;
+- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
++ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
+ true : false;
+
+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
+@@ -1368,7 +1375,7 @@ static int vidioc_s_parm(struct file *fi
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+
+- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+
+ ctx->framerate_num =
+@@ -1738,15 +1745,15 @@ static int vidioc_encoder_cmd(struct fil
+ static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+
+- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+-
+- .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+- .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
+- .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
+- .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
++ .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
++ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap,
++ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap,
++ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap,
++
++ .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
++ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out,
++ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out,
++ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+@@ -2089,7 +2096,7 @@ static int bcm2835_codec_start_streaming
+ ctx->component_enabled = true;
+ }
+
+- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ /*
+ * Create the EOS buffer.
+ * We only need the MMAL part, and want to NOT attach a memory
+@@ -2216,7 +2223,7 @@ static int queue_init(void *priv, struct
+ struct bcm2835_codec_ctx *ctx = priv;
+ int ret;
+
+- src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
+@@ -2230,7 +2237,7 @@ static int queue_init(void *priv, struct
+ if (ret)
+ return ret;
+
+- dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
+++ /dev/null
-From 6eb9a89c28590203658c0ebcbf29d5b41eb8596a Mon Sep 17 00:00:00 2001
-Date: Tue, 23 Jul 2019 14:10:31 +0100
-Subject: [PATCH] drm/modes: Don't apply cmdline's rotation if it
- wasn't specified
-
-Taken from the dri-devel mailing list (11/7/2019) to fixup the cmdline
-parsing, but requires changes as things have moved between 4.19 and 5.2.
-
-
-The rotation mode from cmdline shouldn't be taken into account if it
-wasn't specified in the cmdline. This fixes ignored default display
-orientation when display mode is given using cmdline without the
-rotation being specified.
-
-Fixes: 1bf4e09227c3 ("drm/modes: Allow to specify rotation and reflection on the commandline")
----
- drivers/gpu/drm/drm_fb_helper.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/drm_fb_helper.c
-+++ b/drivers/gpu/drm/drm_fb_helper.c
-@@ -2502,7 +2502,7 @@ static void drm_setup_crtc_rotation(stru
- * simple XOR between the two handle the addition nicely.
- */
- cmdline = &connector->cmdline_mode;
-- if (cmdline->specified) {
-+ if (cmdline->specified && cmdline->rotation_reflection) {
- unsigned int cmdline_rest, panel_rest;
- unsigned int cmdline_rot, panel_rot;
- unsigned int sum_rot, sum_rest;
--- /dev/null
+From 1f524b04b040978e2d96380ff40c3e80feba49a5 Mon Sep 17 00:00:00 2001
+Date: Mon, 22 Jul 2019 22:13:30 +0800
+Subject: [PATCH] staging: bcm2835-codec: implement
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
+
+The stateful decoder specification shows an optional step for retrieving
+the miminum number of capture buffers required for the decoder to
+proceed. While not a required parameter, having it makes some
+applications happy.
+
+bcm2835-codec is a little different from other decoder implementations
+in that there is an intermediate format conversion between the hardware
+and V4L2 buffers. The number of capture buffers required is therefore
+independent of the stream and DPB etc.
+
+There are plans to remove the conversion, but it requires a fair amount
+of rework within the firmware. Until that is done, simply return a value
+of 1.
+
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -2357,6 +2357,18 @@ static int bcm2835_codec_open(struct fil
+ }
+ ctx->fh.ctrl_handler = hdl;
+ v4l2_ctrl_handler_setup(hdl);
++ } else if (dev->role == DECODE) {
++ v4l2_ctrl_handler_init(hdl, 1);
++
++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
++ 1, 1, 1, 1);
++ if (hdl->error) {
++ rc = hdl->error;
++ goto free_ctrl_handler;
++ }
++ ctx->fh.ctrl_handler = hdl;
++ v4l2_ctrl_handler_setup(hdl);
+ }
+
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
--- /dev/null
+From c369e173f9ff254ed3c3b9062e04917122e3536e Mon Sep 17 00:00:00 2001
+Date: Mon, 22 Jul 2019 22:20:55 +0800
+Subject: [PATCH] staging: bcm2835-codec: set device_caps in struct
+ video_device
+
+Instead of filling in the struct v4l2_capability device_caps
+field, fill in the struct video_device device_caps field.
+
+That way the V4L2 core knows what the capabilities of the
+video device are.
+
+This is similar to a cleanup series by Hans Verkuil [1].
+
+[1] https://www.spinics.net/lists/linux-media/msg153313.html
+
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -945,8 +945,6 @@ static int vidioc_querycap(struct file *
+ strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ MEM2MEM_NAME);
+- cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+ }
+
+@@ -2600,6 +2598,7 @@ static int bcm2835_codec_create(struct p
+ vfd = &dev->vfd;
+ vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
++ vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+
+ switch (role) {
+ case DECODE:
+++ /dev/null
-From cb053a15c5c23e775647d6b65fef4c378bf34b5b Mon Sep 17 00:00:00 2001
-Date: Thu, 18 Jul 2019 17:07:05 +0800
-Subject: [PATCH] staging: bcm2835-codec: switch to multi-planar API
-
-There are two APIs for mem2mem devices, the older single-planar API and
-the newer multi-planar one. Without making things overly complex, the
-driver can only support one or the other. However the userspace libv4l2
-library has a plugin that allows multi-planar API devices to service
-single-planar consumers.
-
-Chromium supports the multi-planar API exclusively, though this is
-currently limited to ChromiumOS. It would be possible to add support
-for generic Linux.
-
-Switching to the multi-planar API would allow usage of both APIs from
-userspace.
-
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 145 +++++++++---------
- 1 file changed, 76 insertions(+), 69 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -504,7 +504,7 @@ static struct bcm2835_codec_fmt *find_fo
-
- for (k = 0; k < fmts->num_entries; k++) {
- fmt = &fmts->list[k];
-- if (fmt->fourcc == f->fmt.pix.pixelformat)
-+ if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
- break;
- }
- if (k == fmts->num_entries)
-@@ -522,9 +522,9 @@ static struct bcm2835_codec_q_data *get_
- enum v4l2_buf_type type)
- {
- switch (type) {
-- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- return &ctx->q_data[V4L2_M2M_SRC];
-- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- return &ctx->q_data[V4L2_M2M_DST];
- default:
- v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
-@@ -541,9 +541,9 @@ static struct vchiq_mmal_port *get_port_
- return NULL;
-
- switch (type) {
-- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- return &ctx->component->input[0];
-- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- return &ctx->component->output[0];
- default:
- v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
-@@ -752,7 +752,7 @@ static void handle_fmt_changed(struct bc
- format->es.video.crop.width, format->es.video.crop.height,
- format->es.video.color_space);
-
-- q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
- q_data->crop_width = format->es.video.crop.width;
- q_data->crop_height = format->es.video.crop.height;
- q_data->bytesperline = format->es.video.crop.width;
-@@ -945,7 +945,7 @@ static int vidioc_querycap(struct file *
- strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
- MEM2MEM_NAME);
-- cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
-+ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- return 0;
- }
-@@ -996,16 +996,20 @@ static int vidioc_g_fmt(struct bcm2835_c
-
- q_data = get_q_data(ctx, f->type);
-
-- f->fmt.pix.width = q_data->crop_width;
-- f->fmt.pix.height = q_data->height;
-- f->fmt.pix.field = V4L2_FIELD_NONE;
-- f->fmt.pix.pixelformat = q_data->fmt->fourcc;
-- f->fmt.pix.bytesperline = q_data->bytesperline;
-- f->fmt.pix.sizeimage = q_data->sizeimage;
-- f->fmt.pix.colorspace = ctx->colorspace;
-- f->fmt.pix.xfer_func = ctx->xfer_func;
-- f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
-- f->fmt.pix.quantization = ctx->quant;
-+ f->fmt.pix_mp.width = q_data->crop_width;
-+ f->fmt.pix_mp.height = q_data->height;
-+ f->fmt.pix_mp.pixelformat = q_data->fmt->fourcc;
-+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
-+ f->fmt.pix_mp.colorspace = ctx->colorspace;
-+ f->fmt.pix_mp.plane_fmt[0].sizeimage = q_data->sizeimage;
-+ f->fmt.pix_mp.plane_fmt[0].bytesperline = q_data->bytesperline;
-+ f->fmt.pix_mp.num_planes = 1;
-+ f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc;
-+ f->fmt.pix_mp.quantization = ctx->quant;
-+ f->fmt.pix_mp.xfer_func = ctx->xfer_func;
-+
-+ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
-+ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
-
- return 0;
- }
-@@ -1029,17 +1033,17 @@ static int vidioc_try_fmt(struct bcm2835
- * The V4L2 specification requires the driver to correct the format
- * struct if any of the dimensions is unsupported
- */
-- if (f->fmt.pix.width > MAX_W)
-- f->fmt.pix.width = MAX_W;
-- if (f->fmt.pix.height > MAX_H)
-- f->fmt.pix.height = MAX_H;
-+ if (f->fmt.pix_mp.width > MAX_W)
-+ f->fmt.pix_mp.width = MAX_W;
-+ if (f->fmt.pix_mp.height > MAX_H)
-+ f->fmt.pix_mp.height = MAX_H;
-
- if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
- /* Only clip min w/h on capture. Treat 0x0 as unknown. */
-- if (f->fmt.pix.width < MIN_W)
-- f->fmt.pix.width = MIN_W;
-- if (f->fmt.pix.height < MIN_H)
-- f->fmt.pix.height = MIN_H;
-+ if (f->fmt.pix_mp.width < MIN_W)
-+ f->fmt.pix_mp.width = MIN_W;
-+ if (f->fmt.pix_mp.height < MIN_H)
-+ f->fmt.pix_mp.height = MIN_H;
-
- /*
- * For codecs the buffer must have a vertical alignment of 16
-@@ -1048,16 +1052,18 @@ static int vidioc_try_fmt(struct bcm2835
- * some of the pixels are active.
- */
- if (ctx->dev->role != ISP)
-- f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
-+ f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16);
- }
-- f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
-- fmt);
-- f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
-- f->fmt.pix.width,
-- f->fmt.pix.height,
-- fmt);
-+ f->fmt.pix_mp.num_planes = 1;
-+ f->fmt.pix_mp.plane_fmt[0].bytesperline =
-+ get_bytesperline(f->fmt.pix_mp.width, fmt);
-+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
-+ get_sizeimage(f->fmt.pix_mp.plane_fmt[0].bytesperline,
-+ f->fmt.pix_mp.width, f->fmt.pix_mp.height, fmt);
-+ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
-+ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
-
-- f->fmt.pix.field = V4L2_FIELD_NONE;
-+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
-
- return 0;
- }
-@@ -1070,8 +1076,8 @@ static int vidioc_try_fmt_vid_cap(struct
-
- fmt = find_format(f, ctx->dev, true);
- if (!fmt) {
-- f->fmt.pix.pixelformat = get_default_format(ctx->dev,
-- true)->fourcc;
-+ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
-+ true)->fourcc;
- fmt = find_format(f, ctx->dev, true);
- }
-
-@@ -1086,13 +1092,13 @@ static int vidioc_try_fmt_vid_out(struct
-
- fmt = find_format(f, ctx->dev, false);
- if (!fmt) {
-- f->fmt.pix.pixelformat = get_default_format(ctx->dev,
-- false)->fourcc;
-+ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
-+ false)->fourcc;
- fmt = find_format(f, ctx->dev, false);
- }
-
-- if (!f->fmt.pix.colorspace)
-- f->fmt.pix.colorspace = ctx->colorspace;
-+ if (!f->fmt.pix_mp.colorspace)
-+ f->fmt.pix_mp.colorspace = ctx->colorspace;
-
- return vidioc_try_fmt(ctx, f, fmt);
- }
-@@ -1106,9 +1112,10 @@ static int vidioc_s_fmt(struct bcm2835_c
- bool update_capture_port = false;
- int ret;
-
-- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
-- f->type, f->fmt.pix.width, f->fmt.pix.height,
-- f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
-+ f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
-+ f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage);
-+
-
- vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
- if (!vq)
-@@ -1124,9 +1131,9 @@ static int vidioc_s_fmt(struct bcm2835_c
- }
-
- q_data->fmt = find_format(f, ctx->dev,
-- f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
-- q_data->crop_width = f->fmt.pix.width;
-- q_data->height = f->fmt.pix.height;
-+ f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-+ q_data->crop_width = f->fmt.pix_mp.width;
-+ q_data->height = f->fmt.pix_mp.height;
- if (!q_data->selection_set)
- q_data->crop_height = requested_height;
-
-@@ -1134,21 +1141,21 @@ static int vidioc_s_fmt(struct bcm2835_c
- * Copying the behaviour of vicodec which retains a single set of
- * colorspace parameters for both input and output.
- */
-- ctx->colorspace = f->fmt.pix.colorspace;
-- ctx->xfer_func = f->fmt.pix.xfer_func;
-- ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
-- ctx->quant = f->fmt.pix.quantization;
-+ ctx->colorspace = f->fmt.pix_mp.colorspace;
-+ ctx->xfer_func = f->fmt.pix_mp.xfer_func;
-+ ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
-+ ctx->quant = f->fmt.pix_mp.quantization;
-
- /* All parameters should have been set correctly by try_fmt */
-- q_data->bytesperline = f->fmt.pix.bytesperline;
-- q_data->sizeimage = f->fmt.pix.sizeimage;
-+ 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",
- q_data->bytesperline, q_data->sizeimage);
-
- if (ctx->dev->role == DECODE &&
- q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
-- f->fmt.pix.width && f->fmt.pix.height) {
-+ q_data->crop_width && q_data->height) {
- /*
- * On the decoder, if provided with a resolution on the input
- * side, then replicate that to the output side.
-@@ -1165,7 +1172,7 @@ static int vidioc_s_fmt(struct bcm2835_c
- q_data_dst->height = ALIGN(q_data->crop_height, 16);
-
- q_data_dst->bytesperline =
-- get_bytesperline(f->fmt.pix.width, q_data_dst->fmt);
-+ get_bytesperline(f->fmt.pix_mp.width, q_data_dst->fmt);
- q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline,
- q_data_dst->crop_width,
- q_data_dst->height,
-@@ -1215,7 +1222,7 @@ static int vidioc_s_fmt(struct bcm2835_c
- static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
- {
-- unsigned int height = f->fmt.pix.height;
-+ unsigned int height = f->fmt.pix_mp.height;
- int ret;
-
- ret = vidioc_try_fmt_vid_cap(file, priv, f);
-@@ -1228,7 +1235,7 @@ static int vidioc_s_fmt_vid_cap(struct f
- static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *f)
- {
-- unsigned int height = f->fmt.pix.height;
-+ unsigned int height = f->fmt.pix_mp.height;
- int ret;
-
- ret = vidioc_try_fmt_vid_out(file, priv, f);
-@@ -1244,7 +1251,7 @@ static int vidioc_g_selection(struct fil
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
- struct bcm2835_codec_q_data *q_data;
-- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
-+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
- true : false;
-
- if ((ctx->dev->role == DECODE && !capture_queue) ||
-@@ -1307,7 +1314,7 @@ static int vidioc_s_selection(struct fil
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
- struct bcm2835_codec_q_data *q_data = NULL;
-- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
-+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
- true : false;
-
- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
-@@ -1368,7 +1375,7 @@ static int vidioc_s_parm(struct file *fi
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
-
-- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return -EINVAL;
-
- ctx->framerate_num =
-@@ -1738,15 +1745,15 @@ static int vidioc_encoder_cmd(struct fil
- static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
-
-- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
-- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
--
-- .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
-- .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
-- .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
-- .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
-+ .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
-+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap,
-+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap,
-+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap,
-+
-+ .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
-+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out,
-+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out,
-+ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out,
-
- .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
- .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
-@@ -2089,7 +2096,7 @@ static int bcm2835_codec_start_streaming
- ctx->component_enabled = true;
- }
-
-- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- /*
- * Create the EOS buffer.
- * We only need the MMAL part, and want to NOT attach a memory
-@@ -2216,7 +2223,7 @@ static int queue_init(void *priv, struct
- struct bcm2835_codec_ctx *ctx = priv;
- int ret;
-
-- src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
- src_vq->drv_priv = ctx;
- src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
-@@ -2230,7 +2237,7 @@ static int queue_init(void *priv, struct
- if (ret)
- return ret;
-
-- dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
- dst_vq->drv_priv = ctx;
- dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
--- /dev/null
+From 0a37470a112260ef1c9a016a400fdf1f8792eadc Mon Sep 17 00:00:00 2001
+Date: Tue, 16 Jul 2019 12:18:21 +0100
+Subject: [PATCH] Add HDMI1 facility to the driver.
+
+For generic ALSA, all you need is the bcm2835.h change, but
+have also added structures for IEC958 HDMI. Not sure how to
+test those.
+---
+ .../vc04_services/bcm2835-audio/bcm2835.c | 29 ++++++++++++++++---
+ .../vc04_services/bcm2835-audio/bcm2835.h | 4 ++-
+ 2 files changed, 28 insertions(+), 5 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -79,7 +79,11 @@ static int bcm2835_audio_alsa_newpcm(str
+ if (err)
+ return err;
+
+- err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true);
++ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, AUDIO_DEST_HDMI0, 1, true);
++ if (err)
++ return err;
++
++ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI1", 2, AUDIO_DEST_HDMI1, 1, true);
+ if (err)
+ return err;
+
+@@ -106,7 +110,7 @@ static struct bcm2835_audio_driver bcm28
+ .newctl = snd_bcm2835_new_ctl,
+ };
+
+-static struct bcm2835_audio_driver bcm2835_audio_hdmi = {
++static struct bcm2835_audio_driver bcm2835_audio_hdmi0 = {
+ .driver = {
+ .name = "bcm2835_hdmi",
+ .owner = THIS_MODULE,
+@@ -116,7 +120,20 @@ static struct bcm2835_audio_driver bcm28
+ .minchannels = 1,
+ .newpcm = bcm2835_audio_simple_newpcm,
+ .newctl = snd_bcm2835_new_hdmi_ctl,
+- .route = AUDIO_DEST_HDMI
++ .route = AUDIO_DEST_HDMI0
++};
++
++static struct bcm2835_audio_driver bcm2835_audio_hdmi1 = {
++ .driver = {
++ .name = "bcm2835_hdmi",
++ .owner = THIS_MODULE,
++ },
++ .shortname = "bcm2835 HDMI 1",
++ .longname = "bcm2835 HDMI 1",
++ .minchannels = 1,
++ .newpcm = bcm2835_audio_simple_newpcm,
++ .newctl = snd_bcm2835_new_hdmi_ctl,
++ .route = AUDIO_DEST_HDMI1
+ };
+
+ static struct bcm2835_audio_driver bcm2835_audio_headphones = {
+@@ -143,7 +160,11 @@ static struct bcm2835_audio_drivers chil
+ .is_enabled = &enable_compat_alsa,
+ },
+ {
+- .audio_driver = &bcm2835_audio_hdmi,
++ .audio_driver = &bcm2835_audio_hdmi0,
++ .is_enabled = &enable_hdmi,
++ },
++ {
++ .audio_driver = &bcm2835_audio_hdmi1,
+ .is_enabled = &enable_hdmi,
+ },
+ {
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -33,7 +33,9 @@ enum {
+ enum snd_bcm2835_route {
+ AUDIO_DEST_AUTO = 0,
+ AUDIO_DEST_HEADPHONES = 1,
+- AUDIO_DEST_HDMI = 2,
++ AUDIO_DEST_HDMI = 2, // for backwards compatibility.
++ AUDIO_DEST_HDMI0 = 2,
++ AUDIO_DEST_HDMI1 = 3,
+ AUDIO_DEST_MAX,
+ };
+
+++ /dev/null
-From 1f524b04b040978e2d96380ff40c3e80feba49a5 Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Jul 2019 22:13:30 +0800
-Subject: [PATCH] staging: bcm2835-codec: implement
- V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
-
-The stateful decoder specification shows an optional step for retrieving
-the miminum number of capture buffers required for the decoder to
-proceed. While not a required parameter, having it makes some
-applications happy.
-
-bcm2835-codec is a little different from other decoder implementations
-in that there is an intermediate format conversion between the hardware
-and V4L2 buffers. The number of capture buffers required is therefore
-independent of the stream and DPB etc.
-
-There are plans to remove the conversion, but it requires a fair amount
-of rework within the firmware. Until that is done, simply return a value
-of 1.
-
----
- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -2357,6 +2357,18 @@ static int bcm2835_codec_open(struct fil
- }
- ctx->fh.ctrl_handler = hdl;
- v4l2_ctrl_handler_setup(hdl);
-+ } else if (dev->role == DECODE) {
-+ v4l2_ctrl_handler_init(hdl, 1);
-+
-+ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
-+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
-+ 1, 1, 1, 1);
-+ if (hdl->error) {
-+ rc = hdl->error;
-+ goto free_ctrl_handler;
-+ }
-+ ctx->fh.ctrl_handler = hdl;
-+ v4l2_ctrl_handler_setup(hdl);
- }
-
- ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
--- /dev/null
+From 114845b6010b6e6a320804f2d86ab4d5dc5a06de Mon Sep 17 00:00:00 2001
+Date: Mon, 5 Aug 2019 14:17:14 +0100
+Subject: [PATCH] overlays: Add baudrate parameter to i2c3-i2c6
+
+The overlays for enabling the new BCM2711 I2C interfaces were lacking
+the means to configure the baud/clock rate.
+
+Also explictly set the default pins, rather than relying on the values
+in the base DTB.
+
+---
+ arch/arm/boot/dts/overlays/README | 8 ++++++++
+ arch/arm/boot/dts/overlays/i2c3-overlay.dts | 15 ++++++++++++---
+ arch/arm/boot/dts/overlays/i2c4-overlay.dts | 15 ++++++++++++---
+ arch/arm/boot/dts/overlays/i2c5-overlay.dts | 15 ++++++++++++---
+ arch/arm/boot/dts/overlays/i2c6-overlay.dts | 15 ++++++++++++---
+ 5 files changed, 56 insertions(+), 12 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1221,6 +1221,8 @@ Info: Enable the i2c3 bus
+ Load: dtoverlay=i2c3,<param>
+ Params: pins_2_3 Use GPIOs 2 and 3
+ pins_4_5 Use GPIOs 4 and 5 (default)
++ baudrate Set the baudrate for the interface (default
++ "100000")
+
+
+ Name: i2c4
+@@ -1228,6 +1230,8 @@ Info: Enable the i2c4 bus
+ Load: dtoverlay=i2c4,<param>
+ Params: pins_6_7 Use GPIOs 6 and 7
+ pins_8_9 Use GPIOs 8 and 9 (default)
++ baudrate Set the baudrate for the interface (default
++ "100000")
+
+
+ Name: i2c5
+@@ -1235,6 +1239,8 @@ Info: Enable the i2c5 bus
+ Load: dtoverlay=i2c5,<param>
+ Params: pins_10_11 Use GPIOs 10 and 11
+ pins_12_13 Use GPIOs 12 and 13 (default)
++ baudrate Set the baudrate for the interface (default
++ "100000")
+
+
+ Name: i2c6
+@@ -1242,6 +1248,8 @@ Info: Enable the i2c6 bus
+ Load: dtoverlay=i2c6,<param>
+ Params: pins_0_1 Use GPIOs 0 and 1
+ pins_22_23 Use GPIOs 22 and 23 (default)
++ baudrate Set the baudrate for the interface (default
++ "100000")
+
+
+ Name: i2s-gpio28-31
+--- a/arch/arm/boot/dts/overlays/i2c3-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c3-overlay.dts
+@@ -6,10 +6,11 @@
+
+ fragment@0 {
+ target = <&i2c3>;
+- __overlay__ {
++ frag0: __overlay__ {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c3_pins>;
++ clock-frequency = <100000>;
+ };
+ };
+
+@@ -20,8 +21,16 @@
+ };
+ };
+
++ fragment@2 {
++ target = <&i2c3_pins>;
++ __overlay__ {
++ brcm,pins = <4 5>;
++ };
++ };
++
+ __overrides__ {
+- pins_2_3 = <0>,"=1";
+- pins_4_5 = <0>,"!1";
++ pins_2_3 = <0>,"=1!2";
++ pins_4_5 = <0>,"!1=2";
++ baudrate = <&frag0>, "clock-frequency:0";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/i2c4-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c4-overlay.dts
+@@ -6,10 +6,11 @@
+
+ fragment@0 {
+ target = <&i2c4>;
+- __overlay__ {
++ frag0: __overlay__ {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_pins>;
++ clock-frequency = <100000>;
+ };
+ };
+
+@@ -20,8 +21,16 @@
+ };
+ };
+
++ fragment@2 {
++ target = <&i2c4_pins>;
++ __overlay__ {
++ brcm,pins = <8 9>;
++ };
++ };
++
+ __overrides__ {
+- pins_6_7 = <0>,"=1";
+- pins_8_9 = <0>,"!1";
++ pins_6_7 = <0>,"=1!2";
++ pins_8_9 = <0>,"!1=2";
++ baudrate = <&frag0>, "clock-frequency:0";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/i2c5-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c5-overlay.dts
+@@ -6,10 +6,11 @@
+
+ fragment@0 {
+ target = <&i2c5>;
+- __overlay__ {
++ frag0: __overlay__ {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c5_pins>;
++ clock-frequency = <100000>;
+ };
+ };
+
+@@ -20,8 +21,16 @@
+ };
+ };
+
++ fragment@2 {
++ target = <&i2c5_pins>;
++ __overlay__ {
++ brcm,pins = <12 13>;
++ };
++ };
++
+ __overrides__ {
+- pins_10_11 = <0>,"=1";
+- pins_12_13 = <0>,"!1";
++ pins_10_11 = <0>,"=1!2";
++ pins_12_13 = <0>,"!1=2";
++ baudrate = <&frag0>, "clock-frequency:0";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/i2c6-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c6-overlay.dts
+@@ -6,10 +6,11 @@
+
+ fragment@0 {
+ target = <&i2c6>;
+- __overlay__ {
++ frag0: __overlay__ {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c6_pins>;
++ clock-frequency = <100000>;
+ };
+ };
+
+@@ -20,8 +21,16 @@
+ };
+ };
+
++ fragment@2 {
++ target = <&i2c6_pins>;
++ __overlay__ {
++ brcm,pins = <22 23>;
++ };
++ };
++
+ __overrides__ {
+- pins_0_1 = <0>,"=1";
+- pins_22_23 = <0>,"!1";
++ pins_0_1 = <0>,"=1!2";
++ pins_22_23 = <0>,"!1=2";
++ baudrate = <&frag0>, "clock-frequency:0";
+ };
+ };
+++ /dev/null
-From c369e173f9ff254ed3c3b9062e04917122e3536e Mon Sep 17 00:00:00 2001
-Date: Mon, 22 Jul 2019 22:20:55 +0800
-Subject: [PATCH] staging: bcm2835-codec: set device_caps in struct
- video_device
-
-Instead of filling in the struct v4l2_capability device_caps
-field, fill in the struct video_device device_caps field.
-
-That way the V4L2 core knows what the capabilities of the
-video device are.
-
-This is similar to a cleanup series by Hans Verkuil [1].
-
-[1] https://www.spinics.net/lists/linux-media/msg153313.html
-
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -945,8 +945,6 @@ static int vidioc_querycap(struct file *
- strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
- MEM2MEM_NAME);
-- cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
-- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- return 0;
- }
-
-@@ -2600,6 +2598,7 @@ static int bcm2835_codec_create(struct p
- vfd = &dev->vfd;
- vfd->lock = &dev->dev_mutex;
- vfd->v4l2_dev = &dev->v4l2_dev;
-+ vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
-
- switch (role) {
- case DECODE:
+++ /dev/null
-From 0a37470a112260ef1c9a016a400fdf1f8792eadc Mon Sep 17 00:00:00 2001
-Date: Tue, 16 Jul 2019 12:18:21 +0100
-Subject: [PATCH] Add HDMI1 facility to the driver.
-
-For generic ALSA, all you need is the bcm2835.h change, but
-have also added structures for IEC958 HDMI. Not sure how to
-test those.
----
- .../vc04_services/bcm2835-audio/bcm2835.c | 29 ++++++++++++++++---
- .../vc04_services/bcm2835-audio/bcm2835.h | 4 ++-
- 2 files changed, 28 insertions(+), 5 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -79,7 +79,11 @@ static int bcm2835_audio_alsa_newpcm(str
- if (err)
- return err;
-
-- err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true);
-+ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, AUDIO_DEST_HDMI0, 1, true);
-+ if (err)
-+ return err;
-+
-+ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI1", 2, AUDIO_DEST_HDMI1, 1, true);
- if (err)
- return err;
-
-@@ -106,7 +110,7 @@ static struct bcm2835_audio_driver bcm28
- .newctl = snd_bcm2835_new_ctl,
- };
-
--static struct bcm2835_audio_driver bcm2835_audio_hdmi = {
-+static struct bcm2835_audio_driver bcm2835_audio_hdmi0 = {
- .driver = {
- .name = "bcm2835_hdmi",
- .owner = THIS_MODULE,
-@@ -116,7 +120,20 @@ static struct bcm2835_audio_driver bcm28
- .minchannels = 1,
- .newpcm = bcm2835_audio_simple_newpcm,
- .newctl = snd_bcm2835_new_hdmi_ctl,
-- .route = AUDIO_DEST_HDMI
-+ .route = AUDIO_DEST_HDMI0
-+};
-+
-+static struct bcm2835_audio_driver bcm2835_audio_hdmi1 = {
-+ .driver = {
-+ .name = "bcm2835_hdmi",
-+ .owner = THIS_MODULE,
-+ },
-+ .shortname = "bcm2835 HDMI 1",
-+ .longname = "bcm2835 HDMI 1",
-+ .minchannels = 1,
-+ .newpcm = bcm2835_audio_simple_newpcm,
-+ .newctl = snd_bcm2835_new_hdmi_ctl,
-+ .route = AUDIO_DEST_HDMI1
- };
-
- static struct bcm2835_audio_driver bcm2835_audio_headphones = {
-@@ -143,7 +160,11 @@ static struct bcm2835_audio_drivers chil
- .is_enabled = &enable_compat_alsa,
- },
- {
-- .audio_driver = &bcm2835_audio_hdmi,
-+ .audio_driver = &bcm2835_audio_hdmi0,
-+ .is_enabled = &enable_hdmi,
-+ },
-+ {
-+ .audio_driver = &bcm2835_audio_hdmi1,
- .is_enabled = &enable_hdmi,
- },
- {
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -33,7 +33,9 @@ enum {
- enum snd_bcm2835_route {
- AUDIO_DEST_AUTO = 0,
- AUDIO_DEST_HEADPHONES = 1,
-- AUDIO_DEST_HDMI = 2,
-+ AUDIO_DEST_HDMI = 2, // for backwards compatibility.
-+ AUDIO_DEST_HDMI0 = 2,
-+ AUDIO_DEST_HDMI1 = 3,
- AUDIO_DEST_MAX,
- };
-
--- /dev/null
+From df276f0a5aa865c7926d9d148605d1a59d1d4fbb Mon Sep 17 00:00:00 2001
+Date: Thu, 25 Jul 2019 17:27:44 +0100
+Subject: [PATCH] drm/vc4: Resolve the vblank warnings on mode
+ switching
+
+The details over when and how a driver is to service the
+vblank events are sketchy, and the fkms driver was triggering
+a kernel warning every time the crtc was enabled or disabled.
+
+Copy the event handling as used by the vc4-kms driver slightly
+more closely, and we avoid the warnings.
+
+https://github.com/raspberrypi/linux/issues/3020
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++--------
+ 1 file changed, 33 insertions(+), 15 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -933,6 +933,7 @@ static void vc4_crtc_mode_set_nofb(struc
+
+ static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
++ struct drm_device *dev = crtc->dev;
+ struct drm_plane *plane;
+
+ DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
+@@ -948,6 +949,35 @@ static void vc4_crtc_disable(struct drm_
+
+ drm_atomic_crtc_for_each_plane(plane, crtc)
+ vc4_plane_atomic_disable(plane, plane->state);
++
++ /*
++ * Make sure we issue a vblank event after disabling the CRTC if
++ * someone was waiting it.
++ */
++ if (crtc->state->event) {
++ unsigned long flags;
++
++ spin_lock_irqsave(&dev->event_lock, flags);
++ drm_crtc_send_vblank_event(crtc, crtc->state->event);
++ crtc->state->event = NULL;
++ spin_unlock_irqrestore(&dev->event_lock, flags);
++ }
++}
++
++static void vc4_crtc_consume_event(struct drm_crtc *crtc)
++{
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++ struct drm_device *dev = crtc->dev;
++ unsigned long flags;
++
++ crtc->state->event->pipe = drm_crtc_index(crtc);
++
++ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
++
++ spin_lock_irqsave(&dev->event_lock, flags);
++ vc4_crtc->event = crtc->state->event;
++ crtc->state->event = NULL;
++ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
+
+ static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+@@ -957,6 +987,7 @@ static void vc4_crtc_enable(struct drm_c
+ DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
+ crtc->base.id);
+ drm_crtc_vblank_on(crtc);
++ vc4_crtc_consume_event(crtc);
+
+ /* Unblank the planes (if they're supposed to be displayed). */
+ drm_atomic_crtc_for_each_plane(plane, crtc)
+@@ -1028,23 +1059,10 @@ static int vc4_crtc_atomic_check(struct
+ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+ {
+- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+- struct drm_device *dev = crtc->dev;
+-
+ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
+ crtc->base.id);
+- if (crtc->state->event) {
+- unsigned long flags;
+-
+- crtc->state->event->pipe = drm_crtc_index(crtc);
+-
+- WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+-
+- spin_lock_irqsave(&dev->event_lock, flags);
+- vc4_crtc->event = crtc->state->event;
+- crtc->state->event = NULL;
+- spin_unlock_irqrestore(&dev->event_lock, flags);
+- }
++ if (crtc->state->active && old_state->active && crtc->state->event)
++ vc4_crtc_consume_event(crtc);
+ }
+
+ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
--- /dev/null
+From b2f463facb358b917380683b5e86c5d1cb3db123 Mon Sep 17 00:00:00 2001
+Date: Thu, 25 Jul 2019 17:34:29 +0100
+Subject: [PATCH] drm/vc4: Remove unused mode variable
+
+"89d1376 drm/vc4: Add support for margins to fkms" removed
+the requirement for having the mode structure from vc4_plane_to_mb,
+but didn't remove it as a local to the function, causing a
+compiler warning.
+
+Remove the unused variable.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -523,7 +523,6 @@ static int vc4_plane_to_mb(struct drm_pl
+ const struct vc_image_format *vc_fmt =
+ vc4_get_vc_image_fmt(drm_fmt->format);
+ int num_planes = fb->format->num_planes;
+- struct drm_display_mode *mode = &state->crtc->mode;
+ unsigned int rotation = SUPPORTED_ROTATIONS;
+
+ mb->plane.vc_image_type = vc_fmt->vc_image;
+++ /dev/null
-From 114845b6010b6e6a320804f2d86ab4d5dc5a06de Mon Sep 17 00:00:00 2001
-Date: Mon, 5 Aug 2019 14:17:14 +0100
-Subject: [PATCH] overlays: Add baudrate parameter to i2c3-i2c6
-
-The overlays for enabling the new BCM2711 I2C interfaces were lacking
-the means to configure the baud/clock rate.
-
-Also explictly set the default pins, rather than relying on the values
-in the base DTB.
-
----
- arch/arm/boot/dts/overlays/README | 8 ++++++++
- arch/arm/boot/dts/overlays/i2c3-overlay.dts | 15 ++++++++++++---
- arch/arm/boot/dts/overlays/i2c4-overlay.dts | 15 ++++++++++++---
- arch/arm/boot/dts/overlays/i2c5-overlay.dts | 15 ++++++++++++---
- arch/arm/boot/dts/overlays/i2c6-overlay.dts | 15 ++++++++++++---
- 5 files changed, 56 insertions(+), 12 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1221,6 +1221,8 @@ Info: Enable the i2c3 bus
- Load: dtoverlay=i2c3,<param>
- Params: pins_2_3 Use GPIOs 2 and 3
- pins_4_5 Use GPIOs 4 and 5 (default)
-+ baudrate Set the baudrate for the interface (default
-+ "100000")
-
-
- Name: i2c4
-@@ -1228,6 +1230,8 @@ Info: Enable the i2c4 bus
- Load: dtoverlay=i2c4,<param>
- Params: pins_6_7 Use GPIOs 6 and 7
- pins_8_9 Use GPIOs 8 and 9 (default)
-+ baudrate Set the baudrate for the interface (default
-+ "100000")
-
-
- Name: i2c5
-@@ -1235,6 +1239,8 @@ Info: Enable the i2c5 bus
- Load: dtoverlay=i2c5,<param>
- Params: pins_10_11 Use GPIOs 10 and 11
- pins_12_13 Use GPIOs 12 and 13 (default)
-+ baudrate Set the baudrate for the interface (default
-+ "100000")
-
-
- Name: i2c6
-@@ -1242,6 +1248,8 @@ Info: Enable the i2c6 bus
- Load: dtoverlay=i2c6,<param>
- Params: pins_0_1 Use GPIOs 0 and 1
- pins_22_23 Use GPIOs 22 and 23 (default)
-+ baudrate Set the baudrate for the interface (default
-+ "100000")
-
-
- Name: i2s-gpio28-31
---- a/arch/arm/boot/dts/overlays/i2c3-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c3-overlay.dts
-@@ -6,10 +6,11 @@
-
- fragment@0 {
- target = <&i2c3>;
-- __overlay__ {
-+ frag0: __overlay__ {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&i2c3_pins>;
-+ clock-frequency = <100000>;
- };
- };
-
-@@ -20,8 +21,16 @@
- };
- };
-
-+ fragment@2 {
-+ target = <&i2c3_pins>;
-+ __overlay__ {
-+ brcm,pins = <4 5>;
-+ };
-+ };
-+
- __overrides__ {
-- pins_2_3 = <0>,"=1";
-- pins_4_5 = <0>,"!1";
-+ pins_2_3 = <0>,"=1!2";
-+ pins_4_5 = <0>,"!1=2";
-+ baudrate = <&frag0>, "clock-frequency:0";
- };
- };
---- a/arch/arm/boot/dts/overlays/i2c4-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c4-overlay.dts
-@@ -6,10 +6,11 @@
-
- fragment@0 {
- target = <&i2c4>;
-- __overlay__ {
-+ frag0: __overlay__ {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&i2c4_pins>;
-+ clock-frequency = <100000>;
- };
- };
-
-@@ -20,8 +21,16 @@
- };
- };
-
-+ fragment@2 {
-+ target = <&i2c4_pins>;
-+ __overlay__ {
-+ brcm,pins = <8 9>;
-+ };
-+ };
-+
- __overrides__ {
-- pins_6_7 = <0>,"=1";
-- pins_8_9 = <0>,"!1";
-+ pins_6_7 = <0>,"=1!2";
-+ pins_8_9 = <0>,"!1=2";
-+ baudrate = <&frag0>, "clock-frequency:0";
- };
- };
---- a/arch/arm/boot/dts/overlays/i2c5-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c5-overlay.dts
-@@ -6,10 +6,11 @@
-
- fragment@0 {
- target = <&i2c5>;
-- __overlay__ {
-+ frag0: __overlay__ {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&i2c5_pins>;
-+ clock-frequency = <100000>;
- };
- };
-
-@@ -20,8 +21,16 @@
- };
- };
-
-+ fragment@2 {
-+ target = <&i2c5_pins>;
-+ __overlay__ {
-+ brcm,pins = <12 13>;
-+ };
-+ };
-+
- __overrides__ {
-- pins_10_11 = <0>,"=1";
-- pins_12_13 = <0>,"!1";
-+ pins_10_11 = <0>,"=1!2";
-+ pins_12_13 = <0>,"!1=2";
-+ baudrate = <&frag0>, "clock-frequency:0";
- };
- };
---- a/arch/arm/boot/dts/overlays/i2c6-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c6-overlay.dts
-@@ -6,10 +6,11 @@
-
- fragment@0 {
- target = <&i2c6>;
-- __overlay__ {
-+ frag0: __overlay__ {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&i2c6_pins>;
-+ clock-frequency = <100000>;
- };
- };
-
-@@ -20,8 +21,16 @@
- };
- };
-
-+ fragment@2 {
-+ target = <&i2c6_pins>;
-+ __overlay__ {
-+ brcm,pins = <22 23>;
-+ };
-+ };
-+
- __overrides__ {
-- pins_0_1 = <0>,"=1";
-- pins_22_23 = <0>,"!1";
-+ pins_0_1 = <0>,"=1!2";
-+ pins_22_23 = <0>,"!1=2";
-+ baudrate = <&frag0>, "clock-frequency:0";
- };
- };
+++ /dev/null
-From df276f0a5aa865c7926d9d148605d1a59d1d4fbb Mon Sep 17 00:00:00 2001
-Date: Thu, 25 Jul 2019 17:27:44 +0100
-Subject: [PATCH] drm/vc4: Resolve the vblank warnings on mode
- switching
-
-The details over when and how a driver is to service the
-vblank events are sketchy, and the fkms driver was triggering
-a kernel warning every time the crtc was enabled or disabled.
-
-Copy the event handling as used by the vc4-kms driver slightly
-more closely, and we avoid the warnings.
-
-https://github.com/raspberrypi/linux/issues/3020
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++--------
- 1 file changed, 33 insertions(+), 15 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -933,6 +933,7 @@ static void vc4_crtc_mode_set_nofb(struc
-
- static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
-+ struct drm_device *dev = crtc->dev;
- struct drm_plane *plane;
-
- DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
-@@ -948,6 +949,35 @@ static void vc4_crtc_disable(struct drm_
-
- drm_atomic_crtc_for_each_plane(plane, crtc)
- vc4_plane_atomic_disable(plane, plane->state);
-+
-+ /*
-+ * Make sure we issue a vblank event after disabling the CRTC if
-+ * someone was waiting it.
-+ */
-+ if (crtc->state->event) {
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&dev->event_lock, flags);
-+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
-+ crtc->state->event = NULL;
-+ spin_unlock_irqrestore(&dev->event_lock, flags);
-+ }
-+}
-+
-+static void vc4_crtc_consume_event(struct drm_crtc *crtc)
-+{
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-+ struct drm_device *dev = crtc->dev;
-+ unsigned long flags;
-+
-+ crtc->state->event->pipe = drm_crtc_index(crtc);
-+
-+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
-+
-+ spin_lock_irqsave(&dev->event_lock, flags);
-+ vc4_crtc->event = crtc->state->event;
-+ crtc->state->event = NULL;
-+ spin_unlock_irqrestore(&dev->event_lock, flags);
- }
-
- static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
-@@ -957,6 +987,7 @@ static void vc4_crtc_enable(struct drm_c
- DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
- crtc->base.id);
- drm_crtc_vblank_on(crtc);
-+ vc4_crtc_consume_event(crtc);
-
- /* Unblank the planes (if they're supposed to be displayed). */
- drm_atomic_crtc_for_each_plane(plane, crtc)
-@@ -1028,23 +1059,10 @@ static int vc4_crtc_atomic_check(struct
- static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state)
- {
-- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-- struct drm_device *dev = crtc->dev;
--
- DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
- crtc->base.id);
-- if (crtc->state->event) {
-- unsigned long flags;
--
-- crtc->state->event->pipe = drm_crtc_index(crtc);
--
-- WARN_ON(drm_crtc_vblank_get(crtc) != 0);
--
-- spin_lock_irqsave(&dev->event_lock, flags);
-- vc4_crtc->event = crtc->state->event;
-- crtc->state->event = NULL;
-- spin_unlock_irqrestore(&dev->event_lock, flags);
-- }
-+ if (crtc->state->active && old_state->active && crtc->state->event)
-+ vc4_crtc_consume_event(crtc);
- }
-
- static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
--- /dev/null
+From 9a9ef8123467579c431ced1e98827364d66c615f Mon Sep 17 00:00:00 2001
+Date: Thu, 11 Jul 2019 14:57:09 +0100
+Subject: [PATCH] staging:bcm2835-codec: Expand logging on format
+ setting
+
+Adds some more useful logging during format changed events and
+s_fmt.
+
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -753,6 +753,10 @@ static void handle_fmt_changed(struct bc
+ format->es.video.color_space);
+
+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format was %ux%u, crop %ux%u\n",
++ __func__, q_data->bytesperline, q_data->height,
++ q_data->crop_width, q_data->crop_height);
++
+ q_data->crop_width = format->es.video.crop.width;
+ q_data->crop_height = format->es.video.crop.height;
+ q_data->bytesperline = format->es.video.crop.width;
+@@ -1110,10 +1114,10 @@ static int vidioc_s_fmt(struct bcm2835_c
+ bool update_capture_port = false;
+ int ret;
+
+- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: " V4L2_FOURCC_CONV ", size %u\n",
+ f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+- f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage);
+-
++ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat),
++ f->fmt.pix_mp.plane_fmt[0].sizeimage);
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+++ /dev/null
-From b2f463facb358b917380683b5e86c5d1cb3db123 Mon Sep 17 00:00:00 2001
-Date: Thu, 25 Jul 2019 17:34:29 +0100
-Subject: [PATCH] drm/vc4: Remove unused mode variable
-
-"89d1376 drm/vc4: Add support for margins to fkms" removed
-the requirement for having the mode structure from vc4_plane_to_mb,
-but didn't remove it as a local to the function, causing a
-compiler warning.
-
-Remove the unused variable.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -523,7 +523,6 @@ static int vc4_plane_to_mb(struct drm_pl
- const struct vc_image_format *vc_fmt =
- vc4_get_vc_image_fmt(drm_fmt->format);
- int num_planes = fb->format->num_planes;
-- struct drm_display_mode *mode = &state->crtc->mode;
- unsigned int rotation = SUPPORTED_ROTATIONS;
-
- mb->plane.vc_image_type = vc_fmt->vc_image;
--- /dev/null
+From bcb6e267ca61ce685ed2debc0cee327527cea20d Mon Sep 17 00:00:00 2001
+Date: Thu, 11 Jul 2019 14:58:35 +0100
+Subject: [PATCH] staging: bcm2835-codec: Correct bytesperline on
+ format changed
+
+The handling of format changed events incorrectly set bytesperline
+to the cropped width, which ignored padding and formats with
+more than 8bpp.
+Fix these.
+
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -759,7 +759,9 @@ static void handle_fmt_changed(struct bc
+
+ q_data->crop_width = format->es.video.crop.width;
+ q_data->crop_height = format->es.video.crop.height;
+- q_data->bytesperline = format->es.video.crop.width;
++ q_data->bytesperline = get_bytesperline(format->es.video.width,
++ q_data->fmt);
++
+ q_data->height = format->es.video.height;
+ q_data->sizeimage = format->buffer_size_min;
+ if (format->es.video.color_space)
--- /dev/null
+From cbe5c2a67fb145b210652be20a84690e09e4eb25 Mon Sep 17 00:00:00 2001
+Date: Wed, 7 Aug 2019 11:31:08 +0100
+Subject: [PATCH] drm/vc4: Add missing NULL check to
+ vc4_crtc_consume_event
+
+vc4_crtc_consume_event wasn't checking crtc->state->event was
+set before dereferencing it, leading to an OOPS.
+
+Fixes "a5b534b drm/vc4: Resolve the vblank warnings on mode switching"
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -969,6 +969,9 @@ static void vc4_crtc_consume_event(struc
+ struct drm_device *dev = crtc->dev;
+ unsigned long flags;
+
++ if (!crtc->state->event)
++ return;
++
+ crtc->state->event->pipe = drm_crtc_index(crtc);
+
+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+++ /dev/null
-From 9a9ef8123467579c431ced1e98827364d66c615f Mon Sep 17 00:00:00 2001
-Date: Thu, 11 Jul 2019 14:57:09 +0100
-Subject: [PATCH] staging:bcm2835-codec: Expand logging on format
- setting
-
-Adds some more useful logging during format changed events and
-s_fmt.
-
----
- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 10 +++++++---
- 1 file changed, 7 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -753,6 +753,10 @@ static void handle_fmt_changed(struct bc
- format->es.video.color_space);
-
- q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format was %ux%u, crop %ux%u\n",
-+ __func__, q_data->bytesperline, q_data->height,
-+ q_data->crop_width, q_data->crop_height);
-+
- q_data->crop_width = format->es.video.crop.width;
- q_data->crop_height = format->es.video.crop.height;
- q_data->bytesperline = format->es.video.crop.width;
-@@ -1110,10 +1114,10 @@ static int vidioc_s_fmt(struct bcm2835_c
- bool update_capture_port = false;
- int ret;
-
-- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: " V4L2_FOURCC_CONV ", size %u\n",
- f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
-- f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage);
--
-+ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat),
-+ f->fmt.pix_mp.plane_fmt[0].sizeimage);
-
- vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
- if (!vq)
--- /dev/null
+From 103afc4641ab8d6587e981a5e3fda27427a8bf4b Mon Sep 17 00:00:00 2001
+Date: Fri, 9 Aug 2019 08:51:43 +0100
+Subject: [PATCH] net: bcmgenet: Workaround #2 for Pi4 Ethernet fail
+
+Some combinations of Pi 4Bs and Ethernet switches don't reliably get a
+DCHP-assigned IP address, leaving the unit with a self=assigned 169.254
+address. In the failure case, the Pi is left able to receive packets
+but not send them, suggesting that the MAC<->PHY link is getting into
+a bad state.
+
+It has been found empirically that skipping a reset step by the genet
+driver prevents the failures. No downsides have been discovered yet,
+and unlike the forced renegotiation it doesn't increase the time to
+get an IP address, so the workaround is enabled by default; add
+
+ genet.skip_umac_reset=n
+
+to the command line to disable it.
+
+See: https://github.com/raspberrypi/linux/issues/3108
+
+---
+ drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+@@ -72,6 +72,10 @@
+ #define GENET_RDMA_REG_OFF (priv->hw_params->rdma_offset + \
+ TOTAL_DESC * DMA_DESC_SIZE)
+
++static bool skip_umac_reset = true;
++module_param(skip_umac_reset, bool, 0444);
++MODULE_PARM_DESC(skip_umac_reset, "Skip UMAC reset step");
++
+ static inline void bcmgenet_writel(u32 value, void __iomem *offset)
+ {
+ /* MIPS chips strapped for BE will automagically configure the
+@@ -1993,6 +1997,11 @@ static void reset_umac(struct bcmgenet_p
+ bcmgenet_rbuf_ctrl_set(priv, 0);
+ udelay(10);
+
++ if (skip_umac_reset) {
++ pr_warn("Skipping UMAC reset\n");
++ return;
++ }
++
+ /* disable MAC while updating its registers */
+ bcmgenet_umac_writel(priv, 0, UMAC_CMD);
+
+++ /dev/null
-From bcb6e267ca61ce685ed2debc0cee327527cea20d Mon Sep 17 00:00:00 2001
-Date: Thu, 11 Jul 2019 14:58:35 +0100
-Subject: [PATCH] staging: bcm2835-codec: Correct bytesperline on
- format changed
-
-The handling of format changed events incorrectly set bytesperline
-to the cropped width, which ignored padding and formats with
-more than 8bpp.
-Fix these.
-
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -759,7 +759,9 @@ static void handle_fmt_changed(struct bc
-
- q_data->crop_width = format->es.video.crop.width;
- q_data->crop_height = format->es.video.crop.height;
-- q_data->bytesperline = format->es.video.crop.width;
-+ q_data->bytesperline = get_bytesperline(format->es.video.width,
-+ q_data->fmt);
-+
- q_data->height = format->es.video.height;
- q_data->sizeimage = format->buffer_size_min;
- if (format->es.video.color_space)
+++ /dev/null
-From cbe5c2a67fb145b210652be20a84690e09e4eb25 Mon Sep 17 00:00:00 2001
-Date: Wed, 7 Aug 2019 11:31:08 +0100
-Subject: [PATCH] drm/vc4: Add missing NULL check to
- vc4_crtc_consume_event
-
-vc4_crtc_consume_event wasn't checking crtc->state->event was
-set before dereferencing it, leading to an OOPS.
-
-Fixes "a5b534b drm/vc4: Resolve the vblank warnings on mode switching"
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -969,6 +969,9 @@ static void vc4_crtc_consume_event(struc
- struct drm_device *dev = crtc->dev;
- unsigned long flags;
-
-+ if (!crtc->state->event)
-+ return;
-+
- crtc->state->event->pipe = drm_crtc_index(crtc);
-
- WARN_ON(drm_crtc_vblank_get(crtc) != 0);
--- /dev/null
+From c1fffc2a7dbf7e59aaef36378fb14d1c3dc016a6 Mon Sep 17 00:00:00 2001
+Date: Fri, 3 Aug 2018 11:22:27 +0200
+Subject: [PATCH] drm/vc4: Fix TILE_Y_OFFSET definitions
+
+Y_OFFSET field starts at bit 8 not 7.
+
+---
+ drivers/gpu/drm/vc4/vc4_regs.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -1043,8 +1043,8 @@ enum hvs_pixel_format {
+ #define SCALER_PITCH0_TILE_LINE_DIR BIT(15)
+ #define SCALER_PITCH0_TILE_INITIAL_LINE_DIR BIT(14)
+ /* Y offset within a tile. */
+-#define SCALER_PITCH0_TILE_Y_OFFSET_MASK VC4_MASK(13, 7)
+-#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT 7
++#define SCALER_PITCH0_TILE_Y_OFFSET_MASK VC4_MASK(13, 8)
++#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT 8
+ #define SCALER_PITCH0_TILE_WIDTH_R_MASK VC4_MASK(6, 0)
+ #define SCALER_PITCH0_TILE_WIDTH_R_SHIFT 0
+
--- /dev/null
+From d0b90f9c68a96f2bee66d796cb33367d205e586a Mon Sep 17 00:00:00 2001
+Date: Fri, 3 Aug 2018 11:22:28 +0200
+Subject: [PATCH] drm/vc4: Define missing PITCH0_SINK_PIX field
+
+This is needed to support X/Y negative placement of planes using
+T-format buffers.
+
+---
+ drivers/gpu/drm/vc4/vc4_regs.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -1037,6 +1037,10 @@ enum hvs_pixel_format {
+ #define SCALER_TILE_HEIGHT_MASK VC4_MASK(15, 0)
+ #define SCALER_TILE_HEIGHT_SHIFT 0
+
++/* Common PITCH0 fields */
++#define SCALER_PITCH0_SINK_PIX_MASK VC4_MASK(31, 26)
++#define SCALER_PITCH0_SINK_PIX_SHIFT 26
++
+ /* PITCH0 fields for T-tiled. */
+ #define SCALER_PITCH0_TILE_WIDTH_L_MASK VC4_MASK(22, 16)
+ #define SCALER_PITCH0_TILE_WIDTH_L_SHIFT 16
+++ /dev/null
-From 103afc4641ab8d6587e981a5e3fda27427a8bf4b Mon Sep 17 00:00:00 2001
-Date: Fri, 9 Aug 2019 08:51:43 +0100
-Subject: [PATCH] net: bcmgenet: Workaround #2 for Pi4 Ethernet fail
-
-Some combinations of Pi 4Bs and Ethernet switches don't reliably get a
-DCHP-assigned IP address, leaving the unit with a self=assigned 169.254
-address. In the failure case, the Pi is left able to receive packets
-but not send them, suggesting that the MAC<->PHY link is getting into
-a bad state.
-
-It has been found empirically that skipping a reset step by the genet
-driver prevents the failures. No downsides have been discovered yet,
-and unlike the forced renegotiation it doesn't increase the time to
-get an IP address, so the workaround is enabled by default; add
-
- genet.skip_umac_reset=n
-
-to the command line to disable it.
-
-See: https://github.com/raspberrypi/linux/issues/3108
-
----
- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 +++++++++
- 1 file changed, 9 insertions(+)
-
---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-@@ -72,6 +72,10 @@
- #define GENET_RDMA_REG_OFF (priv->hw_params->rdma_offset + \
- TOTAL_DESC * DMA_DESC_SIZE)
-
-+static bool skip_umac_reset = true;
-+module_param(skip_umac_reset, bool, 0444);
-+MODULE_PARM_DESC(skip_umac_reset, "Skip UMAC reset step");
-+
- static inline void bcmgenet_writel(u32 value, void __iomem *offset)
- {
- /* MIPS chips strapped for BE will automagically configure the
-@@ -1993,6 +1997,11 @@ static void reset_umac(struct bcmgenet_p
- bcmgenet_rbuf_ctrl_set(priv, 0);
- udelay(10);
-
-+ if (skip_umac_reset) {
-+ pr_warn("Skipping UMAC reset\n");
-+ return;
-+ }
-+
- /* disable MAC while updating its registers */
- bcmgenet_umac_writel(priv, 0, UMAC_CMD);
-
+++ /dev/null
-From c1fffc2a7dbf7e59aaef36378fb14d1c3dc016a6 Mon Sep 17 00:00:00 2001
-Date: Fri, 3 Aug 2018 11:22:27 +0200
-Subject: [PATCH] drm/vc4: Fix TILE_Y_OFFSET definitions
-
-Y_OFFSET field starts at bit 8 not 7.
-
----
- drivers/gpu/drm/vc4/vc4_regs.h | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_regs.h
-+++ b/drivers/gpu/drm/vc4/vc4_regs.h
-@@ -1043,8 +1043,8 @@ enum hvs_pixel_format {
- #define SCALER_PITCH0_TILE_LINE_DIR BIT(15)
- #define SCALER_PITCH0_TILE_INITIAL_LINE_DIR BIT(14)
- /* Y offset within a tile. */
--#define SCALER_PITCH0_TILE_Y_OFFSET_MASK VC4_MASK(13, 7)
--#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT 7
-+#define SCALER_PITCH0_TILE_Y_OFFSET_MASK VC4_MASK(13, 8)
-+#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT 8
- #define SCALER_PITCH0_TILE_WIDTH_R_MASK VC4_MASK(6, 0)
- #define SCALER_PITCH0_TILE_WIDTH_R_SHIFT 0
-
--- /dev/null
+From 2a98dc34696c6510a49a684eb56d3a9c2a150571 Mon Sep 17 00:00:00 2001
+Date: Fri, 3 Aug 2018 11:22:29 +0200
+Subject: [PATCH] drm/vc4: Use drm_atomic_helper_check_plane_state() to
+ simplify the logic
+
+drm_atomic_helper_check_plane_state() takes care of checking the
+scaling capabilities and calculating the clipped X/Y offsets for us.
+
+Rely on this function instead of open-coding the logic.
+
+Incidentally, it seems to fix a problem we had with negative X/Y
+positioning of YUV planes.
+
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 103 ++++++++++++++++----------------
+ 1 file changed, 52 insertions(+), 51 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -313,31 +313,59 @@ static int vc4_plane_setup_clipping_and_
+ u32 subpixel_src_mask = (1 << 16) - 1;
+ u32 format = fb->format->format;
+ int num_planes = fb->format->num_planes;
+- u32 h_subsample = 1;
+- u32 v_subsample = 1;
+- int ret;
+- int i;
++ int min_scale = 1, max_scale = INT_MAX;
++ struct drm_crtc_state *crtc_state;
++ u32 h_subsample, v_subsample;
++ int i, ret;
++
++ crtc_state = drm_atomic_get_existing_crtc_state(state->state,
++ state->crtc);
++ if (!crtc_state) {
++ DRM_DEBUG_KMS("Invalid crtc state\n");
++ return -EINVAL;
++ }
++
++ /* No configuring scaling on the cursor plane, since it gets
++ * non-vblank-synced updates, and scaling requires LBM changes which
++ * have to be vblank-synced.
++ */
++ if (plane->type == DRM_PLANE_TYPE_CURSOR) {
++ min_scale = DRM_PLANE_HELPER_NO_SCALING;
++ max_scale = DRM_PLANE_HELPER_NO_SCALING;
++ } else {
++ min_scale = 1;
++ max_scale = INT_MAX;
++ }
++
++ ret = drm_atomic_helper_check_plane_state(state, crtc_state,
++ min_scale, max_scale,
++ true, true);
++ if (ret)
++ return ret;
++
++ h_subsample = drm_format_horz_chroma_subsampling(format);
++ v_subsample = drm_format_vert_chroma_subsampling(format);
+
+ for (i = 0; i < num_planes; i++)
+ vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
+
+ /* We don't support subpixel source positioning for scaling. */
+- if ((state->src_x & subpixel_src_mask) ||
+- (state->src_y & subpixel_src_mask) ||
+- (state->src_w & subpixel_src_mask) ||
+- (state->src_h & subpixel_src_mask)) {
++ if ((state->src.x1 & subpixel_src_mask) ||
++ (state->src.x2 & subpixel_src_mask) ||
++ (state->src.y1 & subpixel_src_mask) ||
++ (state->src.y2 & subpixel_src_mask)) {
+ return -EINVAL;
+ }
+
+- vc4_state->src_x = state->src_x >> 16;
+- vc4_state->src_y = state->src_y >> 16;
+- vc4_state->src_w[0] = state->src_w >> 16;
+- vc4_state->src_h[0] = state->src_h >> 16;
+-
+- vc4_state->crtc_x = state->crtc_x;
+- vc4_state->crtc_y = state->crtc_y;
+- vc4_state->crtc_w = state->crtc_w;
+- vc4_state->crtc_h = state->crtc_h;
++ vc4_state->src_x = state->src.x1 >> 16;
++ vc4_state->src_y = state->src.y1 >> 16;
++ vc4_state->src_w[0] = (state->src.x2 - state->src.x1) >> 16;
++ vc4_state->src_h[0] = (state->src.y2 - state->src.y1) >> 16;
++
++ vc4_state->crtc_x = state->dst.x1;
++ vc4_state->crtc_y = state->dst.y1;
++ vc4_state->crtc_w = state->dst.x2 - state->dst.x1;
++ vc4_state->crtc_h = state->dst.y2 - state->dst.y1;
+
+ ret = vc4_plane_margins_adj(state);
+ if (ret)
+@@ -354,8 +382,6 @@ static int vc4_plane_setup_clipping_and_
+ if (num_planes > 1) {
+ vc4_state->is_yuv = true;
+
+- h_subsample = drm_format_horz_chroma_subsampling(format);
+- v_subsample = drm_format_vert_chroma_subsampling(format);
+ vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
+ vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
+
+@@ -380,39 +406,14 @@ static int vc4_plane_setup_clipping_and_
+ vc4_state->y_scaling[1] = VC4_SCALING_NONE;
+ }
+
+- /* No configuring scaling on the cursor plane, since it gets
+- non-vblank-synced updates, and scaling requires requires
+- LBM changes which have to be vblank-synced.
+- */
+- if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity)
+- return -EINVAL;
+-
+- /* Clamp the on-screen start x/y to 0. The hardware doesn't
+- * support negative y, and negative x wastes bandwidth.
+- */
+- if (vc4_state->crtc_x < 0) {
+- for (i = 0; i < num_planes; i++) {
+- u32 cpp = fb->format->cpp[i];
+- u32 subs = ((i == 0) ? 1 : h_subsample);
+-
+- vc4_state->offsets[i] += (cpp *
+- (-vc4_state->crtc_x) / subs);
+- }
+- vc4_state->src_w[0] += vc4_state->crtc_x;
+- vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
+- vc4_state->crtc_x = 0;
+- }
+-
+- if (vc4_state->crtc_y < 0) {
+- for (i = 0; i < num_planes; i++) {
+- u32 subs = ((i == 0) ? 1 : v_subsample);
+-
+- vc4_state->offsets[i] += (fb->pitches[i] *
+- (-vc4_state->crtc_y) / subs);
+- }
+- vc4_state->src_h[0] += vc4_state->crtc_y;
+- vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample;
+- vc4_state->crtc_y = 0;
++ /* Adjust the base pointer to the first pixel to be scanned out. */
++ for (i = 0; i < num_planes; i++) {
++ vc4_state->offsets[i] += (vc4_state->src_y /
++ (i ? v_subsample : 1)) *
++ fb->pitches[i];
++ vc4_state->offsets[i] += (vc4_state->src_x /
++ (i ? h_subsample : 1)) *
++ fb->format->cpp[i];
+ }
+
+ return 0;
+++ /dev/null
-From d0b90f9c68a96f2bee66d796cb33367d205e586a Mon Sep 17 00:00:00 2001
-Date: Fri, 3 Aug 2018 11:22:28 +0200
-Subject: [PATCH] drm/vc4: Define missing PITCH0_SINK_PIX field
-
-This is needed to support X/Y negative placement of planes using
-T-format buffers.
-
----
- drivers/gpu/drm/vc4/vc4_regs.h | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_regs.h
-+++ b/drivers/gpu/drm/vc4/vc4_regs.h
-@@ -1037,6 +1037,10 @@ enum hvs_pixel_format {
- #define SCALER_TILE_HEIGHT_MASK VC4_MASK(15, 0)
- #define SCALER_TILE_HEIGHT_SHIFT 0
-
-+/* Common PITCH0 fields */
-+#define SCALER_PITCH0_SINK_PIX_MASK VC4_MASK(31, 26)
-+#define SCALER_PITCH0_SINK_PIX_SHIFT 26
-+
- /* PITCH0 fields for T-tiled. */
- #define SCALER_PITCH0_TILE_WIDTH_L_MASK VC4_MASK(22, 16)
- #define SCALER_PITCH0_TILE_WIDTH_L_SHIFT 16
--- /dev/null
+From 58a92eae6ed463c294381e72eefec701d23fcdaf Mon Sep 17 00:00:00 2001
+Date: Fri, 3 Aug 2018 11:22:30 +0200
+Subject: [PATCH] adjustment out of
+ setup_clipping_and_scaling()
+
+The offset adjustment depends on the framebuffer modified, so let's
+just move this operation in the DRM_FORMAT_MOD_LINEAR case inside
+vc4_plane_mode_set().
+
+This we'll be able to fix offset calculation for
+DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED and DRM_FORMAT_MOD_BROADCOM_SANDXXX.
+
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 26 ++++++++++++++++----------
+ 1 file changed, 16 insertions(+), 10 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -406,16 +406,6 @@ static int vc4_plane_setup_clipping_and_
+ vc4_state->y_scaling[1] = VC4_SCALING_NONE;
+ }
+
+- /* Adjust the base pointer to the first pixel to be scanned out. */
+- for (i = 0; i < num_planes; i++) {
+- vc4_state->offsets[i] += (vc4_state->src_y /
+- (i ? v_subsample : 1)) *
+- fb->pitches[i];
+- vc4_state->offsets[i] += (vc4_state->src_x /
+- (i ? h_subsample : 1)) *
+- fb->format->cpp[i];
+- }
+-
+ return 0;
+ }
+
+@@ -523,6 +513,7 @@ static int vc4_plane_mode_set(struct drm
+ const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
+ u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
+ int num_planes = drm_format_num_planes(format->drm);
++ u32 h_subsample, v_subsample;
+ bool mix_plane_alpha;
+ bool covers_screen;
+ u32 scl0, scl1, pitch0;
+@@ -568,10 +559,25 @@ static int vc4_plane_mode_set(struct drm
+ scl1 = vc4_get_scl_field(state, 0);
+ }
+
++ h_subsample = drm_format_horz_chroma_subsampling(format->drm);
++ v_subsample = drm_format_vert_chroma_subsampling(format->drm);
++
+ switch (base_format_mod) {
+ case DRM_FORMAT_MOD_LINEAR:
+ tiling = SCALER_CTL0_TILING_LINEAR;
+ pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
++
++ /* Adjust the base pointer to the first pixel to be scanned
++ * out.
++ */
++ for (i = 0; i < num_planes; i++) {
++ vc4_state->offsets[i] += vc4_state->src_y /
++ (i ? v_subsample : 1) *
++ fb->pitches[i];
++ vc4_state->offsets[i] += vc4_state->src_x /
++ (i ? h_subsample : 1) *
++ fb->format->cpp[i];
++ }
+ break;
+
+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
--- /dev/null
+From 010e3665babdf589e26e2fb098ac1f39e519c0f6 Mon Sep 17 00:00:00 2001
+Date: Fri, 3 Aug 2018 11:22:31 +0200
+Subject: [PATCH] drm/vc4: Fix X/Y positioning of planes using T_TILES
+ modifier
+
+X/Y positioning of T-format buffers is quite tricky and the current
+implementation was failing to position a plane using this format
+correctly when the CRTC X, Y or both X and Y offsets were negative.
+It was also failing when the SRC X/Y offsets were != 0.
+
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 50 ++++++++++++++++++++++++++++-----
+ 1 file changed, 43 insertions(+), 7 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -578,22 +578,58 @@ static int vc4_plane_mode_set(struct drm
+ (i ? h_subsample : 1) *
+ fb->format->cpp[i];
+ }
++
+ break;
+
+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
+- /* For T-tiled, the FB pitch is "how many bytes from
+- * one row to the next, such that pitch * tile_h ==
+- * tile_size * tiles_per_row."
+- */
+ u32 tile_size_shift = 12; /* T tiles are 4kb */
++ /* Whole-tile offsets, mostly for setting the pitch. */
++ u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5;
+ u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */
++ u32 tile_w_mask = (1 << tile_w_shift) - 1;
++ /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice
++ * the height (in pixels) of a 4k tile.
++ */
++ u32 tile_h_mask = (2 << tile_h_shift) - 1;
++ /* For T-tiled, the FB pitch is "how many bytes from one row to
++ * the next, such that
++ *
++ * pitch * tile_h == tile_size * tiles_per_row
++ */
+ u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
++ u32 tiles_l = vc4_state->src_x >> tile_w_shift;
++ u32 tiles_r = tiles_w - tiles_l;
++ u32 tiles_t = vc4_state->src_y >> tile_h_shift;
++ /* Intra-tile offsets, which modify the base address (the
++ * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
++ * base address).
++ */
++ u32 tile_y = (vc4_state->src_y >> 4) & 1;
++ u32 subtile_y = (vc4_state->src_y >> 2) & 3;
++ u32 utile_y = vc4_state->src_y & 3;
++ u32 x_off = vc4_state->src_x & tile_w_mask;
++ u32 y_off = vc4_state->src_y & tile_h_mask;
+
+ tiling = SCALER_CTL0_TILING_256B_OR_T;
++ pitch0 = (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
++ VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
++ VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
++ VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
++ vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift);
++ vc4_state->offsets[0] += subtile_y << 8;
++ vc4_state->offsets[0] += utile_y << 4;
++
++ /* Rows of tiles alternate left-to-right and right-to-left. */
++ if (tiles_t & 1) {
++ pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR;
++ vc4_state->offsets[0] += (tiles_w - tiles_l) <<
++ tile_size_shift;
++ vc4_state->offsets[0] -= (1 + !tile_y) << 10;
++ } else {
++ vc4_state->offsets[0] += tiles_l << tile_size_shift;
++ vc4_state->offsets[0] += tile_y << 10;
++ }
+
+- pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET) |
+- VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L) |
+- VC4_SET_FIELD(tiles_w, SCALER_PITCH0_TILE_WIDTH_R));
+ break;
+ }
+
+++ /dev/null
-From 2a98dc34696c6510a49a684eb56d3a9c2a150571 Mon Sep 17 00:00:00 2001
-Date: Fri, 3 Aug 2018 11:22:29 +0200
-Subject: [PATCH] drm/vc4: Use drm_atomic_helper_check_plane_state() to
- simplify the logic
-
-drm_atomic_helper_check_plane_state() takes care of checking the
-scaling capabilities and calculating the clipped X/Y offsets for us.
-
-Rely on this function instead of open-coding the logic.
-
-Incidentally, it seems to fix a problem we had with negative X/Y
-positioning of YUV planes.
-
----
- drivers/gpu/drm/vc4/vc4_plane.c | 103 ++++++++++++++++----------------
- 1 file changed, 52 insertions(+), 51 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_plane.c
-+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -313,31 +313,59 @@ static int vc4_plane_setup_clipping_and_
- u32 subpixel_src_mask = (1 << 16) - 1;
- u32 format = fb->format->format;
- int num_planes = fb->format->num_planes;
-- u32 h_subsample = 1;
-- u32 v_subsample = 1;
-- int ret;
-- int i;
-+ int min_scale = 1, max_scale = INT_MAX;
-+ struct drm_crtc_state *crtc_state;
-+ u32 h_subsample, v_subsample;
-+ int i, ret;
-+
-+ crtc_state = drm_atomic_get_existing_crtc_state(state->state,
-+ state->crtc);
-+ if (!crtc_state) {
-+ DRM_DEBUG_KMS("Invalid crtc state\n");
-+ return -EINVAL;
-+ }
-+
-+ /* No configuring scaling on the cursor plane, since it gets
-+ * non-vblank-synced updates, and scaling requires LBM changes which
-+ * have to be vblank-synced.
-+ */
-+ if (plane->type == DRM_PLANE_TYPE_CURSOR) {
-+ min_scale = DRM_PLANE_HELPER_NO_SCALING;
-+ max_scale = DRM_PLANE_HELPER_NO_SCALING;
-+ } else {
-+ min_scale = 1;
-+ max_scale = INT_MAX;
-+ }
-+
-+ ret = drm_atomic_helper_check_plane_state(state, crtc_state,
-+ min_scale, max_scale,
-+ true, true);
-+ if (ret)
-+ return ret;
-+
-+ h_subsample = drm_format_horz_chroma_subsampling(format);
-+ v_subsample = drm_format_vert_chroma_subsampling(format);
-
- for (i = 0; i < num_planes; i++)
- vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
-
- /* We don't support subpixel source positioning for scaling. */
-- if ((state->src_x & subpixel_src_mask) ||
-- (state->src_y & subpixel_src_mask) ||
-- (state->src_w & subpixel_src_mask) ||
-- (state->src_h & subpixel_src_mask)) {
-+ if ((state->src.x1 & subpixel_src_mask) ||
-+ (state->src.x2 & subpixel_src_mask) ||
-+ (state->src.y1 & subpixel_src_mask) ||
-+ (state->src.y2 & subpixel_src_mask)) {
- return -EINVAL;
- }
-
-- vc4_state->src_x = state->src_x >> 16;
-- vc4_state->src_y = state->src_y >> 16;
-- vc4_state->src_w[0] = state->src_w >> 16;
-- vc4_state->src_h[0] = state->src_h >> 16;
--
-- vc4_state->crtc_x = state->crtc_x;
-- vc4_state->crtc_y = state->crtc_y;
-- vc4_state->crtc_w = state->crtc_w;
-- vc4_state->crtc_h = state->crtc_h;
-+ vc4_state->src_x = state->src.x1 >> 16;
-+ vc4_state->src_y = state->src.y1 >> 16;
-+ vc4_state->src_w[0] = (state->src.x2 - state->src.x1) >> 16;
-+ vc4_state->src_h[0] = (state->src.y2 - state->src.y1) >> 16;
-+
-+ vc4_state->crtc_x = state->dst.x1;
-+ vc4_state->crtc_y = state->dst.y1;
-+ vc4_state->crtc_w = state->dst.x2 - state->dst.x1;
-+ vc4_state->crtc_h = state->dst.y2 - state->dst.y1;
-
- ret = vc4_plane_margins_adj(state);
- if (ret)
-@@ -354,8 +382,6 @@ static int vc4_plane_setup_clipping_and_
- if (num_planes > 1) {
- vc4_state->is_yuv = true;
-
-- h_subsample = drm_format_horz_chroma_subsampling(format);
-- v_subsample = drm_format_vert_chroma_subsampling(format);
- vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
- vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
-
-@@ -380,39 +406,14 @@ static int vc4_plane_setup_clipping_and_
- vc4_state->y_scaling[1] = VC4_SCALING_NONE;
- }
-
-- /* No configuring scaling on the cursor plane, since it gets
-- non-vblank-synced updates, and scaling requires requires
-- LBM changes which have to be vblank-synced.
-- */
-- if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity)
-- return -EINVAL;
--
-- /* Clamp the on-screen start x/y to 0. The hardware doesn't
-- * support negative y, and negative x wastes bandwidth.
-- */
-- if (vc4_state->crtc_x < 0) {
-- for (i = 0; i < num_planes; i++) {
-- u32 cpp = fb->format->cpp[i];
-- u32 subs = ((i == 0) ? 1 : h_subsample);
--
-- vc4_state->offsets[i] += (cpp *
-- (-vc4_state->crtc_x) / subs);
-- }
-- vc4_state->src_w[0] += vc4_state->crtc_x;
-- vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
-- vc4_state->crtc_x = 0;
-- }
--
-- if (vc4_state->crtc_y < 0) {
-- for (i = 0; i < num_planes; i++) {
-- u32 subs = ((i == 0) ? 1 : v_subsample);
--
-- vc4_state->offsets[i] += (fb->pitches[i] *
-- (-vc4_state->crtc_y) / subs);
-- }
-- vc4_state->src_h[0] += vc4_state->crtc_y;
-- vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample;
-- vc4_state->crtc_y = 0;
-+ /* Adjust the base pointer to the first pixel to be scanned out. */
-+ for (i = 0; i < num_planes; i++) {
-+ vc4_state->offsets[i] += (vc4_state->src_y /
-+ (i ? v_subsample : 1)) *
-+ fb->pitches[i];
-+ vc4_state->offsets[i] += (vc4_state->src_x /
-+ (i ? h_subsample : 1)) *
-+ fb->format->cpp[i];
- }
-
- return 0;
--- /dev/null
+From 0e81807e647c5e12fd897f3d520252ea60de3ff9 Mon Sep 17 00:00:00 2001
+Date: Thu, 15 Nov 2018 11:58:51 +0100
+Subject: [PATCH] drm/vc4: Fix NULL pointer dereference in the async
+ update path
+
+vc4_plane_atomic_async_update() calls vc4_plane_atomic_check()
+which in turn calls vc4_plane_setup_clipping_and_scaling(), and since
+commit 58a6a36fe8e0 ("drm/vc4: Use
+drm_atomic_helper_check_plane_state() to simplify the logic"), this
+function accesses plane_state->state which will be NULL when called
+from the async update path because we're passing the current plane
+state, and plane_state->state has been assigned to NULL in
+drm_atomic_helper_swap_state().
+
+Pass the new state instead of the current one (the new state has
+->state set to a non-NULL value).
+
+Fixes: 58a6a36fe8e0 ("drm/vc4: Use drm_atomic_helper_check_plane_state() to simplify the logic")
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -905,7 +905,7 @@ void vc4_plane_async_set_fb(struct drm_p
+ static void vc4_plane_atomic_async_update(struct drm_plane *plane,
+ struct drm_plane_state *state)
+ {
+- struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
++ struct vc4_plane_state *vc4_state, *new_vc4_state;
+
+ if (plane->state->fb != state->fb) {
+ vc4_plane_async_set_fb(plane, state->fb);
+@@ -927,7 +927,18 @@ static void vc4_plane_atomic_async_updat
+ plane->state->src_y = state->src_y;
+
+ /* Update the display list based on the new crtc_x/y. */
+- vc4_plane_atomic_check(plane, plane->state);
++ vc4_plane_atomic_check(plane, state);
++
++ new_vc4_state = to_vc4_plane_state(state);
++ vc4_state = to_vc4_plane_state(plane->state);
++
++ /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */
++ vc4_state->dlist[vc4_state->pos0_offset] =
++ new_vc4_state->dlist[vc4_state->pos0_offset];
++ vc4_state->dlist[vc4_state->pos2_offset] =
++ new_vc4_state->dlist[vc4_state->pos2_offset];
++ vc4_state->dlist[vc4_state->ptr0_offset] =
++ new_vc4_state->dlist[vc4_state->ptr0_offset];
+
+ /* Note that we can't just call vc4_plane_write_dlist()
+ * because that would smash the context data that the HVS is
+++ /dev/null
-From 58a92eae6ed463c294381e72eefec701d23fcdaf Mon Sep 17 00:00:00 2001
-Date: Fri, 3 Aug 2018 11:22:30 +0200
-Subject: [PATCH] adjustment out of
- setup_clipping_and_scaling()
-
-The offset adjustment depends on the framebuffer modified, so let's
-just move this operation in the DRM_FORMAT_MOD_LINEAR case inside
-vc4_plane_mode_set().
-
-This we'll be able to fix offset calculation for
-DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED and DRM_FORMAT_MOD_BROADCOM_SANDXXX.
-
----
- drivers/gpu/drm/vc4/vc4_plane.c | 26 ++++++++++++++++----------
- 1 file changed, 16 insertions(+), 10 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_plane.c
-+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -406,16 +406,6 @@ static int vc4_plane_setup_clipping_and_
- vc4_state->y_scaling[1] = VC4_SCALING_NONE;
- }
-
-- /* Adjust the base pointer to the first pixel to be scanned out. */
-- for (i = 0; i < num_planes; i++) {
-- vc4_state->offsets[i] += (vc4_state->src_y /
-- (i ? v_subsample : 1)) *
-- fb->pitches[i];
-- vc4_state->offsets[i] += (vc4_state->src_x /
-- (i ? h_subsample : 1)) *
-- fb->format->cpp[i];
-- }
--
- return 0;
- }
-
-@@ -523,6 +513,7 @@ static int vc4_plane_mode_set(struct drm
- const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
- u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
- int num_planes = drm_format_num_planes(format->drm);
-+ u32 h_subsample, v_subsample;
- bool mix_plane_alpha;
- bool covers_screen;
- u32 scl0, scl1, pitch0;
-@@ -568,10 +559,25 @@ static int vc4_plane_mode_set(struct drm
- scl1 = vc4_get_scl_field(state, 0);
- }
-
-+ h_subsample = drm_format_horz_chroma_subsampling(format->drm);
-+ v_subsample = drm_format_vert_chroma_subsampling(format->drm);
-+
- switch (base_format_mod) {
- case DRM_FORMAT_MOD_LINEAR:
- tiling = SCALER_CTL0_TILING_LINEAR;
- pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
-+
-+ /* Adjust the base pointer to the first pixel to be scanned
-+ * out.
-+ */
-+ for (i = 0; i < num_planes; i++) {
-+ vc4_state->offsets[i] += vc4_state->src_y /
-+ (i ? v_subsample : 1) *
-+ fb->pitches[i];
-+ vc4_state->offsets[i] += vc4_state->src_x /
-+ (i ? h_subsample : 1) *
-+ fb->format->cpp[i];
-+ }
- break;
-
- case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
--- /dev/null
+From 188bd7c0085ac5b3d966aa899c6be644907157ea Mon Sep 17 00:00:00 2001
+Date: Mon, 12 Aug 2019 15:48:39 +0100
+Subject: [PATCH] ARM: dts: bcm2711-rpi-4-b: I2C aliases and pulls
+
+The I2C interface nodes need aliases to give them fixed bus numbers,
+and setting the pulls on the GPIOs (particularly 9-13) increases the
+chances of the bus working with weak or absent external pulls.
+
+See: https://www.raspberrypi.org/forums/posting.php?mode=reply&f=107&t=248439
+
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -23,6 +23,10 @@
+ mmc0 = &emmc2;
+ mmc1 = &mmcnr;
+ mmc2 = &sdhost;
++ i2c3 = &i2c3;
++ i2c4 = &i2c4;
++ i2c5 = &i2c5;
++ i2c6 = &i2c6;
+ /delete-property/ ethernet;
+ /delete-property/ intc;
+ ethernet0 = &genet;
+@@ -207,31 +211,37 @@
+ i2c0_pins: i2c0 {
+ brcm,pins = <0 1>;
+ brcm,function = <BCM2835_FSEL_ALT0>;
++ brcm,pull = <BCM2835_PUD_UP>;
+ };
+
+ i2c1_pins: i2c1 {
+ brcm,pins = <2 3>;
+ brcm,function = <BCM2835_FSEL_ALT0>;
++ brcm,pull = <BCM2835_PUD_UP>;
+ };
+
+ i2c3_pins: i2c3 {
+ brcm,pins = <4 5>;
+ brcm,function = <BCM2835_FSEL_ALT5>;
++ brcm,pull = <BCM2835_PUD_UP>;
+ };
+
+ i2c4_pins: i2c4 {
+ brcm,pins = <8 9>;
+ brcm,function = <BCM2835_FSEL_ALT5>;
++ brcm,pull = <BCM2835_PUD_UP>;
+ };
+
+ i2c5_pins: i2c5 {
+ brcm,pins = <12 13>;
+ brcm,function = <BCM2835_FSEL_ALT5>;
++ brcm,pull = <BCM2835_PUD_UP>;
+ };
+
+ i2c6_pins: i2c6 {
+ brcm,pins = <22 23>;
+ brcm,function = <BCM2835_FSEL_ALT5>;
++ brcm,pull = <BCM2835_PUD_UP>;
+ };
+
+ i2s_pins: i2s {
+++ /dev/null
-From 010e3665babdf589e26e2fb098ac1f39e519c0f6 Mon Sep 17 00:00:00 2001
-Date: Fri, 3 Aug 2018 11:22:31 +0200
-Subject: [PATCH] drm/vc4: Fix X/Y positioning of planes using T_TILES
- modifier
-
-X/Y positioning of T-format buffers is quite tricky and the current
-implementation was failing to position a plane using this format
-correctly when the CRTC X, Y or both X and Y offsets were negative.
-It was also failing when the SRC X/Y offsets were != 0.
-
----
- drivers/gpu/drm/vc4/vc4_plane.c | 50 ++++++++++++++++++++++++++++-----
- 1 file changed, 43 insertions(+), 7 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_plane.c
-+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -578,22 +578,58 @@ static int vc4_plane_mode_set(struct drm
- (i ? h_subsample : 1) *
- fb->format->cpp[i];
- }
-+
- break;
-
- case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
-- /* For T-tiled, the FB pitch is "how many bytes from
-- * one row to the next, such that pitch * tile_h ==
-- * tile_size * tiles_per_row."
-- */
- u32 tile_size_shift = 12; /* T tiles are 4kb */
-+ /* Whole-tile offsets, mostly for setting the pitch. */
-+ u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5;
- u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */
-+ u32 tile_w_mask = (1 << tile_w_shift) - 1;
-+ /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice
-+ * the height (in pixels) of a 4k tile.
-+ */
-+ u32 tile_h_mask = (2 << tile_h_shift) - 1;
-+ /* For T-tiled, the FB pitch is "how many bytes from one row to
-+ * the next, such that
-+ *
-+ * pitch * tile_h == tile_size * tiles_per_row
-+ */
- u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
-+ u32 tiles_l = vc4_state->src_x >> tile_w_shift;
-+ u32 tiles_r = tiles_w - tiles_l;
-+ u32 tiles_t = vc4_state->src_y >> tile_h_shift;
-+ /* Intra-tile offsets, which modify the base address (the
-+ * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
-+ * base address).
-+ */
-+ u32 tile_y = (vc4_state->src_y >> 4) & 1;
-+ u32 subtile_y = (vc4_state->src_y >> 2) & 3;
-+ u32 utile_y = vc4_state->src_y & 3;
-+ u32 x_off = vc4_state->src_x & tile_w_mask;
-+ u32 y_off = vc4_state->src_y & tile_h_mask;
-
- tiling = SCALER_CTL0_TILING_256B_OR_T;
-+ pitch0 = (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
-+ VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
-+ VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
-+ VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
-+ vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift);
-+ vc4_state->offsets[0] += subtile_y << 8;
-+ vc4_state->offsets[0] += utile_y << 4;
-+
-+ /* Rows of tiles alternate left-to-right and right-to-left. */
-+ if (tiles_t & 1) {
-+ pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR;
-+ vc4_state->offsets[0] += (tiles_w - tiles_l) <<
-+ tile_size_shift;
-+ vc4_state->offsets[0] -= (1 + !tile_y) << 10;
-+ } else {
-+ vc4_state->offsets[0] += tiles_l << tile_size_shift;
-+ vc4_state->offsets[0] += tile_y << 10;
-+ }
-
-- pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET) |
-- VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L) |
-- VC4_SET_FIELD(tiles_w, SCALER_PITCH0_TILE_WIDTH_R));
- break;
- }
-
+++ /dev/null
-From 0e81807e647c5e12fd897f3d520252ea60de3ff9 Mon Sep 17 00:00:00 2001
-Date: Thu, 15 Nov 2018 11:58:51 +0100
-Subject: [PATCH] drm/vc4: Fix NULL pointer dereference in the async
- update path
-
-vc4_plane_atomic_async_update() calls vc4_plane_atomic_check()
-which in turn calls vc4_plane_setup_clipping_and_scaling(), and since
-commit 58a6a36fe8e0 ("drm/vc4: Use
-drm_atomic_helper_check_plane_state() to simplify the logic"), this
-function accesses plane_state->state which will be NULL when called
-from the async update path because we're passing the current plane
-state, and plane_state->state has been assigned to NULL in
-drm_atomic_helper_swap_state().
-
-Pass the new state instead of the current one (the new state has
-->state set to a non-NULL value).
-
-Fixes: 58a6a36fe8e0 ("drm/vc4: Use drm_atomic_helper_check_plane_state() to simplify the logic")
----
- drivers/gpu/drm/vc4/vc4_plane.c | 15 +++++++++++++--
- 1 file changed, 13 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_plane.c
-+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -905,7 +905,7 @@ void vc4_plane_async_set_fb(struct drm_p
- static void vc4_plane_atomic_async_update(struct drm_plane *plane,
- struct drm_plane_state *state)
- {
-- struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
-+ struct vc4_plane_state *vc4_state, *new_vc4_state;
-
- if (plane->state->fb != state->fb) {
- vc4_plane_async_set_fb(plane, state->fb);
-@@ -927,7 +927,18 @@ static void vc4_plane_atomic_async_updat
- plane->state->src_y = state->src_y;
-
- /* Update the display list based on the new crtc_x/y. */
-- vc4_plane_atomic_check(plane, plane->state);
-+ vc4_plane_atomic_check(plane, state);
-+
-+ new_vc4_state = to_vc4_plane_state(state);
-+ vc4_state = to_vc4_plane_state(plane->state);
-+
-+ /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */
-+ vc4_state->dlist[vc4_state->pos0_offset] =
-+ new_vc4_state->dlist[vc4_state->pos0_offset];
-+ vc4_state->dlist[vc4_state->pos2_offset] =
-+ new_vc4_state->dlist[vc4_state->pos2_offset];
-+ vc4_state->dlist[vc4_state->ptr0_offset] =
-+ new_vc4_state->dlist[vc4_state->ptr0_offset];
-
- /* Note that we can't just call vc4_plane_write_dlist()
- * because that would smash the context data that the HVS is
--- /dev/null
+From c2e02902a3b75b24306dac06cb6f75b683fa0267 Mon Sep 17 00:00:00 2001
+Date: Tue, 13 Aug 2019 15:53:29 +0100
+Subject: [PATCH] xhci: Use more event ring segment table entries
+
+Users have reported log spam created by "Event Ring Full" xHC event
+TRBs. These are caused by interrupt latency in conjunction with a very
+busy set of devices on the bus. The errors are benign, but throughput
+will suffer as the xHC will pause processing of transfers until the
+event ring is drained by the kernel. Expand the number of event TRB slots
+available by increasing the number of event ring segments in the ERST.
+
+Controllers have a hardware-defined limit as to the number of ERST
+entries they can process, so make the actual number in use
+min(ERST_MAX_SEGS, hw_max).
+
+---
+ drivers/usb/host/xhci-mem.c | 8 +++++---
+ drivers/usb/host/xhci.h | 4 ++--
+ 2 files changed, 7 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -2495,9 +2495,11 @@ int xhci_mem_init(struct xhci_hcd *xhci,
+ * Event ring setup: Allocate a normal ring, but also setup
+ * the event ring segment table (ERST). Section 4.9.3.
+ */
++ val2 = 1 << HCS_ERST_MAX(xhci->hcs_params2);
++ val2 = min_t(unsigned int, ERST_MAX_SEGS, val2);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
+- xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
+- 0, flags);
++ xhci->event_ring = xhci_ring_alloc(xhci, val2, 1, TYPE_EVENT,
++ 0, flags);
+ if (!xhci->event_ring)
+ goto fail;
+ if (xhci_check_trb_in_td_math(xhci) < 0)
+@@ -2510,7 +2512,7 @@ int xhci_mem_init(struct xhci_hcd *xhci,
+ /* set ERST count with the number of entries in the segment table */
+ val = readl(&xhci->ir_set->erst_size);
+ val &= ERST_SIZE_MASK;
+- val |= ERST_NUM_SEGS;
++ val |= val2;
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Write ERST size = %i to ir_set 0 (some bits preserved)",
+ val);
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1643,8 +1643,8 @@ struct urb_priv {
+ * Each segment table entry is 4*32bits long. 1K seems like an ok size:
+ * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
+ * meaning 64 ring segments.
+- * Initial allocated size of the ERST, in number of entries */
+-#define ERST_NUM_SEGS 1
++ * Maximum number of segments in the ERST */
++#define ERST_MAX_SEGS 8
+ /* Initial allocated size of the ERST, in number of entries */
+ #define ERST_SIZE 64
+ /* Initial number of event segment rings allocated */
+++ /dev/null
-From 188bd7c0085ac5b3d966aa899c6be644907157ea Mon Sep 17 00:00:00 2001
-Date: Mon, 12 Aug 2019 15:48:39 +0100
-Subject: [PATCH] ARM: dts: bcm2711-rpi-4-b: I2C aliases and pulls
-
-The I2C interface nodes need aliases to give them fixed bus numbers,
-and setting the pulls on the GPIOs (particularly 9-13) increases the
-chances of the bus working with weak or absent external pulls.
-
-See: https://www.raspberrypi.org/forums/posting.php?mode=reply&f=107&t=248439
-
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -23,6 +23,10 @@
- mmc0 = &emmc2;
- mmc1 = &mmcnr;
- mmc2 = &sdhost;
-+ i2c3 = &i2c3;
-+ i2c4 = &i2c4;
-+ i2c5 = &i2c5;
-+ i2c6 = &i2c6;
- /delete-property/ ethernet;
- /delete-property/ intc;
- ethernet0 = &genet;
-@@ -207,31 +211,37 @@
- i2c0_pins: i2c0 {
- brcm,pins = <0 1>;
- brcm,function = <BCM2835_FSEL_ALT0>;
-+ brcm,pull = <BCM2835_PUD_UP>;
- };
-
- i2c1_pins: i2c1 {
- brcm,pins = <2 3>;
- brcm,function = <BCM2835_FSEL_ALT0>;
-+ brcm,pull = <BCM2835_PUD_UP>;
- };
-
- i2c3_pins: i2c3 {
- brcm,pins = <4 5>;
- brcm,function = <BCM2835_FSEL_ALT5>;
-+ brcm,pull = <BCM2835_PUD_UP>;
- };
-
- i2c4_pins: i2c4 {
- brcm,pins = <8 9>;
- brcm,function = <BCM2835_FSEL_ALT5>;
-+ brcm,pull = <BCM2835_PUD_UP>;
- };
-
- i2c5_pins: i2c5 {
- brcm,pins = <12 13>;
- brcm,function = <BCM2835_FSEL_ALT5>;
-+ brcm,pull = <BCM2835_PUD_UP>;
- };
-
- i2c6_pins: i2c6 {
- brcm,pins = <22 23>;
- brcm,function = <BCM2835_FSEL_ALT5>;
-+ brcm,pull = <BCM2835_PUD_UP>;
- };
-
- i2s_pins: i2s {
--- /dev/null
+From 0c6190fa3cfeafd773b51b751a473d6775c23309 Mon Sep 17 00:00:00 2001
+Date: Wed, 14 Aug 2019 14:35:50 +0100
+Subject: [PATCH] dwc_otg: use align_buf for small IN control transfers
+ (#3150)
+
+The hardware will do a 4-byte write to memory on any IN packet received
+that is between 1 and 3 bytes long. This tramples memory in the uvcvideo
+driver, as it uses a sequence of 1- and 2-byte control transfers to
+query the min/max/range/step of each individual camera control and
+gives us buffers that are offsets into a struct.
+
+Catch small control transfers in the data phase and use the align_buf
+to bounce the correct number of bytes into the URB's buffer.
+
+In general, short packets on non-control endpoints should be OK as URBs
+should have enough buffer space for a wMaxPacket size transfer.
+
+See: https://github.com/raspberrypi/linux/issues/3148
+
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+@@ -1182,6 +1182,7 @@ static void assign_and_init_hc(dwc_otg_h
+ dwc_otg_qtd_t *qtd;
+ dwc_otg_hcd_urb_t *urb;
+ void* ptr = NULL;
++ uint16_t wLength;
+ uint32_t intr_enable;
+ unsigned long flags;
+ gintmsk_data_t gintmsk = { .d32 = 0, };
+@@ -1293,6 +1294,23 @@ static void assign_and_init_hc(dwc_otg_h
+ break;
+ case DWC_OTG_CONTROL_DATA:
+ DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
++ /*
++ * Hardware bug: small IN packets with length < 4
++ * cause a 4-byte write to memory. We can only catch
++ * the case where we know a short packet is going to be
++ * returned in a control transfer, as the length is
++ * specified in the setup packet. This is only an issue
++ * for drivers that insist on packing a device's various
++ * properties into a struct and querying them one at a
++ * time (uvcvideo).
++ * Force the use of align_buf so that the subsequent
++ * memcpy puts the right number of bytes in the URB's
++ * buffer.
++ */
++ wLength = ((uint16_t *)urb->setup_packet)[3];
++ if (hc->ep_is_in && wLength < 4)
++ ptr = hc->xfer_buff;
++
+ hc->data_pid_start = qtd->data_toggle;
+ break;
+ case DWC_OTG_CONTROL_STATUS:
--- /dev/null
+From ccd23ce562e8223ba7c6acf7dcb7058ff89ff7ec Mon Sep 17 00:00:00 2001
+Date: Wed, 14 Aug 2019 15:22:55 +0100
+Subject: [PATCH] Ported pcie-brcmstb bounce buffer implementation to
+ ARM64. (#3144)
+
+Ported pcie-brcmstb bounce buffer implementation to ARM64.
+This enables full 4G RAM usage on Raspberry Pi in 64-bit mode.
+
+---
+ arch/arm64/include/asm/dma-mapping.h | 21 +
+ arch/arm64/mm/dma-mapping.c | 50 ++
+ drivers/pci/controller/Makefile | 3 +
+ drivers/pci/controller/pcie-brcmstb-bounce.h | 2 +-
+ .../pci/controller/pcie-brcmstb-bounce64.c | 576 ++++++++++++++++++
+ drivers/pci/controller/pcie-brcmstb.c | 30 +-
+ 6 files changed, 658 insertions(+), 24 deletions(-)
+ create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce64.c
+
+--- a/arch/arm64/include/asm/dma-mapping.h
++++ b/arch/arm64/include/asm/dma-mapping.h
+@@ -24,6 +24,27 @@
+ #include <xen/xen.h>
+ #include <asm/xen/hypervisor.h>
+
++extern void *arm64_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
++ gfp_t gfp, unsigned long attrs);
++extern void arm64_dma_free(struct device *dev, size_t size, void *cpu_addr,
++ dma_addr_t handle, unsigned long attrs);
++extern int arm64_dma_mmap(struct device *dev, struct vm_area_struct *vma,
++ void *cpu_addr, dma_addr_t dma_addr, size_t size,
++ unsigned long attrs);
++extern int arm64_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
++ void *cpu_addr, dma_addr_t dma_addr, size_t size,
++ unsigned long attrs);
++extern int arm64_dma_map_sg(struct device *dev, struct scatterlist *sgl, int nelems,
++ enum dma_data_direction dir, unsigned long attrs);
++extern void arm64_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, int,
++ enum dma_data_direction dir, unsigned long attrs);
++extern void arm64_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl, int nelems,
++ enum dma_data_direction dir);
++extern void arm64_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl, int nelems,
++ enum dma_data_direction dir);
++
++
++
+ extern const struct dma_map_ops dummy_dma_ops;
+
+ static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus)
+--- a/arch/arm64/mm/dma-mapping.c
++++ b/arch/arm64/mm/dma-mapping.c
+@@ -138,6 +138,12 @@ no_mem:
+ return NULL;
+ }
+
++void *arm64_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
++ gfp_t gfp, unsigned long attrs)
++{
++ return __dma_alloc(dev, size, handle, gfp, attrs);
++}
++
+ static void __dma_free(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ unsigned long attrs)
+@@ -154,6 +160,12 @@ static void __dma_free(struct device *de
+ swiotlb_free(dev, size, swiotlb_addr, dma_handle, attrs);
+ }
+
++void arm64_dma_free(struct device *dev, size_t size, void *cpu_addr,
++ dma_addr_t handle, unsigned long attrs)
++{
++ __dma_free(dev, size, cpu_addr, handle, attrs);
++}
++
+ static dma_addr_t __swiotlb_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir,
+@@ -197,6 +209,12 @@ static int __swiotlb_map_sg_attrs(struct
+ return ret;
+ }
+
++int arm64_dma_map_sg(struct device *dev, struct scatterlist *sgl, int nelems,
++ enum dma_data_direction dir, unsigned long attrs)
++{
++ return __swiotlb_map_sg_attrs(dev, sgl, nelems, dir, attrs);
++}
++
+ static void __swiotlb_unmap_sg_attrs(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir,
+@@ -213,6 +231,12 @@ static void __swiotlb_unmap_sg_attrs(str
+ swiotlb_unmap_sg_attrs(dev, sgl, nelems, dir, attrs);
+ }
+
++void arm64_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, int nelems,
++ enum dma_data_direction dir, unsigned long attrs)
++{
++ __swiotlb_unmap_sg_attrs(dev, sgl, nelems, dir, attrs);
++}
++
+ static void __swiotlb_sync_single_for_cpu(struct device *dev,
+ dma_addr_t dev_addr, size_t size,
+ enum dma_data_direction dir)
+@@ -245,6 +269,12 @@ static void __swiotlb_sync_sg_for_cpu(st
+ swiotlb_sync_sg_for_cpu(dev, sgl, nelems, dir);
+ }
+
++void arm64_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl, int nelems,
++ enum dma_data_direction dir)
++{
++ __swiotlb_sync_sg_for_cpu(dev, sgl, nelems, dir);
++}
++
+ static void __swiotlb_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir)
+@@ -259,6 +289,12 @@ static void __swiotlb_sync_sg_for_device
+ sg->length, dir);
+ }
+
++void arm64_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl, int nelems,
++ enum dma_data_direction dir)
++{
++ __swiotlb_sync_sg_for_device(dev, sgl, nelems, dir);
++}
++
+ static int __swiotlb_mmap_pfn(struct vm_area_struct *vma,
+ unsigned long pfn, size_t size)
+ {
+@@ -294,6 +330,13 @@ static int __swiotlb_mmap(struct device
+ return __swiotlb_mmap_pfn(vma, pfn, size);
+ }
+
++int arm64_dma_mmap(struct device *dev, struct vm_area_struct *vma,
++ void *cpu_addr, dma_addr_t dma_addr, size_t size,
++ unsigned long attrs)
++{
++ return __swiotlb_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
++}
++
+ static int __swiotlb_get_sgtable_page(struct sg_table *sgt,
+ struct page *page, size_t size)
+ {
+@@ -314,6 +357,13 @@ static int __swiotlb_get_sgtable(struct
+ return __swiotlb_get_sgtable_page(sgt, page, size);
+ }
+
++int arm64_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
++ void *cpu_addr, dma_addr_t dma_addr, size_t size,
++ unsigned long attrs)
++{
++ return __swiotlb_get_sgtable(dev, sgt, cpu_addr, dma_addr, size, attrs);
++}
++
+ static int __swiotlb_dma_supported(struct device *hwdev, u64 mask)
+ {
+ if (swiotlb)
+--- a/drivers/pci/controller/Makefile
++++ b/drivers/pci/controller/Makefile
+@@ -32,6 +32,9 @@ obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcms
+ ifdef CONFIG_ARM
+ obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce.o
+ endif
++ifdef CONFIG_ARM64
++obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce64.o
++endif
+
+ obj-$(CONFIG_VMD) += vmd.o
+ # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
+--- a/drivers/pci/controller/pcie-brcmstb-bounce.h
++++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
+@@ -6,7 +6,7 @@
+ #ifndef _PCIE_BRCMSTB_BOUNCE_H
+ #define _PCIE_BRCMSTB_BOUNCE_H
+
+-#ifdef CONFIG_ARM
++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+
+ int brcm_pcie_bounce_init(struct device *dev, unsigned long buffer_size,
+ dma_addr_t threshold);
+--- /dev/null
++++ b/drivers/pci/controller/pcie-brcmstb-bounce64.c
+@@ -0,0 +1,576 @@
++/*
++ * This code started out as a version of arch/arm/common/dmabounce.c,
++ * modified to cope with highmem pages. Now it has been changed heavily -
++ * it now preallocates a large block (currently 4MB) and carves it up
++ * sequentially in ring fashion, and DMA is used to copy the data - to the
++ * point where very little of the original remains.
++ *
++ * Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
++ *
++ *
++ * Copyright (C) 2002 Hewlett Packard Company.
++ * Copyright (C) 2004 MontaVista Software, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/page-flags.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/dma-direct.h>
++#include <linux/dmapool.h>
++#include <linux/list.h>
++#include <linux/scatterlist.h>
++#include <linux/bitmap.h>
++#include <linux/swiotlb.h>
++
++#include <asm/cacheflush.h>
++
++#define STATS
++
++#ifdef STATS
++#define DO_STATS(X) do { X ; } while (0)
++#else
++#define DO_STATS(X) do { } while (0)
++#endif
++
++/* ************************************************** */
++
++struct safe_buffer {
++ struct list_head node;
++
++ /* original request */
++ size_t size;
++ int direction;
++
++ struct dmabounce_pool *pool;
++ void *safe;
++ dma_addr_t unsafe_dma_addr;
++ dma_addr_t safe_dma_addr;
++};
++
++struct dmabounce_pool {
++ unsigned long pages;
++ void *virt_addr;
++ dma_addr_t dma_addr;
++ unsigned long *alloc_map;
++ unsigned long alloc_pos;
++ spinlock_t lock;
++ struct device *dev;
++ unsigned long num_pages;
++#ifdef STATS
++ size_t max_size;
++ unsigned long num_bufs;
++ unsigned long max_bufs;
++ unsigned long max_pages;
++#endif
++};
++
++struct dmabounce_device_info {
++ struct device *dev;
++ dma_addr_t threshold;
++ struct list_head safe_buffers;
++ struct dmabounce_pool pool;
++ rwlock_t lock;
++#ifdef STATS
++ unsigned long map_count;
++ unsigned long unmap_count;
++ unsigned long sync_dev_count;
++ unsigned long sync_cpu_count;
++ unsigned long fail_count;
++ int attr_res;
++#endif
++};
++
++static struct dmabounce_device_info *g_dmabounce_device_info;
++
++extern int bcm2838_dma40_memcpy_init(void);
++extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
++
++#ifdef STATS
++static ssize_t
++bounce_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
++ return sprintf(buf, "m:%lu/%lu s:%lu/%lu f:%lu s:%zu b:%lu/%lu a:%lu/%lu\n",
++ device_info->map_count,
++ device_info->unmap_count,
++ device_info->sync_dev_count,
++ device_info->sync_cpu_count,
++ device_info->fail_count,
++ device_info->pool.max_size,
++ device_info->pool.num_bufs,
++ device_info->pool.max_bufs,
++ device_info->pool.num_pages * PAGE_SIZE,
++ device_info->pool.max_pages * PAGE_SIZE);
++}
++
++static DEVICE_ATTR(dmabounce_stats, 0444, bounce_show, NULL);
++#endif
++
++static int bounce_create(struct dmabounce_pool *pool, struct device *dev,
++ unsigned long buffer_size)
++{
++ int ret = -ENOMEM;
++ pool->pages = (buffer_size + PAGE_SIZE - 1)/PAGE_SIZE;
++ pool->alloc_map = bitmap_zalloc(pool->pages, GFP_KERNEL);
++ if (!pool->alloc_map)
++ goto err_bitmap;
++ pool->virt_addr = dma_alloc_coherent(dev, pool->pages * PAGE_SIZE,
++ &pool->dma_addr, GFP_KERNEL);
++ if (!pool->virt_addr)
++ goto err_dmabuf;
++
++ pool->alloc_pos = 0;
++ spin_lock_init(&pool->lock);
++ pool->dev = dev;
++ pool->num_pages = 0;
++
++ DO_STATS(pool->max_size = 0);
++ DO_STATS(pool->num_bufs = 0);
++ DO_STATS(pool->max_bufs = 0);
++ DO_STATS(pool->max_pages = 0);
++
++ return 0;
++
++err_dmabuf:
++ bitmap_free(pool->alloc_map);
++err_bitmap:
++ return ret;
++}
++
++static void bounce_destroy(struct dmabounce_pool *pool)
++{
++ dma_free_coherent(pool->dev, pool->pages * PAGE_SIZE, pool->virt_addr,
++ pool->dma_addr);
++
++ bitmap_free(pool->alloc_map);
++}
++
++static void *bounce_alloc(struct dmabounce_pool *pool, size_t size,
++ dma_addr_t *dmaaddrp)
++{
++ unsigned long pages;
++ unsigned long flags;
++ unsigned long pos;
++
++ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
++
++ DO_STATS(pool->max_size = max(size, pool->max_size));
++
++ spin_lock_irqsave(&pool->lock, flags);
++ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
++ pool->alloc_pos, pages, 0);
++ /* If not found, try from the start */
++ if (pos >= pool->pages && pool->alloc_pos)
++ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
++ 0, pages, 0);
++
++ if (pos >= pool->pages) {
++ spin_unlock_irqrestore(&pool->lock, flags);
++ return NULL;
++ }
++
++ bitmap_set(pool->alloc_map, pos, pages);
++ pool->alloc_pos = (pos + pages) % pool->pages;
++ pool->num_pages += pages;
++
++ DO_STATS(pool->num_bufs++);
++ DO_STATS(pool->max_bufs = max(pool->num_bufs, pool->max_bufs));
++ DO_STATS(pool->max_pages = max(pool->num_pages, pool->max_pages));
++
++ spin_unlock_irqrestore(&pool->lock, flags);
++
++ *dmaaddrp = pool->dma_addr + pos * PAGE_SIZE;
++
++ return pool->virt_addr + pos * PAGE_SIZE;
++}
++
++static void
++bounce_free(struct dmabounce_pool *pool, void *buf, size_t size)
++{
++ unsigned long pages;
++ unsigned long flags;
++ unsigned long pos;
++
++ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
++ pos = (buf - pool->virt_addr)/PAGE_SIZE;
++
++ BUG_ON((buf - pool->virt_addr) & (PAGE_SIZE - 1));
++
++ spin_lock_irqsave(&pool->lock, flags);
++ bitmap_clear(pool->alloc_map, pos, pages);
++ pool->num_pages -= pages;
++ if (pool->num_pages == 0)
++ pool->alloc_pos = 0;
++ DO_STATS(pool->num_bufs--);
++ spin_unlock_irqrestore(&pool->lock, flags);
++}
++
++/* allocate a 'safe' buffer and keep track of it */
++static struct safe_buffer *
++alloc_safe_buffer(struct dmabounce_device_info *device_info,
++ dma_addr_t dma_addr, size_t size, enum dma_data_direction dir)
++{
++ struct safe_buffer *buf;
++ struct dmabounce_pool *pool = &device_info->pool;
++ struct device *dev = device_info->dev;
++ unsigned long flags;
++
++ /*
++ * Although one might expect this to be called in thread context,
++ * using GFP_KERNEL here leads to hard-to-debug lockups. in_atomic()
++ * was previously used to select the appropriate allocation mode,
++ * but this is unsafe.
++ */
++ buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
++ if (!buf) {
++ dev_warn(dev, "%s: kmalloc failed\n", __func__);
++ return NULL;
++ }
++
++ buf->unsafe_dma_addr = dma_addr;
++ buf->size = size;
++ buf->direction = dir;
++ buf->pool = pool;
++
++ buf->safe = bounce_alloc(pool, size, &buf->safe_dma_addr);
++
++ if (!buf->safe) {
++ dev_warn(dev,
++ "%s: could not alloc dma memory (size=%d)\n",
++ __func__, size);
++ kfree(buf);
++ return NULL;
++ }
++
++ write_lock_irqsave(&device_info->lock, flags);
++ list_add(&buf->node, &device_info->safe_buffers);
++ write_unlock_irqrestore(&device_info->lock, flags);
++
++ return buf;
++}
++
++/* determine if a buffer is from our "safe" pool */
++static struct safe_buffer *
++find_safe_buffer(struct dmabounce_device_info *device_info,
++ dma_addr_t safe_dma_addr)
++{
++ struct safe_buffer *b, *rb = NULL;
++ unsigned long flags;
++
++ read_lock_irqsave(&device_info->lock, flags);
++
++ list_for_each_entry(b, &device_info->safe_buffers, node)
++ if (b->safe_dma_addr <= safe_dma_addr &&
++ b->safe_dma_addr + b->size > safe_dma_addr) {
++ rb = b;
++ break;
++ }
++
++ read_unlock_irqrestore(&device_info->lock, flags);
++ return rb;
++}
++
++static void
++free_safe_buffer(struct dmabounce_device_info *device_info,
++ struct safe_buffer *buf)
++{
++ unsigned long flags;
++
++ write_lock_irqsave(&device_info->lock, flags);
++ list_del(&buf->node);
++ write_unlock_irqrestore(&device_info->lock, flags);
++
++ bounce_free(buf->pool, buf->safe, buf->size);
++
++ kfree(buf);
++}
++
++/* ************************************************** */
++
++static struct safe_buffer *
++find_safe_buffer_dev(struct device *dev, dma_addr_t dma_addr, const char *where)
++{
++ if (!dev || !g_dmabounce_device_info)
++ return NULL;
++ if (dma_mapping_error(dev, dma_addr)) {
++ dev_err(dev, "Trying to %s invalid mapping\n", where);
++ return NULL;
++ }
++ return find_safe_buffer(g_dmabounce_device_info, dma_addr);
++}
++
++static dma_addr_t
++map_single(struct device *dev, struct safe_buffer *buf, size_t size,
++ enum dma_data_direction dir, unsigned long attrs)
++{
++ BUG_ON(buf->size != size);
++ BUG_ON(buf->direction != dir);
++
++ dev_dbg(dev, "map: %llx->%llx\n", (u64)buf->unsafe_dma_addr,
++ (u64)buf->safe_dma_addr);
++
++ if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
++ !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
++ bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
++ size);
++
++ return buf->safe_dma_addr;
++}
++
++static dma_addr_t
++unmap_single(struct device *dev, struct safe_buffer *buf, size_t size,
++ enum dma_data_direction dir, unsigned long attrs)
++{
++ BUG_ON(buf->size != size);
++ BUG_ON(buf->direction != dir);
++
++ if ((dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) &&
++ !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
++ dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
++ (u64)buf->unsafe_dma_addr);
++
++ bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
++ size);
++ }
++ return buf->unsafe_dma_addr;
++}
++
++/* ************************************************** */
++
++/*
++ * see if a buffer address is in an 'unsafe' range. if it is
++ * allocate a 'safe' buffer and copy the unsafe buffer into it.
++ * substitute the safe buffer for the unsafe one.
++ * (basically move the buffer from an unsafe area to a safe one)
++ */
++static dma_addr_t
++dmabounce_map_page(struct device *dev, struct page *page, unsigned long offset,
++ size_t size, enum dma_data_direction dir,
++ unsigned long attrs)
++{
++ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
++ dma_addr_t dma_addr;
++
++ dma_addr = phys_to_dma(dev, page_to_phys(page)) + offset;
++
++ swiotlb_sync_single_for_device(dev, dma_addr, size, dir);
++ if (!is_device_dma_coherent(dev))
++ __dma_map_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
++
++ if (device_info && (dma_addr + size) > device_info->threshold) {
++ struct safe_buffer *buf;
++
++ buf = alloc_safe_buffer(device_info, dma_addr, size, dir);
++ if (!buf) {
++ DO_STATS(device_info->fail_count++);
++ return (~(dma_addr_t)0x0);
++ }
++
++ DO_STATS(device_info->map_count++);
++
++ dma_addr = map_single(dev, buf, size, dir, attrs);
++ }
++ return dma_addr;
++}
++
++/*
++ * see if a mapped address was really a "safe" buffer and if so, copy
++ * the data from the safe buffer back to the unsafe buffer and free up
++ * the safe buffer. (basically return things back to the way they
++ * should be)
++ */
++static void
++dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
++ enum dma_data_direction dir, unsigned long attrs)
++{
++ struct safe_buffer *buf;
++
++ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
++ if (buf) {
++ DO_STATS(g_dmabounce_device_info->unmap_count++);
++ dma_addr = unmap_single(dev, buf, size, dir, attrs);
++ free_safe_buffer(g_dmabounce_device_info, buf);
++ }
++
++ if (!is_device_dma_coherent(dev))
++ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
++ swiotlb_sync_single_for_cpu(dev, dma_addr, size, dir);
++}
++
++/*
++ * A version of dmabounce_map_page that assumes the mapping has already
++ * been created - intended for streaming operation.
++ */
++static void
++dmabounce_sync_for_device(struct device *dev, dma_addr_t dma_addr, size_t size,
++ enum dma_data_direction dir)
++{
++ struct safe_buffer *buf;
++
++ swiotlb_sync_single_for_device(dev, dma_addr, size, dir);
++ if (!is_device_dma_coherent(dev))
++ __dma_map_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
++
++ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
++ if (buf) {
++ DO_STATS(g_dmabounce_device_info->sync_dev_count++);
++ map_single(dev, buf, size, dir, 0);
++ }
++}
++
++/*
++ * A version of dmabounce_unmap_page that doesn't destroy the mapping -
++ * intended for streaming operation.
++ */
++static void
++dmabounce_sync_for_cpu(struct device *dev, dma_addr_t dma_addr,
++ size_t size, enum dma_data_direction dir)
++{
++ struct safe_buffer *buf;
++
++ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
++ if (buf) {
++ DO_STATS(g_dmabounce_device_info->sync_cpu_count++);
++ dma_addr = unmap_single(dev, buf, size, dir, 0);
++ }
++
++ if (!is_device_dma_coherent(dev))
++ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
++ swiotlb_sync_single_for_cpu(dev, dma_addr, size, dir);
++}
++
++static int dmabounce_dma_supported(struct device *dev, u64 dma_mask)
++{
++ if (g_dmabounce_device_info)
++ return 0;
++
++ return swiotlb_dma_supported(dev, dma_mask);
++}
++
++static int dmabounce_mapping_error(struct device *dev, dma_addr_t dma_addr)
++{
++ return swiotlb_dma_mapping_error(dev, dma_addr);
++}
++
++static const struct dma_map_ops dmabounce_ops = {
++ .alloc = arm64_dma_alloc,
++ .free = arm64_dma_free,
++ .mmap = arm64_dma_mmap,
++ .get_sgtable = arm64_dma_get_sgtable,
++ .map_page = dmabounce_map_page,
++ .unmap_page = dmabounce_unmap_page,
++ .sync_single_for_cpu = dmabounce_sync_for_cpu,
++ .sync_single_for_device = dmabounce_sync_for_device,
++ .map_sg = arm64_dma_map_sg,
++ .unmap_sg = arm64_dma_unmap_sg,
++ .sync_sg_for_cpu = arm64_dma_sync_sg_for_cpu,
++ .sync_sg_for_device = arm64_dma_sync_sg_for_device,
++ .dma_supported = dmabounce_dma_supported,
++ .mapping_error = dmabounce_mapping_error,
++};
++
++int brcm_pcie_bounce_init(struct device *dev,
++ unsigned long buffer_size,
++ dma_addr_t threshold)
++{
++ struct dmabounce_device_info *device_info;
++ int ret;
++
++ /* Only support a single client */
++ if (g_dmabounce_device_info)
++ return -EBUSY;
++
++ ret = bcm2838_dma40_memcpy_init();
++ if (ret)
++ return ret;
++
++ device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
++ if (!device_info) {
++ dev_err(dev,
++ "Could not allocated dmabounce_device_info\n");
++ return -ENOMEM;
++ }
++
++ ret = bounce_create(&device_info->pool, dev, buffer_size);
++ if (ret) {
++ dev_err(dev,
++ "dmabounce: could not allocate %ld byte DMA pool\n",
++ buffer_size);
++ goto err_bounce;
++ }
++
++ device_info->dev = dev;
++ device_info->threshold = threshold;
++ INIT_LIST_HEAD(&device_info->safe_buffers);
++ rwlock_init(&device_info->lock);
++
++ DO_STATS(device_info->map_count = 0);
++ DO_STATS(device_info->unmap_count = 0);
++ DO_STATS(device_info->sync_dev_count = 0);
++ DO_STATS(device_info->sync_cpu_count = 0);
++ DO_STATS(device_info->fail_count = 0);
++ DO_STATS(device_info->attr_res =
++ device_create_file(dev, &dev_attr_dmabounce_stats));
++
++ g_dmabounce_device_info = device_info;
++
++ dev_err(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
++ buffer_size / 1024, &threshold);
++
++ return 0;
++
++ err_bounce:
++ kfree(device_info);
++ return ret;
++}
++EXPORT_SYMBOL(brcm_pcie_bounce_init);
++
++void brcm_pcie_bounce_uninit(struct device *dev)
++{
++ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
++
++ g_dmabounce_device_info = NULL;
++
++ if (!device_info) {
++ dev_warn(dev,
++ "Never registered with dmabounce but attempting"
++ "to unregister!\n");
++ return;
++ }
++
++ if (!list_empty(&device_info->safe_buffers)) {
++ dev_err(dev,
++ "Removing from dmabounce with pending buffers!\n");
++ BUG();
++ }
++
++ bounce_destroy(&device_info->pool);
++
++ DO_STATS(if (device_info->attr_res == 0)
++ device_remove_file(dev, &dev_attr_dmabounce_stats));
++
++ kfree(device_info);
++}
++EXPORT_SYMBOL(brcm_pcie_bounce_uninit);
++
++int brcm_pcie_bounce_register_dev(struct device *dev)
++{
++ set_dma_ops(dev, &dmabounce_ops);
++
++ return 0;
++}
++EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
++
++MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
++MODULE_LICENSE("GPL");
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -617,28 +617,6 @@ static const struct dma_map_ops brcm_dma
+
+ static void brcm_set_dma_ops(struct device *dev)
+ {
+- int ret;
+-
+- if (IS_ENABLED(CONFIG_ARM64)) {
+- /*
+- * We are going to invoke get_dma_ops(). That
+- * function, at this point in time, invokes
+- * get_arch_dma_ops(), and for ARM64 that function
+- * returns a pointer to dummy_dma_ops. So then we'd
+- * like to call arch_setup_dma_ops(), but that isn't
+- * exported. Instead, we call of_dma_configure(),
+- * which is exported, and this calls
+- * arch_setup_dma_ops(). Once we do this the call to
+- * get_dma_ops() will work properly because
+- * dev->dma_ops will be set.
+- */
+- ret = of_dma_configure(dev, dev->of_node, true);
+- if (ret) {
+- dev_err(dev, "of_dma_configure() failed: %d\n", ret);
+- return;
+- }
+- }
+-
+ arch_dma_ops = get_dma_ops(dev);
+ if (!arch_dma_ops) {
+ dev_err(dev, "failed to get arch_dma_ops\n");
+@@ -657,12 +635,12 @@ static int brcmstb_platform_notifier(str
+ extern unsigned long max_pfn;
+ struct device *dev = __dev;
+ const char *rc_name = "0000:00:00.0";
++ int ret;
+
+ switch (event) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ if (max_pfn > (bounce_threshold/PAGE_SIZE) &&
+ strcmp(dev->kobj.name, rc_name)) {
+- int ret;
+
+ ret = brcm_pcie_bounce_register_dev(dev);
+ if (ret) {
+@@ -671,6 +649,12 @@ static int brcmstb_platform_notifier(str
+ ret);
+ return ret;
+ }
++ } else if (IS_ENABLED(CONFIG_ARM64)) {
++ ret = of_dma_configure(dev, dev->of_node, true);
++ if (ret) {
++ dev_err(dev, "of_dma_configure() failed: %d\n", ret);
++ return;
++ }
+ }
+ brcm_set_dma_ops(dev);
+ return NOTIFY_OK;
+++ /dev/null
-From c2e02902a3b75b24306dac06cb6f75b683fa0267 Mon Sep 17 00:00:00 2001
-Date: Tue, 13 Aug 2019 15:53:29 +0100
-Subject: [PATCH] xhci: Use more event ring segment table entries
-
-Users have reported log spam created by "Event Ring Full" xHC event
-TRBs. These are caused by interrupt latency in conjunction with a very
-busy set of devices on the bus. The errors are benign, but throughput
-will suffer as the xHC will pause processing of transfers until the
-event ring is drained by the kernel. Expand the number of event TRB slots
-available by increasing the number of event ring segments in the ERST.
-
-Controllers have a hardware-defined limit as to the number of ERST
-entries they can process, so make the actual number in use
-min(ERST_MAX_SEGS, hw_max).
-
----
- drivers/usb/host/xhci-mem.c | 8 +++++---
- drivers/usb/host/xhci.h | 4 ++--
- 2 files changed, 7 insertions(+), 5 deletions(-)
-
---- a/drivers/usb/host/xhci-mem.c
-+++ b/drivers/usb/host/xhci-mem.c
-@@ -2495,9 +2495,11 @@ int xhci_mem_init(struct xhci_hcd *xhci,
- * Event ring setup: Allocate a normal ring, but also setup
- * the event ring segment table (ERST). Section 4.9.3.
- */
-+ val2 = 1 << HCS_ERST_MAX(xhci->hcs_params2);
-+ val2 = min_t(unsigned int, ERST_MAX_SEGS, val2);
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
-- xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
-- 0, flags);
-+ xhci->event_ring = xhci_ring_alloc(xhci, val2, 1, TYPE_EVENT,
-+ 0, flags);
- if (!xhci->event_ring)
- goto fail;
- if (xhci_check_trb_in_td_math(xhci) < 0)
-@@ -2510,7 +2512,7 @@ int xhci_mem_init(struct xhci_hcd *xhci,
- /* set ERST count with the number of entries in the segment table */
- val = readl(&xhci->ir_set->erst_size);
- val &= ERST_SIZE_MASK;
-- val |= ERST_NUM_SEGS;
-+ val |= val2;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Write ERST size = %i to ir_set 0 (some bits preserved)",
- val);
---- a/drivers/usb/host/xhci.h
-+++ b/drivers/usb/host/xhci.h
-@@ -1643,8 +1643,8 @@ struct urb_priv {
- * Each segment table entry is 4*32bits long. 1K seems like an ok size:
- * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
- * meaning 64 ring segments.
-- * Initial allocated size of the ERST, in number of entries */
--#define ERST_NUM_SEGS 1
-+ * Maximum number of segments in the ERST */
-+#define ERST_MAX_SEGS 8
- /* Initial allocated size of the ERST, in number of entries */
- #define ERST_SIZE 64
- /* Initial number of event segment rings allocated */
--- /dev/null
+From 709962264bec8f8483df374da5e946c982348e87 Mon Sep 17 00:00:00 2001
+Date: Thu, 15 Aug 2019 12:02:34 +0100
+Subject: [PATCH] configs: arm64/vcm2711: Enable V3D
+
+Enable the V3D driver, which depends on BCM2835_POWER.
+
+Originally submitted by GitHub user 'phire' in a slightly different
+form.
+
+See: https://github.com/raspberrypi/linux/pull/3063
+
+---
+ drivers/gpu/drm/v3d/Kconfig | 2 +-
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/v3d/Kconfig
++++ b/drivers/gpu/drm/v3d/Kconfig
+@@ -1,6 +1,6 @@
+ config DRM_V3D
+ tristate "Broadcom V3D 3.x and newer"
+- depends on ARCH_BCM || ARCH_BCMSTB || COMPILE_TEST
++ depends on ARCH_BCM || ARCH_BCMSTB || ARCH_BCM2835 || COMPILE_TEST
+ depends on DRM
+ depends on COMMON_CLK
+ depends on MMU
+++ /dev/null
-From 0c6190fa3cfeafd773b51b751a473d6775c23309 Mon Sep 17 00:00:00 2001
-Date: Wed, 14 Aug 2019 14:35:50 +0100
-Subject: [PATCH] dwc_otg: use align_buf for small IN control transfers
- (#3150)
-
-The hardware will do a 4-byte write to memory on any IN packet received
-that is between 1 and 3 bytes long. This tramples memory in the uvcvideo
-driver, as it uses a sequence of 1- and 2-byte control transfers to
-query the min/max/range/step of each individual camera control and
-gives us buffers that are offsets into a struct.
-
-Catch small control transfers in the data phase and use the align_buf
-to bounce the correct number of bytes into the URB's buffer.
-
-In general, short packets on non-control endpoints should be OK as URBs
-should have enough buffer space for a wMaxPacket size transfer.
-
-See: https://github.com/raspberrypi/linux/issues/3148
-
----
- drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 18 ++++++++++++++++++
- 1 file changed, 18 insertions(+)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-@@ -1182,6 +1182,7 @@ static void assign_and_init_hc(dwc_otg_h
- dwc_otg_qtd_t *qtd;
- dwc_otg_hcd_urb_t *urb;
- void* ptr = NULL;
-+ uint16_t wLength;
- uint32_t intr_enable;
- unsigned long flags;
- gintmsk_data_t gintmsk = { .d32 = 0, };
-@@ -1293,6 +1294,23 @@ static void assign_and_init_hc(dwc_otg_h
- break;
- case DWC_OTG_CONTROL_DATA:
- DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
-+ /*
-+ * Hardware bug: small IN packets with length < 4
-+ * cause a 4-byte write to memory. We can only catch
-+ * the case where we know a short packet is going to be
-+ * returned in a control transfer, as the length is
-+ * specified in the setup packet. This is only an issue
-+ * for drivers that insist on packing a device's various
-+ * properties into a struct and querying them one at a
-+ * time (uvcvideo).
-+ * Force the use of align_buf so that the subsequent
-+ * memcpy puts the right number of bytes in the URB's
-+ * buffer.
-+ */
-+ wLength = ((uint16_t *)urb->setup_packet)[3];
-+ if (hc->ep_is_in && wLength < 4)
-+ ptr = hc->xfer_buff;
-+
- hc->data_pid_start = qtd->data_toggle;
- break;
- case DWC_OTG_CONTROL_STATUS:
+++ /dev/null
-From ccd23ce562e8223ba7c6acf7dcb7058ff89ff7ec Mon Sep 17 00:00:00 2001
-Date: Wed, 14 Aug 2019 15:22:55 +0100
-Subject: [PATCH] Ported pcie-brcmstb bounce buffer implementation to
- ARM64. (#3144)
-
-Ported pcie-brcmstb bounce buffer implementation to ARM64.
-This enables full 4G RAM usage on Raspberry Pi in 64-bit mode.
-
----
- arch/arm64/include/asm/dma-mapping.h | 21 +
- arch/arm64/mm/dma-mapping.c | 50 ++
- drivers/pci/controller/Makefile | 3 +
- drivers/pci/controller/pcie-brcmstb-bounce.h | 2 +-
- .../pci/controller/pcie-brcmstb-bounce64.c | 576 ++++++++++++++++++
- drivers/pci/controller/pcie-brcmstb.c | 30 +-
- 6 files changed, 658 insertions(+), 24 deletions(-)
- create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce64.c
-
---- a/arch/arm64/include/asm/dma-mapping.h
-+++ b/arch/arm64/include/asm/dma-mapping.h
-@@ -24,6 +24,27 @@
- #include <xen/xen.h>
- #include <asm/xen/hypervisor.h>
-
-+extern void *arm64_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-+ gfp_t gfp, unsigned long attrs);
-+extern void arm64_dma_free(struct device *dev, size_t size, void *cpu_addr,
-+ dma_addr_t handle, unsigned long attrs);
-+extern int arm64_dma_mmap(struct device *dev, struct vm_area_struct *vma,
-+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
-+ unsigned long attrs);
-+extern int arm64_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
-+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
-+ unsigned long attrs);
-+extern int arm64_dma_map_sg(struct device *dev, struct scatterlist *sgl, int nelems,
-+ enum dma_data_direction dir, unsigned long attrs);
-+extern void arm64_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, int,
-+ enum dma_data_direction dir, unsigned long attrs);
-+extern void arm64_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl, int nelems,
-+ enum dma_data_direction dir);
-+extern void arm64_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl, int nelems,
-+ enum dma_data_direction dir);
-+
-+
-+
- extern const struct dma_map_ops dummy_dma_ops;
-
- static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus)
---- a/arch/arm64/mm/dma-mapping.c
-+++ b/arch/arm64/mm/dma-mapping.c
-@@ -138,6 +138,12 @@ no_mem:
- return NULL;
- }
-
-+void *arm64_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-+ gfp_t gfp, unsigned long attrs)
-+{
-+ return __dma_alloc(dev, size, handle, gfp, attrs);
-+}
-+
- static void __dma_free(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle,
- unsigned long attrs)
-@@ -154,6 +160,12 @@ static void __dma_free(struct device *de
- swiotlb_free(dev, size, swiotlb_addr, dma_handle, attrs);
- }
-
-+void arm64_dma_free(struct device *dev, size_t size, void *cpu_addr,
-+ dma_addr_t handle, unsigned long attrs)
-+{
-+ __dma_free(dev, size, cpu_addr, handle, attrs);
-+}
-+
- static dma_addr_t __swiotlb_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size,
- enum dma_data_direction dir,
-@@ -197,6 +209,12 @@ static int __swiotlb_map_sg_attrs(struct
- return ret;
- }
-
-+int arm64_dma_map_sg(struct device *dev, struct scatterlist *sgl, int nelems,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ return __swiotlb_map_sg_attrs(dev, sgl, nelems, dir, attrs);
-+}
-+
- static void __swiotlb_unmap_sg_attrs(struct device *dev,
- struct scatterlist *sgl, int nelems,
- enum dma_data_direction dir,
-@@ -213,6 +231,12 @@ static void __swiotlb_unmap_sg_attrs(str
- swiotlb_unmap_sg_attrs(dev, sgl, nelems, dir, attrs);
- }
-
-+void arm64_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, int nelems,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ __swiotlb_unmap_sg_attrs(dev, sgl, nelems, dir, attrs);
-+}
-+
- static void __swiotlb_sync_single_for_cpu(struct device *dev,
- dma_addr_t dev_addr, size_t size,
- enum dma_data_direction dir)
-@@ -245,6 +269,12 @@ static void __swiotlb_sync_sg_for_cpu(st
- swiotlb_sync_sg_for_cpu(dev, sgl, nelems, dir);
- }
-
-+void arm64_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl, int nelems,
-+ enum dma_data_direction dir)
-+{
-+ __swiotlb_sync_sg_for_cpu(dev, sgl, nelems, dir);
-+}
-+
- static void __swiotlb_sync_sg_for_device(struct device *dev,
- struct scatterlist *sgl, int nelems,
- enum dma_data_direction dir)
-@@ -259,6 +289,12 @@ static void __swiotlb_sync_sg_for_device
- sg->length, dir);
- }
-
-+void arm64_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl, int nelems,
-+ enum dma_data_direction dir)
-+{
-+ __swiotlb_sync_sg_for_device(dev, sgl, nelems, dir);
-+}
-+
- static int __swiotlb_mmap_pfn(struct vm_area_struct *vma,
- unsigned long pfn, size_t size)
- {
-@@ -294,6 +330,13 @@ static int __swiotlb_mmap(struct device
- return __swiotlb_mmap_pfn(vma, pfn, size);
- }
-
-+int arm64_dma_mmap(struct device *dev, struct vm_area_struct *vma,
-+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
-+ unsigned long attrs)
-+{
-+ return __swiotlb_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
-+}
-+
- static int __swiotlb_get_sgtable_page(struct sg_table *sgt,
- struct page *page, size_t size)
- {
-@@ -314,6 +357,13 @@ static int __swiotlb_get_sgtable(struct
- return __swiotlb_get_sgtable_page(sgt, page, size);
- }
-
-+int arm64_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
-+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
-+ unsigned long attrs)
-+{
-+ return __swiotlb_get_sgtable(dev, sgt, cpu_addr, dma_addr, size, attrs);
-+}
-+
- static int __swiotlb_dma_supported(struct device *hwdev, u64 mask)
- {
- if (swiotlb)
---- a/drivers/pci/controller/Makefile
-+++ b/drivers/pci/controller/Makefile
-@@ -32,6 +32,9 @@ obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcms
- ifdef CONFIG_ARM
- obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce.o
- endif
-+ifdef CONFIG_ARM64
-+obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce64.o
-+endif
-
- obj-$(CONFIG_VMD) += vmd.o
- # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
---- a/drivers/pci/controller/pcie-brcmstb-bounce.h
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
-@@ -6,7 +6,7 @@
- #ifndef _PCIE_BRCMSTB_BOUNCE_H
- #define _PCIE_BRCMSTB_BOUNCE_H
-
--#ifdef CONFIG_ARM
-+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
-
- int brcm_pcie_bounce_init(struct device *dev, unsigned long buffer_size,
- dma_addr_t threshold);
---- /dev/null
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce64.c
-@@ -0,0 +1,576 @@
-+/*
-+ * This code started out as a version of arch/arm/common/dmabounce.c,
-+ * modified to cope with highmem pages. Now it has been changed heavily -
-+ * it now preallocates a large block (currently 4MB) and carves it up
-+ * sequentially in ring fashion, and DMA is used to copy the data - to the
-+ * point where very little of the original remains.
-+ *
-+ * Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
-+ *
-+ *
-+ * Copyright (C) 2002 Hewlett Packard Company.
-+ * Copyright (C) 2004 MontaVista Software, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/page-flags.h>
-+#include <linux/device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma-direct.h>
-+#include <linux/dmapool.h>
-+#include <linux/list.h>
-+#include <linux/scatterlist.h>
-+#include <linux/bitmap.h>
-+#include <linux/swiotlb.h>
-+
-+#include <asm/cacheflush.h>
-+
-+#define STATS
-+
-+#ifdef STATS
-+#define DO_STATS(X) do { X ; } while (0)
-+#else
-+#define DO_STATS(X) do { } while (0)
-+#endif
-+
-+/* ************************************************** */
-+
-+struct safe_buffer {
-+ struct list_head node;
-+
-+ /* original request */
-+ size_t size;
-+ int direction;
-+
-+ struct dmabounce_pool *pool;
-+ void *safe;
-+ dma_addr_t unsafe_dma_addr;
-+ dma_addr_t safe_dma_addr;
-+};
-+
-+struct dmabounce_pool {
-+ unsigned long pages;
-+ void *virt_addr;
-+ dma_addr_t dma_addr;
-+ unsigned long *alloc_map;
-+ unsigned long alloc_pos;
-+ spinlock_t lock;
-+ struct device *dev;
-+ unsigned long num_pages;
-+#ifdef STATS
-+ size_t max_size;
-+ unsigned long num_bufs;
-+ unsigned long max_bufs;
-+ unsigned long max_pages;
-+#endif
-+};
-+
-+struct dmabounce_device_info {
-+ struct device *dev;
-+ dma_addr_t threshold;
-+ struct list_head safe_buffers;
-+ struct dmabounce_pool pool;
-+ rwlock_t lock;
-+#ifdef STATS
-+ unsigned long map_count;
-+ unsigned long unmap_count;
-+ unsigned long sync_dev_count;
-+ unsigned long sync_cpu_count;
-+ unsigned long fail_count;
-+ int attr_res;
-+#endif
-+};
-+
-+static struct dmabounce_device_info *g_dmabounce_device_info;
-+
-+extern int bcm2838_dma40_memcpy_init(void);
-+extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-+
-+#ifdef STATS
-+static ssize_t
-+bounce_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+ return sprintf(buf, "m:%lu/%lu s:%lu/%lu f:%lu s:%zu b:%lu/%lu a:%lu/%lu\n",
-+ device_info->map_count,
-+ device_info->unmap_count,
-+ device_info->sync_dev_count,
-+ device_info->sync_cpu_count,
-+ device_info->fail_count,
-+ device_info->pool.max_size,
-+ device_info->pool.num_bufs,
-+ device_info->pool.max_bufs,
-+ device_info->pool.num_pages * PAGE_SIZE,
-+ device_info->pool.max_pages * PAGE_SIZE);
-+}
-+
-+static DEVICE_ATTR(dmabounce_stats, 0444, bounce_show, NULL);
-+#endif
-+
-+static int bounce_create(struct dmabounce_pool *pool, struct device *dev,
-+ unsigned long buffer_size)
-+{
-+ int ret = -ENOMEM;
-+ pool->pages = (buffer_size + PAGE_SIZE - 1)/PAGE_SIZE;
-+ pool->alloc_map = bitmap_zalloc(pool->pages, GFP_KERNEL);
-+ if (!pool->alloc_map)
-+ goto err_bitmap;
-+ pool->virt_addr = dma_alloc_coherent(dev, pool->pages * PAGE_SIZE,
-+ &pool->dma_addr, GFP_KERNEL);
-+ if (!pool->virt_addr)
-+ goto err_dmabuf;
-+
-+ pool->alloc_pos = 0;
-+ spin_lock_init(&pool->lock);
-+ pool->dev = dev;
-+ pool->num_pages = 0;
-+
-+ DO_STATS(pool->max_size = 0);
-+ DO_STATS(pool->num_bufs = 0);
-+ DO_STATS(pool->max_bufs = 0);
-+ DO_STATS(pool->max_pages = 0);
-+
-+ return 0;
-+
-+err_dmabuf:
-+ bitmap_free(pool->alloc_map);
-+err_bitmap:
-+ return ret;
-+}
-+
-+static void bounce_destroy(struct dmabounce_pool *pool)
-+{
-+ dma_free_coherent(pool->dev, pool->pages * PAGE_SIZE, pool->virt_addr,
-+ pool->dma_addr);
-+
-+ bitmap_free(pool->alloc_map);
-+}
-+
-+static void *bounce_alloc(struct dmabounce_pool *pool, size_t size,
-+ dma_addr_t *dmaaddrp)
-+{
-+ unsigned long pages;
-+ unsigned long flags;
-+ unsigned long pos;
-+
-+ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
-+
-+ DO_STATS(pool->max_size = max(size, pool->max_size));
-+
-+ spin_lock_irqsave(&pool->lock, flags);
-+ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
-+ pool->alloc_pos, pages, 0);
-+ /* If not found, try from the start */
-+ if (pos >= pool->pages && pool->alloc_pos)
-+ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
-+ 0, pages, 0);
-+
-+ if (pos >= pool->pages) {
-+ spin_unlock_irqrestore(&pool->lock, flags);
-+ return NULL;
-+ }
-+
-+ bitmap_set(pool->alloc_map, pos, pages);
-+ pool->alloc_pos = (pos + pages) % pool->pages;
-+ pool->num_pages += pages;
-+
-+ DO_STATS(pool->num_bufs++);
-+ DO_STATS(pool->max_bufs = max(pool->num_bufs, pool->max_bufs));
-+ DO_STATS(pool->max_pages = max(pool->num_pages, pool->max_pages));
-+
-+ spin_unlock_irqrestore(&pool->lock, flags);
-+
-+ *dmaaddrp = pool->dma_addr + pos * PAGE_SIZE;
-+
-+ return pool->virt_addr + pos * PAGE_SIZE;
-+}
-+
-+static void
-+bounce_free(struct dmabounce_pool *pool, void *buf, size_t size)
-+{
-+ unsigned long pages;
-+ unsigned long flags;
-+ unsigned long pos;
-+
-+ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
-+ pos = (buf - pool->virt_addr)/PAGE_SIZE;
-+
-+ BUG_ON((buf - pool->virt_addr) & (PAGE_SIZE - 1));
-+
-+ spin_lock_irqsave(&pool->lock, flags);
-+ bitmap_clear(pool->alloc_map, pos, pages);
-+ pool->num_pages -= pages;
-+ if (pool->num_pages == 0)
-+ pool->alloc_pos = 0;
-+ DO_STATS(pool->num_bufs--);
-+ spin_unlock_irqrestore(&pool->lock, flags);
-+}
-+
-+/* allocate a 'safe' buffer and keep track of it */
-+static struct safe_buffer *
-+alloc_safe_buffer(struct dmabounce_device_info *device_info,
-+ dma_addr_t dma_addr, size_t size, enum dma_data_direction dir)
-+{
-+ struct safe_buffer *buf;
-+ struct dmabounce_pool *pool = &device_info->pool;
-+ struct device *dev = device_info->dev;
-+ unsigned long flags;
-+
-+ /*
-+ * Although one might expect this to be called in thread context,
-+ * using GFP_KERNEL here leads to hard-to-debug lockups. in_atomic()
-+ * was previously used to select the appropriate allocation mode,
-+ * but this is unsafe.
-+ */
-+ buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
-+ if (!buf) {
-+ dev_warn(dev, "%s: kmalloc failed\n", __func__);
-+ return NULL;
-+ }
-+
-+ buf->unsafe_dma_addr = dma_addr;
-+ buf->size = size;
-+ buf->direction = dir;
-+ buf->pool = pool;
-+
-+ buf->safe = bounce_alloc(pool, size, &buf->safe_dma_addr);
-+
-+ if (!buf->safe) {
-+ dev_warn(dev,
-+ "%s: could not alloc dma memory (size=%d)\n",
-+ __func__, size);
-+ kfree(buf);
-+ return NULL;
-+ }
-+
-+ write_lock_irqsave(&device_info->lock, flags);
-+ list_add(&buf->node, &device_info->safe_buffers);
-+ write_unlock_irqrestore(&device_info->lock, flags);
-+
-+ return buf;
-+}
-+
-+/* determine if a buffer is from our "safe" pool */
-+static struct safe_buffer *
-+find_safe_buffer(struct dmabounce_device_info *device_info,
-+ dma_addr_t safe_dma_addr)
-+{
-+ struct safe_buffer *b, *rb = NULL;
-+ unsigned long flags;
-+
-+ read_lock_irqsave(&device_info->lock, flags);
-+
-+ list_for_each_entry(b, &device_info->safe_buffers, node)
-+ if (b->safe_dma_addr <= safe_dma_addr &&
-+ b->safe_dma_addr + b->size > safe_dma_addr) {
-+ rb = b;
-+ break;
-+ }
-+
-+ read_unlock_irqrestore(&device_info->lock, flags);
-+ return rb;
-+}
-+
-+static void
-+free_safe_buffer(struct dmabounce_device_info *device_info,
-+ struct safe_buffer *buf)
-+{
-+ unsigned long flags;
-+
-+ write_lock_irqsave(&device_info->lock, flags);
-+ list_del(&buf->node);
-+ write_unlock_irqrestore(&device_info->lock, flags);
-+
-+ bounce_free(buf->pool, buf->safe, buf->size);
-+
-+ kfree(buf);
-+}
-+
-+/* ************************************************** */
-+
-+static struct safe_buffer *
-+find_safe_buffer_dev(struct device *dev, dma_addr_t dma_addr, const char *where)
-+{
-+ if (!dev || !g_dmabounce_device_info)
-+ return NULL;
-+ if (dma_mapping_error(dev, dma_addr)) {
-+ dev_err(dev, "Trying to %s invalid mapping\n", where);
-+ return NULL;
-+ }
-+ return find_safe_buffer(g_dmabounce_device_info, dma_addr);
-+}
-+
-+static dma_addr_t
-+map_single(struct device *dev, struct safe_buffer *buf, size_t size,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ BUG_ON(buf->size != size);
-+ BUG_ON(buf->direction != dir);
-+
-+ dev_dbg(dev, "map: %llx->%llx\n", (u64)buf->unsafe_dma_addr,
-+ (u64)buf->safe_dma_addr);
-+
-+ if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-+ !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-+ bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
-+ size);
-+
-+ return buf->safe_dma_addr;
-+}
-+
-+static dma_addr_t
-+unmap_single(struct device *dev, struct safe_buffer *buf, size_t size,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ BUG_ON(buf->size != size);
-+ BUG_ON(buf->direction != dir);
-+
-+ if ((dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-+ !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
-+ dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
-+ (u64)buf->unsafe_dma_addr);
-+
-+ bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
-+ size);
-+ }
-+ return buf->unsafe_dma_addr;
-+}
-+
-+/* ************************************************** */
-+
-+/*
-+ * see if a buffer address is in an 'unsafe' range. if it is
-+ * allocate a 'safe' buffer and copy the unsafe buffer into it.
-+ * substitute the safe buffer for the unsafe one.
-+ * (basically move the buffer from an unsafe area to a safe one)
-+ */
-+static dma_addr_t
-+dmabounce_map_page(struct device *dev, struct page *page, unsigned long offset,
-+ size_t size, enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+ dma_addr_t dma_addr;
-+
-+ dma_addr = phys_to_dma(dev, page_to_phys(page)) + offset;
-+
-+ swiotlb_sync_single_for_device(dev, dma_addr, size, dir);
-+ if (!is_device_dma_coherent(dev))
-+ __dma_map_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
-+
-+ if (device_info && (dma_addr + size) > device_info->threshold) {
-+ struct safe_buffer *buf;
-+
-+ buf = alloc_safe_buffer(device_info, dma_addr, size, dir);
-+ if (!buf) {
-+ DO_STATS(device_info->fail_count++);
-+ return (~(dma_addr_t)0x0);
-+ }
-+
-+ DO_STATS(device_info->map_count++);
-+
-+ dma_addr = map_single(dev, buf, size, dir, attrs);
-+ }
-+ return dma_addr;
-+}
-+
-+/*
-+ * see if a mapped address was really a "safe" buffer and if so, copy
-+ * the data from the safe buffer back to the unsafe buffer and free up
-+ * the safe buffer. (basically return things back to the way they
-+ * should be)
-+ */
-+static void
-+dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ struct safe_buffer *buf;
-+
-+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+ if (buf) {
-+ DO_STATS(g_dmabounce_device_info->unmap_count++);
-+ dma_addr = unmap_single(dev, buf, size, dir, attrs);
-+ free_safe_buffer(g_dmabounce_device_info, buf);
-+ }
-+
-+ if (!is_device_dma_coherent(dev))
-+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
-+ swiotlb_sync_single_for_cpu(dev, dma_addr, size, dir);
-+}
-+
-+/*
-+ * A version of dmabounce_map_page that assumes the mapping has already
-+ * been created - intended for streaming operation.
-+ */
-+static void
-+dmabounce_sync_for_device(struct device *dev, dma_addr_t dma_addr, size_t size,
-+ enum dma_data_direction dir)
-+{
-+ struct safe_buffer *buf;
-+
-+ swiotlb_sync_single_for_device(dev, dma_addr, size, dir);
-+ if (!is_device_dma_coherent(dev))
-+ __dma_map_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
-+
-+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+ if (buf) {
-+ DO_STATS(g_dmabounce_device_info->sync_dev_count++);
-+ map_single(dev, buf, size, dir, 0);
-+ }
-+}
-+
-+/*
-+ * A version of dmabounce_unmap_page that doesn't destroy the mapping -
-+ * intended for streaming operation.
-+ */
-+static void
-+dmabounce_sync_for_cpu(struct device *dev, dma_addr_t dma_addr,
-+ size_t size, enum dma_data_direction dir)
-+{
-+ struct safe_buffer *buf;
-+
-+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+ if (buf) {
-+ DO_STATS(g_dmabounce_device_info->sync_cpu_count++);
-+ dma_addr = unmap_single(dev, buf, size, dir, 0);
-+ }
-+
-+ if (!is_device_dma_coherent(dev))
-+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
-+ swiotlb_sync_single_for_cpu(dev, dma_addr, size, dir);
-+}
-+
-+static int dmabounce_dma_supported(struct device *dev, u64 dma_mask)
-+{
-+ if (g_dmabounce_device_info)
-+ return 0;
-+
-+ return swiotlb_dma_supported(dev, dma_mask);
-+}
-+
-+static int dmabounce_mapping_error(struct device *dev, dma_addr_t dma_addr)
-+{
-+ return swiotlb_dma_mapping_error(dev, dma_addr);
-+}
-+
-+static const struct dma_map_ops dmabounce_ops = {
-+ .alloc = arm64_dma_alloc,
-+ .free = arm64_dma_free,
-+ .mmap = arm64_dma_mmap,
-+ .get_sgtable = arm64_dma_get_sgtable,
-+ .map_page = dmabounce_map_page,
-+ .unmap_page = dmabounce_unmap_page,
-+ .sync_single_for_cpu = dmabounce_sync_for_cpu,
-+ .sync_single_for_device = dmabounce_sync_for_device,
-+ .map_sg = arm64_dma_map_sg,
-+ .unmap_sg = arm64_dma_unmap_sg,
-+ .sync_sg_for_cpu = arm64_dma_sync_sg_for_cpu,
-+ .sync_sg_for_device = arm64_dma_sync_sg_for_device,
-+ .dma_supported = dmabounce_dma_supported,
-+ .mapping_error = dmabounce_mapping_error,
-+};
-+
-+int brcm_pcie_bounce_init(struct device *dev,
-+ unsigned long buffer_size,
-+ dma_addr_t threshold)
-+{
-+ struct dmabounce_device_info *device_info;
-+ int ret;
-+
-+ /* Only support a single client */
-+ if (g_dmabounce_device_info)
-+ return -EBUSY;
-+
-+ ret = bcm2838_dma40_memcpy_init();
-+ if (ret)
-+ return ret;
-+
-+ device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
-+ if (!device_info) {
-+ dev_err(dev,
-+ "Could not allocated dmabounce_device_info\n");
-+ return -ENOMEM;
-+ }
-+
-+ ret = bounce_create(&device_info->pool, dev, buffer_size);
-+ if (ret) {
-+ dev_err(dev,
-+ "dmabounce: could not allocate %ld byte DMA pool\n",
-+ buffer_size);
-+ goto err_bounce;
-+ }
-+
-+ device_info->dev = dev;
-+ device_info->threshold = threshold;
-+ INIT_LIST_HEAD(&device_info->safe_buffers);
-+ rwlock_init(&device_info->lock);
-+
-+ DO_STATS(device_info->map_count = 0);
-+ DO_STATS(device_info->unmap_count = 0);
-+ DO_STATS(device_info->sync_dev_count = 0);
-+ DO_STATS(device_info->sync_cpu_count = 0);
-+ DO_STATS(device_info->fail_count = 0);
-+ DO_STATS(device_info->attr_res =
-+ device_create_file(dev, &dev_attr_dmabounce_stats));
-+
-+ g_dmabounce_device_info = device_info;
-+
-+ dev_err(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
-+ buffer_size / 1024, &threshold);
-+
-+ return 0;
-+
-+ err_bounce:
-+ kfree(device_info);
-+ return ret;
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_init);
-+
-+void brcm_pcie_bounce_uninit(struct device *dev)
-+{
-+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+
-+ g_dmabounce_device_info = NULL;
-+
-+ if (!device_info) {
-+ dev_warn(dev,
-+ "Never registered with dmabounce but attempting"
-+ "to unregister!\n");
-+ return;
-+ }
-+
-+ if (!list_empty(&device_info->safe_buffers)) {
-+ dev_err(dev,
-+ "Removing from dmabounce with pending buffers!\n");
-+ BUG();
-+ }
-+
-+ bounce_destroy(&device_info->pool);
-+
-+ DO_STATS(if (device_info->attr_res == 0)
-+ device_remove_file(dev, &dev_attr_dmabounce_stats));
-+
-+ kfree(device_info);
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_uninit);
-+
-+int brcm_pcie_bounce_register_dev(struct device *dev)
-+{
-+ set_dma_ops(dev, &dmabounce_ops);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
-+
-+MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
-+MODULE_LICENSE("GPL");
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -617,28 +617,6 @@ static const struct dma_map_ops brcm_dma
-
- static void brcm_set_dma_ops(struct device *dev)
- {
-- int ret;
--
-- if (IS_ENABLED(CONFIG_ARM64)) {
-- /*
-- * We are going to invoke get_dma_ops(). That
-- * function, at this point in time, invokes
-- * get_arch_dma_ops(), and for ARM64 that function
-- * returns a pointer to dummy_dma_ops. So then we'd
-- * like to call arch_setup_dma_ops(), but that isn't
-- * exported. Instead, we call of_dma_configure(),
-- * which is exported, and this calls
-- * arch_setup_dma_ops(). Once we do this the call to
-- * get_dma_ops() will work properly because
-- * dev->dma_ops will be set.
-- */
-- ret = of_dma_configure(dev, dev->of_node, true);
-- if (ret) {
-- dev_err(dev, "of_dma_configure() failed: %d\n", ret);
-- return;
-- }
-- }
--
- arch_dma_ops = get_dma_ops(dev);
- if (!arch_dma_ops) {
- dev_err(dev, "failed to get arch_dma_ops\n");
-@@ -657,12 +635,12 @@ static int brcmstb_platform_notifier(str
- extern unsigned long max_pfn;
- struct device *dev = __dev;
- const char *rc_name = "0000:00:00.0";
-+ int ret;
-
- switch (event) {
- case BUS_NOTIFY_ADD_DEVICE:
- if (max_pfn > (bounce_threshold/PAGE_SIZE) &&
- strcmp(dev->kobj.name, rc_name)) {
-- int ret;
-
- ret = brcm_pcie_bounce_register_dev(dev);
- if (ret) {
-@@ -671,6 +649,12 @@ static int brcmstb_platform_notifier(str
- ret);
- return ret;
- }
-+ } else if (IS_ENABLED(CONFIG_ARM64)) {
-+ ret = of_dma_configure(dev, dev->of_node, true);
-+ if (ret) {
-+ dev_err(dev, "of_dma_configure() failed: %d\n", ret);
-+ return;
-+ }
- }
- brcm_set_dma_ops(dev);
- return NOTIFY_OK;
--- /dev/null
+From ee24998ecaed3d03890a7a5e04dddb8c5d073e97 Mon Sep 17 00:00:00 2001
+Date: Sat, 17 Aug 2019 19:47:30 +0100
+Subject: [PATCH] overlays: sc16ic752-i2c: Fix xtal parameter
+
+The xtal parameter is targetting the wrong node - fix it.
+
+See: https://github.com/raspberrypi/linux/issues/3156
+
+---
+ arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts
+@@ -35,6 +35,6 @@
+ __overrides__ {
+ int_pin = <&sc16is752>,"interrupts:0";
+ addr = <&sc16is752>,"reg:0",<&sc16is752_clk>,"name";
+- xtal = <&sc16is752>,"clock-frequency:0";
++ xtal = <&sc16is752_clk>,"clock-frequency:0";
+ };
+ };
+++ /dev/null
-From 709962264bec8f8483df374da5e946c982348e87 Mon Sep 17 00:00:00 2001
-Date: Thu, 15 Aug 2019 12:02:34 +0100
-Subject: [PATCH] configs: arm64/vcm2711: Enable V3D
-
-Enable the V3D driver, which depends on BCM2835_POWER.
-
-Originally submitted by GitHub user 'phire' in a slightly different
-form.
-
-See: https://github.com/raspberrypi/linux/pull/3063
-
----
- drivers/gpu/drm/v3d/Kconfig | 2 +-
- 2 files changed, 3 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/v3d/Kconfig
-+++ b/drivers/gpu/drm/v3d/Kconfig
-@@ -1,6 +1,6 @@
- config DRM_V3D
- tristate "Broadcom V3D 3.x and newer"
-- depends on ARCH_BCM || ARCH_BCMSTB || COMPILE_TEST
-+ depends on ARCH_BCM || ARCH_BCMSTB || ARCH_BCM2835 || COMPILE_TEST
- depends on DRM
- depends on COMMON_CLK
- depends on MMU
--- /dev/null
+From a24a0a621486b36bcdf5c5e0afb05a5d1dd30003 Mon Sep 17 00:00:00 2001
+Date: Mon, 19 Aug 2019 15:45:20 +0100
+Subject: [PATCH] vc-sm-cma: Fix compatibility ioctl
+
+This code path hasn't been used previously.
+Fixed up after testing with kodi on 32-bit userland and 64-bit kernel
+
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
+@@ -1501,11 +1501,10 @@ static long vc_sm_cma_ioctl(struct file
+ return ret;
+ }
+
+-#ifndef CONFIG_ARM64
+ #ifdef CONFIG_COMPAT
+ struct vc_sm_cma_ioctl_clean_invalid2_32 {
+ u32 op_count;
+- struct vc_sm_cma_ioctl_clean_invalid_block {
++ struct vc_sm_cma_ioctl_clean_invalid_block_32 {
+ u16 invalidate_mode;
+ u16 block_count;
+ compat_uptr_t start_address;
+@@ -1516,7 +1515,7 @@ struct vc_sm_cma_ioctl_clean_invalid2_32
+
+ #define VC_SM_CMA_CMD_CLEAN_INVALID2_32\
+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\
+- struct vc_sm_cma_ioctl_clean_invalid2)
++ struct vc_sm_cma_ioctl_clean_invalid2_32)
+
+ static long vc_sm_cma_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+@@ -1524,24 +1523,21 @@ static long vc_sm_cma_compat_ioctl(struc
+ switch (cmd) {
+ case VC_SM_CMA_CMD_CLEAN_INVALID2_32:
+ /* FIXME */
+- break;
++ return -EINVAL;
+
+ default:
+- return vc_sm_cma_compat_ioctl(file, cmd, arg);
++ return vc_sm_cma_ioctl(file, cmd, arg);
+ }
+ }
+ #endif
+-#endif
+
+ /* Device operations that we managed in this driver. */
+ static const struct file_operations vc_sm_ops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = vc_sm_cma_ioctl,
+-#ifndef CONFIG_ARM64
+ #ifdef CONFIG_COMPAT
+ .compat_ioctl = vc_sm_cma_compat_ioctl,
+ #endif
+-#endif
+ .open = vc_sm_cma_open,
+ .release = vc_sm_cma_release,
+ };
+++ /dev/null
-From ee24998ecaed3d03890a7a5e04dddb8c5d073e97 Mon Sep 17 00:00:00 2001
-Date: Sat, 17 Aug 2019 19:47:30 +0100
-Subject: [PATCH] overlays: sc16ic752-i2c: Fix xtal parameter
-
-The xtal parameter is targetting the wrong node - fix it.
-
-See: https://github.com/raspberrypi/linux/issues/3156
-
----
- arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts
-@@ -35,6 +35,6 @@
- __overrides__ {
- int_pin = <&sc16is752>,"interrupts:0";
- addr = <&sc16is752>,"reg:0",<&sc16is752_clk>,"name";
-- xtal = <&sc16is752>,"clock-frequency:0";
-+ xtal = <&sc16is752_clk>,"clock-frequency:0";
- };
- };
--- /dev/null
+From ae6dba510ac29ef7b0e6c838fb1bcc8b9eb474b7 Mon Sep 17 00:00:00 2001
+Date: Thu, 22 Aug 2019 22:31:37 +0000
+Subject: [PATCH] staging: bcm2835-codec: add support for
+ V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME
+
+fixes #3171
+
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 19 ++++++++++++++++++-
+ 1 file changed, 18 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1587,6 +1587,20 @@ static int bcm2835_codec_s_ctrl(struct v
+ ret = bcm2835_codec_set_level_profile(ctx, ctrl);
+ break;
+
++ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: {
++ u32 mmal_bool = 1;
++
++ if (!ctx->component)
++ break;
++
++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
++ &ctx->component->output[0],
++ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
++ &mmal_bool,
++ sizeof(mmal_bool));
++ break;
++ }
++
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+ return -EINVAL;
+@@ -2311,7 +2325,7 @@ static int bcm2835_codec_open(struct fil
+ hdl = &ctx->hdl;
+ if (dev->role == ENCODE) {
+ /* Encode controls */
+- v4l2_ctrl_handler_init(hdl, 6);
++ v4l2_ctrl_handler_init(hdl, 7);
+
+ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+@@ -2355,6 +2369,9 @@ static int bcm2835_codec_open(struct fil
+ 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_FORCE_KEY_FRAME,
++ 0, 0, 0, 0);
+ if (hdl->error) {
+ rc = hdl->error;
+ goto free_ctrl_handler;
--- /dev/null
+From 9a2eab654b11d27bcc5a32ebd374f6c9acc38ce4 Mon Sep 17 00:00:00 2001
+Date: Fri, 23 Aug 2019 16:29:07 -0700
+Subject: [PATCH] staging: bcm2835-codec: remove unnecessary padding on
+ encoder input
+
+The ISP and ENCODE roles have the same underlying hardware. Neither requires vertical alignment.
+
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1050,12 +1050,12 @@ static int vidioc_try_fmt(struct bcm2835
+ f->fmt.pix_mp.height = MIN_H;
+
+ /*
+- * For codecs the buffer must have a vertical alignment of 16
++ * For decoders the buffer must have a vertical alignment of 16
+ * lines.
+ * The selection will reflect any cropping rectangle when only
+ * some of the pixels are active.
+ */
+- if (ctx->dev->role != ISP)
++ if (ctx->dev->role == DECODE)
+ f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16);
+ }
+ f->fmt.pix_mp.num_planes = 1;
+++ /dev/null
-From a24a0a621486b36bcdf5c5e0afb05a5d1dd30003 Mon Sep 17 00:00:00 2001
-Date: Mon, 19 Aug 2019 15:45:20 +0100
-Subject: [PATCH] vc-sm-cma: Fix compatibility ioctl
-
-This code path hasn't been used previously.
-Fixed up after testing with kodi on 32-bit userland and 64-bit kernel
-
----
- drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 12 ++++--------
- 1 file changed, 4 insertions(+), 8 deletions(-)
-
---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -1501,11 +1501,10 @@ static long vc_sm_cma_ioctl(struct file
- return ret;
- }
-
--#ifndef CONFIG_ARM64
- #ifdef CONFIG_COMPAT
- struct vc_sm_cma_ioctl_clean_invalid2_32 {
- u32 op_count;
-- struct vc_sm_cma_ioctl_clean_invalid_block {
-+ struct vc_sm_cma_ioctl_clean_invalid_block_32 {
- u16 invalidate_mode;
- u16 block_count;
- compat_uptr_t start_address;
-@@ -1516,7 +1515,7 @@ struct vc_sm_cma_ioctl_clean_invalid2_32
-
- #define VC_SM_CMA_CMD_CLEAN_INVALID2_32\
- _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\
-- struct vc_sm_cma_ioctl_clean_invalid2)
-+ struct vc_sm_cma_ioctl_clean_invalid2_32)
-
- static long vc_sm_cma_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-@@ -1524,24 +1523,21 @@ static long vc_sm_cma_compat_ioctl(struc
- switch (cmd) {
- case VC_SM_CMA_CMD_CLEAN_INVALID2_32:
- /* FIXME */
-- break;
-+ return -EINVAL;
-
- default:
-- return vc_sm_cma_compat_ioctl(file, cmd, arg);
-+ return vc_sm_cma_ioctl(file, cmd, arg);
- }
- }
- #endif
--#endif
-
- /* Device operations that we managed in this driver. */
- static const struct file_operations vc_sm_ops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = vc_sm_cma_ioctl,
--#ifndef CONFIG_ARM64
- #ifdef CONFIG_COMPAT
- .compat_ioctl = vc_sm_cma_compat_ioctl,
- #endif
--#endif
- .open = vc_sm_cma_open,
- .release = vc_sm_cma_release,
- };
--- /dev/null
+From ac6c4a17f6f7aeb977b04dd4dc7e801b7776499f Mon Sep 17 00:00:00 2001
+Date: Thu, 29 Aug 2019 16:26:22 +0200
+Subject: [PATCH] arm: dts: add missing Raspberry Pi model names
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is needed to identify the different models on distributions like OpenWrt.
+
+---
+ arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 1 +
+ arch/arm/boot/dts/bcm2708-rpi-b.dts | 1 +
+ arch/arm/boot/dts/bcm2708-rpi-cm.dts | 1 +
+ arch/arm/boot/dts/bcm2710-rpi-cm3.dts | 1 +
+ 4 files changed, 4 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
+@@ -6,6 +6,7 @@
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
++ compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
+ model = "Raspberry Pi Model B+";
+ };
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
+@@ -6,6 +6,7 @@
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
++ compatible = "raspberrypi,model-b", "brcm,bcm2835";
+ model = "Raspberry Pi Model B";
+ };
+
+--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts
++++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts
+@@ -5,6 +5,7 @@
+ #include "bcm283x-rpi-csi1-4lane.dtsi"
+
+ / {
++ compatible = "raspberrypi,compute-module", "brcm,bcm2835";
+ model = "Raspberry Pi Compute Module";
+ };
+
+--- a/arch/arm/boot/dts/bcm2710-rpi-cm3.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-cm3.dts
+@@ -6,6 +6,7 @@
+ #include "bcm283x-rpi-csi1-4lane.dtsi"
+
+ / {
++ compatible = "raspberrypi,3-compute-module", "brcm,bcm2837";
+ model = "Raspberry Pi Compute Module 3";
+ };
+
+++ /dev/null
-From ae6dba510ac29ef7b0e6c838fb1bcc8b9eb474b7 Mon Sep 17 00:00:00 2001
-Date: Thu, 22 Aug 2019 22:31:37 +0000
-Subject: [PATCH] staging: bcm2835-codec: add support for
- V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME
-
-fixes #3171
-
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 19 ++++++++++++++++++-
- 1 file changed, 18 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1587,6 +1587,20 @@ static int bcm2835_codec_s_ctrl(struct v
- ret = bcm2835_codec_set_level_profile(ctx, ctrl);
- break;
-
-+ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: {
-+ u32 mmal_bool = 1;
-+
-+ if (!ctx->component)
-+ break;
-+
-+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
-+ &ctx->component->output[0],
-+ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
-+ &mmal_bool,
-+ sizeof(mmal_bool));
-+ break;
-+ }
-+
- default:
- v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
- return -EINVAL;
-@@ -2311,7 +2325,7 @@ static int bcm2835_codec_open(struct fil
- hdl = &ctx->hdl;
- if (dev->role == ENCODE) {
- /* Encode controls */
-- v4l2_ctrl_handler_init(hdl, 6);
-+ v4l2_ctrl_handler_init(hdl, 7);
-
- v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
-@@ -2355,6 +2369,9 @@ static int bcm2835_codec_open(struct fil
- 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_FORCE_KEY_FRAME,
-+ 0, 0, 0, 0);
- if (hdl->error) {
- rc = hdl->error;
- goto free_ctrl_handler;
--- /dev/null
+From d9f55647637be79ff42cb85497e43ca8b9a69a7b Mon Sep 17 00:00:00 2001
+Date: Tue, 3 Sep 2019 18:16:56 +0100
+Subject: [PATCH] arch/arm: Add model string to cpuinfo
+
+---
+ arch/arm/kernel/setup.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/arch/arm/kernel/setup.c
++++ b/arch/arm/kernel/setup.c
+@@ -1238,6 +1238,8 @@ static int c_show(struct seq_file *m, vo
+ {
+ int i, j;
+ u32 cpuid;
++ struct device_node *np;
++ const char *model;
+
+ for_each_online_cpu(i) {
+ /*
+@@ -1297,6 +1299,14 @@ static int c_show(struct seq_file *m, vo
+ seq_printf(m, "Revision\t: %04x\n", system_rev);
+ seq_printf(m, "Serial\t\t: %s\n", system_serial);
+
++ np = of_find_node_by_path("/");
++ if (np) {
++ if (!of_property_read_string(np, "model",
++ &model))
++ seq_printf(m, "Model\t\t: %s\n", model);
++ of_node_put(np);
++ }
++
+ return 0;
+ }
+
+++ /dev/null
-From 9a2eab654b11d27bcc5a32ebd374f6c9acc38ce4 Mon Sep 17 00:00:00 2001
-Date: Fri, 23 Aug 2019 16:29:07 -0700
-Subject: [PATCH] staging: bcm2835-codec: remove unnecessary padding on
- encoder input
-
-The ISP and ENCODE roles have the same underlying hardware. Neither requires vertical alignment.
-
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1050,12 +1050,12 @@ static int vidioc_try_fmt(struct bcm2835
- f->fmt.pix_mp.height = MIN_H;
-
- /*
-- * For codecs the buffer must have a vertical alignment of 16
-+ * For decoders the buffer must have a vertical alignment of 16
- * lines.
- * The selection will reflect any cropping rectangle when only
- * some of the pixels are active.
- */
-- if (ctx->dev->role != ISP)
-+ if (ctx->dev->role == DECODE)
- f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16);
- }
- f->fmt.pix_mp.num_planes = 1;
--- /dev/null
+From aabfcb0abbc34ca5f3c4b4f872123166eca2e100 Mon Sep 17 00:00:00 2001
+Date: Tue, 3 Sep 2019 18:17:25 +0100
+Subject: [PATCH] arch/arm64: Add Revision, Serial, Model to cpuinfo
+
+---
+ arch/arm64/kernel/cpuinfo.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+--- a/arch/arm64/kernel/cpuinfo.c
++++ b/arch/arm64/kernel/cpuinfo.c
+@@ -27,6 +27,7 @@
+ #include <linux/elf.h>
+ #include <linux/init.h>
+ #include <linux/kernel.h>
++#include <linux/of_platform.h>
+ #include <linux/personality.h>
+ #include <linux/preempt.h>
+ #include <linux/printk.h>
+@@ -126,6 +127,10 @@ static int c_show(struct seq_file *m, vo
+ {
+ int i, j;
+ bool compat = personality(current->personality) == PER_LINUX32;
++ struct device_node *np;
++ const char *model;
++ const char *serial;
++ u32 revision;
+
+ for_each_online_cpu(i) {
+ struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
+@@ -177,6 +182,26 @@ static int c_show(struct seq_file *m, vo
+ seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
+ }
+
++ seq_printf(m, "Hardware\t: BCM2835\n");
++
++ np = of_find_node_by_path("/system");
++ if (np) {
++ if (!of_property_read_u32(np, "linux,revision", &revision))
++ seq_printf(m, "Revision\t: %04x\n", revision);
++ of_node_put(np);
++ }
++
++ np = of_find_node_by_path("/");
++ if (np) {
++ if (!of_property_read_string(np, "serial-number",
++ &serial))
++ seq_printf(m, "Serial\t\t: %s\n", serial);
++ if (!of_property_read_string(np, "model",
++ &model))
++ seq_printf(m, "Model\t\t: %s\n", model);
++ of_node_put(np);
++ }
++
+ return 0;
+ }
+
+++ /dev/null
-From ac6c4a17f6f7aeb977b04dd4dc7e801b7776499f Mon Sep 17 00:00:00 2001
-Date: Thu, 29 Aug 2019 16:26:22 +0200
-Subject: [PATCH] arm: dts: add missing Raspberry Pi model names
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This is needed to identify the different models on distributions like OpenWrt.
-
----
- arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 1 +
- arch/arm/boot/dts/bcm2708-rpi-b.dts | 1 +
- arch/arm/boot/dts/bcm2708-rpi-cm.dts | 1 +
- arch/arm/boot/dts/bcm2710-rpi-cm3.dts | 1 +
- 4 files changed, 4 insertions(+)
-
---- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
-@@ -6,6 +6,7 @@
- #include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
-+ compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
- model = "Raspberry Pi Model B+";
- };
-
---- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
-+++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
-@@ -6,6 +6,7 @@
- #include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
-+ compatible = "raspberrypi,model-b", "brcm,bcm2835";
- model = "Raspberry Pi Model B";
- };
-
---- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts
-+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts
-@@ -5,6 +5,7 @@
- #include "bcm283x-rpi-csi1-4lane.dtsi"
-
- / {
-+ compatible = "raspberrypi,compute-module", "brcm,bcm2835";
- model = "Raspberry Pi Compute Module";
- };
-
---- a/arch/arm/boot/dts/bcm2710-rpi-cm3.dts
-+++ b/arch/arm/boot/dts/bcm2710-rpi-cm3.dts
-@@ -6,6 +6,7 @@
- #include "bcm283x-rpi-csi1-4lane.dtsi"
-
- / {
-+ compatible = "raspberrypi,3-compute-module", "brcm,bcm2837";
- model = "Raspberry Pi Compute Module 3";
- };
-
+++ /dev/null
-From d9f55647637be79ff42cb85497e43ca8b9a69a7b Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Sep 2019 18:16:56 +0100
-Subject: [PATCH] arch/arm: Add model string to cpuinfo
-
----
- arch/arm/kernel/setup.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/arch/arm/kernel/setup.c
-+++ b/arch/arm/kernel/setup.c
-@@ -1238,6 +1238,8 @@ static int c_show(struct seq_file *m, vo
- {
- int i, j;
- u32 cpuid;
-+ struct device_node *np;
-+ const char *model;
-
- for_each_online_cpu(i) {
- /*
-@@ -1297,6 +1299,14 @@ static int c_show(struct seq_file *m, vo
- seq_printf(m, "Revision\t: %04x\n", system_rev);
- seq_printf(m, "Serial\t\t: %s\n", system_serial);
-
-+ np = of_find_node_by_path("/");
-+ if (np) {
-+ if (!of_property_read_string(np, "model",
-+ &model))
-+ seq_printf(m, "Model\t\t: %s\n", model);
-+ of_node_put(np);
-+ }
-+
- return 0;
- }
-
--- /dev/null
+From 2d8a780a994098f7c532b712abd7298e0bca5a12 Mon Sep 17 00:00:00 2001
+Date: Wed, 28 Aug 2019 13:34:30 +0100
+Subject: [PATCH] media: dt-bindings: Add binding for the Sony IMX219
+ sensor
+
+The IMX219 is an 8MPix CSI2 sensor, supporting 2 or 4 data lanes.
+Document the binding for this device.
+
+---
+ .../devicetree/bindings/media/i2c/imx219.txt | 59 +++++++++++++++++++
+ 1 file changed, 59 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/media/i2c/imx219.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/media/i2c/imx219.txt
+@@ -0,0 +1,59 @@
++* Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor
++
++The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor with
++an active array size of 3280H x 2464V. It is programmable through I2C
++interface. The I2C address is fixed to 0x10 as per sensor data sheet.
++Image data is sent through MIPI CSI-2, which is configured as either 2 or 4
++data lanes.
++
++Required Properties:
++- compatible: value should be "sony,imx219" for imx219 sensor
++- reg: I2C bus address of the device
++- clocks: reference to the xclk input clock.
++- clock-names: should be "xclk".
++- DOVDD-supply: Digital I/O voltage supply, 1.8 volts
++- AVDD-supply: Analog voltage supply, 2.8 volts
++- DVDD-supply: Digital core voltage supply, 1.2 volts
++
++Optional Properties:
++- xclr-gpios: reference to the GPIO connected to the xclr pin, if any. Must be
++ released after all supplies are applied.
++ This is an active high signal to the imx219.
++
++The imx219 device node should contain one 'port' child node with
++an 'endpoint' subnode. For further reading on port node refer to
++Documentation/devicetree/bindings/media/video-interfaces.txt.
++
++Endpoint node required properties for CSI-2 connection are:
++- remote-endpoint: a phandle to the bus receiver's endpoint node.
++- clock-lanes: should be set to <0> (clock lane on hardware lane 0)
++- data-lanes: should be set to <1 2>, or <1 2 3 4> (two or four lane CSI-2
++ supported)
++
++Example:
++ sensor@10 {
++ compatible = "sony,imx219";
++ reg = <0x10>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clocks = <&imx219_clk>;
++ clock-names = "xclk";
++ xclr-gpios = <&gpio_sensor 0 0>;
++ DOVDD-supply = <&vgen4_reg>; /* 1.8v */
++ AVDD-supply = <&vgen3_reg>; /* 2.8v */
++ DVDD-supply = <&vgen2_reg>; /* 1.2v */
++
++ imx219_clk: camera-clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <24000000>;
++ };
++
++ port {
++ sensor_out: endpoint {
++ remote-endpoint = <&csiss_in>;
++ clock-lanes = <0>;
++ data-lanes = <1 2>;
++ };
++ };
++ };
+++ /dev/null
-From aabfcb0abbc34ca5f3c4b4f872123166eca2e100 Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Sep 2019 18:17:25 +0100
-Subject: [PATCH] arch/arm64: Add Revision, Serial, Model to cpuinfo
-
----
- arch/arm64/kernel/cpuinfo.c | 25 +++++++++++++++++++++++++
- 1 file changed, 25 insertions(+)
-
---- a/arch/arm64/kernel/cpuinfo.c
-+++ b/arch/arm64/kernel/cpuinfo.c
-@@ -27,6 +27,7 @@
- #include <linux/elf.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
-+#include <linux/of_platform.h>
- #include <linux/personality.h>
- #include <linux/preempt.h>
- #include <linux/printk.h>
-@@ -126,6 +127,10 @@ static int c_show(struct seq_file *m, vo
- {
- int i, j;
- bool compat = personality(current->personality) == PER_LINUX32;
-+ struct device_node *np;
-+ const char *model;
-+ const char *serial;
-+ u32 revision;
-
- for_each_online_cpu(i) {
- struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
-@@ -177,6 +182,26 @@ static int c_show(struct seq_file *m, vo
- seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
- }
-
-+ seq_printf(m, "Hardware\t: BCM2835\n");
-+
-+ np = of_find_node_by_path("/system");
-+ if (np) {
-+ if (!of_property_read_u32(np, "linux,revision", &revision))
-+ seq_printf(m, "Revision\t: %04x\n", revision);
-+ of_node_put(np);
-+ }
-+
-+ np = of_find_node_by_path("/");
-+ if (np) {
-+ if (!of_property_read_string(np, "serial-number",
-+ &serial))
-+ seq_printf(m, "Serial\t\t: %s\n", serial);
-+ if (!of_property_read_string(np, "model",
-+ &model))
-+ seq_printf(m, "Model\t\t: %s\n", model);
-+ of_node_put(np);
-+ }
-+
- return 0;
- }
-
--- /dev/null
+From 2186344c6d83ccd169e16c048c8b43aff95545e2 Mon Sep 17 00:00:00 2001
+Date: Wed, 28 Aug 2019 13:34:49 +0100
+Subject: [PATCH] media: i2c: Add driver for Sony IMX219 sensor
+
+Adds a driver for the 8MPix Sony IMX219 CSI2 sensor.
+Whilst the sensor supports 2 or 4 CSI2 data lanes, this driver
+currently only supports 2 lanes.
+8MPix @ 15fps, 1080P @ 30fps (cropped FOV), and 1640x1232 (2x2 binned)
+@ 30fps are currently supported.
+
+---
+ drivers/media/i2c/Kconfig | 11 +
+ drivers/media/i2c/Makefile | 1 +
+ drivers/media/i2c/imx219.c | 1093 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1105 insertions(+)
+ create mode 100644 drivers/media/i2c/imx219.c
+
+--- a/drivers/media/i2c/Kconfig
++++ b/drivers/media/i2c/Kconfig
+@@ -597,6 +597,17 @@ config VIDEO_APTINA_PLL
+ config VIDEO_SMIAPP_PLL
+ tristate
+
++config VIDEO_IMX219
++ tristate "Sony IMX219 sensor support"
++ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
++ depends on MEDIA_CAMERA_SUPPORT
++ help
++ This is a Video4Linux2 sensor driver for the Sony
++ IMX219 camera.
++
++ To compile this driver as a module, choose M here: the
++ module will be called imx219.
++
+ config VIDEO_IMX258
+ tristate "Sony IMX258 sensor support"
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+--- a/drivers/media/i2c/Makefile
++++ b/drivers/media/i2c/Makefile
+@@ -106,6 +106,7 @@ obj-$(CONFIG_VIDEO_I2C) += video-i2c.o
+ obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
+ obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
+ obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
++obj-$(CONFIG_VIDEO_IMX219) += imx219.o
+ obj-$(CONFIG_VIDEO_IMX258) += imx258.o
+ obj-$(CONFIG_VIDEO_IMX274) += imx274.o
+
+--- /dev/null
++++ b/drivers/media/i2c/imx219.c
+@@ -0,0 +1,1093 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * A V4L2 driver for Sony IMX219 cameras.
++ * Copyright (C) 2019, Raspberry Pi (Trading) Ltd
++ *
++ * Based on Sony imx258 camera driver
++ * Copyright (C) 2018 Intel Corporation
++ *
++ * DT / fwnode changes, and regulator / GPIO control taken from ov5640.c
++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright (C) 2014-2017 Mentor Graphics Inc.
++ *
++ */
++
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++#include <linux/clkdev.h>
++#include <linux/delay.h>
++#include <linux/gpio/consumer.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/pm_runtime.h>
++#include <linux/regulator/consumer.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-fwnode.h>
++#include <media/v4l2-mediabus.h>
++#include <asm/unaligned.h>
++
++#define IMX219_REG_VALUE_08BIT 1
++#define IMX219_REG_VALUE_16BIT 2
++
++#define IMX219_REG_MODE_SELECT 0x0100
++#define IMX219_MODE_STANDBY 0x00
++#define IMX219_MODE_STREAMING 0x01
++
++/* Chip ID */
++#define IMX219_REG_CHIP_ID 0x0000
++#define IMX219_CHIP_ID 0x0219
++
++/* V_TIMING internal */
++#define IMX219_REG_VTS 0x0160
++#define IMX219_VTS_15FPS 0x0dc6
++#define IMX219_VTS_30FPS_1080P 0x06e3
++#define IMX219_VTS_30FPS_BINNED 0x06e3
++#define IMX219_VTS_MAX 0xffff
++
++/*Frame Length Line*/
++#define IMX219_FLL_MIN 0x08a6
++#define IMX219_FLL_MAX 0xffff
++#define IMX219_FLL_STEP 1
++#define IMX219_FLL_DEFAULT 0x0c98
++
++/* HBLANK control - read only */
++#define IMX219_PPL_DEFAULT 5352
++
++/* Exposure control */
++#define IMX219_REG_EXPOSURE 0x015a
++#define IMX219_EXPOSURE_MIN 4
++#define IMX219_EXPOSURE_STEP 1
++#define IMX219_EXPOSURE_DEFAULT 0x640
++#define IMX219_EXPOSURE_MAX 65535
++
++/* Analog gain control */
++#define IMX219_REG_ANALOG_GAIN 0x0157
++#define IMX219_ANA_GAIN_MIN 0
++#define IMX219_ANA_GAIN_MAX 232
++#define IMX219_ANA_GAIN_STEP 1
++#define IMX219_ANA_GAIN_DEFAULT 0x0
++
++/* Digital gain control */
++#define IMX219_REG_DIGITAL_GAIN 0x0158
++#define IMX219_DGTL_GAIN_MIN 0x0100
++#define IMX219_DGTL_GAIN_MAX 0x0fff
++#define IMX219_DGTL_GAIN_DEFAULT 0x0100
++#define IMX219_DGTL_GAIN_STEP 1
++
++/* Test Pattern Control */
++#define IMX219_REG_TEST_PATTERN 0x0600
++#define IMX219_TEST_PATTERN_DISABLE 0
++#define IMX219_TEST_PATTERN_SOLID_COLOR 1
++#define IMX219_TEST_PATTERN_COLOR_BARS 2
++#define IMX219_TEST_PATTERN_GREY_COLOR 3
++#define IMX219_TEST_PATTERN_PN9 4
++
++struct imx219_reg {
++ u16 address;
++ u8 val;
++};
++
++struct imx219_reg_list {
++ u32 num_of_regs;
++ const struct imx219_reg *regs;
++};
++
++/* Mode : resolution and related config&values */
++struct imx219_mode {
++ /* Frame width */
++ u32 width;
++ /* Frame height */
++ u32 height;
++
++ /* V-timing */
++ u32 vts_def;
++
++ /* Default register values */
++ struct imx219_reg_list reg_list;
++};
++
++/*
++ * Register sets lifted off the i2C interface from the Raspberry Pi firmware
++ * driver.
++ * 3280x2464 = mode 2, 1920x1080 = mode 1, and 1640x1232 = mode 4.
++ */
++static const struct imx219_reg mode_3280x2464_regs[] = {
++ {0x0100, 0x00},
++ {0x30eb, 0x0c},
++ {0x30eb, 0x05},
++ {0x300a, 0xff},
++ {0x300b, 0xff},
++ {0x30eb, 0x05},
++ {0x30eb, 0x09},
++ {0x0114, 0x01},
++ {0x0128, 0x00},
++ {0x012a, 0x18},
++ {0x012b, 0x00},
++ {0x0164, 0x00},
++ {0x0165, 0x00},
++ {0x0166, 0x0c},
++ {0x0167, 0xcf},
++ {0x0168, 0x00},
++ {0x0169, 0x00},
++ {0x016a, 0x09},
++ {0x016b, 0x9f},
++ {0x016c, 0x0c},
++ {0x016d, 0xd0},
++ {0x016e, 0x09},
++ {0x016f, 0xa0},
++ {0x0170, 0x01},
++ {0x0171, 0x01},
++ {0x0174, 0x00},
++ {0x0175, 0x00},
++ {0x018c, 0x0a},
++ {0x018d, 0x0a},
++ {0x0301, 0x05},
++ {0x0303, 0x01},
++ {0x0304, 0x03},
++ {0x0305, 0x03},
++ {0x0306, 0x00},
++ {0x0307, 0x39},
++ {0x0309, 0x0a},
++ {0x030b, 0x01},
++ {0x030c, 0x00},
++ {0x030d, 0x72},
++ {0x0624, 0x0c},
++ {0x0625, 0xd0},
++ {0x0626, 0x09},
++ {0x0627, 0xa0},
++ {0x455e, 0x00},
++ {0x471e, 0x4b},
++ {0x4767, 0x0f},
++ {0x4750, 0x14},
++ {0x4540, 0x00},
++ {0x47b4, 0x14},
++ {0x4713, 0x30},
++ {0x478b, 0x10},
++ {0x478f, 0x10},
++ {0x4793, 0x10},
++ {0x4797, 0x0e},
++ {0x479b, 0x0e},
++
++ {0x0172, 0x03},
++ {0x0162, 0x0d},
++ {0x0163, 0x78},
++};
++
++static const struct imx219_reg mode_1920_1080_regs[] = {
++ {0x0100, 0x00},
++ {0x30eb, 0x05},
++ {0x30eb, 0x0c},
++ {0x300a, 0xff},
++ {0x300b, 0xff},
++ {0x30eb, 0x05},
++ {0x30eb, 0x09},
++ {0x0114, 0x01},
++ {0x0128, 0x00},
++ {0x012a, 0x18},
++ {0x012b, 0x00},
++ {0x0162, 0x0d},
++ {0x0163, 0x78},
++ {0x0164, 0x02},
++ {0x0165, 0xa8},
++ {0x0166, 0x0a},
++ {0x0167, 0x27},
++ {0x0168, 0x02},
++ {0x0169, 0xb4},
++ {0x016a, 0x06},
++ {0x016b, 0xeb},
++ {0x016c, 0x07},
++ {0x016d, 0x80},
++ {0x016e, 0x04},
++ {0x016f, 0x38},
++ {0x0170, 0x01},
++ {0x0171, 0x01},
++ {0x0174, 0x00},
++ {0x0175, 0x00},
++ {0x018c, 0x0a},
++ {0x018d, 0x0a},
++ {0x0301, 0x05},
++ {0x0303, 0x01},
++ {0x0304, 0x03},
++ {0x0305, 0x03},
++ {0x0306, 0x00},
++ {0x0307, 0x39},
++ {0x0309, 0x0a},
++ {0x030b, 0x01},
++ {0x030c, 0x00},
++ {0x030d, 0x72},
++ {0x455e, 0x00},
++ {0x471e, 0x4b},
++ {0x4767, 0x0f},
++ {0x4750, 0x14},
++ {0x4540, 0x00},
++ {0x47b4, 0x14},
++ {0x4713, 0x30},
++ {0x478b, 0x10},
++ {0x478f, 0x10},
++ {0x4793, 0x10},
++ {0x4797, 0x0e},
++ {0x479b, 0x0e},
++
++ {0x0172, 0x03},
++ {0x0162, 0x0d},
++ {0x0163, 0x78},
++};
++
++static const struct imx219_reg mode_1640_1232_regs[] = {
++ {0x30eb, 0x0c},
++ {0x30eb, 0x05},
++ {0x300a, 0xff},
++ {0x300b, 0xff},
++ {0x30eb, 0x05},
++ {0x30eb, 0x09},
++ {0x0114, 0x01},
++ {0x0128, 0x00},
++ {0x012a, 0x18},
++ {0x012b, 0x00},
++ {0x0164, 0x00},
++ {0x0165, 0x00},
++ {0x0166, 0x0c},
++ {0x0167, 0xcf},
++ {0x0168, 0x00},
++ {0x0169, 0x00},
++ {0x016a, 0x09},
++ {0x016b, 0x9f},
++ {0x016c, 0x06},
++ {0x016d, 0x68},
++ {0x016e, 0x04},
++ {0x016f, 0xd0},
++ {0x0170, 0x01},
++ {0x0171, 0x01},
++ {0x0174, 0x01},
++ {0x0175, 0x01},
++ {0x018c, 0x0a},
++ {0x018d, 0x0a},
++ {0x0301, 0x05},
++ {0x0303, 0x01},
++ {0x0304, 0x03},
++ {0x0305, 0x03},
++ {0x0306, 0x00},
++ {0x0307, 0x39},
++ {0x0309, 0x0a},
++ {0x030b, 0x01},
++ {0x030c, 0x00},
++ {0x030d, 0x72},
++ {0x455e, 0x00},
++ {0x471e, 0x4b},
++ {0x4767, 0x0f},
++ {0x4750, 0x14},
++ {0x4540, 0x00},
++ {0x47b4, 0x14},
++ {0x4713, 0x30},
++ {0x478b, 0x10},
++ {0x478f, 0x10},
++ {0x4793, 0x10},
++ {0x4797, 0x0e},
++ {0x479b, 0x0e},
++
++ {0x0172, 0x03},
++ {0x0162, 0x0d},
++ {0x0163, 0x78},
++};
++
++static const char * const imx219_test_pattern_menu[] = {
++ "Disabled",
++ "Color Bars",
++ "Solid Color",
++ "Grey Color Bars",
++ "PN9"
++};
++
++static const int imx219_test_pattern_val[] = {
++ IMX219_TEST_PATTERN_DISABLE,
++ IMX219_TEST_PATTERN_COLOR_BARS,
++ IMX219_TEST_PATTERN_SOLID_COLOR,
++ IMX219_TEST_PATTERN_GREY_COLOR,
++ IMX219_TEST_PATTERN_PN9,
++};
++
++/* regulator supplies */
++static const char * const imx219_supply_name[] = {
++ /* Supplies can be enabled in any order */
++ "VANA", /* Analog (2.8V) supply */
++ "VDIG", /* Digital Core (1.8V) supply */
++ "VDDL", /* IF (1.2V) supply */
++};
++
++#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name)
++
++#define IMX219_XCLR_DELAY_MS 10 /* Initialisation delay after XCLR low->high */
++
++/* Mode configs */
++static const struct imx219_mode supported_modes[] = {
++ {
++ /* 8MPix 15fps mode */
++ .width = 3280,
++ .height = 2464,
++ .vts_def = IMX219_VTS_15FPS,
++ .reg_list = {
++ .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
++ .regs = mode_3280x2464_regs,
++ },
++ },
++ {
++ /* 1080P 30fps cropped */
++ .width = 1920,
++ .height = 1080,
++ .vts_def = IMX219_VTS_30FPS_1080P,
++ .reg_list = {
++ .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
++ .regs = mode_1920_1080_regs,
++ },
++ },
++ {
++ /* 2x2 binned 30fps mode */
++ .width = 1640,
++ .height = 1232,
++ .vts_def = IMX219_VTS_30FPS_BINNED,
++ .reg_list = {
++ .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs),
++ .regs = mode_1640_1232_regs,
++ },
++ },
++};
++
++struct imx219 {
++ struct v4l2_subdev sd;
++ struct media_pad pad;
++
++ struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
++ struct clk *xclk; /* system clock to IMX219 */
++ u32 xclk_freq;
++
++ struct gpio_desc *xclr_gpio;
++ struct regulator_bulk_data supplies[IMX219_NUM_SUPPLIES];
++
++ struct v4l2_ctrl_handler ctrl_handler;
++ /* V4L2 Controls */
++ struct v4l2_ctrl *pixel_rate;
++ struct v4l2_ctrl *exposure;
++
++ /* Current mode */
++ const struct imx219_mode *mode;
++
++ /*
++ * Mutex for serialized access:
++ * Protect sensor module set pad format and start/stop streaming safely.
++ */
++ struct mutex mutex;
++
++ int power_count;
++ /* Streaming on/off */
++ bool streaming;
++};
++
++static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd)
++{
++ return container_of(_sd, struct imx219, sd);
++}
++
++/* Read registers up to 2 at a time */
++static int imx219_read_reg(struct imx219 *imx219, u16 reg, u32 len, u32 *val)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ struct i2c_msg msgs[2];
++ u8 addr_buf[2] = { reg >> 8, reg & 0xff };
++ u8 data_buf[4] = { 0, };
++ int ret;
++
++ if (len > 4)
++ return -EINVAL;
++
++ /* Write register address */
++ msgs[0].addr = client->addr;
++ msgs[0].flags = 0;
++ msgs[0].len = ARRAY_SIZE(addr_buf);
++ msgs[0].buf = addr_buf;
++
++ /* Read data from register */
++ msgs[1].addr = client->addr;
++ msgs[1].flags = I2C_M_RD;
++ msgs[1].len = len;
++ msgs[1].buf = &data_buf[4 - len];
++
++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
++ if (ret != ARRAY_SIZE(msgs))
++ return -EIO;
++
++ *val = get_unaligned_be32(data_buf);
++
++ return 0;
++}
++
++/* Write registers up to 2 at a time */
++static int imx219_write_reg(struct imx219 *imx219, u16 reg, u32 len, u32 val)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ u8 buf[6];
++
++ if (len > 4)
++ return -EINVAL;
++
++ put_unaligned_be16(reg, buf);
++ put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
++ if (i2c_master_send(client, buf, len + 2) != len + 2)
++ return -EIO;
++
++ return 0;
++}
++
++/* Write a list of registers */
++static int imx219_write_regs(struct imx219 *imx219,
++ const struct imx219_reg *regs, u32 len)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ unsigned int i;
++ int ret;
++
++ for (i = 0; i < len; i++) {
++ ret = imx219_write_reg(imx219, regs[i].address, 1, regs[i].val);
++ if (ret) {
++ dev_err_ratelimited(&client->dev,
++ "Failed to write reg 0x%4.4x. error = %d\n",
++ regs[i].address, ret);
++
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++/* Power/clock management functions */
++static void imx219_power(struct imx219 *imx219, bool enable)
++{
++ gpiod_set_value_cansleep(imx219->xclr_gpio, enable ? 1 : 0);
++}
++
++static int imx219_set_power_on(struct imx219 *imx219)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ int ret;
++
++ ret = clk_prepare_enable(imx219->xclk);
++ if (ret) {
++ dev_err(&client->dev, "%s: failed to enable clock\n",
++ __func__);
++ return ret;
++ }
++
++ ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES,
++ imx219->supplies);
++ if (ret) {
++ dev_err(&client->dev, "%s: failed to enable regulators\n",
++ __func__);
++ goto xclk_off;
++ }
++
++ imx219_power(imx219, true);
++ msleep(IMX219_XCLR_DELAY_MS);
++
++ return 0;
++xclk_off:
++ clk_disable_unprepare(imx219->xclk);
++ return ret;
++}
++
++static void imx219_set_power_off(struct imx219 *imx219)
++{
++ imx219_power(imx219, false);
++ regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
++ clk_disable_unprepare(imx219->xclk);
++}
++
++static int imx219_set_power(struct imx219 *imx219, bool on)
++{
++ int ret = 0;
++
++ if (on) {
++ ret = imx219_set_power_on(imx219);
++ if (ret)
++ return ret;
++ } else {
++ imx219_set_power_off(imx219);
++ }
++
++ return 0;
++}
++
++/* Open sub-device */
++static int imx219_s_power(struct v4l2_subdev *sd, int on)
++{
++ struct imx219 *imx219 = to_imx219(sd);
++ int ret = 0;
++
++ mutex_lock(&imx219->mutex);
++
++ /*
++ * If the power count is modified from 0 to != 0 or from != 0 to 0,
++ * update the power state.
++ */
++ if (imx219->power_count == !on) {
++ ret = imx219_set_power(imx219, !!on);
++ if (ret)
++ goto out;
++ }
++
++ /* Update the power count. */
++ imx219->power_count += on ? 1 : -1;
++ WARN_ON(imx219->power_count < 0);
++out:
++ mutex_unlock(&imx219->mutex);
++
++ return ret;
++}
++
++static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
++{
++ struct v4l2_mbus_framefmt *try_fmt =
++ v4l2_subdev_get_try_format(sd, fh->pad, 0);
++
++ /* Initialize try_fmt */
++ try_fmt->width = supported_modes[0].width;
++ try_fmt->height = supported_modes[0].height;
++ try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
++ try_fmt->field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct imx219 *imx219 =
++ container_of(ctrl->handler, struct imx219, ctrl_handler);
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ int ret = 0;
++
++ /*
++ * Applying V4L2 control value only happens
++ * when power is up for streaming
++ */
++ if (pm_runtime_get_if_in_use(&client->dev) == 0)
++ return 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_ANALOGUE_GAIN:
++ ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN,
++ IMX219_REG_VALUE_08BIT, ctrl->val);
++ break;
++ case V4L2_CID_EXPOSURE:
++ ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE,
++ IMX219_REG_VALUE_16BIT, ctrl->val);
++ break;
++ case V4L2_CID_DIGITAL_GAIN:
++ ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN,
++ IMX219_REG_VALUE_16BIT, ctrl->val);
++ break;
++ case V4L2_CID_TEST_PATTERN:
++ ret = imx219_write_reg(imx219, IMX219_REG_TEST_PATTERN,
++ IMX219_REG_VALUE_16BIT,
++ imx219_test_pattern_val[ctrl->val]);
++ break;
++ default:
++ dev_info(&client->dev,
++ "ctrl(id:0x%x,val:0x%x) is not handled\n",
++ ctrl->id, ctrl->val);
++ ret = -EINVAL;
++ break;
++ }
++
++ pm_runtime_put(&client->dev);
++
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
++ .s_ctrl = imx219_set_ctrl,
++};
++
++static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ /* Only one bayer order(GRBG) is supported */
++ if (code->index > 0)
++ return -EINVAL;
++
++ code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
++
++ return 0;
++}
++
++static int imx219_enum_frame_size(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_frame_size_enum *fse)
++{
++ if (fse->index >= ARRAY_SIZE(supported_modes))
++ return -EINVAL;
++
++ if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
++ return -EINVAL;
++
++ fse->min_width = supported_modes[fse->index].width;
++ fse->max_width = fse->min_width;
++ fse->min_height = supported_modes[fse->index].height;
++ fse->max_height = fse->min_height;
++
++ return 0;
++}
++
++static void imx219_update_pad_format(const struct imx219_mode *mode,
++ struct v4l2_subdev_format *fmt)
++{
++ fmt->format.width = mode->width;
++ fmt->format.height = mode->height;
++ fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
++ fmt->format.field = V4L2_FIELD_NONE;
++}
++
++static int __imx219_get_pad_format(struct imx219 *imx219,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *fmt)
++{
++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
++ fmt->format = *v4l2_subdev_get_try_format(&imx219->sd, cfg,
++ fmt->pad);
++ else
++ imx219_update_pad_format(imx219->mode, fmt);
++
++ return 0;
++}
++
++static int imx219_get_pad_format(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *fmt)
++{
++ struct imx219 *imx219 = to_imx219(sd);
++ int ret;
++
++ mutex_lock(&imx219->mutex);
++ ret = __imx219_get_pad_format(imx219, cfg, fmt);
++ mutex_unlock(&imx219->mutex);
++
++ return ret;
++}
++
++static int imx219_set_pad_format(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *fmt)
++{
++ struct imx219 *imx219 = to_imx219(sd);
++ const struct imx219_mode *mode;
++ struct v4l2_mbus_framefmt *framefmt;
++
++ mutex_lock(&imx219->mutex);
++
++ /* Only one raw bayer(BGGR) order is supported */
++ fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
++
++ mode = v4l2_find_nearest_size(supported_modes,
++ ARRAY_SIZE(supported_modes),
++ width, height,
++ fmt->format.width, fmt->format.height);
++ imx219_update_pad_format(mode, fmt);
++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
++ framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
++ *framefmt = fmt->format;
++ } else {
++ imx219->mode = mode;
++ }
++
++ mutex_unlock(&imx219->mutex);
++
++ return 0;
++}
++
++/* Start streaming */
++static int imx219_start_streaming(struct imx219 *imx219)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ const struct imx219_reg_list *reg_list;
++ int ret;
++
++ /* Apply default values of current mode */
++ reg_list = &imx219->mode->reg_list;
++ ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs);
++ if (ret) {
++ dev_err(&client->dev, "%s failed to set mode\n", __func__);
++ return ret;
++ }
++
++ /*
++ * Set VTS appropriately for frame rate control.
++ * Currently fixed per mode.
++ */
++ ret = imx219_write_reg(imx219, IMX219_REG_VTS,
++ IMX219_REG_VALUE_16BIT, imx219->mode->vts_def);
++ if (ret)
++ return ret;
++
++ /* Apply customized values from user */
++ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
++ if (ret)
++ return ret;
++
++ /* set stream on register */
++ return imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
++ IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
++}
++
++/* Stop streaming */
++static int imx219_stop_streaming(struct imx219 *imx219)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ int ret;
++
++ /* set stream off register */
++ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
++ IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
++ if (ret)
++ dev_err(&client->dev, "%s failed to set stream\n", __func__);
++
++ /*
++ * Return success even if it was an error, as there is nothing the
++ * caller can do about it.
++ */
++ return 0;
++}
++
++static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
++{
++ struct imx219 *imx219 = to_imx219(sd);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret = 0;
++
++ mutex_lock(&imx219->mutex);
++ if (imx219->streaming == enable) {
++ mutex_unlock(&imx219->mutex);
++ return 0;
++ }
++
++ if (enable) {
++ ret = pm_runtime_get_sync(&client->dev);
++ if (ret < 0) {
++ pm_runtime_put_noidle(&client->dev);
++ goto err_unlock;
++ }
++
++ /*
++ * Apply default & customized values
++ * and then start streaming.
++ */
++ ret = imx219_start_streaming(imx219);
++ if (ret) {
++ pm_runtime_put(&client->dev);
++ goto err_unlock;
++ }
++ } else {
++ imx219_stop_streaming(imx219);
++ pm_runtime_put(&client->dev);
++ }
++
++ imx219->streaming = enable;
++ mutex_unlock(&imx219->mutex);
++
++ return ret;
++
++err_unlock:
++ mutex_unlock(&imx219->mutex);
++
++ return ret;
++}
++
++static int __maybe_unused imx219_suspend(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct imx219 *imx219 = to_imx219(sd);
++
++ if (imx219->streaming)
++ imx219_stop_streaming(imx219);
++
++ return 0;
++}
++
++static int __maybe_unused imx219_resume(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct imx219 *imx219 = to_imx219(sd);
++ int ret;
++
++ if (imx219->streaming) {
++ ret = imx219_start_streaming(imx219);
++ if (ret)
++ goto error;
++ }
++
++ return 0;
++
++error:
++ imx219_stop_streaming(imx219);
++ imx219->streaming = 0;
++ return ret;
++}
++
++static int imx219_get_regulators(struct imx219 *imx219)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ int i;
++
++ for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
++ imx219->supplies[i].supply = imx219_supply_name[i];
++
++ return devm_regulator_bulk_get(&client->dev,
++ IMX219_NUM_SUPPLIES,
++ imx219->supplies);
++}
++
++/* Verify chip ID */
++static int imx219_identify_module(struct imx219 *imx219)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ int ret;
++ u32 val;
++
++ ret = imx219_set_power_on(imx219);
++ if (ret)
++ return ret;
++
++ ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID,
++ IMX219_REG_VALUE_16BIT, &val);
++ if (ret) {
++ dev_err(&client->dev, "failed to read chip id %x\n",
++ IMX219_CHIP_ID);
++ goto power_off;
++ }
++
++ if (val != IMX219_CHIP_ID) {
++ dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
++ IMX219_CHIP_ID, val);
++ ret = -EIO;
++ }
++
++power_off:
++ imx219_set_power_off(imx219);
++ return ret;
++}
++
++static const struct v4l2_subdev_core_ops imx219_core_ops = {
++ .s_power = imx219_s_power,
++};
++
++static const struct v4l2_subdev_video_ops imx219_video_ops = {
++ .s_stream = imx219_set_stream,
++};
++
++static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
++ .enum_mbus_code = imx219_enum_mbus_code,
++ .get_fmt = imx219_get_pad_format,
++ .set_fmt = imx219_set_pad_format,
++ .enum_frame_size = imx219_enum_frame_size,
++};
++
++static const struct v4l2_subdev_ops imx219_subdev_ops = {
++ .core = &imx219_core_ops,
++ .video = &imx219_video_ops,
++ .pad = &imx219_pad_ops,
++};
++
++static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
++ .open = imx219_open,
++};
++
++/* Initialize control handlers */
++static int imx219_init_controls(struct imx219 *imx219)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ struct v4l2_ctrl_handler *ctrl_hdlr;
++ int ret;
++
++ ctrl_hdlr = &imx219->ctrl_handler;
++ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
++ if (ret)
++ return ret;
++
++ mutex_init(&imx219->mutex);
++ ctrl_hdlr->lock = &imx219->mutex;
++
++ imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++ V4L2_CID_EXPOSURE,
++ IMX219_EXPOSURE_MIN,
++ IMX219_EXPOSURE_MAX,
++ IMX219_EXPOSURE_STEP,
++ IMX219_EXPOSURE_DEFAULT);
++
++ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
++ IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
++ IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
++
++ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
++ IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
++ IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
++
++ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops,
++ V4L2_CID_TEST_PATTERN,
++ ARRAY_SIZE(imx219_test_pattern_menu) - 1,
++ 0, 0, imx219_test_pattern_menu);
++
++ if (ctrl_hdlr->error) {
++ ret = ctrl_hdlr->error;
++ dev_err(&client->dev, "%s control init failed (%d)\n",
++ __func__, ret);
++ goto error;
++ }
++
++ imx219->sd.ctrl_handler = ctrl_hdlr;
++
++ return 0;
++
++error:
++ v4l2_ctrl_handler_free(ctrl_hdlr);
++ mutex_destroy(&imx219->mutex);
++
++ return ret;
++}
++
++static void imx219_free_controls(struct imx219 *imx219)
++{
++ v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
++ mutex_destroy(&imx219->mutex);
++}
++
++static int imx219_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct device *dev = &client->dev;
++ struct fwnode_handle *endpoint;
++ struct imx219 *imx219;
++ int ret;
++
++ imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL);
++ if (!imx219)
++ return -ENOMEM;
++
++ /* Initialize subdev */
++ v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
++
++ /* Get CSI2 bus config */
++ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
++ NULL);
++ if (!endpoint) {
++ dev_err(dev, "endpoint node not found\n");
++ return -EINVAL;
++ }
++
++ ret = v4l2_fwnode_endpoint_parse(endpoint, &imx219->ep);
++ fwnode_handle_put(endpoint);
++ if (ret) {
++ dev_err(dev, "Could not parse endpoint\n");
++ return ret;
++ }
++
++ /* Get system clock (xclk) */
++ imx219->xclk = devm_clk_get(dev, "xclk");
++ if (IS_ERR(imx219->xclk)) {
++ dev_err(dev, "failed to get xclk\n");
++ return PTR_ERR(imx219->xclk);
++ }
++
++ imx219->xclk_freq = clk_get_rate(imx219->xclk);
++ if (imx219->xclk_freq != 24000000) {
++ dev_err(dev, "xclk frequency not supported: %d Hz\n",
++ imx219->xclk_freq);
++ return -EINVAL;
++ }
++
++ ret = imx219_get_regulators(imx219);
++ if (ret)
++ return ret;
++
++ /* request optional power down pin */
++ imx219->xclr_gpio = devm_gpiod_get_optional(dev, "xclr",
++ GPIOD_OUT_HIGH);
++
++ /* Check module identity */
++ ret = imx219_identify_module(imx219);
++ if (ret)
++ return ret;
++
++ /* Set default mode to max resolution */
++ imx219->mode = &supported_modes[0];
++
++ ret = imx219_init_controls(imx219);
++ if (ret)
++ return ret;
++
++ /* Initialize subdev */
++ imx219->sd.internal_ops = &imx219_internal_ops;
++ imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
++ imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
++
++ /* Initialize source pad */
++ imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
++
++ ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
++ if (ret)
++ goto error_handler_free;
++
++ ret = v4l2_async_register_subdev_sensor_common(&imx219->sd);
++ if (ret < 0)
++ goto error_media_entity;
++
++ pm_runtime_set_active(&client->dev);
++ pm_runtime_enable(&client->dev);
++ pm_runtime_idle(&client->dev);
++
++ return 0;
++
++error_media_entity:
++ media_entity_cleanup(&imx219->sd.entity);
++
++error_handler_free:
++ imx219_free_controls(imx219);
++
++ return ret;
++}
++
++static int imx219_remove(struct i2c_client *client)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct imx219 *imx219 = to_imx219(sd);
++
++ v4l2_async_unregister_subdev(sd);
++ media_entity_cleanup(&sd->entity);
++ imx219_free_controls(imx219);
++
++ pm_runtime_disable(&client->dev);
++ pm_runtime_set_suspended(&client->dev);
++
++ return 0;
++}
++
++static const struct of_device_id imx219_dt_ids[] = {
++ { .compatible = "sony,imx219" },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, imx219_dt_ids);
++
++static struct i2c_driver imx219_i2c_driver = {
++ .driver = {
++ .name = "imx219",
++ .of_match_table = imx219_dt_ids,
++ },
++ .probe = imx219_probe,
++ .remove = imx219_remove,
++};
++
++module_i2c_driver(imx219_i2c_driver);
++
++MODULE_DESCRIPTION("Sony IMX219 sensor driver");
++MODULE_LICENSE("GPL v2");
--- /dev/null
+From 7a4d12054b24c8cb980be4c6466b50c14beb78d3 Mon Sep 17 00:00:00 2001
+Date: Wed, 28 Aug 2019 13:35:19 +0100
+Subject: [PATCH] dtoverlays: Add overlay for the Sony IMX219 image
+ sensor.
+
+Adds an overlay for the IMX219 image sensor, connected to the
+Unicam CSI2 receiver peripheral.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 12 ++
+ arch/arm/boot/dts/overlays/imx219-overlay.dts | 129 ++++++++++++++++++
+ 3 files changed, 142 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/imx219-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -77,6 +77,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ i2c6.dtbo \
+ i2s-gpio28-31.dtbo \
+ ilitek251x.dtbo \
++ imx219.dtbo \
+ iqaudio-codec.dtbo \
+ iqaudio-dac.dtbo \
+ iqaudio-dacplus.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1269,6 +1269,18 @@ Params: interrupt GPIO use
+ touchscreen (in pixels)
+
+
++Name: imx219
++Info: Sony IMX219 camera module.
++ Uses Unicam 1, which is the standard camera connector on most Pi
++ variants.
++Load: dtoverlay=imx219,<param>=<val>
++Params: i2c_pins_0_1 Use pins 0&1 for the I2C instead of 44&45.
++ Useful on Compute Modules.
++
++ i2c_pins_28_29 Use pins 28&29 for the I2C instead of 44&45.
++ This is required for Pi B+, 2, 0, and 0W.
++
++
+ Name: iqaudio-codec
+ Info: Configures the IQaudio Codec audio card
+ Load: dtoverlay=iqaudio-codec
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/imx219-overlay.dts
+@@ -0,0 +1,129 @@
++// SPDX-License-Identifier: GPL-2.0-only
++// Definitions for IMX219 camera module on VC I2C bus
++/dts-v1/;
++/plugin/;
++
++#include <dt-bindings/gpio/gpio.h>
++
++/{
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&i2c_vc>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ imx219: imx219@10 {
++ compatible = "sony,imx219";
++ reg = <0x10>;
++ status = "okay";
++
++ clocks = <&imx219_clk>;
++ clock-names = "xclk";
++
++ VANA-supply = <&imx219_vana>; /* 2.8v */
++ VDIG-supply = <&imx219_vdig>; /* 1.8v */
++ VDDL-supply = <&imx219_vddl>; /* 1.2v */
++
++ imx219_clk: camera-clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <24000000>;
++ };
++
++ port {
++ imx219_0: endpoint {
++ remote-endpoint = <&csi1_ep>;
++ clock-lanes = <0>;
++ data-lanes = <1 2>;
++ clock-noncontinuous;
++ link-frequencies =
++ /bits/ 64 <297000000>;
++ };
++ };
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&csi1>;
++ __overlay__ {
++ status = "okay";
++
++ port {
++ csi1_ep: endpoint {
++ remote-endpoint = <&imx219_0>;
++ };
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c0_pins>;
++ __dormant__ {
++ brcm,pins = <28 29>;
++ brcm,function = <4>; /* alt0 */
++ };
++ };
++ fragment@3 {
++ target = <&i2c0_pins>;
++ __overlay__ {
++ brcm,pins = <44 45>;
++ brcm,function = <5>; /* alt1 */
++ };
++ };
++ fragment@4 {
++ target = <&i2c0_pins>;
++ __dormant__ {
++ brcm,pins = <0 1>;
++ brcm,function = <4>; /* alt0 */
++ };
++ };
++ fragment@5 {
++ target = <&i2c_vc>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@6 {
++ target-path="/";
++ __overlay__ {
++ imx219_vana: fixedregulator@0 {
++ compatible = "regulator-fixed";
++ regulator-name = "imx219_vana";
++ regulator-min-microvolt = <2800000>;
++ regulator-max-microvolt = <2800000>;
++ gpio = <&gpio 41 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++ 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>;
++ };
++ };
++ };
++
++ fragment@7 {
++ target-path="/__overrides__";
++ __overlay__ {
++ cam0-pwdn-ctrl = <&imx219_vana>,"gpio:0";
++ cam0-pwdn = <&imx219_vana>,"gpio:4";
++ };
++ };
++
++ __overrides__ {
++ i2c_pins_0_1 = <0>,"-2-3+4";
++ i2c_pins_28_29 = <0>,"+2-3-4";
++ };
++};
+++ /dev/null
-From 2d8a780a994098f7c532b712abd7298e0bca5a12 Mon Sep 17 00:00:00 2001
-Date: Wed, 28 Aug 2019 13:34:30 +0100
-Subject: [PATCH] media: dt-bindings: Add binding for the Sony IMX219
- sensor
-
-The IMX219 is an 8MPix CSI2 sensor, supporting 2 or 4 data lanes.
-Document the binding for this device.
-
----
- .../devicetree/bindings/media/i2c/imx219.txt | 59 +++++++++++++++++++
- 1 file changed, 59 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/media/i2c/imx219.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/media/i2c/imx219.txt
-@@ -0,0 +1,59 @@
-+* Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor
-+
-+The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor with
-+an active array size of 3280H x 2464V. It is programmable through I2C
-+interface. The I2C address is fixed to 0x10 as per sensor data sheet.
-+Image data is sent through MIPI CSI-2, which is configured as either 2 or 4
-+data lanes.
-+
-+Required Properties:
-+- compatible: value should be "sony,imx219" for imx219 sensor
-+- reg: I2C bus address of the device
-+- clocks: reference to the xclk input clock.
-+- clock-names: should be "xclk".
-+- DOVDD-supply: Digital I/O voltage supply, 1.8 volts
-+- AVDD-supply: Analog voltage supply, 2.8 volts
-+- DVDD-supply: Digital core voltage supply, 1.2 volts
-+
-+Optional Properties:
-+- xclr-gpios: reference to the GPIO connected to the xclr pin, if any. Must be
-+ released after all supplies are applied.
-+ This is an active high signal to the imx219.
-+
-+The imx219 device node should contain one 'port' child node with
-+an 'endpoint' subnode. For further reading on port node refer to
-+Documentation/devicetree/bindings/media/video-interfaces.txt.
-+
-+Endpoint node required properties for CSI-2 connection are:
-+- remote-endpoint: a phandle to the bus receiver's endpoint node.
-+- clock-lanes: should be set to <0> (clock lane on hardware lane 0)
-+- data-lanes: should be set to <1 2>, or <1 2 3 4> (two or four lane CSI-2
-+ supported)
-+
-+Example:
-+ sensor@10 {
-+ compatible = "sony,imx219";
-+ reg = <0x10>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ clocks = <&imx219_clk>;
-+ clock-names = "xclk";
-+ xclr-gpios = <&gpio_sensor 0 0>;
-+ DOVDD-supply = <&vgen4_reg>; /* 1.8v */
-+ AVDD-supply = <&vgen3_reg>; /* 2.8v */
-+ DVDD-supply = <&vgen2_reg>; /* 1.2v */
-+
-+ imx219_clk: camera-clk {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <24000000>;
-+ };
-+
-+ port {
-+ sensor_out: endpoint {
-+ remote-endpoint = <&csiss_in>;
-+ clock-lanes = <0>;
-+ data-lanes = <1 2>;
-+ };
-+ };
-+ };
+++ /dev/null
-From 2186344c6d83ccd169e16c048c8b43aff95545e2 Mon Sep 17 00:00:00 2001
-Date: Wed, 28 Aug 2019 13:34:49 +0100
-Subject: [PATCH] media: i2c: Add driver for Sony IMX219 sensor
-
-Adds a driver for the 8MPix Sony IMX219 CSI2 sensor.
-Whilst the sensor supports 2 or 4 CSI2 data lanes, this driver
-currently only supports 2 lanes.
-8MPix @ 15fps, 1080P @ 30fps (cropped FOV), and 1640x1232 (2x2 binned)
-@ 30fps are currently supported.
-
----
- drivers/media/i2c/Kconfig | 11 +
- drivers/media/i2c/Makefile | 1 +
- drivers/media/i2c/imx219.c | 1093 ++++++++++++++++++++++++++++++++++++
- 3 files changed, 1105 insertions(+)
- create mode 100644 drivers/media/i2c/imx219.c
-
---- a/drivers/media/i2c/Kconfig
-+++ b/drivers/media/i2c/Kconfig
-@@ -597,6 +597,17 @@ config VIDEO_APTINA_PLL
- config VIDEO_SMIAPP_PLL
- tristate
-
-+config VIDEO_IMX219
-+ tristate "Sony IMX219 sensor support"
-+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
-+ depends on MEDIA_CAMERA_SUPPORT
-+ help
-+ This is a Video4Linux2 sensor driver for the Sony
-+ IMX219 camera.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called imx219.
-+
- config VIDEO_IMX258
- tristate "Sony IMX258 sensor support"
- depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
---- a/drivers/media/i2c/Makefile
-+++ b/drivers/media/i2c/Makefile
-@@ -106,6 +106,7 @@ obj-$(CONFIG_VIDEO_I2C) += video-i2c.o
- obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
- obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
- obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
-+obj-$(CONFIG_VIDEO_IMX219) += imx219.o
- obj-$(CONFIG_VIDEO_IMX258) += imx258.o
- obj-$(CONFIG_VIDEO_IMX274) += imx274.o
-
---- /dev/null
-+++ b/drivers/media/i2c/imx219.c
-@@ -0,0 +1,1093 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * A V4L2 driver for Sony IMX219 cameras.
-+ * Copyright (C) 2019, Raspberry Pi (Trading) Ltd
-+ *
-+ * Based on Sony imx258 camera driver
-+ * Copyright (C) 2018 Intel Corporation
-+ *
-+ * DT / fwnode changes, and regulator / GPIO control taken from ov5640.c
-+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
-+ * Copyright (C) 2014-2017 Mentor Graphics Inc.
-+ *
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/clkdev.h>
-+#include <linux/delay.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/i2c.h>
-+#include <linux/module.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/regulator/consumer.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-mediabus.h>
-+#include <asm/unaligned.h>
-+
-+#define IMX219_REG_VALUE_08BIT 1
-+#define IMX219_REG_VALUE_16BIT 2
-+
-+#define IMX219_REG_MODE_SELECT 0x0100
-+#define IMX219_MODE_STANDBY 0x00
-+#define IMX219_MODE_STREAMING 0x01
-+
-+/* Chip ID */
-+#define IMX219_REG_CHIP_ID 0x0000
-+#define IMX219_CHIP_ID 0x0219
-+
-+/* V_TIMING internal */
-+#define IMX219_REG_VTS 0x0160
-+#define IMX219_VTS_15FPS 0x0dc6
-+#define IMX219_VTS_30FPS_1080P 0x06e3
-+#define IMX219_VTS_30FPS_BINNED 0x06e3
-+#define IMX219_VTS_MAX 0xffff
-+
-+/*Frame Length Line*/
-+#define IMX219_FLL_MIN 0x08a6
-+#define IMX219_FLL_MAX 0xffff
-+#define IMX219_FLL_STEP 1
-+#define IMX219_FLL_DEFAULT 0x0c98
-+
-+/* HBLANK control - read only */
-+#define IMX219_PPL_DEFAULT 5352
-+
-+/* Exposure control */
-+#define IMX219_REG_EXPOSURE 0x015a
-+#define IMX219_EXPOSURE_MIN 4
-+#define IMX219_EXPOSURE_STEP 1
-+#define IMX219_EXPOSURE_DEFAULT 0x640
-+#define IMX219_EXPOSURE_MAX 65535
-+
-+/* Analog gain control */
-+#define IMX219_REG_ANALOG_GAIN 0x0157
-+#define IMX219_ANA_GAIN_MIN 0
-+#define IMX219_ANA_GAIN_MAX 232
-+#define IMX219_ANA_GAIN_STEP 1
-+#define IMX219_ANA_GAIN_DEFAULT 0x0
-+
-+/* Digital gain control */
-+#define IMX219_REG_DIGITAL_GAIN 0x0158
-+#define IMX219_DGTL_GAIN_MIN 0x0100
-+#define IMX219_DGTL_GAIN_MAX 0x0fff
-+#define IMX219_DGTL_GAIN_DEFAULT 0x0100
-+#define IMX219_DGTL_GAIN_STEP 1
-+
-+/* Test Pattern Control */
-+#define IMX219_REG_TEST_PATTERN 0x0600
-+#define IMX219_TEST_PATTERN_DISABLE 0
-+#define IMX219_TEST_PATTERN_SOLID_COLOR 1
-+#define IMX219_TEST_PATTERN_COLOR_BARS 2
-+#define IMX219_TEST_PATTERN_GREY_COLOR 3
-+#define IMX219_TEST_PATTERN_PN9 4
-+
-+struct imx219_reg {
-+ u16 address;
-+ u8 val;
-+};
-+
-+struct imx219_reg_list {
-+ u32 num_of_regs;
-+ const struct imx219_reg *regs;
-+};
-+
-+/* Mode : resolution and related config&values */
-+struct imx219_mode {
-+ /* Frame width */
-+ u32 width;
-+ /* Frame height */
-+ u32 height;
-+
-+ /* V-timing */
-+ u32 vts_def;
-+
-+ /* Default register values */
-+ struct imx219_reg_list reg_list;
-+};
-+
-+/*
-+ * Register sets lifted off the i2C interface from the Raspberry Pi firmware
-+ * driver.
-+ * 3280x2464 = mode 2, 1920x1080 = mode 1, and 1640x1232 = mode 4.
-+ */
-+static const struct imx219_reg mode_3280x2464_regs[] = {
-+ {0x0100, 0x00},
-+ {0x30eb, 0x0c},
-+ {0x30eb, 0x05},
-+ {0x300a, 0xff},
-+ {0x300b, 0xff},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x09},
-+ {0x0114, 0x01},
-+ {0x0128, 0x00},
-+ {0x012a, 0x18},
-+ {0x012b, 0x00},
-+ {0x0164, 0x00},
-+ {0x0165, 0x00},
-+ {0x0166, 0x0c},
-+ {0x0167, 0xcf},
-+ {0x0168, 0x00},
-+ {0x0169, 0x00},
-+ {0x016a, 0x09},
-+ {0x016b, 0x9f},
-+ {0x016c, 0x0c},
-+ {0x016d, 0xd0},
-+ {0x016e, 0x09},
-+ {0x016f, 0xa0},
-+ {0x0170, 0x01},
-+ {0x0171, 0x01},
-+ {0x0174, 0x00},
-+ {0x0175, 0x00},
-+ {0x018c, 0x0a},
-+ {0x018d, 0x0a},
-+ {0x0301, 0x05},
-+ {0x0303, 0x01},
-+ {0x0304, 0x03},
-+ {0x0305, 0x03},
-+ {0x0306, 0x00},
-+ {0x0307, 0x39},
-+ {0x0309, 0x0a},
-+ {0x030b, 0x01},
-+ {0x030c, 0x00},
-+ {0x030d, 0x72},
-+ {0x0624, 0x0c},
-+ {0x0625, 0xd0},
-+ {0x0626, 0x09},
-+ {0x0627, 0xa0},
-+ {0x455e, 0x00},
-+ {0x471e, 0x4b},
-+ {0x4767, 0x0f},
-+ {0x4750, 0x14},
-+ {0x4540, 0x00},
-+ {0x47b4, 0x14},
-+ {0x4713, 0x30},
-+ {0x478b, 0x10},
-+ {0x478f, 0x10},
-+ {0x4793, 0x10},
-+ {0x4797, 0x0e},
-+ {0x479b, 0x0e},
-+
-+ {0x0172, 0x03},
-+ {0x0162, 0x0d},
-+ {0x0163, 0x78},
-+};
-+
-+static const struct imx219_reg mode_1920_1080_regs[] = {
-+ {0x0100, 0x00},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x0c},
-+ {0x300a, 0xff},
-+ {0x300b, 0xff},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x09},
-+ {0x0114, 0x01},
-+ {0x0128, 0x00},
-+ {0x012a, 0x18},
-+ {0x012b, 0x00},
-+ {0x0162, 0x0d},
-+ {0x0163, 0x78},
-+ {0x0164, 0x02},
-+ {0x0165, 0xa8},
-+ {0x0166, 0x0a},
-+ {0x0167, 0x27},
-+ {0x0168, 0x02},
-+ {0x0169, 0xb4},
-+ {0x016a, 0x06},
-+ {0x016b, 0xeb},
-+ {0x016c, 0x07},
-+ {0x016d, 0x80},
-+ {0x016e, 0x04},
-+ {0x016f, 0x38},
-+ {0x0170, 0x01},
-+ {0x0171, 0x01},
-+ {0x0174, 0x00},
-+ {0x0175, 0x00},
-+ {0x018c, 0x0a},
-+ {0x018d, 0x0a},
-+ {0x0301, 0x05},
-+ {0x0303, 0x01},
-+ {0x0304, 0x03},
-+ {0x0305, 0x03},
-+ {0x0306, 0x00},
-+ {0x0307, 0x39},
-+ {0x0309, 0x0a},
-+ {0x030b, 0x01},
-+ {0x030c, 0x00},
-+ {0x030d, 0x72},
-+ {0x455e, 0x00},
-+ {0x471e, 0x4b},
-+ {0x4767, 0x0f},
-+ {0x4750, 0x14},
-+ {0x4540, 0x00},
-+ {0x47b4, 0x14},
-+ {0x4713, 0x30},
-+ {0x478b, 0x10},
-+ {0x478f, 0x10},
-+ {0x4793, 0x10},
-+ {0x4797, 0x0e},
-+ {0x479b, 0x0e},
-+
-+ {0x0172, 0x03},
-+ {0x0162, 0x0d},
-+ {0x0163, 0x78},
-+};
-+
-+static const struct imx219_reg mode_1640_1232_regs[] = {
-+ {0x30eb, 0x0c},
-+ {0x30eb, 0x05},
-+ {0x300a, 0xff},
-+ {0x300b, 0xff},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x09},
-+ {0x0114, 0x01},
-+ {0x0128, 0x00},
-+ {0x012a, 0x18},
-+ {0x012b, 0x00},
-+ {0x0164, 0x00},
-+ {0x0165, 0x00},
-+ {0x0166, 0x0c},
-+ {0x0167, 0xcf},
-+ {0x0168, 0x00},
-+ {0x0169, 0x00},
-+ {0x016a, 0x09},
-+ {0x016b, 0x9f},
-+ {0x016c, 0x06},
-+ {0x016d, 0x68},
-+ {0x016e, 0x04},
-+ {0x016f, 0xd0},
-+ {0x0170, 0x01},
-+ {0x0171, 0x01},
-+ {0x0174, 0x01},
-+ {0x0175, 0x01},
-+ {0x018c, 0x0a},
-+ {0x018d, 0x0a},
-+ {0x0301, 0x05},
-+ {0x0303, 0x01},
-+ {0x0304, 0x03},
-+ {0x0305, 0x03},
-+ {0x0306, 0x00},
-+ {0x0307, 0x39},
-+ {0x0309, 0x0a},
-+ {0x030b, 0x01},
-+ {0x030c, 0x00},
-+ {0x030d, 0x72},
-+ {0x455e, 0x00},
-+ {0x471e, 0x4b},
-+ {0x4767, 0x0f},
-+ {0x4750, 0x14},
-+ {0x4540, 0x00},
-+ {0x47b4, 0x14},
-+ {0x4713, 0x30},
-+ {0x478b, 0x10},
-+ {0x478f, 0x10},
-+ {0x4793, 0x10},
-+ {0x4797, 0x0e},
-+ {0x479b, 0x0e},
-+
-+ {0x0172, 0x03},
-+ {0x0162, 0x0d},
-+ {0x0163, 0x78},
-+};
-+
-+static const char * const imx219_test_pattern_menu[] = {
-+ "Disabled",
-+ "Color Bars",
-+ "Solid Color",
-+ "Grey Color Bars",
-+ "PN9"
-+};
-+
-+static const int imx219_test_pattern_val[] = {
-+ IMX219_TEST_PATTERN_DISABLE,
-+ IMX219_TEST_PATTERN_COLOR_BARS,
-+ IMX219_TEST_PATTERN_SOLID_COLOR,
-+ IMX219_TEST_PATTERN_GREY_COLOR,
-+ IMX219_TEST_PATTERN_PN9,
-+};
-+
-+/* regulator supplies */
-+static const char * const imx219_supply_name[] = {
-+ /* Supplies can be enabled in any order */
-+ "VANA", /* Analog (2.8V) supply */
-+ "VDIG", /* Digital Core (1.8V) supply */
-+ "VDDL", /* IF (1.2V) supply */
-+};
-+
-+#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name)
-+
-+#define IMX219_XCLR_DELAY_MS 10 /* Initialisation delay after XCLR low->high */
-+
-+/* Mode configs */
-+static const struct imx219_mode supported_modes[] = {
-+ {
-+ /* 8MPix 15fps mode */
-+ .width = 3280,
-+ .height = 2464,
-+ .vts_def = IMX219_VTS_15FPS,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
-+ .regs = mode_3280x2464_regs,
-+ },
-+ },
-+ {
-+ /* 1080P 30fps cropped */
-+ .width = 1920,
-+ .height = 1080,
-+ .vts_def = IMX219_VTS_30FPS_1080P,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
-+ .regs = mode_1920_1080_regs,
-+ },
-+ },
-+ {
-+ /* 2x2 binned 30fps mode */
-+ .width = 1640,
-+ .height = 1232,
-+ .vts_def = IMX219_VTS_30FPS_BINNED,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs),
-+ .regs = mode_1640_1232_regs,
-+ },
-+ },
-+};
-+
-+struct imx219 {
-+ struct v4l2_subdev sd;
-+ struct media_pad pad;
-+
-+ struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
-+ struct clk *xclk; /* system clock to IMX219 */
-+ u32 xclk_freq;
-+
-+ struct gpio_desc *xclr_gpio;
-+ struct regulator_bulk_data supplies[IMX219_NUM_SUPPLIES];
-+
-+ struct v4l2_ctrl_handler ctrl_handler;
-+ /* V4L2 Controls */
-+ struct v4l2_ctrl *pixel_rate;
-+ struct v4l2_ctrl *exposure;
-+
-+ /* Current mode */
-+ const struct imx219_mode *mode;
-+
-+ /*
-+ * Mutex for serialized access:
-+ * Protect sensor module set pad format and start/stop streaming safely.
-+ */
-+ struct mutex mutex;
-+
-+ int power_count;
-+ /* Streaming on/off */
-+ bool streaming;
-+};
-+
-+static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd)
-+{
-+ return container_of(_sd, struct imx219, sd);
-+}
-+
-+/* Read registers up to 2 at a time */
-+static int imx219_read_reg(struct imx219 *imx219, u16 reg, u32 len, u32 *val)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ struct i2c_msg msgs[2];
-+ u8 addr_buf[2] = { reg >> 8, reg & 0xff };
-+ u8 data_buf[4] = { 0, };
-+ int ret;
-+
-+ if (len > 4)
-+ return -EINVAL;
-+
-+ /* Write register address */
-+ msgs[0].addr = client->addr;
-+ msgs[0].flags = 0;
-+ msgs[0].len = ARRAY_SIZE(addr_buf);
-+ msgs[0].buf = addr_buf;
-+
-+ /* Read data from register */
-+ msgs[1].addr = client->addr;
-+ msgs[1].flags = I2C_M_RD;
-+ msgs[1].len = len;
-+ msgs[1].buf = &data_buf[4 - len];
-+
-+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
-+ if (ret != ARRAY_SIZE(msgs))
-+ return -EIO;
-+
-+ *val = get_unaligned_be32(data_buf);
-+
-+ return 0;
-+}
-+
-+/* Write registers up to 2 at a time */
-+static int imx219_write_reg(struct imx219 *imx219, u16 reg, u32 len, u32 val)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ u8 buf[6];
-+
-+ if (len > 4)
-+ return -EINVAL;
-+
-+ put_unaligned_be16(reg, buf);
-+ put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
-+ if (i2c_master_send(client, buf, len + 2) != len + 2)
-+ return -EIO;
-+
-+ return 0;
-+}
-+
-+/* Write a list of registers */
-+static int imx219_write_regs(struct imx219 *imx219,
-+ const struct imx219_reg *regs, u32 len)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ unsigned int i;
-+ int ret;
-+
-+ for (i = 0; i < len; i++) {
-+ ret = imx219_write_reg(imx219, regs[i].address, 1, regs[i].val);
-+ if (ret) {
-+ dev_err_ratelimited(&client->dev,
-+ "Failed to write reg 0x%4.4x. error = %d\n",
-+ regs[i].address, ret);
-+
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+/* Power/clock management functions */
-+static void imx219_power(struct imx219 *imx219, bool enable)
-+{
-+ gpiod_set_value_cansleep(imx219->xclr_gpio, enable ? 1 : 0);
-+}
-+
-+static int imx219_set_power_on(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int ret;
-+
-+ ret = clk_prepare_enable(imx219->xclk);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable clock\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES,
-+ imx219->supplies);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable regulators\n",
-+ __func__);
-+ goto xclk_off;
-+ }
-+
-+ imx219_power(imx219, true);
-+ msleep(IMX219_XCLR_DELAY_MS);
-+
-+ return 0;
-+xclk_off:
-+ clk_disable_unprepare(imx219->xclk);
-+ return ret;
-+}
-+
-+static void imx219_set_power_off(struct imx219 *imx219)
-+{
-+ imx219_power(imx219, false);
-+ regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
-+ clk_disable_unprepare(imx219->xclk);
-+}
-+
-+static int imx219_set_power(struct imx219 *imx219, bool on)
-+{
-+ int ret = 0;
-+
-+ if (on) {
-+ ret = imx219_set_power_on(imx219);
-+ if (ret)
-+ return ret;
-+ } else {
-+ imx219_set_power_off(imx219);
-+ }
-+
-+ return 0;
-+}
-+
-+/* Open sub-device */
-+static int imx219_s_power(struct v4l2_subdev *sd, int on)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ int ret = 0;
-+
-+ mutex_lock(&imx219->mutex);
-+
-+ /*
-+ * If the power count is modified from 0 to != 0 or from != 0 to 0,
-+ * update the power state.
-+ */
-+ if (imx219->power_count == !on) {
-+ ret = imx219_set_power(imx219, !!on);
-+ if (ret)
-+ goto out;
-+ }
-+
-+ /* Update the power count. */
-+ imx219->power_count += on ? 1 : -1;
-+ WARN_ON(imx219->power_count < 0);
-+out:
-+ mutex_unlock(&imx219->mutex);
-+
-+ return ret;
-+}
-+
-+static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-+{
-+ struct v4l2_mbus_framefmt *try_fmt =
-+ v4l2_subdev_get_try_format(sd, fh->pad, 0);
-+
-+ /* Initialize try_fmt */
-+ try_fmt->width = supported_modes[0].width;
-+ try_fmt->height = supported_modes[0].height;
-+ try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+ try_fmt->field = V4L2_FIELD_NONE;
-+
-+ return 0;
-+}
-+
-+static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct imx219 *imx219 =
-+ container_of(ctrl->handler, struct imx219, ctrl_handler);
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int ret = 0;
-+
-+ /*
-+ * Applying V4L2 control value only happens
-+ * when power is up for streaming
-+ */
-+ if (pm_runtime_get_if_in_use(&client->dev) == 0)
-+ return 0;
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_ANALOGUE_GAIN:
-+ ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN,
-+ IMX219_REG_VALUE_08BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_EXPOSURE:
-+ ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE,
-+ IMX219_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_DIGITAL_GAIN:
-+ ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN,
-+ IMX219_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN:
-+ ret = imx219_write_reg(imx219, IMX219_REG_TEST_PATTERN,
-+ IMX219_REG_VALUE_16BIT,
-+ imx219_test_pattern_val[ctrl->val]);
-+ break;
-+ default:
-+ dev_info(&client->dev,
-+ "ctrl(id:0x%x,val:0x%x) is not handled\n",
-+ ctrl->id, ctrl->val);
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ pm_runtime_put(&client->dev);
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
-+ .s_ctrl = imx219_set_ctrl,
-+};
-+
-+static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ /* Only one bayer order(GRBG) is supported */
-+ if (code->index > 0)
-+ return -EINVAL;
-+
-+ code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+
-+ return 0;
-+}
-+
-+static int imx219_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ if (fse->index >= ARRAY_SIZE(supported_modes))
-+ return -EINVAL;
-+
-+ if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
-+ return -EINVAL;
-+
-+ fse->min_width = supported_modes[fse->index].width;
-+ fse->max_width = fse->min_width;
-+ fse->min_height = supported_modes[fse->index].height;
-+ fse->max_height = fse->min_height;
-+
-+ return 0;
-+}
-+
-+static void imx219_update_pad_format(const struct imx219_mode *mode,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ fmt->format.width = mode->width;
-+ fmt->format.height = mode->height;
-+ fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+ fmt->format.field = V4L2_FIELD_NONE;
-+}
-+
-+static int __imx219_get_pad_format(struct imx219 *imx219,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-+ fmt->format = *v4l2_subdev_get_try_format(&imx219->sd, cfg,
-+ fmt->pad);
-+ else
-+ imx219_update_pad_format(imx219->mode, fmt);
-+
-+ return 0;
-+}
-+
-+static int imx219_get_pad_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ int ret;
-+
-+ mutex_lock(&imx219->mutex);
-+ ret = __imx219_get_pad_format(imx219, cfg, fmt);
-+ mutex_unlock(&imx219->mutex);
-+
-+ return ret;
-+}
-+
-+static int imx219_set_pad_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ const struct imx219_mode *mode;
-+ struct v4l2_mbus_framefmt *framefmt;
-+
-+ mutex_lock(&imx219->mutex);
-+
-+ /* Only one raw bayer(BGGR) order is supported */
-+ fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+
-+ mode = v4l2_find_nearest_size(supported_modes,
-+ ARRAY_SIZE(supported_modes),
-+ width, height,
-+ fmt->format.width, fmt->format.height);
-+ imx219_update_pad_format(mode, fmt);
-+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-+ framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
-+ *framefmt = fmt->format;
-+ } else {
-+ imx219->mode = mode;
-+ }
-+
-+ mutex_unlock(&imx219->mutex);
-+
-+ return 0;
-+}
-+
-+/* Start streaming */
-+static int imx219_start_streaming(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ const struct imx219_reg_list *reg_list;
-+ int ret;
-+
-+ /* Apply default values of current mode */
-+ reg_list = &imx219->mode->reg_list;
-+ ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs);
-+ if (ret) {
-+ dev_err(&client->dev, "%s failed to set mode\n", __func__);
-+ return ret;
-+ }
-+
-+ /*
-+ * Set VTS appropriately for frame rate control.
-+ * Currently fixed per mode.
-+ */
-+ ret = imx219_write_reg(imx219, IMX219_REG_VTS,
-+ IMX219_REG_VALUE_16BIT, imx219->mode->vts_def);
-+ if (ret)
-+ return ret;
-+
-+ /* Apply customized values from user */
-+ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
-+ if (ret)
-+ return ret;
-+
-+ /* set stream on register */
-+ return imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
-+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
-+}
-+
-+/* Stop streaming */
-+static int imx219_stop_streaming(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int ret;
-+
-+ /* set stream off register */
-+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
-+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
-+ if (ret)
-+ dev_err(&client->dev, "%s failed to set stream\n", __func__);
-+
-+ /*
-+ * Return success even if it was an error, as there is nothing the
-+ * caller can do about it.
-+ */
-+ return 0;
-+}
-+
-+static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+ int ret = 0;
-+
-+ mutex_lock(&imx219->mutex);
-+ if (imx219->streaming == enable) {
-+ mutex_unlock(&imx219->mutex);
-+ return 0;
-+ }
-+
-+ if (enable) {
-+ ret = pm_runtime_get_sync(&client->dev);
-+ if (ret < 0) {
-+ pm_runtime_put_noidle(&client->dev);
-+ goto err_unlock;
-+ }
-+
-+ /*
-+ * Apply default & customized values
-+ * and then start streaming.
-+ */
-+ ret = imx219_start_streaming(imx219);
-+ if (ret) {
-+ pm_runtime_put(&client->dev);
-+ goto err_unlock;
-+ }
-+ } else {
-+ imx219_stop_streaming(imx219);
-+ pm_runtime_put(&client->dev);
-+ }
-+
-+ imx219->streaming = enable;
-+ mutex_unlock(&imx219->mutex);
-+
-+ return ret;
-+
-+err_unlock:
-+ mutex_unlock(&imx219->mutex);
-+
-+ return ret;
-+}
-+
-+static int __maybe_unused imx219_suspend(struct device *dev)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct imx219 *imx219 = to_imx219(sd);
-+
-+ if (imx219->streaming)
-+ imx219_stop_streaming(imx219);
-+
-+ return 0;
-+}
-+
-+static int __maybe_unused imx219_resume(struct device *dev)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct imx219 *imx219 = to_imx219(sd);
-+ int ret;
-+
-+ if (imx219->streaming) {
-+ ret = imx219_start_streaming(imx219);
-+ if (ret)
-+ goto error;
-+ }
-+
-+ return 0;
-+
-+error:
-+ imx219_stop_streaming(imx219);
-+ imx219->streaming = 0;
-+ return ret;
-+}
-+
-+static int imx219_get_regulators(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int i;
-+
-+ for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
-+ imx219->supplies[i].supply = imx219_supply_name[i];
-+
-+ return devm_regulator_bulk_get(&client->dev,
-+ IMX219_NUM_SUPPLIES,
-+ imx219->supplies);
-+}
-+
-+/* Verify chip ID */
-+static int imx219_identify_module(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int ret;
-+ u32 val;
-+
-+ ret = imx219_set_power_on(imx219);
-+ if (ret)
-+ return ret;
-+
-+ ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID,
-+ IMX219_REG_VALUE_16BIT, &val);
-+ if (ret) {
-+ dev_err(&client->dev, "failed to read chip id %x\n",
-+ IMX219_CHIP_ID);
-+ goto power_off;
-+ }
-+
-+ if (val != IMX219_CHIP_ID) {
-+ dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
-+ IMX219_CHIP_ID, val);
-+ ret = -EIO;
-+ }
-+
-+power_off:
-+ imx219_set_power_off(imx219);
-+ return ret;
-+}
-+
-+static const struct v4l2_subdev_core_ops imx219_core_ops = {
-+ .s_power = imx219_s_power,
-+};
-+
-+static const struct v4l2_subdev_video_ops imx219_video_ops = {
-+ .s_stream = imx219_set_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
-+ .enum_mbus_code = imx219_enum_mbus_code,
-+ .get_fmt = imx219_get_pad_format,
-+ .set_fmt = imx219_set_pad_format,
-+ .enum_frame_size = imx219_enum_frame_size,
-+};
-+
-+static const struct v4l2_subdev_ops imx219_subdev_ops = {
-+ .core = &imx219_core_ops,
-+ .video = &imx219_video_ops,
-+ .pad = &imx219_pad_ops,
-+};
-+
-+static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
-+ .open = imx219_open,
-+};
-+
-+/* Initialize control handlers */
-+static int imx219_init_controls(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ struct v4l2_ctrl_handler *ctrl_hdlr;
-+ int ret;
-+
-+ ctrl_hdlr = &imx219->ctrl_handler;
-+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
-+ if (ret)
-+ return ret;
-+
-+ mutex_init(&imx219->mutex);
-+ ctrl_hdlr->lock = &imx219->mutex;
-+
-+ imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
-+ V4L2_CID_EXPOSURE,
-+ IMX219_EXPOSURE_MIN,
-+ IMX219_EXPOSURE_MAX,
-+ IMX219_EXPOSURE_STEP,
-+ IMX219_EXPOSURE_DEFAULT);
-+
-+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
-+ IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
-+ IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
-+
-+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
-+ IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
-+ IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
-+
-+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops,
-+ V4L2_CID_TEST_PATTERN,
-+ ARRAY_SIZE(imx219_test_pattern_menu) - 1,
-+ 0, 0, imx219_test_pattern_menu);
-+
-+ if (ctrl_hdlr->error) {
-+ ret = ctrl_hdlr->error;
-+ dev_err(&client->dev, "%s control init failed (%d)\n",
-+ __func__, ret);
-+ goto error;
-+ }
-+
-+ imx219->sd.ctrl_handler = ctrl_hdlr;
-+
-+ return 0;
-+
-+error:
-+ v4l2_ctrl_handler_free(ctrl_hdlr);
-+ mutex_destroy(&imx219->mutex);
-+
-+ return ret;
-+}
-+
-+static void imx219_free_controls(struct imx219 *imx219)
-+{
-+ v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
-+ mutex_destroy(&imx219->mutex);
-+}
-+
-+static int imx219_probe(struct i2c_client *client,
-+ const struct i2c_device_id *id)
-+{
-+ struct device *dev = &client->dev;
-+ struct fwnode_handle *endpoint;
-+ struct imx219 *imx219;
-+ int ret;
-+
-+ imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL);
-+ if (!imx219)
-+ return -ENOMEM;
-+
-+ /* Initialize subdev */
-+ v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
-+
-+ /* Get CSI2 bus config */
-+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
-+ NULL);
-+ if (!endpoint) {
-+ dev_err(dev, "endpoint node not found\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = v4l2_fwnode_endpoint_parse(endpoint, &imx219->ep);
-+ fwnode_handle_put(endpoint);
-+ if (ret) {
-+ dev_err(dev, "Could not parse endpoint\n");
-+ return ret;
-+ }
-+
-+ /* Get system clock (xclk) */
-+ imx219->xclk = devm_clk_get(dev, "xclk");
-+ if (IS_ERR(imx219->xclk)) {
-+ dev_err(dev, "failed to get xclk\n");
-+ return PTR_ERR(imx219->xclk);
-+ }
-+
-+ imx219->xclk_freq = clk_get_rate(imx219->xclk);
-+ if (imx219->xclk_freq != 24000000) {
-+ dev_err(dev, "xclk frequency not supported: %d Hz\n",
-+ imx219->xclk_freq);
-+ return -EINVAL;
-+ }
-+
-+ ret = imx219_get_regulators(imx219);
-+ if (ret)
-+ return ret;
-+
-+ /* request optional power down pin */
-+ imx219->xclr_gpio = devm_gpiod_get_optional(dev, "xclr",
-+ GPIOD_OUT_HIGH);
-+
-+ /* Check module identity */
-+ ret = imx219_identify_module(imx219);
-+ if (ret)
-+ return ret;
-+
-+ /* Set default mode to max resolution */
-+ imx219->mode = &supported_modes[0];
-+
-+ ret = imx219_init_controls(imx219);
-+ if (ret)
-+ return ret;
-+
-+ /* Initialize subdev */
-+ imx219->sd.internal_ops = &imx219_internal_ops;
-+ imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-+ imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-+
-+ /* Initialize source pad */
-+ imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
-+
-+ ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
-+ if (ret)
-+ goto error_handler_free;
-+
-+ ret = v4l2_async_register_subdev_sensor_common(&imx219->sd);
-+ if (ret < 0)
-+ goto error_media_entity;
-+
-+ pm_runtime_set_active(&client->dev);
-+ pm_runtime_enable(&client->dev);
-+ pm_runtime_idle(&client->dev);
-+
-+ return 0;
-+
-+error_media_entity:
-+ media_entity_cleanup(&imx219->sd.entity);
-+
-+error_handler_free:
-+ imx219_free_controls(imx219);
-+
-+ return ret;
-+}
-+
-+static int imx219_remove(struct i2c_client *client)
-+{
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct imx219 *imx219 = to_imx219(sd);
-+
-+ v4l2_async_unregister_subdev(sd);
-+ media_entity_cleanup(&sd->entity);
-+ imx219_free_controls(imx219);
-+
-+ pm_runtime_disable(&client->dev);
-+ pm_runtime_set_suspended(&client->dev);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id imx219_dt_ids[] = {
-+ { .compatible = "sony,imx219" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, imx219_dt_ids);
-+
-+static struct i2c_driver imx219_i2c_driver = {
-+ .driver = {
-+ .name = "imx219",
-+ .of_match_table = imx219_dt_ids,
-+ },
-+ .probe = imx219_probe,
-+ .remove = imx219_remove,
-+};
-+
-+module_i2c_driver(imx219_i2c_driver);
-+
-+MODULE_DESCRIPTION("Sony IMX219 sensor driver");
-+MODULE_LICENSE("GPL v2");
--- /dev/null
+From d4fc8b1d50522b416baeb1d1f5e5498000af5a7f Mon Sep 17 00:00:00 2001
+Date: Sun, 28 Apr 2019 12:15:35 +0200
+Subject: [PATCH] staging: bcm2835-codec: Fix non-documentation comment
+ block
+
+The job_ready comment is incorrectly using the documentation prefix
+(/**) which causes a warning at build time.
+
+Simplify it.
+
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -557,7 +557,7 @@ static struct vchiq_mmal_port *get_port_
+ * mem2mem callbacks
+ */
+
+-/**
++/*
+ * job_ready() - check whether an instance is ready to be scheduled to run
+ */
+ static int job_ready(void *priv)
+++ /dev/null
-From 7a4d12054b24c8cb980be4c6466b50c14beb78d3 Mon Sep 17 00:00:00 2001
-Date: Wed, 28 Aug 2019 13:35:19 +0100
-Subject: [PATCH] dtoverlays: Add overlay for the Sony IMX219 image
- sensor.
-
-Adds an overlay for the IMX219 image sensor, connected to the
-Unicam CSI2 receiver peripheral.
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 12 ++
- arch/arm/boot/dts/overlays/imx219-overlay.dts | 129 ++++++++++++++++++
- 3 files changed, 142 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/imx219-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -77,6 +77,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- i2c6.dtbo \
- i2s-gpio28-31.dtbo \
- ilitek251x.dtbo \
-+ imx219.dtbo \
- iqaudio-codec.dtbo \
- iqaudio-dac.dtbo \
- iqaudio-dacplus.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1269,6 +1269,18 @@ Params: interrupt GPIO use
- touchscreen (in pixels)
-
-
-+Name: imx219
-+Info: Sony IMX219 camera module.
-+ Uses Unicam 1, which is the standard camera connector on most Pi
-+ variants.
-+Load: dtoverlay=imx219,<param>=<val>
-+Params: i2c_pins_0_1 Use pins 0&1 for the I2C instead of 44&45.
-+ Useful on Compute Modules.
-+
-+ i2c_pins_28_29 Use pins 28&29 for the I2C instead of 44&45.
-+ This is required for Pi B+, 2, 0, and 0W.
-+
-+
- Name: iqaudio-codec
- Info: Configures the IQaudio Codec audio card
- Load: dtoverlay=iqaudio-codec
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/imx219-overlay.dts
-@@ -0,0 +1,129 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+// Definitions for IMX219 camera module on VC I2C bus
-+/dts-v1/;
-+/plugin/;
-+
-+#include <dt-bindings/gpio/gpio.h>
-+
-+/{
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&i2c_vc>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ imx219: imx219@10 {
-+ compatible = "sony,imx219";
-+ reg = <0x10>;
-+ status = "okay";
-+
-+ clocks = <&imx219_clk>;
-+ clock-names = "xclk";
-+
-+ VANA-supply = <&imx219_vana>; /* 2.8v */
-+ VDIG-supply = <&imx219_vdig>; /* 1.8v */
-+ VDDL-supply = <&imx219_vddl>; /* 1.2v */
-+
-+ imx219_clk: camera-clk {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <24000000>;
-+ };
-+
-+ port {
-+ imx219_0: endpoint {
-+ remote-endpoint = <&csi1_ep>;
-+ clock-lanes = <0>;
-+ data-lanes = <1 2>;
-+ clock-noncontinuous;
-+ link-frequencies =
-+ /bits/ 64 <297000000>;
-+ };
-+ };
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&csi1>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ port {
-+ csi1_ep: endpoint {
-+ remote-endpoint = <&imx219_0>;
-+ };
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c0_pins>;
-+ __dormant__ {
-+ brcm,pins = <28 29>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+ };
-+ fragment@3 {
-+ target = <&i2c0_pins>;
-+ __overlay__ {
-+ brcm,pins = <44 45>;
-+ brcm,function = <5>; /* alt1 */
-+ };
-+ };
-+ fragment@4 {
-+ target = <&i2c0_pins>;
-+ __dormant__ {
-+ brcm,pins = <0 1>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+ };
-+ fragment@5 {
-+ target = <&i2c_vc>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@6 {
-+ target-path="/";
-+ __overlay__ {
-+ imx219_vana: fixedregulator@0 {
-+ compatible = "regulator-fixed";
-+ regulator-name = "imx219_vana";
-+ regulator-min-microvolt = <2800000>;
-+ regulator-max-microvolt = <2800000>;
-+ gpio = <&gpio 41 GPIO_ACTIVE_HIGH>;
-+ enable-active-high;
-+ };
-+ 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>;
-+ };
-+ };
-+ };
-+
-+ fragment@7 {
-+ target-path="/__overrides__";
-+ __overlay__ {
-+ cam0-pwdn-ctrl = <&imx219_vana>,"gpio:0";
-+ cam0-pwdn = <&imx219_vana>,"gpio:4";
-+ };
-+ };
-+
-+ __overrides__ {
-+ i2c_pins_0_1 = <0>,"-2-3+4";
-+ i2c_pins_28_29 = <0>,"+2-3-4";
-+ };
-+};
--- /dev/null
+From 2d17824e8e5b2b6a6b830b8fe26c71a7d396f760 Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Mar 2019 11:42:39 +0000
+Subject: [PATCH] staging: bcm2835-codec: Fix declaration of roles
+
+The static role text is declared incorrectly. The static should be
+first, and the roles should also be constified.
+
+Convert from "const static char *" to "static const char * const".
+
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -77,7 +77,7 @@ enum bcm2835_codec_role {
+ ISP,
+ };
+
+-const static char *roles[] = {
++static const char * const roles[] = {
+ "decode",
+ "encode",
+ "isp"
--- /dev/null
+From ca613ed735fc52e68189d2ad0880f1007b931d78 Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Mar 2019 11:55:43 +0000
+Subject: [PATCH] staging: bcm2835-codec: Add role to device name
+
+Three entities are created, Decode, Encode and ISP but all of the video
+nodes use the same video name string "bcm2835-codec" which makes it
+difficult to identify each role.
+
+Append the role-name to the video name to facilitate identifying a
+specific instance from userspace.
+
+The Card-Type is also extended with the role name to support identifying
+the device context from within QUERY_CAP operations.
+
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -947,8 +947,10 @@ static void device_run(void *priv)
+ static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+ {
++ struct bcm2835_codec_dev *dev = video_drvdata(file);
++
+ strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
+- strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
++ strncpy(cap->card, dev->vfd.name, sizeof(cap->card) - 1);
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ MEM2MEM_NAME);
+ return 0;
+@@ -2657,8 +2659,8 @@ static int bcm2835_codec_create(struct p
+ }
+
+ video_set_drvdata(vfd, dev);
+- snprintf(vfd->name, sizeof(vfd->name), "%s",
+- bcm2835_codec_videodev.name);
++ snprintf(vfd->name, sizeof(vfd->name), "%s-%s",
++ bcm2835_codec_videodev.name, roles[role]);
+ v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n",
+ vfd->num);
+
+++ /dev/null
-From d4fc8b1d50522b416baeb1d1f5e5498000af5a7f Mon Sep 17 00:00:00 2001
-Date: Sun, 28 Apr 2019 12:15:35 +0200
-Subject: [PATCH] staging: bcm2835-codec: Fix non-documentation comment
- block
-
-The job_ready comment is incorrectly using the documentation prefix
-(/**) which causes a warning at build time.
-
-Simplify it.
-
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -557,7 +557,7 @@ static struct vchiq_mmal_port *get_port_
- * mem2mem callbacks
- */
-
--/**
-+/*
- * job_ready() - check whether an instance is ready to be scheduled to run
- */
- static int job_ready(void *priv)
+++ /dev/null
-From 2d17824e8e5b2b6a6b830b8fe26c71a7d396f760 Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Mar 2019 11:42:39 +0000
-Subject: [PATCH] staging: bcm2835-codec: Fix declaration of roles
-
-The static role text is declared incorrectly. The static should be
-first, and the roles should also be constified.
-
-Convert from "const static char *" to "static const char * const".
-
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -77,7 +77,7 @@ enum bcm2835_codec_role {
- ISP,
- };
-
--const static char *roles[] = {
-+static const char * const roles[] = {
- "decode",
- "encode",
- "isp"
--- /dev/null
+From 9243f7de67345adfcac52198f78bd12cfebb6867 Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Mar 2019 11:35:26 +0000
+Subject: [PATCH] staging: bcm2835-codec: Pass driver context to create
+ entities
+
+Pass the bcm2835_codec_driver driver context directly into the
+bcm2835_codec_create() so that it can be used to store driver global
+state. Pass the struct platform_device *pdev by adding it to the driver
+global state.
+
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -457,6 +457,8 @@ struct bcm2835_codec_ctx {
+ };
+
+ struct bcm2835_codec_driver {
++ struct platform_device *pdev;
++
+ struct bcm2835_codec_dev *encode;
+ struct bcm2835_codec_dev *decode;
+ struct bcm2835_codec_dev *isp;
+@@ -2587,10 +2589,11 @@ destroy_component:
+ return ret;
+ }
+
+-static int bcm2835_codec_create(struct platform_device *pdev,
++static int bcm2835_codec_create(struct bcm2835_codec_driver *drv,
+ struct bcm2835_codec_dev **new_dev,
+ enum bcm2835_codec_role role)
+ {
++ struct platform_device *pdev = drv->pdev;
+ struct bcm2835_codec_dev *dev;
+ struct video_device *vfd;
+ int video_nr;
+@@ -2711,15 +2714,17 @@ static int bcm2835_codec_probe(struct pl
+ if (!drv)
+ return -ENOMEM;
+
+- ret = bcm2835_codec_create(pdev, &drv->decode, DECODE);
++ drv->pdev = pdev;
++
++ ret = bcm2835_codec_create(drv, &drv->decode, DECODE);
+ if (ret)
+ goto out;
+
+- ret = bcm2835_codec_create(pdev, &drv->encode, ENCODE);
++ ret = bcm2835_codec_create(drv, &drv->encode, ENCODE);
+ if (ret)
+ goto out;
+
+- ret = bcm2835_codec_create(pdev, &drv->isp, ISP);
++ ret = bcm2835_codec_create(drv, &drv->isp, ISP);
+ if (ret)
+ goto out;
+
+++ /dev/null
-From ca613ed735fc52e68189d2ad0880f1007b931d78 Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Mar 2019 11:55:43 +0000
-Subject: [PATCH] staging: bcm2835-codec: Add role to device name
-
-Three entities are created, Decode, Encode and ISP but all of the video
-nodes use the same video name string "bcm2835-codec" which makes it
-difficult to identify each role.
-
-Append the role-name to the video name to facilitate identifying a
-specific instance from userspace.
-
-The Card-Type is also extended with the role name to support identifying
-the device context from within QUERY_CAP operations.
-
----
- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -947,8 +947,10 @@ static void device_run(void *priv)
- static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
- {
-+ struct bcm2835_codec_dev *dev = video_drvdata(file);
-+
- strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
-- strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
-+ strncpy(cap->card, dev->vfd.name, sizeof(cap->card) - 1);
- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
- MEM2MEM_NAME);
- return 0;
-@@ -2657,8 +2659,8 @@ static int bcm2835_codec_create(struct p
- }
-
- video_set_drvdata(vfd, dev);
-- snprintf(vfd->name, sizeof(vfd->name), "%s",
-- bcm2835_codec_videodev.name);
-+ snprintf(vfd->name, sizeof(vfd->name), "%s-%s",
-+ bcm2835_codec_videodev.name, roles[role]);
- v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n",
- vfd->num);
-
--- /dev/null
+From d1ceb85b7c6c7c3eec8b424e0172c29e93a570f2 Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Mar 2019 12:54:15 +0000
+Subject: [PATCH] staging: bcm2835-codec: add media controller support
+
+Provide a single media device to contain all of the bcm2835_codec
+devices created.
+
+---
+ .../vc04_services/bcm2835-codec/Kconfig | 2 +-
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 41 +++++++++++++++++--
+ 2 files changed, 38 insertions(+), 5 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/Kconfig
++++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig
+@@ -1,6 +1,6 @@
+ config VIDEO_CODEC_BCM2835
+ tristate "BCM2835 Video codec support"
+- depends on MEDIA_SUPPORT
++ depends on MEDIA_SUPPORT && MEDIA_CONTROLLER
+ depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST)
+ select BCM2835_VCHIQ_MMAL
+ select VIDEOBUF2_DMA_CONTIG
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -458,6 +458,7 @@ struct bcm2835_codec_ctx {
+
+ struct bcm2835_codec_driver {
+ struct platform_device *pdev;
++ struct media_device mdev;
+
+ struct bcm2835_codec_dev *encode;
+ struct bcm2835_codec_dev *decode;
+@@ -2596,6 +2597,7 @@ static int bcm2835_codec_create(struct b
+ struct platform_device *pdev = drv->pdev;
+ struct bcm2835_codec_dev *dev;
+ struct video_device *vfd;
++ int function;
+ int video_nr;
+ int ret;
+
+@@ -2615,18 +2617,21 @@ static int bcm2835_codec_create(struct b
+ if (ret)
+ goto vchiq_finalise;
+
+- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+- if (ret)
+- goto vchiq_finalise;
+-
+ atomic_set(&dev->num_inst, 0);
+ mutex_init(&dev->dev_mutex);
+
++ /* Initialise the video device */
+ dev->vfd = bcm2835_codec_videodev;
++
+ vfd = &dev->vfd;
+ vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
++ vfd->v4l2_dev->mdev = &drv->mdev;
++
++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
++ if (ret)
++ goto vchiq_finalise;
+
+ switch (role) {
+ case DECODE:
+@@ -2634,11 +2639,13 @@ static int bcm2835_codec_create(struct b
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
++ function = MEDIA_ENT_F_PROC_VIDEO_DECODER;
+ video_nr = decode_video_nr;
+ break;
+ case ENCODE:
+ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
++ function = MEDIA_ENT_F_PROC_VIDEO_ENCODER;
+ video_nr = encode_video_nr;
+ break;
+ case ISP:
+@@ -2648,6 +2655,7 @@ static int bcm2835_codec_create(struct b
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
++ function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
+ video_nr = isp_video_nr;
+ break;
+ default:
+@@ -2676,6 +2684,10 @@ static int bcm2835_codec_create(struct b
+ goto err_m2m;
+ }
+
++ ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, function);
++ if (ret)
++ goto err_m2m;
++
+ v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n",
+ roles[role]);
+ return 0;
+@@ -2697,6 +2709,7 @@ static int bcm2835_codec_destroy(struct
+
+ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME ", %s\n",
+ roles[dev->role]);
++ v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+ v4l2_m2m_release(dev->m2m_dev);
+ video_unregister_device(&dev->vfd);
+ v4l2_device_unregister(&dev->v4l2_dev);
+@@ -2708,6 +2721,7 @@ static int bcm2835_codec_destroy(struct
+ static int bcm2835_codec_probe(struct platform_device *pdev)
+ {
+ struct bcm2835_codec_driver *drv;
++ struct media_device *mdev;
+ int ret = 0;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+@@ -2715,6 +2729,17 @@ static int bcm2835_codec_probe(struct pl
+ return -ENOMEM;
+
+ drv->pdev = pdev;
++ mdev = &drv->mdev;
++ mdev->dev = &pdev->dev;
++
++ strscpy(mdev->model, bcm2835_codec_videodev.name, sizeof(mdev->model));
++ strscpy(mdev->serial, "0000", sizeof(mdev->serial));
++ snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
++ pdev->name);
++
++ /* This should return the vgencmd version information or such .. */
++ mdev->hw_revision = 1;
++ media_device_init(mdev);
+
+ ret = bcm2835_codec_create(drv, &drv->decode, DECODE);
+ if (ret)
+@@ -2728,6 +2753,10 @@ static int bcm2835_codec_probe(struct pl
+ if (ret)
+ goto out;
+
++ /* Register the media device node */
++ if (media_device_register(mdev) < 0)
++ goto out;
++
+ platform_set_drvdata(pdev, drv);
+
+ return 0;
+@@ -2748,12 +2777,16 @@ static int bcm2835_codec_remove(struct p
+ {
+ struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev);
+
++ media_device_unregister(&drv->mdev);
++
+ bcm2835_codec_destroy(drv->isp);
+
+ bcm2835_codec_destroy(drv->encode);
+
+ bcm2835_codec_destroy(drv->decode);
+
++ media_device_cleanup(&drv->mdev);
++
+ return 0;
+ }
+
--- /dev/null
+From 4924b7b5517c9c334cf5faa3c7a29adf9a0c0ba1 Mon Sep 17 00:00:00 2001
+Date: Wed, 28 Aug 2019 15:54:19 +0100
+Subject: [PATCH] media: bcm2835: unicam: Reduce scope of local
+ function
+
+unicam_start_rx() is not used outside of the unicam module. Its current
+definition produces a compiler warning, that no function prototype
+exists.
+
+As the function is only used within the local scope of the module,
+convert it to a static function.
+
+---
+ drivers/media/platform/bcm2835/bcm2835-unicam.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
+@@ -963,7 +963,7 @@ static void unicam_cfg_image_id(struct u
+ }
+ }
+
+-void unicam_start_rx(struct unicam_device *dev, unsigned long addr)
++static void unicam_start_rx(struct unicam_device *dev, unsigned long addr)
+ {
+ struct unicam_cfg *cfg = &dev->cfg;
+ int line_int_freq = dev->v_fmt.fmt.pix.height >> 2;
+++ /dev/null
-From 9243f7de67345adfcac52198f78bd12cfebb6867 Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Mar 2019 11:35:26 +0000
-Subject: [PATCH] staging: bcm2835-codec: Pass driver context to create
- entities
-
-Pass the bcm2835_codec_driver driver context directly into the
-bcm2835_codec_create() so that it can be used to store driver global
-state. Pass the struct platform_device *pdev by adding it to the driver
-global state.
-
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 13 +++++++++----
- 1 file changed, 9 insertions(+), 4 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -457,6 +457,8 @@ struct bcm2835_codec_ctx {
- };
-
- struct bcm2835_codec_driver {
-+ struct platform_device *pdev;
-+
- struct bcm2835_codec_dev *encode;
- struct bcm2835_codec_dev *decode;
- struct bcm2835_codec_dev *isp;
-@@ -2587,10 +2589,11 @@ destroy_component:
- return ret;
- }
-
--static int bcm2835_codec_create(struct platform_device *pdev,
-+static int bcm2835_codec_create(struct bcm2835_codec_driver *drv,
- struct bcm2835_codec_dev **new_dev,
- enum bcm2835_codec_role role)
- {
-+ struct platform_device *pdev = drv->pdev;
- struct bcm2835_codec_dev *dev;
- struct video_device *vfd;
- int video_nr;
-@@ -2711,15 +2714,17 @@ static int bcm2835_codec_probe(struct pl
- if (!drv)
- return -ENOMEM;
-
-- ret = bcm2835_codec_create(pdev, &drv->decode, DECODE);
-+ drv->pdev = pdev;
-+
-+ ret = bcm2835_codec_create(drv, &drv->decode, DECODE);
- if (ret)
- goto out;
-
-- ret = bcm2835_codec_create(pdev, &drv->encode, ENCODE);
-+ ret = bcm2835_codec_create(drv, &drv->encode, ENCODE);
- if (ret)
- goto out;
-
-- ret = bcm2835_codec_create(pdev, &drv->isp, ISP);
-+ ret = bcm2835_codec_create(drv, &drv->isp, ISP);
- if (ret)
- goto out;
-
--- /dev/null
+From 06cd9857f8faa63321506a75988c475906a32970 Mon Sep 17 00:00:00 2001
+Date: Wed, 20 Mar 2019 12:54:47 +0000
+Subject: [PATCH] media: bcm2835: unicam: add media controller support
+
+Add a media controller device node to represent the Unicam device.
+The attached sensor will be automatically added to the media graph by
+V4L2 core.
+
+---
+ drivers/media/platform/bcm2835/Kconfig | 2 +-
+ .../media/platform/bcm2835/bcm2835-unicam.c | 46 ++++++++++++++++++-
+ 2 files changed, 45 insertions(+), 3 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/Kconfig
++++ b/drivers/media/platform/bcm2835/Kconfig
+@@ -2,7 +2,7 @@
+
+ config VIDEO_BCM2835_UNICAM
+ tristate "Broadcom BCM2835 Unicam video capture driver"
+- depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
++ depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
+ depends on ARCH_BCM2835 || COMPILE_TEST
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_FWNODE
+--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
+@@ -314,6 +314,9 @@ struct unicam_device {
+ struct clk *clock;
+ /* V4l2 device */
+ struct v4l2_device v4l2_dev;
++ struct media_device mdev;
++ struct media_pad pad;
++
+ /* parent device */
+ struct platform_device *pdev;
+ /* subdevice async Notifier */
+@@ -1912,6 +1915,8 @@ static int unicam_probe_complete(struct
+ unicam->v4l2_dev.ctrl_handler = NULL;
+
+ video_set_drvdata(vdev, unicam);
++ vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
++
+ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ unicam_err(unicam, "Unable to register video device.\n");
+@@ -1953,6 +1958,16 @@ static int unicam_probe_complete(struct
+ return ret;
+ }
+
++ ret = media_create_pad_link(&unicam->sensor->entity, 0,
++ &unicam->video_dev.entity, 0,
++ MEDIA_LNK_FL_ENABLED |
++ MEDIA_LNK_FL_IMMUTABLE);
++ if (ret) {
++ unicam_err(unicam, "Unable to create pad links.\n");
++ video_unregister_device(&unicam->video_dev);
++ return ret;
++ }
++
+ return 0;
+ }
+
+@@ -2155,18 +2170,38 @@ static int unicam_probe(struct platform_
+ return -EINVAL;
+ }
+
++ unicam->mdev.dev = &pdev->dev;
++ strscpy(unicam->mdev.model, UNICAM_MODULE_NAME,
++ sizeof(unicam->mdev.model));
++ strscpy(unicam->mdev.serial, "", sizeof(unicam->mdev.serial));
++ snprintf(unicam->mdev.bus_info, sizeof(unicam->mdev.bus_info),
++ "platform:%s", pdev->name);
++ unicam->mdev.hw_revision = 1;
++
++ media_entity_pads_init(&unicam->video_dev.entity, 1, &unicam->pad);
++ media_device_init(&unicam->mdev);
++
++ unicam->v4l2_dev.mdev = &unicam->mdev;
++
+ ret = v4l2_device_register(&pdev->dev, &unicam->v4l2_dev);
+ if (ret) {
+ unicam_err(unicam,
+ "Unable to register v4l2 device.\n");
+- return ret;
++ goto media_cleanup;
++ }
++
++ ret = media_device_register(&unicam->mdev);
++ if (ret < 0) {
++ unicam_err(unicam,
++ "Unable to register media-controller device.\n");
++ goto probe_out_v4l2_unregister;
+ }
+
+ /* Reserve space for the controls */
+ hdl = &unicam->ctrl_handler;
+ ret = v4l2_ctrl_handler_init(hdl, 16);
+ if (ret < 0)
+- goto probe_out_v4l2_unregister;
++ goto media_unregister;
+ unicam->v4l2_dev.ctrl_handler = hdl;
+
+ /* set the driver data in platform device */
+@@ -2185,8 +2220,13 @@ static int unicam_probe(struct platform_
+
+ free_hdl:
+ v4l2_ctrl_handler_free(hdl);
++media_unregister:
++ media_device_unregister(&unicam->mdev);
+ probe_out_v4l2_unregister:
+ v4l2_device_unregister(&unicam->v4l2_dev);
++media_cleanup:
++ media_device_cleanup(&unicam->mdev);
++
+ return ret;
+ }
+
+@@ -2204,6 +2244,8 @@ static int unicam_remove(struct platform
+ video_unregister_device(&unicam->video_dev);
+ if (unicam->sensor_config)
+ v4l2_subdev_free_pad_config(unicam->sensor_config);
++ media_device_unregister(&unicam->mdev);
++ media_device_cleanup(&unicam->mdev);
+
+ return 0;
+ }
+++ /dev/null
-From d1ceb85b7c6c7c3eec8b424e0172c29e93a570f2 Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Mar 2019 12:54:15 +0000
-Subject: [PATCH] staging: bcm2835-codec: add media controller support
-
-Provide a single media device to contain all of the bcm2835_codec
-devices created.
-
----
- .../vc04_services/bcm2835-codec/Kconfig | 2 +-
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 41 +++++++++++++++++--
- 2 files changed, 38 insertions(+), 5 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/Kconfig
-+++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig
-@@ -1,6 +1,6 @@
- config VIDEO_CODEC_BCM2835
- tristate "BCM2835 Video codec support"
-- depends on MEDIA_SUPPORT
-+ depends on MEDIA_SUPPORT && MEDIA_CONTROLLER
- depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST)
- select BCM2835_VCHIQ_MMAL
- select VIDEOBUF2_DMA_CONTIG
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -458,6 +458,7 @@ struct bcm2835_codec_ctx {
-
- struct bcm2835_codec_driver {
- struct platform_device *pdev;
-+ struct media_device mdev;
-
- struct bcm2835_codec_dev *encode;
- struct bcm2835_codec_dev *decode;
-@@ -2596,6 +2597,7 @@ static int bcm2835_codec_create(struct b
- struct platform_device *pdev = drv->pdev;
- struct bcm2835_codec_dev *dev;
- struct video_device *vfd;
-+ int function;
- int video_nr;
- int ret;
-
-@@ -2615,18 +2617,21 @@ static int bcm2835_codec_create(struct b
- if (ret)
- goto vchiq_finalise;
-
-- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-- if (ret)
-- goto vchiq_finalise;
--
- atomic_set(&dev->num_inst, 0);
- mutex_init(&dev->dev_mutex);
-
-+ /* Initialise the video device */
- dev->vfd = bcm2835_codec_videodev;
-+
- vfd = &dev->vfd;
- vfd->lock = &dev->dev_mutex;
- vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
-+ vfd->v4l2_dev->mdev = &drv->mdev;
-+
-+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-+ if (ret)
-+ goto vchiq_finalise;
-
- switch (role) {
- case DECODE:
-@@ -2634,11 +2639,13 @@ static int bcm2835_codec_create(struct b
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
- v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
-+ function = MEDIA_ENT_F_PROC_VIDEO_DECODER;
- video_nr = decode_video_nr;
- break;
- case ENCODE:
- v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
-+ function = MEDIA_ENT_F_PROC_VIDEO_ENCODER;
- video_nr = encode_video_nr;
- break;
- case ISP:
-@@ -2648,6 +2655,7 @@ static int bcm2835_codec_create(struct b
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
- v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
-+ function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
- video_nr = isp_video_nr;
- break;
- default:
-@@ -2676,6 +2684,10 @@ static int bcm2835_codec_create(struct b
- goto err_m2m;
- }
-
-+ ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, function);
-+ if (ret)
-+ goto err_m2m;
-+
- v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n",
- roles[role]);
- return 0;
-@@ -2697,6 +2709,7 @@ static int bcm2835_codec_destroy(struct
-
- v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME ", %s\n",
- roles[dev->role]);
-+ v4l2_m2m_unregister_media_controller(dev->m2m_dev);
- v4l2_m2m_release(dev->m2m_dev);
- video_unregister_device(&dev->vfd);
- v4l2_device_unregister(&dev->v4l2_dev);
-@@ -2708,6 +2721,7 @@ static int bcm2835_codec_destroy(struct
- static int bcm2835_codec_probe(struct platform_device *pdev)
- {
- struct bcm2835_codec_driver *drv;
-+ struct media_device *mdev;
- int ret = 0;
-
- drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
-@@ -2715,6 +2729,17 @@ static int bcm2835_codec_probe(struct pl
- return -ENOMEM;
-
- drv->pdev = pdev;
-+ mdev = &drv->mdev;
-+ mdev->dev = &pdev->dev;
-+
-+ strscpy(mdev->model, bcm2835_codec_videodev.name, sizeof(mdev->model));
-+ strscpy(mdev->serial, "0000", sizeof(mdev->serial));
-+ snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
-+ pdev->name);
-+
-+ /* This should return the vgencmd version information or such .. */
-+ mdev->hw_revision = 1;
-+ media_device_init(mdev);
-
- ret = bcm2835_codec_create(drv, &drv->decode, DECODE);
- if (ret)
-@@ -2728,6 +2753,10 @@ static int bcm2835_codec_probe(struct pl
- if (ret)
- goto out;
-
-+ /* Register the media device node */
-+ if (media_device_register(mdev) < 0)
-+ goto out;
-+
- platform_set_drvdata(pdev, drv);
-
- return 0;
-@@ -2748,12 +2777,16 @@ static int bcm2835_codec_remove(struct p
- {
- struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev);
-
-+ media_device_unregister(&drv->mdev);
-+
- bcm2835_codec_destroy(drv->isp);
-
- bcm2835_codec_destroy(drv->encode);
-
- bcm2835_codec_destroy(drv->decode);
-
-+ media_device_cleanup(&drv->mdev);
-+
- return 0;
- }
-
--- /dev/null
+From 7bfcb31431f06efc233e4cc4d7ab65e10a6522cd Mon Sep 17 00:00:00 2001
+Date: Fri, 23 Aug 2019 11:02:22 +0200
+Subject: [PATCH] Limit max_req_size under arm64 (or any other platform
+ that uses swiotlb) to prevent potential buffer overflow due to bouncing.
+
+---
+ drivers/mmc/host/bcm2835-mmc.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/mmc/host/bcm2835-mmc.c
++++ b/drivers/mmc/host/bcm2835-mmc.c
+@@ -38,6 +38,7 @@
+ #include <linux/dmaengine.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/of_dma.h>
++#include <linux/swiotlb.h>
+
+ #include "sdhci.h"
+
+@@ -1374,7 +1375,10 @@ static int bcm2835_mmc_add_host(struct b
+ }
+ #endif
+ mmc->max_segs = 128;
+- mmc->max_req_size = 524288;
++ if (swiotlb_max_segment())
++ mmc->max_req_size = (1 << IO_TLB_SHIFT) * IO_TLB_SEGSIZE;
++ else
++ mmc->max_req_size = 524288;
+ mmc->max_seg_size = mmc->max_req_size;
+ mmc->max_blk_size = 512;
+ mmc->max_blk_count = 65535;
+++ /dev/null
-From 4924b7b5517c9c334cf5faa3c7a29adf9a0c0ba1 Mon Sep 17 00:00:00 2001
-Date: Wed, 28 Aug 2019 15:54:19 +0100
-Subject: [PATCH] media: bcm2835: unicam: Reduce scope of local
- function
-
-unicam_start_rx() is not used outside of the unicam module. Its current
-definition produces a compiler warning, that no function prototype
-exists.
-
-As the function is only used within the local scope of the module,
-convert it to a static function.
-
----
- drivers/media/platform/bcm2835/bcm2835-unicam.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
-@@ -963,7 +963,7 @@ static void unicam_cfg_image_id(struct u
- }
- }
-
--void unicam_start_rx(struct unicam_device *dev, unsigned long addr)
-+static void unicam_start_rx(struct unicam_device *dev, unsigned long addr)
- {
- struct unicam_cfg *cfg = &dev->cfg;
- int line_int_freq = dev->v_fmt.fmt.pix.height >> 2;
--- /dev/null
+From f8554985b77df2dac55f2d7c85e0f0cc3497a1fd Mon Sep 17 00:00:00 2001
+Date: Fri, 23 Aug 2019 11:05:51 +0200
+Subject: [PATCH] Add missing dma_unmap_sg calls to free relevant
+ swiotlb bounce buffers. This prevents DMA leaks.
+
+---
+ drivers/mmc/host/bcm2835-mmc.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+--- a/drivers/mmc/host/bcm2835-mmc.c
++++ b/drivers/mmc/host/bcm2835-mmc.c
+@@ -345,16 +345,17 @@ static void bcm2835_mmc_dma_complete(voi
+
+ host->use_dma = false;
+
+- if (host->data && !(host->data->flags & MMC_DATA_WRITE)) {
+- /* otherwise handled in SDHCI IRQ */
++ if (host->data) {
+ dma_chan = host->dma_chan_rxtx;
+- dir_data = DMA_FROM_DEVICE;
+-
++ if (host->data->flags & MMC_DATA_WRITE)
++ dir_data = DMA_TO_DEVICE;
++ else
++ dir_data = DMA_FROM_DEVICE;
+ dma_unmap_sg(dma_chan->device->dev,
+ host->data->sg, host->data->sg_len,
+ dir_data);
+-
+- bcm2835_mmc_finish_data(host);
++ if (! (host->data->flags & MMC_DATA_WRITE))
++ bcm2835_mmc_finish_data(host);
+ } else if (host->wait_for_dma) {
+ host->wait_for_dma = false;
+ tasklet_schedule(&host->finish_tasklet);
+@@ -540,6 +541,8 @@ static void bcm2835_mmc_transfer_dma(str
+ spin_unlock_irqrestore(&host->lock, flags);
+ dmaengine_submit(desc);
+ dma_async_issue_pending(dma_chan);
++ } else {
++ dma_unmap_sg(dma_chan->device->dev, host->data->sg, len, dir_data);
+ }
+
+ }
+++ /dev/null
-From 06cd9857f8faa63321506a75988c475906a32970 Mon Sep 17 00:00:00 2001
-Date: Wed, 20 Mar 2019 12:54:47 +0000
-Subject: [PATCH] media: bcm2835: unicam: add media controller support
-
-Add a media controller device node to represent the Unicam device.
-The attached sensor will be automatically added to the media graph by
-V4L2 core.
-
----
- drivers/media/platform/bcm2835/Kconfig | 2 +-
- .../media/platform/bcm2835/bcm2835-unicam.c | 46 ++++++++++++++++++-
- 2 files changed, 45 insertions(+), 3 deletions(-)
-
---- a/drivers/media/platform/bcm2835/Kconfig
-+++ b/drivers/media/platform/bcm2835/Kconfig
-@@ -2,7 +2,7 @@
-
- config VIDEO_BCM2835_UNICAM
- tristate "Broadcom BCM2835 Unicam video capture driver"
-- depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
-+ depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
- depends on ARCH_BCM2835 || COMPILE_TEST
- select VIDEOBUF2_DMA_CONTIG
- select V4L2_FWNODE
---- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
-@@ -314,6 +314,9 @@ struct unicam_device {
- struct clk *clock;
- /* V4l2 device */
- struct v4l2_device v4l2_dev;
-+ struct media_device mdev;
-+ struct media_pad pad;
-+
- /* parent device */
- struct platform_device *pdev;
- /* subdevice async Notifier */
-@@ -1912,6 +1915,8 @@ static int unicam_probe_complete(struct
- unicam->v4l2_dev.ctrl_handler = NULL;
-
- video_set_drvdata(vdev, unicam);
-+ vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
-+
- ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
- if (ret) {
- unicam_err(unicam, "Unable to register video device.\n");
-@@ -1953,6 +1958,16 @@ static int unicam_probe_complete(struct
- return ret;
- }
-
-+ ret = media_create_pad_link(&unicam->sensor->entity, 0,
-+ &unicam->video_dev.entity, 0,
-+ MEDIA_LNK_FL_ENABLED |
-+ MEDIA_LNK_FL_IMMUTABLE);
-+ if (ret) {
-+ unicam_err(unicam, "Unable to create pad links.\n");
-+ video_unregister_device(&unicam->video_dev);
-+ return ret;
-+ }
-+
- return 0;
- }
-
-@@ -2155,18 +2170,38 @@ static int unicam_probe(struct platform_
- return -EINVAL;
- }
-
-+ unicam->mdev.dev = &pdev->dev;
-+ strscpy(unicam->mdev.model, UNICAM_MODULE_NAME,
-+ sizeof(unicam->mdev.model));
-+ strscpy(unicam->mdev.serial, "", sizeof(unicam->mdev.serial));
-+ snprintf(unicam->mdev.bus_info, sizeof(unicam->mdev.bus_info),
-+ "platform:%s", pdev->name);
-+ unicam->mdev.hw_revision = 1;
-+
-+ media_entity_pads_init(&unicam->video_dev.entity, 1, &unicam->pad);
-+ media_device_init(&unicam->mdev);
-+
-+ unicam->v4l2_dev.mdev = &unicam->mdev;
-+
- ret = v4l2_device_register(&pdev->dev, &unicam->v4l2_dev);
- if (ret) {
- unicam_err(unicam,
- "Unable to register v4l2 device.\n");
-- return ret;
-+ goto media_cleanup;
-+ }
-+
-+ ret = media_device_register(&unicam->mdev);
-+ if (ret < 0) {
-+ unicam_err(unicam,
-+ "Unable to register media-controller device.\n");
-+ goto probe_out_v4l2_unregister;
- }
-
- /* Reserve space for the controls */
- hdl = &unicam->ctrl_handler;
- ret = v4l2_ctrl_handler_init(hdl, 16);
- if (ret < 0)
-- goto probe_out_v4l2_unregister;
-+ goto media_unregister;
- unicam->v4l2_dev.ctrl_handler = hdl;
-
- /* set the driver data in platform device */
-@@ -2185,8 +2220,13 @@ static int unicam_probe(struct platform_
-
- free_hdl:
- v4l2_ctrl_handler_free(hdl);
-+media_unregister:
-+ media_device_unregister(&unicam->mdev);
- probe_out_v4l2_unregister:
- v4l2_device_unregister(&unicam->v4l2_dev);
-+media_cleanup:
-+ media_device_cleanup(&unicam->mdev);
-+
- return ret;
- }
-
-@@ -2204,6 +2244,8 @@ static int unicam_remove(struct platform
- video_unregister_device(&unicam->video_dev);
- if (unicam->sensor_config)
- v4l2_subdev_free_pad_config(unicam->sensor_config);
-+ media_device_unregister(&unicam->mdev);
-+ media_device_cleanup(&unicam->mdev);
-
- return 0;
- }
+++ /dev/null
-From 7bfcb31431f06efc233e4cc4d7ab65e10a6522cd Mon Sep 17 00:00:00 2001
-Date: Fri, 23 Aug 2019 11:02:22 +0200
-Subject: [PATCH] Limit max_req_size under arm64 (or any other platform
- that uses swiotlb) to prevent potential buffer overflow due to bouncing.
-
----
- drivers/mmc/host/bcm2835-mmc.c | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
---- a/drivers/mmc/host/bcm2835-mmc.c
-+++ b/drivers/mmc/host/bcm2835-mmc.c
-@@ -38,6 +38,7 @@
- #include <linux/dmaengine.h>
- #include <linux/dma-mapping.h>
- #include <linux/of_dma.h>
-+#include <linux/swiotlb.h>
-
- #include "sdhci.h"
-
-@@ -1374,7 +1375,10 @@ static int bcm2835_mmc_add_host(struct b
- }
- #endif
- mmc->max_segs = 128;
-- mmc->max_req_size = 524288;
-+ if (swiotlb_max_segment())
-+ mmc->max_req_size = (1 << IO_TLB_SHIFT) * IO_TLB_SEGSIZE;
-+ else
-+ mmc->max_req_size = 524288;
- mmc->max_seg_size = mmc->max_req_size;
- mmc->max_blk_size = 512;
- mmc->max_blk_count = 65535;
--- /dev/null
+From 9802671acf4250d6541d175ba599da03cee8acc1 Mon Sep 17 00:00:00 2001
+Date: Thu, 5 Sep 2019 17:36:38 +0100
+Subject: [PATCH] overlays: mcp23017: rename the GPIO pins node with
+ the device
+
+In order to allow the overlay to be loaded multiple times the
+GPIO node for the interrupt line needs to be unique.
+Rename it based on the MCP23017 I2C address
+
+https://github.com/raspberrypi/linux/issues/3207
+
+---
+ arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
+@@ -16,7 +16,7 @@
+ fragment@1 {
+ target = <&gpio>;
+ __overlay__ {
+- mcp23017_pins: mcp23017_pins {
++ mcp23017_pins: mcp23017_pins@20 {
+ brcm,pins = <4>;
+ brcm,function = <0>;
+ };
+@@ -55,7 +55,7 @@
+ __overrides__ {
+ gpiopin = <&mcp23017_pins>,"brcm,pins:0",
+ <&mcp23017>,"interrupts:0";
+- addr = <&mcp23017>,"reg:0";
++ addr = <&mcp23017>,"reg:0", <&mcp23017_pins>,"reg:0";
+ mcp23008 = <0>,"=3";
+ };
+ };
+++ /dev/null
-From f8554985b77df2dac55f2d7c85e0f0cc3497a1fd Mon Sep 17 00:00:00 2001
-Date: Fri, 23 Aug 2019 11:05:51 +0200
-Subject: [PATCH] Add missing dma_unmap_sg calls to free relevant
- swiotlb bounce buffers. This prevents DMA leaks.
-
----
- drivers/mmc/host/bcm2835-mmc.c | 15 +++++++++------
- 1 file changed, 9 insertions(+), 6 deletions(-)
-
---- a/drivers/mmc/host/bcm2835-mmc.c
-+++ b/drivers/mmc/host/bcm2835-mmc.c
-@@ -345,16 +345,17 @@ static void bcm2835_mmc_dma_complete(voi
-
- host->use_dma = false;
-
-- if (host->data && !(host->data->flags & MMC_DATA_WRITE)) {
-- /* otherwise handled in SDHCI IRQ */
-+ if (host->data) {
- dma_chan = host->dma_chan_rxtx;
-- dir_data = DMA_FROM_DEVICE;
--
-+ if (host->data->flags & MMC_DATA_WRITE)
-+ dir_data = DMA_TO_DEVICE;
-+ else
-+ dir_data = DMA_FROM_DEVICE;
- dma_unmap_sg(dma_chan->device->dev,
- host->data->sg, host->data->sg_len,
- dir_data);
--
-- bcm2835_mmc_finish_data(host);
-+ if (! (host->data->flags & MMC_DATA_WRITE))
-+ bcm2835_mmc_finish_data(host);
- } else if (host->wait_for_dma) {
- host->wait_for_dma = false;
- tasklet_schedule(&host->finish_tasklet);
-@@ -540,6 +541,8 @@ static void bcm2835_mmc_transfer_dma(str
- spin_unlock_irqrestore(&host->lock, flags);
- dmaengine_submit(desc);
- dma_async_issue_pending(dma_chan);
-+ } else {
-+ dma_unmap_sg(dma_chan->device->dev, host->data->sg, len, dir_data);
- }
-
- }
--- /dev/null
+From b37ac8c50684c3517fb9c6f737e7ea444a7d7405 Mon Sep 17 00:00:00 2001
+Date: Thu, 5 Sep 2019 17:41:46 +0100
+Subject: [PATCH] overlays: mcp23017: Add option for not connecting the
+ int GPIO
+
+The interrupt GPIO is optional to the driver, therefore add an
+option to not configure it.
+
+---
+ arch/arm/boot/dts/overlays/README | 1 +
+ .../boot/dts/overlays/mcp23017-overlay.dts | 21 +++++++++++++------
+ 2 files changed, 16 insertions(+), 6 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1427,6 +1427,7 @@ Params: gpiopin Gpio pin
+ addr I2C address of the MCP23017 (default: 0x20)
+
+ mcp23008 Configure an MCP23008 instead.
++ noints Disable the interrupt GPIO line.
+
+
+ Name: mcp23s17
+--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
+@@ -34,11 +34,6 @@
+ reg = <0x20>;
+ gpio-controller;
+ #gpio-cells = <2>;
+- #interrupt-cells=<2>;
+- interrupt-parent = <&gpio>;
+- interrupts = <4 2>;
+- interrupt-controller;
+- microchip,irq-mirror;
+
+ status = "okay";
+ };
+@@ -52,11 +47,25 @@
+ };
+ };
+
++ fragment@4 {
++ target = <&i2c1>;
++ __overlay__ {
++ mcp23017_irq: mcp@20 {
++ #interrupt-cells=<2>;
++ interrupt-parent = <&gpio>;
++ interrupts = <4 2>;
++ interrupt-controller;
++ microchip,irq-mirror;
++ };
++ };
++ };
++
+ __overrides__ {
+ gpiopin = <&mcp23017_pins>,"brcm,pins:0",
+- <&mcp23017>,"interrupts:0";
++ <&mcp23017_irq>,"interrupts:0";
+ addr = <&mcp23017>,"reg:0", <&mcp23017_pins>,"reg:0";
+ mcp23008 = <0>,"=3";
++ noints = <0>,"!1!4";
+ };
+ };
+
+++ /dev/null
-From 9802671acf4250d6541d175ba599da03cee8acc1 Mon Sep 17 00:00:00 2001
-Date: Thu, 5 Sep 2019 17:36:38 +0100
-Subject: [PATCH] overlays: mcp23017: rename the GPIO pins node with
- the device
-
-In order to allow the overlay to be loaded multiple times the
-GPIO node for the interrupt line needs to be unique.
-Rename it based on the MCP23017 I2C address
-
-https://github.com/raspberrypi/linux/issues/3207
-
----
- arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
-@@ -16,7 +16,7 @@
- fragment@1 {
- target = <&gpio>;
- __overlay__ {
-- mcp23017_pins: mcp23017_pins {
-+ mcp23017_pins: mcp23017_pins@20 {
- brcm,pins = <4>;
- brcm,function = <0>;
- };
-@@ -55,7 +55,7 @@
- __overrides__ {
- gpiopin = <&mcp23017_pins>,"brcm,pins:0",
- <&mcp23017>,"interrupts:0";
-- addr = <&mcp23017>,"reg:0";
-+ addr = <&mcp23017>,"reg:0", <&mcp23017_pins>,"reg:0";
- mcp23008 = <0>,"=3";
- };
- };
--- /dev/null
+From c8f63d006ff5f84ad629f4c06cdc9fee34fdfe3d Mon Sep 17 00:00:00 2001
+Date: Fri, 6 Sep 2019 15:04:51 +0100
+Subject: [PATCH] v4l2: Add a Greyworld AWB mode.
+
+Adds a simple greyworld white balance preset, mainly for use
+with cameras without an IR filter (eg Raspberry Pi NoIR)
+
+---
+ drivers/media/v4l2-core/v4l2-ctrls.c | 1 +
+ include/uapi/linux/v4l2-controls.h | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/drivers/media/v4l2-core/v4l2-ctrls.c
++++ b/drivers/media/v4l2-core/v4l2-ctrls.c
+@@ -275,6 +275,7 @@ const char * const *v4l2_ctrl_get_menu(u
+ "Flash",
+ "Cloudy",
+ "Shade",
++ "Greyworld",
+ NULL,
+ };
+ static const char * const camera_iso_sensitivity_auto[] = {
+--- a/include/uapi/linux/v4l2-controls.h
++++ b/include/uapi/linux/v4l2-controls.h
+@@ -815,6 +815,7 @@ enum v4l2_auto_n_preset_white_balance {
+ V4L2_WHITE_BALANCE_FLASH = 7,
+ V4L2_WHITE_BALANCE_CLOUDY = 8,
+ V4L2_WHITE_BALANCE_SHADE = 9,
++ V4L2_WHITE_BALANCE_GREYWORLD = 10,
+ };
+
+ #define V4L2_CID_WIDE_DYNAMIC_RANGE (V4L2_CID_CAMERA_CLASS_BASE+21)
+++ /dev/null
-From b37ac8c50684c3517fb9c6f737e7ea444a7d7405 Mon Sep 17 00:00:00 2001
-Date: Thu, 5 Sep 2019 17:41:46 +0100
-Subject: [PATCH] overlays: mcp23017: Add option for not connecting the
- int GPIO
-
-The interrupt GPIO is optional to the driver, therefore add an
-option to not configure it.
-
----
- arch/arm/boot/dts/overlays/README | 1 +
- .../boot/dts/overlays/mcp23017-overlay.dts | 21 +++++++++++++------
- 2 files changed, 16 insertions(+), 6 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1427,6 +1427,7 @@ Params: gpiopin Gpio pin
- addr I2C address of the MCP23017 (default: 0x20)
-
- mcp23008 Configure an MCP23008 instead.
-+ noints Disable the interrupt GPIO line.
-
-
- Name: mcp23s17
---- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
-@@ -34,11 +34,6 @@
- reg = <0x20>;
- gpio-controller;
- #gpio-cells = <2>;
-- #interrupt-cells=<2>;
-- interrupt-parent = <&gpio>;
-- interrupts = <4 2>;
-- interrupt-controller;
-- microchip,irq-mirror;
-
- status = "okay";
- };
-@@ -52,11 +47,25 @@
- };
- };
-
-+ fragment@4 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ mcp23017_irq: mcp@20 {
-+ #interrupt-cells=<2>;
-+ interrupt-parent = <&gpio>;
-+ interrupts = <4 2>;
-+ interrupt-controller;
-+ microchip,irq-mirror;
-+ };
-+ };
-+ };
-+
- __overrides__ {
- gpiopin = <&mcp23017_pins>,"brcm,pins:0",
-- <&mcp23017>,"interrupts:0";
-+ <&mcp23017_irq>,"interrupts:0";
- addr = <&mcp23017>,"reg:0", <&mcp23017_pins>,"reg:0";
- mcp23008 = <0>,"=3";
-+ noints = <0>,"!1!4";
- };
- };
-
--- /dev/null
+From b5ec436637af67f37efad1550945b750101527d4 Mon Sep 17 00:00:00 2001
+Date: Fri, 6 Sep 2019 15:13:06 +0100
+Subject: [PATCH] staging: bcm2835-camera: Add greyworld AWB mode
+
+This is mainly used for the NoIR camera which has no IR
+filter and can completely confuse normal AWB presets.
+
+---
+ drivers/staging/vc04_services/bcm2835-camera/controls.c | 8 ++++++--
+ .../staging/vc04_services/vchiq-mmal/mmal-parameters.h | 1 +
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -481,6 +481,10 @@ static int ctrl_set_awb_mode(struct bm28
+ case V4L2_WHITE_BALANCE_SHADE:
+ u32_value = MMAL_PARAM_AWBMODE_SHADE;
+ break;
++
++ case V4L2_WHITE_BALANCE_GREYWORLD:
++ u32_value = MMAL_PARAM_AWBMODE_GREYWORLD;
++ break;
+ }
+
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+@@ -1008,8 +1012,8 @@ static const struct bm2835_mmal_v4l2_ctr
+ {
+ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+ MMAL_CONTROL_TYPE_STD_MENU,
+- ~0x3ff, V4L2_WHITE_BALANCE_SHADE, V4L2_WHITE_BALANCE_AUTO, 0,
+- NULL,
++ ~0x7ff, V4L2_WHITE_BALANCE_GREYWORLD, V4L2_WHITE_BALANCE_AUTO,
++ 0, NULL,
+ MMAL_PARAMETER_AWB_MODE,
+ &ctrl_set_awb_mode,
+ false
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
+@@ -313,6 +313,7 @@ enum mmal_parameter_awbmode {
+ MMAL_PARAM_AWBMODE_INCANDESCENT,
+ MMAL_PARAM_AWBMODE_FLASH,
+ MMAL_PARAM_AWBMODE_HORIZON,
++ MMAL_PARAM_AWBMODE_GREYWORLD,
+ };
+
+ enum mmal_parameter_imagefx {
--- /dev/null
+From 2245d8c6d0feaa94ca55fa8ecfe3ca9c0c05c566 Mon Sep 17 00:00:00 2001
+Date: Mon, 9 Sep 2019 10:16:08 +0100
+Subject: [PATCH] PCI: brcmstb: Fix compilation warning
+
+Fixes: ea2c11a187c0e248343452846457b94715e04969
+Fixes: https://github.com/raspberrypi/linux/issues/3216
+
+---
+ drivers/pci/controller/pcie-brcmstb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -653,7 +653,7 @@ static int brcmstb_platform_notifier(str
+ ret = of_dma_configure(dev, dev->of_node, true);
+ if (ret) {
+ dev_err(dev, "of_dma_configure() failed: %d\n", ret);
+- return;
++ return ret;
+ }
+ }
+ brcm_set_dma_ops(dev);
+++ /dev/null
-From c8f63d006ff5f84ad629f4c06cdc9fee34fdfe3d Mon Sep 17 00:00:00 2001
-Date: Fri, 6 Sep 2019 15:04:51 +0100
-Subject: [PATCH] v4l2: Add a Greyworld AWB mode.
-
-Adds a simple greyworld white balance preset, mainly for use
-with cameras without an IR filter (eg Raspberry Pi NoIR)
-
----
- drivers/media/v4l2-core/v4l2-ctrls.c | 1 +
- include/uapi/linux/v4l2-controls.h | 1 +
- 2 files changed, 2 insertions(+)
-
---- a/drivers/media/v4l2-core/v4l2-ctrls.c
-+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
-@@ -275,6 +275,7 @@ const char * const *v4l2_ctrl_get_menu(u
- "Flash",
- "Cloudy",
- "Shade",
-+ "Greyworld",
- NULL,
- };
- static const char * const camera_iso_sensitivity_auto[] = {
---- a/include/uapi/linux/v4l2-controls.h
-+++ b/include/uapi/linux/v4l2-controls.h
-@@ -815,6 +815,7 @@ enum v4l2_auto_n_preset_white_balance {
- V4L2_WHITE_BALANCE_FLASH = 7,
- V4L2_WHITE_BALANCE_CLOUDY = 8,
- V4L2_WHITE_BALANCE_SHADE = 9,
-+ V4L2_WHITE_BALANCE_GREYWORLD = 10,
- };
-
- #define V4L2_CID_WIDE_DYNAMIC_RANGE (V4L2_CID_CAMERA_CLASS_BASE+21)
--- /dev/null
+From 1e37bc9f0ea83fa4b3f1714b4382edb7b256a251 Mon Sep 17 00:00:00 2001
+Date: Wed, 11 Sep 2019 14:57:18 +0100
+Subject: [PATCH] drm/vc4: Fix for margins in composite/SDTV mode
+ (#3223)
+
+Margins were incorrectly assumed to be setup in SDTV mode, but were
+not actually done, so this make the setup non-conditional on mode.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 11 +++--------
+ 1 file changed, 3 insertions(+), 8 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1588,14 +1588,9 @@ vc4_fkms_connector_init(struct drm_devic
+ connector->interlace_allowed = 0;
+ }
+
+- /* Create and attach TV margin props to this connector.
+- * Already done for SDTV outputs.
+- */
+- if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) {
+- ret = drm_mode_create_tv_margin_properties(dev);
+- if (ret)
+- goto fail;
+- }
++ ret = drm_mode_create_tv_margin_properties(dev);
++ if (ret)
++ goto fail;
+
+ drm_connector_attach_tv_margin_properties(connector);
+
+++ /dev/null
-From b5ec436637af67f37efad1550945b750101527d4 Mon Sep 17 00:00:00 2001
-Date: Fri, 6 Sep 2019 15:13:06 +0100
-Subject: [PATCH] staging: bcm2835-camera: Add greyworld AWB mode
-
-This is mainly used for the NoIR camera which has no IR
-filter and can completely confuse normal AWB presets.
-
----
- drivers/staging/vc04_services/bcm2835-camera/controls.c | 8 ++++++--
- .../staging/vc04_services/vchiq-mmal/mmal-parameters.h | 1 +
- 2 files changed, 7 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -481,6 +481,10 @@ static int ctrl_set_awb_mode(struct bm28
- case V4L2_WHITE_BALANCE_SHADE:
- u32_value = MMAL_PARAM_AWBMODE_SHADE;
- break;
-+
-+ case V4L2_WHITE_BALANCE_GREYWORLD:
-+ u32_value = MMAL_PARAM_AWBMODE_GREYWORLD;
-+ break;
- }
-
- return vchiq_mmal_port_parameter_set(dev->instance, control,
-@@ -1008,8 +1012,8 @@ static const struct bm2835_mmal_v4l2_ctr
- {
- V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
- MMAL_CONTROL_TYPE_STD_MENU,
-- ~0x3ff, V4L2_WHITE_BALANCE_SHADE, V4L2_WHITE_BALANCE_AUTO, 0,
-- NULL,
-+ ~0x7ff, V4L2_WHITE_BALANCE_GREYWORLD, V4L2_WHITE_BALANCE_AUTO,
-+ 0, NULL,
- MMAL_PARAMETER_AWB_MODE,
- &ctrl_set_awb_mode,
- false
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
-@@ -313,6 +313,7 @@ enum mmal_parameter_awbmode {
- MMAL_PARAM_AWBMODE_INCANDESCENT,
- MMAL_PARAM_AWBMODE_FLASH,
- MMAL_PARAM_AWBMODE_HORIZON,
-+ MMAL_PARAM_AWBMODE_GREYWORLD,
- };
-
- enum mmal_parameter_imagefx {
--- /dev/null
+From f0715f5e178f2f7c0afb719a3a35c8ac250b7586 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
+Date: Thu, 12 Sep 2019 14:57:32 +0200
+Subject: [PATCH] Add Hifiberry DAC+DSP soundcard driver (#3224)
+
+Adds the driver for the Hifiberry DAC+DSP. It supports capture and
+playback depending on the DSP firmware.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 ++
+ .../overlays/hifiberry-dacplusdsp-overlay.dts | 34 +++++++
+ sound/soc/bcm/Kconfig | 7 ++
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/hifiberry_dacplusdsp.c | 90 +++++++++++++++++++
+ sound/soc/bcm/rpi-simple-soundcard.c | 19 ++++
+ 10 files changed, 162 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts
+ create mode 100644 sound/soc/bcm/hifiberry_dacplusdsp.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -54,6 +54,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ hifiberry-dacplus.dtbo \
+ hifiberry-dacplusadc.dtbo \
+ hifiberry-dacplusadcpro.dtbo \
++ hifiberry-dacplusdsp.dtbo \
+ hifiberry-digi.dtbo \
+ hifiberry-digi-pro.dtbo \
+ hy28a.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -904,6 +904,12 @@ Params: 24db_digital_gain Allow ga
+ master for bit clock and frame clock.
+
+
++Name: hifiberry-dacplusdsp
++Info: Configures the HifiBerry DAC+DSP audio card
++Load: dtoverlay=hifiberry-dacplusdsp
++Params: <None>
++
++
+ Name: hifiberry-digi
+ Info: Configures the HifiBerry Digi and Digi+ audio card
+ Load: dtoverlay=hifiberry-digi
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts
+@@ -0,0 +1,34 @@
++// Definitions for hifiberry DAC+DSP soundcard overlay
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target-path = "/";
++ __overlay__ {
++ dacplusdsp-codec {
++ #sound-dai-cells = <0>;
++ compatible = "hifiberry,dacplusdsp";
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++};
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -56,6 +56,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
+ help
+ Say Y or M if you want to add support for HifiBerry DAC+ADC PRO.
+
++config SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP
++ tristate "Support for HifiBerry DAC+DSP"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_RPI_SIMPLE_SOUNDCARD
++ help
++ Say Y or M if you want to add support for HifiBerry DSP-DAC.
++
+ config SND_BCM2708_SOC_HIFIBERRY_DIGI
+ tristate "Support for HifiBerry Digi"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -15,6 +15,7 @@ snd-soc-googlevoicehat-codec-objs := goo
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
+ snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
+ snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
++snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
+ snd-soc-justboom-dac-objs := justboom-dac.o
+ snd-soc-rpi-cirrus-objs := rpi-cirrus.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+@@ -40,6 +41,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICE
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
+ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+--- /dev/null
++++ b/sound/soc/bcm/hifiberry_dacplusdsp.c
+@@ -0,0 +1,90 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * ASoC Driver for HiFiBerry DAC + DSP
++ *
++ * Copyright 2018
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <sound/soc.h>
++
++static struct snd_soc_component_driver dacplusdsp_component_driver;
++
++static struct snd_soc_dai_driver dacplusdsp_dai = {
++ .name = "dacplusdsp-hifi",
++ .capture = {
++ .stream_name = "DAC+DSP Capture",
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SNDRV_PCM_RATE_CONTINUOUS,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE |
++ SNDRV_PCM_FMTBIT_S24_LE |
++ SNDRV_PCM_FMTBIT_S32_LE,
++ },
++ .playback = {
++ .stream_name = "DACP+DSP Playback",
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SNDRV_PCM_RATE_CONTINUOUS,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE |
++ SNDRV_PCM_FMTBIT_S24_LE |
++ SNDRV_PCM_FMTBIT_S32_LE,
++ },
++ .symmetric_rates = 1};
++
++#ifdef CONFIG_OF
++static const struct of_device_id dacplusdsp_ids[] = {
++ {
++ .compatible = "hifiberry,dacplusdsp",
++ },
++ {} };
++MODULE_DEVICE_TABLE(of, dacplusdsp_ids);
++#endif
++
++static int dacplusdsp_platform_probe(struct platform_device *pdev)
++{
++ int ret;
++
++ ret = snd_soc_register_component(&pdev->dev,
++ &dacplusdsp_component_driver, &dacplusdsp_dai, 1);
++ if (ret) {
++ pr_alert("snd_soc_register_component failed\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static int dacplusdsp_platform_remove(struct platform_device *pdev)
++{
++ snd_soc_unregister_component(&pdev->dev);
++ return 0;
++}
++
++static struct platform_driver dacplusdsp_driver = {
++ .driver = {
++ .name = "hifiberry-dacplusdsp-codec",
++ .of_match_table = of_match_ptr(dacplusdsp_ids),
++ },
++ .probe = dacplusdsp_platform_probe,
++ .remove = dacplusdsp_platform_remove,
++};
++
++module_platform_driver(dacplusdsp_driver);
++
++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+DSP");
++MODULE_LICENSE("GPL v2");
+--- a/sound/soc/bcm/rpi-simple-soundcard.c
++++ b/sound/soc/bcm/rpi-simple-soundcard.c
+@@ -136,6 +136,23 @@ static struct snd_rpi_simple_drvdata drv
+ .dai = snd_googlevoicehat_soundcard_dai,
+ };
+
++static struct snd_soc_dai_link snd_hifiberrydacplusdsp_soundcard_dai[] = {
++{
++ .name = "Hifiberry DAC+DSP SoundCard",
++ .stream_name = "Hifiberry DAC+DSP SoundCard HiFi",
++ .codec_dai_name = "dacplusdsp-hifi",
++ .codec_name = "dacplusdsp-codec",
++ .dai_fmt = SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++},
++};
++
++static struct snd_rpi_simple_drvdata drvdata_hifiberrydacplusdsp = {
++ .card_name = "snd_rpi_hifiberrydacplusdsp_soundcard",
++ .dai = snd_hifiberrydacplusdsp_soundcard_dai,
++};
++
+ static struct snd_soc_dai_link snd_hifiberry_amp_dai[] = {
+ {
+ .name = "HifiBerry AMP",
+@@ -193,6 +210,8 @@ static const struct of_device_id snd_rpi
+ .data = (void *) &drvdata_adau1977 },
+ { .compatible = "googlevoicehat,googlevoicehat-soundcard",
+ .data = (void *) &drvdata_googlevoicehat },
++ { .compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard",
++ .data = (void *) &drvdata_hifiberrydacplusdsp },
+ { .compatible = "hifiberry,hifiberry-amp",
+ .data = (void *) &drvdata_hifiberry_amp },
+ { .compatible = "hifiberry,hifiberry-dac",
+++ /dev/null
-From 2245d8c6d0feaa94ca55fa8ecfe3ca9c0c05c566 Mon Sep 17 00:00:00 2001
-Date: Mon, 9 Sep 2019 10:16:08 +0100
-Subject: [PATCH] PCI: brcmstb: Fix compilation warning
-
-Fixes: ea2c11a187c0e248343452846457b94715e04969
-Fixes: https://github.com/raspberrypi/linux/issues/3216
-
----
- drivers/pci/controller/pcie-brcmstb.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -653,7 +653,7 @@ static int brcmstb_platform_notifier(str
- ret = of_dma_configure(dev, dev->of_node, true);
- if (ret) {
- dev_err(dev, "of_dma_configure() failed: %d\n", ret);
-- return;
-+ return ret;
- }
- }
- brcm_set_dma_ops(dev);
+++ /dev/null
-From 1e37bc9f0ea83fa4b3f1714b4382edb7b256a251 Mon Sep 17 00:00:00 2001
-Date: Wed, 11 Sep 2019 14:57:18 +0100
-Subject: [PATCH] drm/vc4: Fix for margins in composite/SDTV mode
- (#3223)
-
-Margins were incorrectly assumed to be setup in SDTV mode, but were
-not actually done, so this make the setup non-conditional on mode.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 11 +++--------
- 1 file changed, 3 insertions(+), 8 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1588,14 +1588,9 @@ vc4_fkms_connector_init(struct drm_devic
- connector->interlace_allowed = 0;
- }
-
-- /* Create and attach TV margin props to this connector.
-- * Already done for SDTV outputs.
-- */
-- if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) {
-- ret = drm_mode_create_tv_margin_properties(dev);
-- if (ret)
-- goto fail;
-- }
-+ ret = drm_mode_create_tv_margin_properties(dev);
-+ if (ret)
-+ goto fail;
-
- drm_connector_attach_tv_margin_properties(connector);
-
--- /dev/null
+From b25d17959484972a6585d6e1f7cb2cfb93d1540e Mon Sep 17 00:00:00 2001
+Date: Fri, 6 Sep 2019 17:24:55 +0100
+Subject: [PATCH] staging: bcm2835-codec: Allow height of 1920.
+
+The codec is happy with video up to 1920 high if the width
+is suitably reduced to stay within level limits. eg 1080x1920
+is OK to decode.
+
+Increase the height limit accordingly.
+
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -92,7 +92,7 @@ static const char * const components[] =
+ #define MIN_W 32
+ #define MIN_H 32
+ #define MAX_W 1920
+-#define MAX_H 1088
++#define MAX_H 1920
+ #define BPL_ALIGN 32
+ #define DEFAULT_WIDTH 640
+ #define DEFAULT_HEIGHT 480
+++ /dev/null
-From f0715f5e178f2f7c0afb719a3a35c8ac250b7586 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
-Date: Thu, 12 Sep 2019 14:57:32 +0200
-Subject: [PATCH] Add Hifiberry DAC+DSP soundcard driver (#3224)
-
-Adds the driver for the Hifiberry DAC+DSP. It supports capture and
-playback depending on the DSP firmware.
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 6 ++
- .../overlays/hifiberry-dacplusdsp-overlay.dts | 34 +++++++
- sound/soc/bcm/Kconfig | 7 ++
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/hifiberry_dacplusdsp.c | 90 +++++++++++++++++++
- sound/soc/bcm/rpi-simple-soundcard.c | 19 ++++
- 10 files changed, 162 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts
- create mode 100644 sound/soc/bcm/hifiberry_dacplusdsp.c
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -54,6 +54,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- hifiberry-dacplus.dtbo \
- hifiberry-dacplusadc.dtbo \
- hifiberry-dacplusadcpro.dtbo \
-+ hifiberry-dacplusdsp.dtbo \
- hifiberry-digi.dtbo \
- hifiberry-digi-pro.dtbo \
- hy28a.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -904,6 +904,12 @@ Params: 24db_digital_gain Allow ga
- master for bit clock and frame clock.
-
-
-+Name: hifiberry-dacplusdsp
-+Info: Configures the HifiBerry DAC+DSP audio card
-+Load: dtoverlay=hifiberry-dacplusdsp
-+Params: <None>
-+
-+
- Name: hifiberry-digi
- Info: Configures the HifiBerry Digi and Digi+ audio card
- Load: dtoverlay=hifiberry-digi
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts
-@@ -0,0 +1,34 @@
-+// Definitions for hifiberry DAC+DSP soundcard overlay
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target-path = "/";
-+ __overlay__ {
-+ dacplusdsp-codec {
-+ #sound-dai-cells = <0>;
-+ compatible = "hifiberry,dacplusdsp";
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+};
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -56,6 +56,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
- help
- Say Y or M if you want to add support for HifiBerry DAC+ADC PRO.
-
-+config SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP
-+ tristate "Support for HifiBerry DAC+DSP"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_RPI_SIMPLE_SOUNDCARD
-+ help
-+ Say Y or M if you want to add support for HifiBerry DSP-DAC.
-+
- config SND_BCM2708_SOC_HIFIBERRY_DIGI
- tristate "Support for HifiBerry Digi"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -15,6 +15,7 @@ snd-soc-googlevoicehat-codec-objs := goo
- snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
- snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
- snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
-+snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
- snd-soc-justboom-dac-objs := justboom-dac.o
- snd-soc-rpi-cirrus-objs := rpi-cirrus.o
- snd-soc-rpi-proto-objs := rpi-proto.o
-@@ -40,6 +41,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICE
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
-+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
- obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
---- /dev/null
-+++ b/sound/soc/bcm/hifiberry_dacplusdsp.c
-@@ -0,0 +1,90 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * ASoC Driver for HiFiBerry DAC + DSP
-+ *
-+ * Copyright 2018
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <sound/soc.h>
-+
-+static struct snd_soc_component_driver dacplusdsp_component_driver;
-+
-+static struct snd_soc_dai_driver dacplusdsp_dai = {
-+ .name = "dacplusdsp-hifi",
-+ .capture = {
-+ .stream_name = "DAC+DSP Capture",
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
-+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
-+ SNDRV_PCM_FMTBIT_S24_LE |
-+ SNDRV_PCM_FMTBIT_S32_LE,
-+ },
-+ .playback = {
-+ .stream_name = "DACP+DSP Playback",
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
-+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
-+ SNDRV_PCM_FMTBIT_S24_LE |
-+ SNDRV_PCM_FMTBIT_S32_LE,
-+ },
-+ .symmetric_rates = 1};
-+
-+#ifdef CONFIG_OF
-+static const struct of_device_id dacplusdsp_ids[] = {
-+ {
-+ .compatible = "hifiberry,dacplusdsp",
-+ },
-+ {} };
-+MODULE_DEVICE_TABLE(of, dacplusdsp_ids);
-+#endif
-+
-+static int dacplusdsp_platform_probe(struct platform_device *pdev)
-+{
-+ int ret;
-+
-+ ret = snd_soc_register_component(&pdev->dev,
-+ &dacplusdsp_component_driver, &dacplusdsp_dai, 1);
-+ if (ret) {
-+ pr_alert("snd_soc_register_component failed\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int dacplusdsp_platform_remove(struct platform_device *pdev)
-+{
-+ snd_soc_unregister_component(&pdev->dev);
-+ return 0;
-+}
-+
-+static struct platform_driver dacplusdsp_driver = {
-+ .driver = {
-+ .name = "hifiberry-dacplusdsp-codec",
-+ .of_match_table = of_match_ptr(dacplusdsp_ids),
-+ },
-+ .probe = dacplusdsp_platform_probe,
-+ .remove = dacplusdsp_platform_remove,
-+};
-+
-+module_platform_driver(dacplusdsp_driver);
-+
-+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+DSP");
-+MODULE_LICENSE("GPL v2");
---- a/sound/soc/bcm/rpi-simple-soundcard.c
-+++ b/sound/soc/bcm/rpi-simple-soundcard.c
-@@ -136,6 +136,23 @@ static struct snd_rpi_simple_drvdata drv
- .dai = snd_googlevoicehat_soundcard_dai,
- };
-
-+static struct snd_soc_dai_link snd_hifiberrydacplusdsp_soundcard_dai[] = {
-+{
-+ .name = "Hifiberry DAC+DSP SoundCard",
-+ .stream_name = "Hifiberry DAC+DSP SoundCard HiFi",
-+ .codec_dai_name = "dacplusdsp-hifi",
-+ .codec_name = "dacplusdsp-codec",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S |
-+ SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBS_CFS,
-+},
-+};
-+
-+static struct snd_rpi_simple_drvdata drvdata_hifiberrydacplusdsp = {
-+ .card_name = "snd_rpi_hifiberrydacplusdsp_soundcard",
-+ .dai = snd_hifiberrydacplusdsp_soundcard_dai,
-+};
-+
- static struct snd_soc_dai_link snd_hifiberry_amp_dai[] = {
- {
- .name = "HifiBerry AMP",
-@@ -193,6 +210,8 @@ static const struct of_device_id snd_rpi
- .data = (void *) &drvdata_adau1977 },
- { .compatible = "googlevoicehat,googlevoicehat-soundcard",
- .data = (void *) &drvdata_googlevoicehat },
-+ { .compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard",
-+ .data = (void *) &drvdata_hifiberrydacplusdsp },
- { .compatible = "hifiberry,hifiberry-amp",
- .data = (void *) &drvdata_hifiberry_amp },
- { .compatible = "hifiberry,hifiberry-dac",
--- /dev/null
+From 956fd55c1071c48f00285d82507698c501633e7a Mon Sep 17 00:00:00 2001
+Date: Fri, 13 Sep 2019 15:11:47 +0100
+Subject: [PATCH] staging: bcm2835-codec: Correct g/s_selection API
+ MPLANE support
+
+The g_selection and s_selection API is messed up and requires
+the driver to expect the non-MPLANE buffer types, not the MPLANE
+ones even if they are supported. The V4L2 core will convert the
+MPLANE ones to non-MPLANE should they be passed in
+
+Fixes: 5e484a3 staging: bcm2835-codec: switch to multi-planar API
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 67 +++++++++++++------
+ 1 file changed, 47 insertions(+), 20 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1260,17 +1260,30 @@ static int vidioc_g_selection(struct fil
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+ struct bcm2835_codec_q_data *q_data;
+- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
+- true : false;
+
+- if ((ctx->dev->role == DECODE && !capture_queue) ||
+- (ctx->dev->role == ENCODE && capture_queue))
+- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
+- return -EINVAL;
+-
+- q_data = get_q_data(ctx, s->type);
+- if (!q_data)
++ /*
++ * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and
++ * V4L2_BUF_TYPE_VIDEO_OUTPUT, even if the device implements the MPLANE
++ * API. The V4L2 core will have converted the MPLANE variants to
++ * non-MPLANE.
++ * Open code this instead of using get_q_data in this case.
++ */
++ switch (s->type) {
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ /* CAPTURE on encoder is not valid. */
++ if (ctx->dev->role == ENCODE)
++ return -EINVAL;
++ q_data = &ctx->q_data[V4L2_M2M_DST];
++ break;
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
++ /* OUTPUT on deoder is not valid. */
++ if (ctx->dev->role == DECODE)
++ return -EINVAL;
++ q_data = &ctx->q_data[V4L2_M2M_SRC];
++ break;
++ default:
+ return -EINVAL;
++ }
+
+ switch (ctx->dev->role) {
+ case DECODE:
+@@ -1323,22 +1336,36 @@ static int vidioc_s_selection(struct fil
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+ struct bcm2835_codec_q_data *q_data = NULL;
+- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
+- true : false;
++
++ /*
++ * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and
++ * V4L2_BUF_TYPE_VIDEO_OUTPUT, even if the device implements the MPLANE
++ * API. The V4L2 core will have converted the MPLANE variants to
++ * non-MPLANE.
++ *
++ * Open code this instead of using get_q_data in this case.
++ */
++ switch (s->type) {
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ /* CAPTURE on encoder is not valid. */
++ if (ctx->dev->role == ENCODE)
++ return -EINVAL;
++ q_data = &ctx->q_data[V4L2_M2M_DST];
++ break;
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
++ /* OUTPUT on deoder is not valid. */
++ if (ctx->dev->role == DECODE)
++ return -EINVAL;
++ q_data = &ctx->q_data[V4L2_M2M_SRC];
++ break;
++ default:
++ return -EINVAL;
++ }
+
+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
+ __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top,
+ s->r.width, s->r.height);
+
+- if ((ctx->dev->role == DECODE && !capture_queue) ||
+- (ctx->dev->role == ENCODE && capture_queue))
+- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
+- return -EINVAL;
+-
+- q_data = get_q_data(ctx, s->type);
+- if (!q_data)
+- return -EINVAL;
+-
+ switch (ctx->dev->role) {
+ case DECODE:
+ switch (s->target) {
--- /dev/null
+From f6d983b7bc9ae79d0eb4dea7bc30a1ad5ff428a7 Mon Sep 17 00:00:00 2001
+Date: Fri, 12 Oct 2018 14:54:12 +0200
+Subject: [PATCH] regulator/gpio: Allow nonexclusive GPIO access
+
+commit b0ce7b29bfcd090ddba476f45a75ec0a797b048a upstream.
+
+[ This is a partial cherry-pick, omitting the regulator
+change which isn't required ]
+
+This allows nonexclusive (simultaneous) access to a single
+GPIO line for the fixed regulator enable line. This happens
+when several regulators use the same GPIO for enabling and
+disabling a regulator, and all need a handle on their GPIO
+descriptor.
+
+This solution with a special flag is not entirely elegant
+and should ideally be replaced by something more careful as
+this makes it possible for several consumers to
+enable/disable the same GPIO line to the left and right
+without any consistency. The current use inside the regulator
+core should however be fine as it takes special care to
+handle this.
+
+For the state of the GPIO backend, this is still the
+lesser evil compared to going back to global GPIO
+numbers.
+
+Fixes: efdfeb079cc3 ("regulator: fixed: Convert to use GPIO descriptor only")
+---
+ drivers/gpio/gpiolib.c | 19 +++++++++++++++++--
+ include/linux/gpio/consumer.h | 1 +
+ 2 files changed, 18 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -3988,8 +3988,23 @@ struct gpio_desc *__must_check gpiod_get
+ * the device name as label
+ */
+ status = gpiod_request(desc, con_id ? con_id : devname);
+- if (status < 0)
+- return ERR_PTR(status);
++ if (status < 0) {
++ if (status == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
++ /*
++ * This happens when there are several consumers for
++ * the same GPIO line: we just return here without
++ * further initialization. It is a bit if a hack.
++ * This is necessary to support fixed regulators.
++ *
++ * FIXME: Make this more sane and safe.
++ */
++ dev_info(dev, "nonexclusive access to GPIO for %s\n",
++ con_id ? con_id : devname);
++ return desc;
++ } else {
++ return ERR_PTR(status);
++ }
++ }
+
+ status = gpiod_configure_flags(desc, con_id, lookupflags, flags);
+ if (status < 0) {
+--- a/include/linux/gpio/consumer.h
++++ b/include/linux/gpio/consumer.h
+@@ -30,6 +30,7 @@ struct gpio_descs {
+ #define GPIOD_FLAGS_BIT_DIR_OUT BIT(1)
+ #define GPIOD_FLAGS_BIT_DIR_VAL BIT(2)
+ #define GPIOD_FLAGS_BIT_OPEN_DRAIN BIT(3)
++#define GPIOD_FLAGS_BIT_NONEXCLUSIVE BIT(4)
+
+ /**
+ * Optional flags that can be passed to one of gpiod_* to configure direction
+++ /dev/null
-From b25d17959484972a6585d6e1f7cb2cfb93d1540e Mon Sep 17 00:00:00 2001
-Date: Fri, 6 Sep 2019 17:24:55 +0100
-Subject: [PATCH] staging: bcm2835-codec: Allow height of 1920.
-
-The codec is happy with video up to 1920 high if the width
-is suitably reduced to stay within level limits. eg 1080x1920
-is OK to decode.
-
-Increase the height limit accordingly.
-
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -92,7 +92,7 @@ static const char * const components[] =
- #define MIN_W 32
- #define MIN_H 32
- #define MAX_W 1920
--#define MAX_H 1088
-+#define MAX_H 1920
- #define BPL_ALIGN 32
- #define DEFAULT_WIDTH 640
- #define DEFAULT_HEIGHT 480
--- /dev/null
+From 76870d237adff4c8e419064e7d4f5a8ef87c1085 Mon Sep 17 00:00:00 2001
+Date: Thu, 6 Dec 2018 13:43:44 +0100
+Subject: [PATCH] gpio: Enable nonexclusive gpiods from DT nodes
+
+commit ec757001c818c175e6b610e8ef80c2a25d1ed1a5 upstream.
+
+This makes gpiod_get_from_of_node() respect the
+GPIOD_FLAGS_BIT_NONEXCLUSIVE flag which is especially
+nice when getting regulator GPIOs right out of device
+tree nodes.
+
+Fixes: b0ce7b29bfcd ("regulator/gpio: Allow nonexclusive GPIO access")
+---
+ drivers/gpio/gpiolib.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -4062,6 +4062,8 @@ struct gpio_desc *gpiod_get_from_of_node
+ transitory = flags & OF_GPIO_TRANSITORY;
+
+ ret = gpiod_request(desc, label);
++ if (ret == -EBUSY && (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
++ return desc;
+ if (ret)
+ return ERR_PTR(ret);
+
+++ /dev/null
-From 956fd55c1071c48f00285d82507698c501633e7a Mon Sep 17 00:00:00 2001
-Date: Fri, 13 Sep 2019 15:11:47 +0100
-Subject: [PATCH] staging: bcm2835-codec: Correct g/s_selection API
- MPLANE support
-
-The g_selection and s_selection API is messed up and requires
-the driver to expect the non-MPLANE buffer types, not the MPLANE
-ones even if they are supported. The V4L2 core will convert the
-MPLANE ones to non-MPLANE should they be passed in
-
-Fixes: 5e484a3 staging: bcm2835-codec: switch to multi-planar API
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 67 +++++++++++++------
- 1 file changed, 47 insertions(+), 20 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1260,17 +1260,30 @@ static int vidioc_g_selection(struct fil
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
- struct bcm2835_codec_q_data *q_data;
-- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
-- true : false;
-
-- if ((ctx->dev->role == DECODE && !capture_queue) ||
-- (ctx->dev->role == ENCODE && capture_queue))
-- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
-- return -EINVAL;
--
-- q_data = get_q_data(ctx, s->type);
-- if (!q_data)
-+ /*
-+ * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and
-+ * V4L2_BUF_TYPE_VIDEO_OUTPUT, even if the device implements the MPLANE
-+ * API. The V4L2 core will have converted the MPLANE variants to
-+ * non-MPLANE.
-+ * Open code this instead of using get_q_data in this case.
-+ */
-+ switch (s->type) {
-+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+ /* CAPTURE on encoder is not valid. */
-+ if (ctx->dev->role == ENCODE)
-+ return -EINVAL;
-+ q_data = &ctx->q_data[V4L2_M2M_DST];
-+ break;
-+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-+ /* OUTPUT on deoder is not valid. */
-+ if (ctx->dev->role == DECODE)
-+ return -EINVAL;
-+ q_data = &ctx->q_data[V4L2_M2M_SRC];
-+ break;
-+ default:
- return -EINVAL;
-+ }
-
- switch (ctx->dev->role) {
- case DECODE:
-@@ -1323,22 +1336,36 @@ static int vidioc_s_selection(struct fil
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
- struct bcm2835_codec_q_data *q_data = NULL;
-- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
-- true : false;
-+
-+ /*
-+ * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and
-+ * V4L2_BUF_TYPE_VIDEO_OUTPUT, even if the device implements the MPLANE
-+ * API. The V4L2 core will have converted the MPLANE variants to
-+ * non-MPLANE.
-+ *
-+ * Open code this instead of using get_q_data in this case.
-+ */
-+ switch (s->type) {
-+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+ /* CAPTURE on encoder is not valid. */
-+ if (ctx->dev->role == ENCODE)
-+ return -EINVAL;
-+ q_data = &ctx->q_data[V4L2_M2M_DST];
-+ break;
-+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-+ /* OUTPUT on deoder is not valid. */
-+ if (ctx->dev->role == DECODE)
-+ return -EINVAL;
-+ q_data = &ctx->q_data[V4L2_M2M_SRC];
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-
- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
- __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top,
- s->r.width, s->r.height);
-
-- if ((ctx->dev->role == DECODE && !capture_queue) ||
-- (ctx->dev->role == ENCODE && capture_queue))
-- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
-- return -EINVAL;
--
-- q_data = get_q_data(ctx, s->type);
-- if (!q_data)
-- return -EINVAL;
--
- switch (ctx->dev->role) {
- case DECODE:
- switch (s->target) {
--- /dev/null
+From a37a706547897d77b3194fc507b2546197def430 Mon Sep 17 00:00:00 2001
+Date: Tue, 17 Sep 2019 16:22:09 +0100
+Subject: [PATCH] Fix poll rate on touchscreen (#3238)
+
+Was running at 25Hz, rather than he expected 60. Only been doing it
+for the last 5 years....
+
+Replace msleep_interruptible with usleep_range as the msleep call
+is not accurate for times < 20ms.
+
+Fixes: https://github.com/raspberrypi/linux/issues/3227
+
+---
+ drivers/input/touchscreen/rpi-ft5406.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/input/touchscreen/rpi-ft5406.c
++++ b/drivers/input/touchscreen/rpi-ft5406.c
+@@ -78,7 +78,7 @@ static int ft5406_thread(void *arg)
+
+ while (!kthread_should_stop()) {
+ /* 60fps polling */
+- msleep_interruptible(17);
++ usleep_range(16600, 16700);
+ memcpy_fromio(®s, ts->ts_base, sizeof(struct ft5406_regs));
+ iowrite8(99,
+ ts->ts_base +
+++ /dev/null
-From f6d983b7bc9ae79d0eb4dea7bc30a1ad5ff428a7 Mon Sep 17 00:00:00 2001
-Date: Fri, 12 Oct 2018 14:54:12 +0200
-Subject: [PATCH] regulator/gpio: Allow nonexclusive GPIO access
-
-commit b0ce7b29bfcd090ddba476f45a75ec0a797b048a upstream.
-
-[ This is a partial cherry-pick, omitting the regulator
-change which isn't required ]
-
-This allows nonexclusive (simultaneous) access to a single
-GPIO line for the fixed regulator enable line. This happens
-when several regulators use the same GPIO for enabling and
-disabling a regulator, and all need a handle on their GPIO
-descriptor.
-
-This solution with a special flag is not entirely elegant
-and should ideally be replaced by something more careful as
-this makes it possible for several consumers to
-enable/disable the same GPIO line to the left and right
-without any consistency. The current use inside the regulator
-core should however be fine as it takes special care to
-handle this.
-
-For the state of the GPIO backend, this is still the
-lesser evil compared to going back to global GPIO
-numbers.
-
-Fixes: efdfeb079cc3 ("regulator: fixed: Convert to use GPIO descriptor only")
----
- drivers/gpio/gpiolib.c | 19 +++++++++++++++++--
- include/linux/gpio/consumer.h | 1 +
- 2 files changed, 18 insertions(+), 2 deletions(-)
-
---- a/drivers/gpio/gpiolib.c
-+++ b/drivers/gpio/gpiolib.c
-@@ -3988,8 +3988,23 @@ struct gpio_desc *__must_check gpiod_get
- * the device name as label
- */
- status = gpiod_request(desc, con_id ? con_id : devname);
-- if (status < 0)
-- return ERR_PTR(status);
-+ if (status < 0) {
-+ if (status == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
-+ /*
-+ * This happens when there are several consumers for
-+ * the same GPIO line: we just return here without
-+ * further initialization. It is a bit if a hack.
-+ * This is necessary to support fixed regulators.
-+ *
-+ * FIXME: Make this more sane and safe.
-+ */
-+ dev_info(dev, "nonexclusive access to GPIO for %s\n",
-+ con_id ? con_id : devname);
-+ return desc;
-+ } else {
-+ return ERR_PTR(status);
-+ }
-+ }
-
- status = gpiod_configure_flags(desc, con_id, lookupflags, flags);
- if (status < 0) {
---- a/include/linux/gpio/consumer.h
-+++ b/include/linux/gpio/consumer.h
-@@ -30,6 +30,7 @@ struct gpio_descs {
- #define GPIOD_FLAGS_BIT_DIR_OUT BIT(1)
- #define GPIOD_FLAGS_BIT_DIR_VAL BIT(2)
- #define GPIOD_FLAGS_BIT_OPEN_DRAIN BIT(3)
-+#define GPIOD_FLAGS_BIT_NONEXCLUSIVE BIT(4)
-
- /**
- * Optional flags that can be passed to one of gpiod_* to configure direction
--- /dev/null
+From 75967d69ea58555d12a7d9058653a69210d2ba86 Mon Sep 17 00:00:00 2001
+Date: Wed, 18 Sep 2019 09:02:10 +0100
+Subject: [PATCH] dts: Add DTS for Pi 2B rev 1.2 with BCM2837 (#3235)
+
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/bcm2710-rpi-2-b.dts | 125 ++++++++++++++++++
+ arch/arm64/boot/dts/broadcom/Makefile | 2 +
+ .../boot/dts/broadcom/bcm2710-rpi-2-b.dts | 3 +
+ 4 files changed, 131 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm2710-rpi-2-b.dts
+ create mode 100644 arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -7,6 +7,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2708-rpi-zero.dtb \
+ bcm2708-rpi-zero-w.dtb \
+ bcm2709-rpi-2-b.dtb \
++ bcm2710-rpi-2-b.dtb \
+ bcm2710-rpi-3-b.dtb \
+ bcm2711-rpi-4-b.dtb \
+ bcm2710-rpi-3-b-plus.dtb \
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2710-rpi-2-b.dts
+@@ -0,0 +1,125 @@
++/dts-v1/;
++
++#include "bcm2710.dtsi"
++#include "bcm2709-rpi.dtsi"
++#include "bcm283x-rpi-smsc9514.dtsi"
++#include "bcm283x-rpi-csi1-2lane.dtsi"
++
++/ {
++ compatible = "raspberrypi,2-model-b-rev2", "brcm,bcm2837";
++ model = "Raspberry Pi 2 Model B rev 1.2";
++};
++
++&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 */
++ };
++
++ audio_pins: audio_pins {
++ brcm,pins = <40 45>;
++ brcm,function = <4>;
++ };
++};
++
++&uart0 {
++ 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>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ 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: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&gpio 47 0>;
++ };
++
++ pwr_led: pwr {
++ label = "led1";
++ linux,default-trigger = "input";
++ gpios = <&gpio 35 0>;
++ };
++};
++
++&hdmi {
++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++};
++
++&audio {
++ pinctrl-names = "default";
++ pinctrl-0 = <&audio_pins>;
++};
++
++/ {
++ __overrides__ {
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++
++ pwr_led_gpio = <&pwr_led>,"gpios:4";
++ pwr_led_activelow = <&pwr_led>,"gpios:8";
++ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
++ };
++};
+--- a/arch/arm64/boot/dts/broadcom/Makefile
++++ b/arch/arm64/boot/dts/broadcom/Makefile
+@@ -1,7 +1,9 @@
+ # SPDX-License-Identifier: GPL-2.0
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rpi-3-b.dtb \
+ bcm2837-rpi-3-b-plus.dtb
++dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-2-b.dtb
+ dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-3-b.dtb
++dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-2-b.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-4-b.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b-plus.dtb
+--- /dev/null
++++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts
+@@ -0,0 +1,3 @@
++#define RPI364
++
++#include "../../../../arm/boot/dts/bcm2710-rpi-2-b.dts"
+++ /dev/null
-From 76870d237adff4c8e419064e7d4f5a8ef87c1085 Mon Sep 17 00:00:00 2001
-Date: Thu, 6 Dec 2018 13:43:44 +0100
-Subject: [PATCH] gpio: Enable nonexclusive gpiods from DT nodes
-
-commit ec757001c818c175e6b610e8ef80c2a25d1ed1a5 upstream.
-
-This makes gpiod_get_from_of_node() respect the
-GPIOD_FLAGS_BIT_NONEXCLUSIVE flag which is especially
-nice when getting regulator GPIOs right out of device
-tree nodes.
-
-Fixes: b0ce7b29bfcd ("regulator/gpio: Allow nonexclusive GPIO access")
----
- drivers/gpio/gpiolib.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/gpio/gpiolib.c
-+++ b/drivers/gpio/gpiolib.c
-@@ -4062,6 +4062,8 @@ struct gpio_desc *gpiod_get_from_of_node
- transitory = flags & OF_GPIO_TRANSITORY;
-
- ret = gpiod_request(desc, label);
-+ if (ret == -EBUSY && (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
-+ return desc;
- if (ret)
- return ERR_PTR(ret);
-
+++ /dev/null
-From a37a706547897d77b3194fc507b2546197def430 Mon Sep 17 00:00:00 2001
-Date: Tue, 17 Sep 2019 16:22:09 +0100
-Subject: [PATCH] Fix poll rate on touchscreen (#3238)
-
-Was running at 25Hz, rather than he expected 60. Only been doing it
-for the last 5 years....
-
-Replace msleep_interruptible with usleep_range as the msleep call
-is not accurate for times < 20ms.
-
-Fixes: https://github.com/raspberrypi/linux/issues/3227
-
----
- drivers/input/touchscreen/rpi-ft5406.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/input/touchscreen/rpi-ft5406.c
-+++ b/drivers/input/touchscreen/rpi-ft5406.c
-@@ -78,7 +78,7 @@ static int ft5406_thread(void *arg)
-
- while (!kthread_should_stop()) {
- /* 60fps polling */
-- msleep_interruptible(17);
-+ usleep_range(16600, 16700);
- memcpy_fromio(®s, ts->ts_base, sizeof(struct ft5406_regs));
- iowrite8(99,
- ts->ts_base +
--- /dev/null
+From bc4661703d132ae1fb91d66641c64851eae44959 Mon Sep 17 00:00:00 2001
+Date: Tue, 3 Sep 2019 08:45:24 +0200
+Subject: [PATCH] drm/v3d: clean caches at the end of render jobs on
+ request from user space
+
+Extends the user space ioctl for CL submissions so it can include a request
+to flush the cache once the CL execution has completed. Fixes memory
+write violation messages reported by the kernel in workloads involving
+shader memory writes (SSBOs, shader images, scratch, etc) which sometimes
+also lead to GPU resets during Piglit and CTS workloads.
+
+v2: if v3d_job_init() fails we need to kfree() the job instead of
+ v3d_job_put() it (Eric Anholt).
+
+v3 (Eric Anholt):
+ - Drop _FLAG suffix from the new flag name.
+ - Add a new param so userspace can tell whether cache flushing is
+ implemented in the kernel.
+
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 3 ++
+ drivers/gpu/drm/v3d/v3d_gem.c | 54 +++++++++++++++++++++++++++++------
+ include/uapi/drm/v3d_drm.h | 6 ++--
+ 3 files changed, 53 insertions(+), 10 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -117,6 +117,9 @@ static int v3d_get_param_ioctl(struct dr
+ case DRM_V3D_PARAM_SUPPORTS_CSD:
+ args->value = v3d_has_csd(v3d);
+ return 0;
++ case DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH:
++ args->value = 1;
++ return 0;
+ default:
+ DRM_DEBUG("Unknown parameter %d\n", args->param);
+ return -EINVAL;
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -709,13 +709,16 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ struct drm_v3d_submit_cl *args = data;
+ struct v3d_bin_job *bin = NULL;
+ struct v3d_render_job *render;
++ struct v3d_job *clean_job = NULL;
++ struct v3d_job *last_job;
+ struct ww_acquire_ctx acquire_ctx;
+ int ret = 0;
+
+ trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end);
+
+- if (args->pad != 0) {
+- DRM_INFO("pad must be zero: %d\n", args->pad);
++ if (args->flags != 0 &&
++ args->flags != DRM_V3D_SUBMIT_CL_FLUSH_CACHE) {
++ DRM_INFO("invalid flags: %d\n", args->flags);
+ return -EINVAL;
+ }
+
+@@ -755,12 +758,31 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ bin->render = render;
+ }
+
+- ret = v3d_lookup_bos(dev, file_priv, &render->base,
++ if (args->flags & DRM_V3D_SUBMIT_CL_FLUSH_CACHE) {
++ clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL);
++ if (!clean_job) {
++ ret = -ENOMEM;
++ goto fail;
++ }
++
++ ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0);
++ if (ret) {
++ kfree(clean_job);
++ clean_job = NULL;
++ goto fail;
++ }
++
++ last_job = clean_job;
++ } else {
++ last_job = &render->base;
++ }
++
++ ret = v3d_lookup_bos(dev, file_priv, last_job,
+ args->bo_handles, args->bo_handle_count);
+ if (ret)
+ goto fail;
+
+- ret = v3d_lock_bo_reservations(&render->base, &acquire_ctx);
++ ret = v3d_lock_bo_reservations(last_job, &acquire_ctx);
+ if (ret)
+ goto fail;
+
+@@ -772,33 +794,49 @@ v3d_submit_cl_ioctl(struct drm_device *d
+
+ ret = v3d_add_dep(&render->base,
+ dma_fence_get(bin->base.done_fence));
++ if (ret)
++ goto fail_unreserve;
+ }
+
+ ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER);
+ if (ret)
+ goto fail_unreserve;
++
++ if (clean_job) {
++ ret = v3d_add_dep(clean_job,
++ dma_fence_get(render->base.done_fence));
++ if (ret)
++ goto fail_unreserve;
++ ret = v3d_push_job(v3d_priv, clean_job, V3D_CACHE_CLEAN);
++ if (ret)
++ goto fail_unreserve;
++ }
+ mutex_unlock(&v3d->sched_lock);
+
+ v3d_attach_fences_and_unlock_reservation(file_priv,
+- &render->base,
++ last_job,
+ &acquire_ctx,
+ args->out_sync,
+- render->base.done_fence);
++ last_job->done_fence);
+
+ if (bin)
+ v3d_job_put(&bin->base);
+ v3d_job_put(&render->base);
++ if (clean_job)
++ v3d_job_put(clean_job);
+
+ return 0;
+
+ fail_unreserve:
+ mutex_unlock(&v3d->sched_lock);
+- v3d_unlock_bo_reservations(render->base.bo,
+- render->base.bo_count, &acquire_ctx);
++ v3d_unlock_bo_reservations(last_job->bo,
++ last_job->bo_count, &acquire_ctx);
+ fail:
+ if (bin)
+ v3d_job_put(&bin->base);
+ v3d_job_put(&render->base);
++ if (clean_job)
++ v3d_job_put(clean_job);
+
+ return ret;
+ }
+--- a/include/uapi/drm/v3d_drm.h
++++ b/include/uapi/drm/v3d_drm.h
+@@ -48,6 +48,8 @@ extern "C" {
+ #define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu)
+ #define DRM_IOCTL_V3D_SUBMIT_CSD DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CSD, struct drm_v3d_submit_csd)
+
++#define DRM_V3D_SUBMIT_CL_FLUSH_CACHE 0x01
++
+ /**
+ * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D
+ * engine.
+@@ -106,8 +108,7 @@ struct drm_v3d_submit_cl {
+ /* Number of BO handles passed in (size is that times 4). */
+ __u32 bo_handle_count;
+
+- /* Pad, must be zero-filled. */
+- __u32 pad;
++ __u32 flags;
+ };
+
+ /**
+@@ -175,6 +176,7 @@ enum drm_v3d_param {
+ DRM_V3D_PARAM_V3D_CORE0_IDENT2,
+ DRM_V3D_PARAM_SUPPORTS_TFU,
+ DRM_V3D_PARAM_SUPPORTS_CSD,
++ DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH,
+ };
+
+ struct drm_v3d_get_param {
+++ /dev/null
-From 75967d69ea58555d12a7d9058653a69210d2ba86 Mon Sep 17 00:00:00 2001
-Date: Wed, 18 Sep 2019 09:02:10 +0100
-Subject: [PATCH] dts: Add DTS for Pi 2B rev 1.2 with BCM2837 (#3235)
-
----
- arch/arm/boot/dts/Makefile | 1 +
- arch/arm/boot/dts/bcm2710-rpi-2-b.dts | 125 ++++++++++++++++++
- arch/arm64/boot/dts/broadcom/Makefile | 2 +
- .../boot/dts/broadcom/bcm2710-rpi-2-b.dts | 3 +
- 4 files changed, 131 insertions(+)
- create mode 100644 arch/arm/boot/dts/bcm2710-rpi-2-b.dts
- create mode 100644 arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts
-
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -7,6 +7,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
- bcm2708-rpi-zero.dtb \
- bcm2708-rpi-zero-w.dtb \
- bcm2709-rpi-2-b.dtb \
-+ bcm2710-rpi-2-b.dtb \
- bcm2710-rpi-3-b.dtb \
- bcm2711-rpi-4-b.dtb \
- bcm2710-rpi-3-b-plus.dtb \
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2710-rpi-2-b.dts
-@@ -0,0 +1,125 @@
-+/dts-v1/;
-+
-+#include "bcm2710.dtsi"
-+#include "bcm2709-rpi.dtsi"
-+#include "bcm283x-rpi-smsc9514.dtsi"
-+#include "bcm283x-rpi-csi1-2lane.dtsi"
-+
-+/ {
-+ compatible = "raspberrypi,2-model-b-rev2", "brcm,bcm2837";
-+ model = "Raspberry Pi 2 Model B rev 1.2";
-+};
-+
-+&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 */
-+ };
-+
-+ audio_pins: audio_pins {
-+ brcm,pins = <40 45>;
-+ brcm,function = <4>;
-+ };
-+};
-+
-+&uart0 {
-+ 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>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ 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: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 47 0>;
-+ };
-+
-+ pwr_led: pwr {
-+ label = "led1";
-+ linux,default-trigger = "input";
-+ gpios = <&gpio 35 0>;
-+ };
-+};
-+
-+&hdmi {
-+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+};
-+
-+&audio {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&audio_pins>;
-+};
-+
-+/ {
-+ __overrides__ {
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+
-+ pwr_led_gpio = <&pwr_led>,"gpios:4";
-+ pwr_led_activelow = <&pwr_led>,"gpios:8";
-+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
-+ };
-+};
---- a/arch/arm64/boot/dts/broadcom/Makefile
-+++ b/arch/arm64/boot/dts/broadcom/Makefile
-@@ -1,7 +1,9 @@
- # SPDX-License-Identifier: GPL-2.0
- dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rpi-3-b.dtb \
- bcm2837-rpi-3-b-plus.dtb
-+dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-2-b.dtb
- dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-3-b.dtb
-+dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-2-b.dtb
- dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b.dtb
- dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-4-b.dtb
- dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b-plus.dtb
---- /dev/null
-+++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts
-@@ -0,0 +1,3 @@
-+#define RPI364
-+
-+#include "../../../../arm/boot/dts/bcm2710-rpi-2-b.dts"
--- /dev/null
+From 9dd926d29051324d8621ca2a18bbdd568523ac93 Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Sep 2019 17:24:05 +0200
+Subject: [PATCH] staging: bcm2835-audio: Fix draining behavior
+ regression
+
+The PCM draining behavior got broken since the recent refactoring, and
+this turned out to be the incorrect expectation of the firmware
+behavior regarding "draining". While I expected the "drain" flag at
+the stop operation would do processing the queued samples, it seems
+rather dropping the samples.
+
+As a quick fix, just drop the SNDRV_PCM_INFO_DRAIN_TRIGGER flag, so
+that the driver uses the normal PCM draining procedure. Also, put
+some caution comment to the function for future readers not to fall
+into the same pitfall.
+
+Fixes: d7ca3a71545b ("staging: bcm2835-audio: Operate non-atomic PCM ops")
+BugLink: https://github.com/raspberrypi/linux/issues/2983
+---
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 4 ++--
+ drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c | 1 +
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -12,7 +12,7 @@
+ static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+- SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
++ SNDRV_PCM_INFO_SYNC_APPLPTR),
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
+ .rate_min = 8000,
+@@ -29,7 +29,7 @@ static const struct snd_pcm_hardware snd
+ static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+- SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
++ SNDRV_PCM_INFO_SYNC_APPLPTR),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -297,6 +297,7 @@ int bcm2835_audio_stop(struct bcm2835_al
+ VC_AUDIO_MSG_TYPE_STOP, false);
+ }
+
++/* FIXME: this doesn't seem working as expected for "draining" */
+ int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream)
+ {
+ struct vc_audio_msg m = {
--- /dev/null
+From c6be127c2f4d5f75c60d3778594093ff51593a6e Mon Sep 17 00:00:00 2001
+Date: Sun, 22 Sep 2019 21:51:29 +0100
+Subject: [PATCH] bcm2708_fb: Fix layout of struct
+ vc4_display_settings_t
+
+The display parameters returned by the VC4 firmware in response to the
+RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS tag do not match the
+layout of struct vc4_display_settings_t: the colour depth and row
+pitch are erroneously swapped in the kernel definition. This can
+trigger a kernel warning from pixel_to_pat(), such as:
+
+ pixel_to_pat(): unsupported pixelformat 7296
+
+Fix by adjusting the layout of struct vc4_display_settings_t to match
+the layout as used by the VC4 firmware.
+
+---
+ drivers/video/fbdev/bcm2708_fb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/video/fbdev/bcm2708_fb.c
++++ b/drivers/video/fbdev/bcm2708_fb.c
+@@ -89,8 +89,8 @@ struct vc4_display_settings_t {
+ u32 display_num;
+ u32 width;
+ u32 height;
+- u32 pitch;
+ u32 depth;
++ u32 pitch;
+ u32 virtual_width;
+ u32 virtual_height;
+ u32 virtual_width_offset;
+++ /dev/null
-From bc4661703d132ae1fb91d66641c64851eae44959 Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Sep 2019 08:45:24 +0200
-Subject: [PATCH] drm/v3d: clean caches at the end of render jobs on
- request from user space
-
-Extends the user space ioctl for CL submissions so it can include a request
-to flush the cache once the CL execution has completed. Fixes memory
-write violation messages reported by the kernel in workloads involving
-shader memory writes (SSBOs, shader images, scratch, etc) which sometimes
-also lead to GPU resets during Piglit and CTS workloads.
-
-v2: if v3d_job_init() fails we need to kfree() the job instead of
- v3d_job_put() it (Eric Anholt).
-
-v3 (Eric Anholt):
- - Drop _FLAG suffix from the new flag name.
- - Add a new param so userspace can tell whether cache flushing is
- implemented in the kernel.
-
----
- drivers/gpu/drm/v3d/v3d_drv.c | 3 ++
- drivers/gpu/drm/v3d/v3d_gem.c | 54 +++++++++++++++++++++++++++++------
- include/uapi/drm/v3d_drm.h | 6 ++--
- 3 files changed, 53 insertions(+), 10 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -117,6 +117,9 @@ static int v3d_get_param_ioctl(struct dr
- case DRM_V3D_PARAM_SUPPORTS_CSD:
- args->value = v3d_has_csd(v3d);
- return 0;
-+ case DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH:
-+ args->value = 1;
-+ return 0;
- default:
- DRM_DEBUG("Unknown parameter %d\n", args->param);
- return -EINVAL;
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -709,13 +709,16 @@ v3d_submit_cl_ioctl(struct drm_device *d
- struct drm_v3d_submit_cl *args = data;
- struct v3d_bin_job *bin = NULL;
- struct v3d_render_job *render;
-+ struct v3d_job *clean_job = NULL;
-+ struct v3d_job *last_job;
- struct ww_acquire_ctx acquire_ctx;
- int ret = 0;
-
- trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end);
-
-- if (args->pad != 0) {
-- DRM_INFO("pad must be zero: %d\n", args->pad);
-+ if (args->flags != 0 &&
-+ args->flags != DRM_V3D_SUBMIT_CL_FLUSH_CACHE) {
-+ DRM_INFO("invalid flags: %d\n", args->flags);
- return -EINVAL;
- }
-
-@@ -755,12 +758,31 @@ v3d_submit_cl_ioctl(struct drm_device *d
- bin->render = render;
- }
-
-- ret = v3d_lookup_bos(dev, file_priv, &render->base,
-+ if (args->flags & DRM_V3D_SUBMIT_CL_FLUSH_CACHE) {
-+ clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL);
-+ if (!clean_job) {
-+ ret = -ENOMEM;
-+ goto fail;
-+ }
-+
-+ ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0);
-+ if (ret) {
-+ kfree(clean_job);
-+ clean_job = NULL;
-+ goto fail;
-+ }
-+
-+ last_job = clean_job;
-+ } else {
-+ last_job = &render->base;
-+ }
-+
-+ ret = v3d_lookup_bos(dev, file_priv, last_job,
- args->bo_handles, args->bo_handle_count);
- if (ret)
- goto fail;
-
-- ret = v3d_lock_bo_reservations(&render->base, &acquire_ctx);
-+ ret = v3d_lock_bo_reservations(last_job, &acquire_ctx);
- if (ret)
- goto fail;
-
-@@ -772,33 +794,49 @@ v3d_submit_cl_ioctl(struct drm_device *d
-
- ret = v3d_add_dep(&render->base,
- dma_fence_get(bin->base.done_fence));
-+ if (ret)
-+ goto fail_unreserve;
- }
-
- ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER);
- if (ret)
- goto fail_unreserve;
-+
-+ if (clean_job) {
-+ ret = v3d_add_dep(clean_job,
-+ dma_fence_get(render->base.done_fence));
-+ if (ret)
-+ goto fail_unreserve;
-+ ret = v3d_push_job(v3d_priv, clean_job, V3D_CACHE_CLEAN);
-+ if (ret)
-+ goto fail_unreserve;
-+ }
- mutex_unlock(&v3d->sched_lock);
-
- v3d_attach_fences_and_unlock_reservation(file_priv,
-- &render->base,
-+ last_job,
- &acquire_ctx,
- args->out_sync,
-- render->base.done_fence);
-+ last_job->done_fence);
-
- if (bin)
- v3d_job_put(&bin->base);
- v3d_job_put(&render->base);
-+ if (clean_job)
-+ v3d_job_put(clean_job);
-
- return 0;
-
- fail_unreserve:
- mutex_unlock(&v3d->sched_lock);
-- v3d_unlock_bo_reservations(render->base.bo,
-- render->base.bo_count, &acquire_ctx);
-+ v3d_unlock_bo_reservations(last_job->bo,
-+ last_job->bo_count, &acquire_ctx);
- fail:
- if (bin)
- v3d_job_put(&bin->base);
- v3d_job_put(&render->base);
-+ if (clean_job)
-+ v3d_job_put(clean_job);
-
- return ret;
- }
---- a/include/uapi/drm/v3d_drm.h
-+++ b/include/uapi/drm/v3d_drm.h
-@@ -48,6 +48,8 @@ extern "C" {
- #define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu)
- #define DRM_IOCTL_V3D_SUBMIT_CSD DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CSD, struct drm_v3d_submit_csd)
-
-+#define DRM_V3D_SUBMIT_CL_FLUSH_CACHE 0x01
-+
- /**
- * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D
- * engine.
-@@ -106,8 +108,7 @@ struct drm_v3d_submit_cl {
- /* Number of BO handles passed in (size is that times 4). */
- __u32 bo_handle_count;
-
-- /* Pad, must be zero-filled. */
-- __u32 pad;
-+ __u32 flags;
- };
-
- /**
-@@ -175,6 +176,7 @@ enum drm_v3d_param {
- DRM_V3D_PARAM_V3D_CORE0_IDENT2,
- DRM_V3D_PARAM_SUPPORTS_TFU,
- DRM_V3D_PARAM_SUPPORTS_CSD,
-+ DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH,
- };
-
- struct drm_v3d_get_param {
--- /dev/null
+From b640129382a37105cf2577f251103e550381b797 Mon Sep 17 00:00:00 2001
+Date: Mon, 23 Sep 2019 18:56:37 +0200
+Subject: [PATCH] ARM: dts: bcm283x: Fix DTC warning for memory node
+
+commit f090e1bd7b05f17d35b6e2d0e946d8a8085d264f upstream.
+
+Compiling the bcm283x DTS with W=1 leads to the following warning:
+
+Warning (unit_address_vs_reg): /memory: node has a reg or ranges property,
+but no unit name
+
+Fix this by adding the unit address.
+
+---
+ arch/arm/boot/dts/bcm2835-rpi.dtsi | 2 +-
+ arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 2 +-
+ arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts | 2 +-
+ arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 2 +-
+ 4 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -1,7 +1,7 @@
+ #include <dt-bindings/power/raspberrypi-power.h>
+
+ / {
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0 0x10000000>;
+ };
+--- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
++++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
+@@ -10,7 +10,7 @@
+ compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
+ model = "Raspberry Pi 2 Model B";
+
+- memory {
++ memory@0 {
+ reg = <0 0x40000000>;
+ };
+
+--- a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
+@@ -14,7 +14,7 @@
+ stdout-path = "serial1:115200n8";
+ };
+
+- memory {
++ memory@0 {
+ reg = <0 0x40000000>;
+ };
+
+--- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
+@@ -15,7 +15,7 @@
+ stdout-path = "serial1:115200n8";
+ };
+
+- memory {
++ memory@0 {
+ reg = <0 0x40000000>;
+ };
+
+++ /dev/null
-From 9dd926d29051324d8621ca2a18bbdd568523ac93 Mon Sep 17 00:00:00 2001
-Date: Sat, 14 Sep 2019 17:24:05 +0200
-Subject: [PATCH] staging: bcm2835-audio: Fix draining behavior
- regression
-
-The PCM draining behavior got broken since the recent refactoring, and
-this turned out to be the incorrect expectation of the firmware
-behavior regarding "draining". While I expected the "drain" flag at
-the stop operation would do processing the queued samples, it seems
-rather dropping the samples.
-
-As a quick fix, just drop the SNDRV_PCM_INFO_DRAIN_TRIGGER flag, so
-that the driver uses the normal PCM draining procedure. Also, put
-some caution comment to the function for future readers not to fall
-into the same pitfall.
-
-Fixes: d7ca3a71545b ("staging: bcm2835-audio: Operate non-atomic PCM ops")
-BugLink: https://github.com/raspberrypi/linux/issues/2983
----
- drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c | 4 ++--
- drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c | 1 +
- 2 files changed, 3 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -12,7 +12,7 @@
- static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-- SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
-+ SNDRV_PCM_INFO_SYNC_APPLPTR),
- .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
- .rate_min = 8000,
-@@ -29,7 +29,7 @@ static const struct snd_pcm_hardware snd
- static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-- SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
-+ SNDRV_PCM_INFO_SYNC_APPLPTR),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -297,6 +297,7 @@ int bcm2835_audio_stop(struct bcm2835_al
- VC_AUDIO_MSG_TYPE_STOP, false);
- }
-
-+/* FIXME: this doesn't seem working as expected for "draining" */
- int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream)
- {
- struct vc_audio_msg m = {
--- /dev/null
+From 10524e83179ad016a379ea99364d6912812a9aa5 Mon Sep 17 00:00:00 2001
+Date: Mon, 23 Sep 2019 20:09:12 +0200
+Subject: [PATCH] ARM: dts: bcm27xx: Fix DTC warning for memory node
+
+Compiling the bcm27xx DTS with W=1 leads to the following warning:
+
+Warning (unit_address_vs_reg): /memory: node has a reg or ranges property,
+but no unit name
+
+Fix this by adding the unit address.
+
+---
+ arch/arm/boot/dts/bcm2708-rpi.dtsi | 2 +-
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 +-
+ arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
+@@ -3,7 +3,7 @@
+ #include "bcm2835-rpi.dtsi"
+
+ / {
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x0 0x0>;
+ };
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -8,7 +8,7 @@
+ compatible = "raspberrypi,4-model-b", "brcm,bcm2838";
+ model = "Raspberry Pi 4 Model B";
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0>;
+ };
+--- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
+@@ -13,7 +13,7 @@
+ stdout-path = "serial1:115200n8";
+ };
+
+- memory {
++ memory@0 {
+ reg = <0 0 0x40000000>;
+ };
+
+++ /dev/null
-From c6be127c2f4d5f75c60d3778594093ff51593a6e Mon Sep 17 00:00:00 2001
-Date: Sun, 22 Sep 2019 21:51:29 +0100
-Subject: [PATCH] bcm2708_fb: Fix layout of struct
- vc4_display_settings_t
-
-The display parameters returned by the VC4 firmware in response to the
-RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS tag do not match the
-layout of struct vc4_display_settings_t: the colour depth and row
-pitch are erroneously swapped in the kernel definition. This can
-trigger a kernel warning from pixel_to_pat(), such as:
-
- pixel_to_pat(): unsupported pixelformat 7296
-
-Fix by adjusting the layout of struct vc4_display_settings_t to match
-the layout as used by the VC4 firmware.
-
----
- drivers/video/fbdev/bcm2708_fb.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/video/fbdev/bcm2708_fb.c
-+++ b/drivers/video/fbdev/bcm2708_fb.c
-@@ -89,8 +89,8 @@ struct vc4_display_settings_t {
- u32 display_num;
- u32 width;
- u32 height;
-- u32 pitch;
- u32 depth;
-+ u32 pitch;
- u32 virtual_width;
- u32 virtual_height;
- u32 virtual_width_offset;
--- /dev/null
+From cce15c51f1afbb1aa9d5f7779c9f7c0a17b39701 Mon Sep 17 00:00:00 2001
+Date: Thu, 9 May 2019 19:03:00 +0200
+Subject: [PATCH] ARM: bcm283x: Enable DMA support for SPI controller
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Without this, the driver for the BCM2835 SPI controller uses interrupt
+mode instead of DMA mode, incurring a significant performance penalty.
+The Foundation's device tree has had these attributes for years, but for
+some reason they were never upstreamed.
+
+They were originally contributed by Noralf Trønnes and Martin Sperl:
+https://github.com/raspberrypi/linux/commit/25f3e064afc8
+https://github.com/raspberrypi/linux/commit/e0edb52b47e6
+
+The DREQ numbers 6 and 7 are documented in section 4.2.1.3 of:
+https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
+
+---
+ arch/arm/boot/dts/bcm283x.dtsi | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -403,6 +403,8 @@
+ reg = <0x7e204000 0x200>;
+ interrupts = <2 22>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ dmas = <&dma 6>, <&dma 7>;
++ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+++ /dev/null
-From b640129382a37105cf2577f251103e550381b797 Mon Sep 17 00:00:00 2001
-Date: Mon, 23 Sep 2019 18:56:37 +0200
-Subject: [PATCH] ARM: dts: bcm283x: Fix DTC warning for memory node
-
-commit f090e1bd7b05f17d35b6e2d0e946d8a8085d264f upstream.
-
-Compiling the bcm283x DTS with W=1 leads to the following warning:
-
-Warning (unit_address_vs_reg): /memory: node has a reg or ranges property,
-but no unit name
-
-Fix this by adding the unit address.
-
----
- arch/arm/boot/dts/bcm2835-rpi.dtsi | 2 +-
- arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 2 +-
- arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts | 2 +-
- arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 2 +-
- 4 files changed, 4 insertions(+), 4 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
-@@ -1,7 +1,7 @@
- #include <dt-bindings/power/raspberrypi-power.h>
-
- / {
-- memory {
-+ memory@0 {
- device_type = "memory";
- reg = <0 0x10000000>;
- };
---- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-+++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-@@ -10,7 +10,7 @@
- compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
- model = "Raspberry Pi 2 Model B";
-
-- memory {
-+ memory@0 {
- reg = <0 0x40000000>;
- };
-
---- a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
-@@ -14,7 +14,7 @@
- stdout-path = "serial1:115200n8";
- };
-
-- memory {
-+ memory@0 {
- reg = <0 0x40000000>;
- };
-
---- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
-+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
-@@ -15,7 +15,7 @@
- stdout-path = "serial1:115200n8";
- };
-
-- memory {
-+ memory@0 {
- reg = <0 0x40000000>;
- };
-
+++ /dev/null
-From 10524e83179ad016a379ea99364d6912812a9aa5 Mon Sep 17 00:00:00 2001
-Date: Mon, 23 Sep 2019 20:09:12 +0200
-Subject: [PATCH] ARM: dts: bcm27xx: Fix DTC warning for memory node
-
-Compiling the bcm27xx DTS with W=1 leads to the following warning:
-
-Warning (unit_address_vs_reg): /memory: node has a reg or ranges property,
-but no unit name
-
-Fix this by adding the unit address.
-
----
- arch/arm/boot/dts/bcm2708-rpi.dtsi | 2 +-
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 +-
- arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 2 +-
- 3 files changed, 3 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
-@@ -3,7 +3,7 @@
- #include "bcm2835-rpi.dtsi"
-
- / {
-- memory {
-+ memory@0 {
- device_type = "memory";
- reg = <0x0 0x0>;
- };
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -8,7 +8,7 @@
- compatible = "raspberrypi,4-model-b", "brcm,bcm2838";
- model = "Raspberry Pi 4 Model B";
-
-- memory {
-+ memory@0 {
- device_type = "memory";
- reg = <0x0 0x0 0x0>;
- };
---- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-@@ -13,7 +13,7 @@
- stdout-path = "serial1:115200n8";
- };
-
-- memory {
-+ memory@0 {
- reg = <0 0 0x40000000>;
- };
-
--- /dev/null
+From de002983174698762ecd3e42ab5a4b1bceb80af1 Mon Sep 17 00:00:00 2001
+Date: Sun, 30 Dec 2018 12:07:16 +0100
+Subject: [PATCH] ARM: dts: bcm2835-rpi: Drop unnecessary
+ #address-cells/#size-cells
+
+Compiling the bcm2835-rpi.dtsi with W=1 leads to the following warning:
+
+Warning (avoid_unnecessary_addr_size): /soc/firmware: unnecessary
+ #address-cells/#size-cells without "ranges" or child "reg" property
+
+Fix this by removing these unnecessary properties.
+
+---
+ arch/arm/boot/dts/bcm2835-rpi.dtsi | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -19,8 +19,6 @@
+ soc {
+ firmware: firmware {
+ compatible = "raspberrypi,bcm2835-firmware", "simple-bus";
+- #address-cells = <0>;
+- #size-cells = <0>;
+ mboxes = <&mailbox>;
+ };
+
+++ /dev/null
-From cce15c51f1afbb1aa9d5f7779c9f7c0a17b39701 Mon Sep 17 00:00:00 2001
-Date: Thu, 9 May 2019 19:03:00 +0200
-Subject: [PATCH] ARM: bcm283x: Enable DMA support for SPI controller
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Without this, the driver for the BCM2835 SPI controller uses interrupt
-mode instead of DMA mode, incurring a significant performance penalty.
-The Foundation's device tree has had these attributes for years, but for
-some reason they were never upstreamed.
-
-They were originally contributed by Noralf Trønnes and Martin Sperl:
-https://github.com/raspberrypi/linux/commit/25f3e064afc8
-https://github.com/raspberrypi/linux/commit/e0edb52b47e6
-
-The DREQ numbers 6 and 7 are documented in section 4.2.1.3 of:
-https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
-
----
- arch/arm/boot/dts/bcm283x.dtsi | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -403,6 +403,8 @@
- reg = <0x7e204000 0x200>;
- interrupts = <2 22>;
- clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ dmas = <&dma 6>, <&dma 7>;
-+ dma-names = "tx", "rx";
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
--- /dev/null
+From c31c8018e7cef83c827c913a10ac06b465813b22 Mon Sep 17 00:00:00 2001
+Date: Sat, 21 Sep 2019 15:29:33 +0200
+Subject: [PATCH] ARM: dts: bcm2708-rpi: Define the downstream MMC
+ interfaces at one place
+
+In order to keep downstream definition of the MMC interfaces separate
+and independent from upstream changes, add them to bcm2708-rpi.dtsi.
+
+---
+ arch/arm/boot/dts/bcm2708-rpi.dtsi | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
+@@ -125,13 +125,23 @@
+ firmware = <&firmware>;
+ };
+
++&sdhci {
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_gpio48>;
++ bus-width = <4>;
++};
++
+ sdhost_pins: &sdhost_gpio48 {
+ /* Add alias */
+ };
+
+ &sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_gpio48>;
++ bus-width = <4>;
+ brcm,overclock-50 = <0>;
+ brcm,pio-limit = <1>;
++ status = "okay";
+ };
+
+ &cpu_thermal {
+++ /dev/null
-From de002983174698762ecd3e42ab5a4b1bceb80af1 Mon Sep 17 00:00:00 2001
-Date: Sun, 30 Dec 2018 12:07:16 +0100
-Subject: [PATCH] ARM: dts: bcm2835-rpi: Drop unnecessary
- #address-cells/#size-cells
-
-Compiling the bcm2835-rpi.dtsi with W=1 leads to the following warning:
-
-Warning (avoid_unnecessary_addr_size): /soc/firmware: unnecessary
- #address-cells/#size-cells without "ranges" or child "reg" property
-
-Fix this by removing these unnecessary properties.
-
----
- arch/arm/boot/dts/bcm2835-rpi.dtsi | 2 --
- 1 file changed, 2 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
-@@ -19,8 +19,6 @@
- soc {
- firmware: firmware {
- compatible = "raspberrypi,bcm2835-firmware", "simple-bus";
-- #address-cells = <0>;
-- #size-cells = <0>;
- mboxes = <&mailbox>;
- };
-
--- /dev/null
+From a1905aed89ee45f6662f03b77dc604ff1a169671 Mon Sep 17 00:00:00 2001
+Date: Tue, 17 Sep 2019 19:16:17 +0200
+Subject: [PATCH] ARM: dts: bcm283x: Define MMC interfaces at board
+ level
+
+commit e7774049ff255c8ba72bcee9c7ab307a95e8d7bc upstream.
+
+Starting with RPi 4 this is the first board, which doesn't use sdhost
+as default SD interface. So the MMC interfaces should be defined finally at
+board level. Since all boards using sdhci already does this, we can drop the
+pinctrl part from bcm2835-rpi.dtsi.
+
+---
+ arch/arm/boot/dts/bcm2835-rpi-a-plus.dts | 7 +++++++
+ arch/arm/boot/dts/bcm2835-rpi-a.dts | 7 +++++++
+ arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 7 +++++++
+ arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts | 7 +++++++
+ arch/arm/boot/dts/bcm2835-rpi-b.dts | 7 +++++++
+ arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts | 7 +++++++
+ arch/arm/boot/dts/bcm2835-rpi-zero-w.dts | 7 +++++++
+ arch/arm/boot/dts/bcm2835-rpi-zero.dts | 7 +++++++
+ arch/arm/boot/dts/bcm2835-rpi.dtsi | 13 -------------
+ arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 7 +++++++
+ 10 files changed, 63 insertions(+), 13 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
+@@ -108,6 +108,13 @@
+ status = "okay";
+ };
+
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_gpio48>;
++ bus-width = <4>;
++ status = "okay";
++};
++
+ &uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_gpio14>;
+--- a/arch/arm/boot/dts/bcm2835-rpi-a.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts
+@@ -103,6 +103,13 @@
+ status = "okay";
+ };
+
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_gpio48>;
++ bus-width = <4>;
++ status = "okay";
++};
++
+ &uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_gpio14>;
+--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
+@@ -110,6 +110,13 @@
+ status = "okay";
+ };
+
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_gpio48>;
++ bus-width = <4>;
++ status = "okay";
++};
++
+ &uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_gpio14>;
+--- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
+@@ -103,6 +103,13 @@
+ status = "okay";
+ };
+
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_gpio48>;
++ bus-width = <4>;
++ status = "okay";
++};
++
+ &uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_gpio14>;
+--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
+@@ -98,6 +98,13 @@
+ status = "okay";
+ };
+
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_gpio48>;
++ bus-width = <4>;
++ status = "okay";
++};
++
+ &uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_gpio14>;
+--- a/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
+@@ -81,6 +81,13 @@
+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
+ };
+
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_gpio48>;
++ bus-width = <4>;
++ status = "okay";
++};
++
+ &uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_gpio14>;
+--- a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
+@@ -129,6 +129,13 @@
+ };
+ };
+
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_gpio48>;
++ bus-width = <4>;
++ status = "okay";
++};
++
+ &uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_gpio32 &uart0_ctsrts_gpio30>;
+--- a/arch/arm/boot/dts/bcm2835-rpi-zero.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts
+@@ -105,6 +105,13 @@
+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
+ };
+
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_gpio48>;
++ bus-width = <4>;
++ status = "okay";
++};
++
+ &uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_gpio14>;
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -84,19 +84,6 @@
+ status = "okay";
+ };
+
+-&sdhci {
+- pinctrl-names = "default";
+- pinctrl-0 = <&emmc_gpio48>;
+- bus-width = <4>;
+-};
+-
+-&sdhost {
+- pinctrl-names = "default";
+- pinctrl-0 = <&sdhost_gpio48>;
+- status = "okay";
+- bus-width = <4>;
+-};
+-
+ &usb {
+ power-domains = <&power RPI_POWER_DOMAIN_USB>;
+ };
+--- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
++++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
+@@ -48,6 +48,13 @@
+ status = "okay";
+ };
+
++&sdhost {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdhost_gpio48>;
++ bus-width = <4>;
++ status = "okay";
++};
++
+ &uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_gpio14>;
+++ /dev/null
-From c31c8018e7cef83c827c913a10ac06b465813b22 Mon Sep 17 00:00:00 2001
-Date: Sat, 21 Sep 2019 15:29:33 +0200
-Subject: [PATCH] ARM: dts: bcm2708-rpi: Define the downstream MMC
- interfaces at one place
-
-In order to keep downstream definition of the MMC interfaces separate
-and independent from upstream changes, add them to bcm2708-rpi.dtsi.
-
----
- arch/arm/boot/dts/bcm2708-rpi.dtsi | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
-@@ -125,13 +125,23 @@
- firmware = <&firmware>;
- };
-
-+&sdhci {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&emmc_gpio48>;
-+ bus-width = <4>;
-+};
-+
- sdhost_pins: &sdhost_gpio48 {
- /* Add alias */
- };
-
- &sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_gpio48>;
-+ bus-width = <4>;
- brcm,overclock-50 = <0>;
- brcm,pio-limit = <1>;
-+ status = "okay";
- };
-
- &cpu_thermal {
--- /dev/null
+From c60d699be1eb26a14157cfa5b1ac0cf8afce0dcb Mon Sep 17 00:00:00 2001
+Date: Mon, 23 Sep 2019 19:41:33 +0200
+Subject: [PATCH] ARM: dts: bcm2835-rpi-zero-w: Fix bus-width of sdhci
+
+The commit e7774049ff25 ("ARM: dts: bcm283x: Define MMC interfaces at
+board level") accidently dropped the bus width for the sdhci on the
+RPi Zero W, because the board file was relying on the defaults
+from bcm2835-rpi.dtsi. So fix this performance regression by adding
+the bus width to the board file.
+
+Fixes: e7774049ff25 ("ARM: dts: bcm283x: Define MMC interfaces at board level")
+---
+ arch/arm/boot/dts/bcm2835-rpi-zero-w.dts | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
+@@ -119,6 +119,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-0 = <&emmc_gpio34 &gpclk2_gpio43>;
++ bus-width = <4>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ non-removable;
+ status = "okay";
--- /dev/null
+From 51908b138907d25df02687c514d59373b2a32f18 Mon Sep 17 00:00:00 2001
+Date: Sat, 21 Sep 2019 15:55:19 +0200
+Subject: [PATCH] ARM: dts: bcm2708-rpi: Define the downstream HDMI
+ power at one place
+
+In order to keep downstream definition of the HDMI power domain separate
+and independent from upstream changes, add them to bcm2708-rpi.dtsi.
+
+---
+ arch/arm/boot/dts/bcm2708-rpi.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
+@@ -102,6 +102,7 @@
+ };
+
+ &hdmi {
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
+ status = "disabled";
+ };
+
+++ /dev/null
-From a1905aed89ee45f6662f03b77dc604ff1a169671 Mon Sep 17 00:00:00 2001
-Date: Tue, 17 Sep 2019 19:16:17 +0200
-Subject: [PATCH] ARM: dts: bcm283x: Define MMC interfaces at board
- level
-
-commit e7774049ff255c8ba72bcee9c7ab307a95e8d7bc upstream.
-
-Starting with RPi 4 this is the first board, which doesn't use sdhost
-as default SD interface. So the MMC interfaces should be defined finally at
-board level. Since all boards using sdhci already does this, we can drop the
-pinctrl part from bcm2835-rpi.dtsi.
-
----
- arch/arm/boot/dts/bcm2835-rpi-a-plus.dts | 7 +++++++
- arch/arm/boot/dts/bcm2835-rpi-a.dts | 7 +++++++
- arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 7 +++++++
- arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts | 7 +++++++
- arch/arm/boot/dts/bcm2835-rpi-b.dts | 7 +++++++
- arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts | 7 +++++++
- arch/arm/boot/dts/bcm2835-rpi-zero-w.dts | 7 +++++++
- arch/arm/boot/dts/bcm2835-rpi-zero.dts | 7 +++++++
- arch/arm/boot/dts/bcm2835-rpi.dtsi | 13 -------------
- arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 7 +++++++
- 10 files changed, 63 insertions(+), 13 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
-@@ -108,6 +108,13 @@
- status = "okay";
- };
-
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_gpio48>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
- &uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_gpio14>;
---- a/arch/arm/boot/dts/bcm2835-rpi-a.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts
-@@ -103,6 +103,13 @@
- status = "okay";
- };
-
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_gpio48>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
- &uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_gpio14>;
---- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
-@@ -110,6 +110,13 @@
- status = "okay";
- };
-
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_gpio48>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
- &uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_gpio14>;
---- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
-@@ -103,6 +103,13 @@
- status = "okay";
- };
-
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_gpio48>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
- &uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_gpio14>;
---- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
-@@ -98,6 +98,13 @@
- status = "okay";
- };
-
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_gpio48>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
- &uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_gpio14>;
---- a/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
-@@ -81,6 +81,13 @@
- hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
- };
-
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_gpio48>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
- &uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_gpio14>;
---- a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
-@@ -129,6 +129,13 @@
- };
- };
-
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_gpio48>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
- &uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_gpio32 &uart0_ctsrts_gpio30>;
---- a/arch/arm/boot/dts/bcm2835-rpi-zero.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts
-@@ -105,6 +105,13 @@
- hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
- };
-
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_gpio48>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
- &uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_gpio14>;
---- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
-@@ -84,19 +84,6 @@
- status = "okay";
- };
-
--&sdhci {
-- pinctrl-names = "default";
-- pinctrl-0 = <&emmc_gpio48>;
-- bus-width = <4>;
--};
--
--&sdhost {
-- pinctrl-names = "default";
-- pinctrl-0 = <&sdhost_gpio48>;
-- status = "okay";
-- bus-width = <4>;
--};
--
- &usb {
- power-domains = <&power RPI_POWER_DOMAIN_USB>;
- };
---- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-+++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-@@ -48,6 +48,13 @@
- status = "okay";
- };
-
-+&sdhost {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdhost_gpio48>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
- &uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_gpio14>;
+++ /dev/null
-From c60d699be1eb26a14157cfa5b1ac0cf8afce0dcb Mon Sep 17 00:00:00 2001
-Date: Mon, 23 Sep 2019 19:41:33 +0200
-Subject: [PATCH] ARM: dts: bcm2835-rpi-zero-w: Fix bus-width of sdhci
-
-The commit e7774049ff25 ("ARM: dts: bcm283x: Define MMC interfaces at
-board level") accidently dropped the bus width for the sdhci on the
-RPi Zero W, because the board file was relying on the defaults
-from bcm2835-rpi.dtsi. So fix this performance regression by adding
-the bus width to the board file.
-
-Fixes: e7774049ff25 ("ARM: dts: bcm283x: Define MMC interfaces at board level")
----
- arch/arm/boot/dts/bcm2835-rpi-zero-w.dts | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
-@@ -119,6 +119,7 @@
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-0 = <&emmc_gpio34 &gpclk2_gpio43>;
-+ bus-width = <4>;
- mmc-pwrseq = <&wifi_pwrseq>;
- non-removable;
- status = "okay";
--- /dev/null
+From a3cbeaaee57b7bda4e921bb2cff649fb56c0292d Mon Sep 17 00:00:00 2001
+Date: Tue, 17 Sep 2019 19:31:19 +0200
+Subject: [PATCH] ARM: dts: bcm283x: Enable HDMI at board level
+
+commit 60c833d5664e1b3f71c4471233469790adf505ca upstream.
+
+There might be headless setups of the Compute Module without HDMI,
+so better enable HDMI at board level. Btw this allows moving HDMI
+base definition into upcoming bcm2835-common.dtsi.
+
+---
+ arch/arm/boot/dts/bcm2835-rpi-a-plus.dts | 2 ++
+ arch/arm/boot/dts/bcm2835-rpi-a.dts | 2 ++
+ arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 2 ++
+ arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts | 2 ++
+ arch/arm/boot/dts/bcm2835-rpi-b.dts | 2 ++
+ arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts | 2 ++
+ arch/arm/boot/dts/bcm2835-rpi-zero-w.dts | 2 ++
+ arch/arm/boot/dts/bcm2835-rpi-zero.dts | 2 ++
+ arch/arm/boot/dts/bcm2835-rpi.dtsi | 5 -----
+ arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 2 ++
+ arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts | 2 ++
+ arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 2 ++
+ 12 files changed, 22 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
+@@ -100,6 +100,8 @@
+
+ &hdmi {
+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
+ };
+
+ &pwm {
+--- a/arch/arm/boot/dts/bcm2835-rpi-a.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts
+@@ -95,6 +95,8 @@
+
+ &hdmi {
+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
+ };
+
+ &pwm {
+--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
+@@ -102,6 +102,8 @@
+
+ &hdmi {
+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
+ };
+
+ &pwm {
+--- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
+@@ -95,6 +95,8 @@
+
+ &hdmi {
+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
+ };
+
+ &pwm {
+--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
+@@ -90,6 +90,8 @@
+
+ &hdmi {
+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
+ };
+
+ &pwm {
+--- a/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
+@@ -79,6 +79,8 @@
+
+ &hdmi {
+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
+ };
+
+ &sdhost {
+--- a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
+@@ -113,6 +113,8 @@
+
+ &hdmi {
+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
+ };
+
+ &sdhci {
+--- a/arch/arm/boot/dts/bcm2835-rpi-zero.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts
+@@ -103,6 +103,8 @@
+
+ &hdmi {
+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
+ };
+
+ &sdhost {
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -92,11 +92,6 @@
+ power-domains = <&power RPI_POWER_DOMAIN_V3D>;
+ };
+
+-&hdmi {
+- power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
+- status = "okay";
+-};
+-
+ &vec {
+ power-domains = <&power RPI_POWER_DOMAIN_VEC>;
+ status = "okay";
+--- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
++++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
+@@ -40,6 +40,8 @@
+
+ &hdmi {
+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
+ };
+
+ &pwm {
+--- a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
+@@ -54,6 +54,8 @@
+
+ &hdmi {
+ hpd-gpios = <&gpio 28 GPIO_ACTIVE_LOW>;
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
+ };
+
+ &pwm {
+--- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
+@@ -56,6 +56,8 @@
+
+ &hdmi {
+ hpd-gpios = <&expgpio 4 GPIO_ACTIVE_LOW>;
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "okay";
+ };
+
+ /* uart0 communicates with the BT module */
+++ /dev/null
-From 51908b138907d25df02687c514d59373b2a32f18 Mon Sep 17 00:00:00 2001
-Date: Sat, 21 Sep 2019 15:55:19 +0200
-Subject: [PATCH] ARM: dts: bcm2708-rpi: Define the downstream HDMI
- power at one place
-
-In order to keep downstream definition of the HDMI power domain separate
-and independent from upstream changes, add them to bcm2708-rpi.dtsi.
-
----
- arch/arm/boot/dts/bcm2708-rpi.dtsi | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
-@@ -102,6 +102,7 @@
- };
-
- &hdmi {
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
- status = "disabled";
- };
-
--- /dev/null
+From 125afc5cf080b29e9114d89f6052fa4a936a3f19 Mon Sep 17 00:00:00 2001
+Date: Thu, 19 Sep 2019 20:12:15 +0200
+Subject: [PATCH] clk: bcm2835: Introduce SoC specific clock
+ registration
+
+commit ee0a5a9013b2b2502571a763c3093d400d18191f upstream.
+
+In order to support SoC specific clocks (e.g. emmc2 for BCM2711), we
+extend the description with a SoC support flag. This approach avoids long
+and mostly redundant lists of clock IDs. Since PLLH is specific to
+BCM2835, we register only rest of the clocks as common to all SoC.
+
+---
+ drivers/clk/bcm/clk-bcm2835.c | 115 +++++++++++++++++++++++++++++-----
+ 1 file changed, 98 insertions(+), 17 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -40,7 +40,7 @@
+ #include <linux/debugfs.h>
+ #include <linux/delay.h>
+ #include <linux/module.h>
+-#include <linux/of.h>
++#include <linux/of_device.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+ #include <dt-bindings/clock/bcm2835.h>
+@@ -301,6 +301,9 @@
+
+ #define VCMSG_ID_CORE_CLOCK 4
+
++#define SOC_BCM2835 BIT(0)
++#define SOC_ALL (SOC_BCM2835)
++
+ /*
+ * Names of clocks used within the driver that need to be replaced
+ * with an external parent's name. This array is in the order that
+@@ -333,6 +336,10 @@ struct bcm2835_cprman {
+ struct clk_hw_onecell_data onecell;
+ };
+
++struct cprman_plat_data {
++ unsigned int soc;
++};
++
+ static inline void cprman_write(struct bcm2835_cprman *cprman, u32 reg, u32 val)
+ {
+ writel(CM_PASSWORD | val, cprman->regs + reg);
+@@ -1528,22 +1535,28 @@ typedef struct clk_hw *(*bcm2835_clk_reg
+ const void *data);
+ struct bcm2835_clk_desc {
+ bcm2835_clk_register clk_register;
++ unsigned int supported;
+ const void *data;
+ };
+
+ /* assignment helper macros for different clock types */
+-#define _REGISTER(f, ...) { .clk_register = (bcm2835_clk_register)f, \
+- .data = __VA_ARGS__ }
+-#define REGISTER_PLL(...) _REGISTER(&bcm2835_register_pll, \
++#define _REGISTER(f, s, ...) { .clk_register = (bcm2835_clk_register)f, \
++ .supported = s, \
++ .data = __VA_ARGS__ }
++#define REGISTER_PLL(s, ...) _REGISTER(&bcm2835_register_pll, \
++ s, \
+ &(struct bcm2835_pll_data) \
+ {__VA_ARGS__})
+-#define REGISTER_PLL_DIV(...) _REGISTER(&bcm2835_register_pll_divider, \
+- &(struct bcm2835_pll_divider_data) \
+- {__VA_ARGS__})
+-#define REGISTER_CLK(...) _REGISTER(&bcm2835_register_clock, \
++#define REGISTER_PLL_DIV(s, ...) _REGISTER(&bcm2835_register_pll_divider, \
++ s, \
++ &(struct bcm2835_pll_divider_data) \
++ {__VA_ARGS__})
++#define REGISTER_CLK(s, ...) _REGISTER(&bcm2835_register_clock, \
++ s, \
+ &(struct bcm2835_clock_data) \
+ {__VA_ARGS__})
+-#define REGISTER_GATE(...) _REGISTER(&bcm2835_register_gate, \
++#define REGISTER_GATE(s, ...) _REGISTER(&bcm2835_register_gate, \
++ s, \
+ &(struct bcm2835_gate_data) \
+ {__VA_ARGS__})
+
+@@ -1557,7 +1570,8 @@ static const char *const bcm2835_clock_o
+ "testdebug1"
+ };
+
+-#define REGISTER_OSC_CLK(...) REGISTER_CLK( \
++#define REGISTER_OSC_CLK(s, ...) REGISTER_CLK( \
++ s, \
+ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), \
+ .parents = bcm2835_clock_osc_parents, \
+ __VA_ARGS__)
+@@ -1574,7 +1588,8 @@ static const char *const bcm2835_clock_p
+ "pllh_aux",
+ };
+
+-#define REGISTER_PER_CLK(...) REGISTER_CLK( \
++#define REGISTER_PER_CLK(s, ...) REGISTER_CLK( \
++ s, \
+ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), \
+ .parents = bcm2835_clock_per_parents, \
+ __VA_ARGS__)
+@@ -1599,7 +1614,8 @@ static const char *const bcm2835_pcm_per
+ "-",
+ };
+
+-#define REGISTER_PCM_CLK(...) REGISTER_CLK( \
++#define REGISTER_PCM_CLK(s, ...) REGISTER_CLK( \
++ s, \
+ .num_mux_parents = ARRAY_SIZE(bcm2835_pcm_per_parents), \
+ .parents = bcm2835_pcm_per_parents, \
+ __VA_ARGS__)
+@@ -1618,7 +1634,8 @@ static const char *const bcm2835_clock_v
+ "pllc_core2",
+ };
+
+-#define REGISTER_VPU_CLK(...) REGISTER_CLK( \
++#define REGISTER_VPU_CLK(s, ...) REGISTER_CLK( \
++ s, \
+ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), \
+ .parents = bcm2835_clock_vpu_parents, \
+ __VA_ARGS__)
+@@ -1654,12 +1671,14 @@ static const char *const bcm2835_clock_d
+ "dsi1_byte_inv",
+ };
+
+-#define REGISTER_DSI0_CLK(...) REGISTER_CLK( \
++#define REGISTER_DSI0_CLK(s, ...) REGISTER_CLK( \
++ s, \
+ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi0_parents), \
+ .parents = bcm2835_clock_dsi0_parents, \
+ __VA_ARGS__)
+
+-#define REGISTER_DSI1_CLK(...) REGISTER_CLK( \
++#define REGISTER_DSI1_CLK(s, ...) REGISTER_CLK( \
++ s, \
+ .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi1_parents), \
+ .parents = bcm2835_clock_dsi1_parents, \
+ __VA_ARGS__)
+@@ -1679,6 +1698,7 @@ static const struct bcm2835_clk_desc clk
+ * AUDIO domain is on.
+ */
+ [BCM2835_PLLA] = REGISTER_PLL(
++ SOC_ALL,
+ .name = "plla",
+ .cm_ctrl_reg = CM_PLLA,
+ .a2w_ctrl_reg = A2W_PLLA_CTRL,
+@@ -1693,6 +1713,7 @@ static const struct bcm2835_clk_desc clk
+ .max_rate = 2400000000u,
+ .max_fb_rate = BCM2835_MAX_FB_RATE),
+ [BCM2835_PLLA_CORE] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "plla_core",
+ .source_pll = "plla",
+ .cm_reg = CM_PLLA,
+@@ -1702,6 +1723,7 @@ static const struct bcm2835_clk_desc clk
+ .fixed_divider = 1,
+ .flags = CLK_SET_RATE_PARENT),
+ [BCM2835_PLLA_PER] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "plla_per",
+ .source_pll = "plla",
+ .cm_reg = CM_PLLA,
+@@ -1711,6 +1733,7 @@ static const struct bcm2835_clk_desc clk
+ .fixed_divider = 1,
+ .flags = CLK_SET_RATE_PARENT),
+ [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "plla_dsi0",
+ .source_pll = "plla",
+ .cm_reg = CM_PLLA,
+@@ -1719,6 +1742,7 @@ static const struct bcm2835_clk_desc clk
+ .hold_mask = CM_PLLA_HOLDDSI0,
+ .fixed_divider = 1),
+ [BCM2835_PLLA_CCP2] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "plla_ccp2",
+ .source_pll = "plla",
+ .cm_reg = CM_PLLA,
+@@ -1730,6 +1754,7 @@ static const struct bcm2835_clk_desc clk
+
+ /* PLLB is used for the ARM's clock. */
+ [BCM2835_PLLB] = REGISTER_PLL(
++ SOC_ALL,
+ .name = "pllb",
+ .cm_ctrl_reg = CM_PLLB,
+ .a2w_ctrl_reg = A2W_PLLB_CTRL,
+@@ -1744,6 +1769,7 @@ static const struct bcm2835_clk_desc clk
+ .max_rate = 3000000000u,
+ .max_fb_rate = BCM2835_MAX_FB_RATE),
+ [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "pllb_arm",
+ .source_pll = "pllb",
+ .cm_reg = CM_PLLB,
+@@ -1760,6 +1786,7 @@ static const struct bcm2835_clk_desc clk
+ * AUDIO domain is on.
+ */
+ [BCM2835_PLLC] = REGISTER_PLL(
++ SOC_ALL,
+ .name = "pllc",
+ .cm_ctrl_reg = CM_PLLC,
+ .a2w_ctrl_reg = A2W_PLLC_CTRL,
+@@ -1774,6 +1801,7 @@ static const struct bcm2835_clk_desc clk
+ .max_rate = 3000000000u,
+ .max_fb_rate = BCM2835_MAX_FB_RATE),
+ [BCM2835_PLLC_CORE0] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "pllc_core0",
+ .source_pll = "pllc",
+ .cm_reg = CM_PLLC,
+@@ -1783,6 +1811,7 @@ static const struct bcm2835_clk_desc clk
+ .fixed_divider = 1,
+ .flags = CLK_SET_RATE_PARENT),
+ [BCM2835_PLLC_CORE1] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "pllc_core1",
+ .source_pll = "pllc",
+ .cm_reg = CM_PLLC,
+@@ -1792,6 +1821,7 @@ static const struct bcm2835_clk_desc clk
+ .fixed_divider = 1,
+ .flags = CLK_SET_RATE_PARENT),
+ [BCM2835_PLLC_CORE2] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "pllc_core2",
+ .source_pll = "pllc",
+ .cm_reg = CM_PLLC,
+@@ -1801,6 +1831,7 @@ static const struct bcm2835_clk_desc clk
+ .fixed_divider = 1,
+ .flags = CLK_SET_RATE_PARENT),
+ [BCM2835_PLLC_PER] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "pllc_per",
+ .source_pll = "pllc",
+ .cm_reg = CM_PLLC,
+@@ -1817,6 +1848,7 @@ static const struct bcm2835_clk_desc clk
+ * AUDIO domain is on.
+ */
+ [BCM2835_PLLD] = REGISTER_PLL(
++ SOC_ALL,
+ .name = "plld",
+ .cm_ctrl_reg = CM_PLLD,
+ .a2w_ctrl_reg = A2W_PLLD_CTRL,
+@@ -1831,6 +1863,7 @@ static const struct bcm2835_clk_desc clk
+ .max_rate = 2400000000u,
+ .max_fb_rate = BCM2835_MAX_FB_RATE),
+ [BCM2835_PLLD_CORE] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "plld_core",
+ .source_pll = "plld",
+ .cm_reg = CM_PLLD,
+@@ -1840,6 +1873,7 @@ static const struct bcm2835_clk_desc clk
+ .fixed_divider = 1,
+ .flags = CLK_SET_RATE_PARENT),
+ [BCM2835_PLLD_PER] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "plld_per",
+ .source_pll = "plld",
+ .cm_reg = CM_PLLD,
+@@ -1849,6 +1883,7 @@ static const struct bcm2835_clk_desc clk
+ .fixed_divider = 1,
+ .flags = CLK_SET_RATE_PARENT),
+ [BCM2835_PLLD_DSI0] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "plld_dsi0",
+ .source_pll = "plld",
+ .cm_reg = CM_PLLD,
+@@ -1857,6 +1892,7 @@ static const struct bcm2835_clk_desc clk
+ .hold_mask = CM_PLLD_HOLDDSI0,
+ .fixed_divider = 1),
+ [BCM2835_PLLD_DSI1] = REGISTER_PLL_DIV(
++ SOC_ALL,
+ .name = "plld_dsi1",
+ .source_pll = "plld",
+ .cm_reg = CM_PLLD,
+@@ -1872,6 +1908,7 @@ static const struct bcm2835_clk_desc clk
+ * It is in the HDMI power domain.
+ */
+ [BCM2835_PLLH] = REGISTER_PLL(
++ SOC_BCM2835,
+ "pllh",
+ .cm_ctrl_reg = CM_PLLH,
+ .a2w_ctrl_reg = A2W_PLLH_CTRL,
+@@ -1886,6 +1923,7 @@ static const struct bcm2835_clk_desc clk
+ .max_rate = 3000000000u,
+ .max_fb_rate = BCM2835_MAX_FB_RATE),
+ [BCM2835_PLLH_RCAL] = REGISTER_PLL_DIV(
++ SOC_BCM2835,
+ .name = "pllh_rcal",
+ .source_pll = "pllh",
+ .cm_reg = CM_PLLH,
+@@ -1895,6 +1933,7 @@ static const struct bcm2835_clk_desc clk
+ .fixed_divider = 10,
+ .flags = CLK_SET_RATE_PARENT),
+ [BCM2835_PLLH_AUX] = REGISTER_PLL_DIV(
++ SOC_BCM2835,
+ .name = "pllh_aux",
+ .source_pll = "pllh",
+ .cm_reg = CM_PLLH,
+@@ -1904,6 +1943,7 @@ static const struct bcm2835_clk_desc clk
+ .fixed_divider = 1,
+ .flags = CLK_SET_RATE_PARENT),
+ [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV(
++ SOC_BCM2835,
+ .name = "pllh_pix",
+ .source_pll = "pllh",
+ .cm_reg = CM_PLLH,
+@@ -1919,6 +1959,7 @@ static const struct bcm2835_clk_desc clk
+
+ /* One Time Programmable Memory clock. Maximum 10Mhz. */
+ [BCM2835_CLOCK_OTP] = REGISTER_OSC_CLK(
++ SOC_ALL,
+ .name = "otp",
+ .ctl_reg = CM_OTPCTL,
+ .div_reg = CM_OTPDIV,
+@@ -1930,6 +1971,7 @@ static const struct bcm2835_clk_desc clk
+ * bythe watchdog timer and the camera pulse generator.
+ */
+ [BCM2835_CLOCK_TIMER] = REGISTER_OSC_CLK(
++ SOC_ALL,
+ .name = "timer",
+ .ctl_reg = CM_TIMERCTL,
+ .div_reg = CM_TIMERDIV,
+@@ -1940,12 +1982,14 @@ static const struct bcm2835_clk_desc clk
+ * Generally run at 2Mhz, max 5Mhz.
+ */
+ [BCM2835_CLOCK_TSENS] = REGISTER_OSC_CLK(
++ SOC_ALL,
+ .name = "tsens",
+ .ctl_reg = CM_TSENSCTL,
+ .div_reg = CM_TSENSDIV,
+ .int_bits = 5,
+ .frac_bits = 0),
+ [BCM2835_CLOCK_TEC] = REGISTER_OSC_CLK(
++ SOC_ALL,
+ .name = "tec",
+ .ctl_reg = CM_TECCTL,
+ .div_reg = CM_TECDIV,
+@@ -1954,6 +1998,7 @@ static const struct bcm2835_clk_desc clk
+
+ /* clocks with vpu parent mux */
+ [BCM2835_CLOCK_H264] = REGISTER_VPU_CLK(
++ SOC_ALL,
+ .name = "h264",
+ .ctl_reg = CM_H264CTL,
+ .div_reg = CM_H264DIV,
+@@ -1961,6 +2006,7 @@ static const struct bcm2835_clk_desc clk
+ .frac_bits = 8,
+ .tcnt_mux = 1),
+ [BCM2835_CLOCK_ISP] = REGISTER_VPU_CLK(
++ SOC_ALL,
+ .name = "isp",
+ .ctl_reg = CM_ISPCTL,
+ .div_reg = CM_ISPDIV,
+@@ -1973,6 +2019,7 @@ static const struct bcm2835_clk_desc clk
+ * in the SDRAM controller can't be used.
+ */
+ [BCM2835_CLOCK_SDRAM] = REGISTER_VPU_CLK(
++ SOC_ALL,
+ .name = "sdram",
+ .ctl_reg = CM_SDCCTL,
+ .div_reg = CM_SDCDIV,
+@@ -1980,6 +2027,7 @@ static const struct bcm2835_clk_desc clk
+ .frac_bits = 0,
+ .tcnt_mux = 3),
+ [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK(
++ SOC_ALL,
+ .name = "v3d",
+ .ctl_reg = CM_V3DCTL,
+ .div_reg = CM_V3DDIV,
+@@ -1993,6 +2041,7 @@ static const struct bcm2835_clk_desc clk
+ * in various hardware documentation.
+ */
+ [BCM2835_CLOCK_VPU] = REGISTER_VPU_CLK(
++ SOC_ALL,
+ .name = "vpu",
+ .ctl_reg = CM_VPUCTL,
+ .div_reg = CM_VPUDIV,
+@@ -2004,6 +2053,7 @@ static const struct bcm2835_clk_desc clk
+
+ /* clocks with per parent mux */
+ [BCM2835_CLOCK_AVEO] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "aveo",
+ .ctl_reg = CM_AVEOCTL,
+ .div_reg = CM_AVEODIV,
+@@ -2011,6 +2061,7 @@ static const struct bcm2835_clk_desc clk
+ .frac_bits = 0,
+ .tcnt_mux = 38),
+ [BCM2835_CLOCK_CAM0] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "cam0",
+ .ctl_reg = CM_CAM0CTL,
+ .div_reg = CM_CAM0DIV,
+@@ -2018,6 +2069,7 @@ static const struct bcm2835_clk_desc clk
+ .frac_bits = 8,
+ .tcnt_mux = 14),
+ [BCM2835_CLOCK_CAM1] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "cam1",
+ .ctl_reg = CM_CAM1CTL,
+ .div_reg = CM_CAM1DIV,
+@@ -2025,12 +2077,14 @@ static const struct bcm2835_clk_desc clk
+ .frac_bits = 8,
+ .tcnt_mux = 15),
+ [BCM2835_CLOCK_DFT] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "dft",
+ .ctl_reg = CM_DFTCTL,
+ .div_reg = CM_DFTDIV,
+ .int_bits = 5,
+ .frac_bits = 0),
+ [BCM2835_CLOCK_DPI] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "dpi",
+ .ctl_reg = CM_DPICTL,
+ .div_reg = CM_DPIDIV,
+@@ -2040,6 +2094,7 @@ static const struct bcm2835_clk_desc clk
+
+ /* Arasan EMMC clock */
+ [BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "emmc",
+ .ctl_reg = CM_EMMCCTL,
+ .div_reg = CM_EMMCDIV,
+@@ -2049,6 +2104,7 @@ static const struct bcm2835_clk_desc clk
+
+ /* General purpose (GPIO) clocks */
+ [BCM2835_CLOCK_GP0] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "gp0",
+ .ctl_reg = CM_GP0CTL,
+ .div_reg = CM_GP0DIV,
+@@ -2057,6 +2113,7 @@ static const struct bcm2835_clk_desc clk
+ .is_mash_clock = true,
+ .tcnt_mux = 20),
+ [BCM2835_CLOCK_GP1] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "gp1",
+ .ctl_reg = CM_GP1CTL,
+ .div_reg = CM_GP1DIV,
+@@ -2066,6 +2123,7 @@ static const struct bcm2835_clk_desc clk
+ .is_mash_clock = true,
+ .tcnt_mux = 21),
+ [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "gp2",
+ .ctl_reg = CM_GP2CTL,
+ .div_reg = CM_GP2DIV,
+@@ -2075,6 +2133,7 @@ static const struct bcm2835_clk_desc clk
+
+ /* HDMI state machine */
+ [BCM2835_CLOCK_HSM] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "hsm",
+ .ctl_reg = CM_HSMCTL,
+ .div_reg = CM_HSMDIV,
+@@ -2082,6 +2141,7 @@ static const struct bcm2835_clk_desc clk
+ .frac_bits = 8,
+ .tcnt_mux = 22),
+ [BCM2835_CLOCK_PCM] = REGISTER_PCM_CLK(
++ SOC_ALL,
+ .name = "pcm",
+ .ctl_reg = CM_PCMCTL,
+ .div_reg = CM_PCMDIV,
+@@ -2091,6 +2151,7 @@ static const struct bcm2835_clk_desc clk
+ .low_jitter = true,
+ .tcnt_mux = 23),
+ [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "pwm",
+ .ctl_reg = CM_PWMCTL,
+ .div_reg = CM_PWMDIV,
+@@ -2099,6 +2160,7 @@ static const struct bcm2835_clk_desc clk
+ .is_mash_clock = true,
+ .tcnt_mux = 24),
+ [BCM2835_CLOCK_SLIM] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "slim",
+ .ctl_reg = CM_SLIMCTL,
+ .div_reg = CM_SLIMDIV,
+@@ -2107,6 +2169,7 @@ static const struct bcm2835_clk_desc clk
+ .is_mash_clock = true,
+ .tcnt_mux = 25),
+ [BCM2835_CLOCK_SMI] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "smi",
+ .ctl_reg = CM_SMICTL,
+ .div_reg = CM_SMIDIV,
+@@ -2114,6 +2177,7 @@ static const struct bcm2835_clk_desc clk
+ .frac_bits = 8,
+ .tcnt_mux = 27),
+ [BCM2835_CLOCK_UART] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "uart",
+ .ctl_reg = CM_UARTCTL,
+ .div_reg = CM_UARTDIV,
+@@ -2123,6 +2187,7 @@ static const struct bcm2835_clk_desc clk
+
+ /* 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,
+@@ -2137,6 +2202,7 @@ static const struct bcm2835_clk_desc clk
+
+ /* dsi clocks */
+ [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "dsi0e",
+ .ctl_reg = CM_DSI0ECTL,
+ .div_reg = CM_DSI0EDIV,
+@@ -2144,6 +2210,7 @@ static const struct bcm2835_clk_desc clk
+ .frac_bits = 8,
+ .tcnt_mux = 18),
+ [BCM2835_CLOCK_DSI1E] = REGISTER_PER_CLK(
++ SOC_ALL,
+ .name = "dsi1e",
+ .ctl_reg = CM_DSI1ECTL,
+ .div_reg = CM_DSI1EDIV,
+@@ -2151,6 +2218,7 @@ static const struct bcm2835_clk_desc clk
+ .frac_bits = 8,
+ .tcnt_mux = 19),
+ [BCM2835_CLOCK_DSI0P] = REGISTER_DSI0_CLK(
++ SOC_ALL,
+ .name = "dsi0p",
+ .ctl_reg = CM_DSI0PCTL,
+ .div_reg = CM_DSI0PDIV,
+@@ -2158,6 +2226,7 @@ static const struct bcm2835_clk_desc clk
+ .frac_bits = 0,
+ .tcnt_mux = 12),
+ [BCM2835_CLOCK_DSI1P] = REGISTER_DSI1_CLK(
++ SOC_ALL,
+ .name = "dsi1p",
+ .ctl_reg = CM_DSI1PCTL,
+ .div_reg = CM_DSI1PDIV,
+@@ -2174,6 +2243,7 @@ static const struct bcm2835_clk_desc clk
+ * non-stop vpu clock.
+ */
+ [BCM2835_CLOCK_PERI_IMAGE] = REGISTER_GATE(
++ SOC_ALL,
+ .name = "peri_image",
+ .parent = "vpu",
+ .ctl_reg = CM_PERIICTL),
+@@ -2221,11 +2291,16 @@ static int bcm2835_clk_probe(struct plat
+ struct resource *res;
+ const struct bcm2835_clk_desc *desc;
+ const size_t asize = ARRAY_SIZE(clk_desc_array);
++ const struct cprman_plat_data *pdata;
+ struct device_node *fw_node;
+ size_t i;
+ u32 clk_id;
+ int ret;
+
++ pdata = of_device_get_match_data(&pdev->dev);
++ if (!pdata)
++ return -ENODEV;
++
+ cprman = devm_kzalloc(dev,
+ struct_size(cprman, onecell.hws, asize),
+ GFP_KERNEL);
+@@ -2276,8 +2351,10 @@ static int bcm2835_clk_probe(struct plat
+
+ for (i = 0; i < asize; i++) {
+ desc = &clk_desc_array[i];
+- if (desc->clk_register && desc->data)
++ if (desc->clk_register && desc->data &&
++ (desc->supported & pdata->soc)) {
+ hws[i] = desc->clk_register(cprman, desc->data);
++ }
+ }
+
+ ret = bcm2835_mark_sdc_parent_critical(hws[BCM2835_CLOCK_SDRAM]->clk);
+@@ -2295,8 +2372,12 @@ static int bcm2835_clk_probe(struct plat
+ return 0;
+ }
+
++static const struct cprman_plat_data cprman_bcm2835_plat_data = {
++ .soc = SOC_BCM2835,
++};
++
+ static const struct of_device_id bcm2835_clk_of_match[] = {
+- { .compatible = "brcm,bcm2835-cprman", },
++ { .compatible = "brcm,bcm2835-cprman", .data = &cprman_bcm2835_plat_data },
+ {}
+ };
+ MODULE_DEVICE_TABLE(of, bcm2835_clk_of_match);
+++ /dev/null
-From a3cbeaaee57b7bda4e921bb2cff649fb56c0292d Mon Sep 17 00:00:00 2001
-Date: Tue, 17 Sep 2019 19:31:19 +0200
-Subject: [PATCH] ARM: dts: bcm283x: Enable HDMI at board level
-
-commit 60c833d5664e1b3f71c4471233469790adf505ca upstream.
-
-There might be headless setups of the Compute Module without HDMI,
-so better enable HDMI at board level. Btw this allows moving HDMI
-base definition into upcoming bcm2835-common.dtsi.
-
----
- arch/arm/boot/dts/bcm2835-rpi-a-plus.dts | 2 ++
- arch/arm/boot/dts/bcm2835-rpi-a.dts | 2 ++
- arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 2 ++
- arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts | 2 ++
- arch/arm/boot/dts/bcm2835-rpi-b.dts | 2 ++
- arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts | 2 ++
- arch/arm/boot/dts/bcm2835-rpi-zero-w.dts | 2 ++
- arch/arm/boot/dts/bcm2835-rpi-zero.dts | 2 ++
- arch/arm/boot/dts/bcm2835-rpi.dtsi | 5 -----
- arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 2 ++
- arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts | 2 ++
- arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 2 ++
- 12 files changed, 22 insertions(+), 5 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
-@@ -100,6 +100,8 @@
-
- &hdmi {
- hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "okay";
- };
-
- &pwm {
---- a/arch/arm/boot/dts/bcm2835-rpi-a.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts
-@@ -95,6 +95,8 @@
-
- &hdmi {
- hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "okay";
- };
-
- &pwm {
---- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
-@@ -102,6 +102,8 @@
-
- &hdmi {
- hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "okay";
- };
-
- &pwm {
---- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
-@@ -95,6 +95,8 @@
-
- &hdmi {
- hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "okay";
- };
-
- &pwm {
---- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
-@@ -90,6 +90,8 @@
-
- &hdmi {
- hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "okay";
- };
-
- &pwm {
---- a/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1.dts
-@@ -79,6 +79,8 @@
-
- &hdmi {
- hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "okay";
- };
-
- &sdhost {
---- a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
-@@ -113,6 +113,8 @@
-
- &hdmi {
- hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "okay";
- };
-
- &sdhci {
---- a/arch/arm/boot/dts/bcm2835-rpi-zero.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts
-@@ -103,6 +103,8 @@
-
- &hdmi {
- hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "okay";
- };
-
- &sdhost {
---- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
-@@ -92,11 +92,6 @@
- power-domains = <&power RPI_POWER_DOMAIN_V3D>;
- };
-
--&hdmi {
-- power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-- status = "okay";
--};
--
- &vec {
- power-domains = <&power RPI_POWER_DOMAIN_VEC>;
- status = "okay";
---- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-+++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-@@ -40,6 +40,8 @@
-
- &hdmi {
- hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "okay";
- };
-
- &pwm {
---- a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
-@@ -54,6 +54,8 @@
-
- &hdmi {
- hpd-gpios = <&gpio 28 GPIO_ACTIVE_LOW>;
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "okay";
- };
-
- &pwm {
---- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
-+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
-@@ -56,6 +56,8 @@
-
- &hdmi {
- hpd-gpios = <&expgpio 4 GPIO_ACTIVE_LOW>;
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "okay";
- };
-
- /* uart0 communicates with the BT module */
--- /dev/null
+From b4c6046e1c55ddf211215191be9ea6316238889b Mon Sep 17 00:00:00 2001
+Date: Fri, 20 Sep 2019 07:27:03 +0200
+Subject: [PATCH] clk: bcm2835: Add BCM2711_CLOCK_EMMC2 support
+
+commit 42de9ad400afadd41ee027b5feef234a2d2918b9 upstream.
+
+The new BCM2711 supports an additional clock for the emmc2 block.
+So add a new compatible and register this clock only for BCM2711.
+
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 1 +
+ drivers/clk/bcm/clk-bcm2835.c | 20 +++++++++++++++++++-
+ include/dt-bindings/clock/bcm2835.h | 2 ++
+ 3 files changed, 22 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -210,7 +210,7 @@
+ compatible = "brcm,bcm2711-emmc2";
+ status = "okay";
+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2838_CLOCK_EMMC2>;
++ clocks = <&clocks BCM2711_CLOCK_EMMC2>;
+ reg = <0x7e340000 0x100>;
+ };
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -124,6 +124,8 @@
+ #define CM_AVEODIV 0x1bc
+ #define CM_EMMCCTL 0x1c0
+ #define CM_EMMCDIV 0x1c4
++#define CM_EMMC2CTL 0x1d0
++#define CM_EMMC2DIV 0x1d4
+
+ /* General bits for the CM_*CTL regs */
+ # define CM_ENABLE BIT(4)
+@@ -302,7 +304,8 @@
+ #define VCMSG_ID_CORE_CLOCK 4
+
+ #define SOC_BCM2835 BIT(0)
+-#define SOC_ALL (SOC_BCM2835)
++#define SOC_BCM2711 BIT(1)
++#define SOC_ALL (SOC_BCM2835 | SOC_BCM2711)
+
+ /*
+ * Names of clocks used within the driver that need to be replaced
+@@ -2102,6 +2105,16 @@ static const struct bcm2835_clk_desc clk
+ .frac_bits = 8,
+ .tcnt_mux = 39),
+
++ /* EMMC2 clock (only available for BCM2711) */
++ [BCM2711_CLOCK_EMMC2] = REGISTER_PER_CLK(
++ SOC_BCM2711,
++ .name = "emmc2",
++ .ctl_reg = CM_EMMC2CTL,
++ .div_reg = CM_EMMC2DIV,
++ .int_bits = 4,
++ .frac_bits = 8,
++ .tcnt_mux = 42),
++
+ /* General purpose (GPIO) clocks */
+ [BCM2835_CLOCK_GP0] = REGISTER_PER_CLK(
+ SOC_ALL,
+@@ -2376,8 +2389,13 @@ static const struct cprman_plat_data cpr
+ .soc = SOC_BCM2835,
+ };
+
++static const struct cprman_plat_data cprman_bcm2711_plat_data = {
++ .soc = SOC_BCM2711,
++};
++
+ static const struct of_device_id bcm2835_clk_of_match[] = {
+ { .compatible = "brcm,bcm2835-cprman", .data = &cprman_bcm2835_plat_data },
++ { .compatible = "brcm,bcm2711-cprman", .data = &cprman_bcm2711_plat_data },
+ {}
+ };
+ MODULE_DEVICE_TABLE(of, bcm2835_clk_of_match);
+--- a/include/dt-bindings/clock/bcm2835.h
++++ b/include/dt-bindings/clock/bcm2835.h
+@@ -66,3 +66,5 @@
+ #define BCM2835_CLOCK_DSI1E 48
+ #define BCM2835_CLOCK_DSI0P 49
+ #define BCM2835_CLOCK_DSI1P 50
++
++#define BCM2711_CLOCK_EMMC2 51
--- /dev/null
+From 30972497979c65781bb8170743447b45b6dfd3cd Mon Sep 17 00:00:00 2001
+Date: Thu, 19 Sep 2019 20:45:30 +0200
+Subject: [PATCH] ARM: bcm: Switch board, clk and pinctrl to bcm2711
+ compatible
+
+After the decision to use bcm2711 compatible for upstream, we should
+switch all accepted compatibles to bcm2711. So we can boot with
+one DTB the down- and the upstream kernel.
+
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 +-
+ arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 2 +-
+ arch/arm/boot/dts/bcm2838.dtsi | 4 ++--
+ arch/arm/mach-bcm/board_bcm2835.c | 2 +-
+ 4 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -5,7 +5,7 @@
+ #include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+- compatible = "raspberrypi,4-model-b", "brcm,bcm2838";
++ compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
+ model = "Raspberry Pi 4 Model B";
+
+ memory@0 {
+--- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
+@@ -5,7 +5,7 @@
+ #include "bcm2838-rpi.dtsi"
+
+ / {
+- compatible = "raspberrypi,4-model-b", "brcm,bcm2838";
++ compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
+ model = "Raspberry Pi 4 Model B";
+
+ chosen {
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -440,7 +440,7 @@
+ };
+
+ &clocks {
+- compatible = "brcm,bcm2838-cprman";
++ compatible = "brcm,bcm2711-cprman";
+ };
+
+ &cpu_thermal {
+@@ -456,7 +456,7 @@
+ };
+
+ &gpio {
+- compatible = "brcm,bcm2838-gpio", "brcm,bcm2835-gpio";
++ compatible = "brcm,bcm2711-gpio", "brcm,bcm2835-gpio";
+
+ gpclk0_gpio49: gpclk0_gpio49 {
+ brcm,pins = <49>;
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -118,7 +118,7 @@ static const char * const bcm2835_compat
+ #ifdef CONFIG_ARCH_MULTI_V7
+ "brcm,bcm2836",
+ "brcm,bcm2837",
+- "brcm,bcm2838",
++ "brcm,bcm2711",
+ #endif
+ NULL
+ };
+++ /dev/null
-From 125afc5cf080b29e9114d89f6052fa4a936a3f19 Mon Sep 17 00:00:00 2001
-Date: Thu, 19 Sep 2019 20:12:15 +0200
-Subject: [PATCH] clk: bcm2835: Introduce SoC specific clock
- registration
-
-commit ee0a5a9013b2b2502571a763c3093d400d18191f upstream.
-
-In order to support SoC specific clocks (e.g. emmc2 for BCM2711), we
-extend the description with a SoC support flag. This approach avoids long
-and mostly redundant lists of clock IDs. Since PLLH is specific to
-BCM2835, we register only rest of the clocks as common to all SoC.
-
----
- drivers/clk/bcm/clk-bcm2835.c | 115 +++++++++++++++++++++++++++++-----
- 1 file changed, 98 insertions(+), 17 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -40,7 +40,7 @@
- #include <linux/debugfs.h>
- #include <linux/delay.h>
- #include <linux/module.h>
--#include <linux/of.h>
-+#include <linux/of_device.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
- #include <dt-bindings/clock/bcm2835.h>
-@@ -301,6 +301,9 @@
-
- #define VCMSG_ID_CORE_CLOCK 4
-
-+#define SOC_BCM2835 BIT(0)
-+#define SOC_ALL (SOC_BCM2835)
-+
- /*
- * Names of clocks used within the driver that need to be replaced
- * with an external parent's name. This array is in the order that
-@@ -333,6 +336,10 @@ struct bcm2835_cprman {
- struct clk_hw_onecell_data onecell;
- };
-
-+struct cprman_plat_data {
-+ unsigned int soc;
-+};
-+
- static inline void cprman_write(struct bcm2835_cprman *cprman, u32 reg, u32 val)
- {
- writel(CM_PASSWORD | val, cprman->regs + reg);
-@@ -1528,22 +1535,28 @@ typedef struct clk_hw *(*bcm2835_clk_reg
- const void *data);
- struct bcm2835_clk_desc {
- bcm2835_clk_register clk_register;
-+ unsigned int supported;
- const void *data;
- };
-
- /* assignment helper macros for different clock types */
--#define _REGISTER(f, ...) { .clk_register = (bcm2835_clk_register)f, \
-- .data = __VA_ARGS__ }
--#define REGISTER_PLL(...) _REGISTER(&bcm2835_register_pll, \
-+#define _REGISTER(f, s, ...) { .clk_register = (bcm2835_clk_register)f, \
-+ .supported = s, \
-+ .data = __VA_ARGS__ }
-+#define REGISTER_PLL(s, ...) _REGISTER(&bcm2835_register_pll, \
-+ s, \
- &(struct bcm2835_pll_data) \
- {__VA_ARGS__})
--#define REGISTER_PLL_DIV(...) _REGISTER(&bcm2835_register_pll_divider, \
-- &(struct bcm2835_pll_divider_data) \
-- {__VA_ARGS__})
--#define REGISTER_CLK(...) _REGISTER(&bcm2835_register_clock, \
-+#define REGISTER_PLL_DIV(s, ...) _REGISTER(&bcm2835_register_pll_divider, \
-+ s, \
-+ &(struct bcm2835_pll_divider_data) \
-+ {__VA_ARGS__})
-+#define REGISTER_CLK(s, ...) _REGISTER(&bcm2835_register_clock, \
-+ s, \
- &(struct bcm2835_clock_data) \
- {__VA_ARGS__})
--#define REGISTER_GATE(...) _REGISTER(&bcm2835_register_gate, \
-+#define REGISTER_GATE(s, ...) _REGISTER(&bcm2835_register_gate, \
-+ s, \
- &(struct bcm2835_gate_data) \
- {__VA_ARGS__})
-
-@@ -1557,7 +1570,8 @@ static const char *const bcm2835_clock_o
- "testdebug1"
- };
-
--#define REGISTER_OSC_CLK(...) REGISTER_CLK( \
-+#define REGISTER_OSC_CLK(s, ...) REGISTER_CLK( \
-+ s, \
- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), \
- .parents = bcm2835_clock_osc_parents, \
- __VA_ARGS__)
-@@ -1574,7 +1588,8 @@ static const char *const bcm2835_clock_p
- "pllh_aux",
- };
-
--#define REGISTER_PER_CLK(...) REGISTER_CLK( \
-+#define REGISTER_PER_CLK(s, ...) REGISTER_CLK( \
-+ s, \
- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), \
- .parents = bcm2835_clock_per_parents, \
- __VA_ARGS__)
-@@ -1599,7 +1614,8 @@ static const char *const bcm2835_pcm_per
- "-",
- };
-
--#define REGISTER_PCM_CLK(...) REGISTER_CLK( \
-+#define REGISTER_PCM_CLK(s, ...) REGISTER_CLK( \
-+ s, \
- .num_mux_parents = ARRAY_SIZE(bcm2835_pcm_per_parents), \
- .parents = bcm2835_pcm_per_parents, \
- __VA_ARGS__)
-@@ -1618,7 +1634,8 @@ static const char *const bcm2835_clock_v
- "pllc_core2",
- };
-
--#define REGISTER_VPU_CLK(...) REGISTER_CLK( \
-+#define REGISTER_VPU_CLK(s, ...) REGISTER_CLK( \
-+ s, \
- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), \
- .parents = bcm2835_clock_vpu_parents, \
- __VA_ARGS__)
-@@ -1654,12 +1671,14 @@ static const char *const bcm2835_clock_d
- "dsi1_byte_inv",
- };
-
--#define REGISTER_DSI0_CLK(...) REGISTER_CLK( \
-+#define REGISTER_DSI0_CLK(s, ...) REGISTER_CLK( \
-+ s, \
- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi0_parents), \
- .parents = bcm2835_clock_dsi0_parents, \
- __VA_ARGS__)
-
--#define REGISTER_DSI1_CLK(...) REGISTER_CLK( \
-+#define REGISTER_DSI1_CLK(s, ...) REGISTER_CLK( \
-+ s, \
- .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi1_parents), \
- .parents = bcm2835_clock_dsi1_parents, \
- __VA_ARGS__)
-@@ -1679,6 +1698,7 @@ static const struct bcm2835_clk_desc clk
- * AUDIO domain is on.
- */
- [BCM2835_PLLA] = REGISTER_PLL(
-+ SOC_ALL,
- .name = "plla",
- .cm_ctrl_reg = CM_PLLA,
- .a2w_ctrl_reg = A2W_PLLA_CTRL,
-@@ -1693,6 +1713,7 @@ static const struct bcm2835_clk_desc clk
- .max_rate = 2400000000u,
- .max_fb_rate = BCM2835_MAX_FB_RATE),
- [BCM2835_PLLA_CORE] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "plla_core",
- .source_pll = "plla",
- .cm_reg = CM_PLLA,
-@@ -1702,6 +1723,7 @@ static const struct bcm2835_clk_desc clk
- .fixed_divider = 1,
- .flags = CLK_SET_RATE_PARENT),
- [BCM2835_PLLA_PER] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "plla_per",
- .source_pll = "plla",
- .cm_reg = CM_PLLA,
-@@ -1711,6 +1733,7 @@ static const struct bcm2835_clk_desc clk
- .fixed_divider = 1,
- .flags = CLK_SET_RATE_PARENT),
- [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "plla_dsi0",
- .source_pll = "plla",
- .cm_reg = CM_PLLA,
-@@ -1719,6 +1742,7 @@ static const struct bcm2835_clk_desc clk
- .hold_mask = CM_PLLA_HOLDDSI0,
- .fixed_divider = 1),
- [BCM2835_PLLA_CCP2] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "plla_ccp2",
- .source_pll = "plla",
- .cm_reg = CM_PLLA,
-@@ -1730,6 +1754,7 @@ static const struct bcm2835_clk_desc clk
-
- /* PLLB is used for the ARM's clock. */
- [BCM2835_PLLB] = REGISTER_PLL(
-+ SOC_ALL,
- .name = "pllb",
- .cm_ctrl_reg = CM_PLLB,
- .a2w_ctrl_reg = A2W_PLLB_CTRL,
-@@ -1744,6 +1769,7 @@ static const struct bcm2835_clk_desc clk
- .max_rate = 3000000000u,
- .max_fb_rate = BCM2835_MAX_FB_RATE),
- [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "pllb_arm",
- .source_pll = "pllb",
- .cm_reg = CM_PLLB,
-@@ -1760,6 +1786,7 @@ static const struct bcm2835_clk_desc clk
- * AUDIO domain is on.
- */
- [BCM2835_PLLC] = REGISTER_PLL(
-+ SOC_ALL,
- .name = "pllc",
- .cm_ctrl_reg = CM_PLLC,
- .a2w_ctrl_reg = A2W_PLLC_CTRL,
-@@ -1774,6 +1801,7 @@ static const struct bcm2835_clk_desc clk
- .max_rate = 3000000000u,
- .max_fb_rate = BCM2835_MAX_FB_RATE),
- [BCM2835_PLLC_CORE0] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "pllc_core0",
- .source_pll = "pllc",
- .cm_reg = CM_PLLC,
-@@ -1783,6 +1811,7 @@ static const struct bcm2835_clk_desc clk
- .fixed_divider = 1,
- .flags = CLK_SET_RATE_PARENT),
- [BCM2835_PLLC_CORE1] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "pllc_core1",
- .source_pll = "pllc",
- .cm_reg = CM_PLLC,
-@@ -1792,6 +1821,7 @@ static const struct bcm2835_clk_desc clk
- .fixed_divider = 1,
- .flags = CLK_SET_RATE_PARENT),
- [BCM2835_PLLC_CORE2] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "pllc_core2",
- .source_pll = "pllc",
- .cm_reg = CM_PLLC,
-@@ -1801,6 +1831,7 @@ static const struct bcm2835_clk_desc clk
- .fixed_divider = 1,
- .flags = CLK_SET_RATE_PARENT),
- [BCM2835_PLLC_PER] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "pllc_per",
- .source_pll = "pllc",
- .cm_reg = CM_PLLC,
-@@ -1817,6 +1848,7 @@ static const struct bcm2835_clk_desc clk
- * AUDIO domain is on.
- */
- [BCM2835_PLLD] = REGISTER_PLL(
-+ SOC_ALL,
- .name = "plld",
- .cm_ctrl_reg = CM_PLLD,
- .a2w_ctrl_reg = A2W_PLLD_CTRL,
-@@ -1831,6 +1863,7 @@ static const struct bcm2835_clk_desc clk
- .max_rate = 2400000000u,
- .max_fb_rate = BCM2835_MAX_FB_RATE),
- [BCM2835_PLLD_CORE] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "plld_core",
- .source_pll = "plld",
- .cm_reg = CM_PLLD,
-@@ -1840,6 +1873,7 @@ static const struct bcm2835_clk_desc clk
- .fixed_divider = 1,
- .flags = CLK_SET_RATE_PARENT),
- [BCM2835_PLLD_PER] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "plld_per",
- .source_pll = "plld",
- .cm_reg = CM_PLLD,
-@@ -1849,6 +1883,7 @@ static const struct bcm2835_clk_desc clk
- .fixed_divider = 1,
- .flags = CLK_SET_RATE_PARENT),
- [BCM2835_PLLD_DSI0] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "plld_dsi0",
- .source_pll = "plld",
- .cm_reg = CM_PLLD,
-@@ -1857,6 +1892,7 @@ static const struct bcm2835_clk_desc clk
- .hold_mask = CM_PLLD_HOLDDSI0,
- .fixed_divider = 1),
- [BCM2835_PLLD_DSI1] = REGISTER_PLL_DIV(
-+ SOC_ALL,
- .name = "plld_dsi1",
- .source_pll = "plld",
- .cm_reg = CM_PLLD,
-@@ -1872,6 +1908,7 @@ static const struct bcm2835_clk_desc clk
- * It is in the HDMI power domain.
- */
- [BCM2835_PLLH] = REGISTER_PLL(
-+ SOC_BCM2835,
- "pllh",
- .cm_ctrl_reg = CM_PLLH,
- .a2w_ctrl_reg = A2W_PLLH_CTRL,
-@@ -1886,6 +1923,7 @@ static const struct bcm2835_clk_desc clk
- .max_rate = 3000000000u,
- .max_fb_rate = BCM2835_MAX_FB_RATE),
- [BCM2835_PLLH_RCAL] = REGISTER_PLL_DIV(
-+ SOC_BCM2835,
- .name = "pllh_rcal",
- .source_pll = "pllh",
- .cm_reg = CM_PLLH,
-@@ -1895,6 +1933,7 @@ static const struct bcm2835_clk_desc clk
- .fixed_divider = 10,
- .flags = CLK_SET_RATE_PARENT),
- [BCM2835_PLLH_AUX] = REGISTER_PLL_DIV(
-+ SOC_BCM2835,
- .name = "pllh_aux",
- .source_pll = "pllh",
- .cm_reg = CM_PLLH,
-@@ -1904,6 +1943,7 @@ static const struct bcm2835_clk_desc clk
- .fixed_divider = 1,
- .flags = CLK_SET_RATE_PARENT),
- [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV(
-+ SOC_BCM2835,
- .name = "pllh_pix",
- .source_pll = "pllh",
- .cm_reg = CM_PLLH,
-@@ -1919,6 +1959,7 @@ static const struct bcm2835_clk_desc clk
-
- /* One Time Programmable Memory clock. Maximum 10Mhz. */
- [BCM2835_CLOCK_OTP] = REGISTER_OSC_CLK(
-+ SOC_ALL,
- .name = "otp",
- .ctl_reg = CM_OTPCTL,
- .div_reg = CM_OTPDIV,
-@@ -1930,6 +1971,7 @@ static const struct bcm2835_clk_desc clk
- * bythe watchdog timer and the camera pulse generator.
- */
- [BCM2835_CLOCK_TIMER] = REGISTER_OSC_CLK(
-+ SOC_ALL,
- .name = "timer",
- .ctl_reg = CM_TIMERCTL,
- .div_reg = CM_TIMERDIV,
-@@ -1940,12 +1982,14 @@ static const struct bcm2835_clk_desc clk
- * Generally run at 2Mhz, max 5Mhz.
- */
- [BCM2835_CLOCK_TSENS] = REGISTER_OSC_CLK(
-+ SOC_ALL,
- .name = "tsens",
- .ctl_reg = CM_TSENSCTL,
- .div_reg = CM_TSENSDIV,
- .int_bits = 5,
- .frac_bits = 0),
- [BCM2835_CLOCK_TEC] = REGISTER_OSC_CLK(
-+ SOC_ALL,
- .name = "tec",
- .ctl_reg = CM_TECCTL,
- .div_reg = CM_TECDIV,
-@@ -1954,6 +1998,7 @@ static const struct bcm2835_clk_desc clk
-
- /* clocks with vpu parent mux */
- [BCM2835_CLOCK_H264] = REGISTER_VPU_CLK(
-+ SOC_ALL,
- .name = "h264",
- .ctl_reg = CM_H264CTL,
- .div_reg = CM_H264DIV,
-@@ -1961,6 +2006,7 @@ static const struct bcm2835_clk_desc clk
- .frac_bits = 8,
- .tcnt_mux = 1),
- [BCM2835_CLOCK_ISP] = REGISTER_VPU_CLK(
-+ SOC_ALL,
- .name = "isp",
- .ctl_reg = CM_ISPCTL,
- .div_reg = CM_ISPDIV,
-@@ -1973,6 +2019,7 @@ static const struct bcm2835_clk_desc clk
- * in the SDRAM controller can't be used.
- */
- [BCM2835_CLOCK_SDRAM] = REGISTER_VPU_CLK(
-+ SOC_ALL,
- .name = "sdram",
- .ctl_reg = CM_SDCCTL,
- .div_reg = CM_SDCDIV,
-@@ -1980,6 +2027,7 @@ static const struct bcm2835_clk_desc clk
- .frac_bits = 0,
- .tcnt_mux = 3),
- [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK(
-+ SOC_ALL,
- .name = "v3d",
- .ctl_reg = CM_V3DCTL,
- .div_reg = CM_V3DDIV,
-@@ -1993,6 +2041,7 @@ static const struct bcm2835_clk_desc clk
- * in various hardware documentation.
- */
- [BCM2835_CLOCK_VPU] = REGISTER_VPU_CLK(
-+ SOC_ALL,
- .name = "vpu",
- .ctl_reg = CM_VPUCTL,
- .div_reg = CM_VPUDIV,
-@@ -2004,6 +2053,7 @@ static const struct bcm2835_clk_desc clk
-
- /* clocks with per parent mux */
- [BCM2835_CLOCK_AVEO] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "aveo",
- .ctl_reg = CM_AVEOCTL,
- .div_reg = CM_AVEODIV,
-@@ -2011,6 +2061,7 @@ static const struct bcm2835_clk_desc clk
- .frac_bits = 0,
- .tcnt_mux = 38),
- [BCM2835_CLOCK_CAM0] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "cam0",
- .ctl_reg = CM_CAM0CTL,
- .div_reg = CM_CAM0DIV,
-@@ -2018,6 +2069,7 @@ static const struct bcm2835_clk_desc clk
- .frac_bits = 8,
- .tcnt_mux = 14),
- [BCM2835_CLOCK_CAM1] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "cam1",
- .ctl_reg = CM_CAM1CTL,
- .div_reg = CM_CAM1DIV,
-@@ -2025,12 +2077,14 @@ static const struct bcm2835_clk_desc clk
- .frac_bits = 8,
- .tcnt_mux = 15),
- [BCM2835_CLOCK_DFT] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "dft",
- .ctl_reg = CM_DFTCTL,
- .div_reg = CM_DFTDIV,
- .int_bits = 5,
- .frac_bits = 0),
- [BCM2835_CLOCK_DPI] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "dpi",
- .ctl_reg = CM_DPICTL,
- .div_reg = CM_DPIDIV,
-@@ -2040,6 +2094,7 @@ static const struct bcm2835_clk_desc clk
-
- /* Arasan EMMC clock */
- [BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "emmc",
- .ctl_reg = CM_EMMCCTL,
- .div_reg = CM_EMMCDIV,
-@@ -2049,6 +2104,7 @@ static const struct bcm2835_clk_desc clk
-
- /* General purpose (GPIO) clocks */
- [BCM2835_CLOCK_GP0] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "gp0",
- .ctl_reg = CM_GP0CTL,
- .div_reg = CM_GP0DIV,
-@@ -2057,6 +2113,7 @@ static const struct bcm2835_clk_desc clk
- .is_mash_clock = true,
- .tcnt_mux = 20),
- [BCM2835_CLOCK_GP1] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "gp1",
- .ctl_reg = CM_GP1CTL,
- .div_reg = CM_GP1DIV,
-@@ -2066,6 +2123,7 @@ static const struct bcm2835_clk_desc clk
- .is_mash_clock = true,
- .tcnt_mux = 21),
- [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "gp2",
- .ctl_reg = CM_GP2CTL,
- .div_reg = CM_GP2DIV,
-@@ -2075,6 +2133,7 @@ static const struct bcm2835_clk_desc clk
-
- /* HDMI state machine */
- [BCM2835_CLOCK_HSM] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "hsm",
- .ctl_reg = CM_HSMCTL,
- .div_reg = CM_HSMDIV,
-@@ -2082,6 +2141,7 @@ static const struct bcm2835_clk_desc clk
- .frac_bits = 8,
- .tcnt_mux = 22),
- [BCM2835_CLOCK_PCM] = REGISTER_PCM_CLK(
-+ SOC_ALL,
- .name = "pcm",
- .ctl_reg = CM_PCMCTL,
- .div_reg = CM_PCMDIV,
-@@ -2091,6 +2151,7 @@ static const struct bcm2835_clk_desc clk
- .low_jitter = true,
- .tcnt_mux = 23),
- [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "pwm",
- .ctl_reg = CM_PWMCTL,
- .div_reg = CM_PWMDIV,
-@@ -2099,6 +2160,7 @@ static const struct bcm2835_clk_desc clk
- .is_mash_clock = true,
- .tcnt_mux = 24),
- [BCM2835_CLOCK_SLIM] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "slim",
- .ctl_reg = CM_SLIMCTL,
- .div_reg = CM_SLIMDIV,
-@@ -2107,6 +2169,7 @@ static const struct bcm2835_clk_desc clk
- .is_mash_clock = true,
- .tcnt_mux = 25),
- [BCM2835_CLOCK_SMI] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "smi",
- .ctl_reg = CM_SMICTL,
- .div_reg = CM_SMIDIV,
-@@ -2114,6 +2177,7 @@ static const struct bcm2835_clk_desc clk
- .frac_bits = 8,
- .tcnt_mux = 27),
- [BCM2835_CLOCK_UART] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "uart",
- .ctl_reg = CM_UARTCTL,
- .div_reg = CM_UARTDIV,
-@@ -2123,6 +2187,7 @@ static const struct bcm2835_clk_desc clk
-
- /* 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,
-@@ -2137,6 +2202,7 @@ static const struct bcm2835_clk_desc clk
-
- /* dsi clocks */
- [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "dsi0e",
- .ctl_reg = CM_DSI0ECTL,
- .div_reg = CM_DSI0EDIV,
-@@ -2144,6 +2210,7 @@ static const struct bcm2835_clk_desc clk
- .frac_bits = 8,
- .tcnt_mux = 18),
- [BCM2835_CLOCK_DSI1E] = REGISTER_PER_CLK(
-+ SOC_ALL,
- .name = "dsi1e",
- .ctl_reg = CM_DSI1ECTL,
- .div_reg = CM_DSI1EDIV,
-@@ -2151,6 +2218,7 @@ static const struct bcm2835_clk_desc clk
- .frac_bits = 8,
- .tcnt_mux = 19),
- [BCM2835_CLOCK_DSI0P] = REGISTER_DSI0_CLK(
-+ SOC_ALL,
- .name = "dsi0p",
- .ctl_reg = CM_DSI0PCTL,
- .div_reg = CM_DSI0PDIV,
-@@ -2158,6 +2226,7 @@ static const struct bcm2835_clk_desc clk
- .frac_bits = 0,
- .tcnt_mux = 12),
- [BCM2835_CLOCK_DSI1P] = REGISTER_DSI1_CLK(
-+ SOC_ALL,
- .name = "dsi1p",
- .ctl_reg = CM_DSI1PCTL,
- .div_reg = CM_DSI1PDIV,
-@@ -2174,6 +2243,7 @@ static const struct bcm2835_clk_desc clk
- * non-stop vpu clock.
- */
- [BCM2835_CLOCK_PERI_IMAGE] = REGISTER_GATE(
-+ SOC_ALL,
- .name = "peri_image",
- .parent = "vpu",
- .ctl_reg = CM_PERIICTL),
-@@ -2221,11 +2291,16 @@ static int bcm2835_clk_probe(struct plat
- struct resource *res;
- const struct bcm2835_clk_desc *desc;
- const size_t asize = ARRAY_SIZE(clk_desc_array);
-+ const struct cprman_plat_data *pdata;
- struct device_node *fw_node;
- size_t i;
- u32 clk_id;
- int ret;
-
-+ pdata = of_device_get_match_data(&pdev->dev);
-+ if (!pdata)
-+ return -ENODEV;
-+
- cprman = devm_kzalloc(dev,
- struct_size(cprman, onecell.hws, asize),
- GFP_KERNEL);
-@@ -2276,8 +2351,10 @@ static int bcm2835_clk_probe(struct plat
-
- for (i = 0; i < asize; i++) {
- desc = &clk_desc_array[i];
-- if (desc->clk_register && desc->data)
-+ if (desc->clk_register && desc->data &&
-+ (desc->supported & pdata->soc)) {
- hws[i] = desc->clk_register(cprman, desc->data);
-+ }
- }
-
- ret = bcm2835_mark_sdc_parent_critical(hws[BCM2835_CLOCK_SDRAM]->clk);
-@@ -2295,8 +2372,12 @@ static int bcm2835_clk_probe(struct plat
- return 0;
- }
-
-+static const struct cprman_plat_data cprman_bcm2835_plat_data = {
-+ .soc = SOC_BCM2835,
-+};
-+
- static const struct of_device_id bcm2835_clk_of_match[] = {
-- { .compatible = "brcm,bcm2835-cprman", },
-+ { .compatible = "brcm,bcm2835-cprman", .data = &cprman_bcm2835_plat_data },
- {}
- };
- MODULE_DEVICE_TABLE(of, bcm2835_clk_of_match);
+++ /dev/null
-From b4c6046e1c55ddf211215191be9ea6316238889b Mon Sep 17 00:00:00 2001
-Date: Fri, 20 Sep 2019 07:27:03 +0200
-Subject: [PATCH] clk: bcm2835: Add BCM2711_CLOCK_EMMC2 support
-
-commit 42de9ad400afadd41ee027b5feef234a2d2918b9 upstream.
-
-The new BCM2711 supports an additional clock for the emmc2 block.
-So add a new compatible and register this clock only for BCM2711.
-
----
- arch/arm/boot/dts/bcm2838.dtsi | 1 +
- drivers/clk/bcm/clk-bcm2835.c | 20 +++++++++++++++++++-
- include/dt-bindings/clock/bcm2835.h | 2 ++
- 3 files changed, 22 insertions(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -210,7 +210,7 @@
- compatible = "brcm,bcm2711-emmc2";
- status = "okay";
- interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2838_CLOCK_EMMC2>;
-+ clocks = <&clocks BCM2711_CLOCK_EMMC2>;
- reg = <0x7e340000 0x100>;
- };
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -124,6 +124,8 @@
- #define CM_AVEODIV 0x1bc
- #define CM_EMMCCTL 0x1c0
- #define CM_EMMCDIV 0x1c4
-+#define CM_EMMC2CTL 0x1d0
-+#define CM_EMMC2DIV 0x1d4
-
- /* General bits for the CM_*CTL regs */
- # define CM_ENABLE BIT(4)
-@@ -302,7 +304,8 @@
- #define VCMSG_ID_CORE_CLOCK 4
-
- #define SOC_BCM2835 BIT(0)
--#define SOC_ALL (SOC_BCM2835)
-+#define SOC_BCM2711 BIT(1)
-+#define SOC_ALL (SOC_BCM2835 | SOC_BCM2711)
-
- /*
- * Names of clocks used within the driver that need to be replaced
-@@ -2102,6 +2105,16 @@ static const struct bcm2835_clk_desc clk
- .frac_bits = 8,
- .tcnt_mux = 39),
-
-+ /* EMMC2 clock (only available for BCM2711) */
-+ [BCM2711_CLOCK_EMMC2] = REGISTER_PER_CLK(
-+ SOC_BCM2711,
-+ .name = "emmc2",
-+ .ctl_reg = CM_EMMC2CTL,
-+ .div_reg = CM_EMMC2DIV,
-+ .int_bits = 4,
-+ .frac_bits = 8,
-+ .tcnt_mux = 42),
-+
- /* General purpose (GPIO) clocks */
- [BCM2835_CLOCK_GP0] = REGISTER_PER_CLK(
- SOC_ALL,
-@@ -2376,8 +2389,13 @@ static const struct cprman_plat_data cpr
- .soc = SOC_BCM2835,
- };
-
-+static const struct cprman_plat_data cprman_bcm2711_plat_data = {
-+ .soc = SOC_BCM2711,
-+};
-+
- static const struct of_device_id bcm2835_clk_of_match[] = {
- { .compatible = "brcm,bcm2835-cprman", .data = &cprman_bcm2835_plat_data },
-+ { .compatible = "brcm,bcm2711-cprman", .data = &cprman_bcm2711_plat_data },
- {}
- };
- MODULE_DEVICE_TABLE(of, bcm2835_clk_of_match);
---- a/include/dt-bindings/clock/bcm2835.h
-+++ b/include/dt-bindings/clock/bcm2835.h
-@@ -66,3 +66,5 @@
- #define BCM2835_CLOCK_DSI1E 48
- #define BCM2835_CLOCK_DSI0P 49
- #define BCM2835_CLOCK_DSI1P 50
-+
-+#define BCM2711_CLOCK_EMMC2 51
--- /dev/null
+From e60428993b9ba03e2389eeb61c4b5efaa80b9e05 Mon Sep 17 00:00:00 2001
+Date: Sat, 10 Nov 2018 17:15:11 +0100
+Subject: [PATCH] pinctrl: bcm2835: Switch to SPDX identifier
+
+commit a62c36775ba873611b00b82ce7ebcd4ff2126111 upstream.
+
+Adopt the SPDX license identifier headers to ease license compliance
+management.
+
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 11 +----------
+ include/dt-bindings/pinctrl/bcm2835.h | 8 +-------
+ 2 files changed, 2 insertions(+), 17 deletions(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -1,3 +1,4 @@
++// SPDX-License-Identifier: GPL-2.0+
+ /*
+ * Driver for Broadcom BCM2835 GPIO unit (pinctrl + GPIO)
+ *
+@@ -6,16 +7,6 @@
+ * This driver is inspired by:
+ * pinctrl-nomadik.c, please see original file for copyright information
+ * pinctrl-tegra.c, please see original file for copyright information
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+ */
+
+ #include <linux/bitmap.h>
+--- a/include/dt-bindings/pinctrl/bcm2835.h
++++ b/include/dt-bindings/pinctrl/bcm2835.h
+@@ -1,14 +1,8 @@
++/* SPDX-License-Identifier: GPL-2.0 */
+ /*
+ * Header providing constants for bcm2835 pinctrl bindings.
+ *
+- *
+- * The code contained herein is licensed under the GNU General Public
+- * License. You may obtain a copy of the GNU General Public License
+- * Version 2 at the following locations:
+- *
+- * http://www.opensource.org/licenses/gpl-license.html
+- * http://www.gnu.org/copyleft/gpl.html
+ */
+
+ #ifndef __DT_BINDINGS_PINCTRL_BCM2835_H__
+++ /dev/null
-From 30972497979c65781bb8170743447b45b6dfd3cd Mon Sep 17 00:00:00 2001
-Date: Thu, 19 Sep 2019 20:45:30 +0200
-Subject: [PATCH] ARM: bcm: Switch board, clk and pinctrl to bcm2711
- compatible
-
-After the decision to use bcm2711 compatible for upstream, we should
-switch all accepted compatibles to bcm2711. So we can boot with
-one DTB the down- and the upstream kernel.
-
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 +-
- arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 2 +-
- arch/arm/boot/dts/bcm2838.dtsi | 4 ++--
- arch/arm/mach-bcm/board_bcm2835.c | 2 +-
- 4 files changed, 5 insertions(+), 5 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -5,7 +5,7 @@
- #include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
-- compatible = "raspberrypi,4-model-b", "brcm,bcm2838";
-+ compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
- model = "Raspberry Pi 4 Model B";
-
- memory@0 {
---- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-@@ -5,7 +5,7 @@
- #include "bcm2838-rpi.dtsi"
-
- / {
-- compatible = "raspberrypi,4-model-b", "brcm,bcm2838";
-+ compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
- model = "Raspberry Pi 4 Model B";
-
- chosen {
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -440,7 +440,7 @@
- };
-
- &clocks {
-- compatible = "brcm,bcm2838-cprman";
-+ compatible = "brcm,bcm2711-cprman";
- };
-
- &cpu_thermal {
-@@ -456,7 +456,7 @@
- };
-
- &gpio {
-- compatible = "brcm,bcm2838-gpio", "brcm,bcm2835-gpio";
-+ compatible = "brcm,bcm2711-gpio", "brcm,bcm2835-gpio";
-
- gpclk0_gpio49: gpclk0_gpio49 {
- brcm,pins = <49>;
---- a/arch/arm/mach-bcm/board_bcm2835.c
-+++ b/arch/arm/mach-bcm/board_bcm2835.c
-@@ -118,7 +118,7 @@ static const char * const bcm2835_compat
- #ifdef CONFIG_ARCH_MULTI_V7
- "brcm,bcm2836",
- "brcm,bcm2837",
-- "brcm,bcm2838",
-+ "brcm,bcm2711",
- #endif
- NULL
- };
--- /dev/null
+From 2729832886181a4f8bfe1e2c028a7bdb92004ce7 Mon Sep 17 00:00:00 2001
+Date: Sun, 3 Feb 2019 14:02:33 +0100
+Subject: [PATCH] pinctrl: bcm2835: declare pin config as generic
+
+commit 1cb66f080c27349fbf87fb327d587b4b0b624fa3 upstream.
+
+Since commit 0de704955ee44 ("pinctrl: bcm2835: Add support for
+generic pinctrl binding") this driver is capable to use the generic
+interface. So declare this accordingly.
+
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -969,6 +969,7 @@ static int bcm2835_pinconf_set(struct pi
+ }
+
+ static const struct pinconf_ops bcm2835_pinconf_ops = {
++ .is_generic = true,
+ .pin_config_get = bcm2835_pinconf_get,
+ .pin_config_set = bcm2835_pinconf_set,
+ };
--- /dev/null
+From 289685a9b369bda990c4f22bbc7659ad492e6dbb Mon Sep 17 00:00:00 2001
+Date: Sun, 3 Feb 2019 14:02:34 +0100
+Subject: [PATCH] pinctrl: bcm2835: Direct GPIO config changes to
+ generic pinctrl
+
+commit b6e5531c0f80de2779c87d0235b4fde5310a83b5 upstream.
+
+In order to support GPIO config changes direct these to the generic pinctrl.
+This also requires an adjust of the return code for unsupported parameter
+otherwise gpiod_configure_flags wont work as expected.
+
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -342,6 +342,7 @@ static const struct gpio_chip bcm2835_gp
+ .get = bcm2835_gpio_get,
+ .set = bcm2835_gpio_set,
+ .base = 0,
++ .set_config = gpiochip_generic_config,
+ .ngpio = BCM2835_NUM_GPIOS,
+ .can_sleep = false,
+ };
+@@ -960,7 +961,7 @@ static int bcm2835_pinconf_set(struct pi
+ break;
+
+ default:
+- return -EINVAL;
++ return -ENOTSUPP;
+
+ } /* switch param type */
+ } /* for each config */
+++ /dev/null
-From e60428993b9ba03e2389eeb61c4b5efaa80b9e05 Mon Sep 17 00:00:00 2001
-Date: Sat, 10 Nov 2018 17:15:11 +0100
-Subject: [PATCH] pinctrl: bcm2835: Switch to SPDX identifier
-
-commit a62c36775ba873611b00b82ce7ebcd4ff2126111 upstream.
-
-Adopt the SPDX license identifier headers to ease license compliance
-management.
-
----
- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 11 +----------
- include/dt-bindings/pinctrl/bcm2835.h | 8 +-------
- 2 files changed, 2 insertions(+), 17 deletions(-)
-
---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-@@ -1,3 +1,4 @@
-+// SPDX-License-Identifier: GPL-2.0+
- /*
- * Driver for Broadcom BCM2835 GPIO unit (pinctrl + GPIO)
- *
-@@ -6,16 +7,6 @@
- * This driver is inspired by:
- * pinctrl-nomadik.c, please see original file for copyright information
- * pinctrl-tegra.c, please see original file for copyright information
-- *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License as published by
-- * the Free Software Foundation; either version 2 of the License, or
-- * (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- * GNU General Public License for more details.
- */
-
- #include <linux/bitmap.h>
---- a/include/dt-bindings/pinctrl/bcm2835.h
-+++ b/include/dt-bindings/pinctrl/bcm2835.h
-@@ -1,14 +1,8 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
- /*
- * Header providing constants for bcm2835 pinctrl bindings.
- *
-- *
-- * The code contained herein is licensed under the GNU General Public
-- * License. You may obtain a copy of the GNU General Public License
-- * Version 2 at the following locations:
-- *
-- * http://www.opensource.org/licenses/gpl-license.html
-- * http://www.gnu.org/copyleft/gpl.html
- */
-
- #ifndef __DT_BINDINGS_PINCTRL_BCM2835_H__
--- /dev/null
+From 268bd5b5557ccb0ac4eae998ad7c6261c240b89b Mon Sep 17 00:00:00 2001
+Date: Sun, 21 Jul 2019 16:01:36 +0200
+Subject: [PATCH] pinctrl: bcm2835: Add support for BCM2711 pull-up
+ functionality
+
+commit e38a9a437fb93ddafab5030165e4c6a3a5021669 upstream.
+
+The BCM2711 has a new way of selecting the pull-up/pull-down setting
+for a GPIO pin. The registers used for the BCM2835, GP_PUD and
+GP_PUDCLKn0, are no longer connected. A new set of registers,
+GP_GPIO_PUP_PDN_CNTRL_REGx must be used. This commit will add
+a new compatible string "brcm,bcm2711-gpio" and the kernel
+driver will use it to select which method is used to select
+pull-up/pull-down.
+
+This patch based on a patch by Al Cooper which was intended for the
+BCM7211. This is a bugfixed and improved version.
+
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 105 ++++++++++++++++++++++++--
+ 1 file changed, 100 insertions(+), 5 deletions(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -57,15 +57,24 @@
+ #define GPAFEN0 0x88 /* Pin Async Falling Edge Detect */
+ #define GPPUD 0x94 /* Pin Pull-up/down Enable */
+ #define GPPUDCLK0 0x98 /* Pin Pull-up/down Enable Clock */
++#define GP_GPIO_PUP_PDN_CNTRL_REG0 0xe4 /* 2711 Pin Pull-up/down select */
+
+ #define FSEL_REG(p) (GPFSEL0 + (((p) / 10) * 4))
+ #define FSEL_SHIFT(p) (((p) % 10) * 3)
+ #define GPIO_REG_OFFSET(p) ((p) / 32)
+ #define GPIO_REG_SHIFT(p) ((p) % 32)
+
++#define PUD_2711_MASK 0x3
++#define PUD_2711_REG_OFFSET(p) ((p) / 16)
++#define PUD_2711_REG_SHIFT(p) (((p) % 16) * 2)
++
+ /* argument: bcm2835_pinconf_pull */
+ #define BCM2835_PINCONF_PARAM_PULL (PIN_CONFIG_END + 1)
+
++#define BCM2711_PULL_NONE 0x0
++#define BCM2711_PULL_UP 0x1
++#define BCM2711_PULL_DOWN 0x2
++
+ struct bcm2835_pinctrl {
+ struct device *dev;
+ void __iomem *base;
+@@ -975,6 +984,77 @@ static const struct pinconf_ops bcm2835_
+ .pin_config_set = bcm2835_pinconf_set,
+ };
+
++static void bcm2711_pull_config_set(struct bcm2835_pinctrl *pc,
++ unsigned int pin, unsigned int arg)
++{
++ u32 shifter;
++ u32 value;
++ u32 off;
++
++ off = PUD_2711_REG_OFFSET(pin);
++ shifter = PUD_2711_REG_SHIFT(pin);
++
++ value = bcm2835_gpio_rd(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (off * 4));
++ value &= ~(PUD_2711_MASK << shifter);
++ value |= (arg << shifter);
++ bcm2835_gpio_wr(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (off * 4), value);
++}
++
++static int bcm2711_pinconf_set(struct pinctrl_dev *pctldev,
++ unsigned int pin, unsigned long *configs,
++ unsigned int num_configs)
++{
++ struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
++ u32 param, arg;
++ int i;
++
++ for (i = 0; i < num_configs; i++) {
++ param = pinconf_to_config_param(configs[i]);
++ arg = pinconf_to_config_argument(configs[i]);
++
++ switch (param) {
++ /* convert legacy brcm,pull */
++ case BCM2835_PINCONF_PARAM_PULL:
++ if (arg == BCM2835_PUD_UP)
++ arg = BCM2711_PULL_UP;
++ else if (arg == BCM2835_PUD_DOWN)
++ arg = BCM2711_PULL_DOWN;
++ else
++ arg = BCM2711_PULL_NONE;
++
++ bcm2711_pull_config_set(pc, pin, arg);
++ break;
++
++ /* Set pull generic bindings */
++ case PIN_CONFIG_BIAS_DISABLE:
++ bcm2711_pull_config_set(pc, pin, BCM2711_PULL_NONE);
++ break;
++ case PIN_CONFIG_BIAS_PULL_DOWN:
++ bcm2711_pull_config_set(pc, pin, BCM2711_PULL_DOWN);
++ break;
++ case PIN_CONFIG_BIAS_PULL_UP:
++ bcm2711_pull_config_set(pc, pin, BCM2711_PULL_UP);
++ break;
++
++ /* Set output-high or output-low */
++ case PIN_CONFIG_OUTPUT:
++ bcm2835_gpio_set_bit(pc, arg ? GPSET0 : GPCLR0, pin);
++ break;
++
++ default:
++ return -ENOTSUPP;
++ }
++ } /* for each config */
++
++ return 0;
++}
++
++static const struct pinconf_ops bcm2711_pinconf_ops = {
++ .is_generic = true,
++ .pin_config_get = bcm2835_pinconf_get,
++ .pin_config_set = bcm2711_pinconf_set,
++};
++
+ static struct pinctrl_desc bcm2835_pinctrl_desc = {
+ .name = MODULE_NAME,
+ .pins = bcm2835_gpio_pins,
+@@ -990,6 +1070,18 @@ static struct pinctrl_gpio_range bcm2835
+ .npins = BCM2835_NUM_GPIOS,
+ };
+
++static const struct of_device_id bcm2835_pinctrl_match[] = {
++ {
++ .compatible = "brcm,bcm2835-gpio",
++ .data = &bcm2835_pinconf_ops,
++ },
++ {
++ .compatible = "brcm,bcm2711-gpio",
++ .data = &bcm2711_pinconf_ops,
++ },
++ {}
++};
++
+ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -997,6 +1089,8 @@ static int bcm2835_pinctrl_probe(struct
+ struct bcm2835_pinctrl *pc;
+ struct resource iomem;
+ int err, i;
++ const struct of_device_id *match;
++
+ BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_pins) != BCM2835_NUM_GPIOS);
+ BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_groups) != BCM2835_NUM_GPIOS);
+
+@@ -1073,6 +1167,12 @@ static int bcm2835_pinctrl_probe(struct
+ bcm2835_gpio_irq_handler);
+ }
+
++ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
++ if (match) {
++ bcm2835_pinctrl_desc.confops =
++ (const struct pinconf_ops *)match->data;
++ }
++
+ pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
+ if (IS_ERR(pc->pctl_dev)) {
+ gpiochip_remove(&pc->gpio_chip);
+@@ -1087,11 +1187,6 @@ static int bcm2835_pinctrl_probe(struct
+ return 0;
+ }
+
+-static const struct of_device_id bcm2835_pinctrl_match[] = {
+- { .compatible = "brcm,bcm2835-gpio" },
+- {}
+-};
+-
+ static struct platform_driver bcm2835_pinctrl_driver = {
+ .probe = bcm2835_pinctrl_probe,
+ .driver = {
+++ /dev/null
-From 2729832886181a4f8bfe1e2c028a7bdb92004ce7 Mon Sep 17 00:00:00 2001
-Date: Sun, 3 Feb 2019 14:02:33 +0100
-Subject: [PATCH] pinctrl: bcm2835: declare pin config as generic
-
-commit 1cb66f080c27349fbf87fb327d587b4b0b624fa3 upstream.
-
-Since commit 0de704955ee44 ("pinctrl: bcm2835: Add support for
-generic pinctrl binding") this driver is capable to use the generic
-interface. So declare this accordingly.
-
----
- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-@@ -969,6 +969,7 @@ static int bcm2835_pinconf_set(struct pi
- }
-
- static const struct pinconf_ops bcm2835_pinconf_ops = {
-+ .is_generic = true,
- .pin_config_get = bcm2835_pinconf_get,
- .pin_config_set = bcm2835_pinconf_set,
- };
--- /dev/null
+From 1ed6ab5bf2180bd96a78f27fde848f57f4d6b636 Mon Sep 17 00:00:00 2001
+Date: Tue, 24 Sep 2019 18:26:55 +0100
+Subject: [PATCH] Rename HDMI ALSA device names, check for enable state
+
+HDMI Alsa devices renamed to match names used by DRM, to
+HDMI 1 and HDMI 2
+
+Check for which HDMI devices are connected and only create
+devices for those that are present.
+
+The rename of the devices might cause some backwards compatibility
+issues, but since this particular part of the driver needs to be
+specifically enabled, I suspect the number of people who will see
+the problem will be very small.
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835.c | 70 +++++++++++++++++--
+ 1 file changed, 63 insertions(+), 7 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -9,8 +9,9 @@
+ #include <linux/of.h>
+
+ #include "bcm2835.h"
++#include <soc/bcm2835/raspberrypi-firmware.h>
+
+-static bool enable_hdmi;
++static bool enable_hdmi, enable_hdmi0, enable_hdmi1;
+ static bool enable_headphones;
+ static bool enable_compat_alsa = true;
+
+@@ -115,8 +116,8 @@ static struct bcm2835_audio_driver bcm28
+ .name = "bcm2835_hdmi",
+ .owner = THIS_MODULE,
+ },
+- .shortname = "bcm2835 HDMI",
+- .longname = "bcm2835 HDMI",
++ .shortname = "bcm2835 HDMI 1",
++ .longname = "bcm2835 HDMI 1",
+ .minchannels = 1,
+ .newpcm = bcm2835_audio_simple_newpcm,
+ .newctl = snd_bcm2835_new_hdmi_ctl,
+@@ -128,8 +129,8 @@ static struct bcm2835_audio_driver bcm28
+ .name = "bcm2835_hdmi",
+ .owner = THIS_MODULE,
+ },
+- .shortname = "bcm2835 HDMI 1",
+- .longname = "bcm2835 HDMI 1",
++ .shortname = "bcm2835 HDMI 2",
++ .longname = "bcm2835 HDMI 2",
+ .minchannels = 1,
+ .newpcm = bcm2835_audio_simple_newpcm,
+ .newctl = snd_bcm2835_new_hdmi_ctl,
+@@ -161,11 +162,11 @@ static struct bcm2835_audio_drivers chil
+ },
+ {
+ .audio_driver = &bcm2835_audio_hdmi0,
+- .is_enabled = &enable_hdmi,
++ .is_enabled = &enable_hdmi0,
+ },
+ {
+ .audio_driver = &bcm2835_audio_hdmi1,
+- .is_enabled = &enable_hdmi,
++ .is_enabled = &enable_hdmi1,
+ },
+ {
+ .audio_driver = &bcm2835_audio_headphones,
+@@ -312,6 +313,53 @@ static int snd_add_child_devices(struct
+ return 0;
+ }
+
++static void set_hdmi_enables(struct device *dev)
++{
++ struct device_node *firmware_node;
++ struct rpi_firmware *firmware;
++ u32 num_displays, i, display_id;
++ int ret;
++
++ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
++ firmware = rpi_firmware_get(firmware_node);
++
++ if (!firmware)
++ return;
++
++ of_node_put(firmware_node);
++
++ ret = rpi_firmware_property(firmware,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
++ &num_displays, sizeof(u32));
++
++ if (ret)
++ return;
++
++ for (i = 0; i < num_displays; i++) {
++ display_id = i;
++ ret = rpi_firmware_property(firmware,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
++ &display_id, sizeof(display_id));
++ if (!ret) {
++ if (display_id == 2)
++ enable_hdmi0 = true;
++ if (display_id == 7)
++ enable_hdmi1 = true;
++ }
++ }
++
++ if (!enable_hdmi0 && enable_hdmi1) {
++ /* Swap them over and reassign route. This means
++ * that if we only have one connected, it is always named
++ * HDMI1, irrespective of if its on port HDMI0 or HDMI1.
++ * This should match with the naming of HDMI ports in DRM
++ */
++ enable_hdmi0 = true;
++ enable_hdmi1 = false;
++ bcm2835_audio_hdmi0.route = AUDIO_DEST_HDMI1;
++ }
++}
++
+ static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -332,6 +380,14 @@ static int snd_bcm2835_alsa_probe(struct
+ numchans);
+ }
+
++ if (!enable_compat_alsa) {
++ set_hdmi_enables(dev);
++ // In this mode, always enable analog output
++ enable_headphones = true;
++ } else {
++ enable_hdmi0 = enable_hdmi;
++ }
++
+ err = bcm2835_devm_add_vchi_ctx(dev);
+ if (err)
+ return err;
+++ /dev/null
-From 289685a9b369bda990c4f22bbc7659ad492e6dbb Mon Sep 17 00:00:00 2001
-Date: Sun, 3 Feb 2019 14:02:34 +0100
-Subject: [PATCH] pinctrl: bcm2835: Direct GPIO config changes to
- generic pinctrl
-
-commit b6e5531c0f80de2779c87d0235b4fde5310a83b5 upstream.
-
-In order to support GPIO config changes direct these to the generic pinctrl.
-This also requires an adjust of the return code for unsupported parameter
-otherwise gpiod_configure_flags wont work as expected.
-
----
- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-@@ -342,6 +342,7 @@ static const struct gpio_chip bcm2835_gp
- .get = bcm2835_gpio_get,
- .set = bcm2835_gpio_set,
- .base = 0,
-+ .set_config = gpiochip_generic_config,
- .ngpio = BCM2835_NUM_GPIOS,
- .can_sleep = false,
- };
-@@ -960,7 +961,7 @@ static int bcm2835_pinconf_set(struct pi
- break;
-
- default:
-- return -EINVAL;
-+ return -ENOTSUPP;
-
- } /* switch param type */
- } /* for each config */
--- /dev/null
+From 592f7ebf2755acc81cd794b73916f3b2bcccaa68 Mon Sep 17 00:00:00 2001
+Date: Fri, 4 Oct 2019 16:41:30 +0200
+Subject: [PATCH] pcie-brcmstb-bounce64.c: dev_err() -> dev_info() for
+ info messages
+
+"dmabounce: initialised" is not an error, so do not log it as such.
+Prevents screen polution on OS with "quiet" as kernel parameter.
+
+Closes #3266
+---
+ drivers/pci/controller/pcie-brcmstb-bounce64.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pci/controller/pcie-brcmstb-bounce64.c
++++ b/drivers/pci/controller/pcie-brcmstb-bounce64.c
+@@ -524,7 +524,7 @@ int brcm_pcie_bounce_init(struct device
+
+ g_dmabounce_device_info = device_info;
+
+- dev_err(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
++ dev_info(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
+ buffer_size / 1024, &threshold);
+
+ return 0;
+++ /dev/null
-From 268bd5b5557ccb0ac4eae998ad7c6261c240b89b Mon Sep 17 00:00:00 2001
-Date: Sun, 21 Jul 2019 16:01:36 +0200
-Subject: [PATCH] pinctrl: bcm2835: Add support for BCM2711 pull-up
- functionality
-
-commit e38a9a437fb93ddafab5030165e4c6a3a5021669 upstream.
-
-The BCM2711 has a new way of selecting the pull-up/pull-down setting
-for a GPIO pin. The registers used for the BCM2835, GP_PUD and
-GP_PUDCLKn0, are no longer connected. A new set of registers,
-GP_GPIO_PUP_PDN_CNTRL_REGx must be used. This commit will add
-a new compatible string "brcm,bcm2711-gpio" and the kernel
-driver will use it to select which method is used to select
-pull-up/pull-down.
-
-This patch based on a patch by Al Cooper which was intended for the
-BCM7211. This is a bugfixed and improved version.
-
----
- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 105 ++++++++++++++++++++++++--
- 1 file changed, 100 insertions(+), 5 deletions(-)
-
---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-@@ -57,15 +57,24 @@
- #define GPAFEN0 0x88 /* Pin Async Falling Edge Detect */
- #define GPPUD 0x94 /* Pin Pull-up/down Enable */
- #define GPPUDCLK0 0x98 /* Pin Pull-up/down Enable Clock */
-+#define GP_GPIO_PUP_PDN_CNTRL_REG0 0xe4 /* 2711 Pin Pull-up/down select */
-
- #define FSEL_REG(p) (GPFSEL0 + (((p) / 10) * 4))
- #define FSEL_SHIFT(p) (((p) % 10) * 3)
- #define GPIO_REG_OFFSET(p) ((p) / 32)
- #define GPIO_REG_SHIFT(p) ((p) % 32)
-
-+#define PUD_2711_MASK 0x3
-+#define PUD_2711_REG_OFFSET(p) ((p) / 16)
-+#define PUD_2711_REG_SHIFT(p) (((p) % 16) * 2)
-+
- /* argument: bcm2835_pinconf_pull */
- #define BCM2835_PINCONF_PARAM_PULL (PIN_CONFIG_END + 1)
-
-+#define BCM2711_PULL_NONE 0x0
-+#define BCM2711_PULL_UP 0x1
-+#define BCM2711_PULL_DOWN 0x2
-+
- struct bcm2835_pinctrl {
- struct device *dev;
- void __iomem *base;
-@@ -975,6 +984,77 @@ static const struct pinconf_ops bcm2835_
- .pin_config_set = bcm2835_pinconf_set,
- };
-
-+static void bcm2711_pull_config_set(struct bcm2835_pinctrl *pc,
-+ unsigned int pin, unsigned int arg)
-+{
-+ u32 shifter;
-+ u32 value;
-+ u32 off;
-+
-+ off = PUD_2711_REG_OFFSET(pin);
-+ shifter = PUD_2711_REG_SHIFT(pin);
-+
-+ value = bcm2835_gpio_rd(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (off * 4));
-+ value &= ~(PUD_2711_MASK << shifter);
-+ value |= (arg << shifter);
-+ bcm2835_gpio_wr(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (off * 4), value);
-+}
-+
-+static int bcm2711_pinconf_set(struct pinctrl_dev *pctldev,
-+ unsigned int pin, unsigned long *configs,
-+ unsigned int num_configs)
-+{
-+ struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
-+ u32 param, arg;
-+ int i;
-+
-+ for (i = 0; i < num_configs; i++) {
-+ param = pinconf_to_config_param(configs[i]);
-+ arg = pinconf_to_config_argument(configs[i]);
-+
-+ switch (param) {
-+ /* convert legacy brcm,pull */
-+ case BCM2835_PINCONF_PARAM_PULL:
-+ if (arg == BCM2835_PUD_UP)
-+ arg = BCM2711_PULL_UP;
-+ else if (arg == BCM2835_PUD_DOWN)
-+ arg = BCM2711_PULL_DOWN;
-+ else
-+ arg = BCM2711_PULL_NONE;
-+
-+ bcm2711_pull_config_set(pc, pin, arg);
-+ break;
-+
-+ /* Set pull generic bindings */
-+ case PIN_CONFIG_BIAS_DISABLE:
-+ bcm2711_pull_config_set(pc, pin, BCM2711_PULL_NONE);
-+ break;
-+ case PIN_CONFIG_BIAS_PULL_DOWN:
-+ bcm2711_pull_config_set(pc, pin, BCM2711_PULL_DOWN);
-+ break;
-+ case PIN_CONFIG_BIAS_PULL_UP:
-+ bcm2711_pull_config_set(pc, pin, BCM2711_PULL_UP);
-+ break;
-+
-+ /* Set output-high or output-low */
-+ case PIN_CONFIG_OUTPUT:
-+ bcm2835_gpio_set_bit(pc, arg ? GPSET0 : GPCLR0, pin);
-+ break;
-+
-+ default:
-+ return -ENOTSUPP;
-+ }
-+ } /* for each config */
-+
-+ return 0;
-+}
-+
-+static const struct pinconf_ops bcm2711_pinconf_ops = {
-+ .is_generic = true,
-+ .pin_config_get = bcm2835_pinconf_get,
-+ .pin_config_set = bcm2711_pinconf_set,
-+};
-+
- static struct pinctrl_desc bcm2835_pinctrl_desc = {
- .name = MODULE_NAME,
- .pins = bcm2835_gpio_pins,
-@@ -990,6 +1070,18 @@ static struct pinctrl_gpio_range bcm2835
- .npins = BCM2835_NUM_GPIOS,
- };
-
-+static const struct of_device_id bcm2835_pinctrl_match[] = {
-+ {
-+ .compatible = "brcm,bcm2835-gpio",
-+ .data = &bcm2835_pinconf_ops,
-+ },
-+ {
-+ .compatible = "brcm,bcm2711-gpio",
-+ .data = &bcm2711_pinconf_ops,
-+ },
-+ {}
-+};
-+
- static int bcm2835_pinctrl_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
-@@ -997,6 +1089,8 @@ static int bcm2835_pinctrl_probe(struct
- struct bcm2835_pinctrl *pc;
- struct resource iomem;
- int err, i;
-+ const struct of_device_id *match;
-+
- BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_pins) != BCM2835_NUM_GPIOS);
- BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_groups) != BCM2835_NUM_GPIOS);
-
-@@ -1073,6 +1167,12 @@ static int bcm2835_pinctrl_probe(struct
- bcm2835_gpio_irq_handler);
- }
-
-+ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
-+ if (match) {
-+ bcm2835_pinctrl_desc.confops =
-+ (const struct pinconf_ops *)match->data;
-+ }
-+
- pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
- if (IS_ERR(pc->pctl_dev)) {
- gpiochip_remove(&pc->gpio_chip);
-@@ -1087,11 +1187,6 @@ static int bcm2835_pinctrl_probe(struct
- return 0;
- }
-
--static const struct of_device_id bcm2835_pinctrl_match[] = {
-- { .compatible = "brcm,bcm2835-gpio" },
-- {}
--};
--
- static struct platform_driver bcm2835_pinctrl_driver = {
- .probe = bcm2835_pinctrl_probe,
- .driver = {
+++ /dev/null
-From 1ed6ab5bf2180bd96a78f27fde848f57f4d6b636 Mon Sep 17 00:00:00 2001
-Date: Tue, 24 Sep 2019 18:26:55 +0100
-Subject: [PATCH] Rename HDMI ALSA device names, check for enable state
-
-HDMI Alsa devices renamed to match names used by DRM, to
-HDMI 1 and HDMI 2
-
-Check for which HDMI devices are connected and only create
-devices for those that are present.
-
-The rename of the devices might cause some backwards compatibility
-issues, but since this particular part of the driver needs to be
-specifically enabled, I suspect the number of people who will see
-the problem will be very small.
-
----
- .../vc04_services/bcm2835-audio/bcm2835.c | 70 +++++++++++++++++--
- 1 file changed, 63 insertions(+), 7 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -9,8 +9,9 @@
- #include <linux/of.h>
-
- #include "bcm2835.h"
-+#include <soc/bcm2835/raspberrypi-firmware.h>
-
--static bool enable_hdmi;
-+static bool enable_hdmi, enable_hdmi0, enable_hdmi1;
- static bool enable_headphones;
- static bool enable_compat_alsa = true;
-
-@@ -115,8 +116,8 @@ static struct bcm2835_audio_driver bcm28
- .name = "bcm2835_hdmi",
- .owner = THIS_MODULE,
- },
-- .shortname = "bcm2835 HDMI",
-- .longname = "bcm2835 HDMI",
-+ .shortname = "bcm2835 HDMI 1",
-+ .longname = "bcm2835 HDMI 1",
- .minchannels = 1,
- .newpcm = bcm2835_audio_simple_newpcm,
- .newctl = snd_bcm2835_new_hdmi_ctl,
-@@ -128,8 +129,8 @@ static struct bcm2835_audio_driver bcm28
- .name = "bcm2835_hdmi",
- .owner = THIS_MODULE,
- },
-- .shortname = "bcm2835 HDMI 1",
-- .longname = "bcm2835 HDMI 1",
-+ .shortname = "bcm2835 HDMI 2",
-+ .longname = "bcm2835 HDMI 2",
- .minchannels = 1,
- .newpcm = bcm2835_audio_simple_newpcm,
- .newctl = snd_bcm2835_new_hdmi_ctl,
-@@ -161,11 +162,11 @@ static struct bcm2835_audio_drivers chil
- },
- {
- .audio_driver = &bcm2835_audio_hdmi0,
-- .is_enabled = &enable_hdmi,
-+ .is_enabled = &enable_hdmi0,
- },
- {
- .audio_driver = &bcm2835_audio_hdmi1,
-- .is_enabled = &enable_hdmi,
-+ .is_enabled = &enable_hdmi1,
- },
- {
- .audio_driver = &bcm2835_audio_headphones,
-@@ -312,6 +313,53 @@ static int snd_add_child_devices(struct
- return 0;
- }
-
-+static void set_hdmi_enables(struct device *dev)
-+{
-+ struct device_node *firmware_node;
-+ struct rpi_firmware *firmware;
-+ u32 num_displays, i, display_id;
-+ int ret;
-+
-+ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
-+ firmware = rpi_firmware_get(firmware_node);
-+
-+ if (!firmware)
-+ return;
-+
-+ of_node_put(firmware_node);
-+
-+ ret = rpi_firmware_property(firmware,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
-+ &num_displays, sizeof(u32));
-+
-+ if (ret)
-+ return;
-+
-+ for (i = 0; i < num_displays; i++) {
-+ display_id = i;
-+ ret = rpi_firmware_property(firmware,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
-+ &display_id, sizeof(display_id));
-+ if (!ret) {
-+ if (display_id == 2)
-+ enable_hdmi0 = true;
-+ if (display_id == 7)
-+ enable_hdmi1 = true;
-+ }
-+ }
-+
-+ if (!enable_hdmi0 && enable_hdmi1) {
-+ /* Swap them over and reassign route. This means
-+ * that if we only have one connected, it is always named
-+ * HDMI1, irrespective of if its on port HDMI0 or HDMI1.
-+ * This should match with the naming of HDMI ports in DRM
-+ */
-+ enable_hdmi0 = true;
-+ enable_hdmi1 = false;
-+ bcm2835_audio_hdmi0.route = AUDIO_DEST_HDMI1;
-+ }
-+}
-+
- static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
-@@ -332,6 +380,14 @@ static int snd_bcm2835_alsa_probe(struct
- numchans);
- }
-
-+ if (!enable_compat_alsa) {
-+ set_hdmi_enables(dev);
-+ // In this mode, always enable analog output
-+ enable_headphones = true;
-+ } else {
-+ enable_hdmi0 = enable_hdmi;
-+ }
-+
- err = bcm2835_devm_add_vchi_ctx(dev);
- if (err)
- return err;
--- /dev/null
+From 499e28e3a38f0de843b07bf4bbf7692b07c5e3ba Mon Sep 17 00:00:00 2001
+Date: Mon, 7 Oct 2019 13:51:07 +0100
+Subject: [PATCH] overlays: gpio-shutdown: Add debounce parameter
+
+Give the gpio-shutdown overlay a debounce parameter that requires
+the GPIO to be held at the relevant level for a specified number
+of milliseconds. The default value is 100 - higher than the driver
+default of 5ms to avoid unfortunate glitches.
+
+See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=253680
+
+---
+ arch/arm/boot/dts/overlays/README | 3 +++
+ arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts | 2 ++
+ 2 files changed, 5 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -803,6 +803,9 @@ Params: gpio_pin GPIO pin
+ Note that the default pin (GPIO3) has an
+ external pullup.
+
++ debounce Specify the debounce interval in milliseconds
++ (default 100)
++
+
+ Name: hd44780-lcd
+ Info: Configures an HD44780 compatible LCD display. Uses 4 gpio pins for
+--- a/arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts
+@@ -53,6 +53,7 @@
+ label = "shutdown";
+ linux,code = <116>; // KEY_POWER
+ gpios = <&gpio 3 1>;
++ debounce-interval = <100>; // ms
+ };
+ };
+ };
+@@ -75,6 +76,7 @@
+
+ // Allow setting the active_low flag. 0 = active high, 1 = active low
+ active_low = <&button>,"gpios:8";
++ debounce = <&button>,"debounce-interval:0";
+ };
+
+ };
--- /dev/null
+From 8ad712b22e410a5d13bc6678fbee4a5b0ec9b518 Mon Sep 17 00:00:00 2001
+Date: Wed, 2 Oct 2019 18:41:32 +0200
+Subject: [PATCH] overlays: fix compatible for RPi4
+
+RPi4 compatible is now bcm2711, but some overlays refer to the SoC as
+bcm2838. Fix this overlays as they otherwise won't apply.
+
+---
+ arch/arm/boot/dts/overlays/i2c3-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c4-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c5-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/i2c6-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/uart2-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/uart3-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/uart4-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/uart5-overlay.dts | 2 +-
+ 16 files changed, 16 insertions(+), 16 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/i2c3-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c3-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&i2c3>;
+--- a/arch/arm/boot/dts/overlays/i2c4-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c4-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&i2c4>;
+--- a/arch/arm/boot/dts/overlays/i2c5-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c5-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&i2c5>;
+--- a/arch/arm/boot/dts/overlays/i2c6-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c6-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&i2c6>;
+--- a/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&spi3_cs_pins>;
+--- a/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&spi3_cs_pins>;
+--- a/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&spi4_cs_pins>;
+--- a/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&spi4_cs_pins>;
+--- a/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&spi5_cs_pins>;
+--- a/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&spi5_cs_pins>;
+--- a/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&spi6_cs_pins>;
+--- a/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts
++++ b/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts
+@@ -3,7 +3,7 @@
+
+
+ / {
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&spi6_cs_pins>;
+--- a/arch/arm/boot/dts/overlays/uart2-overlay.dts
++++ b/arch/arm/boot/dts/overlays/uart2-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&uart2>;
+--- a/arch/arm/boot/dts/overlays/uart3-overlay.dts
++++ b/arch/arm/boot/dts/overlays/uart3-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&uart3>;
+--- a/arch/arm/boot/dts/overlays/uart4-overlay.dts
++++ b/arch/arm/boot/dts/overlays/uart4-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&uart4>;
+--- a/arch/arm/boot/dts/overlays/uart5-overlay.dts
++++ b/arch/arm/boot/dts/overlays/uart5-overlay.dts
+@@ -2,7 +2,7 @@
+ /plugin/;
+
+ /{
+- compatible = "brcm,bcm2838";
++ compatible = "brcm,bcm2711";
+
+ fragment@0 {
+ target = <&uart5>;
+++ /dev/null
-From 592f7ebf2755acc81cd794b73916f3b2bcccaa68 Mon Sep 17 00:00:00 2001
-Date: Fri, 4 Oct 2019 16:41:30 +0200
-Subject: [PATCH] pcie-brcmstb-bounce64.c: dev_err() -> dev_info() for
- info messages
-
-"dmabounce: initialised" is not an error, so do not log it as such.
-Prevents screen polution on OS with "quiet" as kernel parameter.
-
-Closes #3266
----
- drivers/pci/controller/pcie-brcmstb-bounce64.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/pci/controller/pcie-brcmstb-bounce64.c
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce64.c
-@@ -524,7 +524,7 @@ int brcm_pcie_bounce_init(struct device
-
- g_dmabounce_device_info = device_info;
-
-- dev_err(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
-+ dev_info(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
- buffer_size / 1024, &threshold);
-
- return 0;
--- /dev/null
+From 7d7f6a80f12fb6e7ba903d070512970e304bcd02 Mon Sep 17 00:00:00 2001
+Date: Wed, 9 Oct 2019 17:22:07 +0100
+Subject: [PATCH] bcm2711: Retain support for old dtbs
+
+The recent series switching to bcm2711 as the DT identifier broke Pis
+running with old DTBs. Add some bcm2838 compatible strings as a
+temporary measure, at least until the next full Raspbian image with
+bcm2711 DTBs.
+
+See: https://github.com/raspberrypi/linux/pull/3244
+
+---
+ arch/arm/mach-bcm/board_bcm2835.c | 2 ++
+ drivers/clk/bcm/clk-bcm2835.c | 2 ++
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 5 +++++
+ 3 files changed, 9 insertions(+)
+
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -119,6 +119,8 @@ static const char * const bcm2835_compat
+ "brcm,bcm2836",
+ "brcm,bcm2837",
+ "brcm,bcm2711",
++ // Temporary, for backwards-compatibility with old DTBs
++ "brcm,bcm2838",
+ #endif
+ NULL
+ };
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -2396,6 +2396,8 @@ static const struct cprman_plat_data cpr
+ static const struct of_device_id bcm2835_clk_of_match[] = {
+ { .compatible = "brcm,bcm2835-cprman", .data = &cprman_bcm2835_plat_data },
+ { .compatible = "brcm,bcm2711-cprman", .data = &cprman_bcm2711_plat_data },
++ // Temporary, for backwards-compatibility with old DTBs
++ { .compatible = "brcm,bcm2838-cprman", .data = &cprman_bcm2711_plat_data },
+ {}
+ };
+ MODULE_DEVICE_TABLE(of, bcm2835_clk_of_match);
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -1079,6 +1079,11 @@ static const struct of_device_id bcm2835
+ .compatible = "brcm,bcm2711-gpio",
+ .data = &bcm2711_pinconf_ops,
+ },
++ // Temporary, for backwards-compatibility with old DTBs
++ {
++ .compatible = "brcm,bcm2838-gpio",
++ .data = &bcm2711_pinconf_ops,
++ },
+ {}
+ };
+
+++ /dev/null
-From 499e28e3a38f0de843b07bf4bbf7692b07c5e3ba Mon Sep 17 00:00:00 2001
-Date: Mon, 7 Oct 2019 13:51:07 +0100
-Subject: [PATCH] overlays: gpio-shutdown: Add debounce parameter
-
-Give the gpio-shutdown overlay a debounce parameter that requires
-the GPIO to be held at the relevant level for a specified number
-of milliseconds. The default value is 100 - higher than the driver
-default of 5ms to avoid unfortunate glitches.
-
-See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=253680
-
----
- arch/arm/boot/dts/overlays/README | 3 +++
- arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts | 2 ++
- 2 files changed, 5 insertions(+)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -803,6 +803,9 @@ Params: gpio_pin GPIO pin
- Note that the default pin (GPIO3) has an
- external pullup.
-
-+ debounce Specify the debounce interval in milliseconds
-+ (default 100)
-+
-
- Name: hd44780-lcd
- Info: Configures an HD44780 compatible LCD display. Uses 4 gpio pins for
---- a/arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/gpio-shutdown-overlay.dts
-@@ -53,6 +53,7 @@
- label = "shutdown";
- linux,code = <116>; // KEY_POWER
- gpios = <&gpio 3 1>;
-+ debounce-interval = <100>; // ms
- };
- };
- };
-@@ -75,6 +76,7 @@
-
- // Allow setting the active_low flag. 0 = active high, 1 = active low
- active_low = <&button>,"gpios:8";
-+ debounce = <&button>,"debounce-interval:0";
- };
-
- };
--- /dev/null
+From 13b916fa2b8a99c9953073316e102e9d027dd708 Mon Sep 17 00:00:00 2001
+Date: Wed, 2 Oct 2019 16:09:24 +0100
+Subject: [PATCH] media: bcm2835-unicam: Add support for raw14 formats
+
+The V4L2 has gained defines for V4L2_PIX_FMT_Sxxxx14P,
+therefore add support for it to bcm2835-unicam.
+
+---
+ .../media/platform/bcm2835/bcm2835-unicam.c | 25 +++++++++++++++++--
+ 1 file changed, 23 insertions(+), 2 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
+@@ -273,10 +273,31 @@ static const struct unicam_fmt formats[]
+ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .depth = 12,
+ .csi_dt = 0x2c,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SBGGR14P,
++ .code = MEDIA_BUS_FMT_SBGGR14_1X14,
++ .depth = 14,
++ .csi_dt = 0x2d,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SGBRG14P,
++ .code = MEDIA_BUS_FMT_SGBRG14_1X14,
++ .depth = 14,
++ .csi_dt = 0x2d,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SGRBG14P,
++ .code = MEDIA_BUS_FMT_SGRBG14_1X14,
++ .depth = 14,
++ .csi_dt = 0x2d,
++ }, {
++ .fourcc = V4L2_PIX_FMT_SRGGB14P,
++ .code = MEDIA_BUS_FMT_SRGGB14_1X14,
++ .depth = 14,
++ .csi_dt = 0x2d,
+ },
+ /*
+- * 14 and 16 bit Bayer formats could be supported, but there are no V4L2
+- * defines for 14bit packed Bayer, and no CSI2 data_type for raw 16.
++ * 16 bit Bayer formats could be supported, but there is no CSI2
++ * data_type defined for raw 16, and no sensors that produce it at
++ * present.
+ */
+ };
+
+++ /dev/null
-From 8ad712b22e410a5d13bc6678fbee4a5b0ec9b518 Mon Sep 17 00:00:00 2001
-Date: Wed, 2 Oct 2019 18:41:32 +0200
-Subject: [PATCH] overlays: fix compatible for RPi4
-
-RPi4 compatible is now bcm2711, but some overlays refer to the SoC as
-bcm2838. Fix this overlays as they otherwise won't apply.
-
----
- arch/arm/boot/dts/overlays/i2c3-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c4-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c5-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/i2c6-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/uart2-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/uart3-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/uart4-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/uart5-overlay.dts | 2 +-
- 16 files changed, 16 insertions(+), 16 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/i2c3-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c3-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&i2c3>;
---- a/arch/arm/boot/dts/overlays/i2c4-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c4-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&i2c4>;
---- a/arch/arm/boot/dts/overlays/i2c5-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c5-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&i2c5>;
---- a/arch/arm/boot/dts/overlays/i2c6-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c6-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&i2c6>;
---- a/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi3-1cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&spi3_cs_pins>;
---- a/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi3-2cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&spi3_cs_pins>;
---- a/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi4-1cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&spi4_cs_pins>;
---- a/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi4-2cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&spi4_cs_pins>;
---- a/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi5-1cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&spi5_cs_pins>;
---- a/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi5-2cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&spi5_cs_pins>;
---- a/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi6-1cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&spi6_cs_pins>;
---- a/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/spi6-2cs-overlay.dts
-@@ -3,7 +3,7 @@
-
-
- / {
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&spi6_cs_pins>;
---- a/arch/arm/boot/dts/overlays/uart2-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/uart2-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&uart2>;
---- a/arch/arm/boot/dts/overlays/uart3-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/uart3-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&uart3>;
---- a/arch/arm/boot/dts/overlays/uart4-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/uart4-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&uart4>;
---- a/arch/arm/boot/dts/overlays/uart5-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/uart5-overlay.dts
-@@ -2,7 +2,7 @@
- /plugin/;
-
- /{
-- compatible = "brcm,bcm2838";
-+ compatible = "brcm,bcm2711";
-
- fragment@0 {
- target = <&uart5>;
+++ /dev/null
-From 7d7f6a80f12fb6e7ba903d070512970e304bcd02 Mon Sep 17 00:00:00 2001
-Date: Wed, 9 Oct 2019 17:22:07 +0100
-Subject: [PATCH] bcm2711: Retain support for old dtbs
-
-The recent series switching to bcm2711 as the DT identifier broke Pis
-running with old DTBs. Add some bcm2838 compatible strings as a
-temporary measure, at least until the next full Raspbian image with
-bcm2711 DTBs.
-
-See: https://github.com/raspberrypi/linux/pull/3244
-
----
- arch/arm/mach-bcm/board_bcm2835.c | 2 ++
- drivers/clk/bcm/clk-bcm2835.c | 2 ++
- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 5 +++++
- 3 files changed, 9 insertions(+)
-
---- a/arch/arm/mach-bcm/board_bcm2835.c
-+++ b/arch/arm/mach-bcm/board_bcm2835.c
-@@ -119,6 +119,8 @@ static const char * const bcm2835_compat
- "brcm,bcm2836",
- "brcm,bcm2837",
- "brcm,bcm2711",
-+ // Temporary, for backwards-compatibility with old DTBs
-+ "brcm,bcm2838",
- #endif
- NULL
- };
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -2396,6 +2396,8 @@ static const struct cprman_plat_data cpr
- static const struct of_device_id bcm2835_clk_of_match[] = {
- { .compatible = "brcm,bcm2835-cprman", .data = &cprman_bcm2835_plat_data },
- { .compatible = "brcm,bcm2711-cprman", .data = &cprman_bcm2711_plat_data },
-+ // Temporary, for backwards-compatibility with old DTBs
-+ { .compatible = "brcm,bcm2838-cprman", .data = &cprman_bcm2711_plat_data },
- {}
- };
- MODULE_DEVICE_TABLE(of, bcm2835_clk_of_match);
---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-@@ -1079,6 +1079,11 @@ static const struct of_device_id bcm2835
- .compatible = "brcm,bcm2711-gpio",
- .data = &bcm2711_pinconf_ops,
- },
-+ // Temporary, for backwards-compatibility with old DTBs
-+ {
-+ .compatible = "brcm,bcm2838-gpio",
-+ .data = &bcm2711_pinconf_ops,
-+ },
- {}
- };
-
--- /dev/null
+From 2c51b8e533a8b43bde18072c9dbbd0fc5084bbe7 Mon Sep 17 00:00:00 2001
+Date: Wed, 2 Oct 2019 17:40:38 +0100
+Subject: [PATCH] media: bcm2835-unicam: Rework to not cache the list
+ of active fmts
+
+Some sensors will change Bayer order based on H & V flips,
+therefore collecting the list of formats at async_bound has
+problems.
+
+Enumerate the formats from the sensor every time.
+
+---
+ .../media/platform/bcm2835/bcm2835-unicam.c | 246 ++++++++++--------
+ 1 file changed, 136 insertions(+), 110 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
+@@ -363,8 +363,6 @@ struct unicam_device {
+ /* Used to store current mbus frame format */
+ struct v4l2_mbus_framefmt m_fmt;
+
+- struct unicam_fmt active_fmts[MAX_POSSIBLE_PIX_FMTS];
+- int num_active_fmt;
+ unsigned int virtual_channel;
+ enum v4l2_mbus_type bus_type;
+ /*
+@@ -455,48 +453,30 @@ static int find_mbus_depth_by_code(u32 c
+ return 0;
+ }
+
+-static const struct unicam_fmt *find_format_by_code(struct unicam_device *dev,
+- u32 code)
++static const struct unicam_fmt *find_format_by_code(u32 code)
+ {
+- const struct unicam_fmt *fmt;
+ unsigned int k;
+
+- for (k = 0; k < dev->num_active_fmt; k++) {
+- fmt = &dev->active_fmts[k];
+- if (fmt->code == code)
+- return fmt;
++ for (k = 0; k < ARRAY_SIZE(formats); k++) {
++ if (formats[k].code == code)
++ return &formats[k];
+ }
+
+ return NULL;
+ }
+
+-static const struct unicam_fmt *find_format_by_pix(struct unicam_device *dev,
+- u32 pixelformat)
++static const struct unicam_fmt *find_format_by_pix(u32 pixelformat)
+ {
+- const struct unicam_fmt *fmt;
+ unsigned int k;
+
+- for (k = 0; k < dev->num_active_fmt; k++) {
+- fmt = &dev->active_fmts[k];
+- if (fmt->fourcc == pixelformat)
+- return fmt;
++ for (k = 0; k < ARRAY_SIZE(formats); k++) {
++ if (formats[k].fourcc == pixelformat)
++ return &formats[k];
+ }
+
+ return NULL;
+ }
+
+-static void dump_active_formats(struct unicam_device *dev)
+-{
+- int i;
+-
+- for (i = 0; i < dev->num_active_fmt; i++) {
+- unicam_dbg(3, dev, "active_fmt[%d] (%p) is code %04x, fourcc " V4L2_FOURCC_CONV ", depth %d\n",
+- i, &dev->active_fmts[i], dev->active_fmts[i].code,
+- V4L2_FOURCC_CONV_ARGS(dev->active_fmts[i].fourcc),
+- dev->active_fmts[i].depth);
+- }
+-}
+-
+ static inline unsigned int bytes_per_line(u32 width,
+ const struct unicam_fmt *fmt)
+ {
+@@ -726,14 +706,40 @@ static int unicam_enum_fmt_vid_cap(struc
+ struct v4l2_fmtdesc *f)
+ {
+ struct unicam_device *dev = video_drvdata(file);
++ struct v4l2_subdev_mbus_code_enum mbus_code;
+ const struct unicam_fmt *fmt = NULL;
++ int index = 0;
++ int ret = 0;
++ int i;
+
+- if (f->index >= dev->num_active_fmt)
+- return -EINVAL;
++ /* Loop whilst the sensor driver says it has more formats, but add a
++ * failsafe against a dodgy driver at 128 (more than any sensor will
++ * ever sensibly advertise)
++ */
++ for (i = 0; !ret && i < 128 ; i++) {
++ memset(&mbus_code, 0, sizeof(mbus_code));
++ mbus_code.index = i;
+
+- fmt = &dev->active_fmts[f->index];
++ ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code,
++ NULL, &mbus_code);
++ if (ret < 0) {
++ unicam_dbg(2, dev,
++ "subdev->enum_mbus_code idx %d returned %d - index invalid\n",
++ i, ret);
++ return -EINVAL;
++ }
+
+- f->pixelformat = fmt->fourcc;
++ fmt = find_format_by_code(mbus_code.code);
++ if (fmt) {
++ if (fmt->fourcc) {
++ if (index == f->index) {
++ f->pixelformat = fmt->fourcc;
++ break;
++ }
++ index++;
++ }
++ }
++ }
+
+ return 0;
+ }
+@@ -748,6 +754,39 @@ static int unicam_g_fmt_vid_cap(struct f
+ return 0;
+ }
+
++static
++const struct unicam_fmt *get_first_supported_format(struct unicam_device *dev)
++{
++ struct v4l2_subdev_mbus_code_enum mbus_code;
++ const struct unicam_fmt *fmt = NULL;
++ int ret;
++ int j;
++
++ for (j = 0; ret != -EINVAL && ret != -ENOIOCTLCMD; ++j) {
++ memset(&mbus_code, 0, sizeof(mbus_code));
++ mbus_code.index = j;
++ ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, NULL,
++ &mbus_code);
++ if (ret < 0) {
++ unicam_dbg(2, dev,
++ "subdev->enum_mbus_code idx %d returned %d - continue\n",
++ j, ret);
++ continue;
++ }
++
++ unicam_dbg(2, dev, "subdev %s: code: %04x idx: %d\n",
++ dev->sensor->name, mbus_code.code, j);
++
++ fmt = find_format_by_code(mbus_code.code);
++ unicam_dbg(2, dev, "fmt %04x returned as %p, V4L2 FOURCC %04x, csi_dt %02X\n",
++ mbus_code.code, fmt, fmt ? fmt->fourcc : 0,
++ fmt ? fmt->csi_dt : 0);
++ if (fmt)
++ return fmt;
++ }
++
++ return NULL;
++}
+ static int unicam_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+ {
+@@ -759,13 +798,15 @@ static int unicam_try_fmt_vid_cap(struct
+ struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
+ int ret;
+
+- fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
++ fmt = find_format_by_pix(f->fmt.pix.pixelformat);
+ if (!fmt) {
+- unicam_dbg(3, dev, "Fourcc format (0x%08x) not found. Use default of %08X\n",
+- f->fmt.pix.pixelformat, dev->active_fmts[0].fourcc);
++ /* Pixel format not supported by unicam. Choose the first
++ * supported format, and let the sensor choose something else.
++ */
++ unicam_dbg(3, dev, "Fourcc format (0x%08x) not found. Use first format.\n",
++ f->fmt.pix.pixelformat);
+
+- /* Just get the first one enumerated */
+- fmt = &dev->active_fmts[0];
++ fmt = &formats[0];
+ f->fmt.pix.pixelformat = fmt->fourcc;
+ }
+
+@@ -785,6 +826,40 @@ static int unicam_try_fmt_vid_cap(struct
+ unicam_info(dev, "Sensor trying to send interlaced video - results may be unpredictable\n");
+
+ v4l2_fill_pix_format(&f->fmt.pix, &sd_fmt.format);
++ if (mbus_fmt->code != fmt->code) {
++ /* Sensor has returned an alternate format */
++ fmt = find_format_by_code(mbus_fmt->code);
++ if (!fmt) {
++ /* The alternate format is one unicam can't support.
++ * Find the first format that is supported by both, and
++ * then set that.
++ */
++ fmt = get_first_supported_format(dev);
++ mbus_fmt->code = fmt->code;
++
++ ret = v4l2_subdev_call(dev->sensor, pad, set_fmt,
++ dev->sensor_config, &sd_fmt);
++ if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
++ return ret;
++
++ if (mbus_fmt->field != V4L2_FIELD_NONE)
++ unicam_info(dev, "Sensor trying to send interlaced video - results may be unpredictable\n");
++
++ v4l2_fill_pix_format(&f->fmt.pix, &sd_fmt.format);
++
++ if (mbus_fmt->code != fmt->code) {
++ /* We've set a format that the sensor reports
++ * as being supported, but it refuses to set it.
++ * Not much else we can do.
++ * Assume that the sensor driver may accept the
++ * format when it is set (rather than tried).
++ */
++ unicam_err(dev, "Sensor won't accept default format, and Unicam can't support sensor default\n");
++ }
++ }
++
++ f->fmt.pix.pixelformat = fmt->fourcc;
++ }
+
+ return unicam_calc_format_size_bpl(dev, fmt, f);
+ }
+@@ -805,10 +880,18 @@ static int unicam_s_fmt_vid_cap(struct f
+ if (ret < 0)
+ return ret;
+
+- fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
++ fmt = find_format_by_pix(f->fmt.pix.pixelformat);
+ if (!fmt) {
+- /* Unknown pixel format - adopt a default */
+- fmt = &dev->active_fmts[0];
++ /* Unknown pixel format - adopt a default.
++ * This shouldn't happen as try_fmt should have resolved any
++ * issues first.
++ */
++ fmt = get_first_supported_format(dev);
++ if (!fmt)
++ /* It shouldn't be possible to get here with no
++ * supported formats
++ */
++ return -EINVAL;
+ f->fmt.pix.pixelformat = fmt->fourcc;
+ return -EINVAL;
+ }
+@@ -944,6 +1027,7 @@ static void unicam_set_packing_config(st
+ unpack = UNICAM_PUM_NONE;
+ break;
+ }
++
+ switch (v4l2_depth) {
+ case 8:
+ pack = UNICAM_PPM_PACK8;
+@@ -1439,7 +1523,7 @@ static int unicam_enum_framesizes(struct
+ int ret;
+
+ /* check for valid format */
+- fmt = find_format_by_pix(dev, fsize->pixel_format);
++ fmt = find_format_by_pix(fsize->pixel_format);
+ if (!fmt) {
+ unicam_dbg(3, dev, "Invalid pixel code: %x\n",
+ fsize->pixel_format);
+@@ -1478,7 +1562,7 @@ static int unicam_enum_frameintervals(st
+ };
+ int ret;
+
+- fmt = find_format_by_pix(dev, fival->pixel_format);
++ fmt = find_format_by_pix(fival->pixel_format);
+ if (!fmt)
+ return -EINVAL;
+
+@@ -1742,27 +1826,6 @@ static const struct v4l2_ioctl_ops unica
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ };
+
+-/*
+- * Adds an entry to the active_fmts array
+- * Returns non-zero if attempting to write off the end of the array.
+- */
+-static int unicam_add_active_format(struct unicam_device *unicam,
+- const struct unicam_fmt *fmt)
+-{
+- //Ensure we don't run off the end of the array.
+- if (unicam->num_active_fmt >= MAX_POSSIBLE_PIX_FMTS)
+- return 1;
+-
+- unicam->active_fmts[unicam->num_active_fmt] = *fmt;
+- unicam_dbg(2, unicam,
+- "matched fourcc: " V4L2_FOURCC_CONV ": code: %04x idx: %d\n",
+- V4L2_FOURCC_CONV_ARGS(fmt->fourcc),
+- fmt->code, unicam->num_active_fmt);
+- unicam->num_active_fmt++;
+-
+- return 0;
+-}
+-
+ static int
+ unicam_async_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+@@ -1770,9 +1833,6 @@ unicam_async_bound(struct v4l2_async_not
+ {
+ struct unicam_device *unicam = container_of(notifier->v4l2_dev,
+ struct unicam_device, v4l2_dev);
+- struct v4l2_subdev_mbus_code_enum mbus_code;
+- int ret = 0;
+- int j;
+
+ if (unicam->sensor) {
+ unicam_info(unicam, "Rejecting subdev %s (Already set!!)",
+@@ -1783,47 +1843,6 @@ unicam_async_bound(struct v4l2_async_not
+ unicam->sensor = subdev;
+ unicam_dbg(1, unicam, "Using sensor %s for capture\n", subdev->name);
+
+- /* Enumerate sub device formats and enable all matching local formats */
+- unicam->num_active_fmt = 0;
+- unicam_dbg(2, unicam, "Get supported formats...\n");
+- for (j = 0; ret != -EINVAL && ret != -ENOIOCTLCMD; ++j) {
+- const struct unicam_fmt *fmt = NULL;
+- int k;
+-
+- memset(&mbus_code, 0, sizeof(mbus_code));
+- mbus_code.index = j;
+- ret = v4l2_subdev_call(subdev, pad, enum_mbus_code,
+- NULL, &mbus_code);
+- if (ret < 0) {
+- unicam_dbg(2, unicam,
+- "subdev->enum_mbus_code idx %d returned %d - continue\n",
+- j, ret);
+- continue;
+- }
+-
+- unicam_dbg(2, unicam, "subdev %s: code: %04x idx: %d\n",
+- subdev->name, mbus_code.code, j);
+-
+- for (k = 0; k < ARRAY_SIZE(formats); k++) {
+- if (mbus_code.code == formats[k].code) {
+- fmt = &formats[k];
+- break;
+- }
+- }
+- unicam_dbg(2, unicam, "fmt %04x returned as %p, V4L2 FOURCC %04x, csi_dt %02X\n",
+- mbus_code.code, fmt, fmt ? fmt->fourcc : 0,
+- fmt ? fmt->csi_dt : 0);
+- if (fmt) {
+- if (unicam_add_active_format(unicam, fmt)) {
+- unicam_dbg(1, unicam, "Active fmt list truncated\n");
+- break;
+- }
+- }
+- }
+- unicam_dbg(2, unicam,
+- "Done all formats\n");
+- dump_active_formats(unicam);
+-
+ return 0;
+ }
+
+@@ -1849,10 +1868,17 @@ static int unicam_probe_complete(struct
+ return ret;
+ }
+
+- fmt = find_format_by_code(unicam, mbus_fmt.code);
++ fmt = find_format_by_code(mbus_fmt.code);
+ if (!fmt) {
+- /* Default image format not valid. Choose first active fmt. */
+- fmt = &unicam->active_fmts[0];
++ /* Find the first format that the sensor and unicam both
++ * support
++ */
++ 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);
+ if (ret)
+++ /dev/null
-From 13b916fa2b8a99c9953073316e102e9d027dd708 Mon Sep 17 00:00:00 2001
-Date: Wed, 2 Oct 2019 16:09:24 +0100
-Subject: [PATCH] media: bcm2835-unicam: Add support for raw14 formats
-
-The V4L2 has gained defines for V4L2_PIX_FMT_Sxxxx14P,
-therefore add support for it to bcm2835-unicam.
-
----
- .../media/platform/bcm2835/bcm2835-unicam.c | 25 +++++++++++++++++--
- 1 file changed, 23 insertions(+), 2 deletions(-)
-
---- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
-@@ -273,10 +273,31 @@ static const struct unicam_fmt formats[]
- .code = MEDIA_BUS_FMT_SRGGB12_1X12,
- .depth = 12,
- .csi_dt = 0x2c,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SBGGR14P,
-+ .code = MEDIA_BUS_FMT_SBGGR14_1X14,
-+ .depth = 14,
-+ .csi_dt = 0x2d,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SGBRG14P,
-+ .code = MEDIA_BUS_FMT_SGBRG14_1X14,
-+ .depth = 14,
-+ .csi_dt = 0x2d,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SGRBG14P,
-+ .code = MEDIA_BUS_FMT_SGRBG14_1X14,
-+ .depth = 14,
-+ .csi_dt = 0x2d,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_SRGGB14P,
-+ .code = MEDIA_BUS_FMT_SRGGB14_1X14,
-+ .depth = 14,
-+ .csi_dt = 0x2d,
- },
- /*
-- * 14 and 16 bit Bayer formats could be supported, but there are no V4L2
-- * defines for 14bit packed Bayer, and no CSI2 data_type for raw 16.
-+ * 16 bit Bayer formats could be supported, but there is no CSI2
-+ * data_type defined for raw 16, and no sensors that produce it at
-+ * present.
- */
- };
-
--- /dev/null
+From 5ae0488f5fc682877ae2a5d454f70884e62120ef Mon Sep 17 00:00:00 2001
+Date: Thu, 3 Oct 2019 13:35:01 +0100
+Subject: [PATCH] media: bcm2835-unicam: Support unpacking CSI format
+ to 16bpp
+
+The CSI packed formats are not the easiest to work with, and
+the peripheral supports unpacking them to 16bpp (but NOT
+shifting the data up into the MSBs).
+Where V4L2 exposes a pixfmt for both packed and unpacked
+formats advertise both as being supported, and unpack the
+data in the peripheral.
+
+---
+ .../media/platform/bcm2835/bcm2835-unicam.c | 102 +++++++++---------
+ 1 file changed, 51 insertions(+), 51 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
+@@ -15,12 +15,15 @@
+ *
+ * This driver directly controls the Unicam peripheral - there is no
+ * involvement with the VideoCore firmware. Unicam receives CSI-2 or
+- * CCP2 data and writes it into SDRAM. The only potential processing options are
+- * to repack Bayer data into an alternate format, and applying windowing.
+- * The repacking does not shift the data, so could repack V4L2_PIX_FMT_Sxxxx10P
++ * CCP2 data and writes it into SDRAM.
++ * The only potential processing options are to repack Bayer data into an
++ * alternate format, and applying windowing.
++ * The repacking does not shift the data, so can repack V4L2_PIX_FMT_Sxxxx10P
+ * to V4L2_PIX_FMT_Sxxxx10, or V4L2_PIX_FMT_Sxxxx12P to V4L2_PIX_FMT_Sxxxx12,
+- * but not generically up to V4L2_PIX_FMT_Sxxxx16.
+- * Adding support for repacking and windowing may be added later.
++ * but not generically up to V4L2_PIX_FMT_Sxxxx16. The driver will add both
++ * formats where the relevant formats are defined, and will automatically
++ * configure the repacking as required.
++ * Support for windowing may be added later.
+ *
+ * It should be possible to connect this driver to any sensor with a
+ * suitable output interface and V4L2 subdevice driver.
+@@ -122,13 +125,16 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
+
+ /*
+ * struct unicam_fmt - Unicam media bus format information
+- * @pixelformat: V4L2 pixel format FCC identifier.
++ * @pixelformat: V4L2 pixel format FCC identifier. 0 if n/a.
++ * @repacked_fourcc: V4L2 pixel format FCC identifier if the data is expanded
++ * out to 16bpp. 0 if n/a.
+ * @code: V4L2 media bus format code.
+- * @depth: Bits per pixel (when stored in memory).
++ * @depth: Bits per pixel as delivered from the source.
+ * @csi_dt: CSI data type.
+ */
+ struct unicam_fmt {
+ u32 fourcc;
++ u32 repacked_fourcc;
+ u32 code;
+ u8 depth;
+ u8 csi_dt;
+@@ -235,41 +241,49 @@ static const struct unicam_fmt formats[]
+ .csi_dt = 0x2a,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR10P,
++ .repacked_fourcc = V4L2_PIX_FMT_SBGGR10,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .depth = 10,
+ .csi_dt = 0x2b,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG10P,
++ .repacked_fourcc = V4L2_PIX_FMT_SGBRG10,
+ .code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .depth = 10,
+ .csi_dt = 0x2b,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG10P,
++ .repacked_fourcc = V4L2_PIX_FMT_SGRBG10,
+ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .depth = 10,
+ .csi_dt = 0x2b,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB10P,
++ .repacked_fourcc = V4L2_PIX_FMT_SRGGB10,
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .depth = 10,
+ .csi_dt = 0x2b,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR12P,
++ .repacked_fourcc = V4L2_PIX_FMT_SBGGR12,
+ .code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .depth = 12,
+ .csi_dt = 0x2c,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG12P,
++ .repacked_fourcc = V4L2_PIX_FMT_SGBRG12,
+ .code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .depth = 12,
+ .csi_dt = 0x2c,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG12P,
++ .repacked_fourcc = V4L2_PIX_FMT_SGRBG12,
+ .code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .depth = 12,
+ .csi_dt = 0x2c,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB12P,
++ .repacked_fourcc = V4L2_PIX_FMT_SRGGB12,
+ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .depth = 12,
+ .csi_dt = 0x2c,
+@@ -439,20 +453,6 @@ static inline void unicam_runtime_put(st
+ }
+
+ /* Format setup functions */
+-static int find_mbus_depth_by_code(u32 code)
+-{
+- const struct unicam_fmt *fmt;
+- unsigned int k;
+-
+- for (k = 0; k < ARRAY_SIZE(formats); k++) {
+- fmt = &formats[k];
+- if (fmt->code == code)
+- return fmt->depth;
+- }
+-
+- return 0;
+-}
+-
+ static const struct unicam_fmt *find_format_by_code(u32 code)
+ {
+ unsigned int k;
+@@ -470,7 +470,8 @@ static const struct unicam_fmt *find_for
+ unsigned int k;
+
+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
+- if (formats[k].fourcc == pixelformat)
++ if (formats[k].fourcc == pixelformat ||
++ formats[k].repacked_fourcc == pixelformat)
+ return &formats[k];
+ }
+
+@@ -478,9 +479,14 @@ static const struct unicam_fmt *find_for
+ }
+
+ static inline unsigned int bytes_per_line(u32 width,
+- const struct unicam_fmt *fmt)
++ const struct unicam_fmt *fmt,
++ u32 v4l2_fourcc)
+ {
+- return ALIGN((width * fmt->depth) >> 3, BPL_ALIGNMENT);
++ if (v4l2_fourcc == fmt->repacked_fourcc)
++ /* Repacking always goes to 16bpp */
++ return ALIGN(width << 1, BPL_ALIGNMENT);
++ else
++ return ALIGN((width * fmt->depth) >> 3, BPL_ALIGNMENT);
+ }
+
+ static int __subdev_get_format(struct unicam_device *dev,
+@@ -538,7 +544,8 @@ static int unicam_calc_format_size_bpl(s
+ &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0,
+ 0);
+
+- min_bytesperline = bytes_per_line(f->fmt.pix.width, fmt);
++ min_bytesperline = bytes_per_line(f->fmt.pix.width, fmt,
++ f->fmt.pix.pixelformat);
+
+ if (f->fmt.pix.bytesperline > min_bytesperline &&
+ f->fmt.pix.bytesperline <= MAX_BYTESPERLINE)
+@@ -738,6 +745,13 @@ static int unicam_enum_fmt_vid_cap(struc
+ }
+ index++;
+ }
++ if (fmt->repacked_fourcc) {
++ if (index == f->index) {
++ f->pixelformat = fmt->repacked_fourcc;
++ break;
++ }
++ index++;
++ }
+ }
+ }
+
+@@ -858,7 +872,10 @@ static int unicam_try_fmt_vid_cap(struct
+ }
+ }
+
+- f->fmt.pix.pixelformat = fmt->fourcc;
++ if (fmt->fourcc)
++ f->fmt.pix.pixelformat = fmt->fourcc;
++ else
++ f->fmt.pix.pixelformat = fmt->repacked_fourcc;
+ }
+
+ return unicam_calc_format_size_bpl(dev, fmt, f);
+@@ -998,16 +1015,14 @@ static void unicam_wr_dma_config(struct
+
+ static void unicam_set_packing_config(struct unicam_device *dev)
+ {
+- int mbus_depth = find_mbus_depth_by_code(dev->fmt->code);
+- int v4l2_depth = dev->fmt->depth;
+ int pack, unpack;
+ u32 val;
+
+- if (mbus_depth == v4l2_depth) {
++ if (dev->v_fmt.fmt.pix.pixelformat == dev->fmt->fourcc) {
+ unpack = UNICAM_PUM_NONE;
+ pack = UNICAM_PPM_NONE;
+ } else {
+- switch (mbus_depth) {
++ switch (dev->fmt->depth) {
+ case 8:
+ unpack = UNICAM_PUM_UNPACK8;
+ break;
+@@ -1028,26 +1043,8 @@ static void unicam_set_packing_config(st
+ break;
+ }
+
+- switch (v4l2_depth) {
+- case 8:
+- pack = UNICAM_PPM_PACK8;
+- break;
+- case 10:
+- pack = UNICAM_PPM_PACK10;
+- break;
+- case 12:
+- pack = UNICAM_PPM_PACK12;
+- break;
+- case 14:
+- pack = UNICAM_PPM_PACK14;
+- break;
+- case 16:
+- pack = UNICAM_PPM_PACK16;
+- break;
+- default:
+- pack = UNICAM_PPM_NONE;
+- break;
+- }
++ /* Repacking is always to 16bpp */
++ pack = UNICAM_PPM_PACK16;
+ }
+
+ val = 0;
+@@ -1893,7 +1890,10 @@ static int unicam_probe_complete(struct
+ }
+
+ unicam->fmt = fmt;
+- unicam->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
++ if (fmt->fourcc)
++ unicam->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
++ else
++ unicam->v_fmt.fmt.pix.pixelformat = fmt->repacked_fourcc;
+
+ /* Read current subdev format */
+ unicam_reset_format(unicam);
--- /dev/null
+From 253dd469e6403b6c2afd25d4f8338a0c1588583f Mon Sep 17 00:00:00 2001
+Date: Thu, 3 Oct 2019 13:45:51 +0100
+Subject: [PATCH] media: bcm2835-unicam: Add support for luma/greyscale
+ formats
+
+Add support for V4L2_PIX_FMT_GREY, V4L2_PIX_FMT_Y10P,
+V4L2_PIX_FMT_Y10, and V4L2_PIX_FMT_Y12 image formats from the
+appropriate mediabus formats advertised by sensors.
+
+---
+ .../media/platform/bcm2835/bcm2835-unicam.c | 21 ++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
+@@ -307,12 +307,31 @@ static const struct unicam_fmt formats[]
+ .code = MEDIA_BUS_FMT_SRGGB14_1X14,
+ .depth = 14,
+ .csi_dt = 0x2d,
+- },
++ }, {
+ /*
+ * 16 bit Bayer formats could be supported, but there is no CSI2
+ * data_type defined for raw 16, and no sensors that produce it at
+ * present.
+ */
++
++ /* Greyscale formats */
++ .fourcc = V4L2_PIX_FMT_GREY,
++ .code = MEDIA_BUS_FMT_Y8_1X8,
++ .depth = 8,
++ .csi_dt = 0x2a,
++ }, {
++ .fourcc = V4L2_PIX_FMT_Y10P,
++ .repacked_fourcc = V4L2_PIX_FMT_Y10,
++ .code = MEDIA_BUS_FMT_Y10_1X10,
++ .depth = 10,
++ .csi_dt = 0x2b,
++ }, {
++ /* NB There is no packed V4L2 fourcc for this format. */
++ .repacked_fourcc = V4L2_PIX_FMT_Y12,
++ .code = MEDIA_BUS_FMT_Y12_1X12,
++ .depth = 12,
++ .csi_dt = 0x2c,
++ },
+ };
+
+ struct unicam_dmaqueue {
+++ /dev/null
-From 2c51b8e533a8b43bde18072c9dbbd0fc5084bbe7 Mon Sep 17 00:00:00 2001
-Date: Wed, 2 Oct 2019 17:40:38 +0100
-Subject: [PATCH] media: bcm2835-unicam: Rework to not cache the list
- of active fmts
-
-Some sensors will change Bayer order based on H & V flips,
-therefore collecting the list of formats at async_bound has
-problems.
-
-Enumerate the formats from the sensor every time.
-
----
- .../media/platform/bcm2835/bcm2835-unicam.c | 246 ++++++++++--------
- 1 file changed, 136 insertions(+), 110 deletions(-)
-
---- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
-@@ -363,8 +363,6 @@ struct unicam_device {
- /* Used to store current mbus frame format */
- struct v4l2_mbus_framefmt m_fmt;
-
-- struct unicam_fmt active_fmts[MAX_POSSIBLE_PIX_FMTS];
-- int num_active_fmt;
- unsigned int virtual_channel;
- enum v4l2_mbus_type bus_type;
- /*
-@@ -455,48 +453,30 @@ static int find_mbus_depth_by_code(u32 c
- return 0;
- }
-
--static const struct unicam_fmt *find_format_by_code(struct unicam_device *dev,
-- u32 code)
-+static const struct unicam_fmt *find_format_by_code(u32 code)
- {
-- const struct unicam_fmt *fmt;
- unsigned int k;
-
-- for (k = 0; k < dev->num_active_fmt; k++) {
-- fmt = &dev->active_fmts[k];
-- if (fmt->code == code)
-- return fmt;
-+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
-+ if (formats[k].code == code)
-+ return &formats[k];
- }
-
- return NULL;
- }
-
--static const struct unicam_fmt *find_format_by_pix(struct unicam_device *dev,
-- u32 pixelformat)
-+static const struct unicam_fmt *find_format_by_pix(u32 pixelformat)
- {
-- const struct unicam_fmt *fmt;
- unsigned int k;
-
-- for (k = 0; k < dev->num_active_fmt; k++) {
-- fmt = &dev->active_fmts[k];
-- if (fmt->fourcc == pixelformat)
-- return fmt;
-+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
-+ if (formats[k].fourcc == pixelformat)
-+ return &formats[k];
- }
-
- return NULL;
- }
-
--static void dump_active_formats(struct unicam_device *dev)
--{
-- int i;
--
-- for (i = 0; i < dev->num_active_fmt; i++) {
-- unicam_dbg(3, dev, "active_fmt[%d] (%p) is code %04x, fourcc " V4L2_FOURCC_CONV ", depth %d\n",
-- i, &dev->active_fmts[i], dev->active_fmts[i].code,
-- V4L2_FOURCC_CONV_ARGS(dev->active_fmts[i].fourcc),
-- dev->active_fmts[i].depth);
-- }
--}
--
- static inline unsigned int bytes_per_line(u32 width,
- const struct unicam_fmt *fmt)
- {
-@@ -726,14 +706,40 @@ static int unicam_enum_fmt_vid_cap(struc
- struct v4l2_fmtdesc *f)
- {
- struct unicam_device *dev = video_drvdata(file);
-+ struct v4l2_subdev_mbus_code_enum mbus_code;
- const struct unicam_fmt *fmt = NULL;
-+ int index = 0;
-+ int ret = 0;
-+ int i;
-
-- if (f->index >= dev->num_active_fmt)
-- return -EINVAL;
-+ /* Loop whilst the sensor driver says it has more formats, but add a
-+ * failsafe against a dodgy driver at 128 (more than any sensor will
-+ * ever sensibly advertise)
-+ */
-+ for (i = 0; !ret && i < 128 ; i++) {
-+ memset(&mbus_code, 0, sizeof(mbus_code));
-+ mbus_code.index = i;
-
-- fmt = &dev->active_fmts[f->index];
-+ ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code,
-+ NULL, &mbus_code);
-+ if (ret < 0) {
-+ unicam_dbg(2, dev,
-+ "subdev->enum_mbus_code idx %d returned %d - index invalid\n",
-+ i, ret);
-+ return -EINVAL;
-+ }
-
-- f->pixelformat = fmt->fourcc;
-+ fmt = find_format_by_code(mbus_code.code);
-+ if (fmt) {
-+ if (fmt->fourcc) {
-+ if (index == f->index) {
-+ f->pixelformat = fmt->fourcc;
-+ break;
-+ }
-+ index++;
-+ }
-+ }
-+ }
-
- return 0;
- }
-@@ -748,6 +754,39 @@ static int unicam_g_fmt_vid_cap(struct f
- return 0;
- }
-
-+static
-+const struct unicam_fmt *get_first_supported_format(struct unicam_device *dev)
-+{
-+ struct v4l2_subdev_mbus_code_enum mbus_code;
-+ const struct unicam_fmt *fmt = NULL;
-+ int ret;
-+ int j;
-+
-+ for (j = 0; ret != -EINVAL && ret != -ENOIOCTLCMD; ++j) {
-+ memset(&mbus_code, 0, sizeof(mbus_code));
-+ mbus_code.index = j;
-+ ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, NULL,
-+ &mbus_code);
-+ if (ret < 0) {
-+ unicam_dbg(2, dev,
-+ "subdev->enum_mbus_code idx %d returned %d - continue\n",
-+ j, ret);
-+ continue;
-+ }
-+
-+ unicam_dbg(2, dev, "subdev %s: code: %04x idx: %d\n",
-+ dev->sensor->name, mbus_code.code, j);
-+
-+ fmt = find_format_by_code(mbus_code.code);
-+ unicam_dbg(2, dev, "fmt %04x returned as %p, V4L2 FOURCC %04x, csi_dt %02X\n",
-+ mbus_code.code, fmt, fmt ? fmt->fourcc : 0,
-+ fmt ? fmt->csi_dt : 0);
-+ if (fmt)
-+ return fmt;
-+ }
-+
-+ return NULL;
-+}
- static int unicam_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
- {
-@@ -759,13 +798,15 @@ static int unicam_try_fmt_vid_cap(struct
- struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
- int ret;
-
-- fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
-+ fmt = find_format_by_pix(f->fmt.pix.pixelformat);
- if (!fmt) {
-- unicam_dbg(3, dev, "Fourcc format (0x%08x) not found. Use default of %08X\n",
-- f->fmt.pix.pixelformat, dev->active_fmts[0].fourcc);
-+ /* Pixel format not supported by unicam. Choose the first
-+ * supported format, and let the sensor choose something else.
-+ */
-+ unicam_dbg(3, dev, "Fourcc format (0x%08x) not found. Use first format.\n",
-+ f->fmt.pix.pixelformat);
-
-- /* Just get the first one enumerated */
-- fmt = &dev->active_fmts[0];
-+ fmt = &formats[0];
- f->fmt.pix.pixelformat = fmt->fourcc;
- }
-
-@@ -785,6 +826,40 @@ static int unicam_try_fmt_vid_cap(struct
- unicam_info(dev, "Sensor trying to send interlaced video - results may be unpredictable\n");
-
- v4l2_fill_pix_format(&f->fmt.pix, &sd_fmt.format);
-+ if (mbus_fmt->code != fmt->code) {
-+ /* Sensor has returned an alternate format */
-+ fmt = find_format_by_code(mbus_fmt->code);
-+ if (!fmt) {
-+ /* The alternate format is one unicam can't support.
-+ * Find the first format that is supported by both, and
-+ * then set that.
-+ */
-+ fmt = get_first_supported_format(dev);
-+ mbus_fmt->code = fmt->code;
-+
-+ ret = v4l2_subdev_call(dev->sensor, pad, set_fmt,
-+ dev->sensor_config, &sd_fmt);
-+ if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
-+ return ret;
-+
-+ if (mbus_fmt->field != V4L2_FIELD_NONE)
-+ unicam_info(dev, "Sensor trying to send interlaced video - results may be unpredictable\n");
-+
-+ v4l2_fill_pix_format(&f->fmt.pix, &sd_fmt.format);
-+
-+ if (mbus_fmt->code != fmt->code) {
-+ /* We've set a format that the sensor reports
-+ * as being supported, but it refuses to set it.
-+ * Not much else we can do.
-+ * Assume that the sensor driver may accept the
-+ * format when it is set (rather than tried).
-+ */
-+ unicam_err(dev, "Sensor won't accept default format, and Unicam can't support sensor default\n");
-+ }
-+ }
-+
-+ f->fmt.pix.pixelformat = fmt->fourcc;
-+ }
-
- return unicam_calc_format_size_bpl(dev, fmt, f);
- }
-@@ -805,10 +880,18 @@ static int unicam_s_fmt_vid_cap(struct f
- if (ret < 0)
- return ret;
-
-- fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
-+ fmt = find_format_by_pix(f->fmt.pix.pixelformat);
- if (!fmt) {
-- /* Unknown pixel format - adopt a default */
-- fmt = &dev->active_fmts[0];
-+ /* Unknown pixel format - adopt a default.
-+ * This shouldn't happen as try_fmt should have resolved any
-+ * issues first.
-+ */
-+ fmt = get_first_supported_format(dev);
-+ if (!fmt)
-+ /* It shouldn't be possible to get here with no
-+ * supported formats
-+ */
-+ return -EINVAL;
- f->fmt.pix.pixelformat = fmt->fourcc;
- return -EINVAL;
- }
-@@ -944,6 +1027,7 @@ static void unicam_set_packing_config(st
- unpack = UNICAM_PUM_NONE;
- break;
- }
-+
- switch (v4l2_depth) {
- case 8:
- pack = UNICAM_PPM_PACK8;
-@@ -1439,7 +1523,7 @@ static int unicam_enum_framesizes(struct
- int ret;
-
- /* check for valid format */
-- fmt = find_format_by_pix(dev, fsize->pixel_format);
-+ fmt = find_format_by_pix(fsize->pixel_format);
- if (!fmt) {
- unicam_dbg(3, dev, "Invalid pixel code: %x\n",
- fsize->pixel_format);
-@@ -1478,7 +1562,7 @@ static int unicam_enum_frameintervals(st
- };
- int ret;
-
-- fmt = find_format_by_pix(dev, fival->pixel_format);
-+ fmt = find_format_by_pix(fival->pixel_format);
- if (!fmt)
- return -EINVAL;
-
-@@ -1742,27 +1826,6 @@ static const struct v4l2_ioctl_ops unica
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- };
-
--/*
-- * Adds an entry to the active_fmts array
-- * Returns non-zero if attempting to write off the end of the array.
-- */
--static int unicam_add_active_format(struct unicam_device *unicam,
-- const struct unicam_fmt *fmt)
--{
-- //Ensure we don't run off the end of the array.
-- if (unicam->num_active_fmt >= MAX_POSSIBLE_PIX_FMTS)
-- return 1;
--
-- unicam->active_fmts[unicam->num_active_fmt] = *fmt;
-- unicam_dbg(2, unicam,
-- "matched fourcc: " V4L2_FOURCC_CONV ": code: %04x idx: %d\n",
-- V4L2_FOURCC_CONV_ARGS(fmt->fourcc),
-- fmt->code, unicam->num_active_fmt);
-- unicam->num_active_fmt++;
--
-- return 0;
--}
--
- static int
- unicam_async_bound(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *subdev,
-@@ -1770,9 +1833,6 @@ unicam_async_bound(struct v4l2_async_not
- {
- struct unicam_device *unicam = container_of(notifier->v4l2_dev,
- struct unicam_device, v4l2_dev);
-- struct v4l2_subdev_mbus_code_enum mbus_code;
-- int ret = 0;
-- int j;
-
- if (unicam->sensor) {
- unicam_info(unicam, "Rejecting subdev %s (Already set!!)",
-@@ -1783,47 +1843,6 @@ unicam_async_bound(struct v4l2_async_not
- unicam->sensor = subdev;
- unicam_dbg(1, unicam, "Using sensor %s for capture\n", subdev->name);
-
-- /* Enumerate sub device formats and enable all matching local formats */
-- unicam->num_active_fmt = 0;
-- unicam_dbg(2, unicam, "Get supported formats...\n");
-- for (j = 0; ret != -EINVAL && ret != -ENOIOCTLCMD; ++j) {
-- const struct unicam_fmt *fmt = NULL;
-- int k;
--
-- memset(&mbus_code, 0, sizeof(mbus_code));
-- mbus_code.index = j;
-- ret = v4l2_subdev_call(subdev, pad, enum_mbus_code,
-- NULL, &mbus_code);
-- if (ret < 0) {
-- unicam_dbg(2, unicam,
-- "subdev->enum_mbus_code idx %d returned %d - continue\n",
-- j, ret);
-- continue;
-- }
--
-- unicam_dbg(2, unicam, "subdev %s: code: %04x idx: %d\n",
-- subdev->name, mbus_code.code, j);
--
-- for (k = 0; k < ARRAY_SIZE(formats); k++) {
-- if (mbus_code.code == formats[k].code) {
-- fmt = &formats[k];
-- break;
-- }
-- }
-- unicam_dbg(2, unicam, "fmt %04x returned as %p, V4L2 FOURCC %04x, csi_dt %02X\n",
-- mbus_code.code, fmt, fmt ? fmt->fourcc : 0,
-- fmt ? fmt->csi_dt : 0);
-- if (fmt) {
-- if (unicam_add_active_format(unicam, fmt)) {
-- unicam_dbg(1, unicam, "Active fmt list truncated\n");
-- break;
-- }
-- }
-- }
-- unicam_dbg(2, unicam,
-- "Done all formats\n");
-- dump_active_formats(unicam);
--
- return 0;
- }
-
-@@ -1849,10 +1868,17 @@ static int unicam_probe_complete(struct
- return ret;
- }
-
-- fmt = find_format_by_code(unicam, mbus_fmt.code);
-+ fmt = find_format_by_code(mbus_fmt.code);
- if (!fmt) {
-- /* Default image format not valid. Choose first active fmt. */
-- fmt = &unicam->active_fmts[0];
-+ /* Find the first format that the sensor and unicam both
-+ * support
-+ */
-+ 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);
- if (ret)
--- /dev/null
+From 799c83fb9b72bcd473099e3da1395c92a5a581ff Mon Sep 17 00:00:00 2001
+Date: Tue, 17 Sep 2019 18:28:17 +0100
+Subject: [PATCH] drm/vc4: Add support for YUV color encodings and
+ ranges
+
+The BT601/BT709 color encoding and limited vs full
+range properties were not being exposed, defaulting
+always to BT601 limited range.
+
+Expose the parameters and set the registers appropriately.
+
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 72 +++++++++++++++++++++++++++++++--
+ drivers/gpu/drm/vc4/vc4_regs.h | 3 ++
+ 2 files changed, 72 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -500,6 +500,53 @@ static void vc4_write_scaling_parameters
+ }
+ }
+
++/* The colorspace conversion matrices are held in 3 entries in the dlist.
++ * Create an array of them, with entries for each full and limited mode, and
++ * each supported colorspace.
++ */
++#define VC4_LIMITED_RANGE 0
++#define VC4_FULL_RANGE 1
++
++static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {
++ {
++ /* Limited range */
++ {
++ /* BT601 */
++ SCALER_CSC0_ITR_R_601_5,
++ SCALER_CSC1_ITR_R_601_5,
++ SCALER_CSC2_ITR_R_601_5,
++ }, {
++ /* BT709 */
++ SCALER_CSC0_ITR_R_709_3,
++ SCALER_CSC1_ITR_R_709_3,
++ SCALER_CSC2_ITR_R_709_3,
++ }, {
++ /* BT2020. Not supported yet - copy 601 */
++ SCALER_CSC0_ITR_R_601_5,
++ SCALER_CSC1_ITR_R_601_5,
++ SCALER_CSC2_ITR_R_601_5,
++ }
++ }, {
++ /* Full range */
++ {
++ /* JFIF */
++ SCALER_CSC0_JPEG_JFIF,
++ SCALER_CSC1_JPEG_JFIF,
++ SCALER_CSC2_JPEG_JFIF,
++ }, {
++ /* BT709 */
++ SCALER_CSC0_ITR_R_709_3_FR,
++ SCALER_CSC1_ITR_R_709_3_FR,
++ SCALER_CSC2_ITR_R_709_3_FR,
++ }, {
++ /* BT2020. Not supported yet - copy JFIF */
++ SCALER_CSC0_JPEG_JFIF,
++ SCALER_CSC1_JPEG_JFIF,
++ SCALER_CSC2_JPEG_JFIF,
++ }
++ }
++};
++
+ /* Writes out a full display list for an active plane to the plane's
+ * private dlist state.
+ */
+@@ -760,9 +807,20 @@ static int vc4_plane_mode_set(struct drm
+
+ /* Colorspace conversion words */
+ if (vc4_state->is_yuv) {
+- vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5);
+- vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5);
+- vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
++ enum drm_color_encoding color_encoding = state->color_encoding;
++ enum drm_color_range color_range = state->color_range;
++ const u32 *ccm;
++
++ if (color_encoding >= DRM_COLOR_ENCODING_MAX)
++ color_encoding = DRM_COLOR_YCBCR_BT601;
++ if (color_range >= DRM_COLOR_RANGE_MAX)
++ color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
++
++ ccm = colorspace_coeffs[color_range][color_encoding];
++
++ vc4_dlist_write(vc4_state, ccm[0]);
++ vc4_dlist_write(vc4_state, ccm[1]);
++ vc4_dlist_write(vc4_state, ccm[2]);
+ }
+
+ if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
+@@ -1116,5 +1174,13 @@ struct drm_plane *vc4_plane_init(struct
+
+ drm_plane_create_alpha_property(plane);
+
++ drm_plane_create_color_properties(plane,
++ BIT(DRM_COLOR_YCBCR_BT601) |
++ BIT(DRM_COLOR_YCBCR_BT709),
++ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
++ BIT(DRM_COLOR_YCBCR_FULL_RANGE),
++ DRM_COLOR_YCBCR_BT709,
++ DRM_COLOR_YCBCR_LIMITED_RANGE);
++
+ return plane;
+ }
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -972,6 +972,7 @@ enum hvs_pixel_format {
+ #define SCALER_CSC0_ITR_R_601_5 0x00f00000
+ #define SCALER_CSC0_ITR_R_709_3 0x00f00000
+ #define SCALER_CSC0_JPEG_JFIF 0x00000000
++#define SCALER_CSC0_ITR_R_709_3_FR 0x00000000
+
+ /* S2.8 contribution of Cb to Green */
+ #define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22)
+@@ -988,6 +989,7 @@ enum hvs_pixel_format {
+ #define SCALER_CSC1_ITR_R_601_5 0xe73304a8
+ #define SCALER_CSC1_ITR_R_709_3 0xf2b784a8
+ #define SCALER_CSC1_JPEG_JFIF 0xea34a400
++#define SCALER_CSC1_ITR_R_709_3_FR 0xe23d0400
+
+ /* S2.8 contribution of Cb to Red */
+ #define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20)
+@@ -1001,6 +1003,7 @@ enum hvs_pixel_format {
+ #define SCALER_CSC2_ITR_R_601_5 0x00066204
+ #define SCALER_CSC2_ITR_R_709_3 0x00072a1c
+ #define SCALER_CSC2_JPEG_JFIF 0x000599c5
++#define SCALER_CSC2_ITR_R_709_3_FR 0x00064ddb
+
+ #define SCALER_TPZ0_VERT_RECALC BIT(31)
+ #define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
+++ /dev/null
-From 5ae0488f5fc682877ae2a5d454f70884e62120ef Mon Sep 17 00:00:00 2001
-Date: Thu, 3 Oct 2019 13:35:01 +0100
-Subject: [PATCH] media: bcm2835-unicam: Support unpacking CSI format
- to 16bpp
-
-The CSI packed formats are not the easiest to work with, and
-the peripheral supports unpacking them to 16bpp (but NOT
-shifting the data up into the MSBs).
-Where V4L2 exposes a pixfmt for both packed and unpacked
-formats advertise both as being supported, and unpack the
-data in the peripheral.
-
----
- .../media/platform/bcm2835/bcm2835-unicam.c | 102 +++++++++---------
- 1 file changed, 51 insertions(+), 51 deletions(-)
-
---- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
-@@ -15,12 +15,15 @@
- *
- * This driver directly controls the Unicam peripheral - there is no
- * involvement with the VideoCore firmware. Unicam receives CSI-2 or
-- * CCP2 data and writes it into SDRAM. The only potential processing options are
-- * to repack Bayer data into an alternate format, and applying windowing.
-- * The repacking does not shift the data, so could repack V4L2_PIX_FMT_Sxxxx10P
-+ * CCP2 data and writes it into SDRAM.
-+ * The only potential processing options are to repack Bayer data into an
-+ * alternate format, and applying windowing.
-+ * The repacking does not shift the data, so can repack V4L2_PIX_FMT_Sxxxx10P
- * to V4L2_PIX_FMT_Sxxxx10, or V4L2_PIX_FMT_Sxxxx12P to V4L2_PIX_FMT_Sxxxx12,
-- * but not generically up to V4L2_PIX_FMT_Sxxxx16.
-- * Adding support for repacking and windowing may be added later.
-+ * but not generically up to V4L2_PIX_FMT_Sxxxx16. The driver will add both
-+ * formats where the relevant formats are defined, and will automatically
-+ * configure the repacking as required.
-+ * Support for windowing may be added later.
- *
- * It should be possible to connect this driver to any sensor with a
- * suitable output interface and V4L2 subdevice driver.
-@@ -122,13 +125,16 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
-
- /*
- * struct unicam_fmt - Unicam media bus format information
-- * @pixelformat: V4L2 pixel format FCC identifier.
-+ * @pixelformat: V4L2 pixel format FCC identifier. 0 if n/a.
-+ * @repacked_fourcc: V4L2 pixel format FCC identifier if the data is expanded
-+ * out to 16bpp. 0 if n/a.
- * @code: V4L2 media bus format code.
-- * @depth: Bits per pixel (when stored in memory).
-+ * @depth: Bits per pixel as delivered from the source.
- * @csi_dt: CSI data type.
- */
- struct unicam_fmt {
- u32 fourcc;
-+ u32 repacked_fourcc;
- u32 code;
- u8 depth;
- u8 csi_dt;
-@@ -235,41 +241,49 @@ static const struct unicam_fmt formats[]
- .csi_dt = 0x2a,
- }, {
- .fourcc = V4L2_PIX_FMT_SBGGR10P,
-+ .repacked_fourcc = V4L2_PIX_FMT_SBGGR10,
- .code = MEDIA_BUS_FMT_SBGGR10_1X10,
- .depth = 10,
- .csi_dt = 0x2b,
- }, {
- .fourcc = V4L2_PIX_FMT_SGBRG10P,
-+ .repacked_fourcc = V4L2_PIX_FMT_SGBRG10,
- .code = MEDIA_BUS_FMT_SGBRG10_1X10,
- .depth = 10,
- .csi_dt = 0x2b,
- }, {
- .fourcc = V4L2_PIX_FMT_SGRBG10P,
-+ .repacked_fourcc = V4L2_PIX_FMT_SGRBG10,
- .code = MEDIA_BUS_FMT_SGRBG10_1X10,
- .depth = 10,
- .csi_dt = 0x2b,
- }, {
- .fourcc = V4L2_PIX_FMT_SRGGB10P,
-+ .repacked_fourcc = V4L2_PIX_FMT_SRGGB10,
- .code = MEDIA_BUS_FMT_SRGGB10_1X10,
- .depth = 10,
- .csi_dt = 0x2b,
- }, {
- .fourcc = V4L2_PIX_FMT_SBGGR12P,
-+ .repacked_fourcc = V4L2_PIX_FMT_SBGGR12,
- .code = MEDIA_BUS_FMT_SBGGR12_1X12,
- .depth = 12,
- .csi_dt = 0x2c,
- }, {
- .fourcc = V4L2_PIX_FMT_SGBRG12P,
-+ .repacked_fourcc = V4L2_PIX_FMT_SGBRG12,
- .code = MEDIA_BUS_FMT_SGBRG12_1X12,
- .depth = 12,
- .csi_dt = 0x2c,
- }, {
- .fourcc = V4L2_PIX_FMT_SGRBG12P,
-+ .repacked_fourcc = V4L2_PIX_FMT_SGRBG12,
- .code = MEDIA_BUS_FMT_SGRBG12_1X12,
- .depth = 12,
- .csi_dt = 0x2c,
- }, {
- .fourcc = V4L2_PIX_FMT_SRGGB12P,
-+ .repacked_fourcc = V4L2_PIX_FMT_SRGGB12,
- .code = MEDIA_BUS_FMT_SRGGB12_1X12,
- .depth = 12,
- .csi_dt = 0x2c,
-@@ -439,20 +453,6 @@ static inline void unicam_runtime_put(st
- }
-
- /* Format setup functions */
--static int find_mbus_depth_by_code(u32 code)
--{
-- const struct unicam_fmt *fmt;
-- unsigned int k;
--
-- for (k = 0; k < ARRAY_SIZE(formats); k++) {
-- fmt = &formats[k];
-- if (fmt->code == code)
-- return fmt->depth;
-- }
--
-- return 0;
--}
--
- static const struct unicam_fmt *find_format_by_code(u32 code)
- {
- unsigned int k;
-@@ -470,7 +470,8 @@ static const struct unicam_fmt *find_for
- unsigned int k;
-
- for (k = 0; k < ARRAY_SIZE(formats); k++) {
-- if (formats[k].fourcc == pixelformat)
-+ if (formats[k].fourcc == pixelformat ||
-+ formats[k].repacked_fourcc == pixelformat)
- return &formats[k];
- }
-
-@@ -478,9 +479,14 @@ static const struct unicam_fmt *find_for
- }
-
- static inline unsigned int bytes_per_line(u32 width,
-- const struct unicam_fmt *fmt)
-+ const struct unicam_fmt *fmt,
-+ u32 v4l2_fourcc)
- {
-- return ALIGN((width * fmt->depth) >> 3, BPL_ALIGNMENT);
-+ if (v4l2_fourcc == fmt->repacked_fourcc)
-+ /* Repacking always goes to 16bpp */
-+ return ALIGN(width << 1, BPL_ALIGNMENT);
-+ else
-+ return ALIGN((width * fmt->depth) >> 3, BPL_ALIGNMENT);
- }
-
- static int __subdev_get_format(struct unicam_device *dev,
-@@ -538,7 +544,8 @@ static int unicam_calc_format_size_bpl(s
- &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0,
- 0);
-
-- min_bytesperline = bytes_per_line(f->fmt.pix.width, fmt);
-+ min_bytesperline = bytes_per_line(f->fmt.pix.width, fmt,
-+ f->fmt.pix.pixelformat);
-
- if (f->fmt.pix.bytesperline > min_bytesperline &&
- f->fmt.pix.bytesperline <= MAX_BYTESPERLINE)
-@@ -738,6 +745,13 @@ static int unicam_enum_fmt_vid_cap(struc
- }
- index++;
- }
-+ if (fmt->repacked_fourcc) {
-+ if (index == f->index) {
-+ f->pixelformat = fmt->repacked_fourcc;
-+ break;
-+ }
-+ index++;
-+ }
- }
- }
-
-@@ -858,7 +872,10 @@ static int unicam_try_fmt_vid_cap(struct
- }
- }
-
-- f->fmt.pix.pixelformat = fmt->fourcc;
-+ if (fmt->fourcc)
-+ f->fmt.pix.pixelformat = fmt->fourcc;
-+ else
-+ f->fmt.pix.pixelformat = fmt->repacked_fourcc;
- }
-
- return unicam_calc_format_size_bpl(dev, fmt, f);
-@@ -998,16 +1015,14 @@ static void unicam_wr_dma_config(struct
-
- static void unicam_set_packing_config(struct unicam_device *dev)
- {
-- int mbus_depth = find_mbus_depth_by_code(dev->fmt->code);
-- int v4l2_depth = dev->fmt->depth;
- int pack, unpack;
- u32 val;
-
-- if (mbus_depth == v4l2_depth) {
-+ if (dev->v_fmt.fmt.pix.pixelformat == dev->fmt->fourcc) {
- unpack = UNICAM_PUM_NONE;
- pack = UNICAM_PPM_NONE;
- } else {
-- switch (mbus_depth) {
-+ switch (dev->fmt->depth) {
- case 8:
- unpack = UNICAM_PUM_UNPACK8;
- break;
-@@ -1028,26 +1043,8 @@ static void unicam_set_packing_config(st
- break;
- }
-
-- switch (v4l2_depth) {
-- case 8:
-- pack = UNICAM_PPM_PACK8;
-- break;
-- case 10:
-- pack = UNICAM_PPM_PACK10;
-- break;
-- case 12:
-- pack = UNICAM_PPM_PACK12;
-- break;
-- case 14:
-- pack = UNICAM_PPM_PACK14;
-- break;
-- case 16:
-- pack = UNICAM_PPM_PACK16;
-- break;
-- default:
-- pack = UNICAM_PPM_NONE;
-- break;
-- }
-+ /* Repacking is always to 16bpp */
-+ pack = UNICAM_PPM_PACK16;
- }
-
- val = 0;
-@@ -1893,7 +1890,10 @@ static int unicam_probe_complete(struct
- }
-
- unicam->fmt = fmt;
-- unicam->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
-+ if (fmt->fourcc)
-+ unicam->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
-+ else
-+ unicam->v_fmt.fmt.pix.pixelformat = fmt->repacked_fourcc;
-
- /* Read current subdev format */
- unicam_reset_format(unicam);
--- /dev/null
+From a8af2085e26bcefad8fb65e2b44d12777a84e219 Mon Sep 17 00:00:00 2001
+Date: Fri, 7 Dec 2018 09:36:05 +0100
+Subject: [PATCH] drm/vc4: Fix negative X/Y positioning on SAND planes
+
+Commit 8e75d582db02bcb171d65ec71eecbd3072a5fd3a upstream.
+
+Commit 3e407417b192 ("drm/vc4: Fix X/Y positioning of planes using
+T_TILES modifier") fixed the problem with T_TILES format, but left
+things in a non-working state for SAND formats. Address that now.
+
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -684,6 +684,7 @@ static int vc4_plane_mode_set(struct drm
+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
+ case DRM_FORMAT_MOD_BROADCOM_SAND256: {
+ uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
++ u32 tile_w, tile, x_off, pix_per_tile;
+
+ /* Column-based NV12 or RGBA.
+ */
+@@ -703,12 +704,15 @@ static int vc4_plane_mode_set(struct drm
+ switch (base_format_mod) {
+ case DRM_FORMAT_MOD_BROADCOM_SAND64:
+ tiling = SCALER_CTL0_TILING_64B;
++ tile_w = 64;
+ break;
+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
+ tiling = SCALER_CTL0_TILING_128B;
++ tile_w = 128;
+ break;
+ case DRM_FORMAT_MOD_BROADCOM_SAND256:
+ tiling = SCALER_CTL0_TILING_256B_OR_T;
++ tile_w = 256;
+ break;
+ default:
+ break;
+@@ -719,6 +723,23 @@ static int vc4_plane_mode_set(struct drm
+ return -EINVAL;
+ }
+
++ pix_per_tile = tile_w / fb->format->cpp[0];
++ tile = vc4_state->src_x / pix_per_tile;
++ x_off = vc4_state->src_x % pix_per_tile;
++
++ /* Adjust the base pointer to the first pixel to be scanned
++ * out.
++ */
++ for (i = 0; i < num_planes; i++) {
++ vc4_state->offsets[i] += param * tile_w * tile;
++ vc4_state->offsets[i] += vc4_state->src_y /
++ (i ? v_subsample : 1) *
++ tile_w;
++ vc4_state->offsets[i] += x_off /
++ (i ? h_subsample : 1) *
++ fb->format->cpp[i];
++ }
++
+ pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);
+ break;
+ }
+++ /dev/null
-From 253dd469e6403b6c2afd25d4f8338a0c1588583f Mon Sep 17 00:00:00 2001
-Date: Thu, 3 Oct 2019 13:45:51 +0100
-Subject: [PATCH] media: bcm2835-unicam: Add support for luma/greyscale
- formats
-
-Add support for V4L2_PIX_FMT_GREY, V4L2_PIX_FMT_Y10P,
-V4L2_PIX_FMT_Y10, and V4L2_PIX_FMT_Y12 image formats from the
-appropriate mediabus formats advertised by sensors.
-
----
- .../media/platform/bcm2835/bcm2835-unicam.c | 21 ++++++++++++++++++-
- 1 file changed, 20 insertions(+), 1 deletion(-)
-
---- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
-@@ -307,12 +307,31 @@ static const struct unicam_fmt formats[]
- .code = MEDIA_BUS_FMT_SRGGB14_1X14,
- .depth = 14,
- .csi_dt = 0x2d,
-- },
-+ }, {
- /*
- * 16 bit Bayer formats could be supported, but there is no CSI2
- * data_type defined for raw 16, and no sensors that produce it at
- * present.
- */
-+
-+ /* Greyscale formats */
-+ .fourcc = V4L2_PIX_FMT_GREY,
-+ .code = MEDIA_BUS_FMT_Y8_1X8,
-+ .depth = 8,
-+ .csi_dt = 0x2a,
-+ }, {
-+ .fourcc = V4L2_PIX_FMT_Y10P,
-+ .repacked_fourcc = V4L2_PIX_FMT_Y10,
-+ .code = MEDIA_BUS_FMT_Y10_1X10,
-+ .depth = 10,
-+ .csi_dt = 0x2b,
-+ }, {
-+ /* NB There is no packed V4L2 fourcc for this format. */
-+ .repacked_fourcc = V4L2_PIX_FMT_Y12,
-+ .code = MEDIA_BUS_FMT_Y12_1X12,
-+ .depth = 12,
-+ .csi_dt = 0x2c,
-+ },
- };
-
- struct unicam_dmaqueue {
--- /dev/null
+From 1246d16c393a2f5790e5492053f26e6b0b62cec8 Mon Sep 17 00:00:00 2001
+Date: Tue, 17 Sep 2019 18:36:32 +0100
+Subject: [PATCH] drm/vc4: Add support for H & V flips
+
+The HVS supports horizontal and vertical flips whilst composing.
+
+Expose these through the standard DRM rotation property.
+
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 54 +++++++++++++++++++++++++++------
+ 1 file changed, 45 insertions(+), 9 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -560,7 +560,9 @@ static int vc4_plane_mode_set(struct drm
+ const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
+ u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
+ int num_planes = drm_format_num_planes(format->drm);
++ bool hflip = false, vflip = false;
+ u32 h_subsample, v_subsample;
++ unsigned int rotation;
+ bool mix_plane_alpha;
+ bool covers_screen;
+ u32 scl0, scl1, pitch0;
+@@ -568,11 +570,26 @@ static int vc4_plane_mode_set(struct drm
+ unsigned long irqflags;
+ u32 hvs_format = format->hvs;
+ int ret, i;
++ u32 src_y;
+
+ ret = vc4_plane_setup_clipping_and_scaling(state);
+ if (ret)
+ return ret;
+
++ rotation = drm_rotation_simplify(state->rotation,
++ DRM_MODE_ROTATE_0 |
++ DRM_MODE_REFLECT_X |
++ DRM_MODE_REFLECT_Y);
++
++ if ((rotation & DRM_MODE_ROTATE_MASK) == DRM_MODE_ROTATE_180) {
++ hflip = true;
++ vflip = true;
++ }
++ if (rotation & DRM_MODE_REFLECT_X)
++ hflip ^= true;
++ if (rotation & DRM_MODE_REFLECT_Y)
++ vflip ^= true;
++
+ /* Allocate the LBM memory that the HVS will use for temporary
+ * storage due to our scaling/format conversion.
+ */
+@@ -609,6 +626,16 @@ static int vc4_plane_mode_set(struct drm
+ h_subsample = drm_format_horz_chroma_subsampling(format->drm);
+ v_subsample = drm_format_vert_chroma_subsampling(format->drm);
+
++ if (!vflip)
++ src_y = vc4_state->src_y;
++ else
++ /* When vflipped the image offset needs to be
++ * the start of the last line of the image, and
++ * the pitch will be subtracted from the offset.
++ */
++ src_y = vc4_state->src_y +
++ vc4_state->src_h[0] - 1;
++
+ switch (base_format_mod) {
+ case DRM_FORMAT_MOD_LINEAR:
+ tiling = SCALER_CTL0_TILING_LINEAR;
+@@ -618,12 +645,13 @@ static int vc4_plane_mode_set(struct drm
+ * out.
+ */
+ for (i = 0; i < num_planes; i++) {
+- vc4_state->offsets[i] += vc4_state->src_y /
++ vc4_state->offsets[i] += src_y /
+ (i ? v_subsample : 1) *
+ fb->pitches[i];
++
+ vc4_state->offsets[i] += vc4_state->src_x /
+- (i ? h_subsample : 1) *
+- fb->format->cpp[i];
++ (i ? h_subsample : 1) *
++ fb->format->cpp[i];
+ }
+
+ break;
+@@ -651,11 +679,11 @@ static int vc4_plane_mode_set(struct drm
+ * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
+ * base address).
+ */
+- u32 tile_y = (vc4_state->src_y >> 4) & 1;
+- u32 subtile_y = (vc4_state->src_y >> 2) & 3;
+- u32 utile_y = vc4_state->src_y & 3;
++ u32 tile_y = (src_y >> 4) & 1;
++ u32 subtile_y = (src_y >> 2) & 3;
++ u32 utile_y = src_y & 3;
+ u32 x_off = vc4_state->src_x & tile_w_mask;
+- u32 y_off = vc4_state->src_y & tile_h_mask;
++ u32 y_off = src_y & tile_h_mask;
+
+ tiling = SCALER_CTL0_TILING_256B_OR_T;
+ pitch0 = (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
+@@ -732,7 +760,7 @@ static int vc4_plane_mode_set(struct drm
+ */
+ for (i = 0; i < num_planes; i++) {
+ vc4_state->offsets[i] += param * tile_w * tile;
+- vc4_state->offsets[i] += vc4_state->src_y /
++ vc4_state->offsets[i] += src_y /
+ (i ? v_subsample : 1) *
+ tile_w;
+ vc4_state->offsets[i] += x_off /
+@@ -759,7 +787,9 @@ static int vc4_plane_mode_set(struct drm
+ VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
+ (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
+ VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
+- VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
++ VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1) |
++ (vflip ? SCALER_CTL0_VFLIP : 0) |
++ (hflip ? SCALER_CTL0_HFLIP : 0));
+
+ /* Position Word 0: Image Positions and Alpha Value */
+ vc4_state->pos0_offset = vc4_state->dlist_count;
+@@ -1203,5 +1233,11 @@ struct drm_plane *vc4_plane_init(struct
+ DRM_COLOR_YCBCR_BT709,
+ DRM_COLOR_YCBCR_LIMITED_RANGE);
+
++ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
++ DRM_MODE_ROTATE_0 |
++ DRM_MODE_ROTATE_180 |
++ DRM_MODE_REFLECT_X |
++ DRM_MODE_REFLECT_Y);
++
+ return plane;
+ }
+++ /dev/null
-From 799c83fb9b72bcd473099e3da1395c92a5a581ff Mon Sep 17 00:00:00 2001
-Date: Tue, 17 Sep 2019 18:28:17 +0100
-Subject: [PATCH] drm/vc4: Add support for YUV color encodings and
- ranges
-
-The BT601/BT709 color encoding and limited vs full
-range properties were not being exposed, defaulting
-always to BT601 limited range.
-
-Expose the parameters and set the registers appropriately.
-
----
- drivers/gpu/drm/vc4/vc4_plane.c | 72 +++++++++++++++++++++++++++++++--
- drivers/gpu/drm/vc4/vc4_regs.h | 3 ++
- 2 files changed, 72 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_plane.c
-+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -500,6 +500,53 @@ static void vc4_write_scaling_parameters
- }
- }
-
-+/* The colorspace conversion matrices are held in 3 entries in the dlist.
-+ * Create an array of them, with entries for each full and limited mode, and
-+ * each supported colorspace.
-+ */
-+#define VC4_LIMITED_RANGE 0
-+#define VC4_FULL_RANGE 1
-+
-+static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {
-+ {
-+ /* Limited range */
-+ {
-+ /* BT601 */
-+ SCALER_CSC0_ITR_R_601_5,
-+ SCALER_CSC1_ITR_R_601_5,
-+ SCALER_CSC2_ITR_R_601_5,
-+ }, {
-+ /* BT709 */
-+ SCALER_CSC0_ITR_R_709_3,
-+ SCALER_CSC1_ITR_R_709_3,
-+ SCALER_CSC2_ITR_R_709_3,
-+ }, {
-+ /* BT2020. Not supported yet - copy 601 */
-+ SCALER_CSC0_ITR_R_601_5,
-+ SCALER_CSC1_ITR_R_601_5,
-+ SCALER_CSC2_ITR_R_601_5,
-+ }
-+ }, {
-+ /* Full range */
-+ {
-+ /* JFIF */
-+ SCALER_CSC0_JPEG_JFIF,
-+ SCALER_CSC1_JPEG_JFIF,
-+ SCALER_CSC2_JPEG_JFIF,
-+ }, {
-+ /* BT709 */
-+ SCALER_CSC0_ITR_R_709_3_FR,
-+ SCALER_CSC1_ITR_R_709_3_FR,
-+ SCALER_CSC2_ITR_R_709_3_FR,
-+ }, {
-+ /* BT2020. Not supported yet - copy JFIF */
-+ SCALER_CSC0_JPEG_JFIF,
-+ SCALER_CSC1_JPEG_JFIF,
-+ SCALER_CSC2_JPEG_JFIF,
-+ }
-+ }
-+};
-+
- /* Writes out a full display list for an active plane to the plane's
- * private dlist state.
- */
-@@ -760,9 +807,20 @@ static int vc4_plane_mode_set(struct drm
-
- /* Colorspace conversion words */
- if (vc4_state->is_yuv) {
-- vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5);
-- vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5);
-- vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
-+ enum drm_color_encoding color_encoding = state->color_encoding;
-+ enum drm_color_range color_range = state->color_range;
-+ const u32 *ccm;
-+
-+ if (color_encoding >= DRM_COLOR_ENCODING_MAX)
-+ color_encoding = DRM_COLOR_YCBCR_BT601;
-+ if (color_range >= DRM_COLOR_RANGE_MAX)
-+ color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
-+
-+ ccm = colorspace_coeffs[color_range][color_encoding];
-+
-+ vc4_dlist_write(vc4_state, ccm[0]);
-+ vc4_dlist_write(vc4_state, ccm[1]);
-+ vc4_dlist_write(vc4_state, ccm[2]);
- }
-
- if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
-@@ -1116,5 +1174,13 @@ struct drm_plane *vc4_plane_init(struct
-
- drm_plane_create_alpha_property(plane);
-
-+ drm_plane_create_color_properties(plane,
-+ BIT(DRM_COLOR_YCBCR_BT601) |
-+ BIT(DRM_COLOR_YCBCR_BT709),
-+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
-+ BIT(DRM_COLOR_YCBCR_FULL_RANGE),
-+ DRM_COLOR_YCBCR_BT709,
-+ DRM_COLOR_YCBCR_LIMITED_RANGE);
-+
- return plane;
- }
---- a/drivers/gpu/drm/vc4/vc4_regs.h
-+++ b/drivers/gpu/drm/vc4/vc4_regs.h
-@@ -972,6 +972,7 @@ enum hvs_pixel_format {
- #define SCALER_CSC0_ITR_R_601_5 0x00f00000
- #define SCALER_CSC0_ITR_R_709_3 0x00f00000
- #define SCALER_CSC0_JPEG_JFIF 0x00000000
-+#define SCALER_CSC0_ITR_R_709_3_FR 0x00000000
-
- /* S2.8 contribution of Cb to Green */
- #define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22)
-@@ -988,6 +989,7 @@ enum hvs_pixel_format {
- #define SCALER_CSC1_ITR_R_601_5 0xe73304a8
- #define SCALER_CSC1_ITR_R_709_3 0xf2b784a8
- #define SCALER_CSC1_JPEG_JFIF 0xea34a400
-+#define SCALER_CSC1_ITR_R_709_3_FR 0xe23d0400
-
- /* S2.8 contribution of Cb to Red */
- #define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20)
-@@ -1001,6 +1003,7 @@ enum hvs_pixel_format {
- #define SCALER_CSC2_ITR_R_601_5 0x00066204
- #define SCALER_CSC2_ITR_R_709_3 0x00072a1c
- #define SCALER_CSC2_JPEG_JFIF 0x000599c5
-+#define SCALER_CSC2_ITR_R_709_3_FR 0x00064ddb
-
- #define SCALER_TPZ0_VERT_RECALC BIT(31)
- #define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
--- /dev/null
+From e99a60f018524bf7b1ba382e3994c22ebcdbafe6 Mon Sep 17 00:00:00 2001
+Date: Wed, 18 Sep 2019 15:49:13 +0100
+Subject: [PATCH] drm/vc4: Correct handling of rotation parameter in
+ fkms
+
+One bit within DRM_MODE_ROTATE_MASK will always be set to
+determine the base rotation 0/90/180/270, and then REFLECT_X
+and REFLECT_Y are on top.
+
+Correct the handling which was assuming that REFLECT_[X|Y]
+was instead of ROTATE_x.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 ++++++++++----------------
+ 1 file changed, 14 insertions(+), 23 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -79,11 +79,6 @@ struct set_plane {
+ #define TRANSFORM_FLIP_HRIZ BIT(16)
+ #define TRANSFORM_FLIP_VERT BIT(17)
+
+-#define SUPPORTED_ROTATIONS (DRM_MODE_ROTATE_0 | \
+- DRM_MODE_ROTATE_180 | \
+- DRM_MODE_REFLECT_X | \
+- DRM_MODE_REFLECT_Y)
+-
+ struct mailbox_set_plane {
+ struct rpi_firmware_property_tag_header tag;
+ struct set_plane plane;
+@@ -523,7 +518,7 @@ static int vc4_plane_to_mb(struct drm_pl
+ const struct vc_image_format *vc_fmt =
+ vc4_get_vc_image_fmt(drm_fmt->format);
+ int num_planes = fb->format->num_planes;
+- unsigned int rotation = SUPPORTED_ROTATIONS;
++ unsigned int rotation;
+
+ mb->plane.vc_image_type = vc_fmt->vc_image;
+ mb->plane.width = fb->width;
+@@ -544,23 +539,16 @@ static int vc4_plane_to_mb(struct drm_pl
+ mb->plane.is_vu = vc_fmt->is_vu;
+ mb->plane.planes[0] = bo->paddr + fb->offsets[0];
+
+- rotation = drm_rotation_simplify(state->rotation, rotation);
+-
+- switch (rotation) {
+- default:
+- case DRM_MODE_ROTATE_0:
+- mb->plane.transform = TRANSFORM_NO_ROTATE;
+- break;
+- case DRM_MODE_ROTATE_180:
+- mb->plane.transform = TRANSFORM_ROTATE_180;
+- break;
+- case DRM_MODE_REFLECT_X:
+- mb->plane.transform = TRANSFORM_FLIP_HRIZ;
+- break;
+- case DRM_MODE_REFLECT_Y:
+- mb->plane.transform = TRANSFORM_FLIP_VERT;
+- break;
+- }
++ rotation = drm_rotation_simplify(state->rotation,
++ DRM_MODE_ROTATE_0 |
++ DRM_MODE_REFLECT_X |
++ DRM_MODE_REFLECT_Y);
++
++ mb->plane.transform = TRANSFORM_NO_ROTATE;
++ if (rotation & DRM_MODE_REFLECT_X)
++ mb->plane.transform |= TRANSFORM_FLIP_HRIZ;
++ if (rotation & DRM_MODE_REFLECT_Y)
++ mb->plane.transform |= TRANSFORM_FLIP_VERT;
+
+ vc4_fkms_margins_adj(state, &mb->plane);
+
+@@ -772,7 +760,10 @@ static struct drm_plane *vc4_fkms_plane_
+
+ drm_plane_create_alpha_property(plane);
+ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
+- SUPPORTED_ROTATIONS);
++ DRM_MODE_ROTATE_0 |
++ DRM_MODE_ROTATE_180 |
++ DRM_MODE_REFLECT_X |
++ DRM_MODE_REFLECT_Y);
+ drm_plane_create_color_properties(plane,
+ BIT(DRM_COLOR_YCBCR_BT601) |
+ BIT(DRM_COLOR_YCBCR_BT709) |
+++ /dev/null
-From a8af2085e26bcefad8fb65e2b44d12777a84e219 Mon Sep 17 00:00:00 2001
-Date: Fri, 7 Dec 2018 09:36:05 +0100
-Subject: [PATCH] drm/vc4: Fix negative X/Y positioning on SAND planes
-
-Commit 8e75d582db02bcb171d65ec71eecbd3072a5fd3a upstream.
-
-Commit 3e407417b192 ("drm/vc4: Fix X/Y positioning of planes using
-T_TILES modifier") fixed the problem with T_TILES format, but left
-things in a non-working state for SAND formats. Address that now.
-
----
- drivers/gpu/drm/vc4/vc4_plane.c | 21 +++++++++++++++++++++
- 1 file changed, 21 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_plane.c
-+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -684,6 +684,7 @@ static int vc4_plane_mode_set(struct drm
- case DRM_FORMAT_MOD_BROADCOM_SAND128:
- case DRM_FORMAT_MOD_BROADCOM_SAND256: {
- uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
-+ u32 tile_w, tile, x_off, pix_per_tile;
-
- /* Column-based NV12 or RGBA.
- */
-@@ -703,12 +704,15 @@ static int vc4_plane_mode_set(struct drm
- switch (base_format_mod) {
- case DRM_FORMAT_MOD_BROADCOM_SAND64:
- tiling = SCALER_CTL0_TILING_64B;
-+ tile_w = 64;
- break;
- case DRM_FORMAT_MOD_BROADCOM_SAND128:
- tiling = SCALER_CTL0_TILING_128B;
-+ tile_w = 128;
- break;
- case DRM_FORMAT_MOD_BROADCOM_SAND256:
- tiling = SCALER_CTL0_TILING_256B_OR_T;
-+ tile_w = 256;
- break;
- default:
- break;
-@@ -719,6 +723,23 @@ static int vc4_plane_mode_set(struct drm
- return -EINVAL;
- }
-
-+ pix_per_tile = tile_w / fb->format->cpp[0];
-+ tile = vc4_state->src_x / pix_per_tile;
-+ x_off = vc4_state->src_x % pix_per_tile;
-+
-+ /* Adjust the base pointer to the first pixel to be scanned
-+ * out.
-+ */
-+ for (i = 0; i < num_planes; i++) {
-+ vc4_state->offsets[i] += param * tile_w * tile;
-+ vc4_state->offsets[i] += vc4_state->src_y /
-+ (i ? v_subsample : 1) *
-+ tile_w;
-+ vc4_state->offsets[i] += x_off /
-+ (i ? h_subsample : 1) *
-+ fb->format->cpp[i];
-+ }
-+
- pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);
- break;
- }
+++ /dev/null
-From 1246d16c393a2f5790e5492053f26e6b0b62cec8 Mon Sep 17 00:00:00 2001
-Date: Tue, 17 Sep 2019 18:36:32 +0100
-Subject: [PATCH] drm/vc4: Add support for H & V flips
-
-The HVS supports horizontal and vertical flips whilst composing.
-
-Expose these through the standard DRM rotation property.
-
----
- drivers/gpu/drm/vc4/vc4_plane.c | 54 +++++++++++++++++++++++++++------
- 1 file changed, 45 insertions(+), 9 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_plane.c
-+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -560,7 +560,9 @@ static int vc4_plane_mode_set(struct drm
- const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
- u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
- int num_planes = drm_format_num_planes(format->drm);
-+ bool hflip = false, vflip = false;
- u32 h_subsample, v_subsample;
-+ unsigned int rotation;
- bool mix_plane_alpha;
- bool covers_screen;
- u32 scl0, scl1, pitch0;
-@@ -568,11 +570,26 @@ static int vc4_plane_mode_set(struct drm
- unsigned long irqflags;
- u32 hvs_format = format->hvs;
- int ret, i;
-+ u32 src_y;
-
- ret = vc4_plane_setup_clipping_and_scaling(state);
- if (ret)
- return ret;
-
-+ rotation = drm_rotation_simplify(state->rotation,
-+ DRM_MODE_ROTATE_0 |
-+ DRM_MODE_REFLECT_X |
-+ DRM_MODE_REFLECT_Y);
-+
-+ if ((rotation & DRM_MODE_ROTATE_MASK) == DRM_MODE_ROTATE_180) {
-+ hflip = true;
-+ vflip = true;
-+ }
-+ if (rotation & DRM_MODE_REFLECT_X)
-+ hflip ^= true;
-+ if (rotation & DRM_MODE_REFLECT_Y)
-+ vflip ^= true;
-+
- /* Allocate the LBM memory that the HVS will use for temporary
- * storage due to our scaling/format conversion.
- */
-@@ -609,6 +626,16 @@ static int vc4_plane_mode_set(struct drm
- h_subsample = drm_format_horz_chroma_subsampling(format->drm);
- v_subsample = drm_format_vert_chroma_subsampling(format->drm);
-
-+ if (!vflip)
-+ src_y = vc4_state->src_y;
-+ else
-+ /* When vflipped the image offset needs to be
-+ * the start of the last line of the image, and
-+ * the pitch will be subtracted from the offset.
-+ */
-+ src_y = vc4_state->src_y +
-+ vc4_state->src_h[0] - 1;
-+
- switch (base_format_mod) {
- case DRM_FORMAT_MOD_LINEAR:
- tiling = SCALER_CTL0_TILING_LINEAR;
-@@ -618,12 +645,13 @@ static int vc4_plane_mode_set(struct drm
- * out.
- */
- for (i = 0; i < num_planes; i++) {
-- vc4_state->offsets[i] += vc4_state->src_y /
-+ vc4_state->offsets[i] += src_y /
- (i ? v_subsample : 1) *
- fb->pitches[i];
-+
- vc4_state->offsets[i] += vc4_state->src_x /
-- (i ? h_subsample : 1) *
-- fb->format->cpp[i];
-+ (i ? h_subsample : 1) *
-+ fb->format->cpp[i];
- }
-
- break;
-@@ -651,11 +679,11 @@ static int vc4_plane_mode_set(struct drm
- * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
- * base address).
- */
-- u32 tile_y = (vc4_state->src_y >> 4) & 1;
-- u32 subtile_y = (vc4_state->src_y >> 2) & 3;
-- u32 utile_y = vc4_state->src_y & 3;
-+ u32 tile_y = (src_y >> 4) & 1;
-+ u32 subtile_y = (src_y >> 2) & 3;
-+ u32 utile_y = src_y & 3;
- u32 x_off = vc4_state->src_x & tile_w_mask;
-- u32 y_off = vc4_state->src_y & tile_h_mask;
-+ u32 y_off = src_y & tile_h_mask;
-
- tiling = SCALER_CTL0_TILING_256B_OR_T;
- pitch0 = (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
-@@ -732,7 +760,7 @@ static int vc4_plane_mode_set(struct drm
- */
- for (i = 0; i < num_planes; i++) {
- vc4_state->offsets[i] += param * tile_w * tile;
-- vc4_state->offsets[i] += vc4_state->src_y /
-+ vc4_state->offsets[i] += src_y /
- (i ? v_subsample : 1) *
- tile_w;
- vc4_state->offsets[i] += x_off /
-@@ -759,7 +787,9 @@ static int vc4_plane_mode_set(struct drm
- VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
- (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
- VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
-- VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
-+ VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1) |
-+ (vflip ? SCALER_CTL0_VFLIP : 0) |
-+ (hflip ? SCALER_CTL0_HFLIP : 0));
-
- /* Position Word 0: Image Positions and Alpha Value */
- vc4_state->pos0_offset = vc4_state->dlist_count;
-@@ -1203,5 +1233,11 @@ struct drm_plane *vc4_plane_init(struct
- DRM_COLOR_YCBCR_BT709,
- DRM_COLOR_YCBCR_LIMITED_RANGE);
-
-+ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
-+ DRM_MODE_ROTATE_0 |
-+ DRM_MODE_ROTATE_180 |
-+ DRM_MODE_REFLECT_X |
-+ DRM_MODE_REFLECT_Y);
-+
- return plane;
- }
--- /dev/null
+From cb9a896a799393b3cb5947bef3c95eb5ffb44776 Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Oct 2019 09:08:47 +0100
+Subject: [PATCH] overlays: Add w5500 overlay
+
+Add an overlay to configure the Wiznet W5500 Ethernet controller on
+SPI0. The 'cs' parameter chooses the Chip Select (default 0).
+
+See: https://github.com/raspberrypi/linux/issues/3276
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 10 ++++
+ arch/arm/boot/dts/overlays/w5500-overlay.dts | 63 ++++++++++++++++++++
+ 3 files changed, 74 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/w5500-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -183,6 +183,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ vga666.dtbo \
+ w1-gpio.dtbo \
+ w1-gpio-pullup.dtbo \
++ w5500.dtbo \
+ wittypi.dtbo
+
+ targets += dtbs dtbs_install
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2538,6 +2538,16 @@ Params: gpiopin GPIO for
+ pullup Now enabled by default (ignored)
+
+
++Name: w5500
++Info: Overlay for the Wiznet W5500 Ethernet Controller on SPI0
++Load: dtoverlay=w5500,<param>=<val>
++Params: int_pin GPIO used for INT (default 25)
++
++ speed SPI bus speed (default 30000000)
++
++ cs SPI bus Chip Select (default 0)
++
++
+ Name: wittypi
+ Info: Configures the wittypi RTC module.
+ Load: dtoverlay=wittypi,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/w5500-overlay.dts
+@@ -0,0 +1,63 @@
++// Overlay for the Wiznet w5500 Ethernet Controller
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev1>;
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ eth1: w5500@0{
++ compatible = "wiznet,w5500";
++ reg = <0>; /* CE0 */
++ pinctrl-names = "default";
++ pinctrl-0 = <ð1_pins>;
++ interrupt-parent = <&gpio>;
++ interrupts = <25 0x8>;
++ spi-max-frequency = <30000000>;
++// local-mac-address = [aa bb cc dd ee ff];
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&gpio>;
++ __overlay__ {
++ eth1_pins: eth1_pins {
++ brcm,pins = <25>;
++ brcm,function = <0>; /* in */
++ brcm,pull = <0>; /* none */
++ };
++ };
++ };
++
++ __overrides__ {
++ int_pin = <ð1>, "interrupts:0",
++ <ð1_pins>, "brcm,pins:0";
++ speed = <ð1>, "spi-max-frequency:0";
++ cs = <ð1>, "reg:0",
++ <0>, "!0=1";
++ };
++};
+++ /dev/null
-From e99a60f018524bf7b1ba382e3994c22ebcdbafe6 Mon Sep 17 00:00:00 2001
-Date: Wed, 18 Sep 2019 15:49:13 +0100
-Subject: [PATCH] drm/vc4: Correct handling of rotation parameter in
- fkms
-
-One bit within DRM_MODE_ROTATE_MASK will always be set to
-determine the base rotation 0/90/180/270, and then REFLECT_X
-and REFLECT_Y are on top.
-
-Correct the handling which was assuming that REFLECT_[X|Y]
-was instead of ROTATE_x.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 ++++++++++----------------
- 1 file changed, 14 insertions(+), 23 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -79,11 +79,6 @@ struct set_plane {
- #define TRANSFORM_FLIP_HRIZ BIT(16)
- #define TRANSFORM_FLIP_VERT BIT(17)
-
--#define SUPPORTED_ROTATIONS (DRM_MODE_ROTATE_0 | \
-- DRM_MODE_ROTATE_180 | \
-- DRM_MODE_REFLECT_X | \
-- DRM_MODE_REFLECT_Y)
--
- struct mailbox_set_plane {
- struct rpi_firmware_property_tag_header tag;
- struct set_plane plane;
-@@ -523,7 +518,7 @@ static int vc4_plane_to_mb(struct drm_pl
- const struct vc_image_format *vc_fmt =
- vc4_get_vc_image_fmt(drm_fmt->format);
- int num_planes = fb->format->num_planes;
-- unsigned int rotation = SUPPORTED_ROTATIONS;
-+ unsigned int rotation;
-
- mb->plane.vc_image_type = vc_fmt->vc_image;
- mb->plane.width = fb->width;
-@@ -544,23 +539,16 @@ static int vc4_plane_to_mb(struct drm_pl
- mb->plane.is_vu = vc_fmt->is_vu;
- mb->plane.planes[0] = bo->paddr + fb->offsets[0];
-
-- rotation = drm_rotation_simplify(state->rotation, rotation);
--
-- switch (rotation) {
-- default:
-- case DRM_MODE_ROTATE_0:
-- mb->plane.transform = TRANSFORM_NO_ROTATE;
-- break;
-- case DRM_MODE_ROTATE_180:
-- mb->plane.transform = TRANSFORM_ROTATE_180;
-- break;
-- case DRM_MODE_REFLECT_X:
-- mb->plane.transform = TRANSFORM_FLIP_HRIZ;
-- break;
-- case DRM_MODE_REFLECT_Y:
-- mb->plane.transform = TRANSFORM_FLIP_VERT;
-- break;
-- }
-+ rotation = drm_rotation_simplify(state->rotation,
-+ DRM_MODE_ROTATE_0 |
-+ DRM_MODE_REFLECT_X |
-+ DRM_MODE_REFLECT_Y);
-+
-+ mb->plane.transform = TRANSFORM_NO_ROTATE;
-+ if (rotation & DRM_MODE_REFLECT_X)
-+ mb->plane.transform |= TRANSFORM_FLIP_HRIZ;
-+ if (rotation & DRM_MODE_REFLECT_Y)
-+ mb->plane.transform |= TRANSFORM_FLIP_VERT;
-
- vc4_fkms_margins_adj(state, &mb->plane);
-
-@@ -772,7 +760,10 @@ static struct drm_plane *vc4_fkms_plane_
-
- drm_plane_create_alpha_property(plane);
- drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
-- SUPPORTED_ROTATIONS);
-+ DRM_MODE_ROTATE_0 |
-+ DRM_MODE_ROTATE_180 |
-+ DRM_MODE_REFLECT_X |
-+ DRM_MODE_REFLECT_Y);
- drm_plane_create_color_properties(plane,
- BIT(DRM_COLOR_YCBCR_BT601) |
- BIT(DRM_COLOR_YCBCR_BT709) |
--- /dev/null
+From 1a013467030ffd6f1958b8a4db1b5312213fb9bd Mon Sep 17 00:00:00 2001
+Date: Thu, 17 Oct 2019 10:16:16 +0100
+Subject: [PATCH] media: bcm2835-unicam: Replace hard coded loop limit
+ with a define
+
+In order to protect against a dodgy sensor driver never returning
+an error from enum_mbus_code there was a hardcoded value of 128
+that aborted the loop.
+There is a need to call enum_mbus_code from elsewhere, so move that
+number to a define so it is common across calls.
+
+---
+ drivers/media/platform/bcm2835/bcm2835-unicam.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
+@@ -97,6 +97,11 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
+ #define unicam_err(dev, fmt, arg...) \
+ v4l2_err(&(dev)->v4l2_dev, fmt, ##arg)
+
++/* To protect against a dodgy sensor driver never returning an error from
++ * enum_mbus_code, set a maximum index value to be used.
++ */
++#define MAX_ENUM_MBUS_CODE 128
++
+ /*
+ * Stride is a 16 bit register, but also has to be a multiple of 16.
+ */
+@@ -738,11 +743,7 @@ static int unicam_enum_fmt_vid_cap(struc
+ int ret = 0;
+ int i;
+
+- /* Loop whilst the sensor driver says it has more formats, but add a
+- * failsafe against a dodgy driver at 128 (more than any sensor will
+- * ever sensibly advertise)
+- */
+- for (i = 0; !ret && i < 128 ; i++) {
++ for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) {
+ memset(&mbus_code, 0, sizeof(mbus_code));
+ mbus_code.index = i;
+
--- /dev/null
+From 94d77466473f3abcf799ac44b8038766ab32f27c Mon Sep 17 00:00:00 2001
+Date: Wed, 16 Oct 2019 18:53:06 +0100
+Subject: [PATCH] media: bcm2835-unicam: Fix one-to-many mapping for
+ YUYV formats
+
+V4L2 format V4L2_PIX_FMT_YUYV maps to both MEDIA_BUS_FMT_YUYV8_2X8
+and MEDIA_BUS_FMT_YUYV8_1X16. The change to not cache the active
+formats also meant that we only ever found the first variant of
+the mediabus format when trying to setup the device.
+
+Flag the formats that have other representations, and ensure
+that the format conversion checks whether the found format
+matches one supported by the sensor before returning it.
+
+---
+ .../media/platform/bcm2835/bcm2835-unicam.c | 45 ++++++++++++++++---
+ 1 file changed, 39 insertions(+), 6 deletions(-)
+
+--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
+@@ -136,6 +136,8 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
+ * @code: V4L2 media bus format code.
+ * @depth: Bits per pixel as delivered from the source.
+ * @csi_dt: CSI data type.
++ * @check_variants: Flag to denote that there are multiple mediabus formats
++ * still in the list that could match this V4L2 format.
+ */
+ struct unicam_fmt {
+ u32 fourcc;
+@@ -143,6 +145,7 @@ struct unicam_fmt {
+ u32 code;
+ u8 depth;
+ u8 csi_dt;
++ u8 check_variants;
+ };
+
+ static const struct unicam_fmt formats[] = {
+@@ -152,21 +155,25 @@ static const struct unicam_fmt formats[]
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .depth = 16,
+ .csi_dt = 0x1e,
++ .check_variants = 1,
+ }, {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .depth = 16,
+ .csi_dt = 0x1e,
++ .check_variants = 1,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .code = MEDIA_BUS_FMT_YVYU8_2X8,
+ .depth = 16,
+ .csi_dt = 0x1e,
++ .check_variants = 1,
+ }, {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
+ .depth = 16,
+ .csi_dt = 0x1e,
++ .check_variants = 1,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .code = MEDIA_BUS_FMT_YUYV8_1X16,
+@@ -489,14 +496,40 @@ static const struct unicam_fmt *find_for
+ return NULL;
+ }
+
+-static const struct unicam_fmt *find_format_by_pix(u32 pixelformat)
++static int check_mbus_format(struct unicam_device *dev,
++ const struct unicam_fmt *format)
++{
++ struct v4l2_subdev_mbus_code_enum mbus_code;
++ int ret = 0;
++ int i;
++
++ for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) {
++ memset(&mbus_code, 0, sizeof(mbus_code));
++ mbus_code.index = i;
++
++ ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code,
++ NULL, &mbus_code);
++
++ if (!ret && mbus_code.code == format->code)
++ return 1;
++ }
++
++ return 0;
++}
++
++static const struct unicam_fmt *find_format_by_pix(struct unicam_device *dev,
++ u32 pixelformat)
+ {
+ unsigned int k;
+
+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
+ if (formats[k].fourcc == pixelformat ||
+- formats[k].repacked_fourcc == pixelformat)
++ formats[k].repacked_fourcc == pixelformat) {
++ if (formats[k].check_variants &&
++ !check_mbus_format(dev, &formats[k]))
++ continue;
+ return &formats[k];
++ }
+ }
+
+ return NULL;
+@@ -832,7 +865,7 @@ static int unicam_try_fmt_vid_cap(struct
+ struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
+ int ret;
+
+- fmt = find_format_by_pix(f->fmt.pix.pixelformat);
++ fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
+ if (!fmt) {
+ /* Pixel format not supported by unicam. Choose the first
+ * supported format, and let the sensor choose something else.
+@@ -917,7 +950,7 @@ static int unicam_s_fmt_vid_cap(struct f
+ if (ret < 0)
+ return ret;
+
+- fmt = find_format_by_pix(f->fmt.pix.pixelformat);
++ fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
+ if (!fmt) {
+ /* Unknown pixel format - adopt a default.
+ * This shouldn't happen as try_fmt should have resolved any
+@@ -1540,7 +1573,7 @@ static int unicam_enum_framesizes(struct
+ int ret;
+
+ /* check for valid format */
+- fmt = find_format_by_pix(fsize->pixel_format);
++ fmt = find_format_by_pix(dev, fsize->pixel_format);
+ if (!fmt) {
+ unicam_dbg(3, dev, "Invalid pixel code: %x\n",
+ fsize->pixel_format);
+@@ -1579,7 +1612,7 @@ static int unicam_enum_frameintervals(st
+ };
+ int ret;
+
+- fmt = find_format_by_pix(fival->pixel_format);
++ fmt = find_format_by_pix(dev, fival->pixel_format);
+ if (!fmt)
+ return -EINVAL;
+
+++ /dev/null
-From cb9a896a799393b3cb5947bef3c95eb5ffb44776 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2019 09:08:47 +0100
-Subject: [PATCH] overlays: Add w5500 overlay
-
-Add an overlay to configure the Wiznet W5500 Ethernet controller on
-SPI0. The 'cs' parameter chooses the Chip Select (default 0).
-
-See: https://github.com/raspberrypi/linux/issues/3276
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 10 ++++
- arch/arm/boot/dts/overlays/w5500-overlay.dts | 63 ++++++++++++++++++++
- 3 files changed, 74 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/w5500-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -183,6 +183,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- vga666.dtbo \
- w1-gpio.dtbo \
- w1-gpio-pullup.dtbo \
-+ w5500.dtbo \
- wittypi.dtbo
-
- targets += dtbs dtbs_install
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -2538,6 +2538,16 @@ Params: gpiopin GPIO for
- pullup Now enabled by default (ignored)
-
-
-+Name: w5500
-+Info: Overlay for the Wiznet W5500 Ethernet Controller on SPI0
-+Load: dtoverlay=w5500,<param>=<val>
-+Params: int_pin GPIO used for INT (default 25)
-+
-+ speed SPI bus speed (default 30000000)
-+
-+ cs SPI bus Chip Select (default 0)
-+
-+
- Name: wittypi
- Info: Configures the wittypi RTC module.
- Load: dtoverlay=wittypi,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/w5500-overlay.dts
-@@ -0,0 +1,63 @@
-+// Overlay for the Wiznet w5500 Ethernet Controller
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&spidev0>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spidev1>;
-+ __dormant__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ eth1: w5500@0{
-+ compatible = "wiznet,w5500";
-+ reg = <0>; /* CE0 */
-+ pinctrl-names = "default";
-+ pinctrl-0 = <ð1_pins>;
-+ interrupt-parent = <&gpio>;
-+ interrupts = <25 0x8>;
-+ spi-max-frequency = <30000000>;
-+// local-mac-address = [aa bb cc dd ee ff];
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ eth1_pins: eth1_pins {
-+ brcm,pins = <25>;
-+ brcm,function = <0>; /* in */
-+ brcm,pull = <0>; /* none */
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ int_pin = <ð1>, "interrupts:0",
-+ <ð1_pins>, "brcm,pins:0";
-+ speed = <ð1>, "spi-max-frequency:0";
-+ cs = <ð1>, "reg:0",
-+ <0>, "!0=1";
-+ };
-+};
--- /dev/null
+From b4f8b92cdfd8ad2e04cdd3f0a73aa4e95d172fb1 Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Oct 2019 19:12:08 +0200
+Subject: [PATCH] dt-bindings: Add binding for the Infineon IRS1125
+ sensor
+
+Adds a binding for the Infineon IRS1125 time-of-flight depth
+sensor.
+
+---
+ .../devicetree/bindings/media/i2c/irs1125.txt | 48 +++++++++++++++++++
+ 1 file changed, 48 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/media/i2c/irs1125.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/media/i2c/irs1125.txt
+@@ -0,0 +1,48 @@
++* Infineon irs1125 time of flight sensor
++
++The Infineon irs1125 is a time of flight digital image sensor with
++an active array size of 352H x 286V. It is programmable through I2C
++interface. The I2C address defaults to 0x3D, but can be reconfigured
++to address 0x3C or 0x41 via I2C commands. Image data is sent through
++MIPI CSI-2, which is configured as either 1 or 2 data lanes.
++
++Required Properties:
++- compatible: value should be "infineon,irs1125" for irs1125 sensor
++- reg: I2C bus address of the device
++- clocks: reference to the xclk input clock.
++- pwdn-gpios: reference to the GPIO connected to the reset pin.
++ This is an active low signal to the iirs1125.
++
++The irs1125 device node should contain one 'port' child node with
++an 'endpoint' subnode. For further reading on port node refer to
++Documentation/devicetree/bindings/media/video-interfaces.txt.
++
++Endpoint node required properties for CSI-2 connection are:
++- remote-endpoint: a phandle to the bus receiver's endpoint node.
++- clock-lanes: should be set to <0> (clock lane on hardware lane 0)
++- data-lanes: should be set to <1> or <1 2> (one or two lane CSI-2
++ supported)
++
++Example:
++ sensor@10 {
++ compatible = "infineon,irs1125";
++ reg = <0x3D>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clocks = <&irs1125_clk>;
++ pwdn-gpios = <&gpio 5 0>;
++
++ irs1125_clk: camera-clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <26000000>;
++ };
++
++ port {
++ sensor_out: endpoint {
++ remote-endpoint = <&csiss_in>;
++ clock-lanes = <0>;
++ data-lanes = <1 2>;
++ };
++ };
++ };
+++ /dev/null
-From 1a013467030ffd6f1958b8a4db1b5312213fb9bd Mon Sep 17 00:00:00 2001
-Date: Thu, 17 Oct 2019 10:16:16 +0100
-Subject: [PATCH] media: bcm2835-unicam: Replace hard coded loop limit
- with a define
-
-In order to protect against a dodgy sensor driver never returning
-an error from enum_mbus_code there was a hardcoded value of 128
-that aborted the loop.
-There is a need to call enum_mbus_code from elsewhere, so move that
-number to a define so it is common across calls.
-
----
- drivers/media/platform/bcm2835/bcm2835-unicam.c | 11 ++++++-----
- 1 file changed, 6 insertions(+), 5 deletions(-)
-
---- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
-@@ -97,6 +97,11 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
- #define unicam_err(dev, fmt, arg...) \
- v4l2_err(&(dev)->v4l2_dev, fmt, ##arg)
-
-+/* To protect against a dodgy sensor driver never returning an error from
-+ * enum_mbus_code, set a maximum index value to be used.
-+ */
-+#define MAX_ENUM_MBUS_CODE 128
-+
- /*
- * Stride is a 16 bit register, but also has to be a multiple of 16.
- */
-@@ -738,11 +743,7 @@ static int unicam_enum_fmt_vid_cap(struc
- int ret = 0;
- int i;
-
-- /* Loop whilst the sensor driver says it has more formats, but add a
-- * failsafe against a dodgy driver at 128 (more than any sensor will
-- * ever sensibly advertise)
-- */
-- for (i = 0; !ret && i < 128 ; i++) {
-+ for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) {
- memset(&mbus_code, 0, sizeof(mbus_code));
- mbus_code.index = i;
-
+++ /dev/null
-From 94d77466473f3abcf799ac44b8038766ab32f27c Mon Sep 17 00:00:00 2001
-Date: Wed, 16 Oct 2019 18:53:06 +0100
-Subject: [PATCH] media: bcm2835-unicam: Fix one-to-many mapping for
- YUYV formats
-
-V4L2 format V4L2_PIX_FMT_YUYV maps to both MEDIA_BUS_FMT_YUYV8_2X8
-and MEDIA_BUS_FMT_YUYV8_1X16. The change to not cache the active
-formats also meant that we only ever found the first variant of
-the mediabus format when trying to setup the device.
-
-Flag the formats that have other representations, and ensure
-that the format conversion checks whether the found format
-matches one supported by the sensor before returning it.
-
----
- .../media/platform/bcm2835/bcm2835-unicam.c | 45 ++++++++++++++++---
- 1 file changed, 39 insertions(+), 6 deletions(-)
-
---- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
-@@ -136,6 +136,8 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
- * @code: V4L2 media bus format code.
- * @depth: Bits per pixel as delivered from the source.
- * @csi_dt: CSI data type.
-+ * @check_variants: Flag to denote that there are multiple mediabus formats
-+ * still in the list that could match this V4L2 format.
- */
- struct unicam_fmt {
- u32 fourcc;
-@@ -143,6 +145,7 @@ struct unicam_fmt {
- u32 code;
- u8 depth;
- u8 csi_dt;
-+ u8 check_variants;
- };
-
- static const struct unicam_fmt formats[] = {
-@@ -152,21 +155,25 @@ static const struct unicam_fmt formats[]
- .code = MEDIA_BUS_FMT_YUYV8_2X8,
- .depth = 16,
- .csi_dt = 0x1e,
-+ .check_variants = 1,
- }, {
- .fourcc = V4L2_PIX_FMT_UYVY,
- .code = MEDIA_BUS_FMT_UYVY8_2X8,
- .depth = 16,
- .csi_dt = 0x1e,
-+ .check_variants = 1,
- }, {
- .fourcc = V4L2_PIX_FMT_YVYU,
- .code = MEDIA_BUS_FMT_YVYU8_2X8,
- .depth = 16,
- .csi_dt = 0x1e,
-+ .check_variants = 1,
- }, {
- .fourcc = V4L2_PIX_FMT_VYUY,
- .code = MEDIA_BUS_FMT_VYUY8_2X8,
- .depth = 16,
- .csi_dt = 0x1e,
-+ .check_variants = 1,
- }, {
- .fourcc = V4L2_PIX_FMT_YUYV,
- .code = MEDIA_BUS_FMT_YUYV8_1X16,
-@@ -489,14 +496,40 @@ static const struct unicam_fmt *find_for
- return NULL;
- }
-
--static const struct unicam_fmt *find_format_by_pix(u32 pixelformat)
-+static int check_mbus_format(struct unicam_device *dev,
-+ const struct unicam_fmt *format)
-+{
-+ struct v4l2_subdev_mbus_code_enum mbus_code;
-+ int ret = 0;
-+ int i;
-+
-+ for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) {
-+ memset(&mbus_code, 0, sizeof(mbus_code));
-+ mbus_code.index = i;
-+
-+ ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code,
-+ NULL, &mbus_code);
-+
-+ if (!ret && mbus_code.code == format->code)
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct unicam_fmt *find_format_by_pix(struct unicam_device *dev,
-+ u32 pixelformat)
- {
- unsigned int k;
-
- for (k = 0; k < ARRAY_SIZE(formats); k++) {
- if (formats[k].fourcc == pixelformat ||
-- formats[k].repacked_fourcc == pixelformat)
-+ formats[k].repacked_fourcc == pixelformat) {
-+ if (formats[k].check_variants &&
-+ !check_mbus_format(dev, &formats[k]))
-+ continue;
- return &formats[k];
-+ }
- }
-
- return NULL;
-@@ -832,7 +865,7 @@ static int unicam_try_fmt_vid_cap(struct
- struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
- int ret;
-
-- fmt = find_format_by_pix(f->fmt.pix.pixelformat);
-+ fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
- if (!fmt) {
- /* Pixel format not supported by unicam. Choose the first
- * supported format, and let the sensor choose something else.
-@@ -917,7 +950,7 @@ static int unicam_s_fmt_vid_cap(struct f
- if (ret < 0)
- return ret;
-
-- fmt = find_format_by_pix(f->fmt.pix.pixelformat);
-+ fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat);
- if (!fmt) {
- /* Unknown pixel format - adopt a default.
- * This shouldn't happen as try_fmt should have resolved any
-@@ -1540,7 +1573,7 @@ static int unicam_enum_framesizes(struct
- int ret;
-
- /* check for valid format */
-- fmt = find_format_by_pix(fsize->pixel_format);
-+ fmt = find_format_by_pix(dev, fsize->pixel_format);
- if (!fmt) {
- unicam_dbg(3, dev, "Invalid pixel code: %x\n",
- fsize->pixel_format);
-@@ -1579,7 +1612,7 @@ static int unicam_enum_frameintervals(st
- };
- int ret;
-
-- fmt = find_format_by_pix(fival->pixel_format);
-+ fmt = find_format_by_pix(dev, fival->pixel_format);
- if (!fmt)
- return -EINVAL;
-
--- /dev/null
+From c09b42cb057ddf8bd20d57c6b0ffd94f3e15ea7c Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Oct 2019 19:12:36 +0200
+Subject: [PATCH] media: i2c: Add a driver for the Infineon IRS1125
+ depth sensor
+
+The Infineon IRS1125 is a time of flight depth sensor that
+has a CSI-2 interface.
+
+Add a V4L2 subdevice driver for this device.
+
+---
+ drivers/media/i2c/Kconfig | 12 +
+ drivers/media/i2c/Makefile | 1 +
+ drivers/media/i2c/irs1125.c | 1112 +++++++++++++++++++++++++++++++++++
+ drivers/media/i2c/irs1125.h | 61 ++
+ 4 files changed, 1186 insertions(+)
+ create mode 100644 drivers/media/i2c/irs1125.c
+ create mode 100644 drivers/media/i2c/irs1125.h
+
+--- a/drivers/media/i2c/Kconfig
++++ b/drivers/media/i2c/Kconfig
+@@ -813,6 +813,18 @@ config VIDEO_OV13858
+ This is a Video4Linux2 sensor driver for the OmniVision
+ OV13858 camera.
+
++config VIDEO_IRS1125
++ tristate "Infineon IRS1125 sensor support"
++ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
++ depends on MEDIA_CAMERA_SUPPORT
++ select V4L2_FWNODE
++ help
++ This is a Video4Linux2 sensor-level driver for the Infineon
++ IRS1125 camera.
++
++ To compile this driver as a module, choose M here: the
++ module will be called irs1125.
++
+ config VIDEO_VS6624
+ tristate "ST VS6624 sensor support"
+ depends on VIDEO_V4L2 && I2C
+--- a/drivers/media/i2c/Makefile
++++ b/drivers/media/i2c/Makefile
+@@ -80,6 +80,7 @@ obj-$(CONFIG_VIDEO_OV772X) += ov772x.o
+ obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
+ obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
+ obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
++obj-$(CONFIG_VIDEO_IRS1125) += irs1125.o
+ obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
+ obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o
+ obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
+--- /dev/null
++++ b/drivers/media/i2c/irs1125.c
+@@ -0,0 +1,1112 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * A V4L2 driver for Infineon IRS1125 TOF cameras.
++ * Copyright (C) 2018, pieye GmbH
++ *
++ * Based on V4L2 OmniVision OV5647 Image Sensor driver
++ *
++ * DT / fwnode changes, and GPIO control taken from ov5640.c
++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright (C) 2014-2017 Mentor Graphics Inc.
++ *
++ */
++
++#include "irs1125.h"
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/gpio/consumer.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_graph.h>
++#include <linux/slab.h>
++#include <linux/videodev2.h>
++#include <linux/firmware.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-fwnode.h>
++#include <media/v4l2-image-sizes.h>
++#include <media/v4l2-mediabus.h>
++#include <media/v4l2-ctrls.h>
++
++#define CHECK_BIT(val, pos) ((val) & BIT(pos))
++
++#define SENSOR_NAME "irs1125"
++
++#define RESET_ACTIVE_DELAY_MS 20
++
++#define IRS1125_ALTERNATE_FW "irs1125_af.bin"
++
++#define IRS1125_REG_CSICFG 0xA882
++#define IRS1125_REG_DESIGN_STEP 0xB0AD
++#define IRS1125_REG_EFUSEVAL2 0xB09F
++#define IRS1125_REG_EFUSEVAL3 0xB0A0
++#define IRS1125_REG_EFUSEVAL4 0xB0A1
++#define IRS1125_REG_DMEM_SHADOW 0xC320
++
++#define IRS1125_DESIGN_STEP_EXPECTED 0x0a12
++
++#define IRS1125_ROW_START_DEF 0
++#define IRS1125_COLUMN_START_DEF 0
++#define IRS1125_WINDOW_HEIGHT_DEF 288
++#define IRS1125_WINDOW_WIDTH_DEF 352
++
++struct regval_list {
++ u16 addr;
++ u16 data;
++};
++
++struct irs1125 {
++ struct v4l2_subdev sd;
++ struct media_pad pad;
++ /* the parsed DT endpoint info */
++ struct v4l2_fwnode_endpoint ep;
++
++ struct clk *xclk;
++ struct v4l2_ctrl_handler ctrl_handler;
++
++ /* To serialize asynchronus callbacks */
++ struct mutex lock;
++
++ /* image data layout */
++ unsigned int num_seq;
++
++ /* reset pin */
++ struct gpio_desc *reset;
++
++ /* V4l2 Controls to grab */
++ struct v4l2_ctrl *ctrl_modplls;
++ struct v4l2_ctrl *ctrl_numseq;
++
++ int power_count;
++};
++
++static inline struct irs1125 *to_state(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct irs1125, sd);
++}
++
++static struct regval_list irs1125_26MHz[] = {
++ {0xB017, 0x0413},
++ {0xB086, 0x3535},
++ {0xB0AE, 0xEF02},
++ {0xA000, 0x0004},
++ {0xFFFF, 100},
++
++ {0xB062, 0x6383},
++ {0xB063, 0x55A8},
++ {0xB068, 0x7628},
++ {0xB069, 0x03E2},
++
++ {0xFFFF, 100},
++ {0xB05A, 0x01C5},
++ {0xB05C, 0x0206},
++ {0xB05D, 0x01C5},
++ {0xB05F, 0x0206},
++ {0xB016, 0x1335},
++ {0xFFFF, 100},
++ {0xA893, 0x8261},
++ {0xA894, 0x89d8},
++ {0xA895, 0x131d},
++ {0xA896, 0x4251},
++ {0xA897, 0x9D8A},
++ {0xA898, 0x0BD8},
++ {0xA899, 0x2245},
++ {0xA89A, 0xAB9B},
++ {0xA89B, 0x03B9},
++ {0xA89C, 0x8041},
++ {0xA89D, 0xE07E},
++ {0xA89E, 0x0307},
++ {0xFFFF, 100},
++ {0xA88D, 0x0004},
++ {0xA800, 0x0E68},
++ {0xA801, 0x0000},
++ {0xA802, 0x000C},
++ {0xA803, 0x0000},
++ {0xA804, 0x0E68},
++ {0xA805, 0x0000},
++ {0xA806, 0x0440},
++ {0xA807, 0x0000},
++ {0xA808, 0x0E68},
++ {0xA809, 0x0000},
++ {0xA80A, 0x0884},
++ {0xA80B, 0x0000},
++ {0xA80C, 0x0E68},
++ {0xA80D, 0x0000},
++ {0xA80E, 0x0CC8},
++ {0xA80F, 0x0000},
++ {0xA810, 0x0E68},
++ {0xA811, 0x0000},
++ {0xA812, 0x2000},
++ {0xA813, 0x0000},
++ {0xA882, 0x0081},
++ {0xA88C, 0x403A},
++ {0xA88F, 0x031E},
++ {0xA892, 0x0351},
++ {0x9813, 0x13FF},
++ {0x981B, 0x7608},
++
++ {0xB008, 0x0000},
++ {0xB015, 0x1513},
++
++ {0xFFFF, 100}
++};
++
++static struct regval_list irs1125_seq_cfg[] = {
++ {0xC3A0, 0x823D},
++ {0xC3A1, 0xB13B},
++ {0xC3A2, 0x0313},
++ {0xC3A3, 0x4659},
++ {0xC3A4, 0xC4EC},
++ {0xC3A5, 0x03CE},
++ {0xC3A6, 0x4259},
++ {0xC3A7, 0xC4EC},
++ {0xC3A8, 0x03CE},
++ {0xC3A9, 0x8839},
++ {0xC3AA, 0x89D8},
++ {0xC3AB, 0x031D},
++
++ {0xC24C, 0x5529},
++ {0xC24D, 0x0000},
++ {0xC24E, 0x1200},
++ {0xC24F, 0x6CB2},
++ {0xC250, 0x0000},
++ {0xC251, 0x5529},
++ {0xC252, 0x42F4},
++ {0xC253, 0xD1AF},
++ {0xC254, 0x8A18},
++ {0xC255, 0x0002},
++ {0xC256, 0x5529},
++ {0xC257, 0x6276},
++ {0xC258, 0x11A7},
++ {0xC259, 0xD907},
++ {0xC25A, 0x0000},
++ {0xC25B, 0x5529},
++ {0xC25C, 0x07E0},
++ {0xC25D, 0x7BFE},
++ {0xC25E, 0x6402},
++ {0xC25F, 0x0019},
++
++ {0xC3AC, 0x0007},
++ {0xC3AD, 0xED88},
++ {0xC320, 0x003E},
++ {0xC321, 0x0000},
++ {0xC322, 0x2000},
++ {0xC323, 0x0000},
++ {0xC324, 0x0271},
++ {0xC325, 0x0000},
++ {0xC326, 0x000C},
++ {0xC327, 0x0000},
++ {0xC328, 0x0271},
++ {0xC329, 0x0000},
++ {0xC32A, 0x0440},
++ {0xC32B, 0x0000},
++ {0xC32C, 0x0271},
++ {0xC32D, 0x0000},
++ {0xC32E, 0x0884},
++ {0xC32F, 0x0000},
++ {0xC330, 0x0271},
++ {0xC331, 0x0000},
++ {0xC332, 0x0CC8},
++ {0xC333, 0x0000},
++ {0xA88D, 0x0004},
++
++ {0xA890, 0x0000},
++ {0xC219, 0x0002},
++ {0xC21A, 0x0000},
++ {0xC21B, 0x0000},
++ {0xC21C, 0x00CD},
++ {0xC21D, 0x0009},
++ {0xC21E, 0x00CD},
++ {0xC21F, 0x0009},
++
++ {0xA87C, 0x0000},
++ {0xC032, 0x0001},
++ {0xC034, 0x0000},
++ {0xC035, 0x0001},
++ {0xC039, 0x0000},
++ {0xC401, 0x0002},
++
++ {0xFFFF, 1},
++ {0xA87C, 0x0001}
++};
++
++static int irs1125_write(struct v4l2_subdev *sd, u16 reg, u16 val)
++{
++ int ret;
++ unsigned char data[4] = { reg >> 8, reg & 0xff, val >> 8, val & 0xff};
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ ret = i2c_master_send(client, data, 4);
++ if (ret < 0)
++ dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
++ __func__, reg);
++
++ return ret;
++}
++
++static int irs1125_read(struct v4l2_subdev *sd, u16 reg, u16 *val)
++{
++ int ret;
++ unsigned char data_w[2] = { reg >> 8, reg & 0xff };
++ char rdval[2];
++
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ ret = i2c_master_send(client, data_w, 2);
++ if (ret < 0) {
++ dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
++ __func__, reg);
++ return ret;
++ }
++
++ ret = i2c_master_recv(client, rdval, 2);
++ if (ret < 0)
++ dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
++ __func__, reg);
++
++ *val = rdval[1] | (rdval[0] << 8);
++
++ return ret;
++}
++
++static int irs1125_write_array(struct v4l2_subdev *sd,
++ struct regval_list *regs, int array_size)
++{
++ int i, ret;
++
++ for (i = 0; i < array_size; i++) {
++ if (regs[i].addr == 0xFFFF) {
++ msleep(regs[i].data);
++ } else {
++ ret = irs1125_write(sd, regs[i].addr, regs[i].data);
++ if (ret < 0)
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static int irs1125_stream_on(struct v4l2_subdev *sd)
++{
++ int ret;
++ struct irs1125 *irs1125 = to_state(sd);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ v4l2_ctrl_grab(irs1125->ctrl_numseq, 1);
++ v4l2_ctrl_grab(irs1125->ctrl_modplls, 1);
++
++ ret = irs1125_write(sd, 0xC400, 0x0001);
++ if (ret < 0) {
++ dev_err(&client->dev, "error enabling firmware: %d", ret);
++ return ret;
++ }
++
++ msleep(100);
++
++ return irs1125_write(sd, 0xA87C, 0x0001);
++}
++
++static int irs1125_stream_off(struct v4l2_subdev *sd)
++{
++ int ret;
++ struct irs1125 *irs1125 = to_state(sd);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ v4l2_ctrl_grab(irs1125->ctrl_numseq, 0);
++ v4l2_ctrl_grab(irs1125->ctrl_modplls, 0);
++
++ ret = irs1125_write(sd, 0xA87C, 0x0000);
++ if (ret < 0) {
++ dev_err(&client->dev, "error disabling trigger: %d", ret);
++ return ret;
++ }
++
++ msleep(100);
++
++ return irs1125_write(sd, 0xC400, 0x0002);
++}
++
++static int __sensor_init(struct v4l2_subdev *sd)
++{
++ unsigned int cnt, idx;
++ int ret;
++ u16 val;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct irs1125 *irs1125 = to_state(sd);
++ const struct firmware *fw;
++ struct regval_list *reg_data;
++
++ cnt = 0;
++ while (1) {
++ ret = irs1125_read(sd, 0xC40F, &val);
++ if (ret < 0) {
++ dev_err(&client->dev, "read register 0xC40F failed\n");
++ return ret;
++ }
++ if (CHECK_BIT(val, 14) == 0)
++ break;
++
++ if (cnt >= 5) {
++ dev_err(&client->dev, "timeout waiting for 0xC40F\n");
++ return -EAGAIN;
++ }
++
++ cnt++;
++ }
++
++ ret = irs1125_write_array(sd, irs1125_26MHz,
++ ARRAY_SIZE(irs1125_26MHz));
++ if (ret < 0) {
++ dev_err(&client->dev, "write sensor default regs error\n");
++ return ret;
++ }
++
++ /* set CSI-2 number of data lanes */
++ if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 1) {
++ val = 0x0001;
++ } else if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 2) {
++ val = 0x0081;
++ } else {
++ dev_err(&client->dev, "invalid number of data lanes %d\n",
++ irs1125->ep.bus.mipi_csi2.num_data_lanes);
++ return -EINVAL;
++ }
++
++ ret = irs1125_write(sd, IRS1125_REG_CSICFG, val);
++ if (ret < 0) {
++ dev_err(&client->dev, "write sensor csi2 config error\n");
++ return ret;
++ }
++
++ /* request the firmware, this will block and timeout */
++ ret = request_firmware(&fw, IRS1125_ALTERNATE_FW, &client->dev);
++ if (ret) {
++ dev_err(&client->dev,
++ "did not find the firmware file '%s' (status %d)\n",
++ IRS1125_ALTERNATE_FW, ret);
++ return ret;
++ }
++
++ if (fw->size % 4) {
++ dev_err(&client->dev, "firmware file '%s' invalid\n",
++ IRS1125_ALTERNATE_FW);
++ release_firmware(fw);
++ return -EINVAL;
++ }
++
++ for (idx = 0; idx < fw->size; idx += 4) {
++ reg_data = (struct regval_list *)&fw->data[idx];
++ ret = irs1125_write(sd, reg_data->addr, reg_data->data);
++ if (ret < 0) {
++ dev_err(&client->dev, "firmware write error\n");
++ release_firmware(fw);
++ return ret;
++ }
++ }
++ release_firmware(fw);
++
++ ret = irs1125_write_array(sd, irs1125_seq_cfg,
++ ARRAY_SIZE(irs1125_seq_cfg));
++ if (ret < 0) {
++ dev_err(&client->dev, "write default sequence failed\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static int irs1125_sensor_power(struct v4l2_subdev *sd, int on)
++{
++ int ret = 0;
++ struct irs1125 *irs1125 = to_state(sd);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ mutex_lock(&irs1125->lock);
++
++ if (on && !irs1125->power_count) {
++ gpiod_set_value_cansleep(irs1125->reset, 1);
++ msleep(RESET_ACTIVE_DELAY_MS);
++
++ ret = clk_prepare_enable(irs1125->xclk);
++ if (ret < 0) {
++ dev_err(&client->dev, "clk prepare enable failed\n");
++ goto out;
++ }
++
++ ret = __sensor_init(sd);
++ if (ret < 0) {
++ clk_disable_unprepare(irs1125->xclk);
++ dev_err(&client->dev,
++ "Camera not available, check Power\n");
++ goto out;
++ }
++ } else if (!on && irs1125->power_count == 1) {
++ gpiod_set_value_cansleep(irs1125->reset, 0);
++ }
++
++ /* Update the power count. */
++ irs1125->power_count += on ? 1 : -1;
++ WARN_ON(irs1125->power_count < 0);
++
++out:
++ mutex_unlock(&irs1125->lock);
++
++ return ret;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int irs1125_sensor_get_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ u16 val;
++ int ret;
++
++ ret = irs1125_read(sd, reg->reg & 0xffff, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = 1;
++
++ return 0;
++}
++
++static int irs1125_sensor_set_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ return irs1125_write(sd, reg->reg & 0xffff, reg->val & 0xffff);
++}
++#endif
++
++static const struct v4l2_subdev_core_ops irs1125_subdev_core_ops = {
++ .s_power = irs1125_sensor_power,
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = irs1125_sensor_get_register,
++ .s_register = irs1125_sensor_set_register,
++#endif
++};
++
++static int irs1125_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ if (enable)
++ return irs1125_stream_on(sd);
++ else
++ return irs1125_stream_off(sd);
++}
++
++static const struct v4l2_subdev_video_ops irs1125_subdev_video_ops = {
++ .s_stream = irs1125_s_stream,
++};
++
++static int irs1125_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ if (code->index > 0)
++ return -EINVAL;
++
++ code->code = MEDIA_BUS_FMT_Y12_1X12;
++
++ return 0;
++}
++
++static int irs1125_set_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *fmt = &format->format;
++ struct irs1125 *irs1125 = to_state(sd);
++
++ if (format->pad != 0)
++ return -EINVAL;
++
++ /* Only one format is supported, so return that */
++ memset(fmt, 0, sizeof(*fmt));
++ fmt->code = MEDIA_BUS_FMT_Y12_1X12;
++ fmt->colorspace = V4L2_COLORSPACE_RAW;
++ fmt->field = V4L2_FIELD_NONE;
++ fmt->width = IRS1125_WINDOW_WIDTH_DEF;
++ fmt->height = IRS1125_WINDOW_HEIGHT_DEF * irs1125->num_seq;
++
++ return 0;
++}
++
++static const struct v4l2_subdev_pad_ops irs1125_subdev_pad_ops = {
++ .enum_mbus_code = irs1125_enum_mbus_code,
++ .set_fmt = irs1125_set_get_fmt,
++ .get_fmt = irs1125_set_get_fmt,
++};
++
++static const struct v4l2_subdev_ops irs1125_subdev_ops = {
++ .core = &irs1125_subdev_core_ops,
++ .video = &irs1125_subdev_video_ops,
++ .pad = &irs1125_subdev_pad_ops,
++};
++
++static int irs1125_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct irs1125 *dev = container_of(ctrl->handler,
++ struct irs1125, ctrl_handler);
++ struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
++ int err, i;
++ struct irs1125_mod_pll *mod_cur, *mod_new;
++ struct irs1125_seq_cfg *cfg_cur, *cfg_new;
++ u16 addr, val;
++
++ err = 0;
++
++ switch (ctrl->id) {
++ case IRS1125_CID_SAFE_RECONFIG:
++ {
++ struct irs1125_illu *illu_cur, *illu_new;
++
++ illu_new = (struct irs1125_illu *)ctrl->p_new.p;
++ illu_cur = (struct irs1125_illu *)ctrl->p_cur.p;
++ for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
++ if (illu_cur[i].exposure != illu_new[i].exposure) {
++ addr = 0xA850 + i * 2;
++ val = illu_new[i].exposure;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (illu_cur[i].framerate != illu_new[i].framerate) {
++ addr = 0xA851 + i * 2;
++ val = illu_new[i].framerate;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ }
++ break;
++ }
++ case IRS1125_CID_MOD_PLL:
++ mod_new = (struct irs1125_mod_pll *)ctrl->p_new.p;
++ mod_cur = (struct irs1125_mod_pll *)ctrl->p_cur.p;
++ for (i = 0; i < IRS1125_NUM_MOD_PLLS; i++) {
++ if (mod_cur[i].pllcfg1 != mod_new[i].pllcfg1) {
++ addr = 0xC3A0 + i * 3;
++ val = mod_new[i].pllcfg1;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg2 != mod_new[i].pllcfg2) {
++ addr = 0xC3A1 + i * 3;
++ val = mod_new[i].pllcfg2;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg3 != mod_new[i].pllcfg3) {
++ addr = 0xC3A2 + i * 3;
++ val = mod_new[i].pllcfg3;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg4 != mod_new[i].pllcfg4) {
++ addr = 0xC24C + i * 5;
++ val = mod_new[i].pllcfg4;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg5 != mod_new[i].pllcfg5) {
++ addr = 0xC24D + i * 5;
++ val = mod_new[i].pllcfg5;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg6 != mod_new[i].pllcfg6) {
++ addr = 0xC24E + i * 5;
++ val = mod_new[i].pllcfg6;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg7 != mod_new[i].pllcfg7) {
++ addr = 0xC24F + i * 5;
++ val = mod_new[i].pllcfg7;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg8 != mod_new[i].pllcfg8) {
++ addr = 0xC250 + i * 5;
++ val = mod_new[i].pllcfg8;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ }
++ break;
++ case IRS1125_CID_SEQ_CONFIG:
++ cfg_new = (struct irs1125_seq_cfg *)ctrl->p_new.p;
++ cfg_cur = (struct irs1125_seq_cfg *)ctrl->p_cur.p;
++ for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
++ if (cfg_cur[i].exposure != cfg_new[i].exposure) {
++ addr = IRS1125_REG_DMEM_SHADOW + i * 4;
++ val = cfg_new[i].exposure;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (cfg_cur[i].framerate != cfg_new[i].framerate) {
++ addr = IRS1125_REG_DMEM_SHADOW + 1 + i * 4;
++ val = cfg_new[i].framerate;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (cfg_cur[i].ps != cfg_new[i].ps) {
++ addr = IRS1125_REG_DMEM_SHADOW + 2 + i * 4;
++ val = cfg_new[i].ps;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (cfg_cur[i].pll != cfg_new[i].pll) {
++ addr = IRS1125_REG_DMEM_SHADOW + 3 + i * 4;
++ val = cfg_new[i].pll;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ }
++ break;
++ case IRS1125_CID_NUM_SEQS:
++ err = irs1125_write(&dev->sd, 0xA88D, ctrl->val - 1);
++ if (err >= 0)
++ dev->num_seq = ctrl->val;
++ break;
++ case IRS1125_CID_CONTINUOUS_TRIG:
++ if (ctrl->val == 0)
++ err = irs1125_write(&dev->sd, 0xA87C, 0);
++ else
++ err = irs1125_write(&dev->sd, 0xA87C, 1);
++ break;
++ case IRS1125_CID_TRIGGER:
++ if (ctrl->val != 0) {
++ err = irs1125_write(&dev->sd, 0xA87C, 1);
++ if (err >= 0)
++ err = irs1125_write(&dev->sd, 0xA87C, 0);
++ }
++ break;
++ case IRS1125_CID_RECONFIG:
++ if (ctrl->val != 0)
++ err = irs1125_write(&dev->sd, 0xA87A, 1);
++ break;
++ case IRS1125_CID_ILLU_ON:
++ if (ctrl->val == 0)
++ err = irs1125_write(&dev->sd, 0xA892, 0x377);
++ else
++ err = irs1125_write(&dev->sd, 0xA892, 0x355);
++ break;
++ default:
++ break;
++ }
++
++ if (err < 0)
++ dev_err(&client->dev, "Error executing control ID: %d, val %d, err %d",
++ ctrl->id, ctrl->val, err);
++ else
++ err = 0;
++
++ return err;
++}
++
++static const struct v4l2_ctrl_ops irs1125_ctrl_ops = {
++ .s_ctrl = irs1125_s_ctrl,
++};
++
++static const struct v4l2_ctrl_config irs1125_custom_ctrls[] = {
++ {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_NUM_SEQS,
++ .name = "Change number of sequences",
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT,
++ .min = 1,
++ .max = 20,
++ .step = 1,
++ .def = 5,
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_MOD_PLL,
++ .name = "Reconfigure modulation PLLs",
++ .type = V4L2_CTRL_TYPE_U16,
++ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
++ .min = 0,
++ .max = U16_MAX,
++ .step = 1,
++ .def = 0,
++ .elem_size = sizeof(u16),
++ .dims = {sizeof(struct irs1125_mod_pll) / sizeof(u16),
++ IRS1125_NUM_MOD_PLLS}
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_SAFE_RECONFIG,
++ .name = "Change exposure and pause of single seq",
++ .type = V4L2_CTRL_TYPE_U16,
++ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
++ .min = 0,
++ .max = U16_MAX,
++ .step = 1,
++ .def = 0,
++ .elem_size = sizeof(u16),
++ .dims = {sizeof(struct irs1125_illu) / sizeof(u16),
++ IRS1125_NUM_SEQ_ENTRIES}
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_SEQ_CONFIG,
++ .name = "Change sequence settings",
++ .type = V4L2_CTRL_TYPE_U16,
++ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
++ .min = 0,
++ .max = U16_MAX,
++ .step = 1,
++ .def = 0,
++ .elem_size = sizeof(u16),
++ .dims = {sizeof(struct irs1125_seq_cfg) / sizeof(u16),
++ IRS1125_NUM_SEQ_ENTRIES}
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_CONTINUOUS_TRIG,
++ .name = "Enable/disable continuous trigger",
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
++ .min = 0,
++ .max = 1,
++ .step = 1,
++ .def = 0
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_TRIGGER,
++ .name = "Capture a single sequence",
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
++ .min = 0,
++ .max = 1,
++ .step = 1,
++ .def = 0
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_RECONFIG,
++ .name = "Trigger imager reconfiguration",
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
++ .min = 0,
++ .max = 1,
++ .step = 1,
++ .def = 0
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_ILLU_ON,
++ .name = "Turn illu on or off",
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
++ .min = 0,
++ .max = 1,
++ .step = 1,
++ .def = 1
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_IDENT0,
++ .name = "Get ident 0 information",
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .flags = V4L2_CTRL_FLAG_READ_ONLY,
++ .min = S32_MIN,
++ .max = S32_MAX,
++ .step = 1,
++ .def = 0
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_IDENT1,
++ .name = "Get ident 1 information",
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .flags = V4L2_CTRL_FLAG_READ_ONLY,
++ .min = S32_MIN,
++ .max = S32_MAX,
++ .step = 1,
++ .def = 0
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_IDENT2,
++ .name = "Get ident 2 information",
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .flags = V4L2_CTRL_FLAG_READ_ONLY,
++ .min = S32_MIN,
++ .max = S32_MAX,
++ .step = 1,
++ .def = 0
++ }
++};
++
++static int irs1125_detect(struct v4l2_subdev *sd)
++{
++ u16 read;
++ int ret;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ ret = irs1125_read(sd, IRS1125_REG_DESIGN_STEP, &read);
++ if (ret < 0) {
++ dev_err(&client->dev, "error reading from i2c\n");
++ return ret;
++ }
++
++ if (read != IRS1125_DESIGN_STEP_EXPECTED) {
++ dev_err(&client->dev, "Design step expected 0x%x got 0x%x",
++ IRS1125_DESIGN_STEP_EXPECTED, read);
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static int irs1125_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
++{
++ struct v4l2_mbus_framefmt *format =
++ v4l2_subdev_get_try_format(sd, fh->pad, 0);
++
++ format->code = MEDIA_BUS_FMT_Y12_1X12;
++ format->width = IRS1125_WINDOW_WIDTH_DEF;
++ format->height = IRS1125_WINDOW_HEIGHT_DEF;
++ format->field = V4L2_FIELD_NONE;
++ format->colorspace = V4L2_COLORSPACE_RAW;
++
++ return 0;
++}
++
++static const struct v4l2_subdev_internal_ops irs1125_subdev_internal_ops = {
++ .open = irs1125_open,
++};
++
++static int irs1125_ctrls_init(struct irs1125 *sensor, struct device *dev)
++{
++ struct v4l2_ctrl *ctrl;
++ int err, i;
++ struct v4l2_ctrl_handler *hdl;
++
++ hdl = &sensor->ctrl_handler;
++ v4l2_ctrl_handler_init(hdl, ARRAY_SIZE(irs1125_custom_ctrls));
++
++ for (i = 0; i < ARRAY_SIZE(irs1125_custom_ctrls); i++) {
++ ctrl = v4l2_ctrl_new_custom(hdl, &irs1125_custom_ctrls[i],
++ NULL);
++ if (!ctrl)
++ dev_err(dev, "Failed to init custom control %s\n",
++ irs1125_custom_ctrls[i].name);
++ else if (irs1125_custom_ctrls[i].id == IRS1125_CID_NUM_SEQS)
++ sensor->ctrl_numseq = ctrl;
++ else if (irs1125_custom_ctrls[i].id == IRS1125_CID_MOD_PLL)
++ sensor->ctrl_modplls = ctrl;
++ }
++
++ if (hdl->error) {
++ dev_err(dev, "Error %d adding controls\n", hdl->error);
++ err = hdl->error;
++ goto error_ctrls;
++ }
++
++ sensor->sd.ctrl_handler = hdl;
++ return 0;
++
++error_ctrls:
++ v4l2_ctrl_handler_free(&sensor->ctrl_handler);
++ return -err;
++}
++
++static int irs1125_ident_setup(struct irs1125 *sensor, struct device *dev)
++{
++ int ret;
++ struct v4l2_ctrl *ctrl;
++ struct v4l2_subdev *sd;
++ u16 read;
++
++ sd = &sensor->sd;
++
++ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT0);
++ if (!ctrl) {
++ dev_err(dev, "could not find device ctrl.\n");
++ return -EINVAL;
++ }
++
++ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL2, &read);
++ if (ret < 0) {
++ dev_err(dev, "error reading from i2c\n");
++ return -EIO;
++ }
++
++ v4l2_ctrl_s_ctrl(ctrl, read);
++
++ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT1);
++ if (!ctrl) {
++ dev_err(dev, "could not find device ctrl.\n");
++ return -EINVAL;
++ }
++
++ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL3, &read);
++ if (ret < 0) {
++ dev_err(dev, "error reading from i2c\n");
++ return -EIO;
++ }
++
++ v4l2_ctrl_s_ctrl(ctrl, read);
++
++ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT2);
++ if (!ctrl) {
++ dev_err(dev, "could not find device ctrl.\n");
++ return -EINVAL;
++ }
++
++ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL4, &read);
++ if (ret < 0) {
++ dev_err(dev, "error reading from i2c\n");
++ return -EIO;
++ }
++ v4l2_ctrl_s_ctrl(ctrl, read & 0xFFFC);
++
++ return 0;
++}
++
++static int irs1125_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct device *dev = &client->dev;
++ struct irs1125 *sensor;
++ int ret;
++ struct fwnode_handle *endpoint;
++ u32 xclk_freq;
++ int gpio_num;
++
++ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
++ if (!sensor)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&sensor->sd, client, &irs1125_subdev_ops);
++
++ /* Get CSI2 bus config */
++ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev),
++ NULL);
++ if (!endpoint) {
++ dev_err(dev, "endpoint node not found\n");
++ return -EINVAL;
++ }
++
++ ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
++ fwnode_handle_put(endpoint);
++ if (ret) {
++ dev_err(dev, "Could not parse endpoint\n");
++ return ret;
++ }
++
++ /* get system clock (xclk) */
++ sensor->xclk = devm_clk_get(dev, NULL);
++ if (IS_ERR(sensor->xclk)) {
++ dev_err(dev, "could not get xclk");
++ return PTR_ERR(sensor->xclk);
++ }
++
++ xclk_freq = clk_get_rate(sensor->xclk);
++ if (xclk_freq != 26000000) {
++ dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq);
++ return -EINVAL;
++ }
++
++ sensor->num_seq = 5;
++
++ /* Request the power down GPIO */
++ sensor->reset = devm_gpiod_get(&client->dev, "pwdn",
++ GPIOD_OUT_LOW);
++
++ if (IS_ERR(sensor->reset)) {
++ dev_err(dev, "could not get reset");
++ return PTR_ERR(sensor->reset);
++ }
++
++ gpio_num = desc_to_gpio(sensor->reset);
++
++ mutex_init(&sensor->lock);
++
++ ret = irs1125_ctrls_init(sensor, dev);
++ if (ret < 0)
++ goto mutex_remove;
++
++ sensor->sd.internal_ops = &irs1125_subdev_internal_ops;
++ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
++ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
++ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
++ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
++ if (ret < 0)
++ goto mutex_remove;
++
++ gpiod_set_value_cansleep(sensor->reset, 1);
++ msleep(RESET_ACTIVE_DELAY_MS);
++
++ ret = irs1125_detect(&sensor->sd);
++ if (ret < 0)
++ goto error;
++
++ ret = irs1125_ident_setup(sensor, dev);
++ if (ret < 0)
++ goto error;
++
++ gpiod_set_value_cansleep(sensor->reset, 0);
++
++ ret = v4l2_async_register_subdev(&sensor->sd);
++ if (ret < 0)
++ goto error;
++
++ dev_dbg(dev, "Infineon IRS1125 camera driver probed\n");
++
++ return 0;
++
++error:
++ media_entity_cleanup(&sensor->sd.entity);
++mutex_remove:
++ mutex_destroy(&sensor->lock);
++ return ret;
++}
++
++static int irs1125_remove(struct i2c_client *client)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct irs1125 *irs1125 = to_state(sd);
++
++ v4l2_async_unregister_subdev(&irs1125->sd);
++ media_entity_cleanup(&irs1125->sd.entity);
++ v4l2_device_unregister_subdev(sd);
++ mutex_destroy(&irs1125->lock);
++ v4l2_ctrl_handler_free(&irs1125->ctrl_handler);
++
++ return 0;
++}
++
++#if IS_ENABLED(CONFIG_OF)
++static const struct of_device_id irs1125_of_match[] = {
++ { .compatible = "infineon,irs1125" },
++ { /* sentinel */ },
++};
++MODULE_DEVICE_TABLE(of, irs1125_of_match);
++#endif
++
++static struct i2c_driver irs1125_driver = {
++ .driver = {
++ .of_match_table = of_match_ptr(irs1125_of_match),
++ .name = SENSOR_NAME,
++ },
++ .probe = irs1125_probe,
++ .remove = irs1125_remove,
++};
++
++module_i2c_driver(irs1125_driver);
++
++MODULE_DESCRIPTION("Infineon irs1125 sensor driver");
++MODULE_LICENSE("GPL v2");
++
+--- /dev/null
++++ b/drivers/media/i2c/irs1125.h
+@@ -0,0 +1,61 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * A V4L2 driver for Infineon IRS1125 TOF cameras.
++ * Copyright (C) 2018, pieye GmbH
++ *
++ * Based on V4L2 OmniVision OV5647 Image Sensor driver
++ *
++ * DT / fwnode changes, and GPIO control taken from ov5640.c
++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright (C) 2014-2017 Mentor Graphics Inc.
++ *
++ */
++
++#ifndef IRS1125_H
++#define IRS1125_H
++
++#include <linux/v4l2-controls.h>
++#include <linux/types.h>
++
++#define IRS1125_NUM_SEQ_ENTRIES 20
++#define IRS1125_NUM_MOD_PLLS 4
++
++#define IRS1125_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
++#define IRS1125_CID_SAFE_RECONFIG (IRS1125_CID_CUSTOM_BASE + 0)
++#define IRS1125_CID_CONTINUOUS_TRIG (IRS1125_CID_CUSTOM_BASE + 1)
++#define IRS1125_CID_TRIGGER (IRS1125_CID_CUSTOM_BASE + 2)
++#define IRS1125_CID_RECONFIG (IRS1125_CID_CUSTOM_BASE + 3)
++#define IRS1125_CID_ILLU_ON (IRS1125_CID_CUSTOM_BASE + 4)
++#define IRS1125_CID_NUM_SEQS (IRS1125_CID_CUSTOM_BASE + 5)
++#define IRS1125_CID_MOD_PLL (IRS1125_CID_CUSTOM_BASE + 6)
++#define IRS1125_CID_SEQ_CONFIG (IRS1125_CID_CUSTOM_BASE + 7)
++#define IRS1125_CID_IDENT0 (IRS1125_CID_CUSTOM_BASE + 8)
++#define IRS1125_CID_IDENT1 (IRS1125_CID_CUSTOM_BASE + 9)
++#define IRS1125_CID_IDENT2 (IRS1125_CID_CUSTOM_BASE + 10)
++
++struct irs1125_seq_cfg {
++ __u16 exposure;
++ __u16 framerate;
++ __u16 ps;
++ __u16 pll;
++};
++
++struct irs1125_illu {
++ __u16 exposure;
++ __u16 framerate;
++};
++
++struct irs1125_mod_pll {
++ __u16 pllcfg1;
++ __u16 pllcfg2;
++ __u16 pllcfg3;
++ __u16 pllcfg4;
++ __u16 pllcfg5;
++ __u16 pllcfg6;
++ __u16 pllcfg7;
++ __u16 pllcfg8;
++};
++
++#endif /* IRS1125 */
++
+++ /dev/null
-From b4f8b92cdfd8ad2e04cdd3f0a73aa4e95d172fb1 Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2019 19:12:08 +0200
-Subject: [PATCH] dt-bindings: Add binding for the Infineon IRS1125
- sensor
-
-Adds a binding for the Infineon IRS1125 time-of-flight depth
-sensor.
-
----
- .../devicetree/bindings/media/i2c/irs1125.txt | 48 +++++++++++++++++++
- 1 file changed, 48 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/media/i2c/irs1125.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/media/i2c/irs1125.txt
-@@ -0,0 +1,48 @@
-+* Infineon irs1125 time of flight sensor
-+
-+The Infineon irs1125 is a time of flight digital image sensor with
-+an active array size of 352H x 286V. It is programmable through I2C
-+interface. The I2C address defaults to 0x3D, but can be reconfigured
-+to address 0x3C or 0x41 via I2C commands. Image data is sent through
-+MIPI CSI-2, which is configured as either 1 or 2 data lanes.
-+
-+Required Properties:
-+- compatible: value should be "infineon,irs1125" for irs1125 sensor
-+- reg: I2C bus address of the device
-+- clocks: reference to the xclk input clock.
-+- pwdn-gpios: reference to the GPIO connected to the reset pin.
-+ This is an active low signal to the iirs1125.
-+
-+The irs1125 device node should contain one 'port' child node with
-+an 'endpoint' subnode. For further reading on port node refer to
-+Documentation/devicetree/bindings/media/video-interfaces.txt.
-+
-+Endpoint node required properties for CSI-2 connection are:
-+- remote-endpoint: a phandle to the bus receiver's endpoint node.
-+- clock-lanes: should be set to <0> (clock lane on hardware lane 0)
-+- data-lanes: should be set to <1> or <1 2> (one or two lane CSI-2
-+ supported)
-+
-+Example:
-+ sensor@10 {
-+ compatible = "infineon,irs1125";
-+ reg = <0x3D>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ clocks = <&irs1125_clk>;
-+ pwdn-gpios = <&gpio 5 0>;
-+
-+ irs1125_clk: camera-clk {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <26000000>;
-+ };
-+
-+ port {
-+ sensor_out: endpoint {
-+ remote-endpoint = <&csiss_in>;
-+ clock-lanes = <0>;
-+ data-lanes = <1 2>;
-+ };
-+ };
-+ };
--- /dev/null
+From 89af5d7df7f548744bd675d96295c0f45e24b31f Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Oct 2019 19:13:02 +0200
+Subject: [PATCH] dtoverlays: Add an overlay for the Infineon IRS1125
+
+The Infineon IRS1125 is a CSI2 time of flight depth sensor
+which has a suitable V4L2 subdevice driver.
+
+Add an overlay for configuring it.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 12 +++
+ .../arm/boot/dts/overlays/irs1125-overlay.dts | 97 +++++++++++++++++++
+ 3 files changed, 110 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/irs1125-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -83,6 +83,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ iqaudio-dac.dtbo \
+ iqaudio-dacplus.dtbo \
+ iqaudio-digi-wm8804-audio.dtbo \
++ irs1125.dtbo \
+ jedec-spi-nor.dtbo \
+ justboom-dac.dtbo \
+ justboom-digi.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1347,6 +1347,18 @@ Params: card_name Override
+ dai stream name.
+
+
++Name: irs1125
++Info: Infineon irs1125 TOF camera module.
++ Uses Unicam 1, which is the standard camera connector on most Pi
++ variants.
++Load: dtoverlay=irs1125,<param>=<val>
++Params: i2c_pins_0_1 Use pins 0&1 for the I2C instead of 44&45.
++ Useful on Compute Modules.
++
++ i2c_pins_28_29 Use pins 28&29 for the I2C instead of 44&45.
++ This is required for Pi B+, 2, 0, and 0W.
++
++
+ Name: jedec-spi-nor
+ Info: Adds support for JEDEC-compliant SPI NOR flash devices. (Note: The
+ "jedec,spi-nor" kernel driver was formerly known as "m25p80".)
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/irs1125-overlay.dts
+@@ -0,0 +1,97 @@
++// SPDX-License-Identifier: GPL-2.0-only
++// Definitions for IRS1125 camera module on VC I2C bus
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&i2c_vc>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ irs1125: irs1125@3D {
++ compatible = "infineon,irs1125";
++ reg = <0x3D>;
++ status = "okay";
++
++ pwdn-gpios = <&gpio 5 0>;
++ clocks = <&irs1125_clk>;
++
++ irs1125_clk: camera-clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <26000000>;
++ };
++
++ port {
++ irs1125_0: endpoint {
++ remote-endpoint = <&csi1_ep>;
++ clock-lanes = <0>;
++ data-lanes = <1 2>;
++ clock-noncontinuous;
++ link-frequencies =
++ /bits/ 64 <297000000>;
++ };
++ };
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&csi1>;
++ __overlay__ {
++ status = "okay";
++
++ port {
++ csi1_ep: endpoint {
++ remote-endpoint = <&irs1125_0>;
++ };
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c0_pins>;
++ __dormant__ {
++ brcm,pins = <28 29>;
++ brcm,function = <4>; /* alt0 */
++ };
++ };
++ fragment@3 {
++ target = <&i2c0_pins>;
++ __overlay__ {
++ brcm,pins = <44 45>;
++ brcm,function = <5>; /* alt1 */
++ };
++ };
++ fragment@4 {
++ target = <&i2c0_pins>;
++ __dormant__ {
++ brcm,pins = <0 1>;
++ brcm,function = <4>; /* alt0 */
++ };
++ };
++ fragment@5 {
++ target = <&i2c_vc>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@6 {
++ target-path="/__overrides__";
++ __overlay__ {
++ cam0-pwdn-ctrl = <&irs1125>,"pwdn-gpios:0";
++ cam0-pwdn = <&irs1125>,"pwdn-gpios:4";
++ };
++ };
++
++ __overrides__ {
++ i2c_pins_0_1 = <0>,"-2-3+4";
++ i2c_pins_28_29 = <0>,"+2-3-4";
++ };
++};
+++ /dev/null
-From c09b42cb057ddf8bd20d57c6b0ffd94f3e15ea7c Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2019 19:12:36 +0200
-Subject: [PATCH] media: i2c: Add a driver for the Infineon IRS1125
- depth sensor
-
-The Infineon IRS1125 is a time of flight depth sensor that
-has a CSI-2 interface.
-
-Add a V4L2 subdevice driver for this device.
-
----
- drivers/media/i2c/Kconfig | 12 +
- drivers/media/i2c/Makefile | 1 +
- drivers/media/i2c/irs1125.c | 1112 +++++++++++++++++++++++++++++++++++
- drivers/media/i2c/irs1125.h | 61 ++
- 4 files changed, 1186 insertions(+)
- create mode 100644 drivers/media/i2c/irs1125.c
- create mode 100644 drivers/media/i2c/irs1125.h
-
---- a/drivers/media/i2c/Kconfig
-+++ b/drivers/media/i2c/Kconfig
-@@ -813,6 +813,18 @@ config VIDEO_OV13858
- This is a Video4Linux2 sensor driver for the OmniVision
- OV13858 camera.
-
-+config VIDEO_IRS1125
-+ tristate "Infineon IRS1125 sensor support"
-+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
-+ depends on MEDIA_CAMERA_SUPPORT
-+ select V4L2_FWNODE
-+ help
-+ This is a Video4Linux2 sensor-level driver for the Infineon
-+ IRS1125 camera.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called irs1125.
-+
- config VIDEO_VS6624
- tristate "ST VS6624 sensor support"
- depends on VIDEO_V4L2 && I2C
---- a/drivers/media/i2c/Makefile
-+++ b/drivers/media/i2c/Makefile
-@@ -80,6 +80,7 @@ obj-$(CONFIG_VIDEO_OV772X) += ov772x.o
- obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
- obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
- obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
-+obj-$(CONFIG_VIDEO_IRS1125) += irs1125.o
- obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
- obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o
- obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
---- /dev/null
-+++ b/drivers/media/i2c/irs1125.c
-@@ -0,0 +1,1112 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * A V4L2 driver for Infineon IRS1125 TOF cameras.
-+ * Copyright (C) 2018, pieye GmbH
-+ *
-+ * Based on V4L2 OmniVision OV5647 Image Sensor driver
-+ *
-+ * DT / fwnode changes, and GPIO control taken from ov5640.c
-+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
-+ * Copyright (C) 2014-2017 Mentor Graphics Inc.
-+ *
-+ */
-+
-+#include "irs1125.h"
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/of_graph.h>
-+#include <linux/slab.h>
-+#include <linux/videodev2.h>
-+#include <linux/firmware.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-image-sizes.h>
-+#include <media/v4l2-mediabus.h>
-+#include <media/v4l2-ctrls.h>
-+
-+#define CHECK_BIT(val, pos) ((val) & BIT(pos))
-+
-+#define SENSOR_NAME "irs1125"
-+
-+#define RESET_ACTIVE_DELAY_MS 20
-+
-+#define IRS1125_ALTERNATE_FW "irs1125_af.bin"
-+
-+#define IRS1125_REG_CSICFG 0xA882
-+#define IRS1125_REG_DESIGN_STEP 0xB0AD
-+#define IRS1125_REG_EFUSEVAL2 0xB09F
-+#define IRS1125_REG_EFUSEVAL3 0xB0A0
-+#define IRS1125_REG_EFUSEVAL4 0xB0A1
-+#define IRS1125_REG_DMEM_SHADOW 0xC320
-+
-+#define IRS1125_DESIGN_STEP_EXPECTED 0x0a12
-+
-+#define IRS1125_ROW_START_DEF 0
-+#define IRS1125_COLUMN_START_DEF 0
-+#define IRS1125_WINDOW_HEIGHT_DEF 288
-+#define IRS1125_WINDOW_WIDTH_DEF 352
-+
-+struct regval_list {
-+ u16 addr;
-+ u16 data;
-+};
-+
-+struct irs1125 {
-+ struct v4l2_subdev sd;
-+ struct media_pad pad;
-+ /* the parsed DT endpoint info */
-+ struct v4l2_fwnode_endpoint ep;
-+
-+ struct clk *xclk;
-+ struct v4l2_ctrl_handler ctrl_handler;
-+
-+ /* To serialize asynchronus callbacks */
-+ struct mutex lock;
-+
-+ /* image data layout */
-+ unsigned int num_seq;
-+
-+ /* reset pin */
-+ struct gpio_desc *reset;
-+
-+ /* V4l2 Controls to grab */
-+ struct v4l2_ctrl *ctrl_modplls;
-+ struct v4l2_ctrl *ctrl_numseq;
-+
-+ int power_count;
-+};
-+
-+static inline struct irs1125 *to_state(struct v4l2_subdev *sd)
-+{
-+ return container_of(sd, struct irs1125, sd);
-+}
-+
-+static struct regval_list irs1125_26MHz[] = {
-+ {0xB017, 0x0413},
-+ {0xB086, 0x3535},
-+ {0xB0AE, 0xEF02},
-+ {0xA000, 0x0004},
-+ {0xFFFF, 100},
-+
-+ {0xB062, 0x6383},
-+ {0xB063, 0x55A8},
-+ {0xB068, 0x7628},
-+ {0xB069, 0x03E2},
-+
-+ {0xFFFF, 100},
-+ {0xB05A, 0x01C5},
-+ {0xB05C, 0x0206},
-+ {0xB05D, 0x01C5},
-+ {0xB05F, 0x0206},
-+ {0xB016, 0x1335},
-+ {0xFFFF, 100},
-+ {0xA893, 0x8261},
-+ {0xA894, 0x89d8},
-+ {0xA895, 0x131d},
-+ {0xA896, 0x4251},
-+ {0xA897, 0x9D8A},
-+ {0xA898, 0x0BD8},
-+ {0xA899, 0x2245},
-+ {0xA89A, 0xAB9B},
-+ {0xA89B, 0x03B9},
-+ {0xA89C, 0x8041},
-+ {0xA89D, 0xE07E},
-+ {0xA89E, 0x0307},
-+ {0xFFFF, 100},
-+ {0xA88D, 0x0004},
-+ {0xA800, 0x0E68},
-+ {0xA801, 0x0000},
-+ {0xA802, 0x000C},
-+ {0xA803, 0x0000},
-+ {0xA804, 0x0E68},
-+ {0xA805, 0x0000},
-+ {0xA806, 0x0440},
-+ {0xA807, 0x0000},
-+ {0xA808, 0x0E68},
-+ {0xA809, 0x0000},
-+ {0xA80A, 0x0884},
-+ {0xA80B, 0x0000},
-+ {0xA80C, 0x0E68},
-+ {0xA80D, 0x0000},
-+ {0xA80E, 0x0CC8},
-+ {0xA80F, 0x0000},
-+ {0xA810, 0x0E68},
-+ {0xA811, 0x0000},
-+ {0xA812, 0x2000},
-+ {0xA813, 0x0000},
-+ {0xA882, 0x0081},
-+ {0xA88C, 0x403A},
-+ {0xA88F, 0x031E},
-+ {0xA892, 0x0351},
-+ {0x9813, 0x13FF},
-+ {0x981B, 0x7608},
-+
-+ {0xB008, 0x0000},
-+ {0xB015, 0x1513},
-+
-+ {0xFFFF, 100}
-+};
-+
-+static struct regval_list irs1125_seq_cfg[] = {
-+ {0xC3A0, 0x823D},
-+ {0xC3A1, 0xB13B},
-+ {0xC3A2, 0x0313},
-+ {0xC3A3, 0x4659},
-+ {0xC3A4, 0xC4EC},
-+ {0xC3A5, 0x03CE},
-+ {0xC3A6, 0x4259},
-+ {0xC3A7, 0xC4EC},
-+ {0xC3A8, 0x03CE},
-+ {0xC3A9, 0x8839},
-+ {0xC3AA, 0x89D8},
-+ {0xC3AB, 0x031D},
-+
-+ {0xC24C, 0x5529},
-+ {0xC24D, 0x0000},
-+ {0xC24E, 0x1200},
-+ {0xC24F, 0x6CB2},
-+ {0xC250, 0x0000},
-+ {0xC251, 0x5529},
-+ {0xC252, 0x42F4},
-+ {0xC253, 0xD1AF},
-+ {0xC254, 0x8A18},
-+ {0xC255, 0x0002},
-+ {0xC256, 0x5529},
-+ {0xC257, 0x6276},
-+ {0xC258, 0x11A7},
-+ {0xC259, 0xD907},
-+ {0xC25A, 0x0000},
-+ {0xC25B, 0x5529},
-+ {0xC25C, 0x07E0},
-+ {0xC25D, 0x7BFE},
-+ {0xC25E, 0x6402},
-+ {0xC25F, 0x0019},
-+
-+ {0xC3AC, 0x0007},
-+ {0xC3AD, 0xED88},
-+ {0xC320, 0x003E},
-+ {0xC321, 0x0000},
-+ {0xC322, 0x2000},
-+ {0xC323, 0x0000},
-+ {0xC324, 0x0271},
-+ {0xC325, 0x0000},
-+ {0xC326, 0x000C},
-+ {0xC327, 0x0000},
-+ {0xC328, 0x0271},
-+ {0xC329, 0x0000},
-+ {0xC32A, 0x0440},
-+ {0xC32B, 0x0000},
-+ {0xC32C, 0x0271},
-+ {0xC32D, 0x0000},
-+ {0xC32E, 0x0884},
-+ {0xC32F, 0x0000},
-+ {0xC330, 0x0271},
-+ {0xC331, 0x0000},
-+ {0xC332, 0x0CC8},
-+ {0xC333, 0x0000},
-+ {0xA88D, 0x0004},
-+
-+ {0xA890, 0x0000},
-+ {0xC219, 0x0002},
-+ {0xC21A, 0x0000},
-+ {0xC21B, 0x0000},
-+ {0xC21C, 0x00CD},
-+ {0xC21D, 0x0009},
-+ {0xC21E, 0x00CD},
-+ {0xC21F, 0x0009},
-+
-+ {0xA87C, 0x0000},
-+ {0xC032, 0x0001},
-+ {0xC034, 0x0000},
-+ {0xC035, 0x0001},
-+ {0xC039, 0x0000},
-+ {0xC401, 0x0002},
-+
-+ {0xFFFF, 1},
-+ {0xA87C, 0x0001}
-+};
-+
-+static int irs1125_write(struct v4l2_subdev *sd, u16 reg, u16 val)
-+{
-+ int ret;
-+ unsigned char data[4] = { reg >> 8, reg & 0xff, val >> 8, val & 0xff};
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+ ret = i2c_master_send(client, data, 4);
-+ if (ret < 0)
-+ dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
-+ __func__, reg);
-+
-+ return ret;
-+}
-+
-+static int irs1125_read(struct v4l2_subdev *sd, u16 reg, u16 *val)
-+{
-+ int ret;
-+ unsigned char data_w[2] = { reg >> 8, reg & 0xff };
-+ char rdval[2];
-+
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+ ret = i2c_master_send(client, data_w, 2);
-+ if (ret < 0) {
-+ dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
-+ __func__, reg);
-+ return ret;
-+ }
-+
-+ ret = i2c_master_recv(client, rdval, 2);
-+ if (ret < 0)
-+ dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
-+ __func__, reg);
-+
-+ *val = rdval[1] | (rdval[0] << 8);
-+
-+ return ret;
-+}
-+
-+static int irs1125_write_array(struct v4l2_subdev *sd,
-+ struct regval_list *regs, int array_size)
-+{
-+ int i, ret;
-+
-+ for (i = 0; i < array_size; i++) {
-+ if (regs[i].addr == 0xFFFF) {
-+ msleep(regs[i].data);
-+ } else {
-+ ret = irs1125_write(sd, regs[i].addr, regs[i].data);
-+ if (ret < 0)
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int irs1125_stream_on(struct v4l2_subdev *sd)
-+{
-+ int ret;
-+ struct irs1125 *irs1125 = to_state(sd);
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+ v4l2_ctrl_grab(irs1125->ctrl_numseq, 1);
-+ v4l2_ctrl_grab(irs1125->ctrl_modplls, 1);
-+
-+ ret = irs1125_write(sd, 0xC400, 0x0001);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "error enabling firmware: %d", ret);
-+ return ret;
-+ }
-+
-+ msleep(100);
-+
-+ return irs1125_write(sd, 0xA87C, 0x0001);
-+}
-+
-+static int irs1125_stream_off(struct v4l2_subdev *sd)
-+{
-+ int ret;
-+ struct irs1125 *irs1125 = to_state(sd);
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+ v4l2_ctrl_grab(irs1125->ctrl_numseq, 0);
-+ v4l2_ctrl_grab(irs1125->ctrl_modplls, 0);
-+
-+ ret = irs1125_write(sd, 0xA87C, 0x0000);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "error disabling trigger: %d", ret);
-+ return ret;
-+ }
-+
-+ msleep(100);
-+
-+ return irs1125_write(sd, 0xC400, 0x0002);
-+}
-+
-+static int __sensor_init(struct v4l2_subdev *sd)
-+{
-+ unsigned int cnt, idx;
-+ int ret;
-+ u16 val;
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+ struct irs1125 *irs1125 = to_state(sd);
-+ const struct firmware *fw;
-+ struct regval_list *reg_data;
-+
-+ cnt = 0;
-+ while (1) {
-+ ret = irs1125_read(sd, 0xC40F, &val);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "read register 0xC40F failed\n");
-+ return ret;
-+ }
-+ if (CHECK_BIT(val, 14) == 0)
-+ break;
-+
-+ if (cnt >= 5) {
-+ dev_err(&client->dev, "timeout waiting for 0xC40F\n");
-+ return -EAGAIN;
-+ }
-+
-+ cnt++;
-+ }
-+
-+ ret = irs1125_write_array(sd, irs1125_26MHz,
-+ ARRAY_SIZE(irs1125_26MHz));
-+ if (ret < 0) {
-+ dev_err(&client->dev, "write sensor default regs error\n");
-+ return ret;
-+ }
-+
-+ /* set CSI-2 number of data lanes */
-+ if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 1) {
-+ val = 0x0001;
-+ } else if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 2) {
-+ val = 0x0081;
-+ } else {
-+ dev_err(&client->dev, "invalid number of data lanes %d\n",
-+ irs1125->ep.bus.mipi_csi2.num_data_lanes);
-+ return -EINVAL;
-+ }
-+
-+ ret = irs1125_write(sd, IRS1125_REG_CSICFG, val);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "write sensor csi2 config error\n");
-+ return ret;
-+ }
-+
-+ /* request the firmware, this will block and timeout */
-+ ret = request_firmware(&fw, IRS1125_ALTERNATE_FW, &client->dev);
-+ if (ret) {
-+ dev_err(&client->dev,
-+ "did not find the firmware file '%s' (status %d)\n",
-+ IRS1125_ALTERNATE_FW, ret);
-+ return ret;
-+ }
-+
-+ if (fw->size % 4) {
-+ dev_err(&client->dev, "firmware file '%s' invalid\n",
-+ IRS1125_ALTERNATE_FW);
-+ release_firmware(fw);
-+ return -EINVAL;
-+ }
-+
-+ for (idx = 0; idx < fw->size; idx += 4) {
-+ reg_data = (struct regval_list *)&fw->data[idx];
-+ ret = irs1125_write(sd, reg_data->addr, reg_data->data);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "firmware write error\n");
-+ release_firmware(fw);
-+ return ret;
-+ }
-+ }
-+ release_firmware(fw);
-+
-+ ret = irs1125_write_array(sd, irs1125_seq_cfg,
-+ ARRAY_SIZE(irs1125_seq_cfg));
-+ if (ret < 0) {
-+ dev_err(&client->dev, "write default sequence failed\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int irs1125_sensor_power(struct v4l2_subdev *sd, int on)
-+{
-+ int ret = 0;
-+ struct irs1125 *irs1125 = to_state(sd);
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+ mutex_lock(&irs1125->lock);
-+
-+ if (on && !irs1125->power_count) {
-+ gpiod_set_value_cansleep(irs1125->reset, 1);
-+ msleep(RESET_ACTIVE_DELAY_MS);
-+
-+ ret = clk_prepare_enable(irs1125->xclk);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "clk prepare enable failed\n");
-+ goto out;
-+ }
-+
-+ ret = __sensor_init(sd);
-+ if (ret < 0) {
-+ clk_disable_unprepare(irs1125->xclk);
-+ dev_err(&client->dev,
-+ "Camera not available, check Power\n");
-+ goto out;
-+ }
-+ } else if (!on && irs1125->power_count == 1) {
-+ gpiod_set_value_cansleep(irs1125->reset, 0);
-+ }
-+
-+ /* Update the power count. */
-+ irs1125->power_count += on ? 1 : -1;
-+ WARN_ON(irs1125->power_count < 0);
-+
-+out:
-+ mutex_unlock(&irs1125->lock);
-+
-+ return ret;
-+}
-+
-+#ifdef CONFIG_VIDEO_ADV_DEBUG
-+static int irs1125_sensor_get_register(struct v4l2_subdev *sd,
-+ struct v4l2_dbg_register *reg)
-+{
-+ u16 val;
-+ int ret;
-+
-+ ret = irs1125_read(sd, reg->reg & 0xffff, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ reg->val = val;
-+ reg->size = 1;
-+
-+ return 0;
-+}
-+
-+static int irs1125_sensor_set_register(struct v4l2_subdev *sd,
-+ const struct v4l2_dbg_register *reg)
-+{
-+ return irs1125_write(sd, reg->reg & 0xffff, reg->val & 0xffff);
-+}
-+#endif
-+
-+static const struct v4l2_subdev_core_ops irs1125_subdev_core_ops = {
-+ .s_power = irs1125_sensor_power,
-+#ifdef CONFIG_VIDEO_ADV_DEBUG
-+ .g_register = irs1125_sensor_get_register,
-+ .s_register = irs1125_sensor_set_register,
-+#endif
-+};
-+
-+static int irs1125_s_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ if (enable)
-+ return irs1125_stream_on(sd);
-+ else
-+ return irs1125_stream_off(sd);
-+}
-+
-+static const struct v4l2_subdev_video_ops irs1125_subdev_video_ops = {
-+ .s_stream = irs1125_s_stream,
-+};
-+
-+static int irs1125_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ if (code->index > 0)
-+ return -EINVAL;
-+
-+ code->code = MEDIA_BUS_FMT_Y12_1X12;
-+
-+ return 0;
-+}
-+
-+static int irs1125_set_get_fmt(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_format *format)
-+{
-+ struct v4l2_mbus_framefmt *fmt = &format->format;
-+ struct irs1125 *irs1125 = to_state(sd);
-+
-+ if (format->pad != 0)
-+ return -EINVAL;
-+
-+ /* Only one format is supported, so return that */
-+ memset(fmt, 0, sizeof(*fmt));
-+ fmt->code = MEDIA_BUS_FMT_Y12_1X12;
-+ fmt->colorspace = V4L2_COLORSPACE_RAW;
-+ fmt->field = V4L2_FIELD_NONE;
-+ fmt->width = IRS1125_WINDOW_WIDTH_DEF;
-+ fmt->height = IRS1125_WINDOW_HEIGHT_DEF * irs1125->num_seq;
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_subdev_pad_ops irs1125_subdev_pad_ops = {
-+ .enum_mbus_code = irs1125_enum_mbus_code,
-+ .set_fmt = irs1125_set_get_fmt,
-+ .get_fmt = irs1125_set_get_fmt,
-+};
-+
-+static const struct v4l2_subdev_ops irs1125_subdev_ops = {
-+ .core = &irs1125_subdev_core_ops,
-+ .video = &irs1125_subdev_video_ops,
-+ .pad = &irs1125_subdev_pad_ops,
-+};
-+
-+static int irs1125_s_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct irs1125 *dev = container_of(ctrl->handler,
-+ struct irs1125, ctrl_handler);
-+ struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
-+ int err, i;
-+ struct irs1125_mod_pll *mod_cur, *mod_new;
-+ struct irs1125_seq_cfg *cfg_cur, *cfg_new;
-+ u16 addr, val;
-+
-+ err = 0;
-+
-+ switch (ctrl->id) {
-+ case IRS1125_CID_SAFE_RECONFIG:
-+ {
-+ struct irs1125_illu *illu_cur, *illu_new;
-+
-+ illu_new = (struct irs1125_illu *)ctrl->p_new.p;
-+ illu_cur = (struct irs1125_illu *)ctrl->p_cur.p;
-+ for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
-+ if (illu_cur[i].exposure != illu_new[i].exposure) {
-+ addr = 0xA850 + i * 2;
-+ val = illu_new[i].exposure;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (illu_cur[i].framerate != illu_new[i].framerate) {
-+ addr = 0xA851 + i * 2;
-+ val = illu_new[i].framerate;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ }
-+ break;
-+ }
-+ case IRS1125_CID_MOD_PLL:
-+ mod_new = (struct irs1125_mod_pll *)ctrl->p_new.p;
-+ mod_cur = (struct irs1125_mod_pll *)ctrl->p_cur.p;
-+ for (i = 0; i < IRS1125_NUM_MOD_PLLS; i++) {
-+ if (mod_cur[i].pllcfg1 != mod_new[i].pllcfg1) {
-+ addr = 0xC3A0 + i * 3;
-+ val = mod_new[i].pllcfg1;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg2 != mod_new[i].pllcfg2) {
-+ addr = 0xC3A1 + i * 3;
-+ val = mod_new[i].pllcfg2;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg3 != mod_new[i].pllcfg3) {
-+ addr = 0xC3A2 + i * 3;
-+ val = mod_new[i].pllcfg3;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg4 != mod_new[i].pllcfg4) {
-+ addr = 0xC24C + i * 5;
-+ val = mod_new[i].pllcfg4;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg5 != mod_new[i].pllcfg5) {
-+ addr = 0xC24D + i * 5;
-+ val = mod_new[i].pllcfg5;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg6 != mod_new[i].pllcfg6) {
-+ addr = 0xC24E + i * 5;
-+ val = mod_new[i].pllcfg6;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg7 != mod_new[i].pllcfg7) {
-+ addr = 0xC24F + i * 5;
-+ val = mod_new[i].pllcfg7;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg8 != mod_new[i].pllcfg8) {
-+ addr = 0xC250 + i * 5;
-+ val = mod_new[i].pllcfg8;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ }
-+ break;
-+ case IRS1125_CID_SEQ_CONFIG:
-+ cfg_new = (struct irs1125_seq_cfg *)ctrl->p_new.p;
-+ cfg_cur = (struct irs1125_seq_cfg *)ctrl->p_cur.p;
-+ for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
-+ if (cfg_cur[i].exposure != cfg_new[i].exposure) {
-+ addr = IRS1125_REG_DMEM_SHADOW + i * 4;
-+ val = cfg_new[i].exposure;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (cfg_cur[i].framerate != cfg_new[i].framerate) {
-+ addr = IRS1125_REG_DMEM_SHADOW + 1 + i * 4;
-+ val = cfg_new[i].framerate;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (cfg_cur[i].ps != cfg_new[i].ps) {
-+ addr = IRS1125_REG_DMEM_SHADOW + 2 + i * 4;
-+ val = cfg_new[i].ps;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (cfg_cur[i].pll != cfg_new[i].pll) {
-+ addr = IRS1125_REG_DMEM_SHADOW + 3 + i * 4;
-+ val = cfg_new[i].pll;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ }
-+ break;
-+ case IRS1125_CID_NUM_SEQS:
-+ err = irs1125_write(&dev->sd, 0xA88D, ctrl->val - 1);
-+ if (err >= 0)
-+ dev->num_seq = ctrl->val;
-+ break;
-+ case IRS1125_CID_CONTINUOUS_TRIG:
-+ if (ctrl->val == 0)
-+ err = irs1125_write(&dev->sd, 0xA87C, 0);
-+ else
-+ err = irs1125_write(&dev->sd, 0xA87C, 1);
-+ break;
-+ case IRS1125_CID_TRIGGER:
-+ if (ctrl->val != 0) {
-+ err = irs1125_write(&dev->sd, 0xA87C, 1);
-+ if (err >= 0)
-+ err = irs1125_write(&dev->sd, 0xA87C, 0);
-+ }
-+ break;
-+ case IRS1125_CID_RECONFIG:
-+ if (ctrl->val != 0)
-+ err = irs1125_write(&dev->sd, 0xA87A, 1);
-+ break;
-+ case IRS1125_CID_ILLU_ON:
-+ if (ctrl->val == 0)
-+ err = irs1125_write(&dev->sd, 0xA892, 0x377);
-+ else
-+ err = irs1125_write(&dev->sd, 0xA892, 0x355);
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ if (err < 0)
-+ dev_err(&client->dev, "Error executing control ID: %d, val %d, err %d",
-+ ctrl->id, ctrl->val, err);
-+ else
-+ err = 0;
-+
-+ return err;
-+}
-+
-+static const struct v4l2_ctrl_ops irs1125_ctrl_ops = {
-+ .s_ctrl = irs1125_s_ctrl,
-+};
-+
-+static const struct v4l2_ctrl_config irs1125_custom_ctrls[] = {
-+ {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_NUM_SEQS,
-+ .name = "Change number of sequences",
-+ .type = V4L2_CTRL_TYPE_INTEGER,
-+ .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT,
-+ .min = 1,
-+ .max = 20,
-+ .step = 1,
-+ .def = 5,
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_MOD_PLL,
-+ .name = "Reconfigure modulation PLLs",
-+ .type = V4L2_CTRL_TYPE_U16,
-+ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
-+ .min = 0,
-+ .max = U16_MAX,
-+ .step = 1,
-+ .def = 0,
-+ .elem_size = sizeof(u16),
-+ .dims = {sizeof(struct irs1125_mod_pll) / sizeof(u16),
-+ IRS1125_NUM_MOD_PLLS}
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_SAFE_RECONFIG,
-+ .name = "Change exposure and pause of single seq",
-+ .type = V4L2_CTRL_TYPE_U16,
-+ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
-+ .min = 0,
-+ .max = U16_MAX,
-+ .step = 1,
-+ .def = 0,
-+ .elem_size = sizeof(u16),
-+ .dims = {sizeof(struct irs1125_illu) / sizeof(u16),
-+ IRS1125_NUM_SEQ_ENTRIES}
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_SEQ_CONFIG,
-+ .name = "Change sequence settings",
-+ .type = V4L2_CTRL_TYPE_U16,
-+ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
-+ .min = 0,
-+ .max = U16_MAX,
-+ .step = 1,
-+ .def = 0,
-+ .elem_size = sizeof(u16),
-+ .dims = {sizeof(struct irs1125_seq_cfg) / sizeof(u16),
-+ IRS1125_NUM_SEQ_ENTRIES}
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_CONTINUOUS_TRIG,
-+ .name = "Enable/disable continuous trigger",
-+ .type = V4L2_CTRL_TYPE_BOOLEAN,
-+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
-+ .min = 0,
-+ .max = 1,
-+ .step = 1,
-+ .def = 0
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_TRIGGER,
-+ .name = "Capture a single sequence",
-+ .type = V4L2_CTRL_TYPE_BOOLEAN,
-+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
-+ .min = 0,
-+ .max = 1,
-+ .step = 1,
-+ .def = 0
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_RECONFIG,
-+ .name = "Trigger imager reconfiguration",
-+ .type = V4L2_CTRL_TYPE_BOOLEAN,
-+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
-+ .min = 0,
-+ .max = 1,
-+ .step = 1,
-+ .def = 0
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_ILLU_ON,
-+ .name = "Turn illu on or off",
-+ .type = V4L2_CTRL_TYPE_BOOLEAN,
-+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
-+ .min = 0,
-+ .max = 1,
-+ .step = 1,
-+ .def = 1
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_IDENT0,
-+ .name = "Get ident 0 information",
-+ .type = V4L2_CTRL_TYPE_INTEGER,
-+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
-+ .min = S32_MIN,
-+ .max = S32_MAX,
-+ .step = 1,
-+ .def = 0
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_IDENT1,
-+ .name = "Get ident 1 information",
-+ .type = V4L2_CTRL_TYPE_INTEGER,
-+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
-+ .min = S32_MIN,
-+ .max = S32_MAX,
-+ .step = 1,
-+ .def = 0
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_IDENT2,
-+ .name = "Get ident 2 information",
-+ .type = V4L2_CTRL_TYPE_INTEGER,
-+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
-+ .min = S32_MIN,
-+ .max = S32_MAX,
-+ .step = 1,
-+ .def = 0
-+ }
-+};
-+
-+static int irs1125_detect(struct v4l2_subdev *sd)
-+{
-+ u16 read;
-+ int ret;
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+ ret = irs1125_read(sd, IRS1125_REG_DESIGN_STEP, &read);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "error reading from i2c\n");
-+ return ret;
-+ }
-+
-+ if (read != IRS1125_DESIGN_STEP_EXPECTED) {
-+ dev_err(&client->dev, "Design step expected 0x%x got 0x%x",
-+ IRS1125_DESIGN_STEP_EXPECTED, read);
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+static int irs1125_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-+{
-+ struct v4l2_mbus_framefmt *format =
-+ v4l2_subdev_get_try_format(sd, fh->pad, 0);
-+
-+ format->code = MEDIA_BUS_FMT_Y12_1X12;
-+ format->width = IRS1125_WINDOW_WIDTH_DEF;
-+ format->height = IRS1125_WINDOW_HEIGHT_DEF;
-+ format->field = V4L2_FIELD_NONE;
-+ format->colorspace = V4L2_COLORSPACE_RAW;
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_subdev_internal_ops irs1125_subdev_internal_ops = {
-+ .open = irs1125_open,
-+};
-+
-+static int irs1125_ctrls_init(struct irs1125 *sensor, struct device *dev)
-+{
-+ struct v4l2_ctrl *ctrl;
-+ int err, i;
-+ struct v4l2_ctrl_handler *hdl;
-+
-+ hdl = &sensor->ctrl_handler;
-+ v4l2_ctrl_handler_init(hdl, ARRAY_SIZE(irs1125_custom_ctrls));
-+
-+ for (i = 0; i < ARRAY_SIZE(irs1125_custom_ctrls); i++) {
-+ ctrl = v4l2_ctrl_new_custom(hdl, &irs1125_custom_ctrls[i],
-+ NULL);
-+ if (!ctrl)
-+ dev_err(dev, "Failed to init custom control %s\n",
-+ irs1125_custom_ctrls[i].name);
-+ else if (irs1125_custom_ctrls[i].id == IRS1125_CID_NUM_SEQS)
-+ sensor->ctrl_numseq = ctrl;
-+ else if (irs1125_custom_ctrls[i].id == IRS1125_CID_MOD_PLL)
-+ sensor->ctrl_modplls = ctrl;
-+ }
-+
-+ if (hdl->error) {
-+ dev_err(dev, "Error %d adding controls\n", hdl->error);
-+ err = hdl->error;
-+ goto error_ctrls;
-+ }
-+
-+ sensor->sd.ctrl_handler = hdl;
-+ return 0;
-+
-+error_ctrls:
-+ v4l2_ctrl_handler_free(&sensor->ctrl_handler);
-+ return -err;
-+}
-+
-+static int irs1125_ident_setup(struct irs1125 *sensor, struct device *dev)
-+{
-+ int ret;
-+ struct v4l2_ctrl *ctrl;
-+ struct v4l2_subdev *sd;
-+ u16 read;
-+
-+ sd = &sensor->sd;
-+
-+ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT0);
-+ if (!ctrl) {
-+ dev_err(dev, "could not find device ctrl.\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL2, &read);
-+ if (ret < 0) {
-+ dev_err(dev, "error reading from i2c\n");
-+ return -EIO;
-+ }
-+
-+ v4l2_ctrl_s_ctrl(ctrl, read);
-+
-+ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT1);
-+ if (!ctrl) {
-+ dev_err(dev, "could not find device ctrl.\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL3, &read);
-+ if (ret < 0) {
-+ dev_err(dev, "error reading from i2c\n");
-+ return -EIO;
-+ }
-+
-+ v4l2_ctrl_s_ctrl(ctrl, read);
-+
-+ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT2);
-+ if (!ctrl) {
-+ dev_err(dev, "could not find device ctrl.\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL4, &read);
-+ if (ret < 0) {
-+ dev_err(dev, "error reading from i2c\n");
-+ return -EIO;
-+ }
-+ v4l2_ctrl_s_ctrl(ctrl, read & 0xFFFC);
-+
-+ return 0;
-+}
-+
-+static int irs1125_probe(struct i2c_client *client,
-+ const struct i2c_device_id *id)
-+{
-+ struct device *dev = &client->dev;
-+ struct irs1125 *sensor;
-+ int ret;
-+ struct fwnode_handle *endpoint;
-+ u32 xclk_freq;
-+ int gpio_num;
-+
-+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
-+ if (!sensor)
-+ return -ENOMEM;
-+
-+ v4l2_i2c_subdev_init(&sensor->sd, client, &irs1125_subdev_ops);
-+
-+ /* Get CSI2 bus config */
-+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev),
-+ NULL);
-+ if (!endpoint) {
-+ dev_err(dev, "endpoint node not found\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
-+ fwnode_handle_put(endpoint);
-+ if (ret) {
-+ dev_err(dev, "Could not parse endpoint\n");
-+ return ret;
-+ }
-+
-+ /* get system clock (xclk) */
-+ sensor->xclk = devm_clk_get(dev, NULL);
-+ if (IS_ERR(sensor->xclk)) {
-+ dev_err(dev, "could not get xclk");
-+ return PTR_ERR(sensor->xclk);
-+ }
-+
-+ xclk_freq = clk_get_rate(sensor->xclk);
-+ if (xclk_freq != 26000000) {
-+ dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq);
-+ return -EINVAL;
-+ }
-+
-+ sensor->num_seq = 5;
-+
-+ /* Request the power down GPIO */
-+ sensor->reset = devm_gpiod_get(&client->dev, "pwdn",
-+ GPIOD_OUT_LOW);
-+
-+ if (IS_ERR(sensor->reset)) {
-+ dev_err(dev, "could not get reset");
-+ return PTR_ERR(sensor->reset);
-+ }
-+
-+ gpio_num = desc_to_gpio(sensor->reset);
-+
-+ mutex_init(&sensor->lock);
-+
-+ ret = irs1125_ctrls_init(sensor, dev);
-+ if (ret < 0)
-+ goto mutex_remove;
-+
-+ sensor->sd.internal_ops = &irs1125_subdev_internal_ops;
-+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
-+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
-+ if (ret < 0)
-+ goto mutex_remove;
-+
-+ gpiod_set_value_cansleep(sensor->reset, 1);
-+ msleep(RESET_ACTIVE_DELAY_MS);
-+
-+ ret = irs1125_detect(&sensor->sd);
-+ if (ret < 0)
-+ goto error;
-+
-+ ret = irs1125_ident_setup(sensor, dev);
-+ if (ret < 0)
-+ goto error;
-+
-+ gpiod_set_value_cansleep(sensor->reset, 0);
-+
-+ ret = v4l2_async_register_subdev(&sensor->sd);
-+ if (ret < 0)
-+ goto error;
-+
-+ dev_dbg(dev, "Infineon IRS1125 camera driver probed\n");
-+
-+ return 0;
-+
-+error:
-+ media_entity_cleanup(&sensor->sd.entity);
-+mutex_remove:
-+ mutex_destroy(&sensor->lock);
-+ return ret;
-+}
-+
-+static int irs1125_remove(struct i2c_client *client)
-+{
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct irs1125 *irs1125 = to_state(sd);
-+
-+ v4l2_async_unregister_subdev(&irs1125->sd);
-+ media_entity_cleanup(&irs1125->sd.entity);
-+ v4l2_device_unregister_subdev(sd);
-+ mutex_destroy(&irs1125->lock);
-+ v4l2_ctrl_handler_free(&irs1125->ctrl_handler);
-+
-+ return 0;
-+}
-+
-+#if IS_ENABLED(CONFIG_OF)
-+static const struct of_device_id irs1125_of_match[] = {
-+ { .compatible = "infineon,irs1125" },
-+ { /* sentinel */ },
-+};
-+MODULE_DEVICE_TABLE(of, irs1125_of_match);
-+#endif
-+
-+static struct i2c_driver irs1125_driver = {
-+ .driver = {
-+ .of_match_table = of_match_ptr(irs1125_of_match),
-+ .name = SENSOR_NAME,
-+ },
-+ .probe = irs1125_probe,
-+ .remove = irs1125_remove,
-+};
-+
-+module_i2c_driver(irs1125_driver);
-+
-+MODULE_DESCRIPTION("Infineon irs1125 sensor driver");
-+MODULE_LICENSE("GPL v2");
-+
---- /dev/null
-+++ b/drivers/media/i2c/irs1125.h
-@@ -0,0 +1,61 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * A V4L2 driver for Infineon IRS1125 TOF cameras.
-+ * Copyright (C) 2018, pieye GmbH
-+ *
-+ * Based on V4L2 OmniVision OV5647 Image Sensor driver
-+ *
-+ * DT / fwnode changes, and GPIO control taken from ov5640.c
-+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
-+ * Copyright (C) 2014-2017 Mentor Graphics Inc.
-+ *
-+ */
-+
-+#ifndef IRS1125_H
-+#define IRS1125_H
-+
-+#include <linux/v4l2-controls.h>
-+#include <linux/types.h>
-+
-+#define IRS1125_NUM_SEQ_ENTRIES 20
-+#define IRS1125_NUM_MOD_PLLS 4
-+
-+#define IRS1125_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
-+#define IRS1125_CID_SAFE_RECONFIG (IRS1125_CID_CUSTOM_BASE + 0)
-+#define IRS1125_CID_CONTINUOUS_TRIG (IRS1125_CID_CUSTOM_BASE + 1)
-+#define IRS1125_CID_TRIGGER (IRS1125_CID_CUSTOM_BASE + 2)
-+#define IRS1125_CID_RECONFIG (IRS1125_CID_CUSTOM_BASE + 3)
-+#define IRS1125_CID_ILLU_ON (IRS1125_CID_CUSTOM_BASE + 4)
-+#define IRS1125_CID_NUM_SEQS (IRS1125_CID_CUSTOM_BASE + 5)
-+#define IRS1125_CID_MOD_PLL (IRS1125_CID_CUSTOM_BASE + 6)
-+#define IRS1125_CID_SEQ_CONFIG (IRS1125_CID_CUSTOM_BASE + 7)
-+#define IRS1125_CID_IDENT0 (IRS1125_CID_CUSTOM_BASE + 8)
-+#define IRS1125_CID_IDENT1 (IRS1125_CID_CUSTOM_BASE + 9)
-+#define IRS1125_CID_IDENT2 (IRS1125_CID_CUSTOM_BASE + 10)
-+
-+struct irs1125_seq_cfg {
-+ __u16 exposure;
-+ __u16 framerate;
-+ __u16 ps;
-+ __u16 pll;
-+};
-+
-+struct irs1125_illu {
-+ __u16 exposure;
-+ __u16 framerate;
-+};
-+
-+struct irs1125_mod_pll {
-+ __u16 pllcfg1;
-+ __u16 pllcfg2;
-+ __u16 pllcfg3;
-+ __u16 pllcfg4;
-+ __u16 pllcfg5;
-+ __u16 pllcfg6;
-+ __u16 pllcfg7;
-+ __u16 pllcfg8;
-+};
-+
-+#endif /* IRS1125 */
-+
--- /dev/null
+From 09ad53f0267e4b5433c27c77b3945d584ac0a6ba Mon Sep 17 00:00:00 2001
+Date: Tue, 22 Oct 2019 08:47:29 +0100
+Subject: [PATCH] rpi-wm8804-soundcard: Fixed MCLKDIV for Allo Digione
+
+The Allo Digione board wants a fixed MCLKDIV of 256.
+
+See: https://github.com/raspberrypi/linux/issues/3296
+
+---
+ sound/soc/bcm/rpi-wm8804-soundcard.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/sound/soc/bcm/rpi-wm8804-soundcard.c
++++ b/sound/soc/bcm/rpi-wm8804-soundcard.c
+@@ -66,6 +66,11 @@ static struct gpio_desc *snd_clk44gpio;
+ static struct gpio_desc *snd_clk48gpio;
+ static int wm8804_samplerate = 0;
+
++/* Forward declarations */
++static struct snd_soc_dai_link snd_allo_digione_dai[];
++static struct snd_soc_card snd_rpi_wm8804;
++
++
+ #define CLK_44EN_RATE 22579200UL
+ #define CLK_48EN_RATE 24576000UL
+
+@@ -90,11 +95,10 @@ static unsigned int snd_rpi_wm8804_enabl
+ static void snd_rpi_wm8804_clk_cfg(unsigned int samplerate,
+ struct wm8804_clk_cfg *clk_cfg)
+ {
+- clk_cfg->mclk_freq = 0;
+- clk_cfg->mclk_div = 1;
+ clk_cfg->sysclk_freq = 27000000;
+
+- if (samplerate <= 96000) {
++ if (samplerate <= 96000 ||
++ snd_rpi_wm8804.dai_link == snd_allo_digione_dai) {
+ clk_cfg->mclk_freq = samplerate * 256;
+ clk_cfg->mclk_div = WM8804_MCLKDIV_256FS;
+ } else {
+++ /dev/null
-From 89af5d7df7f548744bd675d96295c0f45e24b31f Mon Sep 17 00:00:00 2001
-Date: Thu, 10 Oct 2019 19:13:02 +0200
-Subject: [PATCH] dtoverlays: Add an overlay for the Infineon IRS1125
-
-The Infineon IRS1125 is a CSI2 time of flight depth sensor
-which has a suitable V4L2 subdevice driver.
-
-Add an overlay for configuring it.
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 12 +++
- .../arm/boot/dts/overlays/irs1125-overlay.dts | 97 +++++++++++++++++++
- 3 files changed, 110 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/irs1125-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -83,6 +83,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- iqaudio-dac.dtbo \
- iqaudio-dacplus.dtbo \
- iqaudio-digi-wm8804-audio.dtbo \
-+ irs1125.dtbo \
- jedec-spi-nor.dtbo \
- justboom-dac.dtbo \
- justboom-digi.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1347,6 +1347,18 @@ Params: card_name Override
- dai stream name.
-
-
-+Name: irs1125
-+Info: Infineon irs1125 TOF camera module.
-+ Uses Unicam 1, which is the standard camera connector on most Pi
-+ variants.
-+Load: dtoverlay=irs1125,<param>=<val>
-+Params: i2c_pins_0_1 Use pins 0&1 for the I2C instead of 44&45.
-+ Useful on Compute Modules.
-+
-+ i2c_pins_28_29 Use pins 28&29 for the I2C instead of 44&45.
-+ This is required for Pi B+, 2, 0, and 0W.
-+
-+
- Name: jedec-spi-nor
- Info: Adds support for JEDEC-compliant SPI NOR flash devices. (Note: The
- "jedec,spi-nor" kernel driver was formerly known as "m25p80".)
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/irs1125-overlay.dts
-@@ -0,0 +1,97 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+// Definitions for IRS1125 camera module on VC I2C bus
-+/dts-v1/;
-+/plugin/;
-+
-+/{
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&i2c_vc>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ irs1125: irs1125@3D {
-+ compatible = "infineon,irs1125";
-+ reg = <0x3D>;
-+ status = "okay";
-+
-+ pwdn-gpios = <&gpio 5 0>;
-+ clocks = <&irs1125_clk>;
-+
-+ irs1125_clk: camera-clk {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <26000000>;
-+ };
-+
-+ port {
-+ irs1125_0: endpoint {
-+ remote-endpoint = <&csi1_ep>;
-+ clock-lanes = <0>;
-+ data-lanes = <1 2>;
-+ clock-noncontinuous;
-+ link-frequencies =
-+ /bits/ 64 <297000000>;
-+ };
-+ };
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&csi1>;
-+ __overlay__ {
-+ status = "okay";
-+
-+ port {
-+ csi1_ep: endpoint {
-+ remote-endpoint = <&irs1125_0>;
-+ };
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c0_pins>;
-+ __dormant__ {
-+ brcm,pins = <28 29>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+ };
-+ fragment@3 {
-+ target = <&i2c0_pins>;
-+ __overlay__ {
-+ brcm,pins = <44 45>;
-+ brcm,function = <5>; /* alt1 */
-+ };
-+ };
-+ fragment@4 {
-+ target = <&i2c0_pins>;
-+ __dormant__ {
-+ brcm,pins = <0 1>;
-+ brcm,function = <4>; /* alt0 */
-+ };
-+ };
-+ fragment@5 {
-+ target = <&i2c_vc>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@6 {
-+ target-path="/__overrides__";
-+ __overlay__ {
-+ cam0-pwdn-ctrl = <&irs1125>,"pwdn-gpios:0";
-+ cam0-pwdn = <&irs1125>,"pwdn-gpios:4";
-+ };
-+ };
-+
-+ __overrides__ {
-+ i2c_pins_0_1 = <0>,"-2-3+4";
-+ i2c_pins_28_29 = <0>,"+2-3-4";
-+ };
-+};
--- /dev/null
+From 2e3db17d59143bfaf15423feb7eed68893e04f66 Mon Sep 17 00:00:00 2001
+Date: Thu, 24 Oct 2019 14:31:00 +0100
+Subject: [PATCH] dts: bcm2838: Disable DWC OTG block by default
+
+Turning off the OTG USB block saves power. Since it requires the use of
+the dwc2 overlay to make use of it, we can disable it by default.
+
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -647,6 +647,7 @@
+
+ &usb {
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
+ };
+
+ &hdmi {
+++ /dev/null
-From 09ad53f0267e4b5433c27c77b3945d584ac0a6ba Mon Sep 17 00:00:00 2001
-Date: Tue, 22 Oct 2019 08:47:29 +0100
-Subject: [PATCH] rpi-wm8804-soundcard: Fixed MCLKDIV for Allo Digione
-
-The Allo Digione board wants a fixed MCLKDIV of 256.
-
-See: https://github.com/raspberrypi/linux/issues/3296
-
----
- sound/soc/bcm/rpi-wm8804-soundcard.c | 10 +++++++---
- 1 file changed, 7 insertions(+), 3 deletions(-)
-
---- a/sound/soc/bcm/rpi-wm8804-soundcard.c
-+++ b/sound/soc/bcm/rpi-wm8804-soundcard.c
-@@ -66,6 +66,11 @@ static struct gpio_desc *snd_clk44gpio;
- static struct gpio_desc *snd_clk48gpio;
- static int wm8804_samplerate = 0;
-
-+/* Forward declarations */
-+static struct snd_soc_dai_link snd_allo_digione_dai[];
-+static struct snd_soc_card snd_rpi_wm8804;
-+
-+
- #define CLK_44EN_RATE 22579200UL
- #define CLK_48EN_RATE 24576000UL
-
-@@ -90,11 +95,10 @@ static unsigned int snd_rpi_wm8804_enabl
- static void snd_rpi_wm8804_clk_cfg(unsigned int samplerate,
- struct wm8804_clk_cfg *clk_cfg)
- {
-- clk_cfg->mclk_freq = 0;
-- clk_cfg->mclk_div = 1;
- clk_cfg->sysclk_freq = 27000000;
-
-- if (samplerate <= 96000) {
-+ if (samplerate <= 96000 ||
-+ snd_rpi_wm8804.dai_link == snd_allo_digione_dai) {
- clk_cfg->mclk_freq = samplerate * 256;
- clk_cfg->mclk_div = WM8804_MCLKDIV_256FS;
- } else {
--- /dev/null
+From 9894906ad424f266853b61a6996b2da8b119c6e6 Mon Sep 17 00:00:00 2001
+Date: Fri, 13 Sep 2019 17:19:33 +0100
+Subject: [PATCH] staging:bcm2835-codec: Add support for
+ ENUM_FRAMESIZES
+
+Required for compliance testing for the encoder.
+
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 48 +++++++++++++++++--
+ 1 file changed, 44 insertions(+), 4 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -496,9 +496,10 @@ struct bcm2835_codec_fmt *get_default_fo
+ return &dev->supported_fmts[capture ? 1 : 0].list[0];
+ }
+
+-static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
+- struct bcm2835_codec_dev *dev,
+- bool capture)
++static
++struct bcm2835_codec_fmt *find_format_pix_fmt(u32 pix_fmt,
++ struct bcm2835_codec_dev *dev,
++ bool capture)
+ {
+ struct bcm2835_codec_fmt *fmt;
+ unsigned int k;
+@@ -507,7 +508,7 @@ static struct bcm2835_codec_fmt *find_fo
+
+ for (k = 0; k < fmts->num_entries; k++) {
+ fmt = &fmts->list[k];
+- if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
++ if (fmt->fourcc == pix_fmt)
+ break;
+ }
+ if (k == fmts->num_entries)
+@@ -516,6 +517,14 @@ static struct bcm2835_codec_fmt *find_fo
+ return &fmts->list[k];
+ }
+
++static inline
++struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
++ struct bcm2835_codec_dev *dev,
++ bool capture)
++{
++ return find_format_pix_fmt(f->fmt.pix_mp.pixelformat, dev, capture);
++}
++
+ static inline struct bcm2835_codec_ctx *file2ctx(struct file *file)
+ {
+ return container_of(file->private_data, struct bcm2835_codec_ctx, fh);
+@@ -1792,6 +1801,36 @@ static int vidioc_encoder_cmd(struct fil
+ return 0;
+ }
+
++static int vidioc_enum_framesizes(struct file *file, void *fh,
++ struct v4l2_frmsizeenum *fsize)
++{
++ struct bcm2835_codec_fmt *fmt;
++
++ fmt = find_format_pix_fmt(fsize->pixel_format, file2ctx(file)->dev,
++ true);
++ if (!fmt)
++ fmt = find_format_pix_fmt(fsize->pixel_format,
++ file2ctx(file)->dev,
++ false);
++
++ if (!fmt)
++ return -EINVAL;
++
++ if (fsize->index)
++ return -EINVAL;
++
++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
++
++ fsize->stepwise.min_width = MIN_W;
++ fsize->stepwise.max_width = MAX_W;
++ fsize->stepwise.step_width = 1;
++ fsize->stepwise.min_height = MIN_H;
++ fsize->stepwise.max_height = MAX_H;
++ fsize->stepwise.step_height = 1;
++
++ return 0;
++}
++
+ static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+
+@@ -1829,6 +1868,7 @@ static const struct v4l2_ioctl_ops bcm28
+ .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd,
+ .vidioc_encoder_cmd = vidioc_encoder_cmd,
+ .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd,
++ .vidioc_enum_framesizes = vidioc_enum_framesizes,
+ };
+
+ static int bcm2835_codec_set_ctrls(struct bcm2835_codec_ctx *ctx)
+++ /dev/null
-From 2e3db17d59143bfaf15423feb7eed68893e04f66 Mon Sep 17 00:00:00 2001
-Date: Thu, 24 Oct 2019 14:31:00 +0100
-Subject: [PATCH] dts: bcm2838: Disable DWC OTG block by default
-
-Turning off the OTG USB block saves power. Since it requires the use of
-the dwc2 overlay to make use of it, we can disable it by default.
-
----
- arch/arm/boot/dts/bcm2838.dtsi | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -647,6 +647,7 @@
-
- &usb {
- interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
-+ status = "disabled";
- };
-
- &hdmi {
--- /dev/null
+From 9783756bf18033f321161393814dc1dd99c1704a Mon Sep 17 00:00:00 2001
+Date: Fri, 13 Sep 2019 17:22:08 +0100
+Subject: [PATCH] staging: bcm2835-codec: Correct buffer type check on
+ G_PARM
+
+The output queue buffer type is now OUTPUT_MPLANE.
+
+Fixes: 5e484a3 staging: bcm2835-codec: switch to multi-planar API
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1438,7 +1438,7 @@ static int vidioc_g_parm(struct file *fi
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+
+- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+
+ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+++ /dev/null
-From 9894906ad424f266853b61a6996b2da8b119c6e6 Mon Sep 17 00:00:00 2001
-Date: Fri, 13 Sep 2019 17:19:33 +0100
-Subject: [PATCH] staging:bcm2835-codec: Add support for
- ENUM_FRAMESIZES
-
-Required for compliance testing for the encoder.
-
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 48 +++++++++++++++++--
- 1 file changed, 44 insertions(+), 4 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -496,9 +496,10 @@ struct bcm2835_codec_fmt *get_default_fo
- return &dev->supported_fmts[capture ? 1 : 0].list[0];
- }
-
--static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
-- struct bcm2835_codec_dev *dev,
-- bool capture)
-+static
-+struct bcm2835_codec_fmt *find_format_pix_fmt(u32 pix_fmt,
-+ struct bcm2835_codec_dev *dev,
-+ bool capture)
- {
- struct bcm2835_codec_fmt *fmt;
- unsigned int k;
-@@ -507,7 +508,7 @@ static struct bcm2835_codec_fmt *find_fo
-
- for (k = 0; k < fmts->num_entries; k++) {
- fmt = &fmts->list[k];
-- if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
-+ if (fmt->fourcc == pix_fmt)
- break;
- }
- if (k == fmts->num_entries)
-@@ -516,6 +517,14 @@ static struct bcm2835_codec_fmt *find_fo
- return &fmts->list[k];
- }
-
-+static inline
-+struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
-+ struct bcm2835_codec_dev *dev,
-+ bool capture)
-+{
-+ return find_format_pix_fmt(f->fmt.pix_mp.pixelformat, dev, capture);
-+}
-+
- static inline struct bcm2835_codec_ctx *file2ctx(struct file *file)
- {
- return container_of(file->private_data, struct bcm2835_codec_ctx, fh);
-@@ -1792,6 +1801,36 @@ static int vidioc_encoder_cmd(struct fil
- return 0;
- }
-
-+static int vidioc_enum_framesizes(struct file *file, void *fh,
-+ struct v4l2_frmsizeenum *fsize)
-+{
-+ struct bcm2835_codec_fmt *fmt;
-+
-+ fmt = find_format_pix_fmt(fsize->pixel_format, file2ctx(file)->dev,
-+ true);
-+ if (!fmt)
-+ fmt = find_format_pix_fmt(fsize->pixel_format,
-+ file2ctx(file)->dev,
-+ false);
-+
-+ if (!fmt)
-+ return -EINVAL;
-+
-+ if (fsize->index)
-+ return -EINVAL;
-+
-+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-+
-+ fsize->stepwise.min_width = MIN_W;
-+ fsize->stepwise.max_width = MAX_W;
-+ fsize->stepwise.step_width = 1;
-+ fsize->stepwise.min_height = MIN_H;
-+ fsize->stepwise.max_height = MAX_H;
-+ fsize->stepwise.step_height = 1;
-+
-+ return 0;
-+}
-+
- static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
-
-@@ -1829,6 +1868,7 @@ static const struct v4l2_ioctl_ops bcm28
- .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd,
- .vidioc_encoder_cmd = vidioc_encoder_cmd,
- .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd,
-+ .vidioc_enum_framesizes = vidioc_enum_framesizes,
- };
-
- static int bcm2835_codec_set_ctrls(struct bcm2835_codec_ctx *ctx)
--- /dev/null
+From 4d6c40ebfe10dd2fdc64bd7607e51275d5524e47 Mon Sep 17 00:00:00 2001
+Date: Fri, 13 Sep 2019 17:23:26 +0100
+Subject: [PATCH] staging: bcm2835-codec: Set default and error check
+ timeperframe
+
+G_PARM default was invalid as 0/0, and the driver didn't check
+the value set in S_PARM wasn't 0/0.
+
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1423,6 +1423,10 @@ static int vidioc_s_parm(struct file *fi
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+
++ if (!parm->parm.output.timeperframe.denominator ||
++ !parm->parm.output.timeperframe.numerator)
++ return -EINVAL;
++
+ ctx->framerate_num =
+ parm->parm.output.timeperframe.denominator;
+ ctx->framerate_denom =
+@@ -2390,6 +2394,9 @@ static int bcm2835_codec_open(struct fil
+ ctx->colorspace = V4L2_COLORSPACE_REC709;
+ ctx->bitrate = 10 * 1000 * 1000;
+
++ ctx->framerate_num = 30;
++ ctx->framerate_denom = 1;
++
+ /* Initialise V4L2 contexts */
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+++ /dev/null
-From 9783756bf18033f321161393814dc1dd99c1704a Mon Sep 17 00:00:00 2001
-Date: Fri, 13 Sep 2019 17:22:08 +0100
-Subject: [PATCH] staging: bcm2835-codec: Correct buffer type check on
- G_PARM
-
-The output queue buffer type is now OUTPUT_MPLANE.
-
-Fixes: 5e484a3 staging: bcm2835-codec: switch to multi-planar API
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1438,7 +1438,7 @@ static int vidioc_g_parm(struct file *fi
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
-
-- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return -EINVAL;
-
- parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
--- /dev/null
+From 4542b5d7b4e00b11dd37d93986b624c58b198765 Mon Sep 17 00:00:00 2001
+Date: Mon, 7 Oct 2019 14:02:57 +0100
+Subject: [PATCH] staging: bcm2835-codec: Fix imbalance in
+ dma_buf_get/dma_buf_put
+
+When represented with a dmabuf buffer that had previously been
+imported, there was a call to dma_buf_get without a matching
+dma_buf_put. This left dmabufs in limbo after all users had
+supposedly released them.
+
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -2112,6 +2112,11 @@ static int bcm2835_codec_buf_prepare(str
+ }
+
+ buf->mmal.dma_buf = dma_buf;
++ } else {
++ /* We already have a reference count on the dmabuf, so
++ * release the one we acquired above.
++ */
++ dma_buf_put(dma_buf);
+ }
+ ret = 0;
+ break;
--- /dev/null
+From ebb8a4e93e242311d319098ea56e4ef4d92c4d19 Mon Sep 17 00:00:00 2001
+Date: Wed, 16 Oct 2019 14:49:23 +0100
+Subject: [PATCH] drm:vc4 Added calls for firmware display
+ blank/unblank
+
+Requires new display power mailbox call to be present.
+
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 25 ++++++++++++++++++++++
+ include/soc/bcm2835/raspberrypi-firmware.h | 2 +-
+ 2 files changed, 26 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -91,6 +91,12 @@ struct mailbox_blank_display {
+ u32 blank;
+ };
+
++struct mailbox_display_pwr {
++ struct rpi_firmware_property_tag_header tag1;
++ u32 display;
++ u32 state;
++};
++
+ struct mailbox_get_edid {
+ struct rpi_firmware_property_tag_header tag1;
+ u32 block;
+@@ -272,6 +278,7 @@ struct vc4_fkms_encoder {
+ struct drm_encoder base;
+ bool hdmi_monitor;
+ bool rgb_range_selectable;
++ int display_num;
+ };
+
+ static inline struct vc4_fkms_encoder *
+@@ -1613,13 +1620,29 @@ static const struct drm_encoder_funcs vc
+ .destroy = vc4_fkms_encoder_destroy,
+ };
+
++static void vc4_fkms_display_power(struct drm_encoder *encoder, bool power)
++{
++ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
++ struct vc4_dev *vc4 = to_vc4_dev(encoder->dev);
++
++ struct mailbox_display_pwr pwr = {
++ .tag1 = {RPI_FIRMWARE_SET_DISPLAY_POWER, 8, 0, },
++ .display = vc4_encoder->display_num,
++ .state = power ? 1 : 0,
++ };
++
++ rpi_firmware_property_list(vc4->firmware, &pwr, sizeof(pwr));
++}
++
+ static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
+ {
++ vc4_fkms_display_power(encoder, true);
+ DRM_DEBUG_KMS("Encoder_enable\n");
+ }
+
+ static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
+ {
++ vc4_fkms_display_power(encoder, false);
+ DRM_DEBUG_KMS("Encoder_disable\n");
+ }
+
+@@ -1695,6 +1718,8 @@ static int vc4_fkms_create_screen(struct
+ if (!vc4_encoder)
+ return -ENOMEM;
+ vc4_crtc->encoder = &vc4_encoder->base;
++
++ vc4_encoder->display_num = display_ref;
+ vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ;
+
+ drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -155,7 +155,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
+ RPI_FIRMWARE_SET_TIMING = 0x00048017,
+ RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018,
+-
++ RPI_FIRMWARE_SET_DISPLAY_POWER = 0x00048019,
+ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
+ RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
+ };
+++ /dev/null
-From 4d6c40ebfe10dd2fdc64bd7607e51275d5524e47 Mon Sep 17 00:00:00 2001
-Date: Fri, 13 Sep 2019 17:23:26 +0100
-Subject: [PATCH] staging: bcm2835-codec: Set default and error check
- timeperframe
-
-G_PARM default was invalid as 0/0, and the driver didn't check
-the value set in S_PARM wasn't 0/0.
-
----
- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1423,6 +1423,10 @@ static int vidioc_s_parm(struct file *fi
- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return -EINVAL;
-
-+ if (!parm->parm.output.timeperframe.denominator ||
-+ !parm->parm.output.timeperframe.numerator)
-+ return -EINVAL;
-+
- ctx->framerate_num =
- parm->parm.output.timeperframe.denominator;
- ctx->framerate_denom =
-@@ -2390,6 +2394,9 @@ static int bcm2835_codec_open(struct fil
- ctx->colorspace = V4L2_COLORSPACE_REC709;
- ctx->bitrate = 10 * 1000 * 1000;
-
-+ ctx->framerate_num = 30;
-+ ctx->framerate_denom = 1;
-+
- /* Initialise V4L2 contexts */
- v4l2_fh_init(&ctx->fh, video_devdata(file));
- file->private_data = &ctx->fh;
--- /dev/null
+From 633c64173636b2f6acebfddb3d2b69c92bbbcd07 Mon Sep 17 00:00:00 2001
+Date: Thu, 31 Oct 2019 13:37:16 +0000
+Subject: [PATCH] rpi-poe-fan: fix def_pwm1 writes
+
+---
+ drivers/hwmon/rpi-poe-fan.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/hwmon/rpi-poe-fan.c
++++ b/drivers/hwmon/rpi-poe-fan.c
+@@ -110,7 +110,7 @@ static int __set_def_pwm(struct rpi_poe
+ if (ctx->def_pwm_value == def_pwm)
+ goto exit_set_def_pwm_err;
+
+- ret = write_reg(ctx->fw, POE_CUR_PWM, &def_pwm);
++ ret = write_reg(ctx->fw, POE_DEF_PWM, &def_pwm);
+ if (!ret)
+ ctx->def_pwm_value = def_pwm;
+ exit_set_def_pwm_err:
+++ /dev/null
-From 4542b5d7b4e00b11dd37d93986b624c58b198765 Mon Sep 17 00:00:00 2001
-Date: Mon, 7 Oct 2019 14:02:57 +0100
-Subject: [PATCH] staging: bcm2835-codec: Fix imbalance in
- dma_buf_get/dma_buf_put
-
-When represented with a dmabuf buffer that had previously been
-imported, there was a call to dma_buf_get without a matching
-dma_buf_put. This left dmabufs in limbo after all users had
-supposedly released them.
-
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -2112,6 +2112,11 @@ static int bcm2835_codec_buf_prepare(str
- }
-
- buf->mmal.dma_buf = dma_buf;
-+ } else {
-+ /* We already have a reference count on the dmabuf, so
-+ * release the one we acquired above.
-+ */
-+ dma_buf_put(dma_buf);
- }
- ret = 0;
- break;
+++ /dev/null
-From ebb8a4e93e242311d319098ea56e4ef4d92c4d19 Mon Sep 17 00:00:00 2001
-Date: Wed, 16 Oct 2019 14:49:23 +0100
-Subject: [PATCH] drm:vc4 Added calls for firmware display
- blank/unblank
-
-Requires new display power mailbox call to be present.
-
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 25 ++++++++++++++++++++++
- include/soc/bcm2835/raspberrypi-firmware.h | 2 +-
- 2 files changed, 26 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -91,6 +91,12 @@ struct mailbox_blank_display {
- u32 blank;
- };
-
-+struct mailbox_display_pwr {
-+ struct rpi_firmware_property_tag_header tag1;
-+ u32 display;
-+ u32 state;
-+};
-+
- struct mailbox_get_edid {
- struct rpi_firmware_property_tag_header tag1;
- u32 block;
-@@ -272,6 +278,7 @@ struct vc4_fkms_encoder {
- struct drm_encoder base;
- bool hdmi_monitor;
- bool rgb_range_selectable;
-+ int display_num;
- };
-
- static inline struct vc4_fkms_encoder *
-@@ -1613,13 +1620,29 @@ static const struct drm_encoder_funcs vc
- .destroy = vc4_fkms_encoder_destroy,
- };
-
-+static void vc4_fkms_display_power(struct drm_encoder *encoder, bool power)
-+{
-+ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
-+ struct vc4_dev *vc4 = to_vc4_dev(encoder->dev);
-+
-+ struct mailbox_display_pwr pwr = {
-+ .tag1 = {RPI_FIRMWARE_SET_DISPLAY_POWER, 8, 0, },
-+ .display = vc4_encoder->display_num,
-+ .state = power ? 1 : 0,
-+ };
-+
-+ rpi_firmware_property_list(vc4->firmware, &pwr, sizeof(pwr));
-+}
-+
- static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
- {
-+ vc4_fkms_display_power(encoder, true);
- DRM_DEBUG_KMS("Encoder_enable\n");
- }
-
- static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
- {
-+ vc4_fkms_display_power(encoder, false);
- DRM_DEBUG_KMS("Encoder_disable\n");
- }
-
-@@ -1695,6 +1718,8 @@ static int vc4_fkms_create_screen(struct
- if (!vc4_encoder)
- return -ENOMEM;
- vc4_crtc->encoder = &vc4_encoder->base;
-+
-+ vc4_encoder->display_num = display_ref;
- vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ;
-
- drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -155,7 +155,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
- RPI_FIRMWARE_SET_TIMING = 0x00048017,
- RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018,
--
-+ RPI_FIRMWARE_SET_DISPLAY_POWER = 0x00048019,
- RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
- RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
- };
--- /dev/null
+From b1e290ec968186530ec59479adfba89d2cfe21c8 Mon Sep 17 00:00:00 2001
+Date: Sun, 24 Mar 2019 00:18:46 +0200
+Subject: [PATCH] net: phy: bcm54xx: Encode link speed and activity
+ into LEDs
+
+Previously the green and amber LEDs on this quad PHY were solid, to
+indicate an encoding of the link speed (10/100/1000).
+
+This keeps the LEDs always on just as before, but now they flash on
+Rx/Tx activity.
+
+---
+ drivers/net/phy/broadcom.c | 13 +++++++++++++
+ include/linux/brcmphy.h | 16 ++++++++++++++++
+ 2 files changed, 29 insertions(+)
+
+--- a/drivers/net/phy/broadcom.c
++++ b/drivers/net/phy/broadcom.c
+@@ -345,6 +345,19 @@ static int bcm54xx_config_init(struct ph
+
+ bcm54xx_phydsp_config(phydev);
+
++ /* Encode link speed into LED1 and LED3 pair (green/amber).
++ * Also flash these two LEDs on activity. This means configuring
++ * them for MULTICOLOR and encoding link/activity into them.
++ */
++ val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
++ BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
++ bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
++
++ val = BCM_LED_MULTICOLOR_IN_PHASE |
++ BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
++ BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
++ bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
++
+ return 0;
+ }
+
+--- a/include/linux/brcmphy.h
++++ b/include/linux/brcmphy.h
+@@ -148,6 +148,22 @@
+ #define BCM_LED_SRC_OFF 0xe /* Tied high */
+ #define BCM_LED_SRC_ON 0xf /* Tied low */
+
++/*
++ * Broadcom Multicolor LED configurations (expansion register 4)
++ */
++#define BCM_EXP_MULTICOLOR (MII_BCM54XX_EXP_SEL_ER + 0x04)
++#define BCM_LED_MULTICOLOR_IN_PHASE BIT(8)
++#define BCM_LED_MULTICOLOR_LINK_ACT 0x0
++#define BCM_LED_MULTICOLOR_SPEED 0x1
++#define BCM_LED_MULTICOLOR_ACT_FLASH 0x2
++#define BCM_LED_MULTICOLOR_FDX 0x3
++#define BCM_LED_MULTICOLOR_OFF 0x4
++#define BCM_LED_MULTICOLOR_ON 0x5
++#define BCM_LED_MULTICOLOR_ALT 0x6
++#define BCM_LED_MULTICOLOR_FLASH 0x7
++#define BCM_LED_MULTICOLOR_LINK 0x8
++#define BCM_LED_MULTICOLOR_ACT 0x9
++#define BCM_LED_MULTICOLOR_PROGRAM 0xa
+
+ /*
+ * BCM5482: Shadow registers
--- /dev/null
+From 2679834327b5b8db8a7b0c90b632b81c35f9e271 Mon Sep 17 00:00:00 2001
+Date: Thu, 31 Oct 2019 14:39:44 +0000
+Subject: [PATCH] net:phy:2711 Allow ethernet LED mode to be set via
+ device tree
+
+Add device tree entries and code to allow the specification of
+the lighting modes for the LED's on the ethernet connector.
+
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 3 +++
+ arch/arm/boot/dts/bcm2838.dtsi | 1 +
+ arch/arm/boot/dts/overlays/README | 28 +++++++++++++++++++--------
+ drivers/net/phy/broadcom.c | 9 +++++++--
+ 4 files changed, 31 insertions(+), 10 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -334,5 +334,8 @@
+ pwr_led_gpio = <&pwr_led>,"gpios:4";
+ pwr_led_activelow = <&pwr_led>,"gpios:8";
+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
++
++ eth_led0 = <&phy1>,"led-modes:0";
++ eth_led1 = <&phy1>,"led-modes:4";
+ };
+ };
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -380,6 +380,7 @@
+ /* No interrupts - use PHY_POLL */
+ max-speed = <1000>;
+ reg = <0x1>;
++ led-modes = <0x02 0x02>;
+ };
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -102,26 +102,38 @@ Params:
+
+ eee Enable Energy Efficient Ethernet support for
+ compatible devices (default "on"). See also
+- "tx_lpi_timer".
++ "tx_lpi_timer". Pi3B+ only.
+
+ eth_downshift_after Set the number of auto-negotiation failures
+ after which the 1000Mbps modes are disabled.
+ Legal values are 2, 3, 4, 5 and 0, where
+- 0 means never downshift (default 2).
++ 0 means never downshift (default 2). Pi3B+ only.
+
+- eth_led0 Set mode of LED0 (usually orange) (default
+- "1"). The legal values are:
+- 0=link/activity 1=link1000/activity
++ eth_led0 Set mode of LED0 (usually orange). The legal
++ values are:
++
++ Pi3B+
++
++ 0=link/activity 1=link1000/activity (default)
+ 2=link100/activity 3=link10/activity
+ 4=link100/1000/activity 5=link10/1000/activity
+ 6=link10/100/activity 14=off 15=on
+
+- eth_led1 Set mode of LED1 (usually green) (default
+- "6"). See eth_led0 for legal values.
++ Pi4
++
++ 0=Speed/Activity (default) 1=Speed
++ 2=Speed/Flash activity 3=FDX
++ 4=Off 5=On
++ 6=Alt 7=Speed/Flash
++ 8=Link 9=Activity
++
++ eth_led1 Set mode of LED1 (usually green) (Pi3B+ default
++ "6", Pi4 default "0"). See eth_led0 for legal
++ values.
+
+ eth_max_speed Set the maximum speed a link is allowed
+ to negotiate. Legal values are 10, 100 and
+- 1000 (default 1000).
++ 1000 (default 1000). Pi3B+ only.
+
+ i2c_arm Set to "on" to enable the ARM's i2c interface
+ (default "off")
+--- a/drivers/net/phy/broadcom.c
++++ b/drivers/net/phy/broadcom.c
+@@ -292,6 +292,9 @@ static void bcm54xx_adjust_rxrefclk(stru
+ static int bcm54xx_config_init(struct phy_device *phydev)
+ {
+ int reg, err, val;
++ u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT,
++ BCM_LED_MULTICOLOR_LINK_ACT};
++ struct device_node *np = phydev->mdio.dev.of_node;
+
+ reg = phy_read(phydev, MII_BCM54XX_ECR);
+ if (reg < 0)
+@@ -345,6 +348,8 @@ static int bcm54xx_config_init(struct ph
+
+ bcm54xx_phydsp_config(phydev);
+
++ of_property_read_u32_array(np, "led-modes", led_modes, 2);
++
+ /* Encode link speed into LED1 and LED3 pair (green/amber).
+ * Also flash these two LEDs on activity. This means configuring
+ * them for MULTICOLOR and encoding link/activity into them.
+@@ -354,8 +359,8 @@ static int bcm54xx_config_init(struct ph
+ bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
+
+ val = BCM_LED_MULTICOLOR_IN_PHASE |
+- BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
+- BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
++ BCM5482_SHD_LEDS1_LED1(led_modes[0]) |
++ BCM5482_SHD_LEDS1_LED3(led_modes[1]);
+ bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
+
+ return 0;
+++ /dev/null
-From 633c64173636b2f6acebfddb3d2b69c92bbbcd07 Mon Sep 17 00:00:00 2001
-Date: Thu, 31 Oct 2019 13:37:16 +0000
-Subject: [PATCH] rpi-poe-fan: fix def_pwm1 writes
-
----
- drivers/hwmon/rpi-poe-fan.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/hwmon/rpi-poe-fan.c
-+++ b/drivers/hwmon/rpi-poe-fan.c
-@@ -110,7 +110,7 @@ static int __set_def_pwm(struct rpi_poe
- if (ctx->def_pwm_value == def_pwm)
- goto exit_set_def_pwm_err;
-
-- ret = write_reg(ctx->fw, POE_CUR_PWM, &def_pwm);
-+ ret = write_reg(ctx->fw, POE_DEF_PWM, &def_pwm);
- if (!ret)
- ctx->def_pwm_value = def_pwm;
- exit_set_def_pwm_err:
+++ /dev/null
-From b1e290ec968186530ec59479adfba89d2cfe21c8 Mon Sep 17 00:00:00 2001
-Date: Sun, 24 Mar 2019 00:18:46 +0200
-Subject: [PATCH] net: phy: bcm54xx: Encode link speed and activity
- into LEDs
-
-Previously the green and amber LEDs on this quad PHY were solid, to
-indicate an encoding of the link speed (10/100/1000).
-
-This keeps the LEDs always on just as before, but now they flash on
-Rx/Tx activity.
-
----
- drivers/net/phy/broadcom.c | 13 +++++++++++++
- include/linux/brcmphy.h | 16 ++++++++++++++++
- 2 files changed, 29 insertions(+)
-
---- a/drivers/net/phy/broadcom.c
-+++ b/drivers/net/phy/broadcom.c
-@@ -345,6 +345,19 @@ static int bcm54xx_config_init(struct ph
-
- bcm54xx_phydsp_config(phydev);
-
-+ /* Encode link speed into LED1 and LED3 pair (green/amber).
-+ * Also flash these two LEDs on activity. This means configuring
-+ * them for MULTICOLOR and encoding link/activity into them.
-+ */
-+ val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
-+ BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
-+ bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
-+
-+ val = BCM_LED_MULTICOLOR_IN_PHASE |
-+ BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
-+ BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
-+ bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
-+
- return 0;
- }
-
---- a/include/linux/brcmphy.h
-+++ b/include/linux/brcmphy.h
-@@ -148,6 +148,22 @@
- #define BCM_LED_SRC_OFF 0xe /* Tied high */
- #define BCM_LED_SRC_ON 0xf /* Tied low */
-
-+/*
-+ * Broadcom Multicolor LED configurations (expansion register 4)
-+ */
-+#define BCM_EXP_MULTICOLOR (MII_BCM54XX_EXP_SEL_ER + 0x04)
-+#define BCM_LED_MULTICOLOR_IN_PHASE BIT(8)
-+#define BCM_LED_MULTICOLOR_LINK_ACT 0x0
-+#define BCM_LED_MULTICOLOR_SPEED 0x1
-+#define BCM_LED_MULTICOLOR_ACT_FLASH 0x2
-+#define BCM_LED_MULTICOLOR_FDX 0x3
-+#define BCM_LED_MULTICOLOR_OFF 0x4
-+#define BCM_LED_MULTICOLOR_ON 0x5
-+#define BCM_LED_MULTICOLOR_ALT 0x6
-+#define BCM_LED_MULTICOLOR_FLASH 0x7
-+#define BCM_LED_MULTICOLOR_LINK 0x8
-+#define BCM_LED_MULTICOLOR_ACT 0x9
-+#define BCM_LED_MULTICOLOR_PROGRAM 0xa
-
- /*
- * BCM5482: Shadow registers
--- /dev/null
+From f12c4ba9fd01e17bd79b461b203674e92dd253e9 Mon Sep 17 00:00:00 2001
+Date: Wed, 6 Nov 2019 10:00:43 +0100
+Subject: [PATCH] overlays: smi: fix typo in comment (#3320)
+
+5 represent alt1 function not alt0.
+
+---
+ arch/arm/boot/dts/overlays/smi-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/smi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/smi-overlay.dts
+@@ -24,7 +24,7 @@
+ these are already used as ID_SD and ID_SC */
+ brcm,pins = <2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ 16 17 18 19 20 21 22 23 24 25>;
+- /* Alt 0: SMI */
++ /* Alt 1: SMI */
+ brcm,function = <5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5>;
+ /* /CS, /WE and /OE are pulled high, as they are
+++ /dev/null
-From 2679834327b5b8db8a7b0c90b632b81c35f9e271 Mon Sep 17 00:00:00 2001
-Date: Thu, 31 Oct 2019 14:39:44 +0000
-Subject: [PATCH] net:phy:2711 Allow ethernet LED mode to be set via
- device tree
-
-Add device tree entries and code to allow the specification of
-the lighting modes for the LED's on the ethernet connector.
-
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 3 +++
- arch/arm/boot/dts/bcm2838.dtsi | 1 +
- arch/arm/boot/dts/overlays/README | 28 +++++++++++++++++++--------
- drivers/net/phy/broadcom.c | 9 +++++++--
- 4 files changed, 31 insertions(+), 10 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -334,5 +334,8 @@
- pwr_led_gpio = <&pwr_led>,"gpios:4";
- pwr_led_activelow = <&pwr_led>,"gpios:8";
- pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
-+
-+ eth_led0 = <&phy1>,"led-modes:0";
-+ eth_led1 = <&phy1>,"led-modes:4";
- };
- };
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -380,6 +380,7 @@
- /* No interrupts - use PHY_POLL */
- max-speed = <1000>;
- reg = <0x1>;
-+ led-modes = <0x02 0x02>;
- };
- };
- };
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -102,26 +102,38 @@ Params:
-
- eee Enable Energy Efficient Ethernet support for
- compatible devices (default "on"). See also
-- "tx_lpi_timer".
-+ "tx_lpi_timer". Pi3B+ only.
-
- eth_downshift_after Set the number of auto-negotiation failures
- after which the 1000Mbps modes are disabled.
- Legal values are 2, 3, 4, 5 and 0, where
-- 0 means never downshift (default 2).
-+ 0 means never downshift (default 2). Pi3B+ only.
-
-- eth_led0 Set mode of LED0 (usually orange) (default
-- "1"). The legal values are:
-- 0=link/activity 1=link1000/activity
-+ eth_led0 Set mode of LED0 (usually orange). The legal
-+ values are:
-+
-+ Pi3B+
-+
-+ 0=link/activity 1=link1000/activity (default)
- 2=link100/activity 3=link10/activity
- 4=link100/1000/activity 5=link10/1000/activity
- 6=link10/100/activity 14=off 15=on
-
-- eth_led1 Set mode of LED1 (usually green) (default
-- "6"). See eth_led0 for legal values.
-+ Pi4
-+
-+ 0=Speed/Activity (default) 1=Speed
-+ 2=Speed/Flash activity 3=FDX
-+ 4=Off 5=On
-+ 6=Alt 7=Speed/Flash
-+ 8=Link 9=Activity
-+
-+ eth_led1 Set mode of LED1 (usually green) (Pi3B+ default
-+ "6", Pi4 default "0"). See eth_led0 for legal
-+ values.
-
- eth_max_speed Set the maximum speed a link is allowed
- to negotiate. Legal values are 10, 100 and
-- 1000 (default 1000).
-+ 1000 (default 1000). Pi3B+ only.
-
- i2c_arm Set to "on" to enable the ARM's i2c interface
- (default "off")
---- a/drivers/net/phy/broadcom.c
-+++ b/drivers/net/phy/broadcom.c
-@@ -292,6 +292,9 @@ static void bcm54xx_adjust_rxrefclk(stru
- static int bcm54xx_config_init(struct phy_device *phydev)
- {
- int reg, err, val;
-+ u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT,
-+ BCM_LED_MULTICOLOR_LINK_ACT};
-+ struct device_node *np = phydev->mdio.dev.of_node;
-
- reg = phy_read(phydev, MII_BCM54XX_ECR);
- if (reg < 0)
-@@ -345,6 +348,8 @@ static int bcm54xx_config_init(struct ph
-
- bcm54xx_phydsp_config(phydev);
-
-+ of_property_read_u32_array(np, "led-modes", led_modes, 2);
-+
- /* Encode link speed into LED1 and LED3 pair (green/amber).
- * Also flash these two LEDs on activity. This means configuring
- * them for MULTICOLOR and encoding link/activity into them.
-@@ -354,8 +359,8 @@ static int bcm54xx_config_init(struct ph
- bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
-
- val = BCM_LED_MULTICOLOR_IN_PHASE |
-- BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
-- BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
-+ BCM5482_SHD_LEDS1_LED1(led_modes[0]) |
-+ BCM5482_SHD_LEDS1_LED3(led_modes[1]);
- bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
-
- return 0;
--- /dev/null
+From 7d9c69b325c94d59de94cb699a8314ba2c83ab1d Mon Sep 17 00:00:00 2001
+Date: Thu, 7 Nov 2019 14:59:59 +0000
+Subject: [PATCH] net:phy:2711 Change the default ethernet LED actions
+
+This should return default behaviour back to that of previous
+releases.
+---
+ drivers/net/phy/broadcom.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+--- a/drivers/net/phy/broadcom.c
++++ b/drivers/net/phy/broadcom.c
+@@ -293,7 +293,7 @@ static int bcm54xx_config_init(struct ph
+ {
+ int reg, err, val;
+ u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT,
+- BCM_LED_MULTICOLOR_LINK_ACT};
++ BCM_LED_MULTICOLOR_LINK};
+ struct device_node *np = phydev->mdio.dev.of_node;
+
+ reg = phy_read(phydev, MII_BCM54XX_ECR);
+@@ -350,10 +350,6 @@ static int bcm54xx_config_init(struct ph
+
+ of_property_read_u32_array(np, "led-modes", led_modes, 2);
+
+- /* Encode link speed into LED1 and LED3 pair (green/amber).
+- * Also flash these two LEDs on activity. This means configuring
+- * them for MULTICOLOR and encoding link/activity into them.
+- */
+ val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
+ BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
+ bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
--- /dev/null
+From f5505e5d9fbfd11921c39cd55a433877d6d0d6e4 Mon Sep 17 00:00:00 2001
+Date: Thu, 7 Nov 2019 15:24:32 +0000
+Subject: [PATCH] overlays: README: Remove trailing whitespace
+
+A stray space slipped through the net.
+---
+ arch/arm/boot/dts/overlays/README | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -109,7 +109,7 @@ Params:
+ Legal values are 2, 3, 4, 5 and 0, where
+ 0 means never downshift (default 2). Pi3B+ only.
+
+- eth_led0 Set mode of LED0 (usually orange). The legal
++ eth_led0 Set mode of LED0 (usually orange). The legal
+ values are:
+
+ Pi3B+
+++ /dev/null
-From f12c4ba9fd01e17bd79b461b203674e92dd253e9 Mon Sep 17 00:00:00 2001
-Date: Wed, 6 Nov 2019 10:00:43 +0100
-Subject: [PATCH] overlays: smi: fix typo in comment (#3320)
-
-5 represent alt1 function not alt0.
-
----
- arch/arm/boot/dts/overlays/smi-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/smi-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/smi-overlay.dts
-@@ -24,7 +24,7 @@
- these are already used as ID_SD and ID_SC */
- brcm,pins = <2 3 4 5 6 7 8 9 10 11 12 13 14 15
- 16 17 18 19 20 21 22 23 24 25>;
-- /* Alt 0: SMI */
-+ /* Alt 1: SMI */
- brcm,function = <5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
- 5 5 5 5 5 5 5 5 5>;
- /* /CS, /WE and /OE are pulled high, as they are
+++ /dev/null
-From 7d9c69b325c94d59de94cb699a8314ba2c83ab1d Mon Sep 17 00:00:00 2001
-Date: Thu, 7 Nov 2019 14:59:59 +0000
-Subject: [PATCH] net:phy:2711 Change the default ethernet LED actions
-
-This should return default behaviour back to that of previous
-releases.
----
- drivers/net/phy/broadcom.c | 6 +-----
- 1 file changed, 1 insertion(+), 5 deletions(-)
-
---- a/drivers/net/phy/broadcom.c
-+++ b/drivers/net/phy/broadcom.c
-@@ -293,7 +293,7 @@ static int bcm54xx_config_init(struct ph
- {
- int reg, err, val;
- u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT,
-- BCM_LED_MULTICOLOR_LINK_ACT};
-+ BCM_LED_MULTICOLOR_LINK};
- struct device_node *np = phydev->mdio.dev.of_node;
-
- reg = phy_read(phydev, MII_BCM54XX_ECR);
-@@ -350,10 +350,6 @@ static int bcm54xx_config_init(struct ph
-
- of_property_read_u32_array(np, "led-modes", led_modes, 2);
-
-- /* Encode link speed into LED1 and LED3 pair (green/amber).
-- * Also flash these two LEDs on activity. This means configuring
-- * them for MULTICOLOR and encoding link/activity into them.
-- */
- val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
- BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
- bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
--- /dev/null
+From c1e8593fd7fc6a8e7745a6c82c1c19a8fceee70f Mon Sep 17 00:00:00 2001
+Date: Fri, 8 Nov 2019 10:35:57 +0100
+Subject: [PATCH] overlays: Add apds9960 overlay
+
+Add an overlay for the AVAGO APDS9960 digital proximity, ambient light, rgb and gesture sensor.
+Also update overlay README and Makefile.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 8 +++
+ .../boot/dts/overlays/apds9960-overlay.dts | 57 +++++++++++++++++++
+ 3 files changed, 66 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/apds9960-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -15,6 +15,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ allo-katana-dac-audio.dtbo \
+ allo-piano-dac-pcm512x-audio.dtbo \
+ allo-piano-dac-plus-pcm512x-audio.dtbo \
++ apds9960.dtbo \
+ applepi-dac.dtbo \
+ at86rf233.dtbo \
+ audioinjector-addons.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -441,6 +441,14 @@ Params: 24db_digital_gain Allow ga
+ better voice quality. (default Off)
+
+
++Name: apds9960
++Info: Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and
++ gesture sensor
++Load: dtoverlay=apds9960,<param>=<val>
++Params: gpiopin GPIO used for INT (default 4)
++ noints Disable the interrupt GPIO line.
++
++
+ Name: applepi-dac
+ Info: Configures the Orchard Audio ApplePi-DAC audio card
+ Load: dtoverlay=applepi-dac
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/apds9960-overlay.dts
+@@ -0,0 +1,57 @@
++// Definitions for APDS-9960 ambient light and gesture sensor
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&i2c1>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ apds9960_pins: apds9960_pins@39 {
++ brcm,pins = <4>;
++ brcm,function = <0>;
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ apds9960: apds@39 {
++ compatible = "avago,apds9960";
++ reg = <0x39>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&i2c1>;
++ __overlay__ {
++ apds9960_irq: apds@39 {
++ #interrupt-cells=<2>;
++ interrupt-parent = <&gpio>;
++ interrupts = <4 1>;
++ };
++ };
++ };
++
++ __overrides__ {
++ gpiopin = <&apds9960_pins>,"brcm,pins:0",
++ <&apds9960_irq>,"interrupts:0";
++ noints = <0>,"!1!3";
++ };
++};
++
--- /dev/null
+From 49a4a7e355452ce4372c99b2219d7ff8ff613f3f Mon Sep 17 00:00:00 2001
+Date: Sun, 17 Nov 2019 16:20:24 +0000
+Subject: [PATCH] arm: dts: overlays: pitft35-resistive: add upstream
+ compatible
+
+The upstream hx8357d driver uses "adafruit,yx350hv15" for the compatible
+string explicitly for this screen config and not a hx8357d generic for
+the controller so add that in as well so it will work with an unmodified
+upstream kernel driver. We leave the downstream as the priority.
+
+---
+ arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
+@@ -49,7 +49,7 @@
+ #size-cells = <0>;
+
+ pitft: pitft@0{
+- compatible = "himax,hx8357d";
++ compatible = "himax,hx8357d", "adafruit,yx350hv15";
+ reg = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pitft_pins>;
+++ /dev/null
-From f5505e5d9fbfd11921c39cd55a433877d6d0d6e4 Mon Sep 17 00:00:00 2001
-Date: Thu, 7 Nov 2019 15:24:32 +0000
-Subject: [PATCH] overlays: README: Remove trailing whitespace
-
-A stray space slipped through the net.
----
- arch/arm/boot/dts/overlays/README | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -109,7 +109,7 @@ Params:
- Legal values are 2, 3, 4, 5 and 0, where
- 0 means never downshift (default 2). Pi3B+ only.
-
-- eth_led0 Set mode of LED0 (usually orange). The legal
-+ eth_led0 Set mode of LED0 (usually orange). The legal
- values are:
-
- Pi3B+
--- /dev/null
+From 5b8a217fe818bc038592b8a5284ba0c18948fabf Mon Sep 17 00:00:00 2001
+Date: Tue, 6 Aug 2019 15:23:14 +0100
+Subject: [PATCH] clk-bcm2835: Avoid null pointer exception
+
+clk_desc_array[BCM2835_PLLB] doesn't exist so we dereference null when iterating
+
+---
+ drivers/clk/bcm/clk-bcm2835.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -2288,9 +2288,11 @@ static bool bcm2835_clk_is_claimed(const
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) {
+- const char *clk_name = *(const char **)(clk_desc_array[i].data);
+- if (!strcmp(name, clk_name))
+- return bcm2835_clk_claimed[i];
++ if (clk_desc_array[i].data) {
++ const char *clk_name = *(const char **)(clk_desc_array[i].data);
++ if (!strcmp(name, clk_name))
++ return bcm2835_clk_claimed[i];
++ }
+ }
+
+ return false;
+++ /dev/null
-From c1e8593fd7fc6a8e7745a6c82c1c19a8fceee70f Mon Sep 17 00:00:00 2001
-Date: Fri, 8 Nov 2019 10:35:57 +0100
-Subject: [PATCH] overlays: Add apds9960 overlay
-
-Add an overlay for the AVAGO APDS9960 digital proximity, ambient light, rgb and gesture sensor.
-Also update overlay README and Makefile.
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 8 +++
- .../boot/dts/overlays/apds9960-overlay.dts | 57 +++++++++++++++++++
- 3 files changed, 66 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/apds9960-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -15,6 +15,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- allo-katana-dac-audio.dtbo \
- allo-piano-dac-pcm512x-audio.dtbo \
- allo-piano-dac-plus-pcm512x-audio.dtbo \
-+ apds9960.dtbo \
- applepi-dac.dtbo \
- at86rf233.dtbo \
- audioinjector-addons.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -441,6 +441,14 @@ Params: 24db_digital_gain Allow ga
- better voice quality. (default Off)
-
-
-+Name: apds9960
-+Info: Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and
-+ gesture sensor
-+Load: dtoverlay=apds9960,<param>=<val>
-+Params: gpiopin GPIO used for INT (default 4)
-+ noints Disable the interrupt GPIO line.
-+
-+
- Name: applepi-dac
- Info: Configures the Orchard Audio ApplePi-DAC audio card
- Load: dtoverlay=applepi-dac
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/apds9960-overlay.dts
-@@ -0,0 +1,57 @@
-+// Definitions for APDS-9960 ambient light and gesture sensor
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ apds9960_pins: apds9960_pins@39 {
-+ brcm,pins = <4>;
-+ brcm,function = <0>;
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ apds9960: apds@39 {
-+ compatible = "avago,apds9960";
-+ reg = <0x39>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ apds9960_irq: apds@39 {
-+ #interrupt-cells=<2>;
-+ interrupt-parent = <&gpio>;
-+ interrupts = <4 1>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ gpiopin = <&apds9960_pins>,"brcm,pins:0",
-+ <&apds9960_irq>,"interrupts:0";
-+ noints = <0>,"!1!3";
-+ };
-+};
-+
+++ /dev/null
-From 49a4a7e355452ce4372c99b2219d7ff8ff613f3f Mon Sep 17 00:00:00 2001
-Date: Sun, 17 Nov 2019 16:20:24 +0000
-Subject: [PATCH] arm: dts: overlays: pitft35-resistive: add upstream
- compatible
-
-The upstream hx8357d driver uses "adafruit,yx350hv15" for the compatible
-string explicitly for this screen config and not a hx8357d generic for
-the controller so add that in as well so it will work with an unmodified
-upstream kernel driver. We leave the downstream as the priority.
-
----
- arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
-@@ -49,7 +49,7 @@
- #size-cells = <0>;
-
- pitft: pitft@0{
-- compatible = "himax,hx8357d";
-+ compatible = "himax,hx8357d", "adafruit,yx350hv15";
- reg = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pitft_pins>;
--- /dev/null
+From 9048bbff0eca6d74d41fa58875f31560381b3ca3 Mon Sep 17 00:00:00 2001
+Date: Fri, 23 Aug 2019 16:34:38 +0100
+Subject: [PATCH] v3d_drv: Handle missing clock more gracefully
+
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -301,9 +301,9 @@ static int v3d_platform_drm_probe(struct
+ }
+
+ v3d->clk = devm_clk_get(dev, NULL);
+- if (IS_ERR(v3d->clk)) {
+- if (ret != -EPROBE_DEFER)
+- dev_err(dev, "Failed to get clock\n");
++ if (IS_ERR_OR_NULL(v3d->clk)) {
++ if (PTR_ERR(v3d->clk) != -EPROBE_DEFER)
++ dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk));
+ goto dev_free;
+ }
+ v3d->clk_up_rate = clk_get_rate(v3d->clk);
+++ /dev/null
-From 5b8a217fe818bc038592b8a5284ba0c18948fabf Mon Sep 17 00:00:00 2001
-Date: Tue, 6 Aug 2019 15:23:14 +0100
-Subject: [PATCH] clk-bcm2835: Avoid null pointer exception
-
-clk_desc_array[BCM2835_PLLB] doesn't exist so we dereference null when iterating
-
----
- drivers/clk/bcm/clk-bcm2835.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -2288,9 +2288,11 @@ static bool bcm2835_clk_is_claimed(const
- int i;
-
- for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) {
-- const char *clk_name = *(const char **)(clk_desc_array[i].data);
-- if (!strcmp(name, clk_name))
-- return bcm2835_clk_claimed[i];
-+ if (clk_desc_array[i].data) {
-+ const char *clk_name = *(const char **)(clk_desc_array[i].data);
-+ if (!strcmp(name, clk_name))
-+ return bcm2835_clk_claimed[i];
-+ }
- }
-
- return false;
--- /dev/null
+From 84a8cbf64731568c0750137ec38091a46b81d502 Mon Sep 17 00:00:00 2001
+Date: Fri, 4 Jan 2019 15:14:33 +0530
+Subject: [PATCH] cpufreq: scpi/scmi: Fix freeing of dynamic OPPs
+
+Commit 1690d8bb91e370ab772062b79bd434ce815c4729 upstream
+
+Since the commit 2a4eb7358aba "OPP: Don't remove dynamic OPPs from
+_dev_pm_opp_remove_table()", dynamically created OPP aren't
+automatically removed anymore by dev_pm_opp_cpumask_remove_table(). This
+affects the scpi and scmi cpufreq drivers which no longer free OPPs on
+failures or on invocations of the policy->exit() callback.
+
+Create a generic OPP helper dev_pm_opp_remove_all_dynamic() which can be
+called from these drivers instead of dev_pm_opp_cpumask_remove_table().
+
+In dev_pm_opp_remove_all_dynamic(), we need to make sure that the
+opp_list isn't getting accessed simultaneously from other parts of the
+OPP core while the helper is freeing dynamic OPPs, i.e. we can't drop
+the opp_table->lock while traversing through the OPP list. And to
+accomplish that, this patch also creates _opp_kref_release_unlocked()
+which can be called from this new helper with the opp_table lock already
+held.
+
+Fixes: 2a4eb7358aba "OPP: Don't remove dynamic OPPs from _dev_pm_opp_remove_table()"
+---
+ drivers/cpufreq/scmi-cpufreq.c | 4 +--
+ drivers/cpufreq/scpi-cpufreq.c | 4 +--
+ drivers/opp/core.c | 63 +++++++++++++++++++++++++++++++---
+ include/linux/pm_opp.h | 5 +++
+ 4 files changed, 67 insertions(+), 9 deletions(-)
+
+--- a/drivers/cpufreq/scmi-cpufreq.c
++++ b/drivers/cpufreq/scmi-cpufreq.c
+@@ -176,7 +176,7 @@ static int scmi_cpufreq_init(struct cpuf
+ out_free_priv:
+ kfree(priv);
+ out_free_opp:
+- dev_pm_opp_cpumask_remove_table(policy->cpus);
++ dev_pm_opp_remove_all_dynamic(cpu_dev);
+
+ return ret;
+ }
+@@ -188,7 +188,7 @@ static int scmi_cpufreq_exit(struct cpuf
+ cpufreq_cooling_unregister(priv->cdev);
+ dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
+ kfree(priv);
+- dev_pm_opp_cpumask_remove_table(policy->related_cpus);
++ dev_pm_opp_remove_all_dynamic(priv->cpu_dev);
+
+ return 0;
+ }
+--- a/drivers/cpufreq/scpi-cpufreq.c
++++ b/drivers/cpufreq/scpi-cpufreq.c
+@@ -177,7 +177,7 @@ out_free_cpufreq_table:
+ out_free_priv:
+ kfree(priv);
+ out_free_opp:
+- dev_pm_opp_cpumask_remove_table(policy->cpus);
++ dev_pm_opp_remove_all_dynamic(cpu_dev);
+
+ return ret;
+ }
+@@ -190,7 +190,7 @@ static int scpi_cpufreq_exit(struct cpuf
+ clk_put(priv->clk);
+ dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
+ kfree(priv);
+- dev_pm_opp_cpumask_remove_table(policy->related_cpus);
++ dev_pm_opp_remove_all_dynamic(priv->cpu_dev);
+
+ return 0;
+ }
+--- a/drivers/opp/core.c
++++ b/drivers/opp/core.c
+@@ -884,11 +884,9 @@ void _opp_free(struct dev_pm_opp *opp)
+ kfree(opp);
+ }
+
+-static void _opp_kref_release(struct kref *kref)
++static void _opp_kref_release(struct dev_pm_opp *opp,
++ struct opp_table *opp_table)
+ {
+- struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
+- struct opp_table *opp_table = opp->opp_table;
+-
+ /*
+ * Notify the changes in the availability of the operable
+ * frequency/voltage list.
+@@ -897,7 +895,22 @@ static void _opp_kref_release(struct kre
+ opp_debug_remove_one(opp);
+ list_del(&opp->node);
+ kfree(opp);
++}
++
++static void _opp_kref_release_unlocked(struct kref *kref)
++{
++ struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
++ struct opp_table *opp_table = opp->opp_table;
++
++ _opp_kref_release(opp, opp_table);
++}
+
++static void _opp_kref_release_locked(struct kref *kref)
++{
++ struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
++ struct opp_table *opp_table = opp->opp_table;
++
++ _opp_kref_release(opp, opp_table);
+ mutex_unlock(&opp_table->lock);
+ dev_pm_opp_put_opp_table(opp_table);
+ }
+@@ -909,10 +922,16 @@ void dev_pm_opp_get(struct dev_pm_opp *o
+
+ void dev_pm_opp_put(struct dev_pm_opp *opp)
+ {
+- kref_put_mutex(&opp->kref, _opp_kref_release, &opp->opp_table->lock);
++ kref_put_mutex(&opp->kref, _opp_kref_release_locked,
++ &opp->opp_table->lock);
+ }
+ EXPORT_SYMBOL_GPL(dev_pm_opp_put);
+
++static void dev_pm_opp_put_unlocked(struct dev_pm_opp *opp)
++{
++ kref_put(&opp->kref, _opp_kref_release_unlocked);
++}
++
+ /**
+ * dev_pm_opp_remove() - Remove an OPP from OPP table
+ * @dev: device for which we do this operation
+@@ -952,6 +971,40 @@ void dev_pm_opp_remove(struct device *de
+ }
+ EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
+
++/**
++ * dev_pm_opp_remove_all_dynamic() - Remove all dynamically created OPPs
++ * @dev: device for which we do this operation
++ *
++ * This function removes all dynamically created OPPs from the opp table.
++ */
++void dev_pm_opp_remove_all_dynamic(struct device *dev)
++{
++ struct opp_table *opp_table;
++ struct dev_pm_opp *opp, *temp;
++ int count = 0;
++
++ opp_table = _find_opp_table(dev);
++ if (IS_ERR(opp_table))
++ return;
++
++ mutex_lock(&opp_table->lock);
++ list_for_each_entry_safe(opp, temp, &opp_table->opp_list, node) {
++ if (opp->dynamic) {
++ dev_pm_opp_put_unlocked(opp);
++ count++;
++ }
++ }
++ mutex_unlock(&opp_table->lock);
++
++ /* Drop the references taken by dev_pm_opp_add() */
++ while (count--)
++ dev_pm_opp_put_opp_table(opp_table);
++
++ /* Drop the reference taken by _find_opp_table() */
++ dev_pm_opp_put_opp_table(opp_table);
++}
++EXPORT_SYMBOL_GPL(dev_pm_opp_remove_all_dynamic);
++
+ struct dev_pm_opp *_opp_allocate(struct opp_table *table)
+ {
+ struct dev_pm_opp *opp;
+--- a/include/linux/pm_opp.h
++++ b/include/linux/pm_opp.h
+@@ -107,6 +107,7 @@ void dev_pm_opp_put(struct dev_pm_opp *o
+ int dev_pm_opp_add(struct device *dev, unsigned long freq,
+ unsigned long u_volt);
+ void dev_pm_opp_remove(struct device *dev, unsigned long freq);
++void dev_pm_opp_remove_all_dynamic(struct device *dev);
+
+ int dev_pm_opp_enable(struct device *dev, unsigned long freq);
+
+@@ -208,6 +209,10 @@ static inline void dev_pm_opp_remove(str
+ {
+ }
+
++static inline void dev_pm_opp_remove_all_dynamic(struct device *dev)
++{
++}
++
+ static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq)
+ {
+ return 0;
--- /dev/null
+From 35306211392a8c17ba6cde2a6b5d1beb61ca7d54 Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Jun 2019 20:24:54 +0200
+Subject: [PATCH] clk: bcm283x: add driver interfacing with Raspberry
+ Pi's firmware
+
+Commit 4e85e535e6cc6e8a96350e8ee684d0f22eb8629e upstream.
+
+Raspberry Pi's firmware offers an interface though which update it's
+clock's frequencies. This is specially useful in order to change the CPU
+clock (pllb_arm) which is 'owned' by the firmware and we're unable to
+scale using the register interface provided by clk-bcm2835.
+
+---
+ drivers/clk/bcm/Kconfig | 7 +
+ drivers/clk/bcm/Makefile | 1 +
+ drivers/clk/bcm/clk-raspberrypi.c | 300 ++++++++++++++++++++++++++++++
+ 3 files changed, 308 insertions(+)
+ create mode 100644 drivers/clk/bcm/clk-raspberrypi.c
+
+--- a/drivers/clk/bcm/Kconfig
++++ b/drivers/clk/bcm/Kconfig
+@@ -63,3 +63,10 @@ config CLK_BCM_SR
+ default ARCH_BCM_IPROC
+ help
+ Enable common clock framework support for the Broadcom Stingray SoC
++
++config CLK_RASPBERRYPI
++ tristate "Raspberry Pi firmware based clock support"
++ depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
++ help
++ Enable common clock framework support for Raspberry Pi's firmware
++ dependent clocks
+--- a/drivers/clk/bcm/Makefile
++++ b/drivers/clk/bcm/Makefile
+@@ -7,6 +7,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm216
+ obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
+ obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
+ obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o
++obj-$(CONFIG_CLK_RASPBERRYPI) += clk-raspberrypi.o
+ obj-$(CONFIG_ARCH_BCM_53573) += clk-bcm53573-ilp.o
+ obj-$(CONFIG_CLK_BCM_CYGNUS) += clk-cygnus.o
+ obj-$(CONFIG_CLK_BCM_HR2) += clk-hr2.o
+--- /dev/null
++++ b/drivers/clk/bcm/clk-raspberrypi.c
+@@ -0,0 +1,300 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Raspberry Pi driver for firmware controlled clocks
++ *
++ * Even though clk-bcm2835 provides an interface to the hardware registers for
++ * the system clocks we've had to factor out 'pllb' as the firmware 'owns' it.
++ * We're not allowed to change it directly as we might race with the
++ * over-temperature and under-voltage protections provided by the firmware.
++ *
++ */
++
++#include <linux/clkdev.h>
++#include <linux/clk-provider.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <soc/bcm2835/raspberrypi-firmware.h>
++
++#define RPI_FIRMWARE_ARM_CLK_ID 0x00000003
++
++#define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0)
++#define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1)
++
++/*
++ * Even though the firmware interface alters 'pllb' the frequencies are
++ * provided as per 'pllb_arm'. We need to scale before passing them trough.
++ */
++#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE 2
++
++#define A2W_PLL_FRAC_BITS 20
++
++struct raspberrypi_clk {
++ struct device *dev;
++ struct rpi_firmware *firmware;
++
++ unsigned long min_rate;
++ unsigned long max_rate;
++
++ struct clk_hw pllb;
++ struct clk_hw *pllb_arm;
++ struct clk_lookup *pllb_arm_lookup;
++};
++
++/*
++ * Structure of the message passed to Raspberry Pi's firmware in order to
++ * change clock rates. The 'disable_turbo' option is only available to the ARM
++ * clock (pllb) which we enable by default as turbo mode will alter multiple
++ * clocks at once.
++ *
++ * Even though we're able to access the clock registers directly we're bound to
++ * use the firmware interface as the firmware ultimately takes care of
++ * mitigating overheating/undervoltage situations and we would be changing
++ * frequencies behind his back.
++ *
++ * For more information on the firmware interface check:
++ * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
++ */
++struct raspberrypi_firmware_prop {
++ __le32 id;
++ __le32 val;
++ __le32 disable_turbo;
++} __packed;
++
++static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag,
++ u32 clk, u32 *val)
++{
++ struct raspberrypi_firmware_prop msg = {
++ .id = cpu_to_le32(clk),
++ .val = cpu_to_le32(*val),
++ .disable_turbo = cpu_to_le32(1),
++ };
++ int ret;
++
++ ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg));
++ if (ret)
++ return ret;
++
++ *val = le32_to_cpu(msg.val);
++
++ return 0;
++}
++
++static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
++{
++ struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
++ pllb);
++ u32 val = 0;
++ int ret;
++
++ ret = raspberrypi_clock_property(rpi->firmware,
++ RPI_FIRMWARE_GET_CLOCK_STATE,
++ RPI_FIRMWARE_ARM_CLK_ID, &val);
++ if (ret)
++ return 0;
++
++ return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT);
++}
++
++
++static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
++ pllb);
++ u32 val = 0;
++ int ret;
++
++ ret = raspberrypi_clock_property(rpi->firmware,
++ RPI_FIRMWARE_GET_CLOCK_RATE,
++ RPI_FIRMWARE_ARM_CLK_ID,
++ &val);
++ if (ret)
++ return ret;
++
++ return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
++}
++
++static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
++ pllb);
++ u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
++ int ret;
++
++ ret = raspberrypi_clock_property(rpi->firmware,
++ RPI_FIRMWARE_SET_CLOCK_RATE,
++ RPI_FIRMWARE_ARM_CLK_ID,
++ &new_rate);
++ if (ret)
++ dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
++ clk_hw_get_name(hw), ret);
++
++ return ret;
++}
++
++/*
++ * Sadly there is no firmware rate rounding interface. We borrowed it from
++ * clk-bcm2835.
++ */
++static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
++ struct clk_rate_request *req)
++{
++ struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
++ pllb);
++ u64 div, final_rate;
++ u32 ndiv, fdiv;
++
++ /* We can't use req->rate directly as it would overflow */
++ final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate);
++
++ div = (u64)final_rate << A2W_PLL_FRAC_BITS;
++ do_div(div, req->best_parent_rate);
++
++ ndiv = div >> A2W_PLL_FRAC_BITS;
++ fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1);
++
++ final_rate = ((u64)req->best_parent_rate *
++ ((ndiv << A2W_PLL_FRAC_BITS) + fdiv));
++
++ req->rate = final_rate >> A2W_PLL_FRAC_BITS;
++
++ return 0;
++}
++
++static const struct clk_ops raspberrypi_firmware_pll_clk_ops = {
++ .is_prepared = raspberrypi_fw_pll_is_on,
++ .recalc_rate = raspberrypi_fw_pll_get_rate,
++ .set_rate = raspberrypi_fw_pll_set_rate,
++ .determine_rate = raspberrypi_pll_determine_rate,
++};
++
++static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi)
++{
++ u32 min_rate = 0, max_rate = 0;
++ struct clk_init_data init;
++ int ret;
++
++ memset(&init, 0, sizeof(init));
++
++ /* All of the PLLs derive from the external oscillator. */
++ init.parent_names = (const char *[]){ "osc" };
++ init.num_parents = 1;
++ init.name = "pllb";
++ init.ops = &raspberrypi_firmware_pll_clk_ops;
++ init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
++
++ /* Get min & max rates set by the firmware */
++ ret = raspberrypi_clock_property(rpi->firmware,
++ RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
++ RPI_FIRMWARE_ARM_CLK_ID,
++ &min_rate);
++ if (ret) {
++ dev_err(rpi->dev, "Failed to get %s min freq: %d\n",
++ init.name, ret);
++ return ret;
++ }
++
++ ret = raspberrypi_clock_property(rpi->firmware,
++ RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
++ RPI_FIRMWARE_ARM_CLK_ID,
++ &max_rate);
++ if (ret) {
++ dev_err(rpi->dev, "Failed to get %s max freq: %d\n",
++ init.name, ret);
++ return ret;
++ }
++
++ if (!min_rate || !max_rate) {
++ dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n",
++ min_rate, max_rate);
++ return -EINVAL;
++ }
++
++ dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n",
++ min_rate, max_rate);
++
++ rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
++ rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
++
++ rpi->pllb.init = &init;
++
++ return devm_clk_hw_register(rpi->dev, &rpi->pllb);
++}
++
++static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi)
++{
++ rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev,
++ "pllb_arm", "pllb",
++ CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
++ 1, 2);
++ if (IS_ERR(rpi->pllb_arm)) {
++ dev_err(rpi->dev, "Failed to initialize pllb_arm\n");
++ return PTR_ERR(rpi->pllb_arm);
++ }
++
++ rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0");
++ if (!rpi->pllb_arm_lookup) {
++ dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n");
++ clk_hw_unregister_fixed_factor(rpi->pllb_arm);
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++static int raspberrypi_clk_probe(struct platform_device *pdev)
++{
++ struct device_node *firmware_node;
++ struct device *dev = &pdev->dev;
++ struct rpi_firmware *firmware;
++ struct raspberrypi_clk *rpi;
++ int ret;
++
++ firmware_node = of_find_compatible_node(NULL, NULL,
++ "raspberrypi,bcm2835-firmware");
++ if (!firmware_node) {
++ dev_err(dev, "Missing firmware node\n");
++ return -ENOENT;
++ }
++
++ firmware = rpi_firmware_get(firmware_node);
++ of_node_put(firmware_node);
++ if (!firmware)
++ return -EPROBE_DEFER;
++
++ rpi = devm_kzalloc(dev, sizeof(*rpi), GFP_KERNEL);
++ if (!rpi)
++ return -ENOMEM;
++
++ rpi->dev = dev;
++ rpi->firmware = firmware;
++
++ ret = raspberrypi_register_pllb(rpi);
++ if (ret) {
++ dev_err(dev, "Failed to initialize pllb, %d\n", ret);
++ return ret;
++ }
++
++ ret = raspberrypi_register_pllb_arm(rpi);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static struct platform_driver raspberrypi_clk_driver = {
++ .driver = {
++ .name = "raspberrypi-clk",
++ },
++ .probe = raspberrypi_clk_probe,
++};
++module_platform_driver(raspberrypi_clk_driver);
++
++MODULE_DESCRIPTION("Raspberry Pi firmware clock driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:raspberrypi-clk");
+++ /dev/null
-From 9048bbff0eca6d74d41fa58875f31560381b3ca3 Mon Sep 17 00:00:00 2001
-Date: Fri, 23 Aug 2019 16:34:38 +0100
-Subject: [PATCH] v3d_drv: Handle missing clock more gracefully
-
----
- drivers/gpu/drm/v3d/v3d_drv.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -301,9 +301,9 @@ static int v3d_platform_drm_probe(struct
- }
-
- v3d->clk = devm_clk_get(dev, NULL);
-- if (IS_ERR(v3d->clk)) {
-- if (ret != -EPROBE_DEFER)
-- dev_err(dev, "Failed to get clock\n");
-+ if (IS_ERR_OR_NULL(v3d->clk)) {
-+ if (PTR_ERR(v3d->clk) != -EPROBE_DEFER)
-+ dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk));
- goto dev_free;
- }
- v3d->clk_up_rate = clk_get_rate(v3d->clk);
--- /dev/null
+From 1c0d3626312369837bc18051ed6c9611323fce87 Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Jun 2019 20:24:56 +0200
+Subject: [PATCH] cpufreq: add driver for Raspberry Pi
+
+Commit d3df18a97e586702920337056540267807b23f8e upstream.
+
+Raspberry Pi's firmware offers and interface though which update it's
+performance requirements. It allows us to request for specific runtime
+frequencies, which the firmware might or might not respect, depending on
+the firmware configuration and thermals.
+
+As the maximum and minimum frequencies are configurable in the firmware
+there is no way to know in advance their values. So the Raspberry Pi
+cpufreq driver queries them, builds an opp frequency table to then
+launch cpufreq-dt.
+
+Also, as the firmware interface might be configured as a module, making
+the cpu clock unavailable during init, this implements a full fledged
+driver, as opposed to most drivers registering cpufreq-dt, which only
+make use of an init routine.
+
+---
+ drivers/cpufreq/Kconfig.arm | 8 +++
+ drivers/cpufreq/Makefile | 1 +
+ drivers/cpufreq/raspberrypi-cpufreq.c | 97 +++++++++++++++++++++++++++
+ 3 files changed, 106 insertions(+)
+ create mode 100644 drivers/cpufreq/raspberrypi-cpufreq.c
+
+--- a/drivers/cpufreq/Kconfig.arm
++++ b/drivers/cpufreq/Kconfig.arm
+@@ -121,6 +121,14 @@ config ARM_QCOM_CPUFREQ_KRYO
+
+ If in doubt, say N.
+
++config ARM_RASPBERRYPI_CPUFREQ
++ tristate "Raspberry Pi cpufreq support"
++ depends on CLK_RASPBERRYPI || COMPILE_TEST
++ help
++ This adds the CPUFreq driver for Raspberry Pi
++
++ If in doubt, say N.
++
+ config ARM_S3C_CPUFREQ
+ bool
+ help
+--- a/drivers/cpufreq/Makefile
++++ b/drivers/cpufreq/Makefile
+@@ -65,6 +65,7 @@ obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += o
+ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
+ obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
+ obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o
++obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o
+ obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
+ obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
+ obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
+--- /dev/null
++++ b/drivers/cpufreq/raspberrypi-cpufreq.c
+@@ -0,0 +1,97 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Raspberry Pi cpufreq driver
++ *
++ */
++
++#include <linux/clk.h>
++#include <linux/cpu.h>
++#include <linux/cpufreq.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/pm_opp.h>
++
++#define RASPBERRYPI_FREQ_INTERVAL 100000000
++
++static struct platform_device *cpufreq_dt;
++
++static int raspberrypi_cpufreq_probe(struct platform_device *pdev)
++{
++ struct device *cpu_dev;
++ unsigned long min, max;
++ unsigned long rate;
++ struct clk *clk;
++ int ret;
++
++ cpu_dev = get_cpu_device(0);
++ if (!cpu_dev) {
++ pr_err("Cannot get CPU for cpufreq driver\n");
++ return -ENODEV;
++ }
++
++ clk = clk_get(cpu_dev, NULL);
++ if (IS_ERR(clk)) {
++ dev_err(cpu_dev, "Cannot get clock for CPU0\n");
++ return PTR_ERR(clk);
++ }
++
++ /*
++ * The max and min frequencies are configurable in the Raspberry Pi
++ * firmware, so we query them at runtime.
++ */
++ min = roundup(clk_round_rate(clk, 0), RASPBERRYPI_FREQ_INTERVAL);
++ max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL);
++ clk_put(clk);
++
++ for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) {
++ ret = dev_pm_opp_add(cpu_dev, rate, 0);
++ if (ret)
++ goto remove_opp;
++ }
++
++ cpufreq_dt = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
++ ret = PTR_ERR_OR_ZERO(cpufreq_dt);
++ if (ret) {
++ dev_err(cpu_dev, "Failed to create platform device, %d\n", ret);
++ goto remove_opp;
++ }
++
++ return 0;
++
++remove_opp:
++ dev_pm_opp_remove_all_dynamic(cpu_dev);
++
++ return ret;
++}
++
++static int raspberrypi_cpufreq_remove(struct platform_device *pdev)
++{
++ struct device *cpu_dev;
++
++ cpu_dev = get_cpu_device(0);
++ if (cpu_dev)
++ dev_pm_opp_remove_all_dynamic(cpu_dev);
++
++ platform_device_unregister(cpufreq_dt);
++
++ return 0;
++}
++
++/*
++ * Since the driver depends on clk-raspberrypi, which may return EPROBE_DEFER,
++ * all the activity is performed in the probe, which may be defered as well.
++ */
++static struct platform_driver raspberrypi_cpufreq_driver = {
++ .driver = {
++ .name = "raspberrypi-cpufreq",
++ },
++ .probe = raspberrypi_cpufreq_probe,
++ .remove = raspberrypi_cpufreq_remove,
++};
++module_platform_driver(raspberrypi_cpufreq_driver);
++
++MODULE_DESCRIPTION("Raspberry Pi cpufreq driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:raspberrypi-cpufreq");
+++ /dev/null
-From 84a8cbf64731568c0750137ec38091a46b81d502 Mon Sep 17 00:00:00 2001
-Date: Fri, 4 Jan 2019 15:14:33 +0530
-Subject: [PATCH] cpufreq: scpi/scmi: Fix freeing of dynamic OPPs
-
-Commit 1690d8bb91e370ab772062b79bd434ce815c4729 upstream
-
-Since the commit 2a4eb7358aba "OPP: Don't remove dynamic OPPs from
-_dev_pm_opp_remove_table()", dynamically created OPP aren't
-automatically removed anymore by dev_pm_opp_cpumask_remove_table(). This
-affects the scpi and scmi cpufreq drivers which no longer free OPPs on
-failures or on invocations of the policy->exit() callback.
-
-Create a generic OPP helper dev_pm_opp_remove_all_dynamic() which can be
-called from these drivers instead of dev_pm_opp_cpumask_remove_table().
-
-In dev_pm_opp_remove_all_dynamic(), we need to make sure that the
-opp_list isn't getting accessed simultaneously from other parts of the
-OPP core while the helper is freeing dynamic OPPs, i.e. we can't drop
-the opp_table->lock while traversing through the OPP list. And to
-accomplish that, this patch also creates _opp_kref_release_unlocked()
-which can be called from this new helper with the opp_table lock already
-held.
-
-Fixes: 2a4eb7358aba "OPP: Don't remove dynamic OPPs from _dev_pm_opp_remove_table()"
----
- drivers/cpufreq/scmi-cpufreq.c | 4 +--
- drivers/cpufreq/scpi-cpufreq.c | 4 +--
- drivers/opp/core.c | 63 +++++++++++++++++++++++++++++++---
- include/linux/pm_opp.h | 5 +++
- 4 files changed, 67 insertions(+), 9 deletions(-)
-
---- a/drivers/cpufreq/scmi-cpufreq.c
-+++ b/drivers/cpufreq/scmi-cpufreq.c
-@@ -176,7 +176,7 @@ static int scmi_cpufreq_init(struct cpuf
- out_free_priv:
- kfree(priv);
- out_free_opp:
-- dev_pm_opp_cpumask_remove_table(policy->cpus);
-+ dev_pm_opp_remove_all_dynamic(cpu_dev);
-
- return ret;
- }
-@@ -188,7 +188,7 @@ static int scmi_cpufreq_exit(struct cpuf
- cpufreq_cooling_unregister(priv->cdev);
- dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
- kfree(priv);
-- dev_pm_opp_cpumask_remove_table(policy->related_cpus);
-+ dev_pm_opp_remove_all_dynamic(priv->cpu_dev);
-
- return 0;
- }
---- a/drivers/cpufreq/scpi-cpufreq.c
-+++ b/drivers/cpufreq/scpi-cpufreq.c
-@@ -177,7 +177,7 @@ out_free_cpufreq_table:
- out_free_priv:
- kfree(priv);
- out_free_opp:
-- dev_pm_opp_cpumask_remove_table(policy->cpus);
-+ dev_pm_opp_remove_all_dynamic(cpu_dev);
-
- return ret;
- }
-@@ -190,7 +190,7 @@ static int scpi_cpufreq_exit(struct cpuf
- clk_put(priv->clk);
- dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
- kfree(priv);
-- dev_pm_opp_cpumask_remove_table(policy->related_cpus);
-+ dev_pm_opp_remove_all_dynamic(priv->cpu_dev);
-
- return 0;
- }
---- a/drivers/opp/core.c
-+++ b/drivers/opp/core.c
-@@ -884,11 +884,9 @@ void _opp_free(struct dev_pm_opp *opp)
- kfree(opp);
- }
-
--static void _opp_kref_release(struct kref *kref)
-+static void _opp_kref_release(struct dev_pm_opp *opp,
-+ struct opp_table *opp_table)
- {
-- struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
-- struct opp_table *opp_table = opp->opp_table;
--
- /*
- * Notify the changes in the availability of the operable
- * frequency/voltage list.
-@@ -897,7 +895,22 @@ static void _opp_kref_release(struct kre
- opp_debug_remove_one(opp);
- list_del(&opp->node);
- kfree(opp);
-+}
-+
-+static void _opp_kref_release_unlocked(struct kref *kref)
-+{
-+ struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
-+ struct opp_table *opp_table = opp->opp_table;
-+
-+ _opp_kref_release(opp, opp_table);
-+}
-
-+static void _opp_kref_release_locked(struct kref *kref)
-+{
-+ struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
-+ struct opp_table *opp_table = opp->opp_table;
-+
-+ _opp_kref_release(opp, opp_table);
- mutex_unlock(&opp_table->lock);
- dev_pm_opp_put_opp_table(opp_table);
- }
-@@ -909,10 +922,16 @@ void dev_pm_opp_get(struct dev_pm_opp *o
-
- void dev_pm_opp_put(struct dev_pm_opp *opp)
- {
-- kref_put_mutex(&opp->kref, _opp_kref_release, &opp->opp_table->lock);
-+ kref_put_mutex(&opp->kref, _opp_kref_release_locked,
-+ &opp->opp_table->lock);
- }
- EXPORT_SYMBOL_GPL(dev_pm_opp_put);
-
-+static void dev_pm_opp_put_unlocked(struct dev_pm_opp *opp)
-+{
-+ kref_put(&opp->kref, _opp_kref_release_unlocked);
-+}
-+
- /**
- * dev_pm_opp_remove() - Remove an OPP from OPP table
- * @dev: device for which we do this operation
-@@ -952,6 +971,40 @@ void dev_pm_opp_remove(struct device *de
- }
- EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
-
-+/**
-+ * dev_pm_opp_remove_all_dynamic() - Remove all dynamically created OPPs
-+ * @dev: device for which we do this operation
-+ *
-+ * This function removes all dynamically created OPPs from the opp table.
-+ */
-+void dev_pm_opp_remove_all_dynamic(struct device *dev)
-+{
-+ struct opp_table *opp_table;
-+ struct dev_pm_opp *opp, *temp;
-+ int count = 0;
-+
-+ opp_table = _find_opp_table(dev);
-+ if (IS_ERR(opp_table))
-+ return;
-+
-+ mutex_lock(&opp_table->lock);
-+ list_for_each_entry_safe(opp, temp, &opp_table->opp_list, node) {
-+ if (opp->dynamic) {
-+ dev_pm_opp_put_unlocked(opp);
-+ count++;
-+ }
-+ }
-+ mutex_unlock(&opp_table->lock);
-+
-+ /* Drop the references taken by dev_pm_opp_add() */
-+ while (count--)
-+ dev_pm_opp_put_opp_table(opp_table);
-+
-+ /* Drop the reference taken by _find_opp_table() */
-+ dev_pm_opp_put_opp_table(opp_table);
-+}
-+EXPORT_SYMBOL_GPL(dev_pm_opp_remove_all_dynamic);
-+
- struct dev_pm_opp *_opp_allocate(struct opp_table *table)
- {
- struct dev_pm_opp *opp;
---- a/include/linux/pm_opp.h
-+++ b/include/linux/pm_opp.h
-@@ -107,6 +107,7 @@ void dev_pm_opp_put(struct dev_pm_opp *o
- int dev_pm_opp_add(struct device *dev, unsigned long freq,
- unsigned long u_volt);
- void dev_pm_opp_remove(struct device *dev, unsigned long freq);
-+void dev_pm_opp_remove_all_dynamic(struct device *dev);
-
- int dev_pm_opp_enable(struct device *dev, unsigned long freq);
-
-@@ -208,6 +209,10 @@ static inline void dev_pm_opp_remove(str
- {
- }
-
-+static inline void dev_pm_opp_remove_all_dynamic(struct device *dev)
-+{
-+}
-+
- static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq)
- {
- return 0;
+++ /dev/null
-From 35306211392a8c17ba6cde2a6b5d1beb61ca7d54 Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Jun 2019 20:24:54 +0200
-Subject: [PATCH] clk: bcm283x: add driver interfacing with Raspberry
- Pi's firmware
-
-Commit 4e85e535e6cc6e8a96350e8ee684d0f22eb8629e upstream.
-
-Raspberry Pi's firmware offers an interface though which update it's
-clock's frequencies. This is specially useful in order to change the CPU
-clock (pllb_arm) which is 'owned' by the firmware and we're unable to
-scale using the register interface provided by clk-bcm2835.
-
----
- drivers/clk/bcm/Kconfig | 7 +
- drivers/clk/bcm/Makefile | 1 +
- drivers/clk/bcm/clk-raspberrypi.c | 300 ++++++++++++++++++++++++++++++
- 3 files changed, 308 insertions(+)
- create mode 100644 drivers/clk/bcm/clk-raspberrypi.c
-
---- a/drivers/clk/bcm/Kconfig
-+++ b/drivers/clk/bcm/Kconfig
-@@ -63,3 +63,10 @@ config CLK_BCM_SR
- default ARCH_BCM_IPROC
- help
- Enable common clock framework support for the Broadcom Stingray SoC
-+
-+config CLK_RASPBERRYPI
-+ tristate "Raspberry Pi firmware based clock support"
-+ depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
-+ help
-+ Enable common clock framework support for Raspberry Pi's firmware
-+ dependent clocks
---- a/drivers/clk/bcm/Makefile
-+++ b/drivers/clk/bcm/Makefile
-@@ -7,6 +7,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm216
- obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
- obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
- obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o
-+obj-$(CONFIG_CLK_RASPBERRYPI) += clk-raspberrypi.o
- obj-$(CONFIG_ARCH_BCM_53573) += clk-bcm53573-ilp.o
- obj-$(CONFIG_CLK_BCM_CYGNUS) += clk-cygnus.o
- obj-$(CONFIG_CLK_BCM_HR2) += clk-hr2.o
---- /dev/null
-+++ b/drivers/clk/bcm/clk-raspberrypi.c
-@@ -0,0 +1,300 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Raspberry Pi driver for firmware controlled clocks
-+ *
-+ * Even though clk-bcm2835 provides an interface to the hardware registers for
-+ * the system clocks we've had to factor out 'pllb' as the firmware 'owns' it.
-+ * We're not allowed to change it directly as we might race with the
-+ * over-temperature and under-voltage protections provided by the firmware.
-+ *
-+ */
-+
-+#include <linux/clkdev.h>
-+#include <linux/clk-provider.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <soc/bcm2835/raspberrypi-firmware.h>
-+
-+#define RPI_FIRMWARE_ARM_CLK_ID 0x00000003
-+
-+#define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0)
-+#define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1)
-+
-+/*
-+ * Even though the firmware interface alters 'pllb' the frequencies are
-+ * provided as per 'pllb_arm'. We need to scale before passing them trough.
-+ */
-+#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE 2
-+
-+#define A2W_PLL_FRAC_BITS 20
-+
-+struct raspberrypi_clk {
-+ struct device *dev;
-+ struct rpi_firmware *firmware;
-+
-+ unsigned long min_rate;
-+ unsigned long max_rate;
-+
-+ struct clk_hw pllb;
-+ struct clk_hw *pllb_arm;
-+ struct clk_lookup *pllb_arm_lookup;
-+};
-+
-+/*
-+ * Structure of the message passed to Raspberry Pi's firmware in order to
-+ * change clock rates. The 'disable_turbo' option is only available to the ARM
-+ * clock (pllb) which we enable by default as turbo mode will alter multiple
-+ * clocks at once.
-+ *
-+ * Even though we're able to access the clock registers directly we're bound to
-+ * use the firmware interface as the firmware ultimately takes care of
-+ * mitigating overheating/undervoltage situations and we would be changing
-+ * frequencies behind his back.
-+ *
-+ * For more information on the firmware interface check:
-+ * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
-+ */
-+struct raspberrypi_firmware_prop {
-+ __le32 id;
-+ __le32 val;
-+ __le32 disable_turbo;
-+} __packed;
-+
-+static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag,
-+ u32 clk, u32 *val)
-+{
-+ struct raspberrypi_firmware_prop msg = {
-+ .id = cpu_to_le32(clk),
-+ .val = cpu_to_le32(*val),
-+ .disable_turbo = cpu_to_le32(1),
-+ };
-+ int ret;
-+
-+ ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg));
-+ if (ret)
-+ return ret;
-+
-+ *val = le32_to_cpu(msg.val);
-+
-+ return 0;
-+}
-+
-+static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
-+{
-+ struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
-+ pllb);
-+ u32 val = 0;
-+ int ret;
-+
-+ ret = raspberrypi_clock_property(rpi->firmware,
-+ RPI_FIRMWARE_GET_CLOCK_STATE,
-+ RPI_FIRMWARE_ARM_CLK_ID, &val);
-+ if (ret)
-+ return 0;
-+
-+ return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT);
-+}
-+
-+
-+static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw,
-+ unsigned long parent_rate)
-+{
-+ struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
-+ pllb);
-+ u32 val = 0;
-+ int ret;
-+
-+ ret = raspberrypi_clock_property(rpi->firmware,
-+ RPI_FIRMWARE_GET_CLOCK_RATE,
-+ RPI_FIRMWARE_ARM_CLK_ID,
-+ &val);
-+ if (ret)
-+ return ret;
-+
-+ return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
-+}
-+
-+static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long parent_rate)
-+{
-+ struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
-+ pllb);
-+ u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
-+ int ret;
-+
-+ ret = raspberrypi_clock_property(rpi->firmware,
-+ RPI_FIRMWARE_SET_CLOCK_RATE,
-+ RPI_FIRMWARE_ARM_CLK_ID,
-+ &new_rate);
-+ if (ret)
-+ dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
-+ clk_hw_get_name(hw), ret);
-+
-+ return ret;
-+}
-+
-+/*
-+ * Sadly there is no firmware rate rounding interface. We borrowed it from
-+ * clk-bcm2835.
-+ */
-+static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
-+ struct clk_rate_request *req)
-+{
-+ struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
-+ pllb);
-+ u64 div, final_rate;
-+ u32 ndiv, fdiv;
-+
-+ /* We can't use req->rate directly as it would overflow */
-+ final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate);
-+
-+ div = (u64)final_rate << A2W_PLL_FRAC_BITS;
-+ do_div(div, req->best_parent_rate);
-+
-+ ndiv = div >> A2W_PLL_FRAC_BITS;
-+ fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1);
-+
-+ final_rate = ((u64)req->best_parent_rate *
-+ ((ndiv << A2W_PLL_FRAC_BITS) + fdiv));
-+
-+ req->rate = final_rate >> A2W_PLL_FRAC_BITS;
-+
-+ return 0;
-+}
-+
-+static const struct clk_ops raspberrypi_firmware_pll_clk_ops = {
-+ .is_prepared = raspberrypi_fw_pll_is_on,
-+ .recalc_rate = raspberrypi_fw_pll_get_rate,
-+ .set_rate = raspberrypi_fw_pll_set_rate,
-+ .determine_rate = raspberrypi_pll_determine_rate,
-+};
-+
-+static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi)
-+{
-+ u32 min_rate = 0, max_rate = 0;
-+ struct clk_init_data init;
-+ int ret;
-+
-+ memset(&init, 0, sizeof(init));
-+
-+ /* All of the PLLs derive from the external oscillator. */
-+ init.parent_names = (const char *[]){ "osc" };
-+ init.num_parents = 1;
-+ init.name = "pllb";
-+ init.ops = &raspberrypi_firmware_pll_clk_ops;
-+ init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
-+
-+ /* Get min & max rates set by the firmware */
-+ ret = raspberrypi_clock_property(rpi->firmware,
-+ RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
-+ RPI_FIRMWARE_ARM_CLK_ID,
-+ &min_rate);
-+ if (ret) {
-+ dev_err(rpi->dev, "Failed to get %s min freq: %d\n",
-+ init.name, ret);
-+ return ret;
-+ }
-+
-+ ret = raspberrypi_clock_property(rpi->firmware,
-+ RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
-+ RPI_FIRMWARE_ARM_CLK_ID,
-+ &max_rate);
-+ if (ret) {
-+ dev_err(rpi->dev, "Failed to get %s max freq: %d\n",
-+ init.name, ret);
-+ return ret;
-+ }
-+
-+ if (!min_rate || !max_rate) {
-+ dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n",
-+ min_rate, max_rate);
-+ return -EINVAL;
-+ }
-+
-+ dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n",
-+ min_rate, max_rate);
-+
-+ rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
-+ rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
-+
-+ rpi->pllb.init = &init;
-+
-+ return devm_clk_hw_register(rpi->dev, &rpi->pllb);
-+}
-+
-+static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi)
-+{
-+ rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev,
-+ "pllb_arm", "pllb",
-+ CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
-+ 1, 2);
-+ if (IS_ERR(rpi->pllb_arm)) {
-+ dev_err(rpi->dev, "Failed to initialize pllb_arm\n");
-+ return PTR_ERR(rpi->pllb_arm);
-+ }
-+
-+ rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0");
-+ if (!rpi->pllb_arm_lookup) {
-+ dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n");
-+ clk_hw_unregister_fixed_factor(rpi->pllb_arm);
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+
-+static int raspberrypi_clk_probe(struct platform_device *pdev)
-+{
-+ struct device_node *firmware_node;
-+ struct device *dev = &pdev->dev;
-+ struct rpi_firmware *firmware;
-+ struct raspberrypi_clk *rpi;
-+ int ret;
-+
-+ firmware_node = of_find_compatible_node(NULL, NULL,
-+ "raspberrypi,bcm2835-firmware");
-+ if (!firmware_node) {
-+ dev_err(dev, "Missing firmware node\n");
-+ return -ENOENT;
-+ }
-+
-+ firmware = rpi_firmware_get(firmware_node);
-+ of_node_put(firmware_node);
-+ if (!firmware)
-+ return -EPROBE_DEFER;
-+
-+ rpi = devm_kzalloc(dev, sizeof(*rpi), GFP_KERNEL);
-+ if (!rpi)
-+ return -ENOMEM;
-+
-+ rpi->dev = dev;
-+ rpi->firmware = firmware;
-+
-+ ret = raspberrypi_register_pllb(rpi);
-+ if (ret) {
-+ dev_err(dev, "Failed to initialize pllb, %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = raspberrypi_register_pllb_arm(rpi);
-+ if (ret)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static struct platform_driver raspberrypi_clk_driver = {
-+ .driver = {
-+ .name = "raspberrypi-clk",
-+ },
-+ .probe = raspberrypi_clk_probe,
-+};
-+module_platform_driver(raspberrypi_clk_driver);
-+
-+MODULE_DESCRIPTION("Raspberry Pi firmware clock driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:raspberrypi-clk");
--- /dev/null
+From e7f2fcf4bf0b0a227f564fcdde46f3bdd326c1b2 Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Jun 2019 20:24:55 +0200
+Subject: [PATCH] firmware: raspberrypi: register clk device
+
+Commit 91f2cf4a6b2131016b1ae9c9500245f0572112c7 upstream.
+
+Since clk-raspberrypi is tied to the VC4 firmware instead of particular
+hardware it's registration should be performed by the firmware driver.
+
+---
+ drivers/firmware/raspberrypi.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/firmware/raspberrypi.c
++++ b/drivers/firmware/raspberrypi.c
+@@ -24,6 +24,7 @@
+ #define MBOX_CHAN_PROPERTY 8
+
+ static struct platform_device *rpi_hwmon;
++static struct platform_device *rpi_clk;
+
+ struct rpi_firmware {
+ struct mbox_client cl;
+@@ -297,6 +298,12 @@ rpi_register_hwmon_driver(struct device
+ }
+ }
+
++static void rpi_register_clk_driver(struct device *dev)
++{
++ rpi_clk = platform_device_register_data(dev, "raspberrypi-clk",
++ -1, NULL, 0);
++}
++
+ static int rpi_firmware_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -326,6 +333,7 @@ static int rpi_firmware_probe(struct pla
+ rpi_firmware_print_firmware_revision(fw);
+ rpi_firmware_print_firmware_hash(fw);
+ rpi_register_hwmon_driver(dev, fw);
++ rpi_register_clk_driver(dev);
+
+ return 0;
+ }
+@@ -336,6 +344,8 @@ static int rpi_firmware_remove(struct pl
+
+ platform_device_unregister(rpi_hwmon);
+ rpi_hwmon = NULL;
++ platform_device_unregister(rpi_clk);
++ rpi_clk = NULL;
+ mbox_free_channel(fw->chan);
+ g_pdev = NULL;
+
--- /dev/null
+From b39d5caa499559be6c309b9fd8f8b2f992504e18 Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Jun 2019 20:24:57 +0200
+Subject: [PATCH] clk: raspberrypi: register platform device for
+ raspberrypi-cpufreq
+
+Commit e2bb18347c8e5c4187831f3700c380e3c759601a upstream.
+
+As 'clk-raspberrypi' depends on RPi's firmware interface, which might be
+configured as a module, the cpu clock might not be available for the
+cpufreq driver during it's init process. So we register the
+'raspberrypi-cpufreq' platform device after the probe sequence succeeds.
+
+---
+ drivers/clk/bcm/clk-raspberrypi.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+--- a/drivers/clk/bcm/clk-raspberrypi.c
++++ b/drivers/clk/bcm/clk-raspberrypi.c
+@@ -34,6 +34,7 @@
+ struct raspberrypi_clk {
+ struct device *dev;
+ struct rpi_firmware *firmware;
++ struct platform_device *cpufreq;
+
+ unsigned long min_rate;
+ unsigned long max_rate;
+@@ -272,6 +273,7 @@ static int raspberrypi_clk_probe(struct
+
+ rpi->dev = dev;
+ rpi->firmware = firmware;
++ platform_set_drvdata(pdev, rpi);
+
+ ret = raspberrypi_register_pllb(rpi);
+ if (ret) {
+@@ -283,6 +285,18 @@ static int raspberrypi_clk_probe(struct
+ if (ret)
+ return ret;
+
++ rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq",
++ -1, NULL, 0);
++
++ return 0;
++}
++
++static int raspberrypi_clk_remove(struct platform_device *pdev)
++{
++ struct raspberrypi_clk *rpi = platform_get_drvdata(pdev);
++
++ platform_device_unregister(rpi->cpufreq);
++
+ return 0;
+ }
+
+@@ -291,6 +305,7 @@ static struct platform_driver raspberryp
+ .name = "raspberrypi-clk",
+ },
+ .probe = raspberrypi_clk_probe,
++ .remove = raspberrypi_clk_remove,
+ };
+ module_platform_driver(raspberrypi_clk_driver);
+
+++ /dev/null
-From 1c0d3626312369837bc18051ed6c9611323fce87 Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Jun 2019 20:24:56 +0200
-Subject: [PATCH] cpufreq: add driver for Raspberry Pi
-
-Commit d3df18a97e586702920337056540267807b23f8e upstream.
-
-Raspberry Pi's firmware offers and interface though which update it's
-performance requirements. It allows us to request for specific runtime
-frequencies, which the firmware might or might not respect, depending on
-the firmware configuration and thermals.
-
-As the maximum and minimum frequencies are configurable in the firmware
-there is no way to know in advance their values. So the Raspberry Pi
-cpufreq driver queries them, builds an opp frequency table to then
-launch cpufreq-dt.
-
-Also, as the firmware interface might be configured as a module, making
-the cpu clock unavailable during init, this implements a full fledged
-driver, as opposed to most drivers registering cpufreq-dt, which only
-make use of an init routine.
-
----
- drivers/cpufreq/Kconfig.arm | 8 +++
- drivers/cpufreq/Makefile | 1 +
- drivers/cpufreq/raspberrypi-cpufreq.c | 97 +++++++++++++++++++++++++++
- 3 files changed, 106 insertions(+)
- create mode 100644 drivers/cpufreq/raspberrypi-cpufreq.c
-
---- a/drivers/cpufreq/Kconfig.arm
-+++ b/drivers/cpufreq/Kconfig.arm
-@@ -121,6 +121,14 @@ config ARM_QCOM_CPUFREQ_KRYO
-
- If in doubt, say N.
-
-+config ARM_RASPBERRYPI_CPUFREQ
-+ tristate "Raspberry Pi cpufreq support"
-+ depends on CLK_RASPBERRYPI || COMPILE_TEST
-+ help
-+ This adds the CPUFreq driver for Raspberry Pi
-+
-+ If in doubt, say N.
-+
- config ARM_S3C_CPUFREQ
- bool
- help
---- a/drivers/cpufreq/Makefile
-+++ b/drivers/cpufreq/Makefile
-@@ -65,6 +65,7 @@ obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += o
- obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
- obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
- obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o
-+obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o
- obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
- obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
- obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
---- /dev/null
-+++ b/drivers/cpufreq/raspberrypi-cpufreq.c
-@@ -0,0 +1,97 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Raspberry Pi cpufreq driver
-+ *
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/cpu.h>
-+#include <linux/cpufreq.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_opp.h>
-+
-+#define RASPBERRYPI_FREQ_INTERVAL 100000000
-+
-+static struct platform_device *cpufreq_dt;
-+
-+static int raspberrypi_cpufreq_probe(struct platform_device *pdev)
-+{
-+ struct device *cpu_dev;
-+ unsigned long min, max;
-+ unsigned long rate;
-+ struct clk *clk;
-+ int ret;
-+
-+ cpu_dev = get_cpu_device(0);
-+ if (!cpu_dev) {
-+ pr_err("Cannot get CPU for cpufreq driver\n");
-+ return -ENODEV;
-+ }
-+
-+ clk = clk_get(cpu_dev, NULL);
-+ if (IS_ERR(clk)) {
-+ dev_err(cpu_dev, "Cannot get clock for CPU0\n");
-+ return PTR_ERR(clk);
-+ }
-+
-+ /*
-+ * The max and min frequencies are configurable in the Raspberry Pi
-+ * firmware, so we query them at runtime.
-+ */
-+ min = roundup(clk_round_rate(clk, 0), RASPBERRYPI_FREQ_INTERVAL);
-+ max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL);
-+ clk_put(clk);
-+
-+ for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) {
-+ ret = dev_pm_opp_add(cpu_dev, rate, 0);
-+ if (ret)
-+ goto remove_opp;
-+ }
-+
-+ cpufreq_dt = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
-+ ret = PTR_ERR_OR_ZERO(cpufreq_dt);
-+ if (ret) {
-+ dev_err(cpu_dev, "Failed to create platform device, %d\n", ret);
-+ goto remove_opp;
-+ }
-+
-+ return 0;
-+
-+remove_opp:
-+ dev_pm_opp_remove_all_dynamic(cpu_dev);
-+
-+ return ret;
-+}
-+
-+static int raspberrypi_cpufreq_remove(struct platform_device *pdev)
-+{
-+ struct device *cpu_dev;
-+
-+ cpu_dev = get_cpu_device(0);
-+ if (cpu_dev)
-+ dev_pm_opp_remove_all_dynamic(cpu_dev);
-+
-+ platform_device_unregister(cpufreq_dt);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Since the driver depends on clk-raspberrypi, which may return EPROBE_DEFER,
-+ * all the activity is performed in the probe, which may be defered as well.
-+ */
-+static struct platform_driver raspberrypi_cpufreq_driver = {
-+ .driver = {
-+ .name = "raspberrypi-cpufreq",
-+ },
-+ .probe = raspberrypi_cpufreq_probe,
-+ .remove = raspberrypi_cpufreq_remove,
-+};
-+module_platform_driver(raspberrypi_cpufreq_driver);
-+
-+MODULE_DESCRIPTION("Raspberry Pi cpufreq driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:raspberrypi-cpufreq");
--- /dev/null
+From 04ebfc3e25eaa3dd77544b4b950497990b1a327e Mon Sep 17 00:00:00 2001
+Date: Wed, 12 Jun 2019 20:24:53 +0200
+Subject: [PATCH] clk: bcm2835: remove pllb
+
+Commit 2256d89333bd17b8b56b42734a7e1046d52f7fc3 upstream.
+
+Raspberry Pi's firmware controls this pll, we should use the firmware
+interface to access it.
+
+---
+ drivers/clk/bcm/clk-bcm2835.c | 30 ++++--------------------------
+ 1 file changed, 4 insertions(+), 26 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1755,32 +1755,10 @@ static const struct bcm2835_clk_desc clk
+ .fixed_divider = 1,
+ .flags = CLK_SET_RATE_PARENT),
+
+- /* PLLB is used for the ARM's clock. */
+- [BCM2835_PLLB] = REGISTER_PLL(
+- SOC_ALL,
+- .name = "pllb",
+- .cm_ctrl_reg = CM_PLLB,
+- .a2w_ctrl_reg = A2W_PLLB_CTRL,
+- .frac_reg = A2W_PLLB_FRAC,
+- .ana_reg_base = A2W_PLLB_ANA0,
+- .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
+- .lock_mask = CM_LOCK_FLOCKB,
+-
+- .ana = &bcm2835_ana_default,
+-
+- .min_rate = 600000000u,
+- .max_rate = 3000000000u,
+- .max_fb_rate = BCM2835_MAX_FB_RATE),
+- [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV(
+- SOC_ALL,
+- .name = "pllb_arm",
+- .source_pll = "pllb",
+- .cm_reg = CM_PLLB,
+- .a2w_reg = A2W_PLLB_ARM,
+- .load_mask = CM_PLLB_LOADARM,
+- .hold_mask = CM_PLLB_HOLDARM,
+- .fixed_divider = 1,
+- .flags = CLK_SET_RATE_PARENT),
++ /*
++ * PLLB is used for the ARM's clock. Controlled by firmware, see
++ * clk-raspberrypi.c.
++ */
+
+ /*
+ * PLLC is the core PLL, used to drive the core VPU clock.
+++ /dev/null
-From e7f2fcf4bf0b0a227f564fcdde46f3bdd326c1b2 Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Jun 2019 20:24:55 +0200
-Subject: [PATCH] firmware: raspberrypi: register clk device
-
-Commit 91f2cf4a6b2131016b1ae9c9500245f0572112c7 upstream.
-
-Since clk-raspberrypi is tied to the VC4 firmware instead of particular
-hardware it's registration should be performed by the firmware driver.
-
----
- drivers/firmware/raspberrypi.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/firmware/raspberrypi.c
-+++ b/drivers/firmware/raspberrypi.c
-@@ -24,6 +24,7 @@
- #define MBOX_CHAN_PROPERTY 8
-
- static struct platform_device *rpi_hwmon;
-+static struct platform_device *rpi_clk;
-
- struct rpi_firmware {
- struct mbox_client cl;
-@@ -297,6 +298,12 @@ rpi_register_hwmon_driver(struct device
- }
- }
-
-+static void rpi_register_clk_driver(struct device *dev)
-+{
-+ rpi_clk = platform_device_register_data(dev, "raspberrypi-clk",
-+ -1, NULL, 0);
-+}
-+
- static int rpi_firmware_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
-@@ -326,6 +333,7 @@ static int rpi_firmware_probe(struct pla
- rpi_firmware_print_firmware_revision(fw);
- rpi_firmware_print_firmware_hash(fw);
- rpi_register_hwmon_driver(dev, fw);
-+ rpi_register_clk_driver(dev);
-
- return 0;
- }
-@@ -336,6 +344,8 @@ static int rpi_firmware_remove(struct pl
-
- platform_device_unregister(rpi_hwmon);
- rpi_hwmon = NULL;
-+ platform_device_unregister(rpi_clk);
-+ rpi_clk = NULL;
- mbox_free_channel(fw->chan);
- g_pdev = NULL;
-
+++ /dev/null
-From b39d5caa499559be6c309b9fd8f8b2f992504e18 Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Jun 2019 20:24:57 +0200
-Subject: [PATCH] clk: raspberrypi: register platform device for
- raspberrypi-cpufreq
-
-Commit e2bb18347c8e5c4187831f3700c380e3c759601a upstream.
-
-As 'clk-raspberrypi' depends on RPi's firmware interface, which might be
-configured as a module, the cpu clock might not be available for the
-cpufreq driver during it's init process. So we register the
-'raspberrypi-cpufreq' platform device after the probe sequence succeeds.
-
----
- drivers/clk/bcm/clk-raspberrypi.c | 15 +++++++++++++++
- 1 file changed, 15 insertions(+)
-
---- a/drivers/clk/bcm/clk-raspberrypi.c
-+++ b/drivers/clk/bcm/clk-raspberrypi.c
-@@ -34,6 +34,7 @@
- struct raspberrypi_clk {
- struct device *dev;
- struct rpi_firmware *firmware;
-+ struct platform_device *cpufreq;
-
- unsigned long min_rate;
- unsigned long max_rate;
-@@ -272,6 +273,7 @@ static int raspberrypi_clk_probe(struct
-
- rpi->dev = dev;
- rpi->firmware = firmware;
-+ platform_set_drvdata(pdev, rpi);
-
- ret = raspberrypi_register_pllb(rpi);
- if (ret) {
-@@ -283,6 +285,18 @@ static int raspberrypi_clk_probe(struct
- if (ret)
- return ret;
-
-+ rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq",
-+ -1, NULL, 0);
-+
-+ return 0;
-+}
-+
-+static int raspberrypi_clk_remove(struct platform_device *pdev)
-+{
-+ struct raspberrypi_clk *rpi = platform_get_drvdata(pdev);
-+
-+ platform_device_unregister(rpi->cpufreq);
-+
- return 0;
- }
-
-@@ -291,6 +305,7 @@ static struct platform_driver raspberryp
- .name = "raspberrypi-clk",
- },
- .probe = raspberrypi_clk_probe,
-+ .remove = raspberrypi_clk_remove,
- };
- module_platform_driver(raspberrypi_clk_driver);
-
--- /dev/null
+From 2b08d751023fcdf3c37317dc769ce199ba361415 Mon Sep 17 00:00:00 2001
+Date: Mon, 9 Sep 2019 23:50:44 +0100
+Subject: [PATCH] v3d_drv: Allow clock retrieval by name
+
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -300,7 +300,9 @@ static int v3d_platform_drm_probe(struct
+ }
+ }
+
+- v3d->clk = devm_clk_get(dev, NULL);
++ v3d->clk = devm_clk_get(dev, "v3d");
++ if (!v3d->clk)
++ v3d->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR_OR_NULL(v3d->clk)) {
+ if (PTR_ERR(v3d->clk) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk));
+++ /dev/null
-From 04ebfc3e25eaa3dd77544b4b950497990b1a327e Mon Sep 17 00:00:00 2001
-Date: Wed, 12 Jun 2019 20:24:53 +0200
-Subject: [PATCH] clk: bcm2835: remove pllb
-
-Commit 2256d89333bd17b8b56b42734a7e1046d52f7fc3 upstream.
-
-Raspberry Pi's firmware controls this pll, we should use the firmware
-interface to access it.
-
----
- drivers/clk/bcm/clk-bcm2835.c | 30 ++++--------------------------
- 1 file changed, 4 insertions(+), 26 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -1755,32 +1755,10 @@ static const struct bcm2835_clk_desc clk
- .fixed_divider = 1,
- .flags = CLK_SET_RATE_PARENT),
-
-- /* PLLB is used for the ARM's clock. */
-- [BCM2835_PLLB] = REGISTER_PLL(
-- SOC_ALL,
-- .name = "pllb",
-- .cm_ctrl_reg = CM_PLLB,
-- .a2w_ctrl_reg = A2W_PLLB_CTRL,
-- .frac_reg = A2W_PLLB_FRAC,
-- .ana_reg_base = A2W_PLLB_ANA0,
-- .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
-- .lock_mask = CM_LOCK_FLOCKB,
--
-- .ana = &bcm2835_ana_default,
--
-- .min_rate = 600000000u,
-- .max_rate = 3000000000u,
-- .max_fb_rate = BCM2835_MAX_FB_RATE),
-- [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV(
-- SOC_ALL,
-- .name = "pllb_arm",
-- .source_pll = "pllb",
-- .cm_reg = CM_PLLB,
-- .a2w_reg = A2W_PLLB_ARM,
-- .load_mask = CM_PLLB_LOADARM,
-- .hold_mask = CM_PLLB_HOLDARM,
-- .fixed_divider = 1,
-- .flags = CLK_SET_RATE_PARENT),
-+ /*
-+ * PLLB is used for the ARM's clock. Controlled by firmware, see
-+ * clk-raspberrypi.c.
-+ */
-
- /*
- * PLLC is the core PLL, used to drive the core VPU clock.
--- /dev/null
+From ccf2b80332ba86e5a69f7e3a0f097d9558ad5c95 Mon Sep 17 00:00:00 2001
+Date: Thu, 5 Sep 2019 17:59:14 +0100
+Subject: [PATCH] v3d_gem: Kick the clock so firmware knows we are
+ using firmware clock interface
+
+Setting the v3d clock to low value allows firmware to handle dvfs in case
+where v3d hardware is not being actively used (e.g. console use).
+
+---
+ drivers/gpu/drm/v3d/v3d_gem.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -1050,6 +1050,10 @@ v3d_gem_init(struct drm_device *dev)
+ mutex_init(&v3d->clk_lock);
+ INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work);
+
++ /* kick the clock so firmware knows we are using firmware clock interface */
++ v3d_clock_up_get(v3d);
++ v3d_clock_up_put(v3d);
++
+ /* Note: We don't allocate address 0. Various bits of HW
+ * treat 0 as special, such as the occlusion query counters
+ * where 0 means "disabled".
--- /dev/null
+From 801156c2f2d2d074a1d966f59fc63d8056b3cef9 Mon Sep 17 00:00:00 2001
+Date: Mon, 9 Sep 2019 15:49:56 +0100
+Subject: [PATCH] clk-raspberrypi: Allow cpufreq driver to also adjust
+ gpu clocks
+
+For performance/power it is beneficial to adjust gpu clocks with arm clock.
+This is how the downstream cpufreq driver works
+
+---
+ drivers/clk/bcm/clk-raspberrypi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/clk/bcm/clk-raspberrypi.c
++++ b/drivers/clk/bcm/clk-raspberrypi.c
+@@ -70,7 +70,7 @@ static int raspberrypi_clock_property(st
+ struct raspberrypi_firmware_prop msg = {
+ .id = cpu_to_le32(clk),
+ .val = cpu_to_le32(*val),
+- .disable_turbo = cpu_to_le32(1),
++ .disable_turbo = cpu_to_le32(0),
+ };
+ int ret;
+
+++ /dev/null
-From 2b08d751023fcdf3c37317dc769ce199ba361415 Mon Sep 17 00:00:00 2001
-Date: Mon, 9 Sep 2019 23:50:44 +0100
-Subject: [PATCH] v3d_drv: Allow clock retrieval by name
-
----
- drivers/gpu/drm/v3d/v3d_drv.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -300,7 +300,9 @@ static int v3d_platform_drm_probe(struct
- }
- }
-
-- v3d->clk = devm_clk_get(dev, NULL);
-+ v3d->clk = devm_clk_get(dev, "v3d");
-+ if (!v3d->clk)
-+ v3d->clk = devm_clk_get(dev, NULL);
- if (IS_ERR_OR_NULL(v3d->clk)) {
- if (PTR_ERR(v3d->clk) != -EPROBE_DEFER)
- dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk));
--- /dev/null
+From 679f68410271a32f200e48b501027f68bd114d5c Mon Sep 17 00:00:00 2001
+Date: Wed, 21 Aug 2019 14:55:56 +0100
+Subject: [PATCH] clk-raspberrypi: Also support v3d clock
+
+---
+ drivers/clk/bcm/clk-raspberrypi.c | 497 ++++++++++++++++++++++++------
+ 1 file changed, 408 insertions(+), 89 deletions(-)
+
+--- a/drivers/clk/bcm/clk-raspberrypi.c
++++ b/drivers/clk/bcm/clk-raspberrypi.c
+@@ -15,33 +15,103 @@
+ #include <linux/io.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+-
++#include <dt-bindings/clock/bcm2835.h>
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
+ #define RPI_FIRMWARE_ARM_CLK_ID 0x00000003
++#define RPI_FIRMWARE_V3D_CLK_ID 0x00000005
+
+ #define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0)
+ #define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1)
+
+-/*
+- * Even though the firmware interface alters 'pllb' the frequencies are
+- * provided as per 'pllb_arm'. We need to scale before passing them trough.
+- */
+-#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE 2
+-
+ #define A2W_PLL_FRAC_BITS 20
+
++#define SOC_BCM2835 BIT(0)
++#define SOC_BCM2711 BIT(1)
++#define SOC_ALL (SOC_BCM2835 | SOC_BCM2711)
++
+ struct raspberrypi_clk {
+ struct device *dev;
+ struct rpi_firmware *firmware;
+ struct platform_device *cpufreq;
++};
++
++typedef int (*raspberrypi_clk_register)(struct raspberrypi_clk *rpi,
++ const void *data);
++
++
++/* assignment helper macros for different clock types */
++#define _REGISTER(f, s, ...) { .clk_register = (raspberrypi_clk_register)f, \
++ .supported = s, \
++ .data = __VA_ARGS__ }
++#define REGISTER_PLL(s, ...) _REGISTER(&raspberrypi_register_pll, \
++ s, \
++ &(struct raspberrypi_pll_data) \
++ {__VA_ARGS__})
++#define REGISTER_PLL_DIV(s, ...) _REGISTER(&raspberrypi_register_pll_divider, \
++ s, \
++ &(struct raspberrypi_pll_divider_data) \
++ {__VA_ARGS__})
++#define REGISTER_CLK(s, ...) _REGISTER(&raspberrypi_register_clock, \
++ s, \
++ &(struct raspberrypi_clock_data) \
++ {__VA_ARGS__})
++
++
++struct raspberrypi_pll_data {
++ const char *name;
++ const char *const *parents;
++ int num_parents;
++ u32 clock_id;
++};
++
++struct raspberrypi_clock_data {
++ const char *name;
++ const char *const *parents;
++ int num_parents;
++ u32 flags;
++ u32 clock_id;
++};
++
++struct raspberrypi_pll_divider_data {
++ const char *name;
++ const char *divider_name;
++ const char *lookup;
++ const char *source_pll;
++
++ u32 fixed_divider;
++ u32 flags;
++ u32 clock_id;
++};
+
+- unsigned long min_rate;
+- unsigned long max_rate;
++struct raspberrypi_clk_desc {
++ raspberrypi_clk_register clk_register;
++ unsigned int supported;
++ const void *data;
++};
+
+- struct clk_hw pllb;
+- struct clk_hw *pllb_arm;
+- struct clk_lookup *pllb_arm_lookup;
++struct raspberrypi_clock {
++ struct clk_hw hw;
++ struct raspberrypi_clk *rpi;
++ u32 min_rate;
++ u32 max_rate;
++ const struct raspberrypi_clock_data *data;
++};
++
++struct raspberrypi_pll {
++ struct clk_hw hw;
++ struct raspberrypi_clk *rpi;
++ u32 min_rate;
++ u32 max_rate;
++ const struct raspberrypi_pll_data *data;
++};
++
++struct raspberrypi_pll_divider {
++ struct clk_divider div;
++ struct raspberrypi_clk *rpi;
++ u32 min_rate;
++ u32 max_rate;
++ const struct raspberrypi_pll_divider_data *data;
+ };
+
+ /*
+@@ -83,56 +153,49 @@ static int raspberrypi_clock_property(st
+ return 0;
+ }
+
+-static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
++static int raspberrypi_fw_is_on(struct raspberrypi_clk *rpi, u32 clock_id, const char *name)
+ {
+- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+- pllb);
+ u32 val = 0;
+ int ret;
+
+ ret = raspberrypi_clock_property(rpi->firmware,
+ RPI_FIRMWARE_GET_CLOCK_STATE,
+- RPI_FIRMWARE_ARM_CLK_ID, &val);
++ clock_id, &val);
+ if (ret)
+ return 0;
+
+ return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT);
+ }
+
+-
+-static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw,
+- unsigned long parent_rate)
++static unsigned long raspberrypi_fw_get_rate(struct raspberrypi_clk *rpi,
++ u32 clock_id, const char *name, unsigned long parent_rate)
+ {
+- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+- pllb);
+ u32 val = 0;
+ int ret;
+
+ ret = raspberrypi_clock_property(rpi->firmware,
+ RPI_FIRMWARE_GET_CLOCK_RATE,
+- RPI_FIRMWARE_ARM_CLK_ID,
++ clock_id,
+ &val);
+ if (ret)
+- return ret;
+-
+- return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
++ dev_err_ratelimited(rpi->dev, "Failed to get %s frequency: %d",
++ name, ret);
++ return val;
+ }
+
+-static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+- unsigned long parent_rate)
++static int raspberrypi_fw_set_rate(struct raspberrypi_clk *rpi,
++ u32 clock_id, const char *name, u32 rate,
++ unsigned long parent_rate)
+ {
+- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+- pllb);
+- u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+ int ret;
+
+ ret = raspberrypi_clock_property(rpi->firmware,
+ RPI_FIRMWARE_SET_CLOCK_RATE,
+- RPI_FIRMWARE_ARM_CLK_ID,
+- &new_rate);
++ clock_id,
++ &rate);
+ if (ret)
+ dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
+- clk_hw_get_name(hw), ret);
++ name, ret);
+
+ return ret;
+ }
+@@ -141,16 +204,15 @@ static int raspberrypi_fw_pll_set_rate(s
+ * Sadly there is no firmware rate rounding interface. We borrowed it from
+ * clk-bcm2835.
+ */
+-static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
++static int raspberrypi_determine_rate(struct raspberrypi_clk *rpi,
++ u32 clock_id, const char *name, unsigned long min_rate, unsigned long max_rate,
+ struct clk_rate_request *req)
+ {
+- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+- pllb);
+ u64 div, final_rate;
+ u32 ndiv, fdiv;
+
+ /* We can't use req->rate directly as it would overflow */
+- final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate);
++ final_rate = clamp(req->rate, min_rate, max_rate);
+
+ div = (u64)final_rate << A2W_PLL_FRAC_BITS;
+ do_div(div, req->best_parent_rate);
+@@ -166,6 +228,125 @@ static int raspberrypi_pll_determine_rat
+ return 0;
+ }
+
++static int raspberrypi_fw_clock_is_on(struct clk_hw *hw)
++{
++ struct raspberrypi_clock *pll = container_of(hw, struct raspberrypi_clock, hw);
++ struct raspberrypi_clk *rpi = pll->rpi;
++ const struct raspberrypi_clock_data *data = pll->data;
++
++ return raspberrypi_fw_is_on(rpi, data->clock_id, data->name);
++}
++
++static unsigned long raspberrypi_fw_clock_get_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct raspberrypi_clock *pll = container_of(hw, struct raspberrypi_clock, hw);
++ struct raspberrypi_clk *rpi = pll->rpi;
++ const struct raspberrypi_clock_data *data = pll->data;
++
++ return raspberrypi_fw_get_rate(rpi, data->clock_id, data->name, parent_rate);
++}
++
++static int raspberrypi_fw_clock_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct raspberrypi_clock *pll = container_of(hw, struct raspberrypi_clock, hw);
++ struct raspberrypi_clk *rpi = pll->rpi;
++ const struct raspberrypi_clock_data *data = pll->data;
++
++ return raspberrypi_fw_set_rate(rpi, data->clock_id, data->name, rate, parent_rate);
++}
++
++static int raspberrypi_clock_determine_rate(struct clk_hw *hw,
++ struct clk_rate_request *req)
++{
++ struct raspberrypi_clock *pll = container_of(hw, struct raspberrypi_clock, hw);
++ struct raspberrypi_clk *rpi = pll->rpi;
++ const struct raspberrypi_clock_data *data = pll->data;
++
++ return raspberrypi_determine_rate(rpi, data->clock_id, data->name, pll->min_rate, pll->max_rate, req);
++}
++
++static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
++{
++ struct raspberrypi_pll *pll = container_of(hw, struct raspberrypi_pll, hw);
++ struct raspberrypi_clk *rpi = pll->rpi;
++ const struct raspberrypi_pll_data *data = pll->data;
++
++ return raspberrypi_fw_is_on(rpi, data->clock_id, data->name);
++}
++
++static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct raspberrypi_pll *pll = container_of(hw, struct raspberrypi_pll, hw);
++ struct raspberrypi_clk *rpi = pll->rpi;
++ const struct raspberrypi_pll_data *data = pll->data;
++
++ return raspberrypi_fw_get_rate(rpi, data->clock_id, data->name, parent_rate);
++}
++
++static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct raspberrypi_pll *pll = container_of(hw, struct raspberrypi_pll, hw);
++ struct raspberrypi_clk *rpi = pll->rpi;
++ const struct raspberrypi_pll_data *data = pll->data;
++
++ return raspberrypi_fw_set_rate(rpi, data->clock_id, data->name, rate, parent_rate);
++}
++
++static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
++ struct clk_rate_request *req)
++{
++ struct raspberrypi_pll *pll = container_of(hw, struct raspberrypi_pll, hw);
++ struct raspberrypi_clk *rpi = pll->rpi;
++ const struct raspberrypi_pll_data *data = pll->data;
++
++ return raspberrypi_determine_rate(rpi, data->clock_id, data->name, pll->min_rate, pll->max_rate, req);
++}
++
++
++static int raspberrypi_fw_pll_div_is_on(struct clk_hw *hw)
++{
++ struct raspberrypi_pll_divider *pll = container_of(hw, struct raspberrypi_pll_divider, div.hw);
++ struct raspberrypi_clk *rpi = pll->rpi;
++ const struct raspberrypi_pll_divider_data *data = pll->data;
++
++ return raspberrypi_fw_is_on(rpi, data->clock_id, data->name);
++}
++
++static unsigned long raspberrypi_fw_pll_div_get_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct raspberrypi_pll_divider *pll = container_of(hw, struct raspberrypi_pll_divider, div.hw);
++ struct raspberrypi_clk *rpi = pll->rpi;
++ const struct raspberrypi_pll_divider_data *data = pll->data;
++
++ return raspberrypi_fw_get_rate(rpi, data->clock_id, data->name, parent_rate);
++}
++
++static int raspberrypi_fw_pll_div_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct raspberrypi_pll_divider *pll = container_of(hw, struct raspberrypi_pll_divider, div.hw);
++ struct raspberrypi_clk *rpi = pll->rpi;
++ const struct raspberrypi_pll_divider_data *data = pll->data;
++
++ return raspberrypi_fw_set_rate(rpi, data->clock_id, data->name, rate, parent_rate);
++}
++
++static int raspberrypi_pll_div_determine_rate(struct clk_hw *hw,
++ struct clk_rate_request *req)
++{
++ struct raspberrypi_pll_divider *pll = container_of(hw, struct raspberrypi_pll_divider, div.hw);
++ struct raspberrypi_clk *rpi = pll->rpi;
++ const struct raspberrypi_pll_divider_data *data = pll->data;
++
++ return raspberrypi_determine_rate(rpi, data->clock_id, data->name, pll->min_rate, pll->max_rate, req);
++}
++
++
+ static const struct clk_ops raspberrypi_firmware_pll_clk_ops = {
+ .is_prepared = raspberrypi_fw_pll_is_on,
+ .recalc_rate = raspberrypi_fw_pll_get_rate,
+@@ -173,87 +354,225 @@ static const struct clk_ops raspberrypi_
+ .determine_rate = raspberrypi_pll_determine_rate,
+ };
+
+-static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi)
++static const struct clk_ops raspberrypi_firmware_pll_divider_clk_ops = {
++ .is_prepared = raspberrypi_fw_pll_div_is_on,
++ .recalc_rate = raspberrypi_fw_pll_div_get_rate,
++ .set_rate = raspberrypi_fw_pll_div_set_rate,
++ .determine_rate = raspberrypi_pll_div_determine_rate,
++};
++
++static const struct clk_ops raspberrypi_firmware_clk_ops = {
++ .is_prepared = raspberrypi_fw_clock_is_on,
++ .recalc_rate = raspberrypi_fw_clock_get_rate,
++ .set_rate = raspberrypi_fw_clock_set_rate,
++ .determine_rate = raspberrypi_clock_determine_rate,
++};
++
++
++static int raspberrypi_get_clock_range(struct raspberrypi_clk *rpi, u32 clock_id, u32 *min_rate, u32 *max_rate)
+ {
+- u32 min_rate = 0, max_rate = 0;
++ int ret;
++
++ /* Get min & max rates set by the firmware */
++ ret = raspberrypi_clock_property(rpi->firmware,
++ RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
++ clock_id,
++ min_rate);
++ if (ret) {
++ dev_err(rpi->dev, "Failed to get clock %d min freq: %d (%d)\n",
++ clock_id, *min_rate, ret);
++ return ret;
++ }
++
++ ret = raspberrypi_clock_property(rpi->firmware,
++ RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
++ clock_id,
++ max_rate);
++ if (ret) {
++ dev_err(rpi->dev, "Failed to get clock %d max freq: %d (%d)\n",
++ clock_id, *max_rate, ret);
++ return ret;
++ }
++ return 0;
++}
++
++
++static int raspberrypi_register_pll(struct raspberrypi_clk *rpi,
++ const struct raspberrypi_pll_data *data)
++{
++ struct raspberrypi_pll *pll;
+ struct clk_init_data init;
+ int ret;
+
+ memset(&init, 0, sizeof(init));
+
+ /* All of the PLLs derive from the external oscillator. */
+- init.parent_names = (const char *[]){ "osc" };
+- init.num_parents = 1;
+- init.name = "pllb";
++ init.parent_names = data->parents;
++ init.num_parents = data->num_parents;
++ init.name = data->name;
+ init.ops = &raspberrypi_firmware_pll_clk_ops;
+ init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
+
+- /* Get min & max rates set by the firmware */
+- ret = raspberrypi_clock_property(rpi->firmware,
+- RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
+- RPI_FIRMWARE_ARM_CLK_ID,
+- &min_rate);
++ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
++ if (!pll)
++ return -ENOMEM;
++ pll->rpi = rpi;
++ pll->data = data;
++ pll->hw.init = &init;
++
++ ret = raspberrypi_get_clock_range(rpi, data->clock_id, &pll->min_rate, &pll->max_rate);
+ if (ret) {
+- dev_err(rpi->dev, "Failed to get %s min freq: %d\n",
+- init.name, ret);
++ dev_err(rpi->dev, "%s: raspberrypi_get_clock_range(%s) failed: %d\n", __func__, init.name, ret);
+ return ret;
+ }
+
+- ret = raspberrypi_clock_property(rpi->firmware,
+- RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
+- RPI_FIRMWARE_ARM_CLK_ID,
+- &max_rate);
++ ret = devm_clk_hw_register(rpi->dev, &pll->hw);
+ if (ret) {
+- dev_err(rpi->dev, "Failed to get %s max freq: %d\n",
+- init.name, ret);
++ dev_err(rpi->dev, "%s: devm_clk_hw_register(%s) failed: %d\n", __func__, init.name, ret);
+ return ret;
+ }
++ return 0;
++}
+
+- if (!min_rate || !max_rate) {
+- dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n",
+- min_rate, max_rate);
+- return -EINVAL;
+- }
++static int
++raspberrypi_register_pll_divider(struct raspberrypi_clk *rpi,
++ const struct raspberrypi_pll_divider_data *data)
++{
++ struct raspberrypi_pll_divider *divider;
++ struct clk_init_data init;
++ int ret;
++
++ memset(&init, 0, sizeof(init));
++
++ init.parent_names = &data->source_pll;
++ init.num_parents = 1;
++ init.name = data->name;
++ init.ops = &raspberrypi_firmware_pll_divider_clk_ops;
++ init.flags = data->flags | CLK_IGNORE_UNUSED;
+
+- dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n",
+- min_rate, max_rate);
++ divider = devm_kzalloc(rpi->dev, sizeof(*divider), GFP_KERNEL);
++ if (!divider)
++ return -ENOMEM;
++
++ divider->div.hw.init = &init;
++ divider->rpi = rpi;
++ divider->data = data;
++
++ ret = raspberrypi_get_clock_range(rpi, data->clock_id, ÷r->min_rate, ÷r->max_rate);
++ if (ret) {
++ dev_err(rpi->dev, "%s: raspberrypi_get_clock_range(%s) failed: %d\n", __func__, init.name, ret);
++ return ret;
++ }
+
+- rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+- rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
++ ret = devm_clk_hw_register(rpi->dev, ÷r->div.hw);
++ if (ret) {
++ dev_err(rpi->dev, "%s: devm_clk_hw_register(%s) failed: %d\n", __func__, init.name, ret);
++ return ret;
++ }
+
+- rpi->pllb.init = &init;
++ /*
++ * PLLH's channels have a fixed divide by 10 afterwards, which
++ * is what our consumers are actually using.
++ */
++ if (data->fixed_divider != 1) {
++ struct clk_lookup *lookup;
++ struct clk_hw *clk = clk_hw_register_fixed_factor(rpi->dev,
++ data->divider_name,
++ data->name,
++ CLK_SET_RATE_PARENT,
++ 1,
++ data->fixed_divider);
++ if (IS_ERR(clk)) {
++ dev_err(rpi->dev, "%s: clk_hw_register_fixed_factor(%s) failed: %ld\n", __func__, init.name, PTR_ERR(clk));
++ return PTR_ERR(clk);
++ }
++ if (data->lookup) {
++ lookup = clkdev_hw_create(clk, NULL, data->lookup);
++ if (IS_ERR(lookup)) {
++ dev_err(rpi->dev, "%s: clk_hw_register_fixed_factor(%s) failed: %ld\n", __func__, init.name, PTR_ERR(lookup));
++ return PTR_ERR(lookup);
++ }
++ }
++ }
+
+- return devm_clk_hw_register(rpi->dev, &rpi->pllb);
++ return 0;
+ }
+
+-static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi)
++static int raspberrypi_register_clock(struct raspberrypi_clk *rpi,
++ const struct raspberrypi_clock_data *data)
+ {
+- rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev,
+- "pllb_arm", "pllb",
+- CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+- 1, 2);
+- if (IS_ERR(rpi->pllb_arm)) {
+- dev_err(rpi->dev, "Failed to initialize pllb_arm\n");
+- return PTR_ERR(rpi->pllb_arm);
+- }
++ struct raspberrypi_clock *clock;
++ struct clk_init_data init;
++ struct clk *clk;
++ int ret;
++
++ memset(&init, 0, sizeof(init));
++ init.parent_names = data->parents;
++ init.num_parents = data->num_parents;
++ init.name = data->name;
++ init.flags = data->flags | CLK_IGNORE_UNUSED;
+
+- rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0");
+- if (!rpi->pllb_arm_lookup) {
+- dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n");
+- clk_hw_unregister_fixed_factor(rpi->pllb_arm);
++ init.ops = &raspberrypi_firmware_clk_ops;
++
++ clock = devm_kzalloc(rpi->dev, sizeof(*clock), GFP_KERNEL);
++ if (!clock)
+ return -ENOMEM;
+- }
+
++ clock->rpi = rpi;
++ clock->data = data;
++ clock->hw.init = &init;
++
++ ret = raspberrypi_get_clock_range(rpi, data->clock_id, &clock->min_rate, &clock->max_rate);
++ if (ret) {
++ dev_err(rpi->dev, "%s: raspberrypi_get_clock_range(%s) failed: %d\n", __func__, init.name, ret);
++ return ret;
++ }
++ clk = devm_clk_register(rpi->dev, &clock->hw);
++ if (IS_ERR(clk)) {
++ dev_err(rpi->dev, "%s: devm_clk_register(%s) failed: %ld\n", __func__, init.name, PTR_ERR(clk));
++ return PTR_ERR(clk);
++ }
++ ret = clk_register_clkdev(clk, init.name, NULL);
++ if (ret) {
++ dev_err(rpi->dev, "%s: clk_register_clkdev(%s) failed: %d\n", __func__, init.name, ret);
++ return ret;
++ }
+ return 0;
+ }
+
++
++/*
++ * the real definition of all the pll, pll_dividers and clocks
++ * these make use of the above REGISTER_* macros
++ */
++static const struct raspberrypi_clk_desc clk_desc_array[] = {
++ /* the PLL + PLL dividers */
++ [BCM2835_CLOCK_V3D] = REGISTER_CLK(
++ SOC_ALL,
++ .name = "v3d",
++ .parents = (const char *[]){ "osc" },
++ .num_parents = 1,
++ .clock_id = RPI_FIRMWARE_V3D_CLK_ID),
++ [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV(
++ SOC_ALL,
++ .name = "pllb",
++ .source_pll = "osc",
++ .divider_name = "pllb_arm",
++ .lookup = "cpu0",
++ .fixed_divider = 2,
++ .clock_id = RPI_FIRMWARE_ARM_CLK_ID,
++ .flags = CLK_SET_RATE_PARENT),
++};
++
+ static int raspberrypi_clk_probe(struct platform_device *pdev)
+ {
+ struct device_node *firmware_node;
+ struct device *dev = &pdev->dev;
+ struct rpi_firmware *firmware;
+ struct raspberrypi_clk *rpi;
+- int ret;
++ const struct raspberrypi_clk_desc *desc;
++ const size_t asize = ARRAY_SIZE(clk_desc_array);
++ int i;
+
+ firmware_node = of_find_compatible_node(NULL, NULL,
+ "raspberrypi,bcm2835-firmware");
+@@ -275,16 +594,16 @@ static int raspberrypi_clk_probe(struct
+ rpi->firmware = firmware;
+ platform_set_drvdata(pdev, rpi);
+
+- ret = raspberrypi_register_pllb(rpi);
+- if (ret) {
+- dev_err(dev, "Failed to initialize pllb, %d\n", ret);
+- return ret;
++ for (i = 0; i < asize; i++) {
++ desc = &clk_desc_array[i];
++ if (desc->clk_register && desc->data /*&&
++ (desc->supported & pdata->soc)*/) {
++ int ret = desc->clk_register(rpi, desc->data);
++ if (ret)
++ return ret;
++ }
+ }
+
+- ret = raspberrypi_register_pllb_arm(rpi);
+- if (ret)
+- return ret;
+-
+ rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq",
+ -1, NULL, 0);
+
+++ /dev/null
-From ccf2b80332ba86e5a69f7e3a0f097d9558ad5c95 Mon Sep 17 00:00:00 2001
-Date: Thu, 5 Sep 2019 17:59:14 +0100
-Subject: [PATCH] v3d_gem: Kick the clock so firmware knows we are
- using firmware clock interface
-
-Setting the v3d clock to low value allows firmware to handle dvfs in case
-where v3d hardware is not being actively used (e.g. console use).
-
----
- drivers/gpu/drm/v3d/v3d_gem.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -1050,6 +1050,10 @@ v3d_gem_init(struct drm_device *dev)
- mutex_init(&v3d->clk_lock);
- INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work);
-
-+ /* kick the clock so firmware knows we are using firmware clock interface */
-+ v3d_clock_up_get(v3d);
-+ v3d_clock_up_put(v3d);
-+
- /* Note: We don't allocate address 0. Various bits of HW
- * treat 0 as special, such as the occlusion query counters
- * where 0 means "disabled".
--- /dev/null
+From e8e99169991da84d59f1ed70de9621e31b67d505 Mon Sep 17 00:00:00 2001
+Date: Tue, 3 Sep 2019 20:28:00 +0100
+Subject: [PATCH] clk-bcm2835: Disable v3d clock
+
+This is controlled by firmware, see clk-raspberrypi.c
+
+---
+ drivers/clk/bcm/clk-bcm2835.c | 30 ++++++++++++------------------
+ 1 file changed, 12 insertions(+), 18 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1725,16 +1725,12 @@ static const struct bcm2835_clk_desc clk
+ .hold_mask = CM_PLLA_HOLDCORE,
+ .fixed_divider = 1,
+ .flags = CLK_SET_RATE_PARENT),
+- [BCM2835_PLLA_PER] = REGISTER_PLL_DIV(
+- SOC_ALL,
+- .name = "plla_per",
+- .source_pll = "plla",
+- .cm_reg = CM_PLLA,
+- .a2w_reg = A2W_PLLA_PER,
+- .load_mask = CM_PLLA_LOADPER,
+- .hold_mask = CM_PLLA_HOLDPER,
+- .fixed_divider = 1,
+- .flags = CLK_SET_RATE_PARENT),
++
++ /*
++ * PLLA_PER is used for gpu clocks. Controlled by firmware, see
++ * clk-raspberrypi.c.
++ */
++
+ [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV(
+ SOC_ALL,
+ .name = "plla_dsi0",
+@@ -2007,14 +2003,12 @@ static const struct bcm2835_clk_desc clk
+ .int_bits = 6,
+ .frac_bits = 0,
+ .tcnt_mux = 3),
+- [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK(
+- SOC_ALL,
+- .name = "v3d",
+- .ctl_reg = CM_V3DCTL,
+- .div_reg = CM_V3DDIV,
+- .int_bits = 4,
+- .frac_bits = 8,
+- .tcnt_mux = 4),
++
++ /*
++ * CLOCK_V3D is used for v3d clock. Controlled by firmware, see
++ * clk-raspberrypi.c.
++ */
++
+ /*
+ * VPU clock. This doesn't have an enable bit, since it drives
+ * the bus for everything else, and is special so it doesn't need
+++ /dev/null
-From 801156c2f2d2d074a1d966f59fc63d8056b3cef9 Mon Sep 17 00:00:00 2001
-Date: Mon, 9 Sep 2019 15:49:56 +0100
-Subject: [PATCH] clk-raspberrypi: Allow cpufreq driver to also adjust
- gpu clocks
-
-For performance/power it is beneficial to adjust gpu clocks with arm clock.
-This is how the downstream cpufreq driver works
-
----
- drivers/clk/bcm/clk-raspberrypi.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/clk/bcm/clk-raspberrypi.c
-+++ b/drivers/clk/bcm/clk-raspberrypi.c
-@@ -70,7 +70,7 @@ static int raspberrypi_clock_property(st
- struct raspberrypi_firmware_prop msg = {
- .id = cpu_to_le32(clk),
- .val = cpu_to_le32(*val),
-- .disable_turbo = cpu_to_le32(1),
-+ .disable_turbo = cpu_to_le32(0),
- };
- int ret;
-
+++ /dev/null
-From 679f68410271a32f200e48b501027f68bd114d5c Mon Sep 17 00:00:00 2001
-Date: Wed, 21 Aug 2019 14:55:56 +0100
-Subject: [PATCH] clk-raspberrypi: Also support v3d clock
-
----
- drivers/clk/bcm/clk-raspberrypi.c | 497 ++++++++++++++++++++++++------
- 1 file changed, 408 insertions(+), 89 deletions(-)
-
---- a/drivers/clk/bcm/clk-raspberrypi.c
-+++ b/drivers/clk/bcm/clk-raspberrypi.c
-@@ -15,33 +15,103 @@
- #include <linux/io.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
--
-+#include <dt-bindings/clock/bcm2835.h>
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
- #define RPI_FIRMWARE_ARM_CLK_ID 0x00000003
-+#define RPI_FIRMWARE_V3D_CLK_ID 0x00000005
-
- #define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0)
- #define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1)
-
--/*
-- * Even though the firmware interface alters 'pllb' the frequencies are
-- * provided as per 'pllb_arm'. We need to scale before passing them trough.
-- */
--#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE 2
--
- #define A2W_PLL_FRAC_BITS 20
-
-+#define SOC_BCM2835 BIT(0)
-+#define SOC_BCM2711 BIT(1)
-+#define SOC_ALL (SOC_BCM2835 | SOC_BCM2711)
-+
- struct raspberrypi_clk {
- struct device *dev;
- struct rpi_firmware *firmware;
- struct platform_device *cpufreq;
-+};
-+
-+typedef int (*raspberrypi_clk_register)(struct raspberrypi_clk *rpi,
-+ const void *data);
-+
-+
-+/* assignment helper macros for different clock types */
-+#define _REGISTER(f, s, ...) { .clk_register = (raspberrypi_clk_register)f, \
-+ .supported = s, \
-+ .data = __VA_ARGS__ }
-+#define REGISTER_PLL(s, ...) _REGISTER(&raspberrypi_register_pll, \
-+ s, \
-+ &(struct raspberrypi_pll_data) \
-+ {__VA_ARGS__})
-+#define REGISTER_PLL_DIV(s, ...) _REGISTER(&raspberrypi_register_pll_divider, \
-+ s, \
-+ &(struct raspberrypi_pll_divider_data) \
-+ {__VA_ARGS__})
-+#define REGISTER_CLK(s, ...) _REGISTER(&raspberrypi_register_clock, \
-+ s, \
-+ &(struct raspberrypi_clock_data) \
-+ {__VA_ARGS__})
-+
-+
-+struct raspberrypi_pll_data {
-+ const char *name;
-+ const char *const *parents;
-+ int num_parents;
-+ u32 clock_id;
-+};
-+
-+struct raspberrypi_clock_data {
-+ const char *name;
-+ const char *const *parents;
-+ int num_parents;
-+ u32 flags;
-+ u32 clock_id;
-+};
-+
-+struct raspberrypi_pll_divider_data {
-+ const char *name;
-+ const char *divider_name;
-+ const char *lookup;
-+ const char *source_pll;
-+
-+ u32 fixed_divider;
-+ u32 flags;
-+ u32 clock_id;
-+};
-
-- unsigned long min_rate;
-- unsigned long max_rate;
-+struct raspberrypi_clk_desc {
-+ raspberrypi_clk_register clk_register;
-+ unsigned int supported;
-+ const void *data;
-+};
-
-- struct clk_hw pllb;
-- struct clk_hw *pllb_arm;
-- struct clk_lookup *pllb_arm_lookup;
-+struct raspberrypi_clock {
-+ struct clk_hw hw;
-+ struct raspberrypi_clk *rpi;
-+ u32 min_rate;
-+ u32 max_rate;
-+ const struct raspberrypi_clock_data *data;
-+};
-+
-+struct raspberrypi_pll {
-+ struct clk_hw hw;
-+ struct raspberrypi_clk *rpi;
-+ u32 min_rate;
-+ u32 max_rate;
-+ const struct raspberrypi_pll_data *data;
-+};
-+
-+struct raspberrypi_pll_divider {
-+ struct clk_divider div;
-+ struct raspberrypi_clk *rpi;
-+ u32 min_rate;
-+ u32 max_rate;
-+ const struct raspberrypi_pll_divider_data *data;
- };
-
- /*
-@@ -83,56 +153,49 @@ static int raspberrypi_clock_property(st
- return 0;
- }
-
--static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
-+static int raspberrypi_fw_is_on(struct raspberrypi_clk *rpi, u32 clock_id, const char *name)
- {
-- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
-- pllb);
- u32 val = 0;
- int ret;
-
- ret = raspberrypi_clock_property(rpi->firmware,
- RPI_FIRMWARE_GET_CLOCK_STATE,
-- RPI_FIRMWARE_ARM_CLK_ID, &val);
-+ clock_id, &val);
- if (ret)
- return 0;
-
- return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT);
- }
-
--
--static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw,
-- unsigned long parent_rate)
-+static unsigned long raspberrypi_fw_get_rate(struct raspberrypi_clk *rpi,
-+ u32 clock_id, const char *name, unsigned long parent_rate)
- {
-- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
-- pllb);
- u32 val = 0;
- int ret;
-
- ret = raspberrypi_clock_property(rpi->firmware,
- RPI_FIRMWARE_GET_CLOCK_RATE,
-- RPI_FIRMWARE_ARM_CLK_ID,
-+ clock_id,
- &val);
- if (ret)
-- return ret;
--
-- return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
-+ dev_err_ratelimited(rpi->dev, "Failed to get %s frequency: %d",
-+ name, ret);
-+ return val;
- }
-
--static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
-- unsigned long parent_rate)
-+static int raspberrypi_fw_set_rate(struct raspberrypi_clk *rpi,
-+ u32 clock_id, const char *name, u32 rate,
-+ unsigned long parent_rate)
- {
-- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
-- pllb);
-- u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
- int ret;
-
- ret = raspberrypi_clock_property(rpi->firmware,
- RPI_FIRMWARE_SET_CLOCK_RATE,
-- RPI_FIRMWARE_ARM_CLK_ID,
-- &new_rate);
-+ clock_id,
-+ &rate);
- if (ret)
- dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
-- clk_hw_get_name(hw), ret);
-+ name, ret);
-
- return ret;
- }
-@@ -141,16 +204,15 @@ static int raspberrypi_fw_pll_set_rate(s
- * Sadly there is no firmware rate rounding interface. We borrowed it from
- * clk-bcm2835.
- */
--static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
-+static int raspberrypi_determine_rate(struct raspberrypi_clk *rpi,
-+ u32 clock_id, const char *name, unsigned long min_rate, unsigned long max_rate,
- struct clk_rate_request *req)
- {
-- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
-- pllb);
- u64 div, final_rate;
- u32 ndiv, fdiv;
-
- /* We can't use req->rate directly as it would overflow */
-- final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate);
-+ final_rate = clamp(req->rate, min_rate, max_rate);
-
- div = (u64)final_rate << A2W_PLL_FRAC_BITS;
- do_div(div, req->best_parent_rate);
-@@ -166,6 +228,125 @@ static int raspberrypi_pll_determine_rat
- return 0;
- }
-
-+static int raspberrypi_fw_clock_is_on(struct clk_hw *hw)
-+{
-+ struct raspberrypi_clock *pll = container_of(hw, struct raspberrypi_clock, hw);
-+ struct raspberrypi_clk *rpi = pll->rpi;
-+ const struct raspberrypi_clock_data *data = pll->data;
-+
-+ return raspberrypi_fw_is_on(rpi, data->clock_id, data->name);
-+}
-+
-+static unsigned long raspberrypi_fw_clock_get_rate(struct clk_hw *hw,
-+ unsigned long parent_rate)
-+{
-+ struct raspberrypi_clock *pll = container_of(hw, struct raspberrypi_clock, hw);
-+ struct raspberrypi_clk *rpi = pll->rpi;
-+ const struct raspberrypi_clock_data *data = pll->data;
-+
-+ return raspberrypi_fw_get_rate(rpi, data->clock_id, data->name, parent_rate);
-+}
-+
-+static int raspberrypi_fw_clock_set_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long parent_rate)
-+{
-+ struct raspberrypi_clock *pll = container_of(hw, struct raspberrypi_clock, hw);
-+ struct raspberrypi_clk *rpi = pll->rpi;
-+ const struct raspberrypi_clock_data *data = pll->data;
-+
-+ return raspberrypi_fw_set_rate(rpi, data->clock_id, data->name, rate, parent_rate);
-+}
-+
-+static int raspberrypi_clock_determine_rate(struct clk_hw *hw,
-+ struct clk_rate_request *req)
-+{
-+ struct raspberrypi_clock *pll = container_of(hw, struct raspberrypi_clock, hw);
-+ struct raspberrypi_clk *rpi = pll->rpi;
-+ const struct raspberrypi_clock_data *data = pll->data;
-+
-+ return raspberrypi_determine_rate(rpi, data->clock_id, data->name, pll->min_rate, pll->max_rate, req);
-+}
-+
-+static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
-+{
-+ struct raspberrypi_pll *pll = container_of(hw, struct raspberrypi_pll, hw);
-+ struct raspberrypi_clk *rpi = pll->rpi;
-+ const struct raspberrypi_pll_data *data = pll->data;
-+
-+ return raspberrypi_fw_is_on(rpi, data->clock_id, data->name);
-+}
-+
-+static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw,
-+ unsigned long parent_rate)
-+{
-+ struct raspberrypi_pll *pll = container_of(hw, struct raspberrypi_pll, hw);
-+ struct raspberrypi_clk *rpi = pll->rpi;
-+ const struct raspberrypi_pll_data *data = pll->data;
-+
-+ return raspberrypi_fw_get_rate(rpi, data->clock_id, data->name, parent_rate);
-+}
-+
-+static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long parent_rate)
-+{
-+ struct raspberrypi_pll *pll = container_of(hw, struct raspberrypi_pll, hw);
-+ struct raspberrypi_clk *rpi = pll->rpi;
-+ const struct raspberrypi_pll_data *data = pll->data;
-+
-+ return raspberrypi_fw_set_rate(rpi, data->clock_id, data->name, rate, parent_rate);
-+}
-+
-+static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
-+ struct clk_rate_request *req)
-+{
-+ struct raspberrypi_pll *pll = container_of(hw, struct raspberrypi_pll, hw);
-+ struct raspberrypi_clk *rpi = pll->rpi;
-+ const struct raspberrypi_pll_data *data = pll->data;
-+
-+ return raspberrypi_determine_rate(rpi, data->clock_id, data->name, pll->min_rate, pll->max_rate, req);
-+}
-+
-+
-+static int raspberrypi_fw_pll_div_is_on(struct clk_hw *hw)
-+{
-+ struct raspberrypi_pll_divider *pll = container_of(hw, struct raspberrypi_pll_divider, div.hw);
-+ struct raspberrypi_clk *rpi = pll->rpi;
-+ const struct raspberrypi_pll_divider_data *data = pll->data;
-+
-+ return raspberrypi_fw_is_on(rpi, data->clock_id, data->name);
-+}
-+
-+static unsigned long raspberrypi_fw_pll_div_get_rate(struct clk_hw *hw,
-+ unsigned long parent_rate)
-+{
-+ struct raspberrypi_pll_divider *pll = container_of(hw, struct raspberrypi_pll_divider, div.hw);
-+ struct raspberrypi_clk *rpi = pll->rpi;
-+ const struct raspberrypi_pll_divider_data *data = pll->data;
-+
-+ return raspberrypi_fw_get_rate(rpi, data->clock_id, data->name, parent_rate);
-+}
-+
-+static int raspberrypi_fw_pll_div_set_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long parent_rate)
-+{
-+ struct raspberrypi_pll_divider *pll = container_of(hw, struct raspberrypi_pll_divider, div.hw);
-+ struct raspberrypi_clk *rpi = pll->rpi;
-+ const struct raspberrypi_pll_divider_data *data = pll->data;
-+
-+ return raspberrypi_fw_set_rate(rpi, data->clock_id, data->name, rate, parent_rate);
-+}
-+
-+static int raspberrypi_pll_div_determine_rate(struct clk_hw *hw,
-+ struct clk_rate_request *req)
-+{
-+ struct raspberrypi_pll_divider *pll = container_of(hw, struct raspberrypi_pll_divider, div.hw);
-+ struct raspberrypi_clk *rpi = pll->rpi;
-+ const struct raspberrypi_pll_divider_data *data = pll->data;
-+
-+ return raspberrypi_determine_rate(rpi, data->clock_id, data->name, pll->min_rate, pll->max_rate, req);
-+}
-+
-+
- static const struct clk_ops raspberrypi_firmware_pll_clk_ops = {
- .is_prepared = raspberrypi_fw_pll_is_on,
- .recalc_rate = raspberrypi_fw_pll_get_rate,
-@@ -173,87 +354,225 @@ static const struct clk_ops raspberrypi_
- .determine_rate = raspberrypi_pll_determine_rate,
- };
-
--static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi)
-+static const struct clk_ops raspberrypi_firmware_pll_divider_clk_ops = {
-+ .is_prepared = raspberrypi_fw_pll_div_is_on,
-+ .recalc_rate = raspberrypi_fw_pll_div_get_rate,
-+ .set_rate = raspberrypi_fw_pll_div_set_rate,
-+ .determine_rate = raspberrypi_pll_div_determine_rate,
-+};
-+
-+static const struct clk_ops raspberrypi_firmware_clk_ops = {
-+ .is_prepared = raspberrypi_fw_clock_is_on,
-+ .recalc_rate = raspberrypi_fw_clock_get_rate,
-+ .set_rate = raspberrypi_fw_clock_set_rate,
-+ .determine_rate = raspberrypi_clock_determine_rate,
-+};
-+
-+
-+static int raspberrypi_get_clock_range(struct raspberrypi_clk *rpi, u32 clock_id, u32 *min_rate, u32 *max_rate)
- {
-- u32 min_rate = 0, max_rate = 0;
-+ int ret;
-+
-+ /* Get min & max rates set by the firmware */
-+ ret = raspberrypi_clock_property(rpi->firmware,
-+ RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
-+ clock_id,
-+ min_rate);
-+ if (ret) {
-+ dev_err(rpi->dev, "Failed to get clock %d min freq: %d (%d)\n",
-+ clock_id, *min_rate, ret);
-+ return ret;
-+ }
-+
-+ ret = raspberrypi_clock_property(rpi->firmware,
-+ RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
-+ clock_id,
-+ max_rate);
-+ if (ret) {
-+ dev_err(rpi->dev, "Failed to get clock %d max freq: %d (%d)\n",
-+ clock_id, *max_rate, ret);
-+ return ret;
-+ }
-+ return 0;
-+}
-+
-+
-+static int raspberrypi_register_pll(struct raspberrypi_clk *rpi,
-+ const struct raspberrypi_pll_data *data)
-+{
-+ struct raspberrypi_pll *pll;
- struct clk_init_data init;
- int ret;
-
- memset(&init, 0, sizeof(init));
-
- /* All of the PLLs derive from the external oscillator. */
-- init.parent_names = (const char *[]){ "osc" };
-- init.num_parents = 1;
-- init.name = "pllb";
-+ init.parent_names = data->parents;
-+ init.num_parents = data->num_parents;
-+ init.name = data->name;
- init.ops = &raspberrypi_firmware_pll_clk_ops;
- init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
-
-- /* Get min & max rates set by the firmware */
-- ret = raspberrypi_clock_property(rpi->firmware,
-- RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
-- RPI_FIRMWARE_ARM_CLK_ID,
-- &min_rate);
-+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
-+ if (!pll)
-+ return -ENOMEM;
-+ pll->rpi = rpi;
-+ pll->data = data;
-+ pll->hw.init = &init;
-+
-+ ret = raspberrypi_get_clock_range(rpi, data->clock_id, &pll->min_rate, &pll->max_rate);
- if (ret) {
-- dev_err(rpi->dev, "Failed to get %s min freq: %d\n",
-- init.name, ret);
-+ dev_err(rpi->dev, "%s: raspberrypi_get_clock_range(%s) failed: %d\n", __func__, init.name, ret);
- return ret;
- }
-
-- ret = raspberrypi_clock_property(rpi->firmware,
-- RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
-- RPI_FIRMWARE_ARM_CLK_ID,
-- &max_rate);
-+ ret = devm_clk_hw_register(rpi->dev, &pll->hw);
- if (ret) {
-- dev_err(rpi->dev, "Failed to get %s max freq: %d\n",
-- init.name, ret);
-+ dev_err(rpi->dev, "%s: devm_clk_hw_register(%s) failed: %d\n", __func__, init.name, ret);
- return ret;
- }
-+ return 0;
-+}
-
-- if (!min_rate || !max_rate) {
-- dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n",
-- min_rate, max_rate);
-- return -EINVAL;
-- }
-+static int
-+raspberrypi_register_pll_divider(struct raspberrypi_clk *rpi,
-+ const struct raspberrypi_pll_divider_data *data)
-+{
-+ struct raspberrypi_pll_divider *divider;
-+ struct clk_init_data init;
-+ int ret;
-+
-+ memset(&init, 0, sizeof(init));
-+
-+ init.parent_names = &data->source_pll;
-+ init.num_parents = 1;
-+ init.name = data->name;
-+ init.ops = &raspberrypi_firmware_pll_divider_clk_ops;
-+ init.flags = data->flags | CLK_IGNORE_UNUSED;
-
-- dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n",
-- min_rate, max_rate);
-+ divider = devm_kzalloc(rpi->dev, sizeof(*divider), GFP_KERNEL);
-+ if (!divider)
-+ return -ENOMEM;
-+
-+ divider->div.hw.init = &init;
-+ divider->rpi = rpi;
-+ divider->data = data;
-+
-+ ret = raspberrypi_get_clock_range(rpi, data->clock_id, ÷r->min_rate, ÷r->max_rate);
-+ if (ret) {
-+ dev_err(rpi->dev, "%s: raspberrypi_get_clock_range(%s) failed: %d\n", __func__, init.name, ret);
-+ return ret;
-+ }
-
-- rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
-- rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
-+ ret = devm_clk_hw_register(rpi->dev, ÷r->div.hw);
-+ if (ret) {
-+ dev_err(rpi->dev, "%s: devm_clk_hw_register(%s) failed: %d\n", __func__, init.name, ret);
-+ return ret;
-+ }
-
-- rpi->pllb.init = &init;
-+ /*
-+ * PLLH's channels have a fixed divide by 10 afterwards, which
-+ * is what our consumers are actually using.
-+ */
-+ if (data->fixed_divider != 1) {
-+ struct clk_lookup *lookup;
-+ struct clk_hw *clk = clk_hw_register_fixed_factor(rpi->dev,
-+ data->divider_name,
-+ data->name,
-+ CLK_SET_RATE_PARENT,
-+ 1,
-+ data->fixed_divider);
-+ if (IS_ERR(clk)) {
-+ dev_err(rpi->dev, "%s: clk_hw_register_fixed_factor(%s) failed: %ld\n", __func__, init.name, PTR_ERR(clk));
-+ return PTR_ERR(clk);
-+ }
-+ if (data->lookup) {
-+ lookup = clkdev_hw_create(clk, NULL, data->lookup);
-+ if (IS_ERR(lookup)) {
-+ dev_err(rpi->dev, "%s: clk_hw_register_fixed_factor(%s) failed: %ld\n", __func__, init.name, PTR_ERR(lookup));
-+ return PTR_ERR(lookup);
-+ }
-+ }
-+ }
-
-- return devm_clk_hw_register(rpi->dev, &rpi->pllb);
-+ return 0;
- }
-
--static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi)
-+static int raspberrypi_register_clock(struct raspberrypi_clk *rpi,
-+ const struct raspberrypi_clock_data *data)
- {
-- rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev,
-- "pllb_arm", "pllb",
-- CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
-- 1, 2);
-- if (IS_ERR(rpi->pllb_arm)) {
-- dev_err(rpi->dev, "Failed to initialize pllb_arm\n");
-- return PTR_ERR(rpi->pllb_arm);
-- }
-+ struct raspberrypi_clock *clock;
-+ struct clk_init_data init;
-+ struct clk *clk;
-+ int ret;
-+
-+ memset(&init, 0, sizeof(init));
-+ init.parent_names = data->parents;
-+ init.num_parents = data->num_parents;
-+ init.name = data->name;
-+ init.flags = data->flags | CLK_IGNORE_UNUSED;
-
-- rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0");
-- if (!rpi->pllb_arm_lookup) {
-- dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n");
-- clk_hw_unregister_fixed_factor(rpi->pllb_arm);
-+ init.ops = &raspberrypi_firmware_clk_ops;
-+
-+ clock = devm_kzalloc(rpi->dev, sizeof(*clock), GFP_KERNEL);
-+ if (!clock)
- return -ENOMEM;
-- }
-
-+ clock->rpi = rpi;
-+ clock->data = data;
-+ clock->hw.init = &init;
-+
-+ ret = raspberrypi_get_clock_range(rpi, data->clock_id, &clock->min_rate, &clock->max_rate);
-+ if (ret) {
-+ dev_err(rpi->dev, "%s: raspberrypi_get_clock_range(%s) failed: %d\n", __func__, init.name, ret);
-+ return ret;
-+ }
-+ clk = devm_clk_register(rpi->dev, &clock->hw);
-+ if (IS_ERR(clk)) {
-+ dev_err(rpi->dev, "%s: devm_clk_register(%s) failed: %ld\n", __func__, init.name, PTR_ERR(clk));
-+ return PTR_ERR(clk);
-+ }
-+ ret = clk_register_clkdev(clk, init.name, NULL);
-+ if (ret) {
-+ dev_err(rpi->dev, "%s: clk_register_clkdev(%s) failed: %d\n", __func__, init.name, ret);
-+ return ret;
-+ }
- return 0;
- }
-
-+
-+/*
-+ * the real definition of all the pll, pll_dividers and clocks
-+ * these make use of the above REGISTER_* macros
-+ */
-+static const struct raspberrypi_clk_desc clk_desc_array[] = {
-+ /* the PLL + PLL dividers */
-+ [BCM2835_CLOCK_V3D] = REGISTER_CLK(
-+ SOC_ALL,
-+ .name = "v3d",
-+ .parents = (const char *[]){ "osc" },
-+ .num_parents = 1,
-+ .clock_id = RPI_FIRMWARE_V3D_CLK_ID),
-+ [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV(
-+ SOC_ALL,
-+ .name = "pllb",
-+ .source_pll = "osc",
-+ .divider_name = "pllb_arm",
-+ .lookup = "cpu0",
-+ .fixed_divider = 2,
-+ .clock_id = RPI_FIRMWARE_ARM_CLK_ID,
-+ .flags = CLK_SET_RATE_PARENT),
-+};
-+
- static int raspberrypi_clk_probe(struct platform_device *pdev)
- {
- struct device_node *firmware_node;
- struct device *dev = &pdev->dev;
- struct rpi_firmware *firmware;
- struct raspberrypi_clk *rpi;
-- int ret;
-+ const struct raspberrypi_clk_desc *desc;
-+ const size_t asize = ARRAY_SIZE(clk_desc_array);
-+ int i;
-
- firmware_node = of_find_compatible_node(NULL, NULL,
- "raspberrypi,bcm2835-firmware");
-@@ -275,16 +594,16 @@ static int raspberrypi_clk_probe(struct
- rpi->firmware = firmware;
- platform_set_drvdata(pdev, rpi);
-
-- ret = raspberrypi_register_pllb(rpi);
-- if (ret) {
-- dev_err(dev, "Failed to initialize pllb, %d\n", ret);
-- return ret;
-+ for (i = 0; i < asize; i++) {
-+ desc = &clk_desc_array[i];
-+ if (desc->clk_register && desc->data /*&&
-+ (desc->supported & pdata->soc)*/) {
-+ int ret = desc->clk_register(rpi, desc->data);
-+ if (ret)
-+ return ret;
-+ }
- }
-
-- ret = raspberrypi_register_pllb_arm(rpi);
-- if (ret)
-- return ret;
--
- rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq",
- -1, NULL, 0);
-
--- /dev/null
+From c4374e446b6957234432d5c3f5d5f89f1acb807d Mon Sep 17 00:00:00 2001
+Date: Thu, 7 Nov 2019 12:25:27 +0000
+Subject: [PATCH] fixup! clk-raspberrypi: Also support v3d clock
+
+---
+ drivers/clk/bcm/clk-raspberrypi.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/bcm/clk-raspberrypi.c
++++ b/drivers/clk/bcm/clk-raspberrypi.c
+@@ -474,7 +474,7 @@ raspberrypi_register_pll_divider(struct
+ * PLLH's channels have a fixed divide by 10 afterwards, which
+ * is what our consumers are actually using.
+ */
+- if (data->fixed_divider != 1) {
++ if (data->fixed_divider != 0) {
+ struct clk_lookup *lookup;
+ struct clk_hw *clk = clk_hw_register_fixed_factor(rpi->dev,
+ data->divider_name,
+@@ -559,7 +559,7 @@ static const struct raspberrypi_clk_desc
+ .source_pll = "osc",
+ .divider_name = "pllb_arm",
+ .lookup = "cpu0",
+- .fixed_divider = 2,
++ .fixed_divider = 1,
+ .clock_id = RPI_FIRMWARE_ARM_CLK_ID,
+ .flags = CLK_SET_RATE_PARENT),
+ };
+++ /dev/null
-From e8e99169991da84d59f1ed70de9621e31b67d505 Mon Sep 17 00:00:00 2001
-Date: Tue, 3 Sep 2019 20:28:00 +0100
-Subject: [PATCH] clk-bcm2835: Disable v3d clock
-
-This is controlled by firmware, see clk-raspberrypi.c
-
----
- drivers/clk/bcm/clk-bcm2835.c | 30 ++++++++++++------------------
- 1 file changed, 12 insertions(+), 18 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -1725,16 +1725,12 @@ static const struct bcm2835_clk_desc clk
- .hold_mask = CM_PLLA_HOLDCORE,
- .fixed_divider = 1,
- .flags = CLK_SET_RATE_PARENT),
-- [BCM2835_PLLA_PER] = REGISTER_PLL_DIV(
-- SOC_ALL,
-- .name = "plla_per",
-- .source_pll = "plla",
-- .cm_reg = CM_PLLA,
-- .a2w_reg = A2W_PLLA_PER,
-- .load_mask = CM_PLLA_LOADPER,
-- .hold_mask = CM_PLLA_HOLDPER,
-- .fixed_divider = 1,
-- .flags = CLK_SET_RATE_PARENT),
-+
-+ /*
-+ * PLLA_PER is used for gpu clocks. Controlled by firmware, see
-+ * clk-raspberrypi.c.
-+ */
-+
- [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV(
- SOC_ALL,
- .name = "plla_dsi0",
-@@ -2007,14 +2003,12 @@ static const struct bcm2835_clk_desc clk
- .int_bits = 6,
- .frac_bits = 0,
- .tcnt_mux = 3),
-- [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK(
-- SOC_ALL,
-- .name = "v3d",
-- .ctl_reg = CM_V3DCTL,
-- .div_reg = CM_V3DDIV,
-- .int_bits = 4,
-- .frac_bits = 8,
-- .tcnt_mux = 4),
-+
-+ /*
-+ * CLOCK_V3D is used for v3d clock. Controlled by firmware, see
-+ * clk-raspberrypi.c.
-+ */
-+
- /*
- * VPU clock. This doesn't have an enable bit, since it drives
- * the bus for everything else, and is special so it doesn't need
--- /dev/null
+From 05c745c001c8c82bbba8a6d953ad77ad25c92c5f Mon Sep 17 00:00:00 2001
+Date: Thu, 7 Nov 2019 14:11:08 +0000
+Subject: [PATCH] fixup! clk-raspberrypi: Also support v3d clock
+
+---
+ drivers/clk/bcm/clk-raspberrypi.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/clk/bcm/clk-raspberrypi.c
++++ b/drivers/clk/bcm/clk-raspberrypi.c
+@@ -351,21 +351,21 @@ static const struct clk_ops raspberrypi_
+ .is_prepared = raspberrypi_fw_pll_is_on,
+ .recalc_rate = raspberrypi_fw_pll_get_rate,
+ .set_rate = raspberrypi_fw_pll_set_rate,
+- .determine_rate = raspberrypi_pll_determine_rate,
++ //.determine_rate = raspberrypi_pll_determine_rate,
+ };
+
+ static const struct clk_ops raspberrypi_firmware_pll_divider_clk_ops = {
+ .is_prepared = raspberrypi_fw_pll_div_is_on,
+ .recalc_rate = raspberrypi_fw_pll_div_get_rate,
+ .set_rate = raspberrypi_fw_pll_div_set_rate,
+- .determine_rate = raspberrypi_pll_div_determine_rate,
++ //.determine_rate = raspberrypi_pll_div_determine_rate,
+ };
+
+ static const struct clk_ops raspberrypi_firmware_clk_ops = {
+ .is_prepared = raspberrypi_fw_clock_is_on,
+ .recalc_rate = raspberrypi_fw_clock_get_rate,
+ .set_rate = raspberrypi_fw_clock_set_rate,
+- .determine_rate = raspberrypi_clock_determine_rate,
++ //.determine_rate = raspberrypi_clock_determine_rate,
+ };
+
+
+++ /dev/null
-From c4374e446b6957234432d5c3f5d5f89f1acb807d Mon Sep 17 00:00:00 2001
-Date: Thu, 7 Nov 2019 12:25:27 +0000
-Subject: [PATCH] fixup! clk-raspberrypi: Also support v3d clock
-
----
- drivers/clk/bcm/clk-raspberrypi.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/clk/bcm/clk-raspberrypi.c
-+++ b/drivers/clk/bcm/clk-raspberrypi.c
-@@ -474,7 +474,7 @@ raspberrypi_register_pll_divider(struct
- * PLLH's channels have a fixed divide by 10 afterwards, which
- * is what our consumers are actually using.
- */
-- if (data->fixed_divider != 1) {
-+ if (data->fixed_divider != 0) {
- struct clk_lookup *lookup;
- struct clk_hw *clk = clk_hw_register_fixed_factor(rpi->dev,
- data->divider_name,
-@@ -559,7 +559,7 @@ static const struct raspberrypi_clk_desc
- .source_pll = "osc",
- .divider_name = "pllb_arm",
- .lookup = "cpu0",
-- .fixed_divider = 2,
-+ .fixed_divider = 1,
- .clock_id = RPI_FIRMWARE_ARM_CLK_ID,
- .flags = CLK_SET_RATE_PARENT),
- };
--- /dev/null
+From 1c038a58f4183602fc1699d68b21f5e22a12176d Mon Sep 17 00:00:00 2001
+Date: Fri, 13 Sep 2019 13:45:11 +0100
+Subject: [PATCH] raspberrypi-cpufreq: Only report integer pll divisor
+ frequencies
+
+---
+ drivers/cpufreq/raspberrypi-cpufreq.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/cpufreq/raspberrypi-cpufreq.c
++++ b/drivers/cpufreq/raspberrypi-cpufreq.c
+@@ -8,6 +8,7 @@
+ #include <linux/clk.h>
+ #include <linux/cpu.h>
+ #include <linux/cpufreq.h>
++#include <linux/math64.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_opp.h>
+@@ -22,6 +23,7 @@ static int raspberrypi_cpufreq_probe(str
+ unsigned long min, max;
+ unsigned long rate;
+ struct clk *clk;
++ int div;
+ int ret;
+
+ cpu_dev = get_cpu_device(0);
+@@ -44,7 +46,10 @@ static int raspberrypi_cpufreq_probe(str
+ max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL);
+ clk_put(clk);
+
+- for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) {
++ for (div = 2; ; div++) {
++ rate = div_u64((u64)max * 2, div);
++ if (rate < min)
++ break;
+ ret = dev_pm_opp_add(cpu_dev, rate, 0);
+ if (ret)
+ goto remove_opp;
-From 05c745c001c8c82bbba8a6d953ad77ad25c92c5f Mon Sep 17 00:00:00 2001
+From afb2cfe3056fc643cee8ae25991f4b9c22d48bef Mon Sep 17 00:00:00 2001
-Date: Thu, 7 Nov 2019 14:11:08 +0000
+Date: Thu, 7 Nov 2019 14:23:38 +0000
Subject: [PATCH] fixup! clk-raspberrypi: Also support v3d clock
---
- drivers/clk/bcm/clk-raspberrypi.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
+ drivers/clk/bcm/clk-raspberrypi.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
--- a/drivers/clk/bcm/clk-raspberrypi.c
+++ b/drivers/clk/bcm/clk-raspberrypi.c
-@@ -351,21 +351,21 @@ static const struct clk_ops raspberrypi_
+@@ -208,6 +208,9 @@ static int raspberrypi_determine_rate(st
+ u32 clock_id, const char *name, unsigned long min_rate, unsigned long max_rate,
+ struct clk_rate_request *req)
+ {
++#if 1
++ req->rate = clamp(req->rate, min_rate, max_rate);
++#else
+ u64 div, final_rate;
+ u32 ndiv, fdiv;
+
+@@ -225,6 +228,7 @@ static int raspberrypi_determine_rate(st
+
+ req->rate = final_rate >> A2W_PLL_FRAC_BITS;
+
++#endif
+ return 0;
+ }
+
+@@ -351,21 +355,21 @@ static const struct clk_ops raspberrypi_
.is_prepared = raspberrypi_fw_pll_is_on,
.recalc_rate = raspberrypi_fw_pll_get_rate,
.set_rate = raspberrypi_fw_pll_set_rate,
-- .determine_rate = raspberrypi_pll_determine_rate,
-+ //.determine_rate = raspberrypi_pll_determine_rate,
+- //.determine_rate = raspberrypi_pll_determine_rate,
++ .determine_rate = raspberrypi_pll_determine_rate,
};
static const struct clk_ops raspberrypi_firmware_pll_divider_clk_ops = {
.is_prepared = raspberrypi_fw_pll_div_is_on,
.recalc_rate = raspberrypi_fw_pll_div_get_rate,
.set_rate = raspberrypi_fw_pll_div_set_rate,
-- .determine_rate = raspberrypi_pll_div_determine_rate,
-+ //.determine_rate = raspberrypi_pll_div_determine_rate,
+- //.determine_rate = raspberrypi_pll_div_determine_rate,
++ .determine_rate = raspberrypi_pll_div_determine_rate,
};
static const struct clk_ops raspberrypi_firmware_clk_ops = {
.is_prepared = raspberrypi_fw_clock_is_on,
.recalc_rate = raspberrypi_fw_clock_get_rate,
.set_rate = raspberrypi_fw_clock_set_rate,
-- .determine_rate = raspberrypi_clock_determine_rate,
-+ //.determine_rate = raspberrypi_clock_determine_rate,
+- //.determine_rate = raspberrypi_clock_determine_rate,
++ .determine_rate = raspberrypi_clock_determine_rate,
};
--- /dev/null
+From ea1e25b4c0a055b31a0217ffbfd6972c28643912 Mon Sep 17 00:00:00 2001
+Date: Fri, 22 Nov 2019 15:08:25 +0000
+Subject: [PATCH] arm/dts: Correct Pi 4B LED values
+
+The initial PHY LED settings are wrong Pi 4B (the correct values got
+dropped somewhere along the way). The PHY declaration should arguably
+go in a separate file included by bcm2711-rpi-4-b.dts, but we can
+fix that as we switch over to using more of the upstream BCM2711
+support in 5.4 and later.
+
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 2 +-
+ arch/arm/boot/dts/overlays/README | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -380,7 +380,7 @@
+ /* No interrupts - use PHY_POLL */
+ max-speed = <1000>;
+ reg = <0x1>;
+- led-modes = <0x02 0x02>;
++ led-modes = <0x00 0x08>; /* link/activity link */
+ };
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -128,7 +128,7 @@ Params:
+ 8=Link 9=Activity
+
+ eth_led1 Set mode of LED1 (usually green) (Pi3B+ default
+- "6", Pi4 default "0"). See eth_led0 for legal
++ "6", Pi4 default "8"). See eth_led0 for legal
+ values.
+
+ eth_max_speed Set the maximum speed a link is allowed
+++ /dev/null
-From 1c038a58f4183602fc1699d68b21f5e22a12176d Mon Sep 17 00:00:00 2001
-Date: Fri, 13 Sep 2019 13:45:11 +0100
-Subject: [PATCH] raspberrypi-cpufreq: Only report integer pll divisor
- frequencies
-
----
- drivers/cpufreq/raspberrypi-cpufreq.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
---- a/drivers/cpufreq/raspberrypi-cpufreq.c
-+++ b/drivers/cpufreq/raspberrypi-cpufreq.c
-@@ -8,6 +8,7 @@
- #include <linux/clk.h>
- #include <linux/cpu.h>
- #include <linux/cpufreq.h>
-+#include <linux/math64.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/pm_opp.h>
-@@ -22,6 +23,7 @@ static int raspberrypi_cpufreq_probe(str
- unsigned long min, max;
- unsigned long rate;
- struct clk *clk;
-+ int div;
- int ret;
-
- cpu_dev = get_cpu_device(0);
-@@ -44,7 +46,10 @@ static int raspberrypi_cpufreq_probe(str
- max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL);
- clk_put(clk);
-
-- for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) {
-+ for (div = 2; ; div++) {
-+ rate = div_u64((u64)max * 2, div);
-+ if (rate < min)
-+ break;
- ret = dev_pm_opp_add(cpu_dev, rate, 0);
- if (ret)
- goto remove_opp;
--- /dev/null
+From 75e50217c8c8d9ab8dc84547fd149d9bfe32ae5d Mon Sep 17 00:00:00 2001
+Date: Fri, 22 Nov 2019 16:23:32 +0000
+Subject: [PATCH] drm/v3d: Set dma_mask as well as coherent_dma_mask
+
+Both coherent_dma_mask and dma_mask act as constraints on allocations
+and bounce buffer usage, so be sure to set dma_mask to the appropriate
+value otherwise the effective mask could be incorrect.
+
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -261,7 +261,7 @@ static int v3d_platform_drm_probe(struct
+ int ret;
+ u32 ident1;
+
+- dev->coherent_dma_mask = DMA_BIT_MASK(36);
++ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
+
+ v3d = kzalloc(sizeof(*v3d), GFP_KERNEL);
+ if (!v3d)
+++ /dev/null
-From afb2cfe3056fc643cee8ae25991f4b9c22d48bef Mon Sep 17 00:00:00 2001
-Date: Thu, 7 Nov 2019 14:23:38 +0000
-Subject: [PATCH] fixup! clk-raspberrypi: Also support v3d clock
-
----
- drivers/clk/bcm/clk-raspberrypi.c | 10 +++++++---
- 1 file changed, 7 insertions(+), 3 deletions(-)
-
---- a/drivers/clk/bcm/clk-raspberrypi.c
-+++ b/drivers/clk/bcm/clk-raspberrypi.c
-@@ -208,6 +208,9 @@ static int raspberrypi_determine_rate(st
- u32 clock_id, const char *name, unsigned long min_rate, unsigned long max_rate,
- struct clk_rate_request *req)
- {
-+#if 1
-+ req->rate = clamp(req->rate, min_rate, max_rate);
-+#else
- u64 div, final_rate;
- u32 ndiv, fdiv;
-
-@@ -225,6 +228,7 @@ static int raspberrypi_determine_rate(st
-
- req->rate = final_rate >> A2W_PLL_FRAC_BITS;
-
-+#endif
- return 0;
- }
-
-@@ -351,21 +355,21 @@ static const struct clk_ops raspberrypi_
- .is_prepared = raspberrypi_fw_pll_is_on,
- .recalc_rate = raspberrypi_fw_pll_get_rate,
- .set_rate = raspberrypi_fw_pll_set_rate,
-- //.determine_rate = raspberrypi_pll_determine_rate,
-+ .determine_rate = raspberrypi_pll_determine_rate,
- };
-
- static const struct clk_ops raspberrypi_firmware_pll_divider_clk_ops = {
- .is_prepared = raspberrypi_fw_pll_div_is_on,
- .recalc_rate = raspberrypi_fw_pll_div_get_rate,
- .set_rate = raspberrypi_fw_pll_div_set_rate,
-- //.determine_rate = raspberrypi_pll_div_determine_rate,
-+ .determine_rate = raspberrypi_pll_div_determine_rate,
- };
-
- static const struct clk_ops raspberrypi_firmware_clk_ops = {
- .is_prepared = raspberrypi_fw_clock_is_on,
- .recalc_rate = raspberrypi_fw_clock_get_rate,
- .set_rate = raspberrypi_fw_clock_set_rate,
-- //.determine_rate = raspberrypi_clock_determine_rate,
-+ .determine_rate = raspberrypi_clock_determine_rate,
- };
-
-
--- /dev/null
+From 11febee7b0326ade03f45238f136b7830d317e2e Mon Sep 17 00:00:00 2001
+Date: Thu, 28 Nov 2019 15:49:08 +0000
+Subject: [PATCH] arm/dts: 2711: Add 'pcie0' alias
+
+It is useful for the firmware to be able to locate the pcie DT node,
+so add an alias pointing to it in the same way that "ethernet0"
+points to the genet.
+
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -30,6 +30,7 @@
+ /delete-property/ ethernet;
+ /delete-property/ intc;
+ ethernet0 = &genet;
++ pcie0 = &pcie_0;
+ };
+ };
+
+++ /dev/null
-From ea1e25b4c0a055b31a0217ffbfd6972c28643912 Mon Sep 17 00:00:00 2001
-Date: Fri, 22 Nov 2019 15:08:25 +0000
-Subject: [PATCH] arm/dts: Correct Pi 4B LED values
-
-The initial PHY LED settings are wrong Pi 4B (the correct values got
-dropped somewhere along the way). The PHY declaration should arguably
-go in a separate file included by bcm2711-rpi-4-b.dts, but we can
-fix that as we switch over to using more of the upstream BCM2711
-support in 5.4 and later.
-
----
- arch/arm/boot/dts/bcm2838.dtsi | 2 +-
- arch/arm/boot/dts/overlays/README | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -380,7 +380,7 @@
- /* No interrupts - use PHY_POLL */
- max-speed = <1000>;
- reg = <0x1>;
-- led-modes = <0x02 0x02>;
-+ led-modes = <0x00 0x08>; /* link/activity link */
- };
- };
- };
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -128,7 +128,7 @@ Params:
- 8=Link 9=Activity
-
- eth_led1 Set mode of LED1 (usually green) (Pi3B+ default
-- "6", Pi4 default "0"). See eth_led0 for legal
-+ "6", Pi4 default "8"). See eth_led0 for legal
- values.
-
- eth_max_speed Set the maximum speed a link is allowed
+++ /dev/null
-From 75e50217c8c8d9ab8dc84547fd149d9bfe32ae5d Mon Sep 17 00:00:00 2001
-Date: Fri, 22 Nov 2019 16:23:32 +0000
-Subject: [PATCH] drm/v3d: Set dma_mask as well as coherent_dma_mask
-
-Both coherent_dma_mask and dma_mask act as constraints on allocations
-and bounce buffer usage, so be sure to set dma_mask to the appropriate
-value otherwise the effective mask could be incorrect.
-
----
- drivers/gpu/drm/v3d/v3d_drv.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -261,7 +261,7 @@ static int v3d_platform_drm_probe(struct
- int ret;
- u32 ident1;
-
-- dev->coherent_dma_mask = DMA_BIT_MASK(36);
-+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
-
- v3d = kzalloc(sizeof(*v3d), GFP_KERNEL);
- if (!v3d)
--- /dev/null
+From ce0e4cf60033eb7e15266b329183f945f2a82c61 Mon Sep 17 00:00:00 2001
+Date: Mon, 2 Dec 2019 10:28:44 +0000
+Subject: [PATCH] spidev: Completely disable the DT warning
+
+The upstream SPI and DT maintainers are completely opposed to declaring
+in Device Tree that an SPI CS line is to be managed by the spidev
+driver, even though the facility is useful on a hobbyist device like a
+Raspberry Pi where arbitrary devices can be attached, and the
+alternative to DT declaration (spi_board_info) has been almost entirely
+rendered obsolete by DT.
+
+Continue to override their objections by disabling the warning.
+
+See: https://github.com/raspberrypi/linux/issues/3361
+ https://github.com/raspberrypi/linux/issues/1054
+
+---
+ drivers/spi/spidev.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/spi/spidev.c
++++ b/drivers/spi/spidev.c
+@@ -728,6 +728,7 @@ static int spidev_probe(struct spi_devic
+ * compatible string, it is a Linux implementation thing
+ * rather than a description of the hardware.
+ */
++ if (0) /* Disable the warning - this feature is too useful */
+ WARN(spi->dev.of_node &&
+ of_device_is_compatible(spi->dev.of_node, "spidev"),
+ "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);
+++ /dev/null
-From 11febee7b0326ade03f45238f136b7830d317e2e Mon Sep 17 00:00:00 2001
-Date: Thu, 28 Nov 2019 15:49:08 +0000
-Subject: [PATCH] arm/dts: 2711: Add 'pcie0' alias
-
-It is useful for the firmware to be able to locate the pcie DT node,
-so add an alias pointing to it in the same way that "ethernet0"
-points to the genet.
-
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -30,6 +30,7 @@
- /delete-property/ ethernet;
- /delete-property/ intc;
- ethernet0 = &genet;
-+ pcie0 = &pcie_0;
- };
- };
-
--- /dev/null
+From 7140cf0d83c10f93ca8212edb17697baf9cafb45 Mon Sep 17 00:00:00 2001
+Date: Mon, 1 Apr 2019 11:35:59 -0700
+Subject: [PATCH] drm/vc4: Disable V3D interactions if the v3d
+ component didn't probe.
+
+Commit ffc26740714962e3e8801dca7ef32b636b3781db upstream.
+
+One might want to use the VC4 display stack without using Mesa.
+Similar to the debugfs fixes for not having all of the possible
+display bits enabled, make sure you can't oops in vc4 if v3d isn't
+enabled.
+
+v2: Fix matching against other v3d variants (review by Paul), don't
+ forget to set irq_enabled so that the vblank uapi works
+v3: Use -ENODEV instead of -EINVAL on Paul's suggestion.
+
+---
+ drivers/gpu/drm/vc4/vc4_drv.c | 10 ++++++++++
+ drivers/gpu/drm/vc4/vc4_drv.h | 1 +
+ drivers/gpu/drm/vc4/vc4_gem.c | 10 ++++++++++
+ drivers/gpu/drm/vc4/vc4_irq.c | 9 +++++++++
+ drivers/gpu/drm/vc4/vc4_perfmon.c | 18 ++++++++++++++++++
+ drivers/gpu/drm/vc4/vc4_v3d.c | 2 +-
+ 6 files changed, 49 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.c
++++ b/drivers/gpu/drm/vc4/vc4_drv.c
+@@ -71,6 +71,9 @@ static int vc4_get_param_ioctl(struct dr
+ if (args->pad != 0)
+ return -EINVAL;
+
++ if (!vc4->v3d)
++ return -ENODEV;
++
+ switch (args->param) {
+ case DRM_VC4_PARAM_V3D_IDENT0:
+ ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev);
+@@ -271,6 +274,7 @@ static int vc4_drm_bind(struct device *d
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm;
+ struct vc4_dev *vc4;
++ struct device_node *node;
+ int ret = 0;
+
+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
+@@ -279,6 +283,12 @@ static int vc4_drm_bind(struct device *d
+ if (!vc4)
+ return -ENOMEM;
+
++ /* If VC4 V3D is missing, don't advertise render nodes. */
++ node = of_find_matching_node_and_match(NULL, vc4_v3d_dt_match, NULL);
++ if (!node || !of_device_is_available(node))
++ vc4_drm_driver.driver_features &= ~DRIVER_RENDER;
++ of_node_put(node);
++
+ drm = drm_dev_alloc(&vc4_drm_driver, dev);
+ if (IS_ERR(drm))
+ return PTR_ERR(drm);
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -787,6 +787,7 @@ void vc4_plane_async_set_fb(struct drm_p
+
+ /* vc4_v3d.c */
+ extern struct platform_driver vc4_v3d_driver;
++extern const struct of_device_id vc4_v3d_dt_match[];
+ int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused);
+ int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused);
+ int vc4_v3d_get_bin_slot(struct vc4_dev *vc4);
+--- a/drivers/gpu/drm/vc4/vc4_gem.c
++++ b/drivers/gpu/drm/vc4/vc4_gem.c
+@@ -74,6 +74,11 @@ vc4_get_hang_state_ioctl(struct drm_devi
+ u32 i;
+ int ret = 0;
+
++ if (!vc4->v3d) {
++ DRM_DEBUG("VC4_GET_HANG_STATE with no VC4 V3D probed\n");
++ return -ENODEV;
++ }
++
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
+ kernel_state = vc4->hang_state;
+ if (!kernel_state) {
+@@ -1124,6 +1129,11 @@ vc4_submit_cl_ioctl(struct drm_device *d
+ struct dma_fence *in_fence;
+ int ret = 0;
+
++ if (!vc4->v3d) {
++ DRM_DEBUG("VC4_SUBMIT_CL with no VC4 V3D probed\n");
++ return -ENODEV;
++ }
++
+ if ((args->flags & ~(VC4_SUBMIT_CL_USE_CLEAR_COLOR |
+ VC4_SUBMIT_CL_FIXED_RCL_ORDER |
+ VC4_SUBMIT_CL_RCL_ORDER_INCREASING_X |
+--- a/drivers/gpu/drm/vc4/vc4_irq.c
++++ b/drivers/gpu/drm/vc4/vc4_irq.c
+@@ -229,6 +229,9 @@ vc4_irq_preinstall(struct drm_device *de
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
++ if (!vc4->v3d)
++ return;
++
+ init_waitqueue_head(&vc4->job_wait_queue);
+ INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work);
+
+@@ -243,6 +246,9 @@ vc4_irq_postinstall(struct drm_device *d
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
++ if (!vc4->v3d)
++ return 0;
++
+ /* Enable both the render done and out of memory interrupts. */
+ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS);
+
+@@ -254,6 +260,9 @@ vc4_irq_uninstall(struct drm_device *dev
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+
++ if (!vc4->v3d)
++ return;
++
+ /* Disable sending interrupts for our driver's IRQs. */
+ V3D_WRITE(V3D_INTDIS, V3D_DRIVER_IRQS);
+
+--- a/drivers/gpu/drm/vc4/vc4_perfmon.c
++++ b/drivers/gpu/drm/vc4/vc4_perfmon.c
+@@ -100,12 +100,18 @@ void vc4_perfmon_close_file(struct vc4_f
+ int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+ {
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_file *vc4file = file_priv->driver_priv;
+ struct drm_vc4_perfmon_create *req = data;
+ struct vc4_perfmon *perfmon;
+ unsigned int i;
+ int ret;
+
++ if (!vc4->v3d) {
++ DRM_DEBUG("Creating perfmon no VC4 V3D probed\n");
++ return -ENODEV;
++ }
++
+ /* Number of monitored counters cannot exceed HW limits. */
+ if (req->ncounters > DRM_VC4_MAX_PERF_COUNTERS ||
+ !req->ncounters)
+@@ -146,10 +152,16 @@ int vc4_perfmon_create_ioctl(struct drm_
+ int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+ {
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_file *vc4file = file_priv->driver_priv;
+ struct drm_vc4_perfmon_destroy *req = data;
+ struct vc4_perfmon *perfmon;
+
++ if (!vc4->v3d) {
++ DRM_DEBUG("Destroying perfmon no VC4 V3D probed\n");
++ return -ENODEV;
++ }
++
+ mutex_lock(&vc4file->perfmon.lock);
+ perfmon = idr_remove(&vc4file->perfmon.idr, req->id);
+ mutex_unlock(&vc4file->perfmon.lock);
+@@ -164,11 +176,17 @@ int vc4_perfmon_destroy_ioctl(struct drm
+ int vc4_perfmon_get_values_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+ {
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_file *vc4file = file_priv->driver_priv;
+ struct drm_vc4_perfmon_get_values *req = data;
+ struct vc4_perfmon *perfmon;
+ int ret;
+
++ if (!vc4->v3d) {
++ DRM_DEBUG("Getting perfmon no VC4 V3D probed\n");
++ return -ENODEV;
++ }
++
+ mutex_lock(&vc4file->perfmon.lock);
+ perfmon = idr_find(&vc4file->perfmon.idr, req->id);
+ vc4_perfmon_get(perfmon);
+--- a/drivers/gpu/drm/vc4/vc4_v3d.c
++++ b/drivers/gpu/drm/vc4/vc4_v3d.c
+@@ -452,7 +452,7 @@ static int vc4_v3d_dev_remove(struct pla
+ return 0;
+ }
+
+-static const struct of_device_id vc4_v3d_dt_match[] = {
++const struct of_device_id vc4_v3d_dt_match[] = {
+ { .compatible = "brcm,bcm2835-v3d" },
+ { .compatible = "brcm,cygnus-v3d" },
+ { .compatible = "brcm,vc4-v3d" },
--- /dev/null
+From 4ca89eb8570cb86314a5a7b55a15d15f53ce5757 Mon Sep 17 00:00:00 2001
+Date: Sat, 16 Nov 2019 12:41:06 +0100
+Subject: [PATCH] sound/soc: only first codec is master in multicodec
+ setup
+
+When using multiple codecs, at most one codec should generate the master
+clock. All codecs except the first are therefore configured for slave
+mode.
+
+---
+ sound/soc/soc-core.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/soc-core.c
++++ b/sound/soc/soc-core.c
+@@ -1688,8 +1688,15 @@ int snd_soc_runtime_set_dai_fmt(struct s
+
+ for (i = 0; i < rtd->num_codecs; i++) {
+ struct snd_soc_dai *codec_dai = codec_dais[i];
++ unsigned int codec_dai_fmt = dai_fmt;
+
+- ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
++ // there can only be one master when using multiple codecs
++ if (i && (codec_dai_fmt & SND_SOC_DAIFMT_MASTER_MASK)) {
++ codec_dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
++ codec_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
++ }
++
++ ret = snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+ if (ret != 0 && ret != -ENOTSUPP) {
+ dev_warn(codec_dai->dev,
+ "ASoC: Failed to set DAI format: %d\n", ret);
+++ /dev/null
-From ce0e4cf60033eb7e15266b329183f945f2a82c61 Mon Sep 17 00:00:00 2001
-Date: Mon, 2 Dec 2019 10:28:44 +0000
-Subject: [PATCH] spidev: Completely disable the DT warning
-
-The upstream SPI and DT maintainers are completely opposed to declaring
-in Device Tree that an SPI CS line is to be managed by the spidev
-driver, even though the facility is useful on a hobbyist device like a
-Raspberry Pi where arbitrary devices can be attached, and the
-alternative to DT declaration (spi_board_info) has been almost entirely
-rendered obsolete by DT.
-
-Continue to override their objections by disabling the warning.
-
-See: https://github.com/raspberrypi/linux/issues/3361
- https://github.com/raspberrypi/linux/issues/1054
-
----
- drivers/spi/spidev.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/spi/spidev.c
-+++ b/drivers/spi/spidev.c
-@@ -728,6 +728,7 @@ static int spidev_probe(struct spi_devic
- * compatible string, it is a Linux implementation thing
- * rather than a description of the hardware.
- */
-+ if (0) /* Disable the warning - this feature is too useful */
- WARN(spi->dev.of_node &&
- of_device_is_compatible(spi->dev.of_node, "spidev"),
- "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);
--- /dev/null
+From 8f11db84e124da59b8a717d66fc424ef070f4be0 Mon Sep 17 00:00:00 2001
+Date: Sat, 16 Nov 2019 13:14:43 +0100
+Subject: [PATCH] Allow simultaneous use of JustBoom DAC and Digi
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 20 ++
+ .../dts/overlays/justboom-both-overlay.dts | 65 +++++
+ sound/soc/bcm/Kconfig | 12 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/justboom-both.c | 269 ++++++++++++++++++
+ 11 files changed, 374 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/justboom-both-overlay.dts
+ create mode 100644 sound/soc/bcm/justboom-both.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -86,6 +86,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ iqaudio-digi-wm8804-audio.dtbo \
+ irs1125.dtbo \
+ jedec-spi-nor.dtbo \
++ justboom-both.dtbo \
+ justboom-dac.dtbo \
+ justboom-digi.dtbo \
+ ltc294x.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1388,6 +1388,26 @@ Params: flash-spi<n>-<m> Enables
+ on SPI<n>, CS#<m>.
+
+
++Name: justboom-both
++Info: Simultaneous usage of an justboom-dac and justboom-digi based
++ card
++Load: dtoverlay=justboom-both,<param>=<val>
++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
++ Digital volume control. Enable with
++ "dtoverlay=justboom-dac,24db_digital_gain"
++ (The default behaviour is that the Digital
++ volume control is limited to a maximum of
++ 0dB. ie. it can attenuate but not provide
++ gain. For most users, this will be desired
++ as it will prevent clipping. By appending
++ the 24dB_digital_gain parameter, the Digital
++ volume control will allow up to 24dB of
++ gain. If this parameter is enabled, it is the
++ responsibility of the user to ensure that
++ the Digital volume control is set to a value
++ that does not result in clipping/distortion!)
++
++
+ Name: justboom-dac
+ Info: Configures the JustBoom DAC HAT, Amp HAT, DAC Zero and Amp Zero audio
+ cards
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/justboom-both-overlay.dts
+@@ -0,0 +1,65 @@
++// SPDX-License-Identifier: GPL-2.0
++// Definitions for JustBoom Both (Digi+DAC)
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ wm8804@3b {
++ #sound-dai-cells = <0>;
++ compatible = "wlf,wm8804";
++ reg = <0x3b>;
++ PVDD-supply = <&vdd_3v3_reg>;
++ DVDD-supply = <&vdd_3v3_reg>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm5122@4d {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm5122";
++ reg = <0x4d>;
++ AVDD-supply = <&vdd_3v3_reg>;
++ DVDD-supply = <&vdd_3v3_reg>;
++ CPVDD-supply = <&vdd_3v3_reg>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&sound>;
++ frag3: __overlay__ {
++ compatible = "justboom,justboom-both";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ 24db_digital_gain = <&frag3>,"justboom,24db_digital_gain?";
++ };
++};
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -102,6 +102,18 @@ config SND_BCM2708_SOC_RPI_PROTO
+ help
+ Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
+
++config SND_BCM2708_SOC_JUSTBOOM_BOTH
++ tristate "Support for simultaneous JustBoom Digi and JustBoom DAC"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_WM8804
++ select SND_SOC_PCM512x
++ help
++ Say Y or M if you want to add support for simultaneous
++ JustBoom Digi and JustBoom DAC.
++
++ This is not the right choice if you only have one but both of
++ these cards.
++
+ config SND_BCM2708_SOC_JUSTBOOM_DAC
+ tristate "Support for JustBoom DAC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -16,6 +16,7 @@ snd-soc-hifiberry-dacplus-objs := hifibe
+ snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
+ snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
+ snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
++snd-soc-justboom-both-objs := justboom-both.o
+ snd-soc-justboom-dac-objs := justboom-dac.o
+ snd-soc-rpi-cirrus-objs := rpi-cirrus.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+@@ -42,6 +43,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
++obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH) += snd-soc-justboom-both.o
+ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+--- /dev/null
++++ b/sound/soc/bcm/justboom-both.c
+@@ -0,0 +1,269 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard.
++ *
++ *
++ * Driver for when connecting simultaneously justboom-digi and justboom-dac
++ *
++ * Based upon code from:
++ * justboom-digi.c
++ * justboom-dac.c
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++#include "../codecs/wm8804.h"
++#include "../codecs/pcm512x.h"
++
++
++static bool digital_gain_0db_limit = true;
++
++static int snd_rpi_justboom_both_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
++ struct snd_soc_component *dac = rtd->codec_dais[1]->component;
++
++ /* enable TX output */
++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0);
++
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++
++ if (digital_gain_0db_limit) {
++ int ret;
++ struct snd_soc_card *card = rtd->card;
++
++ ret = snd_soc_limit_volume(card, "Digital Playback Volume",
++ 207);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to set volume limit: %d\n",
++ ret);
++ }
++
++ return 0;
++}
++
++static int snd_rpi_justboom_both_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ int sysclk = 27000000; /* This is fixed on this board */
++
++ long mclk_freq = 0;
++ int mclk_div = 1;
++ int sampling_freq = 1;
++
++ int ret;
++
++ int samplerate = params_rate(params);
++
++ if (samplerate <= 96000) {
++ mclk_freq = samplerate*256;
++ mclk_div = WM8804_MCLKDIV_256FS;
++ } else {
++ mclk_freq = samplerate*128;
++ mclk_div = WM8804_MCLKDIV_128FS;
++ }
++
++ switch (samplerate) {
++ case 32000:
++ sampling_freq = 0x03;
++ break;
++ case 44100:
++ sampling_freq = 0x00;
++ break;
++ case 48000:
++ sampling_freq = 0x02;
++ break;
++ case 88200:
++ sampling_freq = 0x08;
++ break;
++ case 96000:
++ sampling_freq = 0x0a;
++ break;
++ case 176400:
++ sampling_freq = 0x0c;
++ break;
++ case 192000:
++ sampling_freq = 0x0e;
++ break;
++ default:
++ dev_err(rtd->card->dev,
++ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
++ samplerate);
++ }
++
++ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
++ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
++
++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
++ sysclk, SND_SOC_CLOCK_OUT);
++ if (ret < 0) {
++ dev_err(rtd->card->dev,
++ "Failed to set WM8804 SYSCLK: %d\n", ret);
++ return ret;
++ }
++
++ /* Enable TX output */
++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0);
++
++ /* Power on */
++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x9, 0);
++
++ /* set sampling frequency status bits */
++ snd_soc_component_update_bits(digi, WM8804_SPDTX4, 0x0f, sampling_freq);
++
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
++}
++
++static int snd_rpi_justboom_both_startup(struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
++ struct snd_soc_component *dac = rtd->codec_dais[1]->component;
++
++ /* turn on digital output */
++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x00);
++
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++
++ return 0;
++}
++
++static void snd_rpi_justboom_both_shutdown(struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
++ struct snd_soc_component *dac = rtd->codec_dais[1]->component;
++
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++
++ /* turn off output */
++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x3c);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_justboom_both_ops = {
++ .hw_params = snd_rpi_justboom_both_hw_params,
++ .startup = snd_rpi_justboom_both_startup,
++ .shutdown = snd_rpi_justboom_both_shutdown,
++};
++
++static struct snd_soc_dai_link_component justboom_both_codecs[] = {
++{
++ .dai_name = "wm8804-spdif",
++ .name = "wm8804.1-003b",
++},
++{
++ .dai_name = "pcm512x-hifi",
++ .name = "pcm512x.1-004d",
++},
++};
++
++static struct snd_soc_dai_link snd_rpi_justboom_both_dai[] = {
++{
++ .name = "JustBoom Digi",
++ .stream_name = "JustBoom Digi HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .platform_name = "bcm2708-i2s.0",
++ .codecs = justboom_both_codecs,
++ .num_codecs = ARRAY_SIZE(justboom_both_codecs),
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM,
++ .ops = &snd_rpi_justboom_both_ops,
++ .init = snd_rpi_justboom_both_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_justboom_both = {
++ .name = "snd_rpi_justboom_both",
++ .driver_name = "JustBoomBoth",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_justboom_both_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_justboom_both_dai),
++};
++
++static int snd_rpi_justboom_both_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ snd_rpi_justboom_both.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_justboom_both_dai[0];
++
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++
++ digital_gain_0db_limit = !of_property_read_bool(
++ pdev->dev.of_node, "justboom,24db_digital_gain");
++ }
++
++ ret = snd_soc_register_card(&snd_rpi_justboom_both);
++ if (ret && ret != -EPROBE_DEFER) {
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++ }
++
++ return ret;
++}
++
++static int snd_rpi_justboom_both_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_justboom_both);
++}
++
++static const struct of_device_id snd_rpi_justboom_both_of_match[] = {
++ { .compatible = "justboom,justboom-both", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_justboom_both_of_match);
++
++static struct platform_driver snd_rpi_justboom_both_driver = {
++ .driver = {
++ .name = "snd-rpi-justboom-both",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_justboom_both_of_match,
++ },
++ .probe = snd_rpi_justboom_both_probe,
++ .remove = snd_rpi_justboom_both_remove,
++};
++
++module_platform_driver(snd_rpi_justboom_both_driver);
++
++MODULE_DESCRIPTION("ASoC Driver for simultaneous use of JustBoom PI Digi & DAC HAT Sound Cards");
++MODULE_LICENSE("GPL v2");
+++ /dev/null
-From 7140cf0d83c10f93ca8212edb17697baf9cafb45 Mon Sep 17 00:00:00 2001
-Date: Mon, 1 Apr 2019 11:35:59 -0700
-Subject: [PATCH] drm/vc4: Disable V3D interactions if the v3d
- component didn't probe.
-
-Commit ffc26740714962e3e8801dca7ef32b636b3781db upstream.
-
-One might want to use the VC4 display stack without using Mesa.
-Similar to the debugfs fixes for not having all of the possible
-display bits enabled, make sure you can't oops in vc4 if v3d isn't
-enabled.
-
-v2: Fix matching against other v3d variants (review by Paul), don't
- forget to set irq_enabled so that the vblank uapi works
-v3: Use -ENODEV instead of -EINVAL on Paul's suggestion.
-
----
- drivers/gpu/drm/vc4/vc4_drv.c | 10 ++++++++++
- drivers/gpu/drm/vc4/vc4_drv.h | 1 +
- drivers/gpu/drm/vc4/vc4_gem.c | 10 ++++++++++
- drivers/gpu/drm/vc4/vc4_irq.c | 9 +++++++++
- drivers/gpu/drm/vc4/vc4_perfmon.c | 18 ++++++++++++++++++
- drivers/gpu/drm/vc4/vc4_v3d.c | 2 +-
- 6 files changed, 49 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_drv.c
-+++ b/drivers/gpu/drm/vc4/vc4_drv.c
-@@ -71,6 +71,9 @@ static int vc4_get_param_ioctl(struct dr
- if (args->pad != 0)
- return -EINVAL;
-
-+ if (!vc4->v3d)
-+ return -ENODEV;
-+
- switch (args->param) {
- case DRM_VC4_PARAM_V3D_IDENT0:
- ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev);
-@@ -271,6 +274,7 @@ static int vc4_drm_bind(struct device *d
- struct platform_device *pdev = to_platform_device(dev);
- struct drm_device *drm;
- struct vc4_dev *vc4;
-+ struct device_node *node;
- int ret = 0;
-
- dev->coherent_dma_mask = DMA_BIT_MASK(32);
-@@ -279,6 +283,12 @@ static int vc4_drm_bind(struct device *d
- if (!vc4)
- return -ENOMEM;
-
-+ /* If VC4 V3D is missing, don't advertise render nodes. */
-+ node = of_find_matching_node_and_match(NULL, vc4_v3d_dt_match, NULL);
-+ if (!node || !of_device_is_available(node))
-+ vc4_drm_driver.driver_features &= ~DRIVER_RENDER;
-+ of_node_put(node);
-+
- drm = drm_dev_alloc(&vc4_drm_driver, dev);
- if (IS_ERR(drm))
- return PTR_ERR(drm);
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -787,6 +787,7 @@ void vc4_plane_async_set_fb(struct drm_p
-
- /* vc4_v3d.c */
- extern struct platform_driver vc4_v3d_driver;
-+extern const struct of_device_id vc4_v3d_dt_match[];
- int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused);
- int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused);
- int vc4_v3d_get_bin_slot(struct vc4_dev *vc4);
---- a/drivers/gpu/drm/vc4/vc4_gem.c
-+++ b/drivers/gpu/drm/vc4/vc4_gem.c
-@@ -74,6 +74,11 @@ vc4_get_hang_state_ioctl(struct drm_devi
- u32 i;
- int ret = 0;
-
-+ if (!vc4->v3d) {
-+ DRM_DEBUG("VC4_GET_HANG_STATE with no VC4 V3D probed\n");
-+ return -ENODEV;
-+ }
-+
- spin_lock_irqsave(&vc4->job_lock, irqflags);
- kernel_state = vc4->hang_state;
- if (!kernel_state) {
-@@ -1124,6 +1129,11 @@ vc4_submit_cl_ioctl(struct drm_device *d
- struct dma_fence *in_fence;
- int ret = 0;
-
-+ if (!vc4->v3d) {
-+ DRM_DEBUG("VC4_SUBMIT_CL with no VC4 V3D probed\n");
-+ return -ENODEV;
-+ }
-+
- if ((args->flags & ~(VC4_SUBMIT_CL_USE_CLEAR_COLOR |
- VC4_SUBMIT_CL_FIXED_RCL_ORDER |
- VC4_SUBMIT_CL_RCL_ORDER_INCREASING_X |
---- a/drivers/gpu/drm/vc4/vc4_irq.c
-+++ b/drivers/gpu/drm/vc4/vc4_irq.c
-@@ -229,6 +229,9 @@ vc4_irq_preinstall(struct drm_device *de
- {
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-
-+ if (!vc4->v3d)
-+ return;
-+
- init_waitqueue_head(&vc4->job_wait_queue);
- INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work);
-
-@@ -243,6 +246,9 @@ vc4_irq_postinstall(struct drm_device *d
- {
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-
-+ if (!vc4->v3d)
-+ return 0;
-+
- /* Enable both the render done and out of memory interrupts. */
- V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS);
-
-@@ -254,6 +260,9 @@ vc4_irq_uninstall(struct drm_device *dev
- {
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-
-+ if (!vc4->v3d)
-+ return;
-+
- /* Disable sending interrupts for our driver's IRQs. */
- V3D_WRITE(V3D_INTDIS, V3D_DRIVER_IRQS);
-
---- a/drivers/gpu/drm/vc4/vc4_perfmon.c
-+++ b/drivers/gpu/drm/vc4/vc4_perfmon.c
-@@ -100,12 +100,18 @@ void vc4_perfmon_close_file(struct vc4_f
- int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
- {
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct vc4_file *vc4file = file_priv->driver_priv;
- struct drm_vc4_perfmon_create *req = data;
- struct vc4_perfmon *perfmon;
- unsigned int i;
- int ret;
-
-+ if (!vc4->v3d) {
-+ DRM_DEBUG("Creating perfmon no VC4 V3D probed\n");
-+ return -ENODEV;
-+ }
-+
- /* Number of monitored counters cannot exceed HW limits. */
- if (req->ncounters > DRM_VC4_MAX_PERF_COUNTERS ||
- !req->ncounters)
-@@ -146,10 +152,16 @@ int vc4_perfmon_create_ioctl(struct drm_
- int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
- {
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct vc4_file *vc4file = file_priv->driver_priv;
- struct drm_vc4_perfmon_destroy *req = data;
- struct vc4_perfmon *perfmon;
-
-+ if (!vc4->v3d) {
-+ DRM_DEBUG("Destroying perfmon no VC4 V3D probed\n");
-+ return -ENODEV;
-+ }
-+
- mutex_lock(&vc4file->perfmon.lock);
- perfmon = idr_remove(&vc4file->perfmon.idr, req->id);
- mutex_unlock(&vc4file->perfmon.lock);
-@@ -164,11 +176,17 @@ int vc4_perfmon_destroy_ioctl(struct drm
- int vc4_perfmon_get_values_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
- {
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct vc4_file *vc4file = file_priv->driver_priv;
- struct drm_vc4_perfmon_get_values *req = data;
- struct vc4_perfmon *perfmon;
- int ret;
-
-+ if (!vc4->v3d) {
-+ DRM_DEBUG("Getting perfmon no VC4 V3D probed\n");
-+ return -ENODEV;
-+ }
-+
- mutex_lock(&vc4file->perfmon.lock);
- perfmon = idr_find(&vc4file->perfmon.idr, req->id);
- vc4_perfmon_get(perfmon);
---- a/drivers/gpu/drm/vc4/vc4_v3d.c
-+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
-@@ -452,7 +452,7 @@ static int vc4_v3d_dev_remove(struct pla
- return 0;
- }
-
--static const struct of_device_id vc4_v3d_dt_match[] = {
-+const struct of_device_id vc4_v3d_dt_match[] = {
- { .compatible = "brcm,bcm2835-v3d" },
- { .compatible = "brcm,cygnus-v3d" },
- { .compatible = "brcm,vc4-v3d" },
--- /dev/null
+From 2a15e634d80f78cf2d8aa16ecf0f3cf930e277b4 Mon Sep 17 00:00:00 2001
+Date: Sun, 17 Nov 2019 10:31:46 +0800
+Subject: [PATCH] dwc_otg: checking the urb->transfer_buffer too early
+ (#3332)
+
+After enable the HIGHMEM and VMSPLIT_3G, the dwc_otg driver doesn't
+work well on Pi2/3 boards with 1G physical ram. Users experience
+the failure when copying a file of 600M size to the USB stick. And
+at the same time, the dmesg shows:
+usb 1-1.1.2: reset high-speed USB device number 8 using dwc_otg
+sd 0:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK
+blk_update_request: I/O error, dev sda, sector 3024048 op 0x1:(WRITE) flags 0x4000 phys_seg 15 prio class 0
+
+When this happens, the sg_buf sent to the driver is located in the
+highmem region, the usb_sg_init() in the core/message.c will leave
+transfer_buffer to NULL if the sg_buf is in highmem, but in the
+dwc_otg driver, it returns -EINVAL unconditionally if transfer_buffer
+is NULL.
+
+The driver can handle the situation of buffer to be NULL, if it is in
+DMA mode, it will convert an address from transfer_dma.
+
+But if the conversion fails or it is in the PIO mode, we should check
+buffer and return -EINVAL if it is NULL.
+
+BugLink: https://bugs.launchpad.net/bugs/1852510
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
+@@ -821,10 +821,6 @@ static int dwc_otg_urb_enqueue(struct us
+ dump_urb_info(urb, "dwc_otg_urb_enqueue");
+ }
+ #endif
+-
+- if (!urb->transfer_buffer && urb->transfer_buffer_length)
+- return -EINVAL;
+-
+ if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+ || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
+ if (!dwc_otg_hcd_is_bandwidth_allocated
+@@ -881,6 +877,13 @@ static int dwc_otg_urb_enqueue(struct us
+ &urb->transfer_dma, buf);
+ }
+
++ if (!buf && urb->transfer_buffer_length) {
++ DWC_FREE(dwc_otg_urb);
++ DWC_ERROR("transfer_buffer is NULL in PIO mode or both "
++ "transfer_buffer and transfer_dma are NULL in DMA mode\n");
++ return -EINVAL;
++ }
++
+ if (!(urb->transfer_flags & URB_NO_INTERRUPT))
+ flags |= URB_GIVEBACK_ASAP;
+ if (urb->transfer_flags & URB_ZERO_PACKET)
+++ /dev/null
-From 4ca89eb8570cb86314a5a7b55a15d15f53ce5757 Mon Sep 17 00:00:00 2001
-Date: Sat, 16 Nov 2019 12:41:06 +0100
-Subject: [PATCH] sound/soc: only first codec is master in multicodec
- setup
-
-When using multiple codecs, at most one codec should generate the master
-clock. All codecs except the first are therefore configured for slave
-mode.
-
----
- sound/soc/soc-core.c | 9 ++++++++-
- 1 file changed, 8 insertions(+), 1 deletion(-)
-
---- a/sound/soc/soc-core.c
-+++ b/sound/soc/soc-core.c
-@@ -1688,8 +1688,15 @@ int snd_soc_runtime_set_dai_fmt(struct s
-
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_dai *codec_dai = codec_dais[i];
-+ unsigned int codec_dai_fmt = dai_fmt;
-
-- ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
-+ // there can only be one master when using multiple codecs
-+ if (i && (codec_dai_fmt & SND_SOC_DAIFMT_MASTER_MASK)) {
-+ codec_dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
-+ codec_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
-+ }
-+
-+ ret = snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
- if (ret != 0 && ret != -ENOTSUPP) {
- dev_warn(codec_dai->dev,
- "ASoC: Failed to set DAI format: %d\n", ret);
+++ /dev/null
-From 8f11db84e124da59b8a717d66fc424ef070f4be0 Mon Sep 17 00:00:00 2001
-Date: Sat, 16 Nov 2019 13:14:43 +0100
-Subject: [PATCH] Allow simultaneous use of JustBoom DAC and Digi
-
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 20 ++
- .../dts/overlays/justboom-both-overlay.dts | 65 +++++
- sound/soc/bcm/Kconfig | 12 +
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/justboom-both.c | 269 ++++++++++++++++++
- 11 files changed, 374 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/justboom-both-overlay.dts
- create mode 100644 sound/soc/bcm/justboom-both.c
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -86,6 +86,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- iqaudio-digi-wm8804-audio.dtbo \
- irs1125.dtbo \
- jedec-spi-nor.dtbo \
-+ justboom-both.dtbo \
- justboom-dac.dtbo \
- justboom-digi.dtbo \
- ltc294x.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1388,6 +1388,26 @@ Params: flash-spi<n>-<m> Enables
- on SPI<n>, CS#<m>.
-
-
-+Name: justboom-both
-+Info: Simultaneous usage of an justboom-dac and justboom-digi based
-+ card
-+Load: dtoverlay=justboom-both,<param>=<val>
-+Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
-+ Digital volume control. Enable with
-+ "dtoverlay=justboom-dac,24db_digital_gain"
-+ (The default behaviour is that the Digital
-+ volume control is limited to a maximum of
-+ 0dB. ie. it can attenuate but not provide
-+ gain. For most users, this will be desired
-+ as it will prevent clipping. By appending
-+ the 24dB_digital_gain parameter, the Digital
-+ volume control will allow up to 24dB of
-+ gain. If this parameter is enabled, it is the
-+ responsibility of the user to ensure that
-+ the Digital volume control is set to a value
-+ that does not result in clipping/distortion!)
-+
-+
- Name: justboom-dac
- Info: Configures the JustBoom DAC HAT, Amp HAT, DAC Zero and Amp Zero audio
- cards
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/justboom-both-overlay.dts
-@@ -0,0 +1,65 @@
-+// SPDX-License-Identifier: GPL-2.0
-+// Definitions for JustBoom Both (Digi+DAC)
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ wm8804@3b {
-+ #sound-dai-cells = <0>;
-+ compatible = "wlf,wm8804";
-+ reg = <0x3b>;
-+ PVDD-supply = <&vdd_3v3_reg>;
-+ DVDD-supply = <&vdd_3v3_reg>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ pcm5122@4d {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,pcm5122";
-+ reg = <0x4d>;
-+ AVDD-supply = <&vdd_3v3_reg>;
-+ DVDD-supply = <&vdd_3v3_reg>;
-+ CPVDD-supply = <&vdd_3v3_reg>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&sound>;
-+ frag3: __overlay__ {
-+ compatible = "justboom,justboom-both";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ 24db_digital_gain = <&frag3>,"justboom,24db_digital_gain?";
-+ };
-+};
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -102,6 +102,18 @@ config SND_BCM2708_SOC_RPI_PROTO
- help
- Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
-
-+config SND_BCM2708_SOC_JUSTBOOM_BOTH
-+ tristate "Support for simultaneous JustBoom Digi and JustBoom DAC"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_WM8804
-+ select SND_SOC_PCM512x
-+ help
-+ Say Y or M if you want to add support for simultaneous
-+ JustBoom Digi and JustBoom DAC.
-+
-+ This is not the right choice if you only have one but both of
-+ these cards.
-+
- config SND_BCM2708_SOC_JUSTBOOM_DAC
- tristate "Support for JustBoom DAC"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -16,6 +16,7 @@ snd-soc-hifiberry-dacplus-objs := hifibe
- snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
- snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
- snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
-+snd-soc-justboom-both-objs := justboom-both.o
- snd-soc-justboom-dac-objs := justboom-dac.o
- snd-soc-rpi-cirrus-objs := rpi-cirrus.o
- snd-soc-rpi-proto-objs := rpi-proto.o
-@@ -42,6 +43,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
-+obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH) += snd-soc-justboom-both.o
- obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
---- /dev/null
-+++ b/sound/soc/bcm/justboom-both.c
-@@ -0,0 +1,269 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard.
-+ *
-+ *
-+ * Driver for when connecting simultaneously justboom-digi and justboom-dac
-+ *
-+ * Based upon code from:
-+ * justboom-digi.c
-+ * justboom-dac.c
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+
-+#include "../codecs/wm8804.h"
-+#include "../codecs/pcm512x.h"
-+
-+
-+static bool digital_gain_0db_limit = true;
-+
-+static int snd_rpi_justboom_both_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
-+ struct snd_soc_component *dac = rtd->codec_dais[1]->component;
-+
-+ /* enable TX output */
-+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0);
-+
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+
-+ if (digital_gain_0db_limit) {
-+ int ret;
-+ struct snd_soc_card *card = rtd->card;
-+
-+ ret = snd_soc_limit_volume(card, "Digital Playback Volume",
-+ 207);
-+ if (ret < 0)
-+ dev_warn(card->dev, "Failed to set volume limit: %d\n",
-+ ret);
-+ }
-+
-+ return 0;
-+}
-+
-+static int snd_rpi_justboom_both_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
-+ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+
-+ int sysclk = 27000000; /* This is fixed on this board */
-+
-+ long mclk_freq = 0;
-+ int mclk_div = 1;
-+ int sampling_freq = 1;
-+
-+ int ret;
-+
-+ int samplerate = params_rate(params);
-+
-+ if (samplerate <= 96000) {
-+ mclk_freq = samplerate*256;
-+ mclk_div = WM8804_MCLKDIV_256FS;
-+ } else {
-+ mclk_freq = samplerate*128;
-+ mclk_div = WM8804_MCLKDIV_128FS;
-+ }
-+
-+ switch (samplerate) {
-+ case 32000:
-+ sampling_freq = 0x03;
-+ break;
-+ case 44100:
-+ sampling_freq = 0x00;
-+ break;
-+ case 48000:
-+ sampling_freq = 0x02;
-+ break;
-+ case 88200:
-+ sampling_freq = 0x08;
-+ break;
-+ case 96000:
-+ sampling_freq = 0x0a;
-+ break;
-+ case 176400:
-+ sampling_freq = 0x0c;
-+ break;
-+ case 192000:
-+ sampling_freq = 0x0e;
-+ break;
-+ default:
-+ dev_err(rtd->card->dev,
-+ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
-+ samplerate);
-+ }
-+
-+ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
-+ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
-+
-+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
-+ sysclk, SND_SOC_CLOCK_OUT);
-+ if (ret < 0) {
-+ dev_err(rtd->card->dev,
-+ "Failed to set WM8804 SYSCLK: %d\n", ret);
-+ return ret;
-+ }
-+
-+ /* Enable TX output */
-+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0);
-+
-+ /* Power on */
-+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x9, 0);
-+
-+ /* set sampling frequency status bits */
-+ snd_soc_component_update_bits(digi, WM8804_SPDTX4, 0x0f, sampling_freq);
-+
-+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
-+}
-+
-+static int snd_rpi_justboom_both_startup(struct snd_pcm_substream *substream)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
-+ struct snd_soc_component *dac = rtd->codec_dais[1]->component;
-+
-+ /* turn on digital output */
-+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x00);
-+
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+
-+ return 0;
-+}
-+
-+static void snd_rpi_justboom_both_shutdown(struct snd_pcm_substream *substream)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
-+ struct snd_soc_component *dac = rtd->codec_dais[1]->component;
-+
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
-+
-+ /* turn off output */
-+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x3c);
-+}
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_justboom_both_ops = {
-+ .hw_params = snd_rpi_justboom_both_hw_params,
-+ .startup = snd_rpi_justboom_both_startup,
-+ .shutdown = snd_rpi_justboom_both_shutdown,
-+};
-+
-+static struct snd_soc_dai_link_component justboom_both_codecs[] = {
-+{
-+ .dai_name = "wm8804-spdif",
-+ .name = "wm8804.1-003b",
-+},
-+{
-+ .dai_name = "pcm512x-hifi",
-+ .name = "pcm512x.1-004d",
-+},
-+};
-+
-+static struct snd_soc_dai_link snd_rpi_justboom_both_dai[] = {
-+{
-+ .name = "JustBoom Digi",
-+ .stream_name = "JustBoom Digi HiFi",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codecs = justboom_both_codecs,
-+ .num_codecs = ARRAY_SIZE(justboom_both_codecs),
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBM_CFM,
-+ .ops = &snd_rpi_justboom_both_ops,
-+ .init = snd_rpi_justboom_both_init,
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_justboom_both = {
-+ .name = "snd_rpi_justboom_both",
-+ .driver_name = "JustBoomBoth",
-+ .owner = THIS_MODULE,
-+ .dai_link = snd_rpi_justboom_both_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_justboom_both_dai),
-+};
-+
-+static int snd_rpi_justboom_both_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ snd_rpi_justboom_both.dev = &pdev->dev;
-+
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai = &snd_rpi_justboom_both_dai[0];
-+
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+
-+ if (i2s_node) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
-+
-+ digital_gain_0db_limit = !of_property_read_bool(
-+ pdev->dev.of_node, "justboom,24db_digital_gain");
-+ }
-+
-+ ret = snd_soc_register_card(&snd_rpi_justboom_both);
-+ if (ret && ret != -EPROBE_DEFER) {
-+ dev_err(&pdev->dev,
-+ "snd_soc_register_card() failed: %d\n", ret);
-+ }
-+
-+ return ret;
-+}
-+
-+static int snd_rpi_justboom_both_remove(struct platform_device *pdev)
-+{
-+ return snd_soc_unregister_card(&snd_rpi_justboom_both);
-+}
-+
-+static const struct of_device_id snd_rpi_justboom_both_of_match[] = {
-+ { .compatible = "justboom,justboom-both", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, snd_rpi_justboom_both_of_match);
-+
-+static struct platform_driver snd_rpi_justboom_both_driver = {
-+ .driver = {
-+ .name = "snd-rpi-justboom-both",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_justboom_both_of_match,
-+ },
-+ .probe = snd_rpi_justboom_both_probe,
-+ .remove = snd_rpi_justboom_both_remove,
-+};
-+
-+module_platform_driver(snd_rpi_justboom_both_driver);
-+
-+MODULE_DESCRIPTION("ASoC Driver for simultaneous use of JustBoom PI Digi & DAC HAT Sound Cards");
-+MODULE_LICENSE("GPL v2");
--- /dev/null
+From e650f4bfbe9a09e5b75d702884a8ba8d9df6ccdf Mon Sep 17 00:00:00 2001
+Date: Mon, 9 Dec 2019 12:32:20 +0000
+Subject: [PATCH] overlays: Make mcp342x run-time compatible
+
+The order of processing of run-time overlays differs from that done by
+the firmware. This means that certain parameter processing techniques
+are not compatible with run-time use. The mcp342x overlay is one such
+overlay, but it is easy to change the implementation without changing
+the interface.
+
+See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=258294
+
+---
+ .../arm/boot/dts/overlays/mcp342x-overlay.dts | 133 ++++++++++++++----
+ 1 file changed, 102 insertions(+), 31 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
+@@ -8,14 +8,15 @@
+
+ fragment@0 {
+ target = <&i2c1>;
+- __overlay__ {
++ __dormant__ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "okay";
+
+- mcp342x: mcp@68 {
++ mcp3421: mcp@68 {
+ reg = <0x68>;
++ compatible = "microchip,mcp3421";
+
+ status = "okay";
+ };
+@@ -23,71 +24,141 @@
+ };
+
+ fragment@1 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3421";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp3422: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3422";
++
++ status = "okay";
++ };
+ };
+ };
+
+ fragment@2 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3422";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp3423: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3423";
++
++ status = "okay";
++ };
+ };
+ };
+
+ fragment@3 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3423";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp3424: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3424";
++
++ status = "okay";
++ };
+ };
+ };
+
+ fragment@4 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3424";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp3425: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3425","mcp3425";
++
++ status = "okay";
++ };
+ };
+ };
+
+ fragment@5 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3425";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp3426: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3426";
++
++ status = "okay";
++ };
+ };
+ };
+
+ fragment@6 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3426";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp3427: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3427";
++
++ status = "okay";
++ };
+ };
+ };
+
+ fragment@7 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3427";
+- };
+- };
++ #address-cells = <1>;
++ #size-cells = <0>;
+
+- fragment@8 {
+- target = <&mcp342x>;
+- __dormant__ {
+- compatible = "microchip,mcp3428";
++ status = "okay";
++
++ mcp3428: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3428";
++
++ status = "okay";
++ };
+ };
+ };
+
+ __overrides__ {
+- addr = <&mcp342x>,"reg:0";
+- mcp3421 = <0>,"=1";
+- mcp3422 = <0>,"=2";
+- mcp3423 = <0>,"=3";
+- mcp3424 = <0>,"=4";
+- mcp3425 = <0>,"=5";
+- mcp3426 = <0>,"=6";
+- mcp3427 = <0>,"=7";
+- mcp3428 = <0>,"=8";
++ addr = <&mcp3421>,"reg:0",
++ <&mcp3422>,"reg:0",
++ <&mcp3423>,"reg:0",
++ <&mcp3424>,"reg:0",
++ <&mcp3425>,"reg:0",
++ <&mcp3426>,"reg:0",
++ <&mcp3427>,"reg:0",
++ <&mcp3428>,"reg:0";
++ mcp3421 = <0>,"=0";
++ mcp3422 = <0>,"=1";
++ mcp3423 = <0>,"=2";
++ mcp3424 = <0>,"=3";
++ mcp3425 = <0>,"=4";
++ mcp3426 = <0>,"=5";
++ mcp3427 = <0>,"=6";
++ mcp3428 = <0>,"=7";
+ };
+ };
+
+++ /dev/null
-From 2a15e634d80f78cf2d8aa16ecf0f3cf930e277b4 Mon Sep 17 00:00:00 2001
-Date: Sun, 17 Nov 2019 10:31:46 +0800
-Subject: [PATCH] dwc_otg: checking the urb->transfer_buffer too early
- (#3332)
-
-After enable the HIGHMEM and VMSPLIT_3G, the dwc_otg driver doesn't
-work well on Pi2/3 boards with 1G physical ram. Users experience
-the failure when copying a file of 600M size to the USB stick. And
-at the same time, the dmesg shows:
-usb 1-1.1.2: reset high-speed USB device number 8 using dwc_otg
-sd 0:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK
-blk_update_request: I/O error, dev sda, sector 3024048 op 0x1:(WRITE) flags 0x4000 phys_seg 15 prio class 0
-
-When this happens, the sg_buf sent to the driver is located in the
-highmem region, the usb_sg_init() in the core/message.c will leave
-transfer_buffer to NULL if the sg_buf is in highmem, but in the
-dwc_otg driver, it returns -EINVAL unconditionally if transfer_buffer
-is NULL.
-
-The driver can handle the situation of buffer to be NULL, if it is in
-DMA mode, it will convert an address from transfer_dma.
-
-But if the conversion fails or it is in the PIO mode, we should check
-buffer and return -EINVAL if it is NULL.
-
-BugLink: https://bugs.launchpad.net/bugs/1852510
----
- drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 11 +++++++----
- 1 file changed, 7 insertions(+), 4 deletions(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-@@ -821,10 +821,6 @@ static int dwc_otg_urb_enqueue(struct us
- dump_urb_info(urb, "dwc_otg_urb_enqueue");
- }
- #endif
--
-- if (!urb->transfer_buffer && urb->transfer_buffer_length)
-- return -EINVAL;
--
- if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
- || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
- if (!dwc_otg_hcd_is_bandwidth_allocated
-@@ -881,6 +877,13 @@ static int dwc_otg_urb_enqueue(struct us
- &urb->transfer_dma, buf);
- }
-
-+ if (!buf && urb->transfer_buffer_length) {
-+ DWC_FREE(dwc_otg_urb);
-+ DWC_ERROR("transfer_buffer is NULL in PIO mode or both "
-+ "transfer_buffer and transfer_dma are NULL in DMA mode\n");
-+ return -EINVAL;
-+ }
-+
- if (!(urb->transfer_flags & URB_NO_INTERRUPT))
- flags |= URB_GIVEBACK_ASAP;
- if (urb->transfer_flags & URB_ZERO_PACKET)
--- /dev/null
+From 26e95c876831692f28894041c5a1db5934715939 Mon Sep 17 00:00:00 2001
+Date: Wed, 18 Dec 2019 10:41:33 +0000
+Subject: [PATCH] overlays: dht11: Allow multiple instantiation
+
+Add addresses to the dht11 and dht11_pins nodes to allow unique names
+to be generated by assigning to the "reg" property.
+
+---
+ arch/arm/boot/dts/overlays/dht11-overlay.dts | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/dht11-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dht11-overlay.dts
+@@ -24,7 +24,7 @@
+ fragment@1 {
+ target = <&gpio>;
+ __overlay__ {
+- dht11_pins: dht11_pins {
++ dht11_pins: dht11_pins@0 {
+ brcm,pins = <4>;
+ brcm,function = <0>; // in
+ brcm,pull = <0>; // off
+@@ -34,6 +34,8 @@
+
+ __overrides__ {
+ gpiopin = <&dht11_pins>,"brcm,pins:0",
+- <&dht11>,"gpios:4";
++ <&dht11_pins>, "reg:0",
++ <&dht11>,"gpios:4",
++ <&dht11>,"reg:0";
+ };
+ };
+++ /dev/null
-From e650f4bfbe9a09e5b75d702884a8ba8d9df6ccdf Mon Sep 17 00:00:00 2001
-Date: Mon, 9 Dec 2019 12:32:20 +0000
-Subject: [PATCH] overlays: Make mcp342x run-time compatible
-
-The order of processing of run-time overlays differs from that done by
-the firmware. This means that certain parameter processing techniques
-are not compatible with run-time use. The mcp342x overlay is one such
-overlay, but it is easy to change the implementation without changing
-the interface.
-
-See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=258294
-
----
- .../arm/boot/dts/overlays/mcp342x-overlay.dts | 133 ++++++++++++++----
- 1 file changed, 102 insertions(+), 31 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
-@@ -8,14 +8,15 @@
-
- fragment@0 {
- target = <&i2c1>;
-- __overlay__ {
-+ __dormant__ {
- #address-cells = <1>;
- #size-cells = <0>;
-
- status = "okay";
-
-- mcp342x: mcp@68 {
-+ mcp3421: mcp@68 {
- reg = <0x68>;
-+ compatible = "microchip,mcp3421";
-
- status = "okay";
- };
-@@ -23,71 +24,141 @@
- };
-
- fragment@1 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3421";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp3422: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3422";
-+
-+ status = "okay";
-+ };
- };
- };
-
- fragment@2 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3422";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp3423: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3423";
-+
-+ status = "okay";
-+ };
- };
- };
-
- fragment@3 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3423";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp3424: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3424";
-+
-+ status = "okay";
-+ };
- };
- };
-
- fragment@4 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3424";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp3425: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3425","mcp3425";
-+
-+ status = "okay";
-+ };
- };
- };
-
- fragment@5 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3425";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp3426: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3426";
-+
-+ status = "okay";
-+ };
- };
- };
-
- fragment@6 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3426";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp3427: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3427";
-+
-+ status = "okay";
-+ };
- };
- };
-
- fragment@7 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3427";
-- };
-- };
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-
-- fragment@8 {
-- target = <&mcp342x>;
-- __dormant__ {
-- compatible = "microchip,mcp3428";
-+ status = "okay";
-+
-+ mcp3428: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3428";
-+
-+ status = "okay";
-+ };
- };
- };
-
- __overrides__ {
-- addr = <&mcp342x>,"reg:0";
-- mcp3421 = <0>,"=1";
-- mcp3422 = <0>,"=2";
-- mcp3423 = <0>,"=3";
-- mcp3424 = <0>,"=4";
-- mcp3425 = <0>,"=5";
-- mcp3426 = <0>,"=6";
-- mcp3427 = <0>,"=7";
-- mcp3428 = <0>,"=8";
-+ addr = <&mcp3421>,"reg:0",
-+ <&mcp3422>,"reg:0",
-+ <&mcp3423>,"reg:0",
-+ <&mcp3424>,"reg:0",
-+ <&mcp3425>,"reg:0",
-+ <&mcp3426>,"reg:0",
-+ <&mcp3427>,"reg:0",
-+ <&mcp3428>,"reg:0";
-+ mcp3421 = <0>,"=0";
-+ mcp3422 = <0>,"=1";
-+ mcp3423 = <0>,"=2";
-+ mcp3424 = <0>,"=3";
-+ mcp3425 = <0>,"=4";
-+ mcp3426 = <0>,"=5";
-+ mcp3427 = <0>,"=6";
-+ mcp3428 = <0>,"=7";
- };
- };
-
--- /dev/null
+From b85f76a63d5f1b13220c61244469d55487db84f1 Mon Sep 17 00:00:00 2001
+Date: Sun, 22 Dec 2019 15:29:40 +0000
+Subject: [PATCH] overlays: i2c-rtc: Add pcf85363 support
+
+See: https://github.com/raspberrypi/firmware/issues/1309
+
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 16 ++++++++++++++++
+ 2 files changed, 18 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1078,6 +1078,8 @@ Params: abx80x Select o
+
+ pcf8523 Select the PCF8523 device
+
++ pcf85363 Select the PCF85363 device
++
+ pcf8563 Select the PCF8563 device
+
+ rv3028 Select the Micro Crystal RV3028 device
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+@@ -188,6 +188,21 @@
+ };
+ };
+
++ fragment@12 {
++ target = <&i2c_arm>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcf85363@51 {
++ compatible = "nxp,pcf85363";
++ reg = <0x51>;
++ status = "okay";
++ };
++ };
++ };
++
+ __overrides__ {
+ abx80x = <0>,"+0";
+ ds1307 = <0>,"+1";
+@@ -201,6 +216,7 @@
+ m41t62 = <0>,"+9";
+ rv3028 = <0>,"+10";
+ pcf2129 = <0>,"+11";
++ pcf85363 = <0>,"+12";
+
+ addr = <&abx80x>, "reg:0",
+ <&ds1307>, "reg:0",
+++ /dev/null
-From 26e95c876831692f28894041c5a1db5934715939 Mon Sep 17 00:00:00 2001
-Date: Wed, 18 Dec 2019 10:41:33 +0000
-Subject: [PATCH] overlays: dht11: Allow multiple instantiation
-
-Add addresses to the dht11 and dht11_pins nodes to allow unique names
-to be generated by assigning to the "reg" property.
-
----
- arch/arm/boot/dts/overlays/dht11-overlay.dts | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/dht11-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dht11-overlay.dts
-@@ -24,7 +24,7 @@
- fragment@1 {
- target = <&gpio>;
- __overlay__ {
-- dht11_pins: dht11_pins {
-+ dht11_pins: dht11_pins@0 {
- brcm,pins = <4>;
- brcm,function = <0>; // in
- brcm,pull = <0>; // off
-@@ -34,6 +34,8 @@
-
- __overrides__ {
- gpiopin = <&dht11_pins>,"brcm,pins:0",
-- <&dht11>,"gpios:4";
-+ <&dht11_pins>, "reg:0",
-+ <&dht11>,"gpios:4",
-+ <&dht11>,"reg:0";
- };
- };
--- /dev/null
+From e1bbcb1097b9d968ae61397a66a73a440a0ce705 Mon Sep 17 00:00:00 2001
+Date: Mon, 6 Jan 2020 16:04:30 +0000
+Subject: [PATCH] pinctrl: bcm2835: Remove gpiochip on error
+
+A failure in gpiochip_irqchip_add leads to a leak of a gpiochip. Fix
+the leak with the use of devm_gpiochip_add_data.
+
+Fixes: 85ae9e512f43 ("pinctrl: bcm2835: switch to GPIOLIB_IRQCHIP")
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -1140,7 +1140,7 @@ static int bcm2835_pinctrl_probe(struct
+ raw_spin_lock_init(&pc->irq_lock[i]);
+ }
+
+- err = gpiochip_add_data(&pc->gpio_chip, pc);
++ err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc);
+ if (err) {
+ dev_err(dev, "could not add GPIO chip\n");
+ return err;
+++ /dev/null
-From b85f76a63d5f1b13220c61244469d55487db84f1 Mon Sep 17 00:00:00 2001
-Date: Sun, 22 Dec 2019 15:29:40 +0000
-Subject: [PATCH] overlays: i2c-rtc: Add pcf85363 support
-
-See: https://github.com/raspberrypi/firmware/issues/1309
-
----
- arch/arm/boot/dts/overlays/README | 2 ++
- arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 16 ++++++++++++++++
- 2 files changed, 18 insertions(+)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1078,6 +1078,8 @@ Params: abx80x Select o
-
- pcf8523 Select the PCF8523 device
-
-+ pcf85363 Select the PCF85363 device
-+
- pcf8563 Select the PCF8563 device
-
- rv3028 Select the Micro Crystal RV3028 device
---- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-@@ -188,6 +188,21 @@
- };
- };
-
-+ fragment@12 {
-+ target = <&i2c_arm>;
-+ __dormant__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ pcf85363@51 {
-+ compatible = "nxp,pcf85363";
-+ reg = <0x51>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
- __overrides__ {
- abx80x = <0>,"+0";
- ds1307 = <0>,"+1";
-@@ -201,6 +216,7 @@
- m41t62 = <0>,"+9";
- rv3028 = <0>,"+10";
- pcf2129 = <0>,"+11";
-+ pcf85363 = <0>,"+12";
-
- addr = <&abx80x>, "reg:0",
- <&ds1307>, "reg:0",
--- /dev/null
+From 0b3764707993123148b4e94d44ff282b111c8edb Mon Sep 17 00:00:00 2001
+Date: Mon, 6 Jan 2020 14:05:42 +0000
+Subject: [PATCH] pinctrl: bcm2835: Change init order for gpio hogs
+
+pinctrl-bcm2835 is a combined pinctrl/gpio driver. Currently the gpio
+side is registered first, but this breaks gpio hogs (which are
+configured during gpiochip_add_data). Part of the hog initialisation
+is a call to pinctrl_gpio_request, and since the pinctrl driver hasn't
+yet been registered this results in an -EPROBE_DEFER from which it can
+never recover.
+
+Change the initialisation sequence to register the pinctrl driver
+first.
+
+See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=260600
+
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 34 +++++++++++++--------------
+ 1 file changed, 17 insertions(+), 17 deletions(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -1140,9 +1140,25 @@ static int bcm2835_pinctrl_probe(struct
+ raw_spin_lock_init(&pc->irq_lock[i]);
+ }
+
++ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
++ if (match) {
++ bcm2835_pinctrl_desc.confops =
++ (const struct pinconf_ops *)match->data;
++ }
++
++ pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
++ if (IS_ERR(pc->pctl_dev))
++ return PTR_ERR(pc->pctl_dev);
++
++ pc->gpio_range = bcm2835_pinctrl_gpio_range;
++ pc->gpio_range.base = pc->gpio_chip.base;
++ pc->gpio_range.gc = &pc->gpio_chip;
++ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
++
+ err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc);
+ if (err) {
+ dev_err(dev, "could not add GPIO chip\n");
++ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
+ return err;
+ }
+
+@@ -1150,6 +1166,7 @@ static int bcm2835_pinctrl_probe(struct
+ 0, handle_level_irq, IRQ_TYPE_NONE);
+ if (err) {
+ dev_info(dev, "could not add irqchip\n");
++ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
+ return err;
+ }
+
+@@ -1172,23 +1189,6 @@ static int bcm2835_pinctrl_probe(struct
+ bcm2835_gpio_irq_handler);
+ }
+
+- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
+- if (match) {
+- bcm2835_pinctrl_desc.confops =
+- (const struct pinconf_ops *)match->data;
+- }
+-
+- pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
+- if (IS_ERR(pc->pctl_dev)) {
+- gpiochip_remove(&pc->gpio_chip);
+- return PTR_ERR(pc->pctl_dev);
+- }
+-
+- pc->gpio_range = bcm2835_pinctrl_gpio_range;
+- pc->gpio_range.base = pc->gpio_chip.base;
+- pc->gpio_range.gc = &pc->gpio_chip;
+- pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
+-
+ return 0;
+ }
+
--- /dev/null
+From 5b12b655f266ea29e91a7b7a46385df05bb70ed8 Mon Sep 17 00:00:00 2001
+Date: Tue, 7 Jan 2020 11:04:21 +0200
+Subject: [PATCH] Pisound: MIDI communication fixes for scaled down
+ CPU.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+* Increased maximum SPI communication speed to avoid running too slow
+ when the CPU is scaled down and losing MIDI data.
+
+* Keep track of buffer usage in millibytes for higher precision.
+
+---
+ sound/soc/bcm/pisound.c | 31 ++++++++++++++++++-------------
+ 1 file changed, 18 insertions(+), 13 deletions(-)
+
+--- a/sound/soc/bcm/pisound.c
++++ b/sound/soc/bcm/pisound.c
+@@ -1,6 +1,6 @@
+ /*
+ * Pisound Linux kernel module.
+- * Copyright (C) 2016-2019 Vilniaus Blokas UAB, https://blokas.io/pisound
++ * Copyright (C) 2016-2020 Vilniaus Blokas UAB, https://blokas.io/pisound
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -326,7 +326,7 @@ static void spi_transfer(const uint8_t *
+ transfer.tx_buf = txbuf;
+ transfer.rx_buf = rxbuf;
+ transfer.len = len;
+- transfer.speed_hz = 100000;
++ transfer.speed_hz = 150000;
+ transfer.delay_usecs = 10;
+ spi_message_add_tail(&transfer, &msg);
+
+@@ -403,9 +403,9 @@ static struct spi_device *pisnd_spi_find
+ static void pisnd_work_handler(struct work_struct *work)
+ {
+ enum { TRANSFER_SIZE = 4 };
+- enum { PISOUND_OUTPUT_BUFFER_SIZE = 128 };
+- enum { MIDI_BYTES_PER_SECOND = 3125 };
+- int out_buffer_used = 0;
++ enum { PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES = 127 * 1000 };
++ enum { MIDI_MILLIBYTES_PER_JIFFIE = (3125 * 1000) / HZ };
++ int out_buffer_used_millibytes = 0;
+ unsigned long now;
+ uint8_t val;
+ uint8_t txbuf[TRANSFER_SIZE];
+@@ -445,7 +445,9 @@ static void pisnd_work_handler(struct wo
+ had_data = false;
+ memset(txbuf, 0, sizeof(txbuf));
+ for (i = 0; i < sizeof(txbuf) &&
+- out_buffer_used < PISOUND_OUTPUT_BUFFER_SIZE;
++ ((out_buffer_used_millibytes+1000 <
++ PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES) ||
++ g_ledFlashDurationChanged);
+ i += 2) {
+
+ val = 0;
+@@ -458,7 +460,7 @@ static void pisnd_work_handler(struct wo
+ } else if (kfifo_get(&spi_fifo_out, &val)) {
+ txbuf[i+0] = 0x0f;
+ txbuf[i+1] = val;
+- ++out_buffer_used;
++ out_buffer_used_millibytes += 1000;
+ }
+ }
+
+@@ -469,12 +471,14 @@ static void pisnd_work_handler(struct wo
+ * rate.
+ */
+ now = jiffies;
+- out_buffer_used -=
+- (MIDI_BYTES_PER_SECOND / HZ) /
+- (now - last_transfer_at);
+- if (out_buffer_used < 0)
+- out_buffer_used = 0;
+- last_transfer_at = now;
++ if (now != last_transfer_at) {
++ out_buffer_used_millibytes -=
++ (now - last_transfer_at) *
++ MIDI_MILLIBYTES_PER_JIFFIE;
++ if (out_buffer_used_millibytes < 0)
++ out_buffer_used_millibytes = 0;
++ last_transfer_at = now;
++ }
+
+ for (i = 0; i < sizeof(rxbuf); i += 2) {
+ if (rxbuf[i]) {
+@@ -489,6 +493,7 @@ static void pisnd_work_handler(struct wo
+ || !kfifo_is_empty(&spi_fifo_out)
+ || pisnd_spi_has_more()
+ || g_ledFlashDurationChanged
++ || out_buffer_used_millibytes != 0
+ );
+
+ if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
--- /dev/null
+From 1738aaf187e0c8e97fbdd9661960b835f45e8985 Mon Sep 17 00:00:00 2001
+Date: Mon, 18 Nov 2019 23:02:55 +0200
+Subject: [PATCH] leds: pca963x: Fix open-drain initialization
+
+commit 697529091ac7a0a90ca349b914bb30641c13c753 upstream.
+
+Before commit bb29b9cccd95 ("leds: pca963x: Add bindings to invert
+polarity") Mode register 2 was initialized directly with either 0x01
+or 0x05 for open-drain or totem pole (push-pull) configuration.
+
+Afterwards, MODE2 initialization started using bitwise operations on
+top of the default MODE2 register value (0x05). Using bitwise OR for
+setting OUTDRV with 0x01 and 0x05 does not produce correct results.
+When open-drain is used, instead of setting OUTDRV to 0, the driver
+keeps it as 1:
+
+Open-drain: 0x05 | 0x01 -> 0x05 (0b101 - incorrect)
+Totem pole: 0x05 | 0x05 -> 0x05 (0b101 - correct but still wrong)
+
+Now OUTDRV setting uses correct bitwise operations for initialization:
+
+Open-drain: 0x05 & ~0x04 -> 0x01 (0b001 - correct)
+Totem pole: 0x05 | 0x04 -> 0x05 (0b101 - correct)
+
+Additional MODE2 register definitions are introduced now as well.
+
+Fixes: bb29b9cccd95 ("leds: pca963x: Add bindings to invert polarity")
+---
+ drivers/leds/leds-pca963x.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/leds/leds-pca963x.c
++++ b/drivers/leds/leds-pca963x.c
+@@ -43,6 +43,8 @@
+ #define PCA963X_LED_PWM 0x2 /* Controlled through PWM */
+ #define PCA963X_LED_GRP_PWM 0x3 /* Controlled through PWM/GRPPWM */
+
++#define PCA963X_MODE2_OUTDRV 0x04 /* Open-drain or totem pole */
++#define PCA963X_MODE2_INVRT 0x10 /* Normal or inverted direction */
+ #define PCA963X_MODE2_DMBLNK 0x20 /* Enable blinking */
+
+ #define PCA963X_MODE1 0x00
+@@ -462,12 +464,12 @@ static int pca963x_probe(struct i2c_clie
+ PCA963X_MODE2);
+ /* Configure output: open-drain or totem pole (push-pull) */
+ if (pdata->outdrv == PCA963X_OPEN_DRAIN)
+- mode2 |= 0x01;
++ mode2 &= ~PCA963X_MODE2_OUTDRV;
+ else
+- mode2 |= 0x05;
++ mode2 |= PCA963X_MODE2_OUTDRV;
+ /* Configure direction: normal or inverted */
+ if (pdata->dir == PCA963X_INVERTED)
+- mode2 |= 0x10;
++ mode2 |= PCA963X_MODE2_INVRT;
+ i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2,
+ mode2);
+ }
--- /dev/null
+From ca88aee39825dd81ef1e8306b5947c5ae3918d1a Mon Sep 17 00:00:00 2001
+Date: Thu, 9 Jan 2020 21:16:49 +0100
+Subject: [PATCH] add BME680 to i2c-sensor overlay
+
+---
+ arch/arm/boot/dts/overlays/README | 7 +++++--
+ .../boot/dts/overlays/i2c-sensor-overlay.dts | 19 ++++++++++++++++++-
+ 2 files changed, 23 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1159,12 +1159,15 @@ Name: i2c-sensor
+ Info: Adds support for a number of I2C barometric pressure and temperature
+ sensors on i2c_arm
+ Load: dtoverlay=i2c-sensor,<param>=<val>
+-Params: addr Set the address for the BME280, BMP280, DS1621,
+- HDC100X, LM75, SHT3x or TMP102
++Params: addr Set the address for the BME280, BME680, BMP280,
++ DS1621, HDC100X, LM75, SHT3x or TMP102
+
+ bme280 Select the Bosch Sensortronic BME280
+ Valid addresses 0x76-0x77, default 0x76
+
++ bme680 Select the Bosch Sensortronic BME680
++ Valid addresses 0x76-0x77, default 0x76
++
+ bmp085 Select the Bosch Sensortronic BMP085
+
+ bmp180 Select the Bosch Sensortronic BMP180
+--- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
+@@ -216,10 +216,26 @@
+ };
+ };
+
++ fragment@14 {
++ target = <&i2c_arm>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ bme680: bme680@76 {
++ compatible = "bosch,bme680";
++ reg = <0x76>;
++ status = "okay";
++ };
++ };
++ };
++
++
+ __overrides__ {
+ addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0",
+ <&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0",
+- <&ds1621>,"reg:0";
++ <&ds1621>,"reg:0", <&bme680>,"reg:0";
+ bme280 = <0>,"+0";
+ bmp085 = <0>,"+1";
+ bmp180 = <0>,"+2";
+@@ -235,5 +251,6 @@
+ sht3x = <0>,"+11";
+ ds1621 = <0>,"+12";
+ max17040 = <0>,"+13";
++ bme680 = <0>,"+14";
+ };
+ };
--- /dev/null
+From 7ae8ef63c14ca2fea76c9db5799321f1b3e31c36 Mon Sep 17 00:00:00 2001
+Date: Tue, 7 Jan 2020 10:08:19 +0000
+Subject: [PATCH] dwc_otg: constrain endpoint max packet and transfer
+ size on split IN
+
+The hcd would unconditionally set the transfer length to the endpoint
+packet size for non-isoc IN transfers. If the remaining buffer length
+was less than the length of returned data, random memory would get
+scribbled over, with bad effects if it crossed a page boundary.
+
+Force a babble error if this happens by limiting the max transfer size
+to the available buffer space. DMA will stop writing to memory on a
+babble condition.
+
+The hardware expects xfersize to be an integer multiple of maxpacket
+size, so override hcchar.b.mps as well.
+
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+@@ -1813,7 +1813,7 @@ int fiq_fsm_queue_split_transaction(dwc_
+ st->nr_errors = 0;
+
+ st->hcchar_copy.d32 = 0;
+- st->hcchar_copy.b.mps = hc->max_packet;
++ st->hcchar_copy.b.mps = min_t(uint32_t, hc->xfer_len, hc->max_packet);
+ st->hcchar_copy.b.epdir = hc->ep_is_in;
+ st->hcchar_copy.b.devaddr = hc->dev_addr;
+ st->hcchar_copy.b.epnum = hc->ep_num;
+@@ -1858,7 +1858,7 @@ int fiq_fsm_queue_split_transaction(dwc_
+ st->hctsiz_copy.b.pid = hc->data_pid_start;
+
+ if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
+- hc->xfer_len = hc->max_packet;
++ hc->xfer_len = min_t(uint32_t, hc->xfer_len, hc->max_packet);
+ } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
+ hc->xfer_len = 188;
+ }
--- /dev/null
+From af6743f045159970b95f6426de13c0fb82678e67 Mon Sep 17 00:00:00 2001
+Date: Wed, 8 Jan 2020 12:48:09 +0000
+Subject: [PATCH] dwc_otg: fiq_fsm: pause when cancelling split
+ transactions
+
+Non-periodic splits will DMA to/from the driver-provided transfer_buffer,
+which may be freed immediately after the dequeue call returns. Block until
+we know the transfer is complete.
+
+A similar delay is needed when cleaning up disconnects, as the FIQ could
+have started a periodic transfer in the previous microframe to the one
+that triggered a disconnect.
+
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 33 +++++++++++++++++++++--
+ drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 1 +
+ 2 files changed, 32 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+@@ -175,6 +175,7 @@ static void kill_urbs_in_qh_list(dwc_otg
+ dwc_list_link_t *qh_item, *qh_tmp;
+ dwc_otg_qh_t *qh;
+ dwc_otg_qtd_t *qtd, *qtd_tmp;
++ int quiesced = 0;
+
+ DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) {
+ qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
+@@ -198,8 +199,17 @@ static void kill_urbs_in_qh_list(dwc_otg
+ qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
+ qh->channel->halt_pending = 1;
+ if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO ||
+- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
++ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
+ hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED;
++ /* We're called from disconnect callback or in the middle of freeing the HCD here,
++ * so FIQ is disabled, top-level interrupts masked and we're holding the spinlock.
++ * No further URBs will be submitted, but wait 1 microframe for any previously
++ * submitted periodic DMA to finish.
++ */
++ if (!quiesced) {
++ udelay(125);
++ quiesced = 1;
++ }
+ } else {
+ dwc_otg_hc_halt(hcd->core_if, qh->channel,
+ DWC_OTG_HC_XFER_URB_DEQUEUE);
+@@ -600,15 +610,34 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_
+ /* In FIQ FSM mode, we need to shut down carefully.
+ * The FIQ may attempt to restart a disabled channel */
+ if (fiq_fsm_enable && (hcd->fiq_state->channel[n].fsm != FIQ_PASSTHROUGH)) {
++ int retries = 3;
++ int running = 0;
++ enum fiq_fsm_state state;
++
+ local_fiq_disable();
+ fiq_fsm_spin_lock(&hcd->fiq_state->lock);
+ qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
+ qh->channel->halt_pending = 1;
+ if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO ||
+- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
++ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
+ hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED;
+ fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
+ local_fiq_enable();
++
++ if (dwc_qh_is_non_per(qh)) {
++ do {
++ state = READ_ONCE(hcd->fiq_state->channel[n].fsm);
++ running = (state != FIQ_NP_SPLIT_DONE) &&
++ (state != FIQ_NP_SPLIT_LS_ABORTED) &&
++ (state != FIQ_NP_SPLIT_HS_ABORTED);
++ if (!running)
++ break;
++ udelay(125);
++ } while(--retries);
++ if (!retries)
++ DWC_WARN("Timed out waiting for FSM NP transfer to complete on %d",
++ qh->channel->hc_num);
++ }
+ } else {
+ dwc_otg_hc_halt(hcd->core_if, qh->channel,
+ DWC_OTG_HC_XFER_URB_DEQUEUE);
+--- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
++++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
+@@ -27,6 +27,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/stat.h>
+ #include <linux/pci.h>
++#include <linux/compiler.h>
+
+ #include <linux/version.h>
+
--- /dev/null
+From b2d43d61a1d6d070664f10d12b3c8b6df11eb21d Mon Sep 17 00:00:00 2001
+Date: Mon, 13 Jan 2020 15:54:55 +0000
+Subject: [PATCH] dwc_otg: fiq_fsm: add a barrier on entry into FIQ
+ handler(s)
+
+On BCM2835, there is no hardware guarantee that multiple outstanding
+reads to different peripherals will complete in-order. The FIQ code
+uses peripheral reads without barriers for performance, so in the case
+where a read to a slow peripheral was issued immediately prior to FIQ
+entry, the first peripheral read that the FIQ did could end up with
+wrong read data returned.
+
+Add dsb(sy) on entry so that all outstanding reads are retired.
+
+The FIQ only issues reads to the dwc_otg core, so per-read barriers
+in the handler itself are not required.
+
+On BCM2836 and BCM2837 the barrier is not strictly required due to
+differences in how the peripheral bus is implemented, but having
+arch-specific handlers that introduce different latencies is risky.
+
+---
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
+@@ -1259,6 +1259,9 @@ void notrace dwc_otg_fiq_fsm(struct fiq_
+ haintmsk_data_t haintmsk;
+ int kick_irq = 0;
+
++ /* Ensure peripheral reads issued prior to FIQ entry are complete */
++ dsb(sy);
++
+ gintsts_handled.d32 = 0;
+ haint_handled.d32 = 0;
+
+@@ -1379,6 +1382,9 @@ void notrace dwc_otg_fiq_nop(struct fiq_
+ gintmsk_data_t gintmsk;
+ hfnum_data_t hfnum;
+
++ /* Ensure peripheral reads issued prior to FIQ entry are complete */
++ dsb(sy);
++
+ fiq_fsm_spin_lock(&state->lock);
+ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM);
+ gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS);
--- /dev/null
+From 4d19be9132ca10cf582450a86dcb2c41f227f589 Mon Sep 17 00:00:00 2001
+Date: Tue, 10 Dec 2019 22:45:04 +0300
+Subject: [PATCH] Add universal device tree overlay for SPI devices
+
+Just specify the SPI address and device name ("compatible" property).
+This overlay lacks any device-specific parameter support!
+(some of them could be added later)
+
+Examples:
+1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz:
+ dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000
+2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz:
+ dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204"
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 23 ++
+ arch/arm/boot/dts/overlays/anyspi-overlay.dts | 205 ++++++++++++++++++
+ 3 files changed, 229 insertions(+)
+ create mode 100755 arch/arm/boot/dts/overlays/anyspi-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -15,6 +15,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ allo-katana-dac-audio.dtbo \
+ allo-piano-dac-pcm512x-audio.dtbo \
+ allo-piano-dac-plus-pcm512x-audio.dtbo \
++ anyspi.dtbo \
+ apds9960.dtbo \
+ applepi-dac.dtbo \
+ at86rf233.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -441,6 +441,29 @@ Params: 24db_digital_gain Allow ga
+ better voice quality. (default Off)
+
+
++Name: anyspi
++Info: Universal device tree overlay for SPI devices
++
++ Just specify the SPI address and device name ("compatible" property).
++ This overlay lacks any device-specific parameter support!
++
++ 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.
++
++ Examples:
++ 1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz:
++ dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000
++ 2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz:
++ dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204"
++Load: dtoverlay=anyspi,<param>=<val>
++Params: spi<n>-<m> Configure device at spi<n>, cs<m>
++ (boolean, required)
++ dev Set device name to search compatible module
++ (string, required)
++ speed Set SPI clock frequency in Hz
++ (integer, optional, default 500000)
++
++
+ Name: apds9960
+ Info: Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and
+ gesture sensor
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/anyspi-overlay.dts
+@@ -0,0 +1,205 @@
++/*
++ * Universal device tree overlay for SPI devices
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spidev0>;
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev1>;
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target-path = "spi1/spidev@0";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target-path = "spi1/spidev@1";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@4 {
++ target-path = "spi1/spidev@2";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@5 {
++ target-path = "spi2/spidev@0";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@6 {
++ target-path = "spi2/spidev@1";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@7 {
++ target-path = "spi2/spidev@2";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@8 {
++ target = <&spi0>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_00: anyspi@0 {
++ reg = <0>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@9 {
++ target = <&spi0>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_01: anyspi@1 {
++ reg = <1>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@10 {
++ target = <&spi1>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_10: anyspi@0 {
++ reg = <0>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@11 {
++ target = <&spi1>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_11: anyspi@1 {
++ reg = <1>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@12 {
++ target = <&spi1>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_12: anyspi@2 {
++ reg = <2>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@13 {
++ target = <&spi2>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_20: anyspi@0 {
++ reg = <0>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@14 {
++ target = <&spi2>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_21: anyspi@1 {
++ reg = <1>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@15 {
++ target = <&spi2>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_22: anyspi@2 {
++ reg = <2>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ __overrides__ {
++ spi0-0 = <0>, "+0+8";
++ spi0-1 = <0>, "+1+9";
++ spi1-0 = <0>, "+2+10";
++ spi1-1 = <0>, "+3+11";
++ spi1-2 = <0>, "+4+12";
++ spi2-0 = <0>, "+5+13";
++ spi2-1 = <0>, "+6+14";
++ spi2-2 = <0>, "+7+15";
++ dev = <&anyspi_00>,"compatible",
++ <&anyspi_01>,"compatible",
++ <&anyspi_10>,"compatible",
++ <&anyspi_11>,"compatible",
++ <&anyspi_12>,"compatible",
++ <&anyspi_20>,"compatible",
++ <&anyspi_21>,"compatible",
++ <&anyspi_22>,"compatible";
++ speed = <&anyspi_00>, "spi-max-frequency:0",
++ <&anyspi_01>, "spi-max-frequency:0",
++ <&anyspi_10>, "spi-max-frequency:0",
++ <&anyspi_11>, "spi-max-frequency:0",
++ <&anyspi_12>, "spi-max-frequency:0",
++ <&anyspi_20>, "spi-max-frequency:0",
++ <&anyspi_21>, "spi-max-frequency:0",
++ <&anyspi_22>, "spi-max-frequency:0";
++ };
++};
--- /dev/null
+From bb4781b1dac98688a3cf64cf728a64d811ca6add Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
+Date: Tue, 21 Jan 2020 15:58:39 +0100
+Subject: [PATCH] sound: Add the HiFiBerry DAC+HD version
+
+This adds the driver for the DAC+HD version supporting HiFiBerry's
+PCM179x based DACs. It also adds PLL control for clock generation.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 +
+ .../overlays/hifiberry-dacplushd-overlay.dts | 106 ++++++
+ drivers/clk/Makefile | 1 +
+ drivers/clk/clk-hifiberry-dachd.c | 333 ++++++++++++++++++
+ sound/soc/bcm/Kconfig | 7 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/hifiberry_dacplushd.c | 235 ++++++++++++
+ 13 files changed, 696 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
+ create mode 100644 drivers/clk/clk-hifiberry-dachd.c
+ create mode 100644 sound/soc/bcm/hifiberry_dacplushd.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -57,6 +57,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ hifiberry-dacplusadc.dtbo \
+ hifiberry-dacplusadcpro.dtbo \
+ hifiberry-dacplusdsp.dtbo \
++ hifiberry-dacplushd.dtbo \
+ hifiberry-digi.dtbo \
+ hifiberry-digi-pro.dtbo \
+ hy28a.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -956,6 +956,12 @@ Load: dtoverlay=hifiberry-dacplusdsp
+ Params: <None>
+
+
++Name: hifiberry-dacplushd
++Info: Configures the HifiBerry DAC+ HD audio card
++Load: dtoverlay=hifiberry-dacplushd
++Params: <None>
++
++
+ Name: hifiberry-digi
+ Info: Configures the HifiBerry Digi and Digi+ audio card
+ Load: dtoverlay=hifiberry-digi
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
+@@ -0,0 +1,106 @@
++// Definitions for HiFiBerry DAC+ HD
++/dts-v1/;
++/plugin/;
++
++#include <dt-bindings/gpio/gpio.h>
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target-path = "/clocks";
++ __overlay__ {
++ dachd_osc: pll_dachd_osc {
++ compatible = "hifiberry,dachd-clk";
++ #clock-cells = <0>;
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm1792a@4c {
++ compatible = "ti,pcm1792a";
++ #sound-dai-cells = <0>;
++ #clock-cells = <0>;
++ clocks = <&dachd_osc>;
++ reg = <0x4c>;
++ status = "okay";
++ };
++ pll: pll@62 {
++ compatible = "hifiberry,dachd-clk";
++ #clock-cells = <0>;
++ reg = <0x62>;
++ clocks = <&dachd_osc>;
++ status = "okay";
++ common_pll_regs = [
++ 02 53 03 00 07 20 0F 00
++ 10 0D 11 1D 12 0D 13 8C
++ 14 8C 15 8C 16 8C 17 8C
++ 18 2A 1C 00 1D 0F 1F 00
++ 2A 00 2C 00 2F 00 30 00
++ 31 00 32 00 34 00 37 00
++ 38 00 39 00 3A 00 3B 01
++ 3E 00 3F 00 40 00 41 00
++ 5A 00 5B 00 95 00 96 00
++ 97 00 98 00 99 00 9A 00
++ 9B 00 A2 00 A3 00 A4 00
++ B7 92 ];
++ 192k_pll_regs = [
++ 1A 0C 1B 35 1E F0 20 09
++ 21 50 2B 02 2D 10 2E 40
++ 33 01 35 22 36 80 3C 22
++ 3D 46 ];
++ 96k_pll_regs = [
++ 1A 0C 1B 35 1E F0 20 09
++ 21 50 2B 02 2D 10 2E 40
++ 33 01 35 47 36 00 3C 32
++ 3D 46 ];
++ 48k_pll_regs = [
++ 1A 0C 1B 35 1E F0 20 09
++ 21 50 2B 02 2D 10 2E 40
++ 33 01 35 90 36 00 3C 42
++ 3D 46 ];
++ 176k4_pll_regs = [
++ 1A 3D 1B 09 1E F3 20 13
++ 21 75 2B 04 2D 11 2E E0
++ 33 02 35 25 36 C0 3C 22
++ 3D 7A ];
++ 88k2_pll_regs = [
++ 1A 3D 1B 09 1E F3 20 13
++ 21 75 2B 04 2D 11 2E E0
++ 33 01 35 4D 36 80 3C 32
++ 3D 7A ];
++ 44k1_pll_regs = [
++ 1A 3D 1B 09 1E F3 20 13
++ 21 75 2B 04 2D 11 2E E0
++ 33 01 35 9D 36 00 3C 42
++ 3D 7A ];
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "hifiberry,hifiberry-dacplushd";
++ i2s-controller = <&i2s>;
++ clocks = <&pll 0>;
++ reset-gpio = <&gpio 16 GPIO_ACTIVE_LOW>;
++ status = "okay";
++ };
++ };
++
++};
+--- a/drivers/clk/Makefile
++++ b/drivers/clk/Makefile
+@@ -32,6 +32,7 @@ obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-
+ obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
+ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += clk-hifiberry-dacpro.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += clk-hifiberry-dachd.o
+ obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
+ obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
+ obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
+--- /dev/null
++++ b/drivers/clk/clk-hifiberry-dachd.c
+@@ -0,0 +1,333 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Clock Driver for HiFiBerry DAC+ HD
++ *
++ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
++ * Copyright 2020
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/clk.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++#include <linux/regmap.h>
++
++#define NO_PLL_RESET 0
++#define PLL_RESET 1
++#define HIFIBERRY_PLL_MAX_REGISTER 256
++#define DEFAULT_RATE 44100
++
++static struct reg_default hifiberry_pll_reg_defaults[] = {
++ {0x02, 0x53}, {0x03, 0x00}, {0x07, 0x20}, {0x0F, 0x00},
++ {0x10, 0x0D}, {0x11, 0x1D}, {0x12, 0x0D}, {0x13, 0x8C},
++ {0x14, 0x8C}, {0x15, 0x8C}, {0x16, 0x8C}, {0x17, 0x8C},
++ {0x18, 0x2A}, {0x1C, 0x00}, {0x1D, 0x0F}, {0x1F, 0x00},
++ {0x2A, 0x00}, {0x2C, 0x00}, {0x2F, 0x00}, {0x30, 0x00},
++ {0x31, 0x00}, {0x32, 0x00}, {0x34, 0x00}, {0x37, 0x00},
++ {0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x01},
++ {0x3E, 0x00}, {0x3F, 0x00}, {0x40, 0x00}, {0x41, 0x00},
++ {0x5A, 0x00}, {0x5B, 0x00}, {0x95, 0x00}, {0x96, 0x00},
++ {0x97, 0x00}, {0x98, 0x00}, {0x99, 0x00}, {0x9A, 0x00},
++ {0x9B, 0x00}, {0xA2, 0x00}, {0xA3, 0x00}, {0xA4, 0x00},
++ {0xB7, 0x92},
++ {0x1A, 0x3D}, {0x1B, 0x09}, {0x1E, 0xF3}, {0x20, 0x13},
++ {0x21, 0x75}, {0x2B, 0x04}, {0x2D, 0x11}, {0x2E, 0xE0},
++ {0x3D, 0x7A},
++ {0x35, 0x9D}, {0x36, 0x00}, {0x3C, 0x42},
++ { 177, 0xAC},
++};
++static struct reg_default common_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_common_pll_regs;
++static struct reg_default dedicated_192k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_192k_pll_regs;
++static struct reg_default dedicated_96k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_96k_pll_regs;
++static struct reg_default dedicated_48k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_48k_pll_regs;
++static struct reg_default dedicated_176k4_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_176k4_pll_regs;
++static struct reg_default dedicated_88k2_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_88k2_pll_regs;
++static struct reg_default dedicated_44k1_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_44k1_pll_regs;
++
++/**
++ * struct clk_hifiberry_drvdata - Common struct to the HiFiBerry DAC HD Clk
++ * @hw: clk_hw for the common clk framework
++ */
++struct clk_hifiberry_drvdata {
++ struct regmap *regmap;
++ struct clk *clk;
++ struct clk_hw hw;
++ unsigned long rate;
++};
++
++#define to_hifiberry_clk(_hw) \
++ container_of(_hw, struct clk_hifiberry_drvdata, hw)
++
++static int clk_hifiberry_dachd_write_pll_regs(struct regmap *regmap,
++ struct reg_default *regs,
++ int num, int do_pll_reset)
++{
++ int i;
++ int ret = 0;
++ char pll_soft_reset[] = { 177, 0xAC, };
++
++ for (i = 0; i < num; i++) {
++ ret |= regmap_write(regmap, regs[i].reg, regs[i].def);
++ if (ret)
++ return ret;
++ }
++ if (do_pll_reset) {
++ ret |= regmap_write(regmap, pll_soft_reset[0],
++ pll_soft_reset[1]);
++ mdelay(10);
++ }
++ return ret;
++}
++
++static unsigned long clk_hifiberry_dachd_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ return to_hifiberry_clk(hw)->rate;
++}
++
++static long clk_hifiberry_dachd_round_rate(struct clk_hw *hw,
++ unsigned long rate, unsigned long *parent_rate)
++{
++ return rate;
++}
++
++static int clk_hifiberry_dachd_set_rate(struct clk_hw *hw,
++ unsigned long rate, unsigned long parent_rate)
++{
++ int ret;
++ struct clk_hifiberry_drvdata *drvdata = to_hifiberry_clk(hw);
++
++ switch (rate) {
++ case 44100:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_44k1_pll_regs, num_dedicated_44k1_pll_regs,
++ PLL_RESET);
++ break;
++ case 88200:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_88k2_pll_regs, num_dedicated_88k2_pll_regs,
++ PLL_RESET);
++ break;
++ case 176400:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_176k4_pll_regs, num_dedicated_176k4_pll_regs,
++ PLL_RESET);
++ break;
++ case 48000:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_48k_pll_regs, num_dedicated_48k_pll_regs,
++ PLL_RESET);
++ break;
++ case 96000:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_96k_pll_regs, num_dedicated_96k_pll_regs,
++ PLL_RESET);
++ break;
++ case 192000:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_192k_pll_regs, num_dedicated_192k_pll_regs,
++ PLL_RESET);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ to_hifiberry_clk(hw)->rate = rate;
++
++ return ret;
++}
++
++const struct clk_ops clk_hifiberry_dachd_rate_ops = {
++ .recalc_rate = clk_hifiberry_dachd_recalc_rate,
++ .round_rate = clk_hifiberry_dachd_round_rate,
++ .set_rate = clk_hifiberry_dachd_set_rate,
++};
++
++static int clk_hifiberry_get_prop_values(struct device *dev,
++ char *prop_name,
++ struct reg_default *regs)
++{
++ int ret;
++ int i;
++ u8 tmp[2 * HIFIBERRY_PLL_MAX_REGISTER];
++
++ ret = of_property_read_variable_u8_array(dev->of_node, prop_name,
++ tmp, 0, 2 * HIFIBERRY_PLL_MAX_REGISTER);
++ if (ret < 0)
++ return ret;
++ if (ret & 1) {
++ dev_err(dev,
++ "%s <%s> -> #%i odd number of bytes for reg/val pairs!",
++ __func__,
++ prop_name,
++ ret);
++ return -EINVAL;
++ }
++ ret /= 2;
++ for (i = 0; i < ret; i++) {
++ regs[i].reg = (u32)tmp[2 * i];
++ regs[i].def = (u32)tmp[2 * i + 1];
++ }
++ return ret;
++}
++
++
++static int clk_hifiberry_dachd_dt_parse(struct device *dev)
++{
++ num_common_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "common_pll_regs", common_pll_regs);
++ num_dedicated_44k1_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "44k1_pll_regs", dedicated_44k1_pll_regs);
++ num_dedicated_88k2_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "88k2_pll_regs", dedicated_88k2_pll_regs);
++ num_dedicated_176k4_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "176k4_pll_regs", dedicated_176k4_pll_regs);
++ num_dedicated_48k_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "48k_pll_regs", dedicated_48k_pll_regs);
++ num_dedicated_96k_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "96k_pll_regs", dedicated_96k_pll_regs);
++ num_dedicated_192k_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "192k_pll_regs", dedicated_192k_pll_regs);
++ return 0;
++}
++
++
++static int clk_hifiberry_dachd_remove(struct device *dev)
++{
++ of_clk_del_provider(dev->of_node);
++ return 0;
++}
++
++const struct regmap_config hifiberry_pll_regmap = {
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = HIFIBERRY_PLL_MAX_REGISTER,
++ .reg_defaults = hifiberry_pll_reg_defaults,
++ .num_reg_defaults = ARRAY_SIZE(hifiberry_pll_reg_defaults),
++ .cache_type = REGCACHE_RBTREE,
++};
++EXPORT_SYMBOL_GPL(hifiberry_pll_regmap);
++
++
++static int clk_hifiberry_dachd_i2c_probe(struct i2c_client *i2c,
++ const struct i2c_device_id *id)
++{
++ struct clk_hifiberry_drvdata *hdclk;
++ int ret = 0;
++ struct clk_init_data init;
++ struct device *dev = &i2c->dev;
++ struct device_node *dev_node = dev->of_node;
++ struct regmap_config config = hifiberry_pll_regmap;
++
++ hdclk = devm_kzalloc(&i2c->dev,
++ sizeof(struct clk_hifiberry_drvdata), GFP_KERNEL);
++ if (!hdclk)
++ return -ENOMEM;
++
++ i2c_set_clientdata(i2c, hdclk);
++
++ hdclk->regmap = devm_regmap_init_i2c(i2c, &config);
++
++ if (IS_ERR(hdclk->regmap))
++ return PTR_ERR(hdclk->regmap);
++
++ /* start PLL to allow detection of DAC */
++ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap,
++ hifiberry_pll_reg_defaults,
++ ARRAY_SIZE(hifiberry_pll_reg_defaults),
++ PLL_RESET);
++ if (ret)
++ return ret;
++
++ clk_hifiberry_dachd_dt_parse(dev);
++
++ /* restart PLL with configs from DTB */
++ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, common_pll_regs,
++ num_common_pll_regs, PLL_RESET);
++ if (ret)
++ return ret;
++
++ init.name = "clk-hifiberry-dachd";
++ init.ops = &clk_hifiberry_dachd_rate_ops;
++ init.flags = CLK_IS_BASIC;
++ init.parent_names = NULL;
++ init.num_parents = 0;
++
++ hdclk->hw.init = &init;
++
++ hdclk->clk = devm_clk_register(dev, &hdclk->hw);
++ if (IS_ERR(hdclk->clk)) {
++ dev_err(dev, "unable to register %s\n", init.name);
++ return PTR_ERR(hdclk->clk);
++ }
++
++ ret = of_clk_add_provider(dev_node, of_clk_src_simple_get, hdclk->clk);
++ if (ret != 0) {
++ dev_err(dev, "Cannot of_clk_add_provider");
++ return ret;
++ }
++
++ ret = clk_set_rate(hdclk->hw.clk, DEFAULT_RATE);
++ if (ret != 0) {
++ dev_err(dev, "Cannot set rate : %d\n", ret);
++ return -EINVAL;
++ }
++
++ return ret;
++}
++
++static int clk_hifiberry_dachd_i2c_remove(struct i2c_client *i2c)
++{
++ clk_hifiberry_dachd_remove(&i2c->dev);
++ return 0;
++}
++
++static const struct i2c_device_id clk_hifiberry_dachd_i2c_id[] = {
++ { "dachd-clk", },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, clk_hifiberry_dachd_i2c_id);
++
++static const struct of_device_id clk_hifiberry_dachd_of_match[] = {
++ { .compatible = "hifiberry,dachd-clk", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, clk_hifiberry_dachd_of_match);
++
++static struct i2c_driver clk_hifiberry_dachd_i2c_driver = {
++ .probe = clk_hifiberry_dachd_i2c_probe,
++ .remove = clk_hifiberry_dachd_i2c_remove,
++ .id_table = clk_hifiberry_dachd_i2c_id,
++ .driver = {
++ .name = "dachd-clk",
++ .of_match_table = of_match_ptr(clk_hifiberry_dachd_of_match),
++ },
++};
++
++module_i2c_driver(clk_hifiberry_dachd_i2c_driver);
++
++
++MODULE_DESCRIPTION("HiFiBerry DAC+ HD clock driver");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:clk-hifiberry-dachd");
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -40,6 +40,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
+ help
+ Say Y or M if you want to add support for HifiBerry DAC+.
+
++config SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD
++ tristate "Support for HifiBerry DAC+ HD"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_PCM179X_I2C
++ help
++ Say Y or M if you want to add support for HifiBerry DAC+ HD.
++
+ config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC
+ tristate "Support for HifiBerry DAC+ADC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -13,6 +13,7 @@ snd-soc-googlevoicehat-codec-objs := goo
+
+ # BCM2708 Machine Support
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
++snd-soc-hifiberry-dacplushd-objs := hifiberry_dacplushd.o
+ snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
+ snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
+ snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
+@@ -40,6 +41,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi
+
+ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += snd-soc-hifiberry-dacplushd.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
+--- /dev/null
++++ b/sound/soc/bcm/hifiberry_dacplushd.c
+@@ -0,0 +1,235 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * ASoC Driver for HiFiBerry DAC+ HD
++ *
++ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
++ * Copyright 2020
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/delay.h>
++#include <linux/gpio.h>
++#include <linux/gpio/consumer.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <linux/i2c.h>
++#include <linux/clk.h>
++
++#include "../codecs/pcm179x.h"
++
++#define DEFAULT_RATE 44100
++
++struct brd_drv_data {
++ struct regmap *regmap;
++ struct clk *sclk;
++};
++
++static struct brd_drv_data drvdata;
++static struct gpio_desc *reset_gpio;
++static const unsigned int hb_dacplushd_rates[] = {
++ 192000, 96000, 48000, 176400, 88200, 44100,
++};
++
++static struct snd_pcm_hw_constraint_list hb_dacplushd_constraints = {
++ .list = hb_dacplushd_rates,
++ .count = ARRAY_SIZE(hb_dacplushd_rates),
++};
++
++static int snd_rpi_hb_dacplushd_startup(struct snd_pcm_substream *substream)
++{
++ /* constraints for standard sample rates */
++ snd_pcm_hw_constraint_list(substream->runtime, 0,
++ SNDRV_PCM_HW_PARAM_RATE,
++ &hb_dacplushd_constraints);
++ return 0;
++}
++
++static void snd_rpi_hifiberry_dacplushd_set_sclk(
++ struct snd_soc_component *component,
++ int sample_rate)
++{
++ if (!IS_ERR(drvdata.sclk))
++ clk_set_rate(drvdata.sclk, sample_rate);
++}
++
++static int snd_rpi_hifiberry_dacplushd_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_dai_link *dai = rtd->dai_link;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ dai->name = "HiFiBerry DAC+ HD";
++ dai->stream_name = "HiFiBerry DAC+ HD HiFi";
++ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBM_CFM;
++
++ /* allow only fixed 32 clock counts per channel */
++ snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
++
++ return 0;
++}
++
++static int snd_rpi_hifiberry_dacplushd_hw_params(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ int ret = 0;
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++
++ struct snd_soc_component *component = rtd->codec_dai->component;
++
++ snd_rpi_hifiberry_dacplushd_set_sclk(component, params_rate(params));
++ return ret;
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_hifiberry_dacplushd_ops = {
++ .startup = snd_rpi_hb_dacplushd_startup,
++ .hw_params = snd_rpi_hifiberry_dacplushd_hw_params,
++};
++
++static struct snd_soc_dai_link snd_rpi_hifiberry_dacplushd_dai[] = {
++{
++ .name = "HiFiBerry DAC+ HD",
++ .stream_name = "HiFiBerry DAC+ HD HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "pcm179x-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "pcm179x.1-004c",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_hifiberry_dacplushd_ops,
++ .init = snd_rpi_hifiberry_dacplushd_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_hifiberry_dacplushd = {
++ .name = "snd_rpi_hifiberry_dacplushd",
++ .driver_name = "HifiberryDacplusHD",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_hifiberry_dacplushd_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplushd_dai),
++};
++
++static int snd_rpi_hifiberry_dacplushd_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ static int dac_reset_done;
++ struct device *dev = &pdev->dev;
++ struct device_node *dev_node = dev->of_node;
++
++ snd_rpi_hifiberry_dacplushd.dev = &pdev->dev;
++
++ /* get GPIO and release DAC from RESET */
++ if (!dac_reset_done) {
++ reset_gpio = gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
++ if (IS_ERR(reset_gpio)) {
++ dev_err(&pdev->dev, "gpiod_get() failed\n");
++ return -EINVAL;
++ }
++ dac_reset_done = 1;
++ }
++ if (!IS_ERR(reset_gpio))
++ gpiod_set_value(reset_gpio, 0);
++ msleep(1);
++ if (!IS_ERR(reset_gpio))
++ gpiod_set_value(reset_gpio, 1);
++ msleep(1);
++ if (!IS_ERR(reset_gpio))
++ gpiod_set_value(reset_gpio, 0);
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai;
++
++ dai = &snd_rpi_hifiberry_dacplushd_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ } else {
++ return -EPROBE_DEFER;
++ }
++
++ }
++
++ ret = devm_snd_soc_register_card(&pdev->dev,
++ &snd_rpi_hifiberry_dacplushd);
++ if (ret && ret != -EPROBE_DEFER) {
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++ return ret;
++ }
++ if (ret == -EPROBE_DEFER)
++ return ret;
++
++ dev_set_drvdata(dev, &drvdata);
++ if (dev_node == NULL) {
++ dev_err(&pdev->dev, "Device tree node not found\n");
++ return -ENODEV;
++ }
++
++ drvdata.sclk = devm_clk_get(dev, NULL);
++ if (IS_ERR(drvdata.sclk)) {
++ drvdata.sclk = ERR_PTR(-ENOENT);
++ return -ENODEV;
++ }
++
++ clk_set_rate(drvdata.sclk, DEFAULT_RATE);
++
++ return ret;
++}
++
++static int snd_rpi_hifiberry_dacplushd_remove(struct platform_device *pdev)
++{
++ if (IS_ERR(reset_gpio))
++ return -EINVAL;
++
++ /* put DAC into RESET and release GPIO */
++ gpiod_set_value(reset_gpio, 0);
++ gpiod_put(reset_gpio);
++
++ return 0;
++}
++
++static const struct of_device_id snd_rpi_hifiberry_dacplushd_of_match[] = {
++ { .compatible = "hifiberry,hifiberry-dacplushd", },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplushd_of_match);
++
++static struct platform_driver snd_rpi_hifiberry_dacplushd_driver = {
++ .driver = {
++ .name = "snd-rpi-hifiberry-dacplushd",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_hifiberry_dacplushd_of_match,
++ },
++ .probe = snd_rpi_hifiberry_dacplushd_probe,
++ .remove = snd_rpi_hifiberry_dacplushd_remove,
++};
++
++module_platform_driver(snd_rpi_hifiberry_dacplushd_driver);
++
++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ HD");
++MODULE_LICENSE("GPL v2");
--- /dev/null
+From 43551a95378230b8d062e107e012573739af2bf1 Mon Sep 17 00:00:00 2001
+Date: Wed, 22 Jan 2020 16:03:00 +0000
+Subject: [PATCH] Initialise rpi-firmware before clk-bcm2835
+
+The IMA (Integrity Measurement Architecture) looks for a TPM (Trusted
+Platform Module) having been registered when it initialises; otherwise
+it assumes there is no TPM. It has been observed on BCM2835 that IMA
+is initialised before TPM, and that initialising the BCM2835 clock
+driver before the firmware driver has the effect of reversing this
+order.
+
+Change the firmware driver to initialise at core_initcall, delaying the
+BCM2835 clock driver to postcore_initcall.
+
+See: https://github.com/raspberrypi/linux/issues/3291
+ https://github.com/raspberrypi/linux/pull/3297
+
+---
+ drivers/clk/bcm/clk-bcm2835.c | 2 +-
+ drivers/firmware/raspberrypi.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -2388,7 +2388,7 @@ static int __init __bcm2835_clk_driver_i
+ {
+ return platform_driver_register(&bcm2835_clk_driver);
+ }
+-core_initcall(__bcm2835_clk_driver_init);
++postcore_initcall(__bcm2835_clk_driver_init);
+
+ MODULE_DESCRIPTION("BCM2835 clock driver");
+--- a/drivers/firmware/raspberrypi.c
++++ b/drivers/firmware/raspberrypi.c
+@@ -404,7 +404,7 @@ out2:
+ out1:
+ return ret;
+ }
+-subsys_initcall(rpi_firmware_init);
++core_initcall(rpi_firmware_init);
+
+ static void __init rpi_firmware_exit(void)
+ {
--- /dev/null
+From 898cec85907f8f171264c8be281a9ac2979b1655 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
+Date: Thu, 23 Jan 2020 13:32:13 +0100
+Subject: [PATCH] Fix master mode settings of HiFiBerry DAC+ADC PRO
+ card (#3424)
+
+This patch fixes the board DAI setting when in master-mode.
+Wrong setting could have caused random pop noise.
+
+---
+ sound/soc/bcm/hifiberry_dacplusadcpro.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c
++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
+@@ -285,6 +285,8 @@ static int snd_rpi_hifiberry_dacplusadcp
+
+ dai->name = "HiFiBerry DAC+ADC Pro";
+ dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi";
++ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBM_CFM;
+
+ // set DAC DAI configuration
+ ret = snd_soc_dai_set_fmt(rtd->codec_dais[0],
--- /dev/null
+From 0a865ae13d5f98594562ebe5713caec65ab689e5 Mon Sep 17 00:00:00 2001
+Date: Fri, 24 Jan 2020 09:02:37 +0000
+Subject: [PATCH] overlays: Use preferred compatible strings
+
+Make sure all overlays have correct compatible strings before enabling
+the automated checking.
+
+---
+ arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts | 2 ++
+ arch/arm/boot/dts/overlays/pwm-overlay.dts | 2 ++
+ arch/arm/boot/dts/overlays/smi-dev-overlay.dts | 2 ++
+ 5 files changed, 8 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/clocks";
+--- a/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
++++ b/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
+@@ -17,6 +17,8 @@ N.B.:
+ */
+
+ / {
++ compatible = "brcm,bcm2835";
++
+ fragment@0 {
+ target = <&gpio>;
+ __overlay__ {
+--- a/arch/arm/boot/dts/overlays/pwm-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pwm-overlay.dts
+@@ -15,6 +15,8 @@ N.B.:
+ */
+
+ / {
++ compatible = "brcm,bcm2835";
++
+ fragment@0 {
+ target = <&gpio>;
+ __overlay__ {
+--- a/arch/arm/boot/dts/overlays/smi-dev-overlay.dts
++++ b/arch/arm/boot/dts/overlays/smi-dev-overlay.dts
+@@ -5,6 +5,8 @@
+ /plugin/;
+
+ /{
++ compatible = "brcm,bcm2835";
++
+ fragment@0 {
+ target = <&soc>;
+ __overlay__ {
--- /dev/null
+From d4f4b57c667141ca98711cfcb30ae2b8deb1a034 Mon Sep 17 00:00:00 2001
+Date: Fri, 24 Jan 2020 11:38:28 +0000
+Subject: [PATCH] tty: amba-pl011: Add un/throttle support
+
+The PL011 driver lacks throttle and unthrottle methods. As a result,
+sending more data to the Pi than it can immediately sink while CRTSCTS
+is enabled causes a NULL pointer to be followed.
+
+Add a throttle handler that disables the RX interrupts, and an
+unthrottle handler that reenables them.
+
+---
+ drivers/tty/serial/amba-pl011.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -1323,6 +1323,32 @@ static void pl011_start_tx(struct uart_p
+ pl011_start_tx_pio(uap);
+ }
+
++static void pl011_throttle(struct uart_port *port)
++{
++ struct uart_amba_port *uap =
++ container_of(port, struct uart_amba_port, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&uap->port.lock, flags);
++ uap->im &= ~(UART011_RTIM | UART011_RXIM);
++ pl011_write(uap->im, uap, REG_IMSC);
++ spin_unlock_irqrestore(&uap->port.lock, flags);
++}
++
++static void pl011_unthrottle(struct uart_port *port)
++{
++ struct uart_amba_port *uap =
++ container_of(port, struct uart_amba_port, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&uap->port.lock, flags);
++ uap->im |= UART011_RTIM;
++ if (!pl011_dma_rx_running(uap))
++ uap->im |= UART011_RXIM;
++ pl011_write(uap->im, uap, REG_IMSC);
++ spin_unlock_irqrestore(&uap->port.lock, flags);
++}
++
+ static void pl011_stop_rx(struct uart_port *port)
+ {
+ struct uart_amba_port *uap =
+@@ -2165,6 +2191,8 @@ static const struct uart_ops amba_pl011_
+ .stop_tx = pl011_stop_tx,
+ .start_tx = pl011_start_tx,
+ .stop_rx = pl011_stop_rx,
++ .throttle = pl011_throttle,
++ .unthrottle = pl011_unthrottle,
+ .enable_ms = pl011_enable_ms,
+ .break_ctl = pl011_break_ctl,
+ .startup = pl011_startup,
--- /dev/null
+From 493aa5b9a2f57003dd0a16946eb56b08650090b4 Mon Sep 17 00:00:00 2001
+Date: Sun, 26 Jan 2020 23:33:54 +0100
+Subject: [PATCH] Fix i2c-pwm-pca9685a overlay
+
+---
+ arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
+@@ -13,7 +13,7 @@
+ status = "okay";
+
+ pca: pca@40 {
+- compatible = "nxp,pca9685";
++ compatible = "nxp,pca9685-pwm";
+ #pwm-cells = <2>;
+ reg = <0x40>;
+ status = "okay";
--- /dev/null
+From c23190019110e3314041f2184552a8343de55117 Mon Sep 17 00:00:00 2001
+Date: Mon, 27 Jan 2020 17:45:51 +0100
+Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+ADC PRO sound
+ card
+
+This adds a DT overlay parameter 'leds_off' which allows
+to switch off the onboard activity LEDs at all times
+which has been requested by some users.
+
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ .../overlays/hifiberry-dacplusadcpro-overlay.dts | 1 +
+ sound/soc/bcm/hifiberry_dacplusadcpro.c | 15 +++++++++++++--
+ 3 files changed, 16 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -948,6 +948,8 @@ Params: 24db_digital_gain Allow ga
+ that does not result in clipping/distortion!)
+ slave Force DAC+ADC Pro into slave mode, using Pi as
+ master for bit clock and frame clock.
++ leds_off If set to 'true' the onboard indicator LEDs
++ are switched off at all times.
+
+
+ Name: hifiberry-dacplusdsp
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
+@@ -60,5 +60,6 @@
+ 24db_digital_gain =
+ <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,24db_digital_gain?";
+ slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?";
++ leds_off = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,leds_off?";
+ };
+ };
+--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c
++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
+@@ -54,6 +54,7 @@ struct pcm512x_priv {
+ static bool slave;
+ static bool snd_rpi_hifiberry_is_dacpro;
+ static bool digital_gain_0db_limit = true;
++static bool leds_off;
+
+ static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x10
+@@ -321,7 +322,10 @@ static int snd_rpi_hifiberry_dacplusadcp
+
+ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
+ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
+- snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++ if (leds_off)
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++ else
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+
+ ret = pcm1863_add_controls(adc);
+ if (ret < 0)
+@@ -331,7 +335,10 @@ static int snd_rpi_hifiberry_dacplusadcp
+ /* set GPIO2 to output, GPIO3 input */
+ snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00);
+ snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04);
+- snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
++ if (leds_off)
++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00);
++ else
++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
+
+ if (digital_gain_0db_limit) {
+ int ret;
+@@ -417,6 +424,8 @@ static int snd_rpi_hifiberry_dacplusadcp
+ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
+ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
+
++ if (leds_off)
++ return 0;
+ /* switch on respective LED */
+ if (!substream->stream)
+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+@@ -508,6 +517,8 @@ static int snd_rpi_hifiberry_dacplusadcp
+ pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain");
+ slave = of_property_read_bool(pdev->dev.of_node,
+ "hifiberry-dacplusadcpro,slave");
++ leds_off = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplusadcpro,leds_off");
+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro);
+ if (ret && ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
--- /dev/null
+From ee513338448ddbb72ac8f76e7053865fe926a18c Mon Sep 17 00:00:00 2001
+Date: Mon, 27 Jan 2020 20:37:34 +0100
+Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+ADC sound card
+
+This adds a DT overlay parameter 'leds_off' which allows
+to switch off the onboard activity LEDs at all times
+which has been requested by some users.
+
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ .../boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 1 +
+ sound/soc/bcm/hifiberry_dacplusadc.c | 10 +++++++++-
+ 3 files changed, 12 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -927,6 +927,8 @@ Params: 24db_digital_gain Allow ga
+ that does not result in clipping/distortion!)
+ slave Force DAC+ Pro into slave mode, using Pi as
+ master for bit clock and frame clock.
++ leds_off If set to 'true' the onboard indicator LEDs
++ are switched off at all times.
+
+
+ Name: hifiberry-dacplusadcpro
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
+@@ -67,5 +67,6 @@
+ 24db_digital_gain =
+ <&hifiberry_dacplusadc>,"hifiberry,24db_digital_gain?";
+ slave = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,slave?";
++ leds_off = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,leds_off?";
+ };
+ };
+--- a/sound/soc/bcm/hifiberry_dacplusadc.c
++++ b/sound/soc/bcm/hifiberry_dacplusadc.c
+@@ -54,6 +54,7 @@ struct pcm512x_priv {
+ static bool slave;
+ static bool snd_rpi_hifiberry_is_dacpro;
+ static bool digital_gain_0db_limit = true;
++static bool leds_off;
+
+ static void snd_rpi_hifiberry_dacplusadc_select_clk(struct snd_soc_component *component,
+ int clk_id)
+@@ -175,7 +176,10 @@ static int snd_rpi_hifiberry_dacplusadc_
+
+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
+- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++ if (leds_off)
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++ else
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+
+ if (digital_gain_0db_limit) {
+ int ret;
+@@ -256,6 +260,8 @@ static int snd_rpi_hifiberry_dacplusadc_
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_component *component = rtd->codec_dai->component;
+
++ if (leds_off)
++ return 0;
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1,
+ 0x08, 0x08);
+ hifiberry_dacplusadc_LED_cnt++;
+@@ -347,6 +353,8 @@ static int snd_rpi_hifiberry_dacplusadc_
+ pdev->dev.of_node, "hifiberry,24db_digital_gain");
+ slave = of_property_read_bool(pdev->dev.of_node,
+ "hifiberry-dacplusadc,slave");
++ leds_off = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplusadc,leds_off");
+
+ ret = devm_snd_soc_register_card(&pdev->dev,
+ &snd_rpi_hifiberry_dacplusadc);
--- /dev/null
+From 5eccee0e620b799558d89ebee29280116ad37e4f Mon Sep 17 00:00:00 2001
+Date: Mon, 27 Jan 2020 20:58:24 +0100
+Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+/DAC+PRO sound
+ cards
+
+This adds a DT overlay parameter 'leds_off' which allows
+to switch off the onboard activity LEDs at all times
+which has been requested by some users.
+
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ .../boot/dts/overlays/hifiberry-dacplus-overlay.dts | 1 +
+ sound/soc/bcm/hifiberry_dacplus.c | 10 +++++++++-
+ 3 files changed, 12 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -906,6 +906,8 @@ Params: 24db_digital_gain Allow ga
+ that does not result in clipping/distortion!)
+ slave Force DAC+ Pro into slave mode, using Pi as
+ master for bit clock and frame clock.
++ leds_off If set to 'true' the onboard indicator LEDs
++ are switched off at all times.
+
+
+ Name: hifiberry-dacplusadc
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
+@@ -55,5 +55,6 @@
+ 24db_digital_gain =
+ <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?";
+ slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?";
++ leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?";
+ };
+ };
+--- a/sound/soc/bcm/hifiberry_dacplus.c
++++ b/sound/soc/bcm/hifiberry_dacplus.c
+@@ -50,6 +50,7 @@ struct pcm512x_priv {
+ static bool slave;
+ static bool snd_rpi_hifiberry_is_dacpro;
+ static bool digital_gain_0db_limit = true;
++static bool leds_off;
+
+ static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_component *component,
+ int clk_id)
+@@ -171,7 +172,10 @@ static int snd_rpi_hifiberry_dacplus_ini
+
+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
+- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++ if (leds_off)
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++ else
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+
+ if (digital_gain_0db_limit)
+ {
+@@ -251,6 +255,8 @@ static int snd_rpi_hifiberry_dacplus_sta
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_component *component = rtd->codec_dai->component;
+
++ if (leds_off)
++ return 0;
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+ return 0;
+ }
+@@ -319,6 +325,8 @@ static int snd_rpi_hifiberry_dacplus_pro
+ pdev->dev.of_node, "hifiberry,24db_digital_gain");
+ slave = of_property_read_bool(pdev->dev.of_node,
+ "hifiberry-dacplus,slave");
++ leds_off = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplus,leds_off");
+ }
+
+ ret = devm_snd_soc_register_card(&pdev->dev,
--- /dev/null
+From a879ab9cad6b598c08988404934273d3cbfbd993 Mon Sep 17 00:00:00 2001
+Date: Tue, 28 Jan 2020 14:16:37 +0200
+Subject: [PATCH] pisound: Added reading Pisound board hardware
+ revision and exposing it (#3425)
+
+pisound: Added reading Pisound board hardware revision and exposing it in kernel log and sysfs file:
+
+/sys/kernel/pisound/hw_version
+
+---
+ sound/soc/bcm/pisound.c | 86 ++++++++++++++++++++++++++++-------------
+ 1 file changed, 59 insertions(+), 27 deletions(-)
+
+--- a/sound/soc/bcm/pisound.c
++++ b/sound/soc/bcm/pisound.c
+@@ -51,7 +51,8 @@ static void pisnd_spi_set_callback(pisnd
+
+ static const char *pisnd_spi_get_serial(void);
+ static const char *pisnd_spi_get_id(void);
+-static const char *pisnd_spi_get_version(void);
++static const char *pisnd_spi_get_fw_version(void);
++static const char *pisnd_spi_get_hw_version(void);
+
+ static int pisnd_midi_init(struct snd_card *card);
+ static void pisnd_midi_uninit(void);
+@@ -222,7 +223,9 @@ static pisnd_spi_recv_cb g_recvCallback;
+
+ static char g_serial_num[11];
+ static char g_id[25];
+-static char g_version[5];
++enum { MAX_VERSION_STR_LEN = 6 };
++static char g_fw_version[MAX_VERSION_STR_LEN];
++static char g_hw_version[MAX_VERSION_STR_LEN];
+
+ static uint8_t g_ledFlashDuration;
+ static bool g_ledFlashDurationChanged;
+@@ -558,7 +561,8 @@ static int spi_read_info(void)
+ char *p;
+
+ memset(g_serial_num, 0, sizeof(g_serial_num));
+- memset(g_version, 0, sizeof(g_version));
++ memset(g_fw_version, 0, sizeof(g_fw_version));
++ strcpy(g_hw_version, "1.0"); // Assume 1.0 hw version.
+ memset(g_id, 0, sizeof(g_id));
+
+ tmp = spi_transfer16(0);
+@@ -581,12 +585,28 @@ static int spi_read_info(void)
+ return -EINVAL;
+
+ snprintf(
+- g_version,
+- sizeof(g_version),
++ g_fw_version,
++ MAX_VERSION_STR_LEN,
+ "%x.%02x",
+ buffer[0],
+ buffer[1]
+ );
++
++ g_fw_version[MAX_VERSION_STR_LEN-1] = '\0';
++ break;
++ case 3:
++ if (n != 2)
++ return -EINVAL;
++
++ snprintf(
++ g_hw_version,
++ MAX_VERSION_STR_LEN,
++ "%x.%x",
++ buffer[0],
++ buffer[1]
++ );
++
++ g_hw_version[MAX_VERSION_STR_LEN-1] = '\0';
+ break;
+ case 1:
+ if (n >= sizeof(g_serial_num))
+@@ -596,12 +616,14 @@ static int spi_read_info(void)
+ break;
+ case 2:
+ {
+- if (n >= sizeof(g_id))
++ if (n*2 >= sizeof(g_id))
+ return -EINVAL;
+
+ p = g_id;
+ for (j = 0; j < n; ++j)
+ p += sprintf(p, "%02x", buffer[j]);
++
++ *p = '\0';
+ }
+ break;
+ default:
+@@ -619,7 +641,8 @@ static int pisnd_spi_init(struct device
+
+ memset(g_serial_num, 0, sizeof(g_serial_num));
+ memset(g_id, 0, sizeof(g_id));
+- memset(g_version, 0, sizeof(g_version));
++ memset(g_fw_version, 0, sizeof(g_fw_version));
++ memset(g_hw_version, 0, sizeof(g_hw_version));
+
+ spi = pisnd_spi_find_device();
+
+@@ -729,26 +752,22 @@ static void pisnd_spi_set_callback(pisnd
+
+ static const char *pisnd_spi_get_serial(void)
+ {
+- if (strlen(g_serial_num))
+- return g_serial_num;
+-
+- return "";
++ return g_serial_num;
+ }
+
+ static const char *pisnd_spi_get_id(void)
+ {
+- if (strlen(g_id))
+- return g_id;
+-
+- return "";
++ return g_id;
+ }
+
+-static const char *pisnd_spi_get_version(void)
++static const char *pisnd_spi_get_fw_version(void)
+ {
+- if (strlen(g_version))
+- return g_version;
++ return g_fw_version;
++}
+
+- return "";
++static const char *pisnd_spi_get_hw_version(void)
++{
++ return g_hw_version;
+ }
+
+ static const struct of_device_id pisound_of_match[] = {
+@@ -1054,13 +1073,22 @@ static ssize_t pisnd_id_show(
+ return sprintf(buf, "%s\n", pisnd_spi_get_id());
+ }
+
+-static ssize_t pisnd_version_show(
++static ssize_t pisnd_fw_version_show(
+ struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf
+ )
+ {
+- return sprintf(buf, "%s\n", pisnd_spi_get_version());
++ return sprintf(buf, "%s\n", pisnd_spi_get_fw_version());
++}
++
++static ssize_t pisnd_hw_version_show(
++ struct kobject *kobj,
++ struct kobj_attribute *attr,
++ char *buf
++)
++{
++ return sprintf(buf, "%s\n", pisnd_spi_get_hw_version());
+ }
+
+ static ssize_t pisnd_led_store(
+@@ -1085,15 +1113,18 @@ static struct kobj_attribute pisnd_seria
+ __ATTR(serial, 0444, pisnd_serial_show, NULL);
+ static struct kobj_attribute pisnd_id_attribute =
+ __ATTR(id, 0444, pisnd_id_show, NULL);
+-static struct kobj_attribute pisnd_version_attribute =
+- __ATTR(version, 0444, pisnd_version_show, NULL);
++static struct kobj_attribute pisnd_fw_version_attribute =
++ __ATTR(version, 0444, pisnd_fw_version_show, NULL);
++static struct kobj_attribute pisnd_hw_version_attribute =
++__ATTR(hw_version, 0444, pisnd_hw_version_show, NULL);
+ static struct kobj_attribute pisnd_led_attribute =
+ __ATTR(led, 0644, NULL, pisnd_led_store);
+
+ static struct attribute *attrs[] = {
+ &pisnd_serial_attribute.attr,
+ &pisnd_id_attribute.attr,
+- &pisnd_version_attribute.attr,
++ &pisnd_fw_version_attribute.attr,
++ &pisnd_hw_version_attribute.attr,
+ &pisnd_led_attribute.attr,
+ NULL
+ };
+@@ -1112,9 +1143,10 @@ static int pisnd_probe(struct platform_d
+ }
+
+ printi("Detected Pisound card:\n");
+- printi("\tSerial: %s\n", pisnd_spi_get_serial());
+- printi("\tVersion: %s\n", pisnd_spi_get_version());
+- printi("\tId: %s\n", pisnd_spi_get_id());
++ printi("\tSerial: %s\n", pisnd_spi_get_serial());
++ printi("\tFirmware Version: %s\n", pisnd_spi_get_fw_version());
++ printi("\tHardware Version: %s\n", pisnd_spi_get_hw_version());
++ printi("\tId: %s\n", pisnd_spi_get_id());
+
+ pisnd_kobj = kobject_create_and_add("pisound", kernel_kobj);
+ if (!pisnd_kobj) {
--- /dev/null
+From 5ee0de9d7abd644d4cb678fe26ac5130a1a8075f Mon Sep 17 00:00:00 2001
+Date: Fri, 2 Aug 2019 15:20:11 +0100
+Subject: [PATCH] mmc: sdhci-iproc: Fix vmmc regulators on iProc
+
+The Linux support for controlling card power via regulators appears to
+be contentious. I would argue that the default behaviour is contrary to
+the SDHCI spec - turning off the power writes a reserved value to the
+SD Bus Voltage Select field of the Power Control Register, which
+seems to kill the Arasan/iProc controller - but fortunately there is a
+hook in sdhci_ops to override the behaviour. Borrow the implementation
+from sdhci_arasan_set_power.
+
+---
+ drivers/mmc/host/sdhci-iproc.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/mmc/host/sdhci-iproc.c
++++ b/drivers/mmc/host/sdhci-iproc.c
+@@ -162,6 +162,17 @@ static void sdhci_iproc_writeb(struct sd
+ sdhci_iproc_writel(host, newval, reg & ~3);
+ }
+
++static void sdhci_iproc_set_power(struct sdhci_host *host, unsigned char mode,
++ unsigned short vdd)
++{
++ if (!IS_ERR(host->mmc->supply.vmmc)) {
++ struct mmc_host *mmc = host->mmc;
++
++ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
++ }
++ sdhci_set_power_noreg(host, mode, vdd);
++}
++
+ static const struct sdhci_ops sdhci_iproc_ops = {
+ .set_clock = sdhci_set_clock,
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+@@ -178,6 +189,7 @@ static const struct sdhci_ops sdhci_ipro
+ .write_w = sdhci_iproc_writew,
+ .write_b = sdhci_iproc_writeb,
+ .set_clock = sdhci_set_clock,
++ .set_power = sdhci_iproc_set_power,
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .set_bus_width = sdhci_set_bus_width,
+ .reset = sdhci_reset,
--- /dev/null
+From 03bd617d5ba9124a59e86f285385b95415962af7 Mon Sep 17 00:00:00 2001
+Date: Tue, 30 Jul 2019 12:37:02 +0100
+Subject: [PATCH] ARM: dts: Declare RPi 4B SD card power regulator
+
+Later revisions of the Raspberry Pi 4B have a separate control over the
+SD card power. Expose that control to Linux as a fixed regulator with
+a GPIO enable.
+
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 11 +++++++++++
+ arch/arm/configs/bcm2711_defconfig | 2 +-
+ arch/arm64/configs/bcm2711_defconfig | 2 +-
+ 3 files changed, 13 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -122,6 +122,16 @@
+ states = <1800000 0x1
+ 3300000 0x0>;
+ };
++
++ sd_vcc_reg: sd_vcc_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "vcc-sd";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ enable-active-high;
++ gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>;
++ };
+ };
+
+ &sdhost {
+@@ -132,6 +142,7 @@
+ status = "okay";
+ broken-cd;
+ vqmmc-supply = <&sd_io_1v8_reg>;
++ vmmc-supply = <&sd_vcc_reg>;
+ };
+
+ &leds {
--- /dev/null
+From 4b777f389e22abb364e398f45673e54bcda9cc55 Mon Sep 17 00:00:00 2001
+Date: Fri, 12 Jul 2019 11:41:25 +0100
+Subject: [PATCH] pcie-brcmstb: Bounce buffer support is for BCM2711B0
+
+Add a new compatible string to identify BCM2711B0, as later revisions
+don't require the bounce buffer support.
+
+---
+ drivers/pci/controller/pcie-brcmstb.c | 31 +++++++++++++++++++++++----
+ 1 file changed, 27 insertions(+), 4 deletions(-)
+
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -206,6 +206,8 @@ enum pcie_type {
+ BCM7435,
+ GENERIC,
+ BCM7278,
++ BCM2711B0,
++ BCM2711,
+ };
+
+ struct brcm_window {
+@@ -302,6 +304,20 @@ static const int pcie_offsets[] = {
+ [EXT_CFG_DATA] = 0x8000,
+ };
+
++static const struct pcie_cfg_data bcm2711b0_cfg = {
++ .reg_field_info = pcie_reg_field_info,
++ .offsets = pcie_offsets,
++ .max_burst_size = BURST_SIZE_128,
++ .type = BCM2711B0,
++};
++
++static const struct pcie_cfg_data bcm2711_cfg = {
++ .reg_field_info = pcie_reg_field_info,
++ .offsets = pcie_offsets,
++ .max_burst_size = BURST_SIZE_128,
++ .type = BCM2711,
++};
++
+ static const struct pcie_cfg_data bcm7435_cfg = {
+ .reg_field_info = pcie_reg_field_info,
+ .offsets = pcie_offsets,
+@@ -312,7 +328,7 @@ static const struct pcie_cfg_data bcm743
+ static const struct pcie_cfg_data generic_cfg = {
+ .reg_field_info = pcie_reg_field_info,
+ .offsets = pcie_offsets,
+- .max_burst_size = BURST_SIZE_128, // before BURST_SIZE_512
++ .max_burst_size = BURST_SIZE_512,
+ .type = GENERIC,
+ };
+
+@@ -380,7 +396,7 @@ static unsigned int bounce_buffer = 32*1
+ module_param(bounce_buffer, uint, 0644);
+ MODULE_PARM_DESC(bounce_buffer, "Size of bounce buffer");
+
+-static unsigned int bounce_threshold = 0xc0000000;
++static unsigned int bounce_threshold;
+ module_param(bounce_threshold, uint, 0644);
+ MODULE_PARM_DESC(bounce_threshold, "Bounce threshold");
+
+@@ -1681,6 +1697,8 @@ static int brcm_pcie_remove(struct platf
+ }
+
+ static const struct of_device_id brcm_pcie_match[] = {
++ { .compatible = "brcm,bcm2711b0-pcie", .data = &bcm2711b0_cfg },
++ { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg },
+ { .compatible = "brcm,bcm7425-pcie", .data = &bcm7425_cfg },
+ { .compatible = "brcm,bcm7435-pcie", .data = &bcm7435_cfg },
+ { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg },
+@@ -1736,8 +1754,13 @@ static int brcm_pcie_probe(struct platfo
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+- /* To Do: Add hardware check if this ever gets fixed */
+- if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
++ if (!bounce_threshold) {
++ /* PCIe on BCM2711B0 can only address 3GB */
++ if (pcie->type == BCM2711B0 || pcie->type == GENERIC)
++ bounce_threshold = 0xc0000000;
++ }
++
++ if (bounce_threshold && (max_pfn > (bounce_threshold/PAGE_SIZE))) {
+ int ret;
+ ret = brcm_pcie_bounce_init(&pdev->dev, bounce_buffer,
+ (dma_addr_t)bounce_threshold);
--- /dev/null
+From bacf6a02fe12125d2d675f0c6238d9265d31b45f Mon Sep 17 00:00:00 2001
+Date: Fri, 12 Jul 2019 11:43:03 +0100
+Subject: [PATCH] bcm2838.dtsi: Use BCM2711 PCIe compatible string
+
+The BCM2711 PCIe controller has a limited address range in the B0
+silicon, and the driver uses a compatible string to identify the
+limitation. The current Pi 4 firmware will override the compatible
+string if it detects a downstream DTB and it is running on a newer
+revision but set the default value to enable the workaround for
+backwards-compatibility with old firmware.
+
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -327,7 +327,8 @@
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ bus-range = <0x0 0x01>;
+- compatible = "brcm,bcm7211-pcie", "brcm,bcm7445-pcie",
++ compatible = "brcm,bcm2711b0-pcie", // Safe value
++ "brcm,bcm2711-pcie",
+ "brcm,pci-plat-dev";
+ max-link-speed = <2>;
+ tot-num-pcie = <1>;
--- /dev/null
+From 8aa8fd89094952e3201b927fb846ba61b30cab6b Mon Sep 17 00:00:00 2001
+Date: Wed, 29 Jan 2020 11:29:06 +0000
+Subject: [PATCH] ARM: dts: Remove bcm2838-rpi-4-b.dts
+
+Upstream are not going to use the bcm2838 identifier, so begin the
+cleanup by removing the suggested upstream Pi 4 .dts file.
+
+---
+ arch/arm/boot/dts/Makefile | 1 -
+ arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 118 --------------------------
+ 2 files changed, 119 deletions(-)
+ delete mode 100644 arch/arm/boot/dts/bcm2838-rpi-4-b.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -95,7 +95,6 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2836-rpi-2-b.dtb \
+ bcm2837-rpi-3-b.dtb \
+ bcm2837-rpi-3-b-plus.dtb \
+- bcm2838-rpi-4-b.dtb \
+ bcm2835-rpi-zero.dtb \
+ bcm2835-rpi-zero-w.dtb
+ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+--- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
++++ /dev/null
+@@ -1,118 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/dts-v1/;
+-#include "bcm2838.dtsi"
+-#include "bcm2835-rpi.dtsi"
+-#include "bcm2838-rpi.dtsi"
+-
+-/ {
+- compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
+- model = "Raspberry Pi 4 Model B";
+-
+- chosen {
+- /* 8250 auxiliary UART instead of pl011 */
+- stdout-path = "serial1:115200n8";
+- };
+-
+- memory@0 {
+- reg = <0 0 0x40000000>;
+- };
+-
+- leds {
+- act {
+- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+- };
+-
+- pwr {
+- label = "PWR";
+- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+- };
+- };
+-
+- wifi_pwrseq: wifi-pwrseq {
+- compatible = "mmc-pwrseq-simple";
+- reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
+- };
+-
+- sd_io_1v8_reg: sd_io_1v8_reg {
+- status = "okay";
+- compatible = "regulator-gpio";
+- vin-supply = <&vdd_5v0_reg>;
+- regulator-name = "vdd-sd-io";
+- regulator-min-microvolt = <1800000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-boot-on;
+- regulator-always-on;
+- regulator-settling-time-us = <5000>;
+-
+- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
+- states = <1800000 0x1
+- 3300000 0x0>;
+- };
+-};
+-
+-&firmware {
+- expgpio: gpio {
+- compatible = "raspberrypi,firmware-gpio";
+- gpio-controller;
+- #gpio-cells = <2>;
+- gpio-line-names = "BT_ON",
+- "WL_ON",
+- "PWR_LED_OFF",
+- "GLOBAL_RESET",
+- "VDD_SD_IO_SEL",
+- "CAM_GPIO",
+- "",
+- "";
+- status = "okay";
+- };
+-};
+-
+-&pwm1 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio41>;
+- status = "okay";
+-};
+-
+-/* SDHCI is used to control the SDIO for wireless */
+-&sdhci {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- pinctrl-names = "default";
+- pinctrl-0 = <&emmc_gpio34>;
+- status = "okay";
+- bus-width = <4>;
+- non-removable;
+- mmc-pwrseq = <&wifi_pwrseq>;
+-
+- brcmf: wifi@1 {
+- reg = <1>;
+- compatible = "brcm,bcm4329-fmac";
+- };
+-};
+-
+-/* EMMC2 is used to drive the SD card */
+-&emmc2 {
+- status = "okay";
+- broken-cd;
+- vqmmc-supply = <&sd_io_1v8_reg>;
+-};
+-
+-/* uart0 communicates with the BT module */
+-&uart0 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32 &gpclk2_gpio43>;
+- status = "okay";
+-
+- bluetooth {
+- compatible = "brcm,bcm43438-bt";
+- max-speed = <2000000>;
+- shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
+- };
+-};
+-
+-/* uart1 is mapped to the pin header */
+-&uart1 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart1_gpio14>;
+- status = "okay";
+-};
--- /dev/null
+From 8ef5143f743a4e922fdf0029f81452d3d7003daf Mon Sep 17 00:00:00 2001
+Date: Wed, 29 Jan 2020 09:35:19 +0000
+Subject: [PATCH] tty: amba-pl011: Avoid rare write-when-full error
+
+Under some circumstances on BCM283x processors data loss can be
+observed - a single byte missing from the TX output stream. These bytes
+are always the last byte of a batch of 8 written from pl011_tx_chars
+when from_irq is true, meaning that the FIFO full flag is not checked
+before writing.
+
+The transmit optimisation relies on the FIFO being half-empty when the
+TX interrupt is raised. Instrumenting the driver further showed that
+the failure case correlated with the TX FIFO full flag being set at the
+point where the last byte was written to the data register, which
+explains the data loss but not how the FIFO appeared to be prematurely
+full. A possible explanation is that a FIFO write was in flight at the
+time the interrupt was raised, but as yet there is no hypothesis as to
+how this might occur.
+
+In the absence of a clear understanding of the failure mechanism, avoid
+the problem by checking the FIFO levels before writing the last byte of
+the group, which will have minimal performance impact.
+
+---
+ drivers/tty/serial/amba-pl011.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -1444,6 +1444,10 @@ static bool pl011_tx_chars(struct uart_a
+ if (likely(from_irq) && count-- == 0)
+ break;
+
++ if (likely(from_irq) && count == 0 &&
++ pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
++ break;
++
+ if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
+ break;
+
--- /dev/null
+From fd483c4e43a983d90c308c4d668e83be4fd6a392 Mon Sep 17 00:00:00 2001
+Date: Wed, 15 Jan 2020 11:26:19 +0000
+Subject: [PATCH] usb: xhci: Raspberry Pi FW loader for VIA VL805
+
+The VL805 FW may either be loaded from an SPI EEPROM or alternatively
+loaded directly by the VideoCore firmware. A PCI reset will reset
+the VL805 XHCI controller on the Raspberry Pi4 requiring the firmware
+to be reloaded if an SPI EEPROM is not present.
+
+Use a VideoCore mailbox to trigger the loading of the VL805
+firmware (if necessary) after a PCI reset.
+
+---
+ drivers/usb/host/pci-quirks.c | 31 +++++++++++++++++++++-
+ include/soc/bcm2835/raspberrypi-firmware.h | 2 +-
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/pci-quirks.c
++++ b/drivers/usb/host/pci-quirks.c
+@@ -18,7 +18,7 @@
+ #include <linux/dmi.h>
+ #include "pci-quirks.h"
+ #include "xhci-ext-caps.h"
+-
++#include <soc/bcm2835/raspberrypi-firmware.h>
+
+ #define UHCI_USBLEGSUP 0xc0 /* legacy support */
+ #define UHCI_USBCMD 0 /* command register */
+@@ -632,6 +632,32 @@ EXPORT_SYMBOL_GPL(usb_amd_pt_check_port)
+
+ #endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */
+
++/* The VL805 firmware may either be loaded from an EEPROM or by the BIOS into
++ * memory. If run from memory it must be reloaded after a PCI fundmental reset.
++ * The Raspberry Pi firmware acts as the BIOS in this case.
++ */
++static void usb_vl805_init(struct pci_dev *pdev)
++{
++#if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE)
++ struct rpi_firmware *fw;
++ struct {
++ u32 dev_addr;
++ } packet;
++ int ret;
++
++ fw = rpi_firmware_get(NULL);
++ if (!fw)
++ return;
++
++ packet.dev_addr = (pdev->bus->number << 20) |
++ (PCI_SLOT(pdev->devfn) << 15) | (PCI_FUNC(pdev->devfn) << 12);
++
++ dev_dbg(&pdev->dev, "RPI_FIRMWARE_NOTIFY_XHCI_RESET %x", packet.dev_addr);
++ ret = rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET,
++ &packet, sizeof(packet));
++#endif
++}
++
+ #if IS_ENABLED(CONFIG_USB_UHCI_HCD)
+
+ /*
+@@ -1226,6 +1252,9 @@ hc_init:
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+ usb_enable_intel_xhci_ports(pdev);
+
++ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483)
++ usb_vl805_init(pdev);
++
+ op_reg_base = base + XHCI_HC_LENGTH(readl(base));
+
+ /* Wait for the host controller to be ready before writing any
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -98,7 +98,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045,
+ RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049,
+ RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050,
+-
++ RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058,
+
+ /* Dispmanx TAGS */
+ RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
--- /dev/null
+From 8a120b47005fccce4534f8a73c3a3deda92f95fa Mon Sep 17 00:00:00 2001
+Date: Wed, 29 Jan 2020 14:32:51 +0000
+Subject: [PATCH] overlays: Correct the eth_led* colour assignments
+
+See: https://github.com/raspberrypi/firmware/issues/1311
+
+---
+ arch/arm/boot/dts/overlays/README | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -109,27 +109,28 @@ Params:
+ Legal values are 2, 3, 4, 5 and 0, where
+ 0 means never downshift (default 2). Pi3B+ only.
+
+- eth_led0 Set mode of LED0 (usually orange). The legal
+- values are:
++ eth_led0 Set mode of LED0 - amber on Pi3B+ (default "1"),
++ green on Pi4 (default "0").
++ The legal values are:
+
+ Pi3B+
+
+- 0=link/activity 1=link1000/activity (default)
++ 0=link/activity 1=link1000/activity
+ 2=link100/activity 3=link10/activity
+ 4=link100/1000/activity 5=link10/1000/activity
+ 6=link10/100/activity 14=off 15=on
+
+ Pi4
+
+- 0=Speed/Activity (default) 1=Speed
+- 2=Speed/Flash activity 3=FDX
++ 0=Speed/Activity 1=Speed
++ 2=Flash activity 3=FDX
+ 4=Off 5=On
+ 6=Alt 7=Speed/Flash
+ 8=Link 9=Activity
+
+- eth_led1 Set mode of LED1 (usually green) (Pi3B+ default
+- "6", Pi4 default "8"). See eth_led0 for legal
+- values.
++ eth_led1 Set mode of LED1 - green on Pi3B (default "6"),
++ amber on Pi4 (default "8"). See eth_led0 for
++ legal values.
+
+ eth_max_speed Set the maximum speed a link is allowed
+ to negotiate. Legal values are 10, 100 and
--- /dev/null
+From b006cc7ddfa96c044068ef367c0bc82c2d221ca3 Mon Sep 17 00:00:00 2001
+Date: Tue, 1 Oct 2019 10:19:50 +0100
+Subject: [PATCH] overlays: Remove hack from uart0 overlay
+
+The uart0 overlay contained a hack to return GPIOs 14 and 15 to inputs
+when the UART0 function was moved to alternative pins. This has the
+unwanted side effect of claiming GPIOs 14 & 15, preventing them being
+used for something else.
+
+See: https://github.com/raspberrypi/linux/issues/2856
+ https://www.raspberrypi.org/forums/viewtopic.php?f=98&t=252911
+
+---
+ arch/arm/boot/dts/overlays/uart0-overlay.dts | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/uart0-overlay.dts
++++ b/arch/arm/boot/dts/overlays/uart0-overlay.dts
+@@ -17,17 +17,16 @@
+ target = <&gpio>;
+ __overlay__ {
+ uart0_pins: uart0_pins {
+- brcm,pins = <14 15 14 15>;
+- brcm,function = <0 0 4 4>; /* alt0 */
+- brcm,pull = <0 0 0 2>;
++ brcm,pins = <14 15>;
++ brcm,function = <4>; /* alt0 */
++ brcm,pull = <0 2>;
+ };
+ };
+ };
+
+ __overrides__ {
+- txd0_pin = <&uart0_pins>,"brcm,pins:8";
+- rxd0_pin = <&uart0_pins>,"brcm,pins:12";
+- pin_func = <&uart0_pins>,"brcm,function:8",
+- <&uart0_pins>,"brcm,function:12";
++ txd0_pin = <&uart0_pins>,"brcm,pins:0";
++ rxd0_pin = <&uart0_pins>,"brcm,pins:4";
++ pin_func = <&uart0_pins>,"brcm,function:0";
+ };
+ };
--- /dev/null
+From d7044f06dea839c61a01e6016a4b9dee15543f8d Mon Sep 17 00:00:00 2001
+Date: Thu, 30 Jan 2020 09:47:00 +0000
+Subject: [PATCH] ARM: dts: Add sd_poll_once dtparam to bcm283x/2711
+
+The old sdtweak overlay allowed the SD interface to be effectively
+disabled unless there was a card present at boot time, but that
+overlay doesn't work on bcm2711 and has largely been replaced by
+a set of sd_* dtparams (which have the advantage of being board-
+specific.
+
+Add an sd_poll_once dtparam to allow the same functionality on
+all Raspberry Pi boards.
+
+See: https://github.com/raspberrypi/linux/issues/3286
+
+---
+ arch/arm/boot/dts/bcm2708-rpi.dtsi | 1 +
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 ++
+ arch/arm/boot/dts/overlays/README | 7 +++++++
+ 3 files changed, 10 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
+@@ -92,6 +92,7 @@
+ watchdog = <&watchdog>,"status";
+ random = <&random>,"status";
+ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
++ sd_poll_once = <&sdhost>,"non-removable?";
+ sd_force_pio = <&sdhost>,"brcm,force-pio?";
+ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
+ sd_debug = <&sdhost>,"brcm,debug";
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -349,5 +349,7 @@
+
+ eth_led0 = <&phy1>,"led-modes:0";
+ eth_led1 = <&phy1>,"led-modes:4";
++
++ sd_poll_once = <&emmc2>, "non-removable?";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -165,6 +165,13 @@ Params:
+ sd_overclock Clock (in MHz) to use when the MMC framework
+ requests 50MHz
+
++ sd_poll_once Looks for a card once after booting. Useful
++ for network booting scenarios to avoid the
++ overhead of continuous polling. N.B. Using
++ this option restricts the system to using a
++ single card per boot (or none at all).
++ (default off)
++
+ sd_force_pio Disable DMA support for SD driver (default off)
+
+ sd_pio_limit Number of blocks above which to use DMA for
--- /dev/null
+From db048a80e63c66607b3bd73fa641802ec83bf166 Mon Sep 17 00:00:00 2001
+Date: Fri, 31 Jan 2020 10:57:21 +0100
+Subject: [PATCH] overlays: Add ssd1306-spi overlay (#3440)
+
+Add an overlay for SSD1306 based OLED boards using SPI.
+This will load the staging fbtft driver.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 12 +++
+ .../boot/dts/overlays/ssd1306-spi-overlay.dts | 82 +++++++++++++++++++
+ 3 files changed, 95 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -168,6 +168,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ spi6-1cs.dtbo \
+ spi6-2cs.dtbo \
+ ssd1306.dtbo \
++ ssd1306-spi.dtbo \
+ superaudioboard.dtbo \
+ sx150x.dtbo \
+ tc358743.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2428,6 +2428,18 @@ Params: address Location
+ https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
+
+
++Name: ssd1306-spi
++Info: Overlay for SSD1306 OLED via SPI using fbtft staging driver.
++Load: dtoverlay=ssd1306-spi,<param>=<val>
++Params: speed SPI bus speed (default 10000000)
++ rotate Display rotation (0, 90, 180 or 270; default 0)
++ fps Delay between frame updates (default 25)
++ debug Debug output level (0-7; default 0)
++ dc_pin GPIO pin for D/C (default 24)
++ reset_pin GPIO pin for RESET (default 25)
++ height Display height (32 or 64; default 64)
++
++
+ Name: superaudioboard
+ Info: Configures the SuperAudioBoard sound card
+ Load: dtoverlay=superaudioboard,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
+@@ -0,0 +1,82 @@
++/*
++ * Device Tree overlay for SSD1306 based SPI OLED display
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target = <&gpio>;
++ __overlay__ {
++ ssd1306_pins: ssd1306_pins {
++ brcm,pins = <25 24>;
++ brcm,function = <1 1>; /* out out */
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ ssd1306: ssd1306@0{
++ compatible = "solomon,ssd1306";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&ssd1306_pins>;
++
++ spi-max-frequency = <10000000>;
++ bgr = <0>;
++ bpp = <1>;
++ rotate = <0>;
++ fps = <25>;
++ buswidth = <8>;
++ reset-gpios = <&gpio 25 0>;
++ dc-gpios = <&gpio 24 0>;
++ debug = <0>;
++
++ solomon,height = <64>;
++ solomon,width = <128>;
++ solomon,page-offset = <0>;
++ };
++ };
++ };
++
++ __overrides__ {
++ speed = <&ssd1306>,"spi-max-frequency:0";
++ rotate = <&ssd1306>,"rotate:0";
++ fps = <&ssd1306>,"fps:0";
++ debug = <&ssd1306>,"debug:0";
++ dc_pin = <&ssd1306>,"dc-gpios:4>";
++ reset_pin = <&ssd1306>,"reset-gpios:4>";
++ height = <&ssd1306>,"solomon,height:0>";
++ };
++};
--- /dev/null
+From 1b8ea7066ee06404e0148702bc3e85a191f6d867 Mon Sep 17 00:00:00 2001
+Date: Fri, 31 Jan 2020 12:45:43 +0100
+Subject: [PATCH] overlays: Add sh1106-spi and ssd1351-spi overlays
+ (#3442)
+
+Add overlays for SH1106 and SSD1351 based OLED displays.
+SH1106 is present in many 1.3 inch OLEDs and SSD1351 is present in
+1.5 inch RGB OLEDs from AliExpress.
+
+This will load the staging fbtft drivers.
+
+---
+ arch/arm/boot/dts/overlays/Makefile | 2 +
+ arch/arm/boot/dts/overlays/README | 23 ++++++
+ .../boot/dts/overlays/sh1106-spi-overlay.dts | 82 +++++++++++++++++++
+ .../boot/dts/overlays/ssd1351-spi-overlay.dts | 81 ++++++++++++++++++
+ 4 files changed, 188 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -145,6 +145,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ sdhost.dtbo \
+ sdio.dtbo \
+ sdtweak.dtbo \
++ sh1106-spi.dtbo \
+ smi.dtbo \
+ smi-dev.dtbo \
+ smi-nand.dtbo \
+@@ -169,6 +170,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ spi6-2cs.dtbo \
+ ssd1306.dtbo \
+ ssd1306-spi.dtbo \
++ ssd1351-spi.dtbo \
+ superaudioboard.dtbo \
+ sx150x.dtbo \
+ tc358743.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2145,6 +2145,18 @@ Params: overclock_50 Clock (i
+ (default on)
+
+
++Name: sh1106-spi
++Info: Overlay for SH1106 OLED via SPI using fbtft staging driver.
++Load: dtoverlay=sh1106-spi,<param>=<val>
++Params: speed SPI bus speed (default 4000000)
++ rotate Display rotation (0, 90, 180 or 270; default 0)
++ fps Delay between frame updates (default 25)
++ debug Debug output level (0-7; default 0)
++ dc_pin GPIO pin for D/C (default 24)
++ reset_pin GPIO pin for RESET (default 25)
++ height Display height (32 or 64; default 64)
++
++
+ Name: smi
+ Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25!
+ Load: dtoverlay=smi
+@@ -2440,6 +2452,17 @@ Params: speed SPI bus
+ height Display height (32 or 64; default 64)
+
+
++Name: ssd1351-spi
++Info: Overlay for SSD1351 OLED via SPI using fbtft staging driver.
++Load: dtoverlay=ssd1351-spi,<param>=<val>
++Params: speed SPI bus speed (default 4500000)
++ rotate Display rotation (0, 90, 180 or 270; default 0)
++ fps Delay between frame updates (default 25)
++ debug Debug output level (0-7; default 0)
++ dc_pin GPIO pin for D/C (default 24)
++ reset_pin GPIO pin for RESET (default 25)
++
++
+ Name: superaudioboard
+ Info: Configures the SuperAudioBoard sound card
+ Load: dtoverlay=superaudioboard,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
+@@ -0,0 +1,82 @@
++/*
++ * Device Tree overlay for SH1106 based SPI OLED display
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target = <&gpio>;
++ __overlay__ {
++ sh1106_pins: sh1106_pins {
++ brcm,pins = <25 24>;
++ brcm,function = <1 1>; /* out out */
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ sh1106: sh1106@0{
++ compatible = "sinowealth,sh1106";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&sh1106_pins>;
++
++ spi-max-frequency = <4000000>;
++ bgr = <0>;
++ bpp = <1>;
++ rotate = <0>;
++ fps = <25>;
++ buswidth = <8>;
++ reset-gpios = <&gpio 25 0>;
++ dc-gpios = <&gpio 24 0>;
++ debug = <0>;
++
++ sinowealth,height = <64>;
++ sinowealth,width = <128>;
++ sinowealth,page-offset = <0>;
++ };
++ };
++ };
++
++ __overrides__ {
++ speed = <&sh1106>,"spi-max-frequency:0";
++ rotate = <&sh1106>,"rotate:0";
++ fps = <&sh1106>,"fps:0";
++ debug = <&sh1106>,"debug:0";
++ dc_pin = <&sh1106>,"dc-gpios:4>";
++ reset_pin = <&sh1106>,"reset-gpios:4>";
++ height = <&sh1106>,"sinowealth,height:0>";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
+@@ -0,0 +1,81 @@
++/*
++ * Device Tree overlay for SSD1351 based SPI OLED display
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target = <&gpio>;
++ __overlay__ {
++ ssd1351_pins: ssd1351_pins {
++ brcm,pins = <25 24>;
++ brcm,function = <1 1>; /* out out */
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ ssd1351: ssd1351@0{
++ compatible = "solomon,ssd1351";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&ssd1351_pins>;
++
++ spi-max-frequency = <4500000>;
++ bgr = <0>;
++ bpp = <16>;
++ rotate = <0>;
++ fps = <25>;
++ buswidth = <8>;
++ reset-gpios = <&gpio 25 0>;
++ dc-gpios = <&gpio 24 0>;
++ debug = <0>;
++
++ solomon,height = <128>;
++ solomon,width = <128>;
++ solomon,page-offset = <0>;
++ };
++ };
++ };
++
++ __overrides__ {
++ speed = <&ssd1351>,"spi-max-frequency:0";
++ rotate = <&ssd1351>,"rotate:0";
++ fps = <&ssd1351>,"fps:0";
++ debug = <&ssd1351>,"debug:0";
++ dc_pin = <&ssd1351>,"dc-gpios:4>";
++ reset_pin = <&ssd1351>,"reset-gpios:4>";
++ };
++};
--- /dev/null
+From 389107911744588cce5e06c23a058c9cfb641f33 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Feb 2020 13:03:21 +0000
+Subject: [PATCH] overlays: dwc2: Increase RX FIFO size
+
+The previous version of the dwc2 overlay set the RX FIFO size to
+256 4-byte words. This sounds large enough for a 1024 byte packet (the
+largest isochronous high speed packet allowed), but it doesn't take
+into account some extra space needed by the hardware.
+
+Minas Harutyunyan at Synopsys (the source of the DWC OTG design)
+came up with a more correct value, 301, but since there is spare packet
+RAM this can be increased to 558 to allow two packets per frame.
+
+See: https://github.com/raspberrypi/linux/issues/3447
+
+---
+ arch/arm/boot/dts/overlays/dwc2-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/dwc2-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts
+@@ -12,7 +12,7 @@
+ compatible = "brcm,bcm2835-usb";
+ dr_mode = "otg";
+ g-np-tx-fifo-size = <32>;
+- g-rx-fifo-size = <256>;
++ g-rx-fifo-size = <558>;
+ g-tx-fifo-size = <512 512 512 512 512 256 256>;
+ status = "okay";
+ };
--- /dev/null
+From 11ef396f6e72b22469e1c8aebf5fd50488a9431d Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Feb 2020 15:22:55 +0000
+Subject: [PATCH] overlays: Fix mcp23017's addr parameter
+
+The addr parameter of the mcp23017 overlay was broken by the addition
+of the noints parameter; splitting the mcp node in two without also
+modifying the second half from the addr parameter would cause the two
+halves to separate. Change the implementation strategy to patch
+fragment 2 (as was originally proposed). This will prevent the
+overlay from being applied at runtime until the "dtoverlay" command
+is improved, but the overlay already has this restriction due to
+fragment 3 so this isn't a step backwards.
+
+See: https://github.com/raspberrypi/linux/issues/3449
+
+---
+ arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
+@@ -48,15 +48,13 @@
+ };
+
+ fragment@4 {
+- target = <&i2c1>;
+- __overlay__ {
+- mcp23017_irq: mcp@20 {
+- #interrupt-cells=<2>;
+- interrupt-parent = <&gpio>;
+- interrupts = <4 2>;
+- interrupt-controller;
+- microchip,irq-mirror;
+- };
++ target = <&mcp23017>;
++ mcp23017_irq: __overlay__ {
++ #interrupt-cells=<2>;
++ interrupt-parent = <&gpio>;
++ interrupts = <4 2>;
++ interrupt-controller;
++ microchip,irq-mirror;
+ };
+ };
+
--- /dev/null
+From f80af7bdb76f767a236eeb55b6ea210023180cd6 Mon Sep 17 00:00:00 2001
+Date: Tue, 4 Feb 2020 16:14:48 +0100
+Subject: [PATCH] overlays: fix sh1106-spi, ssd1306-spi and ssd1351-spi overlays
+
+---
+ .../arm/boot/dts/overlays/sh1106-spi-overlay.dts | 16 +++++++++-------
+ .../boot/dts/overlays/ssd1306-spi-overlay.dts | 16 +++++++++-------
+ .../boot/dts/overlays/ssd1351-spi-overlay.dts | 14 ++++++++------
+ 3 files changed, 26 insertions(+), 20 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
+@@ -71,12 +71,14 @@
+ };
+
+ __overrides__ {
+- speed = <&sh1106>,"spi-max-frequency:0";
+- rotate = <&sh1106>,"rotate:0";
+- fps = <&sh1106>,"fps:0";
+- debug = <&sh1106>,"debug:0";
+- dc_pin = <&sh1106>,"dc-gpios:4>";
+- reset_pin = <&sh1106>,"reset-gpios:4>";
+- height = <&sh1106>,"sinowealth,height:0>";
++ speed = <&sh1106>,"spi-max-frequency:0";
++ rotate = <&sh1106>,"rotate:0";
++ fps = <&sh1106>,"fps:0";
++ debug = <&sh1106>,"debug:0";
++ dc_pin = <&sh1106>,"dc-gpios:4",
++ <&sh1106_pins>,"brcm,pins:4;
++ reset_pin = <&sh1106>,"reset-gpios:4",
++ <&sh1106_pins>,"brcm,pins:0;
++ height = <&sh1106>,"sinowealth,height:0";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
+@@ -71,12 +71,14 @@
+ };
+
+ __overrides__ {
+- speed = <&ssd1306>,"spi-max-frequency:0";
+- rotate = <&ssd1306>,"rotate:0";
+- fps = <&ssd1306>,"fps:0";
+- debug = <&ssd1306>,"debug:0";
+- dc_pin = <&ssd1306>,"dc-gpios:4>";
+- reset_pin = <&ssd1306>,"reset-gpios:4>";
+- height = <&ssd1306>,"solomon,height:0>";
++ speed = <&ssd1306>,"spi-max-frequency:0";
++ rotate = <&ssd1306>,"rotate:0";
++ fps = <&ssd1306>,"fps:0";
++ debug = <&ssd1306>,"debug:0";
++ dc_pin = <&ssd1306>,"dc-gpios:4";
++ <&ssd1306_pins>,"brcm,pins:4";
++ reset_pin = <&ssd1306>,"reset-gpios:4";
++ <&ssd1306_pins>,"brcm,pins:0";
++ height = <&ssd1306>,"solomon,height:0";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
+@@ -71,11 +71,13 @@
+ };
+
+ __overrides__ {
+- speed = <&ssd1351>,"spi-max-frequency:0";
+- rotate = <&ssd1351>,"rotate:0";
+- fps = <&ssd1351>,"fps:0";
+- debug = <&ssd1351>,"debug:0";
+- dc_pin = <&ssd1351>,"dc-gpios:4>";
+- reset_pin = <&ssd1351>,"reset-gpios:4>";
++ speed = <&ssd1351>,"spi-max-frequency:0";
++ rotate = <&ssd1351>,"rotate:0";
++ fps = <&ssd1351>,"fps:0";
++ debug = <&ssd1351>,"debug:0";
++ dc_pin = <&ssd1351>,"dc-gpios:4",
++ <&ssd1351_pins>,"brcm,pins:4";
++ reset_pin = <&ssd1351>,"reset-gpios:4";
++ <&ssd1351_pins>,"brcm,pins:0";
+ };
+ };
--- /dev/null
+From 45754db702ff044e45ba14efdcf3708151e25c5f Mon Sep 17 00:00:00 2001
+Date: Wed, 5 Feb 2020 01:48:10 +0900
+Subject: [PATCH] Fix a sh1106-spi, ssd1306-spi, ssd1351-spi overlays
+
+---
+ arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts | 4 ++--
+ arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts | 4 ++--
+ arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts | 2 +-
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
+@@ -76,9 +76,9 @@
+ fps = <&sh1106>,"fps:0";
+ debug = <&sh1106>,"debug:0";
+ dc_pin = <&sh1106>,"dc-gpios:4",
+- <&sh1106_pins>,"brcm,pins:4;
++ <&sh1106_pins>,"brcm,pins:4";
+ reset_pin = <&sh1106>,"reset-gpios:4",
+- <&sh1106_pins>,"brcm,pins:0;
++ <&sh1106_pins>,"brcm,pins:0";
+ height = <&sh1106>,"sinowealth,height:0";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
+@@ -75,9 +75,9 @@
+ rotate = <&ssd1306>,"rotate:0";
+ fps = <&ssd1306>,"fps:0";
+ debug = <&ssd1306>,"debug:0";
+- dc_pin = <&ssd1306>,"dc-gpios:4";
++ dc_pin = <&ssd1306>,"dc-gpios:4",
+ <&ssd1306_pins>,"brcm,pins:4";
+- reset_pin = <&ssd1306>,"reset-gpios:4";
++ reset_pin = <&ssd1306>,"reset-gpios:4",
+ <&ssd1306_pins>,"brcm,pins:0";
+ height = <&ssd1306>,"solomon,height:0";
+ };
+--- a/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
+@@ -77,7 +77,7 @@
+ debug = <&ssd1351>,"debug:0";
+ dc_pin = <&ssd1351>,"dc-gpios:4",
+ <&ssd1351_pins>,"brcm,pins:4";
+- reset_pin = <&ssd1351>,"reset-gpios:4";
++ reset_pin = <&ssd1351>,"reset-gpios:4",
+ <&ssd1351_pins>,"brcm,pins:0";
+ };
+ };