aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.4/950-0899-media-bcm2835-unicam-Set-VPU-min-clock-freq-to-250Mh.patch
blob: 788606cd8be9dcb7c7fc4377a371b7a366bea603 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
From 09c1533f7f5dabd79aa2018083d1b71d26cd7eda Mon Sep 17 00:00:00 2001
From: Naushir Patuck <naush@raspberrypi.com>
Date: Mon, 11 May 2020 13:02:22 +0100
Subject: [PATCH] media: bcm2835: unicam: Set VPU min clock freq to
 250Mhz.

When streaming with Unicam, the VPU must have a clock frequency of at
least 250Mhz.  Otherwise, the input fifos could overrun, causing
image corruption.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
 arch/arm/boot/dts/bcm270x.dtsi                | 10 ++--
 .../media/platform/bcm2835/bcm2835-unicam.c   | 49 +++++++++++++++++--
 2 files changed, 50 insertions(+), 9 deletions(-)

--- a/arch/arm/boot/dts/bcm270x.dtsi
+++ b/arch/arm/boot/dts/bcm270x.dtsi
@@ -88,8 +88,9 @@
 			reg = <0x7e800000 0x800>,
 			      <0x7e802000 0x4>;
 			interrupts = <2 6>;
-			clocks = <&clocks BCM2835_CLOCK_CAM0>;
-			clock-names = "lp";
+			clocks = <&clocks BCM2835_CLOCK_CAM0>,
+				 <&firmware_clocks 4>;
+			clock-names = "lp", "vpu";
 			power-domains = <&power RPI_POWER_DOMAIN_UNICAM0>;
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -102,8 +103,9 @@
 			reg = <0x7e801000 0x800>,
 			      <0x7e802004 0x4>;
 			interrupts = <2 7>;
-			clocks = <&clocks BCM2835_CLOCK_CAM1>;
-			clock-names = "lp";
+			clocks = <&clocks BCM2835_CLOCK_CAM1>,
+				 <&firmware_clocks 4>;
+			clock-names = "lp", "vpu";
 			power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>;
 			#address-cells = <1>;
 			#size-cells = <0>;
--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
@@ -89,6 +89,11 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
 		v4l2_err(&(dev)->v4l2_dev, fmt, ##arg)
 
 /*
+ * Unicam must request a minimum of 250Mhz from the VPU clock.
+ * Otherwise the input FIFOs overrun and cause image corruption.
+ */
+#define MIN_VPU_CLOCK_RATE (250 * 1000 * 1000)
+/*
  * To protect against a dodgy sensor driver never returning an error from
  * enum_mbus_code, set a maximum index value to be used.
  */
@@ -417,8 +422,10 @@ struct unicam_device {
 	void __iomem *base;
 	/* clock gating base address */
 	void __iomem *clk_gate_base;
-	/* clock handle */
+	/* lp clock handle */
 	struct clk *clock;
+	/* vpu clock handle */
+	struct clk *vpu_clock;
 	/* V4l2 device */
 	struct v4l2_device v4l2_dev;
 	struct media_device mdev;
@@ -1674,16 +1681,28 @@ static int unicam_start_streaming(struct
 	unicam_dbg(1, dev, "Running with %u data lanes\n",
 		   dev->active_data_lanes);
 
-	ret = clk_set_rate(dev->clock, 100 * 1000 * 1000);
+	ret = clk_set_min_rate(dev->vpu_clock, MIN_VPU_CLOCK_RATE);
+	if (ret) {
+		unicam_err(dev, "failed to set up VPU clock\n");
+		goto err_pm_put;
+	}
+
+	ret = clk_prepare_enable(dev->vpu_clock);
 	if (ret) {
-		unicam_err(dev, "failed to set up clock\n");
+		unicam_err(dev, "Failed to enable VPU clock: %d\n", ret);
 		goto err_pm_put;
 	}
 
+	ret = clk_set_rate(dev->clock, 100 * 1000 * 1000);
+	if (ret) {
+		unicam_err(dev, "failed to set up CSI clock\n");
+		goto err_vpu_clock;
+	}
+
 	ret = clk_prepare_enable(dev->clock);
 	if (ret) {
 		unicam_err(dev, "Failed to enable CSI clock: %d\n", ret);
-		goto err_pm_put;
+		goto err_vpu_clock;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(dev->node); i++) {
@@ -1717,6 +1736,11 @@ static int unicam_start_streaming(struct
 err_disable_unicam:
 	unicam_disable(dev);
 	clk_disable_unprepare(dev->clock);
+err_vpu_clock:
+	ret = clk_set_min_rate(dev->vpu_clock, 0);
+	if (ret)
+		unicam_err(dev, "failed to reset the VPU clock\n");
+	clk_disable_unprepare(dev->vpu_clock);
 err_pm_put:
 	unicam_runtime_put(dev);
 err_streaming:
@@ -1734,6 +1758,8 @@ static void unicam_stop_streaming(struct
 	node->streaming = false;
 
 	if (node->pad_id == IMAGE_PAD) {
+		int ret;
+
 		/*
 		 * Stop streaming the sensor and disable the peripheral.
 		 * We cannot continue streaming embedded data with the
@@ -1743,6 +1769,12 @@ static void unicam_stop_streaming(struct
 			unicam_err(dev, "stream off failed in subdev\n");
 
 		unicam_disable(dev);
+
+		ret = clk_set_min_rate(dev->vpu_clock, 0);
+		if (ret)
+			unicam_err(dev, "failed to reset the min VPU clock\n");
+
+		clk_disable_unprepare(dev->vpu_clock);
 		clk_disable_unprepare(dev->clock);
 		unicam_runtime_put(dev);
 
@@ -2742,11 +2774,18 @@ static int unicam_probe(struct platform_
 
 	unicam->clock = devm_clk_get(&pdev->dev, "lp");
 	if (IS_ERR(unicam->clock)) {
-		unicam_err(unicam, "Failed to get clock\n");
+		unicam_err(unicam, "Failed to get lp clock\n");
 		ret = PTR_ERR(unicam->clock);
 		goto err_unicam_put;
 	}
 
+	unicam->vpu_clock = devm_clk_get(&pdev->dev, "vpu");
+	if (IS_ERR(unicam->vpu_clock)) {
+		unicam_err(unicam, "Failed to get vpu clock\n");
+		ret = PTR_ERR(unicam->vpu_clock);
+		goto err_unicam_put;
+	}
+
 	ret = platform_get_irq(pdev, 0);
 	if (ret <= 0) {
 		dev_err(&pdev->dev, "No IRQ resource\n");