aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.10/950-0294-media-bcm2835-unicam-Set-VPU-min-clock-freq-to-250Mh.patch
blob: 7fd337edb89315a82e59d3b00b6ffd5101462d41 (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
From d839c8936020f393c5536d83b783198217243e8d 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>
---
 .../media/platform/bcm2835/bcm2835-unicam.c   | 49 +++++++++++++++++--
 1 file changed, 44 insertions(+), 5 deletions(-)

--- 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;
@@ -1678,16 +1685,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++) {
@@ -1721,6 +1740,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:
@@ -1738,6 +1762,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
@@ -1747,6 +1773,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);
 
@@ -2750,11 +2782,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");