aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2013-06-17 07:48:27 -0400
committerLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2013-08-09 17:17:53 -0400
commit90374b5c25c9f04895c52a1e7a2468ee8dac525b (patch)
tree12d6f168083bdab0902c003b068527b3a7c130fe /drivers
parent7cbc05cb518304b746bea00bc7c0b005217bcaf7 (diff)
drm/rcar-du: Add internal LVDS encoder support
The R8A7790 includes two internal LVDS encoders. Support them in the DU driver. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/rcar-du/Kconfig7
-rw-r--r--drivers/gpu/drm/rcar-du/Makefile4
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.h2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h4
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_encoder.c38
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_encoder.h2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c5
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c196
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h46
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_lvds_regs.h69
12 files changed, 374 insertions, 3 deletions
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index 72887df8dd76..c590cd9dca0b 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -7,3 +7,10 @@ config DRM_RCAR_DU
7 help 7 help
8 Choose this option if you have an R-Car chipset. 8 Choose this option if you have an R-Car chipset.
9 If M is selected the module will be called rcar-du-drm. 9 If M is selected the module will be called rcar-du-drm.
10
11config DRM_RCAR_LVDS
12 bool "R-Car DU LVDS Encoder Support"
13 depends on DRM_RCAR_DU
14 help
15 Enable support the R-Car Display Unit embedded LVDS encoders
16 (currently only on R8A7790).
diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
index b9b5e666fbba..12b8d4477835 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -7,4 +7,6 @@ rcar-du-drm-y := rcar_du_crtc.o \
7 rcar_du_plane.o \ 7 rcar_du_plane.o \
8 rcar_du_vgacon.o 8 rcar_du_vgacon.o
9 9
10obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o 10rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_lvdsenc.o
11
12obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 245800ddd1a8..33df7a583143 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -26,8 +26,6 @@
26#include "rcar_du_plane.h" 26#include "rcar_du_plane.h"
27#include "rcar_du_regs.h" 27#include "rcar_du_regs.h"
28 28
29#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc)
30
31static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg) 29static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg)
32{ 30{
33 struct rcar_du_device *rcdu = rcrtc->group->dev; 31 struct rcar_du_device *rcdu = rcrtc->group->dev;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 39a983d13afb..43e7575c700c 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -39,6 +39,8 @@ struct rcar_du_crtc {
39 struct rcar_du_plane *plane; 39 struct rcar_du_plane *plane;
40}; 40};
41 41
42#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc)
43
42int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index); 44int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index);
43void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable); 45void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable);
44void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc, 46void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 4bc399734490..38a8b52624ce 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -232,6 +232,7 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = {
232 .encoder_type = DRM_MODE_ENCODER_NONE, 232 .encoder_type = DRM_MODE_ENCODER_NONE,
233 }, 233 },
234 }, 234 },
235 .num_lvds = 0,
235}; 236};
236 237
237static const struct rcar_du_device_info rcar_du_r8a7790_info = { 238static const struct rcar_du_device_info rcar_du_r8a7790_info = {
@@ -255,6 +256,7 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = {
255 .encoder_type = DRM_MODE_ENCODER_LVDS, 256 .encoder_type = DRM_MODE_ENCODER_LVDS,
256 }, 257 },
257 }, 258 },
259 .num_lvds = 2,
258}; 260};
259 261
260static const struct platform_device_id rcar_du_id_table[] = { 262static const struct platform_device_id rcar_du_id_table[] = {
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index 924f5e08f060..050d71c1f785 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -24,6 +24,7 @@ struct clk;
24struct device; 24struct device;
25struct drm_device; 25struct drm_device;
26struct rcar_du_device; 26struct rcar_du_device;
27struct rcar_du_lvdsenc;
27 28
28#define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */ 29#define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */
29#define RCAR_DU_FEATURE_ALIGN_128B (1 << 1) /* Align pitches to 128 bytes */ 30#define RCAR_DU_FEATURE_ALIGN_128B (1 << 1) /* Align pitches to 128 bytes */
@@ -48,11 +49,13 @@ struct rcar_du_output_routing {
48 * @features: device features (RCAR_DU_FEATURE_*) 49 * @features: device features (RCAR_DU_FEATURE_*)
49 * @num_crtcs: total number of CRTCs 50 * @num_crtcs: total number of CRTCs
50 * @routes: array of CRTC to output routes, indexed by output (RCAR_DU_OUTPUT_*) 51 * @routes: array of CRTC to output routes, indexed by output (RCAR_DU_OUTPUT_*)
52 * @num_lvds: number of internal LVDS encoders
51 */ 53 */
52struct rcar_du_device_info { 54struct rcar_du_device_info {
53 unsigned int features; 55 unsigned int features;
54 unsigned int num_crtcs; 56 unsigned int num_crtcs;
55 struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX]; 57 struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX];
58 unsigned int num_lvds;
56}; 59};
57 60
58struct rcar_du_device { 61struct rcar_du_device {
@@ -70,6 +73,7 @@ struct rcar_du_device {
70 struct rcar_du_group groups[2]; 73 struct rcar_du_group groups[2];
71 74
72 unsigned int dpad0_source; 75 unsigned int dpad0_source;
76 struct rcar_du_lvdsenc *lvds[2];
73}; 77};
74 78
75static inline bool rcar_du_has(struct rcar_du_device *rcdu, 79static inline bool rcar_du_has(struct rcar_du_device *rcdu,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
index 2aac28d21f87..3daa7a168dc6 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
@@ -11,6 +11,8 @@
11 * (at your option) any later version. 11 * (at your option) any later version.
12 */ 12 */
13 13
14#include <linux/export.h>
15
14#include <drm/drmP.h> 16#include <drm/drmP.h>
15#include <drm/drm_crtc.h> 17#include <drm/drm_crtc.h>
16#include <drm/drm_crtc_helper.h> 18#include <drm/drm_crtc_helper.h>
@@ -19,6 +21,7 @@
19#include "rcar_du_encoder.h" 21#include "rcar_du_encoder.h"
20#include "rcar_du_kms.h" 22#include "rcar_du_kms.h"
21#include "rcar_du_lvdscon.h" 23#include "rcar_du_lvdscon.h"
24#include "rcar_du_lvdsenc.h"
22#include "rcar_du_vgacon.h" 25#include "rcar_du_vgacon.h"
23 26
24/* ----------------------------------------------------------------------------- 27/* -----------------------------------------------------------------------------
@@ -39,12 +42,17 @@ rcar_du_connector_best_encoder(struct drm_connector *connector)
39 42
40static void rcar_du_encoder_dpms(struct drm_encoder *encoder, int mode) 43static void rcar_du_encoder_dpms(struct drm_encoder *encoder, int mode)
41{ 44{
45 struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
46
47 if (renc->lvds)
48 rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, mode);
42} 49}
43 50
44static bool rcar_du_encoder_mode_fixup(struct drm_encoder *encoder, 51static bool rcar_du_encoder_mode_fixup(struct drm_encoder *encoder,
45 const struct drm_display_mode *mode, 52 const struct drm_display_mode *mode,
46 struct drm_display_mode *adjusted_mode) 53 struct drm_display_mode *adjusted_mode)
47{ 54{
55 struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
48 const struct drm_display_mode *panel_mode; 56 const struct drm_display_mode *panel_mode;
49 struct drm_device *dev = encoder->dev; 57 struct drm_device *dev = encoder->dev;
50 struct drm_connector *connector; 58 struct drm_connector *connector;
@@ -82,15 +90,32 @@ static bool rcar_du_encoder_mode_fixup(struct drm_encoder *encoder,
82 /* The flat panel mode is fixed, just copy it to the adjusted mode. */ 90 /* The flat panel mode is fixed, just copy it to the adjusted mode. */
83 drm_mode_copy(adjusted_mode, panel_mode); 91 drm_mode_copy(adjusted_mode, panel_mode);
84 92
93 /* The internal LVDS encoder has a clock frequency operating range of
94 * 30MHz to 150MHz. Clamp the clock accordingly.
95 */
96 if (renc->lvds)
97 adjusted_mode->clock = clamp(adjusted_mode->clock,
98 30000, 150000);
99
85 return true; 100 return true;
86} 101}
87 102
88static void rcar_du_encoder_mode_prepare(struct drm_encoder *encoder) 103static void rcar_du_encoder_mode_prepare(struct drm_encoder *encoder)
89{ 104{
105 struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
106
107 if (renc->lvds)
108 rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc,
109 DRM_MODE_DPMS_OFF);
90} 110}
91 111
92static void rcar_du_encoder_mode_commit(struct drm_encoder *encoder) 112static void rcar_du_encoder_mode_commit(struct drm_encoder *encoder)
93{ 113{
114 struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
115
116 if (renc->lvds)
117 rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc,
118 DRM_MODE_DPMS_ON);
94} 119}
95 120
96static void rcar_du_encoder_mode_set(struct drm_encoder *encoder, 121static void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
@@ -129,6 +154,19 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
129 154
130 renc->output = output; 155 renc->output = output;
131 156
157 switch (output) {
158 case RCAR_DU_OUTPUT_LVDS0:
159 renc->lvds = rcdu->lvds[0];
160 break;
161
162 case RCAR_DU_OUTPUT_LVDS1:
163 renc->lvds = rcdu->lvds[1];
164 break;
165
166 default:
167 break;
168 }
169
132 switch (type) { 170 switch (type) {
133 case RCAR_DU_ENCODER_VGA: 171 case RCAR_DU_ENCODER_VGA:
134 encoder_type = DRM_MODE_ENCODER_DAC; 172 encoder_type = DRM_MODE_ENCODER_DAC;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
index 2310416ea21f..0e5a65e45d0e 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
@@ -19,10 +19,12 @@
19#include <drm/drm_crtc.h> 19#include <drm/drm_crtc.h>
20 20
21struct rcar_du_device; 21struct rcar_du_device;
22struct rcar_du_lvdsenc;
22 23
23struct rcar_du_encoder { 24struct rcar_du_encoder {
24 struct drm_encoder encoder; 25 struct drm_encoder encoder;
25 enum rcar_du_output output; 26 enum rcar_du_output output;
27 struct rcar_du_lvdsenc *lvds;
26}; 28};
27 29
28#define to_rcar_encoder(e) \ 30#define to_rcar_encoder(e) \
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index 2b92e68a09f0..cc71b1a0c3ce 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -21,6 +21,7 @@
21#include "rcar_du_drv.h" 21#include "rcar_du_drv.h"
22#include "rcar_du_encoder.h" 22#include "rcar_du_encoder.h"
23#include "rcar_du_kms.h" 23#include "rcar_du_kms.h"
24#include "rcar_du_lvdsenc.h"
24#include "rcar_du_regs.h" 25#include "rcar_du_regs.h"
25 26
26/* ----------------------------------------------------------------------------- 27/* -----------------------------------------------------------------------------
@@ -217,6 +218,10 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
217 } 218 }
218 219
219 /* Initialize the encoders. */ 220 /* Initialize the encoders. */
221 ret = rcar_du_lvdsenc_init(rcdu);
222 if (ret < 0)
223 return ret;
224
220 for (i = 0; i < rcdu->pdata->num_encoders; ++i) { 225 for (i = 0; i < rcdu->pdata->num_encoders; ++i) {
221 const struct rcar_du_encoder_data *pdata = 226 const struct rcar_du_encoder_data *pdata =
222 &rcdu->pdata->encoders[i]; 227 &rcdu->pdata->encoders[i];
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
new file mode 100644
index 000000000000..a0f6a1781925
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
@@ -0,0 +1,196 @@
1/*
2 * rcar_du_lvdsenc.c -- R-Car Display Unit LVDS Encoder
3 *
4 * Copyright (C) 2013 Renesas Corporation
5 *
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/clk.h>
15#include <linux/delay.h>
16#include <linux/io.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
19
20#include "rcar_du_drv.h"
21#include "rcar_du_encoder.h"
22#include "rcar_du_lvdsenc.h"
23#include "rcar_lvds_regs.h"
24
25struct rcar_du_lvdsenc {
26 struct rcar_du_device *dev;
27
28 unsigned int index;
29 void __iomem *mmio;
30 struct clk *clock;
31 int dpms;
32
33 enum rcar_lvds_input input;
34};
35
36static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data)
37{
38 iowrite32(data, lvds->mmio + reg);
39}
40
41static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
42 struct rcar_du_crtc *rcrtc)
43{
44 const struct drm_display_mode *mode = &rcrtc->crtc.mode;
45 unsigned int freq = mode->clock;
46 u32 lvdcr0;
47 u32 pllcr;
48 int ret;
49
50 if (lvds->dpms == DRM_MODE_DPMS_ON)
51 return 0;
52
53 ret = clk_prepare_enable(lvds->clock);
54 if (ret < 0)
55 return ret;
56
57 /* PLL clock configuration */
58 if (freq <= 38000)
59 pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
60 else if (freq <= 60000)
61 pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
62 else if (freq <= 121000)
63 pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
64 else
65 pllcr = LVDPLLCR_PLLDLYCNT_150M;
66
67 rcar_lvds_write(lvds, LVDPLLCR, pllcr);
68
69 /* Hardcode the channels and control signals routing for now.
70 *
71 * HSYNC -> CTRL0
72 * VSYNC -> CTRL1
73 * DISP -> CTRL2
74 * 0 -> CTRL3
75 *
76 * Channels 1 and 3 are switched on ES1.
77 */
78 rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
79 LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
80 LVDCTRCR_CTR0SEL_HSYNC);
81 rcar_lvds_write(lvds, LVDCHCR,
82 LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3) |
83 LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1));
84
85 /* Select the input, hardcode mode 0, enable LVDS operation and turn
86 * bias circuitry on.
87 */
88 lvdcr0 = LVDCR0_BEN | LVDCR0_LVEN;
89 if (rcrtc->index == 2)
90 lvdcr0 |= LVDCR0_DUSEL;
91 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
92
93 /* Turn all the channels on. */
94 rcar_lvds_write(lvds, LVDCR1, LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
95 LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY);
96
97 /* Turn the PLL on, wait for the startup delay, and turn the output
98 * on.
99 */
100 lvdcr0 |= LVDCR0_PLLEN;
101 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
102
103 usleep_range(100, 150);
104
105 lvdcr0 |= LVDCR0_LVRES;
106 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
107
108 lvds->dpms = DRM_MODE_DPMS_ON;
109 return 0;
110}
111
112static void rcar_du_lvdsenc_stop(struct rcar_du_lvdsenc *lvds)
113{
114 if (lvds->dpms == DRM_MODE_DPMS_OFF)
115 return;
116
117 rcar_lvds_write(lvds, LVDCR0, 0);
118 rcar_lvds_write(lvds, LVDCR1, 0);
119
120 clk_disable_unprepare(lvds->clock);
121
122 lvds->dpms = DRM_MODE_DPMS_OFF;
123}
124
125int rcar_du_lvdsenc_dpms(struct rcar_du_lvdsenc *lvds,
126 struct drm_crtc *crtc, int mode)
127{
128 if (mode == DRM_MODE_DPMS_OFF) {
129 rcar_du_lvdsenc_stop(lvds);
130 return 0;
131 } else if (crtc) {
132 struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
133 return rcar_du_lvdsenc_start(lvds, rcrtc);
134 } else
135 return -EINVAL;
136}
137
138static int rcar_du_lvdsenc_get_resources(struct rcar_du_lvdsenc *lvds,
139 struct platform_device *pdev)
140{
141 struct resource *mem;
142 char name[7];
143
144 sprintf(name, "lvds.%u", lvds->index);
145
146 mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
147 if (mem == NULL) {
148 dev_err(&pdev->dev, "failed to get memory resource for %s\n",
149 name);
150 return -EINVAL;
151 }
152
153 lvds->mmio = devm_ioremap_resource(&pdev->dev, mem);
154 if (lvds->mmio == NULL) {
155 dev_err(&pdev->dev, "failed to remap memory resource for %s\n",
156 name);
157 return -ENOMEM;
158 }
159
160 lvds->clock = devm_clk_get(&pdev->dev, name);
161 if (IS_ERR(lvds->clock)) {
162 dev_err(&pdev->dev, "failed to get clock for %s\n", name);
163 return PTR_ERR(lvds->clock);
164 }
165
166 return 0;
167}
168
169int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu)
170{
171 struct platform_device *pdev = to_platform_device(rcdu->dev);
172 struct rcar_du_lvdsenc *lvds;
173 unsigned int i;
174 int ret;
175
176 for (i = 0; i < rcdu->info->num_lvds; ++i) {
177 lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
178 if (lvds == NULL) {
179 dev_err(&pdev->dev, "failed to allocate private data\n");
180 return -ENOMEM;
181 }
182
183 lvds->dev = rcdu;
184 lvds->index = i;
185 lvds->input = i ? RCAR_LVDS_INPUT_DU1 : RCAR_LVDS_INPUT_DU0;
186 lvds->dpms = DRM_MODE_DPMS_OFF;
187
188 ret = rcar_du_lvdsenc_get_resources(lvds, pdev);
189 if (ret < 0)
190 return ret;
191
192 rcdu->lvds[i] = lvds;
193 }
194
195 return 0;
196}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
new file mode 100644
index 000000000000..7051c6de19ae
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
@@ -0,0 +1,46 @@
1/*
2 * rcar_du_lvdsenc.h -- R-Car Display Unit LVDS Encoder
3 *
4 * Copyright (C) 2013 Renesas Corporation
5 *
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#ifndef __RCAR_DU_LVDSENC_H__
15#define __RCAR_DU_LVDSENC_H__
16
17#include <linux/io.h>
18#include <linux/module.h>
19#include <linux/platform_data/rcar-du.h>
20
21struct rcar_drm_crtc;
22struct rcar_du_lvdsenc;
23
24enum rcar_lvds_input {
25 RCAR_LVDS_INPUT_DU0,
26 RCAR_LVDS_INPUT_DU1,
27 RCAR_LVDS_INPUT_DU2,
28};
29
30#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
31int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu);
32int rcar_du_lvdsenc_dpms(struct rcar_du_lvdsenc *lvds,
33 struct drm_crtc *crtc, int mode);
34#else
35static inline int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu)
36{
37 return 0;
38}
39static inline int rcar_du_lvdsenc_dpms(struct rcar_du_lvdsenc *lvds,
40 struct drm_crtc *crtc, int mode)
41{
42 return 0;
43}
44#endif
45
46#endif /* __RCAR_DU_LVDSENC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
new file mode 100644
index 000000000000..77cf9289ab65
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
@@ -0,0 +1,69 @@
1/*
2 * rcar_lvds_regs.h -- R-Car LVDS Interface Registers Definitions
3 *
4 * Copyright (C) 2013 Renesas Electronics Corporation
5 *
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation.
11 */
12
13#ifndef __RCAR_LVDS_REGS_H__
14#define __RCAR_LVDS_REGS_H__
15
16#define LVDCR0 0x0000
17#define LVDCR0_DUSEL (1 << 15)
18#define LVDCR0_DMD (1 << 12)
19#define LVDCR0_LVMD_MASK (0xf << 8)
20#define LVDCR0_LVMD_SHIFT 8
21#define LVDCR0_PLLEN (1 << 4)
22#define LVDCR0_BEN (1 << 2)
23#define LVDCR0_LVEN (1 << 1)
24#define LVDCR0_LVRES (1 << 0)
25
26#define LVDCR1 0x0004
27#define LVDCR1_CKSEL (1 << 15)
28#define LVDCR1_CHSTBY(n) (3 << (2 + (n) * 2))
29#define LVDCR1_CLKSTBY (3 << 0)
30
31#define LVDPLLCR 0x0008
32#define LVDPLLCR_CEEN (1 << 14)
33#define LVDPLLCR_FBEN (1 << 13)
34#define LVDPLLCR_COSEL (1 << 12)
35#define LVDPLLCR_PLLDLYCNT_150M (0x1bf << 0)
36#define LVDPLLCR_PLLDLYCNT_121M (0x22c << 0)
37#define LVDPLLCR_PLLDLYCNT_60M (0x77b << 0)
38#define LVDPLLCR_PLLDLYCNT_38M (0x69a << 0)
39#define LVDPLLCR_PLLDLYCNT_MASK (0x7ff << 0)
40
41#define LVDCTRCR 0x000c
42#define LVDCTRCR_CTR3SEL_ZERO (0 << 12)
43#define LVDCTRCR_CTR3SEL_ODD (1 << 12)
44#define LVDCTRCR_CTR3SEL_CDE (2 << 12)
45#define LVDCTRCR_CTR3SEL_MASK (7 << 12)
46#define LVDCTRCR_CTR2SEL_DISP (0 << 8)
47#define LVDCTRCR_CTR2SEL_ODD (1 << 8)
48#define LVDCTRCR_CTR2SEL_CDE (2 << 8)
49#define LVDCTRCR_CTR2SEL_HSYNC (3 << 8)
50#define LVDCTRCR_CTR2SEL_VSYNC (4 << 8)
51#define LVDCTRCR_CTR2SEL_MASK (7 << 8)
52#define LVDCTRCR_CTR1SEL_VSYNC (0 << 4)
53#define LVDCTRCR_CTR1SEL_DISP (1 << 4)
54#define LVDCTRCR_CTR1SEL_ODD (2 << 4)
55#define LVDCTRCR_CTR1SEL_CDE (3 << 4)
56#define LVDCTRCR_CTR1SEL_HSYNC (4 << 4)
57#define LVDCTRCR_CTR1SEL_MASK (7 << 4)
58#define LVDCTRCR_CTR0SEL_HSYNC (0 << 0)
59#define LVDCTRCR_CTR0SEL_VSYNC (1 << 0)
60#define LVDCTRCR_CTR0SEL_DISP (2 << 0)
61#define LVDCTRCR_CTR0SEL_ODD (3 << 0)
62#define LVDCTRCR_CTR0SEL_CDE (4 << 0)
63#define LVDCTRCR_CTR0SEL_MASK (7 << 0)
64
65#define LVDCHCR 0x0010
66#define LVDCHCR_CHSEL_CH(n, c) ((((c) - (n)) & 3) << ((n) * 4))
67#define LVDCHCR_CHSEL_MASK(n) (3 << ((n) * 4))
68
69#endif /* __RCAR_LVDS_REGS_H__ */