aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2015-10-01 08:25:03 -0400
committerThierry Reding <treding@nvidia.com>2016-07-14 08:57:00 -0400
commitb299221ca99683e50ea03ac8ca638f9f43d2a59c (patch)
tree8db40dfed8e6425803d845eaaf016246c7c91554
parentaaff8bd2e824b6256e6cc1bd4eb3714de0683996 (diff)
drm/tegra: sor: Implement sor1_brick clock
sor1_brick is a clock that can be used as a source for the sor1 clock. The registers to control the clock output are part of the sor1 IP block and hence the sor driver is the best place to implement it. Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/gpu/drm/tegra/sor.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index 1eb19ca9fea4..896ba3bfbb2f 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -7,6 +7,7 @@
7 */ 7 */
8 8
9#include <linux/clk.h> 9#include <linux/clk.h>
10#include <linux/clk-provider.h>
10#include <linux/debugfs.h> 11#include <linux/debugfs.h>
11#include <linux/gpio.h> 12#include <linux/gpio.h>
12#include <linux/io.h> 13#include <linux/io.h>
@@ -170,6 +171,7 @@ struct tegra_sor {
170 171
171 struct reset_control *rst; 172 struct reset_control *rst;
172 struct clk *clk_parent; 173 struct clk *clk_parent;
174 struct clk *clk_brick;
173 struct clk *clk_safe; 175 struct clk *clk_safe;
174 struct clk *clk_dp; 176 struct clk *clk_dp;
175 struct clk *clk; 177 struct clk *clk;
@@ -255,6 +257,101 @@ static int tegra_sor_set_parent_clock(struct tegra_sor *sor, struct clk *parent)
255 return 0; 257 return 0;
256} 258}
257 259
260struct tegra_clk_sor_brick {
261 struct clk_hw hw;
262 struct tegra_sor *sor;
263};
264
265static inline struct tegra_clk_sor_brick *to_brick(struct clk_hw *hw)
266{
267 return container_of(hw, struct tegra_clk_sor_brick, hw);
268}
269
270static const char * const tegra_clk_sor_brick_parents[] = {
271 "pll_d2_out0", "pll_dp"
272};
273
274static int tegra_clk_sor_brick_set_parent(struct clk_hw *hw, u8 index)
275{
276 struct tegra_clk_sor_brick *brick = to_brick(hw);
277 struct tegra_sor *sor = brick->sor;
278 u32 value;
279
280 value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
281 value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK;
282
283 switch (index) {
284 case 0:
285 value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK;
286 break;
287
288 case 1:
289 value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK;
290 break;
291 }
292
293 tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
294
295 return 0;
296}
297
298static u8 tegra_clk_sor_brick_get_parent(struct clk_hw *hw)
299{
300 struct tegra_clk_sor_brick *brick = to_brick(hw);
301 struct tegra_sor *sor = brick->sor;
302 u8 parent = U8_MAX;
303 u32 value;
304
305 value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
306
307 switch (value & SOR_CLK_CNTRL_DP_CLK_SEL_MASK) {
308 case SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK:
309 case SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_PCLK:
310 parent = 0;
311 break;
312
313 case SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK:
314 case SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK:
315 parent = 1;
316 break;
317 }
318
319 return parent;
320}
321
322static const struct clk_ops tegra_clk_sor_brick_ops = {
323 .set_parent = tegra_clk_sor_brick_set_parent,
324 .get_parent = tegra_clk_sor_brick_get_parent,
325};
326
327static struct clk *tegra_clk_sor_brick_register(struct tegra_sor *sor,
328 const char *name)
329{
330 struct tegra_clk_sor_brick *brick;
331 struct clk_init_data init;
332 struct clk *clk;
333
334 brick = devm_kzalloc(sor->dev, sizeof(*brick), GFP_KERNEL);
335 if (!brick)
336 return ERR_PTR(-ENOMEM);
337
338 brick->sor = sor;
339
340 init.name = name;
341 init.flags = 0;
342 init.parent_names = tegra_clk_sor_brick_parents;
343 init.num_parents = ARRAY_SIZE(tegra_clk_sor_brick_parents);
344 init.ops = &tegra_clk_sor_brick_ops;
345
346 brick->hw.init = &init;
347
348 clk = devm_clk_register(sor->dev, &brick->hw);
349 if (IS_ERR(clk))
350 kfree(brick);
351
352 return clk;
353}
354
258static int tegra_sor_dp_train_fast(struct tegra_sor *sor, 355static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
259 struct drm_dp_link *link) 356 struct drm_dp_link *link)
260{ 357{
@@ -2522,6 +2619,16 @@ static int tegra_sor_probe(struct platform_device *pdev)
2522 platform_set_drvdata(pdev, sor); 2619 platform_set_drvdata(pdev, sor);
2523 pm_runtime_enable(&pdev->dev); 2620 pm_runtime_enable(&pdev->dev);
2524 2621
2622 pm_runtime_get_sync(&pdev->dev);
2623 sor->clk_brick = tegra_clk_sor_brick_register(sor, "sor1_brick");
2624 pm_runtime_put(&pdev->dev);
2625
2626 if (IS_ERR(sor->clk_brick)) {
2627 err = PTR_ERR(sor->clk_brick);
2628 dev_err(&pdev->dev, "failed to register SOR clock: %d\n", err);
2629 goto remove;
2630 }
2631
2525 INIT_LIST_HEAD(&sor->client.list); 2632 INIT_LIST_HEAD(&sor->client.list);
2526 sor->client.ops = &sor_client_ops; 2633 sor->client.ops = &sor_client_ops;
2527 sor->client.dev = &pdev->dev; 2634 sor->client.dev = &pdev->dev;