Commit | Line | Data |
---|---|---|
9026e0d1 MR |
1 | /* |
2 | * Copyright (C) 2015 Free Electrons | |
3 | * Copyright (C) 2015 NextThing Co | |
4 | * | |
5 | * Maxime Ripard <maxime.ripard@free-electrons.com> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License as | |
9 | * published by the Free Software Foundation; either version 2 of | |
10 | * the License, or (at your option) any later version. | |
11 | */ | |
12 | ||
13 | #include <drm/drmP.h> | |
14 | #include <drm/drm_atomic_helper.h> | |
15 | #include <drm/drm_crtc.h> | |
16 | #include <drm/drm_crtc_helper.h> | |
17 | #include <drm/drm_modes.h> | |
18 | ||
19 | #include <linux/clk-provider.h> | |
20 | #include <linux/ioport.h> | |
21 | #include <linux/of_address.h> | |
75448607 | 22 | #include <linux/of_graph.h> |
9026e0d1 MR |
23 | #include <linux/of_irq.h> |
24 | #include <linux/regmap.h> | |
25 | ||
26 | #include <video/videomode.h> | |
27 | ||
28 | #include "sun4i_backend.h" | |
29 | #include "sun4i_crtc.h" | |
30 | #include "sun4i_drv.h" | |
b3f266e4 | 31 | #include "sun4i_layer.h" |
9026e0d1 MR |
32 | #include "sun4i_tcon.h" |
33 | ||
34 | static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc, | |
35 | struct drm_crtc_state *old_state) | |
36 | { | |
37 | struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | |
38 | struct drm_device *dev = crtc->dev; | |
39 | unsigned long flags; | |
40 | ||
41 | if (crtc->state->event) { | |
42 | WARN_ON(drm_crtc_vblank_get(crtc) != 0); | |
43 | ||
44 | spin_lock_irqsave(&dev->event_lock, flags); | |
45 | scrtc->event = crtc->state->event; | |
46 | spin_unlock_irqrestore(&dev->event_lock, flags); | |
47 | crtc->state->event = NULL; | |
48 | } | |
49 | } | |
50 | ||
51 | static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, | |
52 | struct drm_crtc_state *old_state) | |
53 | { | |
54 | struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | |
a33e93db | 55 | struct drm_pending_vblank_event *event = crtc->state->event; |
9026e0d1 MR |
56 | |
57 | DRM_DEBUG_DRIVER("Committing plane changes\n"); | |
58 | ||
3c64fb37 | 59 | sun4i_backend_commit(scrtc->backend); |
a33e93db DV |
60 | |
61 | if (event) { | |
62 | crtc->state->event = NULL; | |
63 | ||
64 | spin_lock_irq(&crtc->dev->event_lock); | |
65 | if (drm_crtc_vblank_get(crtc) == 0) | |
66 | drm_crtc_arm_vblank_event(crtc, event); | |
67 | else | |
68 | drm_crtc_send_vblank_event(crtc, event); | |
69 | spin_unlock_irq(&crtc->dev->event_lock); | |
70 | } | |
9026e0d1 MR |
71 | } |
72 | ||
73 | static void sun4i_crtc_disable(struct drm_crtc *crtc) | |
74 | { | |
75 | struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | |
9026e0d1 MR |
76 | |
77 | DRM_DEBUG_DRIVER("Disabling the CRTC\n"); | |
78 | ||
3c64fb37 | 79 | sun4i_tcon_disable(scrtc->tcon); |
2cd36830 MR |
80 | |
81 | if (crtc->state->event && !crtc->state->active) { | |
82 | spin_lock_irq(&crtc->dev->event_lock); | |
83 | drm_crtc_send_vblank_event(crtc, crtc->state->event); | |
84 | spin_unlock_irq(&crtc->dev->event_lock); | |
85 | ||
86 | crtc->state->event = NULL; | |
87 | } | |
9026e0d1 MR |
88 | } |
89 | ||
90 | static void sun4i_crtc_enable(struct drm_crtc *crtc) | |
91 | { | |
92 | struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | |
9026e0d1 MR |
93 | |
94 | DRM_DEBUG_DRIVER("Enabling the CRTC\n"); | |
95 | ||
3c64fb37 | 96 | sun4i_tcon_enable(scrtc->tcon); |
9026e0d1 MR |
97 | } |
98 | ||
99 | static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = { | |
100 | .atomic_begin = sun4i_crtc_atomic_begin, | |
101 | .atomic_flush = sun4i_crtc_atomic_flush, | |
102 | .disable = sun4i_crtc_disable, | |
103 | .enable = sun4i_crtc_enable, | |
104 | }; | |
105 | ||
50480a78 SG |
106 | static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc) |
107 | { | |
108 | struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | |
50480a78 SG |
109 | |
110 | DRM_DEBUG_DRIVER("Enabling VBLANK on crtc %p\n", crtc); | |
111 | ||
3c64fb37 | 112 | sun4i_tcon_enable_vblank(scrtc->tcon, true); |
50480a78 SG |
113 | |
114 | return 0; | |
115 | } | |
116 | ||
117 | static void sun4i_crtc_disable_vblank(struct drm_crtc *crtc) | |
118 | { | |
119 | struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | |
50480a78 SG |
120 | |
121 | DRM_DEBUG_DRIVER("Disabling VBLANK on crtc %p\n", crtc); | |
122 | ||
3c64fb37 | 123 | sun4i_tcon_enable_vblank(scrtc->tcon, false); |
50480a78 SG |
124 | } |
125 | ||
9026e0d1 MR |
126 | static const struct drm_crtc_funcs sun4i_crtc_funcs = { |
127 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | |
128 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | |
129 | .destroy = drm_crtc_cleanup, | |
130 | .page_flip = drm_atomic_helper_page_flip, | |
131 | .reset = drm_atomic_helper_crtc_reset, | |
132 | .set_config = drm_atomic_helper_set_config, | |
50480a78 SG |
133 | .enable_vblank = sun4i_crtc_enable_vblank, |
134 | .disable_vblank = sun4i_crtc_disable_vblank, | |
9026e0d1 MR |
135 | }; |
136 | ||
137 | struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm) | |
138 | { | |
139 | struct sun4i_drv *drv = drm->dev_private; | |
140 | struct sun4i_crtc *scrtc; | |
dcd21580 CYT |
141 | struct drm_plane *primary = NULL, *cursor = NULL; |
142 | int ret, i; | |
9026e0d1 MR |
143 | |
144 | scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL); | |
145 | if (!scrtc) | |
ea411fd2 | 146 | return ERR_PTR(-ENOMEM); |
3c64fb37 CYT |
147 | scrtc->backend = drv->backend; |
148 | scrtc->tcon = drv->tcon; | |
9026e0d1 | 149 | |
b3f266e4 CYT |
150 | /* Create our layers */ |
151 | scrtc->layers = sun4i_layers_init(drm); | |
152 | if (IS_ERR(scrtc->layers)) { | |
153 | dev_err(drm->dev, "Couldn't create the planes\n"); | |
dcd21580 CYT |
154 | return NULL; |
155 | } | |
156 | ||
157 | /* find primary and cursor planes for drm_crtc_init_with_planes */ | |
158 | for (i = 0; scrtc->layers[i]; i++) { | |
159 | struct sun4i_layer *layer = scrtc->layers[i]; | |
160 | ||
161 | switch (layer->plane.type) { | |
162 | case DRM_PLANE_TYPE_PRIMARY: | |
163 | primary = &layer->plane; | |
164 | break; | |
165 | case DRM_PLANE_TYPE_CURSOR: | |
166 | cursor = &layer->plane; | |
167 | break; | |
168 | default: | |
169 | break; | |
170 | } | |
b3f266e4 CYT |
171 | } |
172 | ||
9026e0d1 | 173 | ret = drm_crtc_init_with_planes(drm, &scrtc->crtc, |
dcd21580 CYT |
174 | primary, |
175 | cursor, | |
9026e0d1 MR |
176 | &sun4i_crtc_funcs, |
177 | NULL); | |
178 | if (ret) { | |
179 | dev_err(drm->dev, "Couldn't init DRM CRTC\n"); | |
ea411fd2 | 180 | return ERR_PTR(ret); |
9026e0d1 MR |
181 | } |
182 | ||
183 | drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs); | |
184 | ||
75448607 | 185 | /* Set crtc.port to output port node of the tcon */ |
e4cdcb7c | 186 | scrtc->crtc.port = of_graph_get_port_by_id(scrtc->tcon->dev->of_node, |
75448607 CYT |
187 | 1); |
188 | ||
a5154a4d CYT |
189 | /* Set possible_crtcs to this crtc for overlay planes */ |
190 | for (i = 0; scrtc->layers[i]; i++) { | |
191 | uint32_t possible_crtcs = BIT(drm_crtc_index(&scrtc->crtc)); | |
192 | struct sun4i_layer *layer = scrtc->layers[i]; | |
193 | ||
194 | if (layer->plane.type == DRM_PLANE_TYPE_OVERLAY) | |
195 | layer->plane.possible_crtcs = possible_crtcs; | |
196 | } | |
197 | ||
9026e0d1 MR |
198 | return scrtc; |
199 | } |