aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-04-19 23:19:34 -0400
committerDave Airlie <airlied@redhat.com>2017-04-19 23:19:34 -0400
commitcb2e77c1d53366696a7f47dbcedba99603ca1b55 (patch)
tree70d3d3e649b312f715d0239ac8c75ea1637664fd
parent856ee92e8602bd86d34388ac08381c5cb3918756 (diff)
parent2da042ac05e91b78e4484b731e8eb335c90385d3 (diff)
Merge tag 'sunxi-drm-for-4.12' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into drm-next
Allwinner DRM changes for 4.12 Not any functional changes, but a lot of preliminary rework in order to support multiple display pipelines. * tag 'sunxi-drm-for-4.12' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux: (26 commits) MAINTAINERS: Add sun4i-drm git repo drm/sun4i: Pass pointer for underlying backend into layer init drm/sun4i: Pass pointers for associated backend and tcon into crtc init drm/sun4i: tv: Get tcon and backend pointers from associated crtc drm/sun4i: Use embedded tcon pointer to get the tcon's output port node drm/sun4i: Fix tcon channel 0 comment about backporch = backporch + hsync drm/sun4i: Fix TCON clock and regmap initialization sequence drm/sun4i: Grab reserved memory region drm/sun4i: Add backend and tcon pointers to sun4i_crtc drm/sun4i: Add backend pointer to sun4i_layer drm/sun4i: rgb: Pass tcon pointer when initializing RGB encoder drm/sun4i: tv: Switch to drm_of_find_possible_crtcs drm/sun4i: Drop hardcoded .possible_crtcs values from layers drm/sun4i: Drop primary layer pointer from sun4i_drv drm/sun4i: Initialize crtc from tcon bind function drm/sun4i: Move layers from sun4i_drv to sun4i_crtc drm/sun4i: Add end of list element for sun4i_layers_init's returned list drm/sun4i: Set drm_crtc.port to the underlying TCON's output port node drm/sun4i: Make sunxi_rgb2yuv_coef constant drm/sun4i: Make sun4i_crtc_init return ERR_PTR style error codes ...
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/gpu/drm/sun4i/Makefile4
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_backend.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_crtc.c70
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_crtc.h8
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c47
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.h4
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_framebuffer.c1
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_layer.c32
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_layer.h4
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_rgb.c30
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_rgb.h2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.c36
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.h3
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tv.c27
15 files changed, 164 insertions, 107 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 93ed0319b3d6..afba0760fdaf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4247,6 +4247,7 @@ L: dri-devel@lists.freedesktop.org
4247S: Supported 4247S: Supported
4248F: drivers/gpu/drm/sun4i/ 4248F: drivers/gpu/drm/sun4i/
4249F: Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt 4249F: Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
4250T: git git://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux.git
4250 4251
4251DRM DRIVERS FOR AMLOGIC SOCS 4252DRM DRIVERS FOR AMLOGIC SOCS
4252M: Neil Armstrong <narmstrong@baylibre.com> 4253M: Neil Armstrong <narmstrong@baylibre.com>
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index d625a82a6e5f..59b757350a1f 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -1,11 +1,11 @@
1sun4i-drm-y += sun4i_crtc.o
2sun4i-drm-y += sun4i_drv.o 1sun4i-drm-y += sun4i_drv.o
3sun4i-drm-y += sun4i_framebuffer.o 2sun4i-drm-y += sun4i_framebuffer.o
4sun4i-drm-y += sun4i_layer.o
5 3
6sun4i-tcon-y += sun4i_tcon.o 4sun4i-tcon-y += sun4i_tcon.o
7sun4i-tcon-y += sun4i_rgb.o 5sun4i-tcon-y += sun4i_rgb.o
8sun4i-tcon-y += sun4i_dotclock.o 6sun4i-tcon-y += sun4i_dotclock.o
7sun4i-tcon-y += sun4i_crtc.o
8sun4i-tcon-y += sun4i_layer.o
9 9
10obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o sun4i-tcon.o 10obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o sun4i-tcon.o
11obj-$(CONFIG_DRM_SUN4I) += sun4i_backend.o 11obj-$(CONFIG_DRM_SUN4I) += sun4i_backend.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 08ce15070f80..d660741ba475 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -24,7 +24,7 @@
24#include "sun4i_backend.h" 24#include "sun4i_backend.h"
25#include "sun4i_drv.h" 25#include "sun4i_drv.h"
26 26
27static u32 sunxi_rgb2yuv_coef[12] = { 27static const u32 sunxi_rgb2yuv_coef[12] = {
28 0x00000107, 0x00000204, 0x00000064, 0x00000108, 28 0x00000107, 0x00000204, 0x00000064, 0x00000108,
29 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808, 29 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
30 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 30 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index a5d546a68e16..3c876c3a356a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -19,6 +19,7 @@
19#include <linux/clk-provider.h> 19#include <linux/clk-provider.h>
20#include <linux/ioport.h> 20#include <linux/ioport.h>
21#include <linux/of_address.h> 21#include <linux/of_address.h>
22#include <linux/of_graph.h>
22#include <linux/of_irq.h> 23#include <linux/of_irq.h>
23#include <linux/regmap.h> 24#include <linux/regmap.h>
24 25
@@ -27,6 +28,7 @@
27#include "sun4i_backend.h" 28#include "sun4i_backend.h"
28#include "sun4i_crtc.h" 29#include "sun4i_crtc.h"
29#include "sun4i_drv.h" 30#include "sun4i_drv.h"
31#include "sun4i_layer.h"
30#include "sun4i_tcon.h" 32#include "sun4i_tcon.h"
31 33
32static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc, 34static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
@@ -50,12 +52,11 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
50 struct drm_crtc_state *old_state) 52 struct drm_crtc_state *old_state)
51{ 53{
52 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 54 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
53 struct sun4i_drv *drv = scrtc->drv;
54 struct drm_pending_vblank_event *event = crtc->state->event; 55 struct drm_pending_vblank_event *event = crtc->state->event;
55 56
56 DRM_DEBUG_DRIVER("Committing plane changes\n"); 57 DRM_DEBUG_DRIVER("Committing plane changes\n");
57 58
58 sun4i_backend_commit(drv->backend); 59 sun4i_backend_commit(scrtc->backend);
59 60
60 if (event) { 61 if (event) {
61 crtc->state->event = NULL; 62 crtc->state->event = NULL;
@@ -72,11 +73,10 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
72static void sun4i_crtc_disable(struct drm_crtc *crtc) 73static void sun4i_crtc_disable(struct drm_crtc *crtc)
73{ 74{
74 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 75 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
75 struct sun4i_drv *drv = scrtc->drv;
76 76
77 DRM_DEBUG_DRIVER("Disabling the CRTC\n"); 77 DRM_DEBUG_DRIVER("Disabling the CRTC\n");
78 78
79 sun4i_tcon_disable(drv->tcon); 79 sun4i_tcon_disable(scrtc->tcon);
80 80
81 if (crtc->state->event && !crtc->state->active) { 81 if (crtc->state->event && !crtc->state->active) {
82 spin_lock_irq(&crtc->dev->event_lock); 82 spin_lock_irq(&crtc->dev->event_lock);
@@ -90,11 +90,10 @@ static void sun4i_crtc_disable(struct drm_crtc *crtc)
90static void sun4i_crtc_enable(struct drm_crtc *crtc) 90static void sun4i_crtc_enable(struct drm_crtc *crtc)
91{ 91{
92 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 92 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
93 struct sun4i_drv *drv = scrtc->drv;
94 93
95 DRM_DEBUG_DRIVER("Enabling the CRTC\n"); 94 DRM_DEBUG_DRIVER("Enabling the CRTC\n");
96 95
97 sun4i_tcon_enable(drv->tcon); 96 sun4i_tcon_enable(scrtc->tcon);
98} 97}
99 98
100static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = { 99static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
@@ -107,11 +106,10 @@ static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
107static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc) 106static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc)
108{ 107{
109 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 108 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
110 struct sun4i_drv *drv = scrtc->drv;
111 109
112 DRM_DEBUG_DRIVER("Enabling VBLANK on crtc %p\n", crtc); 110 DRM_DEBUG_DRIVER("Enabling VBLANK on crtc %p\n", crtc);
113 111
114 sun4i_tcon_enable_vblank(drv->tcon, true); 112 sun4i_tcon_enable_vblank(scrtc->tcon, true);
115 113
116 return 0; 114 return 0;
117} 115}
@@ -119,11 +117,10 @@ static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc)
119static void sun4i_crtc_disable_vblank(struct drm_crtc *crtc) 117static void sun4i_crtc_disable_vblank(struct drm_crtc *crtc)
120{ 118{
121 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 119 struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
122 struct sun4i_drv *drv = scrtc->drv;
123 120
124 DRM_DEBUG_DRIVER("Disabling VBLANK on crtc %p\n", crtc); 121 DRM_DEBUG_DRIVER("Disabling VBLANK on crtc %p\n", crtc);
125 122
126 sun4i_tcon_enable_vblank(drv->tcon, false); 123 sun4i_tcon_enable_vblank(scrtc->tcon, false);
127} 124}
128 125
129static const struct drm_crtc_funcs sun4i_crtc_funcs = { 126static const struct drm_crtc_funcs sun4i_crtc_funcs = {
@@ -137,28 +134,67 @@ static const struct drm_crtc_funcs sun4i_crtc_funcs = {
137 .disable_vblank = sun4i_crtc_disable_vblank, 134 .disable_vblank = sun4i_crtc_disable_vblank,
138}; 135};
139 136
140struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm) 137struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
138 struct sun4i_backend *backend,
139 struct sun4i_tcon *tcon)
141{ 140{
142 struct sun4i_drv *drv = drm->dev_private;
143 struct sun4i_crtc *scrtc; 141 struct sun4i_crtc *scrtc;
144 int ret; 142 struct drm_plane *primary = NULL, *cursor = NULL;
143 int ret, i;
145 144
146 scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL); 145 scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
147 if (!scrtc) 146 if (!scrtc)
147 return ERR_PTR(-ENOMEM);
148 scrtc->backend = backend;
149 scrtc->tcon = tcon;
150
151 /* Create our layers */
152 scrtc->layers = sun4i_layers_init(drm, scrtc->backend);
153 if (IS_ERR(scrtc->layers)) {
154 dev_err(drm->dev, "Couldn't create the planes\n");
148 return NULL; 155 return NULL;
149 scrtc->drv = drv; 156 }
157
158 /* find primary and cursor planes for drm_crtc_init_with_planes */
159 for (i = 0; scrtc->layers[i]; i++) {
160 struct sun4i_layer *layer = scrtc->layers[i];
161
162 switch (layer->plane.type) {
163 case DRM_PLANE_TYPE_PRIMARY:
164 primary = &layer->plane;
165 break;
166 case DRM_PLANE_TYPE_CURSOR:
167 cursor = &layer->plane;
168 break;
169 default:
170 break;
171 }
172 }
150 173
151 ret = drm_crtc_init_with_planes(drm, &scrtc->crtc, 174 ret = drm_crtc_init_with_planes(drm, &scrtc->crtc,
152 drv->primary, 175 primary,
153 NULL, 176 cursor,
154 &sun4i_crtc_funcs, 177 &sun4i_crtc_funcs,
155 NULL); 178 NULL);
156 if (ret) { 179 if (ret) {
157 dev_err(drm->dev, "Couldn't init DRM CRTC\n"); 180 dev_err(drm->dev, "Couldn't init DRM CRTC\n");
158 return NULL; 181 return ERR_PTR(ret);
159 } 182 }
160 183
161 drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs); 184 drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs);
162 185
186 /* Set crtc.port to output port node of the tcon */
187 scrtc->crtc.port = of_graph_get_port_by_id(scrtc->tcon->dev->of_node,
188 1);
189
190 /* Set possible_crtcs to this crtc for overlay planes */
191 for (i = 0; scrtc->layers[i]; i++) {
192 uint32_t possible_crtcs = BIT(drm_crtc_index(&scrtc->crtc));
193 struct sun4i_layer *layer = scrtc->layers[i];
194
195 if (layer->plane.type == DRM_PLANE_TYPE_OVERLAY)
196 layer->plane.possible_crtcs = possible_crtcs;
197 }
198
163 return scrtc; 199 return scrtc;
164} 200}
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.h b/drivers/gpu/drm/sun4i/sun4i_crtc.h
index dec8ce4d9b25..230cb8f0d601 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.h
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.h
@@ -17,7 +17,9 @@ struct sun4i_crtc {
17 struct drm_crtc crtc; 17 struct drm_crtc crtc;
18 struct drm_pending_vblank_event *event; 18 struct drm_pending_vblank_event *event;
19 19
20 struct sun4i_drv *drv; 20 struct sun4i_backend *backend;
21 struct sun4i_tcon *tcon;
22 struct sun4i_layer **layers;
21}; 23};
22 24
23static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc) 25static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc)
@@ -25,6 +27,8 @@ static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc)
25 return container_of(crtc, struct sun4i_crtc, crtc); 27 return container_of(crtc, struct sun4i_crtc, crtc);
26} 28}
27 29
28struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm); 30struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
31 struct sun4i_backend *backend,
32 struct sun4i_tcon *tcon);
29 33
30#endif /* _SUN4I_CRTC_H_ */ 34#endif /* _SUN4I_CRTC_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 329ea56106a5..8ddd72cd5873 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -12,6 +12,7 @@
12 12
13#include <linux/component.h> 13#include <linux/component.h>
14#include <linux/of_graph.h> 14#include <linux/of_graph.h>
15#include <linux/of_reserved_mem.h>
15 16
16#include <drm/drmP.h> 17#include <drm/drmP.h>
17#include <drm/drm_crtc_helper.h> 18#include <drm/drm_crtc_helper.h>
@@ -20,10 +21,9 @@
20#include <drm/drm_fb_helper.h> 21#include <drm/drm_fb_helper.h>
21#include <drm/drm_of.h> 22#include <drm/drm_of.h>
22 23
23#include "sun4i_crtc.h"
24#include "sun4i_drv.h" 24#include "sun4i_drv.h"
25#include "sun4i_framebuffer.h" 25#include "sun4i_framebuffer.h"
26#include "sun4i_layer.h" 26#include "sun4i_tcon.h"
27 27
28DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops); 28DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops);
29 29
@@ -92,30 +92,25 @@ static int sun4i_drv_bind(struct device *dev)
92 } 92 }
93 drm->dev_private = drv; 93 drm->dev_private = drv;
94 94
95 drm_vblank_init(drm, 1); 95 ret = of_reserved_mem_device_init(dev);
96 if (ret && ret != -ENODEV) {
97 dev_err(drm->dev, "Couldn't claim our memory region\n");
98 goto free_drm;
99 }
100
101 /* drm_vblank_init calls kcalloc, which can fail */
102 ret = drm_vblank_init(drm, 1);
103 if (ret)
104 goto free_mem_region;
105
96 drm_mode_config_init(drm); 106 drm_mode_config_init(drm);
97 107
98 ret = component_bind_all(drm->dev, drm); 108 ret = component_bind_all(drm->dev, drm);
99 if (ret) { 109 if (ret) {
100 dev_err(drm->dev, "Couldn't bind all pipelines components\n"); 110 dev_err(drm->dev, "Couldn't bind all pipelines components\n");
101 goto free_drm; 111 goto cleanup_mode_config;
102 }
103
104 /* Create our layers */
105 drv->layers = sun4i_layers_init(drm);
106 if (IS_ERR(drv->layers)) {
107 dev_err(drm->dev, "Couldn't create the planes\n");
108 ret = PTR_ERR(drv->layers);
109 goto free_drm;
110 } 112 }
111 113
112 /* Create our CRTC */
113 drv->crtc = sun4i_crtc_init(drm);
114 if (!drv->crtc) {
115 dev_err(drm->dev, "Couldn't create the CRTC\n");
116 ret = -EINVAL;
117 goto free_drm;
118 }
119 drm->irq_enabled = true; 114 drm->irq_enabled = true;
120 115
121 /* Remove early framebuffers (ie. simplefb) */ 116 /* Remove early framebuffers (ie. simplefb) */
@@ -126,7 +121,7 @@ static int sun4i_drv_bind(struct device *dev)
126 if (IS_ERR(drv->fbdev)) { 121 if (IS_ERR(drv->fbdev)) {
127 dev_err(drm->dev, "Couldn't create our framebuffer\n"); 122 dev_err(drm->dev, "Couldn't create our framebuffer\n");
128 ret = PTR_ERR(drv->fbdev); 123 ret = PTR_ERR(drv->fbdev);
129 goto free_drm; 124 goto cleanup_mode_config;
130 } 125 }
131 126
132 /* Enable connectors polling */ 127 /* Enable connectors polling */
@@ -134,10 +129,18 @@ static int sun4i_drv_bind(struct device *dev)
134 129
135 ret = drm_dev_register(drm, 0); 130 ret = drm_dev_register(drm, 0);
136 if (ret) 131 if (ret)
137 goto free_drm; 132 goto finish_poll;
138 133
139 return 0; 134 return 0;
140 135
136finish_poll:
137 drm_kms_helper_poll_fini(drm);
138 sun4i_framebuffer_free(drm);
139cleanup_mode_config:
140 drm_mode_config_cleanup(drm);
141 drm_vblank_cleanup(drm);
142free_mem_region:
143 of_reserved_mem_device_release(dev);
141free_drm: 144free_drm:
142 drm_dev_unref(drm); 145 drm_dev_unref(drm);
143 return ret; 146 return ret;
@@ -150,7 +153,9 @@ static void sun4i_drv_unbind(struct device *dev)
150 drm_dev_unregister(drm); 153 drm_dev_unregister(drm);
151 drm_kms_helper_poll_fini(drm); 154 drm_kms_helper_poll_fini(drm);
152 sun4i_framebuffer_free(drm); 155 sun4i_framebuffer_free(drm);
156 drm_mode_config_cleanup(drm);
153 drm_vblank_cleanup(drm); 157 drm_vblank_cleanup(drm);
158 of_reserved_mem_device_release(dev);
154 drm_dev_unref(drm); 159 drm_dev_unref(drm);
155} 160}
156 161
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
index 597353eab728..5df50126ff52 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.h
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
@@ -18,13 +18,9 @@
18 18
19struct sun4i_drv { 19struct sun4i_drv {
20 struct sun4i_backend *backend; 20 struct sun4i_backend *backend;
21 struct sun4i_crtc *crtc;
22 struct sun4i_tcon *tcon; 21 struct sun4i_tcon *tcon;
23 22
24 struct drm_plane *primary;
25 struct drm_fbdev_cma *fbdev; 23 struct drm_fbdev_cma *fbdev;
26
27 struct sun4i_layer **layers;
28}; 24};
29 25
30#endif /* _SUN4I_DRV_H_ */ 26#endif /* _SUN4I_DRV_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
index 2c3beff8b53e..9872e0fc03b0 100644
--- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
@@ -48,5 +48,4 @@ void sun4i_framebuffer_free(struct drm_device *drm)
48 struct sun4i_drv *drv = drm->dev_private; 48 struct sun4i_drv *drv = drm->dev_private;
49 49
50 drm_fbdev_cma_fini(drv->fbdev); 50 drm_fbdev_cma_fini(drv->fbdev);
51 drm_mode_config_cleanup(drm);
52} 51}
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 5d53c977bca5..f26bde5b9117 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -16,7 +16,6 @@
16#include <drm/drmP.h> 16#include <drm/drmP.h>
17 17
18#include "sun4i_backend.h" 18#include "sun4i_backend.h"
19#include "sun4i_drv.h"
20#include "sun4i_layer.h" 19#include "sun4i_layer.h"
21 20
22struct sun4i_plane_desc { 21struct sun4i_plane_desc {
@@ -36,8 +35,7 @@ static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
36 struct drm_plane_state *old_state) 35 struct drm_plane_state *old_state)
37{ 36{
38 struct sun4i_layer *layer = plane_to_sun4i_layer(plane); 37 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
39 struct sun4i_drv *drv = layer->drv; 38 struct sun4i_backend *backend = layer->backend;
40 struct sun4i_backend *backend = drv->backend;
41 39
42 sun4i_backend_layer_enable(backend, layer->id, false); 40 sun4i_backend_layer_enable(backend, layer->id, false);
43} 41}
@@ -46,8 +44,7 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
46 struct drm_plane_state *old_state) 44 struct drm_plane_state *old_state)
47{ 45{
48 struct sun4i_layer *layer = plane_to_sun4i_layer(plane); 46 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
49 struct sun4i_drv *drv = layer->drv; 47 struct sun4i_backend *backend = layer->backend;
50 struct sun4i_backend *backend = drv->backend;
51 48
52 sun4i_backend_update_layer_coord(backend, layer->id, plane); 49 sun4i_backend_update_layer_coord(backend, layer->id, plane);
53 sun4i_backend_update_layer_formats(backend, layer->id, plane); 50 sun4i_backend_update_layer_formats(backend, layer->id, plane);
@@ -104,9 +101,9 @@ static const struct sun4i_plane_desc sun4i_backend_planes[] = {
104}; 101};
105 102
106static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, 103static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
104 struct sun4i_backend *backend,
107 const struct sun4i_plane_desc *plane) 105 const struct sun4i_plane_desc *plane)
108{ 106{
109 struct sun4i_drv *drv = drm->dev_private;
110 struct sun4i_layer *layer; 107 struct sun4i_layer *layer;
111 int ret; 108 int ret;
112 109
@@ -114,7 +111,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
114 if (!layer) 111 if (!layer)
115 return ERR_PTR(-ENOMEM); 112 return ERR_PTR(-ENOMEM);
116 113
117 ret = drm_universal_plane_init(drm, &layer->plane, BIT(0), 114 /* possible crtcs are set later */
115 ret = drm_universal_plane_init(drm, &layer->plane, 0,
118 &sun4i_backend_layer_funcs, 116 &sun4i_backend_layer_funcs,
119 plane->formats, plane->nformats, 117 plane->formats, plane->nformats,
120 plane->type, NULL); 118 plane->type, NULL);
@@ -125,22 +123,19 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
125 123
126 drm_plane_helper_add(&layer->plane, 124 drm_plane_helper_add(&layer->plane,
127 &sun4i_backend_layer_helper_funcs); 125 &sun4i_backend_layer_helper_funcs);
128 layer->drv = drv; 126 layer->backend = backend;
129
130 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
131 drv->primary = &layer->plane;
132 127
133 return layer; 128 return layer;
134} 129}
135 130
136struct sun4i_layer **sun4i_layers_init(struct drm_device *drm) 131struct sun4i_layer **sun4i_layers_init(struct drm_device *drm,
132 struct sun4i_backend *backend)
137{ 133{
138 struct sun4i_drv *drv = drm->dev_private;
139 struct sun4i_layer **layers; 134 struct sun4i_layer **layers;
140 int i; 135 int i;
141 136
142 layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes), 137 layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1,
143 sizeof(**layers), GFP_KERNEL); 138 sizeof(*layers), GFP_KERNEL);
144 if (!layers) 139 if (!layers)
145 return ERR_PTR(-ENOMEM); 140 return ERR_PTR(-ENOMEM);
146 141
@@ -167,9 +162,9 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
167 */ 162 */
168 for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) { 163 for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
169 const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i]; 164 const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
170 struct sun4i_layer *layer = layers[i]; 165 struct sun4i_layer *layer;
171 166
172 layer = sun4i_layer_init_one(drm, plane); 167 layer = sun4i_layer_init_one(drm, backend, plane);
173 if (IS_ERR(layer)) { 168 if (IS_ERR(layer)) {
174 dev_err(drm->dev, "Couldn't initialize %s plane\n", 169 dev_err(drm->dev, "Couldn't initialize %s plane\n",
175 i ? "overlay" : "primary"); 170 i ? "overlay" : "primary");
@@ -178,11 +173,12 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
178 173
179 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n", 174 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
180 i ? "overlay" : "primary", plane->pipe); 175 i ? "overlay" : "primary", plane->pipe);
181 regmap_update_bits(drv->backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i), 176 regmap_update_bits(backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
182 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK, 177 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
183 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe)); 178 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
184 179
185 layer->id = i; 180 layer->id = i;
181 layers[i] = layer;
186 }; 182 };
187 183
188 return layers; 184 return layers;
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
index a2f65d7a3f4e..4be1f0919df2 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
@@ -16,6 +16,7 @@
16struct sun4i_layer { 16struct sun4i_layer {
17 struct drm_plane plane; 17 struct drm_plane plane;
18 struct sun4i_drv *drv; 18 struct sun4i_drv *drv;
19 struct sun4i_backend *backend;
19 int id; 20 int id;
20}; 21};
21 22
@@ -25,6 +26,7 @@ plane_to_sun4i_layer(struct drm_plane *plane)
25 return container_of(plane, struct sun4i_layer, plane); 26 return container_of(plane, struct sun4i_layer, plane);
26} 27}
27 28
28struct sun4i_layer **sun4i_layers_init(struct drm_device *drm); 29struct sun4i_layer **sun4i_layers_init(struct drm_device *drm,
30 struct sun4i_backend *backend);
29 31
30#endif /* _SUN4I_LAYER_H_ */ 32#endif /* _SUN4I_LAYER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index 46280dd70c9e..67f0b91a99de 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -18,7 +18,7 @@
18#include <drm/drm_of.h> 18#include <drm/drm_of.h>
19#include <drm/drm_panel.h> 19#include <drm/drm_panel.h>
20 20
21#include "sun4i_drv.h" 21#include "sun4i_crtc.h"
22#include "sun4i_tcon.h" 22#include "sun4i_tcon.h"
23#include "sun4i_rgb.h" 23#include "sun4i_rgb.h"
24 24
@@ -26,7 +26,7 @@ struct sun4i_rgb {
26 struct drm_connector connector; 26 struct drm_connector connector;
27 struct drm_encoder encoder; 27 struct drm_encoder encoder;
28 28
29 struct sun4i_drv *drv; 29 struct sun4i_tcon *tcon;
30}; 30};
31 31
32static inline struct sun4i_rgb * 32static inline struct sun4i_rgb *
@@ -47,8 +47,7 @@ static int sun4i_rgb_get_modes(struct drm_connector *connector)
47{ 47{
48 struct sun4i_rgb *rgb = 48 struct sun4i_rgb *rgb =
49 drm_connector_to_sun4i_rgb(connector); 49 drm_connector_to_sun4i_rgb(connector);
50 struct sun4i_drv *drv = rgb->drv; 50 struct sun4i_tcon *tcon = rgb->tcon;
51 struct sun4i_tcon *tcon = drv->tcon;
52 51
53 return drm_panel_get_modes(tcon->panel); 52 return drm_panel_get_modes(tcon->panel);
54} 53}
@@ -57,8 +56,7 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector,
57 struct drm_display_mode *mode) 56 struct drm_display_mode *mode)
58{ 57{
59 struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector); 58 struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
60 struct sun4i_drv *drv = rgb->drv; 59 struct sun4i_tcon *tcon = rgb->tcon;
61 struct sun4i_tcon *tcon = drv->tcon;
62 u32 hsync = mode->hsync_end - mode->hsync_start; 60 u32 hsync = mode->hsync_end - mode->hsync_start;
63 u32 vsync = mode->vsync_end - mode->vsync_start; 61 u32 vsync = mode->vsync_end - mode->vsync_start;
64 unsigned long rate = mode->clock * 1000; 62 unsigned long rate = mode->clock * 1000;
@@ -115,8 +113,7 @@ static void
115sun4i_rgb_connector_destroy(struct drm_connector *connector) 113sun4i_rgb_connector_destroy(struct drm_connector *connector)
116{ 114{
117 struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector); 115 struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
118 struct sun4i_drv *drv = rgb->drv; 116 struct sun4i_tcon *tcon = rgb->tcon;
119 struct sun4i_tcon *tcon = drv->tcon;
120 117
121 drm_panel_detach(tcon->panel); 118 drm_panel_detach(tcon->panel);
122 drm_connector_cleanup(connector); 119 drm_connector_cleanup(connector);
@@ -141,8 +138,7 @@ static int sun4i_rgb_atomic_check(struct drm_encoder *encoder,
141static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder) 138static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
142{ 139{
143 struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder); 140 struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
144 struct sun4i_drv *drv = rgb->drv; 141 struct sun4i_tcon *tcon = rgb->tcon;
145 struct sun4i_tcon *tcon = drv->tcon;
146 142
147 DRM_DEBUG_DRIVER("Enabling RGB output\n"); 143 DRM_DEBUG_DRIVER("Enabling RGB output\n");
148 144
@@ -158,8 +154,7 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
158static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder) 154static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
159{ 155{
160 struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder); 156 struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
161 struct sun4i_drv *drv = rgb->drv; 157 struct sun4i_tcon *tcon = rgb->tcon;
162 struct sun4i_tcon *tcon = drv->tcon;
163 158
164 DRM_DEBUG_DRIVER("Disabling RGB output\n"); 159 DRM_DEBUG_DRIVER("Disabling RGB output\n");
165 160
@@ -177,8 +172,7 @@ static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
177 struct drm_display_mode *adjusted_mode) 172 struct drm_display_mode *adjusted_mode)
178{ 173{
179 struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder); 174 struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
180 struct sun4i_drv *drv = rgb->drv; 175 struct sun4i_tcon *tcon = rgb->tcon;
181 struct sun4i_tcon *tcon = drv->tcon;
182 176
183 sun4i_tcon0_mode_set(tcon, mode); 177 sun4i_tcon0_mode_set(tcon, mode);
184 178
@@ -204,10 +198,8 @@ static struct drm_encoder_funcs sun4i_rgb_enc_funcs = {
204 .destroy = sun4i_rgb_enc_destroy, 198 .destroy = sun4i_rgb_enc_destroy,
205}; 199};
206 200
207int sun4i_rgb_init(struct drm_device *drm) 201int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon)
208{ 202{
209 struct sun4i_drv *drv = drm->dev_private;
210 struct sun4i_tcon *tcon = drv->tcon;
211 struct drm_encoder *encoder; 203 struct drm_encoder *encoder;
212 struct drm_bridge *bridge; 204 struct drm_bridge *bridge;
213 struct sun4i_rgb *rgb; 205 struct sun4i_rgb *rgb;
@@ -216,7 +208,7 @@ int sun4i_rgb_init(struct drm_device *drm)
216 rgb = devm_kzalloc(drm->dev, sizeof(*rgb), GFP_KERNEL); 208 rgb = devm_kzalloc(drm->dev, sizeof(*rgb), GFP_KERNEL);
217 if (!rgb) 209 if (!rgb)
218 return -ENOMEM; 210 return -ENOMEM;
219 rgb->drv = drv; 211 rgb->tcon = tcon;
220 encoder = &rgb->encoder; 212 encoder = &rgb->encoder;
221 213
222 ret = drm_of_find_panel_or_bridge(tcon->dev->of_node, 1, 0, 214 ret = drm_of_find_panel_or_bridge(tcon->dev->of_node, 1, 0,
@@ -239,7 +231,7 @@ int sun4i_rgb_init(struct drm_device *drm)
239 } 231 }
240 232
241 /* The RGB encoder can only work with the TCON channel 0 */ 233 /* The RGB encoder can only work with the TCON channel 0 */
242 rgb->encoder.possible_crtcs = BIT(0); 234 rgb->encoder.possible_crtcs = BIT(drm_crtc_index(&tcon->crtc->crtc));
243 235
244 if (tcon->panel) { 236 if (tcon->panel) {
245 drm_connector_helper_add(&rgb->connector, 237 drm_connector_helper_add(&rgb->connector,
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.h b/drivers/gpu/drm/sun4i/sun4i_rgb.h
index 7c4da4c8acdd..40c18f4a6c7e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.h
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.h
@@ -13,6 +13,6 @@
13#ifndef _SUN4I_RGB_H_ 13#ifndef _SUN4I_RGB_H_
14#define _SUN4I_RGB_H_ 14#define _SUN4I_RGB_H_
15 15
16int sun4i_rgb_init(struct drm_device *drm); 16int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon);
17 17
18#endif /* _SUN4I_RGB_H_ */ 18#endif /* _SUN4I_RGB_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 2e4e365cecf9..9a83a85529ac 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -142,7 +142,7 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
142 142
143 /* 143 /*
144 * This is called a backporch in the register documentation, 144 * This is called a backporch in the register documentation,
145 * but it really is the front porch + hsync 145 * but it really is the back porch + hsync
146 */ 146 */
147 bp = mode->crtc_htotal - mode->crtc_hsync_start; 147 bp = mode->crtc_htotal - mode->crtc_hsync_start;
148 DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n", 148 DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
@@ -155,7 +155,7 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
155 155
156 /* 156 /*
157 * This is called a backporch in the register documentation, 157 * This is called a backporch in the register documentation,
158 * but it really is the front porch + hsync 158 * but it really is the back porch + hsync
159 */ 159 */
160 bp = mode->crtc_vtotal - mode->crtc_vsync_start; 160 bp = mode->crtc_vtotal - mode->crtc_vsync_start;
161 DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n", 161 DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
@@ -289,8 +289,7 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
289{ 289{
290 struct sun4i_tcon *tcon = private; 290 struct sun4i_tcon *tcon = private;
291 struct drm_device *drm = tcon->drm; 291 struct drm_device *drm = tcon->drm;
292 struct sun4i_drv *drv = drm->dev_private; 292 struct sun4i_crtc *scrtc = tcon->crtc;
293 struct sun4i_crtc *scrtc = drv->crtc;
294 unsigned int status; 293 unsigned int status;
295 294
296 regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status); 295 regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
@@ -335,12 +334,11 @@ static int sun4i_tcon_init_clocks(struct device *dev,
335 } 334 }
336 } 335 }
337 336
338 return sun4i_dclk_create(dev, tcon); 337 return 0;
339} 338}
340 339
341static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon) 340static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
342{ 341{
343 sun4i_dclk_free(tcon);
344 clk_disable_unprepare(tcon->clk); 342 clk_disable_unprepare(tcon->clk);
345} 343}
346 344
@@ -437,30 +435,45 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
437 return ret; 435 return ret;
438 } 436 }
439 437
438 ret = sun4i_tcon_init_clocks(dev, tcon);
439 if (ret) {
440 dev_err(dev, "Couldn't init our TCON clocks\n");
441 goto err_assert_reset;
442 }
443
440 ret = sun4i_tcon_init_regmap(dev, tcon); 444 ret = sun4i_tcon_init_regmap(dev, tcon);
441 if (ret) { 445 if (ret) {
442 dev_err(dev, "Couldn't init our TCON regmap\n"); 446 dev_err(dev, "Couldn't init our TCON regmap\n");
443 goto err_assert_reset; 447 goto err_free_clocks;
444 } 448 }
445 449
446 ret = sun4i_tcon_init_clocks(dev, tcon); 450 ret = sun4i_dclk_create(dev, tcon);
447 if (ret) { 451 if (ret) {
448 dev_err(dev, "Couldn't init our TCON clocks\n"); 452 dev_err(dev, "Couldn't create our TCON dot clock\n");
449 goto err_assert_reset; 453 goto err_free_clocks;
450 } 454 }
451 455
452 ret = sun4i_tcon_init_irq(dev, tcon); 456 ret = sun4i_tcon_init_irq(dev, tcon);
453 if (ret) { 457 if (ret) {
454 dev_err(dev, "Couldn't init our TCON interrupts\n"); 458 dev_err(dev, "Couldn't init our TCON interrupts\n");
459 goto err_free_dotclock;
460 }
461
462 tcon->crtc = sun4i_crtc_init(drm, drv->backend, tcon);
463 if (IS_ERR(tcon->crtc)) {
464 dev_err(dev, "Couldn't create our CRTC\n");
465 ret = PTR_ERR(tcon->crtc);
455 goto err_free_clocks; 466 goto err_free_clocks;
456 } 467 }
457 468
458 ret = sun4i_rgb_init(drm); 469 ret = sun4i_rgb_init(drm, tcon);
459 if (ret < 0) 470 if (ret < 0)
460 goto err_free_clocks; 471 goto err_free_clocks;
461 472
462 return 0; 473 return 0;
463 474
475err_free_dotclock:
476 sun4i_dclk_free(tcon);
464err_free_clocks: 477err_free_clocks:
465 sun4i_tcon_free_clocks(tcon); 478 sun4i_tcon_free_clocks(tcon);
466err_assert_reset: 479err_assert_reset:
@@ -473,6 +486,7 @@ static void sun4i_tcon_unbind(struct device *dev, struct device *master,
473{ 486{
474 struct sun4i_tcon *tcon = dev_get_drvdata(dev); 487 struct sun4i_tcon *tcon = dev_get_drvdata(dev);
475 488
489 sun4i_dclk_free(tcon);
476 sun4i_tcon_free_clocks(tcon); 490 sun4i_tcon_free_clocks(tcon);
477} 491}
478 492
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index 166064bafe2e..f636343a935d 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -169,6 +169,9 @@ struct sun4i_tcon {
169 169
170 /* Platform adjustments */ 170 /* Platform adjustments */
171 const struct sun4i_tcon_quirks *quirks; 171 const struct sun4i_tcon_quirks *quirks;
172
173 /* Associated crtc */
174 struct sun4i_crtc *crtc;
172}; 175};
173 176
174struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node); 177struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index c6f47222e8fc..49c49431a053 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -19,9 +19,11 @@
19#include <drm/drmP.h> 19#include <drm/drmP.h>
20#include <drm/drm_atomic_helper.h> 20#include <drm/drm_atomic_helper.h>
21#include <drm/drm_crtc_helper.h> 21#include <drm/drm_crtc_helper.h>
22#include <drm/drm_of.h>
22#include <drm/drm_panel.h> 23#include <drm/drm_panel.h>
23 24
24#include "sun4i_backend.h" 25#include "sun4i_backend.h"
26#include "sun4i_crtc.h"
25#include "sun4i_drv.h" 27#include "sun4i_drv.h"
26#include "sun4i_tcon.h" 28#include "sun4i_tcon.h"
27 29
@@ -349,8 +351,9 @@ static int sun4i_tv_atomic_check(struct drm_encoder *encoder,
349static void sun4i_tv_disable(struct drm_encoder *encoder) 351static void sun4i_tv_disable(struct drm_encoder *encoder)
350{ 352{
351 struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder); 353 struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
352 struct sun4i_drv *drv = tv->drv; 354 struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
353 struct sun4i_tcon *tcon = drv->tcon; 355 struct sun4i_tcon *tcon = crtc->tcon;
356 struct sun4i_backend *backend = crtc->backend;
354 357
355 DRM_DEBUG_DRIVER("Disabling the TV Output\n"); 358 DRM_DEBUG_DRIVER("Disabling the TV Output\n");
356 359
@@ -359,18 +362,19 @@ static void sun4i_tv_disable(struct drm_encoder *encoder)
359 regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG, 362 regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
360 SUN4I_TVE_EN_ENABLE, 363 SUN4I_TVE_EN_ENABLE,
361 0); 364 0);
362 sun4i_backend_disable_color_correction(drv->backend); 365 sun4i_backend_disable_color_correction(backend);
363} 366}
364 367
365static void sun4i_tv_enable(struct drm_encoder *encoder) 368static void sun4i_tv_enable(struct drm_encoder *encoder)
366{ 369{
367 struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder); 370 struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
368 struct sun4i_drv *drv = tv->drv; 371 struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
369 struct sun4i_tcon *tcon = drv->tcon; 372 struct sun4i_tcon *tcon = crtc->tcon;
373 struct sun4i_backend *backend = crtc->backend;
370 374
371 DRM_DEBUG_DRIVER("Enabling the TV Output\n"); 375 DRM_DEBUG_DRIVER("Enabling the TV Output\n");
372 376
373 sun4i_backend_apply_color_correction(drv->backend); 377 sun4i_backend_apply_color_correction(backend);
374 378
375 regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG, 379 regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
376 SUN4I_TVE_EN_ENABLE, 380 SUN4I_TVE_EN_ENABLE,
@@ -384,8 +388,8 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder,
384 struct drm_display_mode *adjusted_mode) 388 struct drm_display_mode *adjusted_mode)
385{ 389{
386 struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder); 390 struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
387 struct sun4i_drv *drv = tv->drv; 391 struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
388 struct sun4i_tcon *tcon = drv->tcon; 392 struct sun4i_tcon *tcon = crtc->tcon;
389 const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode); 393 const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
390 394
391 sun4i_tcon1_mode_set(tcon, mode); 395 sun4i_tcon1_mode_set(tcon, mode);
@@ -623,7 +627,12 @@ static int sun4i_tv_bind(struct device *dev, struct device *master,
623 goto err_disable_clk; 627 goto err_disable_clk;
624 } 628 }
625 629
626 tv->encoder.possible_crtcs = BIT(0); 630 tv->encoder.possible_crtcs = drm_of_find_possible_crtcs(drm,
631 dev->of_node);
632 if (!tv->encoder.possible_crtcs) {
633 ret = -EPROBE_DEFER;
634 goto err_disable_clk;
635 }
627 636
628 drm_connector_helper_add(&tv->connector, 637 drm_connector_helper_add(&tv->connector,
629 &sun4i_tv_comp_connector_helper_funcs); 638 &sun4i_tv_comp_connector_helper_funcs);