Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/drm/armada/armada_510.c
26481 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 2012 Russell King
4
*
5
* Armada 510 (aka Dove) variant support
6
*/
7
#include <linux/clk.h>
8
#include <linux/io.h>
9
#include <linux/of.h>
10
#include <drm/drm_probe_helper.h>
11
#include "armada_crtc.h"
12
#include "armada_drm.h"
13
#include "armada_hw.h"
14
15
struct armada510_variant_data {
16
struct clk *clks[4];
17
struct clk *sel_clk;
18
};
19
20
static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
21
{
22
struct armada510_variant_data *v;
23
struct clk *clk;
24
int idx;
25
26
v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL);
27
if (!v)
28
return -ENOMEM;
29
30
dcrtc->variant_data = v;
31
32
if (dev->of_node) {
33
struct property *prop;
34
const char *s;
35
36
of_property_for_each_string(dev->of_node, "clock-names", prop,
37
s) {
38
if (!strcmp(s, "ext_ref_clk0"))
39
idx = 0;
40
else if (!strcmp(s, "ext_ref_clk1"))
41
idx = 1;
42
else if (!strcmp(s, "plldivider"))
43
idx = 2;
44
else if (!strcmp(s, "axibus"))
45
idx = 3;
46
else
47
continue;
48
49
clk = devm_clk_get(dev, s);
50
if (IS_ERR(clk))
51
return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
52
PTR_ERR(clk);
53
v->clks[idx] = clk;
54
}
55
} else {
56
clk = devm_clk_get(dev, "ext_ref_clk1");
57
if (IS_ERR(clk))
58
return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
59
PTR_ERR(clk);
60
61
v->clks[1] = clk;
62
}
63
64
/*
65
* Lower the watermark so to eliminate jitter at higher bandwidths.
66
* Disable SRAM read wait state to avoid system hang with external
67
* clock.
68
*/
69
armada_updatel(CFG_DMA_WM(0x20), CFG_SRAM_WAIT | CFG_DMA_WM_MASK,
70
dcrtc->base + LCD_CFG_RDREG4F);
71
72
/* Initialise SPU register */
73
writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND,
74
dcrtc->base + LCD_SPU_ADV_REG);
75
76
return 0;
77
}
78
79
static const u32 armada510_clk_sels[] = {
80
SCLK_510_EXTCLK0,
81
SCLK_510_EXTCLK1,
82
SCLK_510_PLL,
83
SCLK_510_AXI,
84
};
85
86
static const struct armada_clocking_params armada510_clocking = {
87
/* HDMI requires -0.6%..+0.5% */
88
.permillage_min = 994,
89
.permillage_max = 1005,
90
.settable = BIT(0) | BIT(1),
91
.div_max = SCLK_510_INT_DIV_MASK,
92
};
93
94
/*
95
* Armada510 specific SCLK register selection.
96
* This gets called with sclk = NULL to test whether the mode is
97
* supportable, and again with sclk != NULL to set the clocks up for
98
* that. The former can return an error, but the latter is expected
99
* not to.
100
*/
101
static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
102
const struct drm_display_mode *mode, uint32_t *sclk)
103
{
104
struct armada510_variant_data *v = dcrtc->variant_data;
105
unsigned long desired_khz = mode->crtc_clock;
106
struct armada_clk_result res;
107
int ret, idx;
108
109
idx = armada_crtc_select_clock(dcrtc, &res, &armada510_clocking,
110
v->clks, ARRAY_SIZE(v->clks),
111
desired_khz);
112
if (idx < 0)
113
return idx;
114
115
ret = clk_prepare_enable(res.clk);
116
if (ret)
117
return ret;
118
119
if (sclk) {
120
clk_set_rate(res.clk, res.desired_clk_hz);
121
122
*sclk = res.div | armada510_clk_sels[idx];
123
124
/* We are now using this clock */
125
v->sel_clk = res.clk;
126
swap(dcrtc->clk, res.clk);
127
}
128
129
clk_disable_unprepare(res.clk);
130
131
return 0;
132
}
133
134
static void armada510_crtc_disable(struct armada_crtc *dcrtc)
135
{
136
if (dcrtc->clk) {
137
clk_disable_unprepare(dcrtc->clk);
138
dcrtc->clk = NULL;
139
}
140
}
141
142
static void armada510_crtc_enable(struct armada_crtc *dcrtc,
143
const struct drm_display_mode *mode)
144
{
145
struct armada510_variant_data *v = dcrtc->variant_data;
146
147
if (!dcrtc->clk && v->sel_clk) {
148
if (!WARN_ON(clk_prepare_enable(v->sel_clk)))
149
dcrtc->clk = v->sel_clk;
150
}
151
}
152
153
const struct armada_variant armada510_ops = {
154
.has_spu_adv_reg = true,
155
.init = armada510_crtc_init,
156
.compute_clock = armada510_crtc_compute_clock,
157
.disable = armada510_crtc_disable,
158
.enable = armada510_crtc_enable,
159
};
160
161