aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/rcar-du/Kconfig1
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_lvds.c77
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_lvds.h27
4 files changed, 96 insertions, 11 deletions
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index f0c1f8731a27..1ac55c65eac0 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -81,7 +81,7 @@ obj-$(CONFIG_DRM_UDL) += udl/
81obj-$(CONFIG_DRM_AST) += ast/ 81obj-$(CONFIG_DRM_AST) += ast/
82obj-$(CONFIG_DRM_ARMADA) += armada/ 82obj-$(CONFIG_DRM_ARMADA) += armada/
83obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/ 83obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/
84obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/ 84obj-y += rcar-du/
85obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ 85obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
86obj-y += omapdrm/ 86obj-y += omapdrm/
87obj-$(CONFIG_DRM_SUN4I) += sun4i/ 87obj-$(CONFIG_DRM_SUN4I) += sun4i/
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index 225141656e19..7c36e2777a15 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -4,6 +4,7 @@ config DRM_RCAR_DU
4 depends on DRM && OF 4 depends on DRM && OF
5 depends on ARM || ARM64 5 depends on ARM || ARM64
6 depends on ARCH_RENESAS || COMPILE_TEST 6 depends on ARCH_RENESAS || COMPILE_TEST
7 imply DRM_RCAR_LVDS
7 select DRM_KMS_HELPER 8 select DRM_KMS_HELPER
8 select DRM_KMS_CMA_HELPER 9 select DRM_KMS_CMA_HELPER
9 select DRM_GEM_CMA_HELPER 10 select DRM_GEM_CMA_HELPER
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
index a7789c5b3880..7ef97b2a6eda 100644
--- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
@@ -23,6 +23,7 @@
23#include <drm/drm_panel.h> 23#include <drm/drm_panel.h>
24#include <drm/drm_probe_helper.h> 24#include <drm/drm_probe_helper.h>
25 25
26#include "rcar_lvds.h"
26#include "rcar_lvds_regs.h" 27#include "rcar_lvds_regs.h"
27 28
28struct rcar_lvds; 29struct rcar_lvds;
@@ -183,8 +184,9 @@ struct pll_info {
183 184
184static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk, 185static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk,
185 unsigned long target, struct pll_info *pll, 186 unsigned long target, struct pll_info *pll,
186 u32 clksel) 187 u32 clksel, bool dot_clock_only)
187{ 188{
189 unsigned int div7 = dot_clock_only ? 1 : 7;
188 unsigned long output; 190 unsigned long output;
189 unsigned long fin; 191 unsigned long fin;
190 unsigned int m_min; 192 unsigned int m_min;
@@ -218,9 +220,9 @@ static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk,
218 * `------------> | | 220 * `------------> | |
219 * |/ 221 * |/
220 * 222 *
221 * The /7 divider is optional when the LVDS PLL is used to generate a 223 * The /7 divider is optional, it is enabled when the LVDS PLL is used
222 * dot clock for the DU RGB output, without using the LVDS encoder. We 224 * to drive the LVDS encoder, and disabled when used to generate a dot
223 * don't support this configuration yet. 225 * clock for the DU RGB output, without using the LVDS encoder.
224 * 226 *
225 * The PLL allowed input frequency range is 12 MHz to 192 MHz. 227 * The PLL allowed input frequency range is 12 MHz to 192 MHz.
226 */ 228 */
@@ -280,7 +282,7 @@ static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk,
280 * the PLL, followed by a an optional fixed /7 282 * the PLL, followed by a an optional fixed /7
281 * divider. 283 * divider.
282 */ 284 */
283 fout = fvco / (1 << e) / 7; 285 fout = fvco / (1 << e) / div7;
284 div = DIV_ROUND_CLOSEST(fout, target); 286 div = DIV_ROUND_CLOSEST(fout, target);
285 diff = abs(fout / div - target); 287 diff = abs(fout / div - target);
286 288
@@ -301,7 +303,7 @@ static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk,
301 303
302done: 304done:
303 output = fin * pll->pll_n / pll->pll_m / (1 << pll->pll_e) 305 output = fin * pll->pll_n / pll->pll_m / (1 << pll->pll_e)
304 / 7 / pll->div; 306 / div7 / pll->div;
305 error = (long)(output - target) * 10000 / (long)target; 307 error = (long)(output - target) * 10000 / (long)target;
306 308
307 dev_dbg(lvds->dev, 309 dev_dbg(lvds->dev,
@@ -311,17 +313,18 @@ done:
311 pll->pll_m, pll->pll_n, pll->pll_e, pll->div); 313 pll->pll_m, pll->pll_n, pll->pll_e, pll->div);
312} 314}
313 315
314static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq) 316static void __rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds,
317 unsigned int freq, bool dot_clock_only)
315{ 318{
316 struct pll_info pll = { .diff = (unsigned long)-1 }; 319 struct pll_info pll = { .diff = (unsigned long)-1 };
317 u32 lvdpllcr; 320 u32 lvdpllcr;
318 321
319 rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[0], freq, &pll, 322 rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[0], freq, &pll,
320 LVDPLLCR_CKSEL_DU_DOTCLKIN(0)); 323 LVDPLLCR_CKSEL_DU_DOTCLKIN(0), dot_clock_only);
321 rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[1], freq, &pll, 324 rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[1], freq, &pll,
322 LVDPLLCR_CKSEL_DU_DOTCLKIN(1)); 325 LVDPLLCR_CKSEL_DU_DOTCLKIN(1), dot_clock_only);
323 rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.extal, freq, &pll, 326 rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.extal, freq, &pll,
324 LVDPLLCR_CKSEL_EXTAL); 327 LVDPLLCR_CKSEL_EXTAL, dot_clock_only);
325 328
326 lvdpllcr = LVDPLLCR_PLLON | pll.clksel | LVDPLLCR_CLKOUT 329 lvdpllcr = LVDPLLCR_PLLON | pll.clksel | LVDPLLCR_CLKOUT
327 | LVDPLLCR_PLLN(pll.pll_n - 1) | LVDPLLCR_PLLM(pll.pll_m - 1); 330 | LVDPLLCR_PLLN(pll.pll_n - 1) | LVDPLLCR_PLLM(pll.pll_m - 1);
@@ -330,6 +333,9 @@ static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq)
330 lvdpllcr |= LVDPLLCR_STP_CLKOUTE | LVDPLLCR_OUTCLKSEL 333 lvdpllcr |= LVDPLLCR_STP_CLKOUTE | LVDPLLCR_OUTCLKSEL
331 | LVDPLLCR_PLLE(pll.pll_e - 1); 334 | LVDPLLCR_PLLE(pll.pll_e - 1);
332 335
336 if (dot_clock_only)
337 lvdpllcr |= LVDPLLCR_OCKSEL;
338
333 rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr); 339 rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr);
334 340
335 if (pll.div > 1) 341 if (pll.div > 1)
@@ -343,6 +349,57 @@ static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq)
343 rcar_lvds_write(lvds, LVDDIV, 0); 349 rcar_lvds_write(lvds, LVDDIV, 0);
344} 350}
345 351
352static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq)
353{
354 __rcar_lvds_pll_setup_d3_e3(lvds, freq, false);
355}
356
357/* -----------------------------------------------------------------------------
358 * Clock - D3/E3 only
359 */
360
361int rcar_lvds_clk_enable(struct drm_bridge *bridge, unsigned long freq)
362{
363 struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
364 int ret;
365
366 if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)))
367 return -ENODEV;
368
369 dev_dbg(lvds->dev, "enabling LVDS PLL, freq=%luHz\n", freq);
370
371 WARN_ON(lvds->enabled);
372
373 ret = clk_prepare_enable(lvds->clocks.mod);
374 if (ret < 0)
375 return ret;
376
377 __rcar_lvds_pll_setup_d3_e3(lvds, freq, true);
378
379 lvds->enabled = true;
380 return 0;
381}
382EXPORT_SYMBOL_GPL(rcar_lvds_clk_enable);
383
384void rcar_lvds_clk_disable(struct drm_bridge *bridge)
385{
386 struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
387
388 if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)))
389 return;
390
391 dev_dbg(lvds->dev, "disabling LVDS PLL\n");
392
393 WARN_ON(!lvds->enabled);
394
395 rcar_lvds_write(lvds, LVDPLLCR, 0);
396
397 clk_disable_unprepare(lvds->clocks.mod);
398
399 lvds->enabled = false;
400}
401EXPORT_SYMBOL_GPL(rcar_lvds_clk_disable);
402
346/* ----------------------------------------------------------------------------- 403/* -----------------------------------------------------------------------------
347 * Bridge 404 * Bridge
348 */ 405 */
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.h b/drivers/gpu/drm/rcar-du/rcar_lvds.h
new file mode 100644
index 000000000000..a709cae1bc32
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds.h
@@ -0,0 +1,27 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * rcar_lvds.h -- R-Car LVDS Encoder
4 *
5 * Copyright (C) 2013-2018 Renesas Electronics Corporation
6 *
7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8 */
9
10#ifndef __RCAR_LVDS_H__
11#define __RCAR_LVDS_H__
12
13struct drm_bridge;
14
15#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
16int rcar_lvds_clk_enable(struct drm_bridge *bridge, unsigned long freq);
17void rcar_lvds_clk_disable(struct drm_bridge *bridge);
18#else
19static inline int rcar_lvds_clk_enable(struct drm_bridge *bridge,
20 unsigned long freq)
21{
22 return -ENOSYS;
23}
24static inline void rcar_lvds_clk_disable(struct drm_bridge *bridge) { }
25#endif /* CONFIG_DRM_RCAR_LVDS */
26
27#endif /* __RCAR_LVDS_H__ */