Skip to content

Commit c891a65

Browse files
jernejskmripard
authored andcommitted
drm/sun4i: Add support for second clock parent to DW HDMI PHY clk driver
Expand HDMI PHY clock driver to support second clock parent. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-20-jernej.skrabec@siol.net
1 parent aef13fd commit c891a65

File tree

3 files changed

+73
-24
lines changed

3 files changed

+73
-24
lines changed

drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
#define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN BIT(28)
100100
#define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 BIT(27)
101101
#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK BIT(26)
102+
#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT 26
102103
#define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN BIT(25)
103104
#define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x) ((x) << 22)
104105
#define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x) ((x) << 20)
@@ -190,6 +191,7 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi);
190191
void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
191192
const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);
192193

193-
int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev);
194+
int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
195+
bool second_parent);
194196

195197
#endif /* _SUN8I_DW_HDMI_H_ */

drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,8 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
491491
}
492492
}
493493

494-
ret = sun8i_phy_clk_create(phy, dev);
494+
ret = sun8i_phy_clk_create(phy, dev,
495+
phy->variant->has_second_pll);
495496
if (ret) {
496497
dev_err(dev, "Couldn't create the PHY clock\n");
497498
goto err_put_clk_pll1;

drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c

Lines changed: 68 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,35 +22,45 @@ static int sun8i_phy_clk_determine_rate(struct clk_hw *hw,
2222
{
2323
unsigned long rate = req->rate;
2424
unsigned long best_rate = 0;
25+
struct clk_hw *best_parent = NULL;
2526
struct clk_hw *parent;
2627
int best_div = 1;
27-
int i;
28+
int i, p;
2829

29-
parent = clk_hw_get_parent(hw);
30-
31-
for (i = 1; i <= 16; i++) {
32-
unsigned long ideal = rate * i;
33-
unsigned long rounded;
34-
35-
rounded = clk_hw_round_rate(parent, ideal);
30+
for (p = 0; p < clk_hw_get_num_parents(hw); p++) {
31+
parent = clk_hw_get_parent_by_index(hw, p);
32+
if (!parent)
33+
continue;
3634

37-
if (rounded == ideal) {
38-
best_rate = rounded;
39-
best_div = i;
40-
break;
35+
for (i = 1; i <= 16; i++) {
36+
unsigned long ideal = rate * i;
37+
unsigned long rounded;
38+
39+
rounded = clk_hw_round_rate(parent, ideal);
40+
41+
if (rounded == ideal) {
42+
best_rate = rounded;
43+
best_div = i;
44+
best_parent = parent;
45+
break;
46+
}
47+
48+
if (!best_rate ||
49+
abs(rate - rounded / i) <
50+
abs(rate - best_rate / best_div)) {
51+
best_rate = rounded;
52+
best_div = i;
53+
best_parent = parent;
54+
}
4155
}
4256

43-
if (!best_rate ||
44-
abs(rate - rounded / i) <
45-
abs(rate - best_rate / best_div)) {
46-
best_rate = rounded;
47-
best_div = i;
48-
}
57+
if (best_rate / best_div == rate)
58+
break;
4959
}
5060

5161
req->rate = best_rate / best_div;
5262
req->best_parent_rate = best_rate;
53-
req->best_parent_hw = parent;
63+
req->best_parent_hw = best_parent;
5464

5565
return 0;
5666
}
@@ -95,30 +105,66 @@ static int sun8i_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
95105
return 0;
96106
}
97107

108+
static u8 sun8i_phy_clk_get_parent(struct clk_hw *hw)
109+
{
110+
struct sun8i_phy_clk *priv = hw_to_phy_clk(hw);
111+
u32 reg;
112+
113+
regmap_read(priv->phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, &reg);
114+
reg = (reg & SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK) >>
115+
SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT;
116+
117+
return reg;
118+
}
119+
120+
static int sun8i_phy_clk_set_parent(struct clk_hw *hw, u8 index)
121+
{
122+
struct sun8i_phy_clk *priv = hw_to_phy_clk(hw);
123+
124+
if (index > 1)
125+
return -EINVAL;
126+
127+
regmap_update_bits(priv->phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
128+
SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
129+
index << SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT);
130+
131+
return 0;
132+
}
133+
98134
static const struct clk_ops sun8i_phy_clk_ops = {
99135
.determine_rate = sun8i_phy_clk_determine_rate,
100136
.recalc_rate = sun8i_phy_clk_recalc_rate,
101137
.set_rate = sun8i_phy_clk_set_rate,
138+
139+
.get_parent = sun8i_phy_clk_get_parent,
140+
.set_parent = sun8i_phy_clk_set_parent,
102141
};
103142

104-
int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev)
143+
int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
144+
bool second_parent)
105145
{
106146
struct clk_init_data init;
107147
struct sun8i_phy_clk *priv;
108-
const char *parents[1];
148+
const char *parents[2];
109149

110150
parents[0] = __clk_get_name(phy->clk_pll0);
111151
if (!parents[0])
112152
return -ENODEV;
113153

154+
if (second_parent) {
155+
parents[1] = __clk_get_name(phy->clk_pll1);
156+
if (!parents[1])
157+
return -ENODEV;
158+
}
159+
114160
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
115161
if (!priv)
116162
return -ENOMEM;
117163

118164
init.name = "hdmi-phy-clk";
119165
init.ops = &sun8i_phy_clk_ops;
120166
init.parent_names = parents;
121-
init.num_parents = 1;
167+
init.num_parents = second_parent ? 2 : 1;
122168
init.flags = CLK_SET_RATE_PARENT;
123169

124170
priv->phy = phy;

0 commit comments

Comments
 (0)