drm/tegra: Fixes for v4.15-rc1

This includes an update to the SOR pad clock programming needed because
 of some changes that went in through the clock tree.
 -----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCAAxFiEEiOrDCAFJzPfAjcif3SOs138+s6EFAloVbGQTHHRyZWRpbmdA
 bnZpZGlhLmNvbQAKCRDdI6zXfz6zoUzwD/4np5tShnMB4pp3TNpbbZ0x2wrbRc/f
 J3/ueUzWxGY1g2aFgRnQ91RRBo0BgjEFKQfLe1lxT4Q/7O81twtzluz7PDI3qHSS
 sAvNrJLAudcWIGAsIs6A8GUlDIwvenuscw5QoLPimpdwFopKl89Smrzubn3ZXzok
 VOG+6KcUY9sUMINl/EvBDJCm6K4Hb6wMrOohwOug0qkL126Oz0j1kHCbQz28jDwL
 DiDR9RBx+c0DHWfkpiE9IJ9I266QHDtKSmMi43+Bu/gX74HW/ipN+eZQbzIcFyIT
 OM6s4pPUZtNI4e4N+zQ8Uj3JwccjsQtQo+mwFw0TzzdfXkqxC7feOENEzmOdwFWW
 X99ESrOPdbnvGLorGu3LtubsshXkvU3ME6wt+dNDIJjlg/+b1QwPKN8rVTTcw+ey
 xrcqiqeoPMSDhxTOZtAuskg3kDO1RcnnftUInkqyZ1bj0BcIdXW+e7Oz5w1Zasp7
 ozleNL+XqrKTNKDeq6iJrPvFbyUR5TuGF9GmcIJegzTDf+FLDHhc1cEzPVmmDD5B
 vSdO+V5gpVefep8HEu/xS4L/oMr9tr6xVrQ8zNtbuWyt0uA27YRIsaagJ5ebsJCg
 W3AgftB35mZm1mJ8b4zv9q3UWAc2EvFxFGrzk1SIzxFQbmaDjuB3ZGgBjcg0lhD7
 hBGbv9jqL9IuLQ==
 =JFFp
 -----END PGP SIGNATURE-----

Merge tag 'drm/tegra/for-4.15-rc1-fixes' of git://anongit.freedesktop.org/tegra/linux into drm-next

drm/tegra: Fixes for v4.15-rc1

This includes an update to the SOR pad clock programming needed because
of some changes that went in through the clock tree.

* tag 'drm/tegra/for-4.15-rc1-fixes' of git://anongit.freedesktop.org/tegra/linux:
  drm/tegra: sor: Reimplement pad clock
This commit is contained in:
Dave Airlie 2017-11-23 08:52:38 +10:00
commit 2d56131006

View File

@ -174,9 +174,9 @@ struct tegra_sor {
struct reset_control *rst; struct reset_control *rst;
struct clk *clk_parent; struct clk *clk_parent;
struct clk *clk_brick;
struct clk *clk_safe; struct clk *clk_safe;
struct clk *clk_src; struct clk *clk_out;
struct clk *clk_pad;
struct clk *clk_dp; struct clk *clk_dp;
struct clk *clk; struct clk *clk;
@ -255,7 +255,7 @@ static int tegra_sor_set_parent_clock(struct tegra_sor *sor, struct clk *parent)
clk_disable_unprepare(sor->clk); clk_disable_unprepare(sor->clk);
err = clk_set_parent(sor->clk, parent); err = clk_set_parent(sor->clk_out, parent);
if (err < 0) if (err < 0)
return err; return err;
@ -266,24 +266,24 @@ static int tegra_sor_set_parent_clock(struct tegra_sor *sor, struct clk *parent)
return 0; return 0;
} }
struct tegra_clk_sor_brick { struct tegra_clk_sor_pad {
struct clk_hw hw; struct clk_hw hw;
struct tegra_sor *sor; struct tegra_sor *sor;
}; };
static inline struct tegra_clk_sor_brick *to_brick(struct clk_hw *hw) static inline struct tegra_clk_sor_pad *to_pad(struct clk_hw *hw)
{ {
return container_of(hw, struct tegra_clk_sor_brick, hw); return container_of(hw, struct tegra_clk_sor_pad, hw);
} }
static const char * const tegra_clk_sor_brick_parents[] = { static const char * const tegra_clk_sor_pad_parents[] = {
"pll_d2_out0", "pll_dp" "pll_d2_out0", "pll_dp"
}; };
static int tegra_clk_sor_brick_set_parent(struct clk_hw *hw, u8 index) static int tegra_clk_sor_pad_set_parent(struct clk_hw *hw, u8 index)
{ {
struct tegra_clk_sor_brick *brick = to_brick(hw); struct tegra_clk_sor_pad *pad = to_pad(hw);
struct tegra_sor *sor = brick->sor; struct tegra_sor *sor = pad->sor;
u32 value; u32 value;
value = tegra_sor_readl(sor, SOR_CLK_CNTRL); value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
@ -304,10 +304,10 @@ static int tegra_clk_sor_brick_set_parent(struct clk_hw *hw, u8 index)
return 0; return 0;
} }
static u8 tegra_clk_sor_brick_get_parent(struct clk_hw *hw) static u8 tegra_clk_sor_pad_get_parent(struct clk_hw *hw)
{ {
struct tegra_clk_sor_brick *brick = to_brick(hw); struct tegra_clk_sor_pad *pad = to_pad(hw);
struct tegra_sor *sor = brick->sor; struct tegra_sor *sor = pad->sor;
u8 parent = U8_MAX; u8 parent = U8_MAX;
u32 value; u32 value;
@ -328,33 +328,33 @@ static u8 tegra_clk_sor_brick_get_parent(struct clk_hw *hw)
return parent; return parent;
} }
static const struct clk_ops tegra_clk_sor_brick_ops = { static const struct clk_ops tegra_clk_sor_pad_ops = {
.set_parent = tegra_clk_sor_brick_set_parent, .set_parent = tegra_clk_sor_pad_set_parent,
.get_parent = tegra_clk_sor_brick_get_parent, .get_parent = tegra_clk_sor_pad_get_parent,
}; };
static struct clk *tegra_clk_sor_brick_register(struct tegra_sor *sor, static struct clk *tegra_clk_sor_pad_register(struct tegra_sor *sor,
const char *name) const char *name)
{ {
struct tegra_clk_sor_brick *brick; struct tegra_clk_sor_pad *pad;
struct clk_init_data init; struct clk_init_data init;
struct clk *clk; struct clk *clk;
brick = devm_kzalloc(sor->dev, sizeof(*brick), GFP_KERNEL); pad = devm_kzalloc(sor->dev, sizeof(*pad), GFP_KERNEL);
if (!brick) if (!pad)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
brick->sor = sor; pad->sor = sor;
init.name = name; init.name = name;
init.flags = 0; init.flags = 0;
init.parent_names = tegra_clk_sor_brick_parents; init.parent_names = tegra_clk_sor_pad_parents;
init.num_parents = ARRAY_SIZE(tegra_clk_sor_brick_parents); init.num_parents = ARRAY_SIZE(tegra_clk_sor_pad_parents);
init.ops = &tegra_clk_sor_brick_ops; init.ops = &tegra_clk_sor_pad_ops;
brick->hw.init = &init; pad->hw.init = &init;
clk = devm_clk_register(sor->dev, &brick->hw); clk = devm_clk_register(sor->dev, &pad->hw);
return clk; return clk;
} }
@ -998,8 +998,10 @@ static int tegra_sor_power_down(struct tegra_sor *sor)
/* switch to safe parent clock */ /* switch to safe parent clock */
err = tegra_sor_set_parent_clock(sor, sor->clk_safe); err = tegra_sor_set_parent_clock(sor, sor->clk_safe);
if (err < 0) if (err < 0) {
dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
return err;
}
value = tegra_sor_readl(sor, SOR_DP_PADCTL0); value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 | value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 |
@ -2007,8 +2009,10 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
/* switch to safe parent clock */ /* switch to safe parent clock */
err = tegra_sor_set_parent_clock(sor, sor->clk_safe); err = tegra_sor_set_parent_clock(sor, sor->clk_safe);
if (err < 0) if (err < 0) {
dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
return;
}
div = clk_get_rate(sor->clk) / 1000000 * 4; div = clk_get_rate(sor->clk) / 1000000 * 4;
@ -2111,13 +2115,17 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
tegra_sor_writel(sor, value, SOR_XBAR_CTRL); tegra_sor_writel(sor, value, SOR_XBAR_CTRL);
/* switch to parent clock */ /* switch to parent clock */
err = clk_set_parent(sor->clk_src, sor->clk_parent); err = clk_set_parent(sor->clk, sor->clk_parent);
if (err < 0) if (err < 0) {
dev_err(sor->dev, "failed to set source clock: %d\n", err);
err = tegra_sor_set_parent_clock(sor, sor->clk_src);
if (err < 0)
dev_err(sor->dev, "failed to set parent clock: %d\n", err); dev_err(sor->dev, "failed to set parent clock: %d\n", err);
return;
}
err = tegra_sor_set_parent_clock(sor, sor->clk_pad);
if (err < 0) {
dev_err(sor->dev, "failed to set pad clock: %d\n", err);
return;
}
value = SOR_INPUT_CONTROL_HDMI_SRC_SELECT(dc->pipe); value = SOR_INPUT_CONTROL_HDMI_SRC_SELECT(dc->pipe);
@ -2628,11 +2636,24 @@ static int tegra_sor_probe(struct platform_device *pdev)
} }
if (sor->soc->supports_hdmi || sor->soc->supports_dp) { if (sor->soc->supports_hdmi || sor->soc->supports_dp) {
sor->clk_src = devm_clk_get(&pdev->dev, "source"); struct device_node *np = pdev->dev.of_node;
if (IS_ERR(sor->clk_src)) { const char *name;
err = PTR_ERR(sor->clk_src);
dev_err(sor->dev, "failed to get source clock: %d\n", /*
err); * For backwards compatibility with Tegra210 device trees,
* fall back to the old clock name "source" if the new "out"
* clock is not available.
*/
if (of_property_match_string(np, "clock-names", "out") < 0)
name = "source";
else
name = "out";
sor->clk_out = devm_clk_get(&pdev->dev, name);
if (IS_ERR(sor->clk_out)) {
err = PTR_ERR(sor->clk_out);
dev_err(sor->dev, "failed to get %s clock: %d\n",
name, err);
goto remove; goto remove;
} }
} }
@ -2658,16 +2679,60 @@ static int tegra_sor_probe(struct platform_device *pdev)
goto remove; goto remove;
} }
/*
* Starting with Tegra186, the BPMP provides an implementation for
* the pad output clock, so we have to look it up from device tree.
*/
sor->clk_pad = devm_clk_get(&pdev->dev, "pad");
if (IS_ERR(sor->clk_pad)) {
if (sor->clk_pad != ERR_PTR(-ENOENT)) {
err = PTR_ERR(sor->clk_pad);
goto remove;
}
/*
* If the pad output clock is not available, then we assume
* we're on Tegra210 or earlier and have to provide our own
* implementation.
*/
sor->clk_pad = NULL;
}
/*
* The bootloader may have set up the SOR such that it's module clock
* is sourced by one of the display PLLs. However, that doesn't work
* without properly having set up other bits of the SOR.
*/
err = clk_set_parent(sor->clk_out, sor->clk_safe);
if (err < 0) {
dev_err(&pdev->dev, "failed to use safe clock: %d\n", err);
goto remove;
}
platform_set_drvdata(pdev, sor); platform_set_drvdata(pdev, sor);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev); /*
sor->clk_brick = tegra_clk_sor_brick_register(sor, "sor1_brick"); * On Tegra210 and earlier, provide our own implementation for the
pm_runtime_put(&pdev->dev); * pad output clock.
*/
if (!sor->clk_pad) {
err = pm_runtime_get_sync(&pdev->dev);
if (err < 0) {
dev_err(&pdev->dev, "failed to get runtime PM: %d\n",
err);
goto remove;
}
if (IS_ERR(sor->clk_brick)) { sor->clk_pad = tegra_clk_sor_pad_register(sor,
err = PTR_ERR(sor->clk_brick); "sor1_pad_clkout");
dev_err(&pdev->dev, "failed to register SOR clock: %d\n", err); pm_runtime_put(&pdev->dev);
}
if (IS_ERR(sor->clk_pad)) {
err = PTR_ERR(sor->clk_pad);
dev_err(&pdev->dev, "failed to register SOR pad clock: %d\n",
err);
goto remove; goto remove;
} }