forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-13 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e
kernel/drivers/gpu/drm/armada/armada_510.c
....@@ -1,31 +1,72 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (C) 2012 Russell King
3
- *
4
- * This program is free software; you can redistribute it and/or modify
5
- * it under the terms of the GNU General Public License version 2 as
6
- * published by the Free Software Foundation.
74 *
85 * Armada 510 (aka Dove) variant support
96 */
107 #include <linux/clk.h>
118 #include <linux/io.h>
12
-#include <drm/drm_crtc_helper.h>
9
+#include <drm/drm_probe_helper.h>
1310 #include "armada_crtc.h"
1411 #include "armada_drm.h"
1512 #include "armada_hw.h"
1613
14
+struct armada510_variant_data {
15
+ struct clk *clks[4];
16
+ struct clk *sel_clk;
17
+};
18
+
1719 static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
1820 {
21
+ struct armada510_variant_data *v;
1922 struct clk *clk;
23
+ int idx;
2024
21
- clk = devm_clk_get(dev, "ext_ref_clk1");
22
- if (IS_ERR(clk))
23
- return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : PTR_ERR(clk);
25
+ v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL);
26
+ if (!v)
27
+ return -ENOMEM;
2428
25
- dcrtc->extclk[0] = clk;
29
+ dcrtc->variant_data = v;
2630
27
- /* Lower the watermark so to eliminate jitter at higher bandwidths */
28
- armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F);
31
+ if (dev->of_node) {
32
+ struct property *prop;
33
+ const char *s;
34
+
35
+ of_property_for_each_string(dev->of_node, "clock-names", prop,
36
+ s) {
37
+ if (!strcmp(s, "ext_ref_clk0"))
38
+ idx = 0;
39
+ else if (!strcmp(s, "ext_ref_clk1"))
40
+ idx = 1;
41
+ else if (!strcmp(s, "plldivider"))
42
+ idx = 2;
43
+ else if (!strcmp(s, "axibus"))
44
+ idx = 3;
45
+ else
46
+ continue;
47
+
48
+ clk = devm_clk_get(dev, s);
49
+ if (IS_ERR(clk))
50
+ return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
51
+ PTR_ERR(clk);
52
+ v->clks[idx] = clk;
53
+ }
54
+ } else {
55
+ clk = devm_clk_get(dev, "ext_ref_clk1");
56
+ if (IS_ERR(clk))
57
+ return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
58
+ PTR_ERR(clk);
59
+
60
+ v->clks[1] = clk;
61
+ }
62
+
63
+ /*
64
+ * Lower the watermark so to eliminate jitter at higher bandwidths.
65
+ * Disable SRAM read wait state to avoid system hang with external
66
+ * clock.
67
+ */
68
+ armada_updatel(CFG_DMA_WM(0x20), CFG_SRAM_WAIT | CFG_DMA_WM_MASK,
69
+ dcrtc->base + LCD_CFG_RDREG4F);
2970
3071 /* Initialise SPU register */
3172 writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND,
....@@ -34,65 +75,77 @@
3475 return 0;
3576 }
3677
78
+static const u32 armada510_clk_sels[] = {
79
+ SCLK_510_EXTCLK0,
80
+ SCLK_510_EXTCLK1,
81
+ SCLK_510_PLL,
82
+ SCLK_510_AXI,
83
+};
84
+
85
+static const struct armada_clocking_params armada510_clocking = {
86
+ /* HDMI requires -0.6%..+0.5% */
87
+ .permillage_min = 994,
88
+ .permillage_max = 1005,
89
+ .settable = BIT(0) | BIT(1),
90
+ .div_max = SCLK_510_INT_DIV_MASK,
91
+};
92
+
3793 /*
3894 * Armada510 specific SCLK register selection.
3995 * This gets called with sclk = NULL to test whether the mode is
4096 * supportable, and again with sclk != NULL to set the clocks up for
4197 * that. The former can return an error, but the latter is expected
4298 * not to.
43
- *
44
- * We currently are pretty rudimentary here, always selecting
45
- * EXT_REF_CLK_1 for LCD0 and erroring LCD1. This needs improvement!
4699 */
47100 static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
48101 const struct drm_display_mode *mode, uint32_t *sclk)
49102 {
50
- struct clk *clk = dcrtc->extclk[0];
51
- int ret;
103
+ struct armada510_variant_data *v = dcrtc->variant_data;
104
+ unsigned long desired_khz = mode->crtc_clock;
105
+ struct armada_clk_result res;
106
+ int ret, idx;
52107
53
- if (dcrtc->num == 1)
54
- return -EINVAL;
108
+ idx = armada_crtc_select_clock(dcrtc, &res, &armada510_clocking,
109
+ v->clks, ARRAY_SIZE(v->clks),
110
+ desired_khz);
111
+ if (idx < 0)
112
+ return idx;
55113
56
- if (IS_ERR(clk))
57
- return PTR_ERR(clk);
58
-
59
- if (dcrtc->clk != clk) {
60
- ret = clk_prepare_enable(clk);
61
- if (ret)
62
- return ret;
63
- dcrtc->clk = clk;
64
- }
114
+ ret = clk_prepare_enable(res.clk);
115
+ if (ret)
116
+ return ret;
65117
66118 if (sclk) {
67
- uint32_t rate, ref, div;
119
+ clk_set_rate(res.clk, res.desired_clk_hz);
68120
69
- rate = mode->clock * 1000;
70
- ref = clk_round_rate(clk, rate);
71
- div = DIV_ROUND_UP(ref, rate);
72
- if (div < 1)
73
- div = 1;
121
+ *sclk = res.div | armada510_clk_sels[idx];
74122
75
- clk_set_rate(clk, ref);
76
- *sclk = div | SCLK_510_EXTCLK1;
123
+ /* We are now using this clock */
124
+ v->sel_clk = res.clk;
125
+ swap(dcrtc->clk, res.clk);
77126 }
127
+
128
+ clk_disable_unprepare(res.clk);
78129
79130 return 0;
80131 }
81132
82133 static void armada510_crtc_disable(struct armada_crtc *dcrtc)
83134 {
84
- if (!IS_ERR(dcrtc->clk)) {
135
+ if (dcrtc->clk) {
85136 clk_disable_unprepare(dcrtc->clk);
86
- dcrtc->clk = ERR_PTR(-EINVAL);
137
+ dcrtc->clk = NULL;
87138 }
88139 }
89140
90141 static void armada510_crtc_enable(struct armada_crtc *dcrtc,
91142 const struct drm_display_mode *mode)
92143 {
93
- if (IS_ERR(dcrtc->clk)) {
94
- dcrtc->clk = dcrtc->extclk[0];
95
- WARN_ON(clk_prepare_enable(dcrtc->clk));
144
+ struct armada510_variant_data *v = dcrtc->variant_data;
145
+
146
+ if (!dcrtc->clk && v->sel_clk) {
147
+ if (!WARN_ON(clk_prepare_enable(v->sel_clk)))
148
+ dcrtc->clk = v->sel_clk;
96149 }
97150 }
98151