Browse Source

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
Dave Airlie 7 năm trước cách đây
mục cha
commit
2d56131006
1 tập tin đã thay đổi với 111 bổ sung46 xóa
  1. 111 46
      drivers/gpu/drm/tegra/sor.c

+ 111 - 46
drivers/gpu/drm/tegra/sor.c

@@ -174,9 +174,9 @@ struct tegra_sor {
 
 	struct reset_control *rst;
 	struct clk *clk_parent;
-	struct clk *clk_brick;
 	struct clk *clk_safe;
-	struct clk *clk_src;
+	struct clk *clk_out;
+	struct clk *clk_pad;
 	struct clk *clk_dp;
 	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);
 
-	err = clk_set_parent(sor->clk, parent);
+	err = clk_set_parent(sor->clk_out, parent);
 	if (err < 0)
 		return err;
 
@@ -266,24 +266,24 @@ static int tegra_sor_set_parent_clock(struct tegra_sor *sor, struct clk *parent)
 	return 0;
 }
 
-struct tegra_clk_sor_brick {
+struct tegra_clk_sor_pad {
 	struct clk_hw hw;
 	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"
 };
 
-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_sor *sor = brick->sor;
+	struct tegra_clk_sor_pad *pad = to_pad(hw);
+	struct tegra_sor *sor = pad->sor;
 	u32 value;
 
 	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;
 }
 
-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_sor *sor = brick->sor;
+	struct tegra_clk_sor_pad *pad = to_pad(hw);
+	struct tegra_sor *sor = pad->sor;
 	u8 parent = U8_MAX;
 	u32 value;
 
@@ -328,33 +328,33 @@ static u8 tegra_clk_sor_brick_get_parent(struct clk_hw *hw)
 	return parent;
 }
 
-static const struct clk_ops tegra_clk_sor_brick_ops = {
-	.set_parent = tegra_clk_sor_brick_set_parent,
-	.get_parent = tegra_clk_sor_brick_get_parent,
+static const struct clk_ops tegra_clk_sor_pad_ops = {
+	.set_parent = tegra_clk_sor_pad_set_parent,
+	.get_parent = tegra_clk_sor_pad_get_parent,
 };
 
-static struct clk *tegra_clk_sor_brick_register(struct tegra_sor *sor,
-						const char *name)
+static struct clk *tegra_clk_sor_pad_register(struct tegra_sor *sor,
+					      const char *name)
 {
-	struct tegra_clk_sor_brick *brick;
+	struct tegra_clk_sor_pad *pad;
 	struct clk_init_data init;
 	struct clk *clk;
 
-	brick = devm_kzalloc(sor->dev, sizeof(*brick), GFP_KERNEL);
-	if (!brick)
+	pad = devm_kzalloc(sor->dev, sizeof(*pad), GFP_KERNEL);
+	if (!pad)
 		return ERR_PTR(-ENOMEM);
 
-	brick->sor = sor;
+	pad->sor = sor;
 
 	init.name = name;
 	init.flags = 0;
-	init.parent_names = tegra_clk_sor_brick_parents;
-	init.num_parents = ARRAY_SIZE(tegra_clk_sor_brick_parents);
-	init.ops = &tegra_clk_sor_brick_ops;
+	init.parent_names = tegra_clk_sor_pad_parents;
+	init.num_parents = ARRAY_SIZE(tegra_clk_sor_pad_parents);
+	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;
 }
@@ -998,8 +998,10 @@ static int tegra_sor_power_down(struct tegra_sor *sor)
 
 	/* switch to safe parent clock */
 	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);
+		return err;
+	}
 
 	value = tegra_sor_readl(sor, SOR_DP_PADCTL0);
 	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 */
 	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);
+		return;
+	}
 
 	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);
 
 	/* switch to parent clock */
-	err = clk_set_parent(sor->clk_src, sor->clk_parent);
-	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)
+	err = clk_set_parent(sor->clk, sor->clk_parent);
+	if (err < 0) {
 		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);
 
@@ -2628,11 +2636,24 @@ static int tegra_sor_probe(struct platform_device *pdev)
 	}
 
 	if (sor->soc->supports_hdmi || sor->soc->supports_dp) {
-		sor->clk_src = devm_clk_get(&pdev->dev, "source");
-		if (IS_ERR(sor->clk_src)) {
-			err = PTR_ERR(sor->clk_src);
-			dev_err(sor->dev, "failed to get source clock: %d\n",
-				err);
+		struct device_node *np = pdev->dev.of_node;
+		const char *name;
+
+		/*
+		 * 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;
 		}
 	}
@@ -2658,16 +2679,60 @@ static int tegra_sor_probe(struct platform_device *pdev)
 		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);
 	pm_runtime_enable(&pdev->dev);
 
-	pm_runtime_get_sync(&pdev->dev);
-	sor->clk_brick = tegra_clk_sor_brick_register(sor, "sor1_brick");
-	pm_runtime_put(&pdev->dev);
+	/*
+	 * On Tegra210 and earlier, provide our own implementation for the
+	 * 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;
+		}
+
+		sor->clk_pad = tegra_clk_sor_pad_register(sor,
+							  "sor1_pad_clkout");
+		pm_runtime_put(&pdev->dev);
+	}
 
-	if (IS_ERR(sor->clk_brick)) {
-		err = PTR_ERR(sor->clk_brick);
-		dev_err(&pdev->dev, "failed to register SOR clock: %d\n", err);
+	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;
 	}