forked from openwrt/openwrt
-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
950-0271-media-bcm2835-unicam-Set-VPU-min-clock-freq-to-250Mh.patch
127 lines (115 loc) · 3.87 KB
/
950-0271-media-bcm2835-unicam-Set-VPU-min-clock-freq-to-250Mh.patch
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 bf30883473f0d25fa7614d53022c20330d840aa0 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");