diff options
Diffstat (limited to 'drivers')
20 files changed, 896 insertions, 243 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c index 961a1806a246..37e6ec704e1d 100644 --- a/drivers/gpu/drm/exynos/exynos_ddc.c +++ b/drivers/gpu/drm/exynos/exynos_ddc.c | |||
@@ -26,29 +26,41 @@ static int s5p_ddc_probe(struct i2c_client *client, | |||
26 | { | 26 | { |
27 | hdmi_attach_ddc_client(client); | 27 | hdmi_attach_ddc_client(client); |
28 | 28 | ||
29 | dev_info(&client->adapter->dev, "attached s5p_ddc " | 29 | dev_info(&client->adapter->dev, |
30 | "into i2c adapter successfully\n"); | 30 | "attached %s into i2c adapter successfully\n", |
31 | client->name); | ||
31 | 32 | ||
32 | return 0; | 33 | return 0; |
33 | } | 34 | } |
34 | 35 | ||
35 | static int s5p_ddc_remove(struct i2c_client *client) | 36 | static int s5p_ddc_remove(struct i2c_client *client) |
36 | { | 37 | { |
37 | dev_info(&client->adapter->dev, "detached s5p_ddc " | 38 | dev_info(&client->adapter->dev, |
38 | "from i2c adapter successfully\n"); | 39 | "detached %s from i2c adapter successfully\n", |
40 | client->name); | ||
39 | 41 | ||
40 | return 0; | 42 | return 0; |
41 | } | 43 | } |
42 | 44 | ||
43 | static struct i2c_device_id ddc_idtable[] = { | 45 | static struct i2c_device_id ddc_idtable[] = { |
44 | {"s5p_ddc", 0}, | 46 | {"s5p_ddc", 0}, |
47 | {"exynos5-hdmiddc", 0}, | ||
45 | { }, | 48 | { }, |
46 | }; | 49 | }; |
47 | 50 | ||
51 | static struct of_device_id hdmiddc_match_types[] = { | ||
52 | { | ||
53 | .compatible = "samsung,exynos5-hdmiddc", | ||
54 | }, { | ||
55 | /* end node */ | ||
56 | } | ||
57 | }; | ||
58 | |||
48 | struct i2c_driver ddc_driver = { | 59 | struct i2c_driver ddc_driver = { |
49 | .driver = { | 60 | .driver = { |
50 | .name = "s5p_ddc", | 61 | .name = "exynos-hdmiddc", |
51 | .owner = THIS_MODULE, | 62 | .owner = THIS_MODULE, |
63 | .of_match_table = hdmiddc_match_types, | ||
52 | }, | 64 | }, |
53 | .id_table = ddc_idtable, | 65 | .id_table = ddc_idtable, |
54 | .probe = s5p_ddc_probe, | 66 | .probe = s5p_ddc_probe, |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c index c2b1b1441ed0..18c271862ca8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c | |||
@@ -40,6 +40,7 @@ struct exynos_drm_connector { | |||
40 | struct drm_connector drm_connector; | 40 | struct drm_connector drm_connector; |
41 | uint32_t encoder_id; | 41 | uint32_t encoder_id; |
42 | struct exynos_drm_manager *manager; | 42 | struct exynos_drm_manager *manager; |
43 | uint32_t dpms; | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | /* convert exynos_video_timings to drm_display_mode */ | 46 | /* convert exynos_video_timings to drm_display_mode */ |
@@ -149,8 +150,12 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) | |||
149 | count = drm_add_edid_modes(connector, edid); | 150 | count = drm_add_edid_modes(connector, edid); |
150 | kfree(edid); | 151 | kfree(edid); |
151 | } else { | 152 | } else { |
152 | struct drm_display_mode *mode = drm_mode_create(connector->dev); | ||
153 | struct exynos_drm_panel_info *panel; | 153 | struct exynos_drm_panel_info *panel; |
154 | struct drm_display_mode *mode = drm_mode_create(connector->dev); | ||
155 | if (!mode) { | ||
156 | DRM_ERROR("failed to create a new display mode.\n"); | ||
157 | return 0; | ||
158 | } | ||
154 | 159 | ||
155 | if (display_ops->get_panel) | 160 | if (display_ops->get_panel) |
156 | panel = display_ops->get_panel(manager->dev); | 161 | panel = display_ops->get_panel(manager->dev); |
@@ -194,8 +199,7 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector, | |||
194 | return ret; | 199 | return ret; |
195 | } | 200 | } |
196 | 201 | ||
197 | static struct drm_encoder *exynos_drm_best_encoder( | 202 | struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector) |
198 | struct drm_connector *connector) | ||
199 | { | 203 | { |
200 | struct drm_device *dev = connector->dev; | 204 | struct drm_device *dev = connector->dev; |
201 | struct exynos_drm_connector *exynos_connector = | 205 | struct exynos_drm_connector *exynos_connector = |
@@ -224,6 +228,43 @@ static struct drm_connector_helper_funcs exynos_connector_helper_funcs = { | |||
224 | .best_encoder = exynos_drm_best_encoder, | 228 | .best_encoder = exynos_drm_best_encoder, |
225 | }; | 229 | }; |
226 | 230 | ||
231 | void exynos_drm_display_power(struct drm_connector *connector, int mode) | ||
232 | { | ||
233 | struct drm_encoder *encoder = exynos_drm_best_encoder(connector); | ||
234 | struct exynos_drm_connector *exynos_connector; | ||
235 | struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); | ||
236 | struct exynos_drm_display_ops *display_ops = manager->display_ops; | ||
237 | |||
238 | exynos_connector = to_exynos_connector(connector); | ||
239 | |||
240 | if (exynos_connector->dpms == mode) { | ||
241 | DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); | ||
242 | return; | ||
243 | } | ||
244 | |||
245 | if (display_ops && display_ops->power_on) | ||
246 | display_ops->power_on(manager->dev, mode); | ||
247 | |||
248 | exynos_connector->dpms = mode; | ||
249 | } | ||
250 | |||
251 | static void exynos_drm_connector_dpms(struct drm_connector *connector, | ||
252 | int mode) | ||
253 | { | ||
254 | DRM_DEBUG_KMS("%s\n", __FILE__); | ||
255 | |||
256 | /* | ||
257 | * in case that drm_crtc_helper_set_mode() is called, | ||
258 | * encoder/crtc->funcs->dpms() will be just returned | ||
259 | * because they already were DRM_MODE_DPMS_ON so only | ||
260 | * exynos_drm_display_power() will be called. | ||
261 | */ | ||
262 | drm_helper_connector_dpms(connector, mode); | ||
263 | |||
264 | exynos_drm_display_power(connector, mode); | ||
265 | |||
266 | } | ||
267 | |||
227 | static int exynos_drm_connector_fill_modes(struct drm_connector *connector, | 268 | static int exynos_drm_connector_fill_modes(struct drm_connector *connector, |
228 | unsigned int max_width, unsigned int max_height) | 269 | unsigned int max_width, unsigned int max_height) |
229 | { | 270 | { |
@@ -283,7 +324,7 @@ static void exynos_drm_connector_destroy(struct drm_connector *connector) | |||
283 | } | 324 | } |
284 | 325 | ||
285 | static struct drm_connector_funcs exynos_connector_funcs = { | 326 | static struct drm_connector_funcs exynos_connector_funcs = { |
286 | .dpms = drm_helper_connector_dpms, | 327 | .dpms = exynos_drm_connector_dpms, |
287 | .fill_modes = exynos_drm_connector_fill_modes, | 328 | .fill_modes = exynos_drm_connector_fill_modes, |
288 | .detect = exynos_drm_connector_detect, | 329 | .detect = exynos_drm_connector_detect, |
289 | .destroy = exynos_drm_connector_destroy, | 330 | .destroy = exynos_drm_connector_destroy, |
@@ -332,6 +373,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev, | |||
332 | 373 | ||
333 | exynos_connector->encoder_id = encoder->base.id; | 374 | exynos_connector->encoder_id = encoder->base.id; |
334 | exynos_connector->manager = manager; | 375 | exynos_connector->manager = manager; |
376 | exynos_connector->dpms = DRM_MODE_DPMS_OFF; | ||
335 | connector->encoder = encoder; | 377 | connector->encoder = encoder; |
336 | 378 | ||
337 | err = drm_mode_connector_attach_encoder(connector, encoder); | 379 | err = drm_mode_connector_attach_encoder(connector, encoder); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.h b/drivers/gpu/drm/exynos/exynos_drm_connector.h index 1c7b2b5b579c..22f6cc442c3d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.h +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.h | |||
@@ -31,4 +31,8 @@ | |||
31 | struct drm_connector *exynos_drm_connector_create(struct drm_device *dev, | 31 | struct drm_connector *exynos_drm_connector_create(struct drm_device *dev, |
32 | struct drm_encoder *encoder); | 32 | struct drm_encoder *encoder); |
33 | 33 | ||
34 | struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector); | ||
35 | |||
36 | void exynos_drm_display_power(struct drm_connector *connector, int mode); | ||
37 | |||
34 | #endif | 38 | #endif |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 19bdf0a194eb..94026ad76a77 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c | |||
@@ -34,33 +34,15 @@ | |||
34 | 34 | ||
35 | static LIST_HEAD(exynos_drm_subdrv_list); | 35 | static LIST_HEAD(exynos_drm_subdrv_list); |
36 | 36 | ||
37 | static int exynos_drm_subdrv_probe(struct drm_device *dev, | 37 | static int exynos_drm_create_enc_conn(struct drm_device *dev, |
38 | struct exynos_drm_subdrv *subdrv) | 38 | struct exynos_drm_subdrv *subdrv) |
39 | { | 39 | { |
40 | struct drm_encoder *encoder; | 40 | struct drm_encoder *encoder; |
41 | struct drm_connector *connector; | 41 | struct drm_connector *connector; |
42 | int ret; | ||
42 | 43 | ||
43 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 44 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
44 | 45 | ||
45 | if (subdrv->probe) { | ||
46 | int ret; | ||
47 | |||
48 | /* | ||
49 | * this probe callback would be called by sub driver | ||
50 | * after setting of all resources to this sub driver, | ||
51 | * such as clock, irq and register map are done or by load() | ||
52 | * of exynos drm driver. | ||
53 | * | ||
54 | * P.S. note that this driver is considered for modularization. | ||
55 | */ | ||
56 | ret = subdrv->probe(dev, subdrv->dev); | ||
57 | if (ret) | ||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | if (!subdrv->manager) | ||
62 | return 0; | ||
63 | |||
64 | subdrv->manager->dev = subdrv->dev; | 46 | subdrv->manager->dev = subdrv->dev; |
65 | 47 | ||
66 | /* create and initialize a encoder for this sub driver. */ | 48 | /* create and initialize a encoder for this sub driver. */ |
@@ -78,24 +60,22 @@ static int exynos_drm_subdrv_probe(struct drm_device *dev, | |||
78 | connector = exynos_drm_connector_create(dev, encoder); | 60 | connector = exynos_drm_connector_create(dev, encoder); |
79 | if (!connector) { | 61 | if (!connector) { |
80 | DRM_ERROR("failed to create connector\n"); | 62 | DRM_ERROR("failed to create connector\n"); |
81 | encoder->funcs->destroy(encoder); | 63 | ret = -EFAULT; |
82 | return -EFAULT; | 64 | goto err_destroy_encoder; |
83 | } | 65 | } |
84 | 66 | ||
85 | subdrv->encoder = encoder; | 67 | subdrv->encoder = encoder; |
86 | subdrv->connector = connector; | 68 | subdrv->connector = connector; |
87 | 69 | ||
88 | return 0; | 70 | return 0; |
71 | |||
72 | err_destroy_encoder: | ||
73 | encoder->funcs->destroy(encoder); | ||
74 | return ret; | ||
89 | } | 75 | } |
90 | 76 | ||
91 | static void exynos_drm_subdrv_remove(struct drm_device *dev, | 77 | static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv) |
92 | struct exynos_drm_subdrv *subdrv) | ||
93 | { | 78 | { |
94 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | ||
95 | |||
96 | if (subdrv->remove) | ||
97 | subdrv->remove(dev); | ||
98 | |||
99 | if (subdrv->encoder) { | 79 | if (subdrv->encoder) { |
100 | struct drm_encoder *encoder = subdrv->encoder; | 80 | struct drm_encoder *encoder = subdrv->encoder; |
101 | encoder->funcs->destroy(encoder); | 81 | encoder->funcs->destroy(encoder); |
@@ -109,9 +89,43 @@ static void exynos_drm_subdrv_remove(struct drm_device *dev, | |||
109 | } | 89 | } |
110 | } | 90 | } |
111 | 91 | ||
92 | static int exynos_drm_subdrv_probe(struct drm_device *dev, | ||
93 | struct exynos_drm_subdrv *subdrv) | ||
94 | { | ||
95 | if (subdrv->probe) { | ||
96 | int ret; | ||
97 | |||
98 | subdrv->drm_dev = dev; | ||
99 | |||
100 | /* | ||
101 | * this probe callback would be called by sub driver | ||
102 | * after setting of all resources to this sub driver, | ||
103 | * such as clock, irq and register map are done or by load() | ||
104 | * of exynos drm driver. | ||
105 | * | ||
106 | * P.S. note that this driver is considered for modularization. | ||
107 | */ | ||
108 | ret = subdrv->probe(dev, subdrv->dev); | ||
109 | if (ret) | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static void exynos_drm_subdrv_remove(struct drm_device *dev, | ||
117 | struct exynos_drm_subdrv *subdrv) | ||
118 | { | ||
119 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | ||
120 | |||
121 | if (subdrv->remove) | ||
122 | subdrv->remove(dev, subdrv->dev); | ||
123 | } | ||
124 | |||
112 | int exynos_drm_device_register(struct drm_device *dev) | 125 | int exynos_drm_device_register(struct drm_device *dev) |
113 | { | 126 | { |
114 | struct exynos_drm_subdrv *subdrv, *n; | 127 | struct exynos_drm_subdrv *subdrv, *n; |
128 | unsigned int fine_cnt = 0; | ||
115 | int err; | 129 | int err; |
116 | 130 | ||
117 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 131 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
@@ -120,14 +134,36 @@ int exynos_drm_device_register(struct drm_device *dev) | |||
120 | return -EINVAL; | 134 | return -EINVAL; |
121 | 135 | ||
122 | list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { | 136 | list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { |
123 | subdrv->drm_dev = dev; | ||
124 | err = exynos_drm_subdrv_probe(dev, subdrv); | 137 | err = exynos_drm_subdrv_probe(dev, subdrv); |
125 | if (err) { | 138 | if (err) { |
126 | DRM_DEBUG("exynos drm subdrv probe failed.\n"); | 139 | DRM_DEBUG("exynos drm subdrv probe failed.\n"); |
127 | list_del(&subdrv->list); | 140 | list_del(&subdrv->list); |
141 | continue; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * if manager is null then it means that this sub driver | ||
146 | * doesn't need encoder and connector. | ||
147 | */ | ||
148 | if (!subdrv->manager) { | ||
149 | fine_cnt++; | ||
150 | continue; | ||
151 | } | ||
152 | |||
153 | err = exynos_drm_create_enc_conn(dev, subdrv); | ||
154 | if (err) { | ||
155 | DRM_DEBUG("failed to create encoder and connector.\n"); | ||
156 | exynos_drm_subdrv_remove(dev, subdrv); | ||
157 | list_del(&subdrv->list); | ||
158 | continue; | ||
128 | } | 159 | } |
160 | |||
161 | fine_cnt++; | ||
129 | } | 162 | } |
130 | 163 | ||
164 | if (!fine_cnt) | ||
165 | return -EINVAL; | ||
166 | |||
131 | return 0; | 167 | return 0; |
132 | } | 168 | } |
133 | EXPORT_SYMBOL_GPL(exynos_drm_device_register); | 169 | EXPORT_SYMBOL_GPL(exynos_drm_device_register); |
@@ -143,8 +179,10 @@ int exynos_drm_device_unregister(struct drm_device *dev) | |||
143 | return -EINVAL; | 179 | return -EINVAL; |
144 | } | 180 | } |
145 | 181 | ||
146 | list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) | 182 | list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { |
147 | exynos_drm_subdrv_remove(dev, subdrv); | 183 | exynos_drm_subdrv_remove(dev, subdrv); |
184 | exynos_drm_destroy_enc_conn(subdrv); | ||
185 | } | ||
148 | 186 | ||
149 | return 0; | 187 | return 0; |
150 | } | 188 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index df1e34f0f091..fce245f64c4f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c | |||
@@ -66,7 +66,6 @@ struct exynos_drm_crtc { | |||
66 | 66 | ||
67 | static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) | 67 | static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) |
68 | { | 68 | { |
69 | struct drm_device *dev = crtc->dev; | ||
70 | struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | 69 | struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); |
71 | 70 | ||
72 | DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); | 71 | DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); |
@@ -76,12 +75,8 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
76 | return; | 75 | return; |
77 | } | 76 | } |
78 | 77 | ||
79 | mutex_lock(&dev->struct_mutex); | ||
80 | |||
81 | exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms); | 78 | exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms); |
82 | exynos_crtc->dpms = mode; | 79 | exynos_crtc->dpms = mode; |
83 | |||
84 | mutex_unlock(&dev->struct_mutex); | ||
85 | } | 80 | } |
86 | 81 | ||
87 | static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) | 82 | static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) |
@@ -97,6 +92,7 @@ static void exynos_drm_crtc_commit(struct drm_crtc *crtc) | |||
97 | 92 | ||
98 | DRM_DEBUG_KMS("%s\n", __FILE__); | 93 | DRM_DEBUG_KMS("%s\n", __FILE__); |
99 | 94 | ||
95 | exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); | ||
100 | exynos_plane_commit(exynos_crtc->plane); | 96 | exynos_plane_commit(exynos_crtc->plane); |
101 | exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON); | 97 | exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON); |
102 | } | 98 | } |
@@ -126,8 +122,6 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, | |||
126 | 122 | ||
127 | DRM_DEBUG_KMS("%s\n", __FILE__); | 123 | DRM_DEBUG_KMS("%s\n", __FILE__); |
128 | 124 | ||
129 | exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); | ||
130 | |||
131 | /* | 125 | /* |
132 | * copy the mode data adjusted by mode_fixup() into crtc->mode | 126 | * copy the mode data adjusted by mode_fixup() into crtc->mode |
133 | * so that hardware can be seet to proper mode. | 127 | * so that hardware can be seet to proper mode. |
@@ -161,6 +155,12 @@ static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | |||
161 | 155 | ||
162 | DRM_DEBUG_KMS("%s\n", __FILE__); | 156 | DRM_DEBUG_KMS("%s\n", __FILE__); |
163 | 157 | ||
158 | /* when framebuffer changing is requested, crtc's dpms should be on */ | ||
159 | if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { | ||
160 | DRM_ERROR("failed framebuffer changing request.\n"); | ||
161 | return -EPERM; | ||
162 | } | ||
163 | |||
164 | crtc_w = crtc->fb->width - x; | 164 | crtc_w = crtc->fb->width - x; |
165 | crtc_h = crtc->fb->height - y; | 165 | crtc_h = crtc->fb->height - y; |
166 | 166 | ||
@@ -213,6 +213,12 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, | |||
213 | 213 | ||
214 | DRM_DEBUG_KMS("%s\n", __FILE__); | 214 | DRM_DEBUG_KMS("%s\n", __FILE__); |
215 | 215 | ||
216 | /* when the page flip is requested, crtc's dpms should be on */ | ||
217 | if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { | ||
218 | DRM_ERROR("failed page flip request.\n"); | ||
219 | return -EINVAL; | ||
220 | } | ||
221 | |||
216 | mutex_lock(&dev->struct_mutex); | 222 | mutex_lock(&dev->struct_mutex); |
217 | 223 | ||
218 | if (event) { | 224 | if (event) { |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index a4ab98b52dd8..a34231036496 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h | |||
@@ -36,6 +36,20 @@ | |||
36 | #define MAX_FB_BUFFER 4 | 36 | #define MAX_FB_BUFFER 4 |
37 | #define DEFAULT_ZPOS -1 | 37 | #define DEFAULT_ZPOS -1 |
38 | 38 | ||
39 | #define _wait_for(COND, MS) ({ \ | ||
40 | unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ | ||
41 | int ret__ = 0; \ | ||
42 | while (!(COND)) { \ | ||
43 | if (time_after(jiffies, timeout__)) { \ | ||
44 | ret__ = -ETIMEDOUT; \ | ||
45 | break; \ | ||
46 | } \ | ||
47 | } \ | ||
48 | ret__; \ | ||
49 | }) | ||
50 | |||
51 | #define wait_for(COND, MS) _wait_for(COND, MS) | ||
52 | |||
39 | struct drm_device; | 53 | struct drm_device; |
40 | struct exynos_drm_overlay; | 54 | struct exynos_drm_overlay; |
41 | struct drm_connector; | 55 | struct drm_connector; |
@@ -60,6 +74,8 @@ enum exynos_drm_output_type { | |||
60 | * @commit: apply hardware specific overlay data to registers. | 74 | * @commit: apply hardware specific overlay data to registers. |
61 | * @enable: enable hardware specific overlay. | 75 | * @enable: enable hardware specific overlay. |
62 | * @disable: disable hardware specific overlay. | 76 | * @disable: disable hardware specific overlay. |
77 | * @wait_for_vblank: wait for vblank interrupt to make sure that | ||
78 | * hardware overlay is disabled. | ||
63 | */ | 79 | */ |
64 | struct exynos_drm_overlay_ops { | 80 | struct exynos_drm_overlay_ops { |
65 | void (*mode_set)(struct device *subdrv_dev, | 81 | void (*mode_set)(struct device *subdrv_dev, |
@@ -67,6 +83,7 @@ struct exynos_drm_overlay_ops { | |||
67 | void (*commit)(struct device *subdrv_dev, int zpos); | 83 | void (*commit)(struct device *subdrv_dev, int zpos); |
68 | void (*enable)(struct device *subdrv_dev, int zpos); | 84 | void (*enable)(struct device *subdrv_dev, int zpos); |
69 | void (*disable)(struct device *subdrv_dev, int zpos); | 85 | void (*disable)(struct device *subdrv_dev, int zpos); |
86 | void (*wait_for_vblank)(struct device *subdrv_dev); | ||
70 | }; | 87 | }; |
71 | 88 | ||
72 | /* | 89 | /* |
@@ -265,7 +282,7 @@ struct exynos_drm_subdrv { | |||
265 | struct exynos_drm_manager *manager; | 282 | struct exynos_drm_manager *manager; |
266 | 283 | ||
267 | int (*probe)(struct drm_device *drm_dev, struct device *dev); | 284 | int (*probe)(struct drm_device *drm_dev, struct device *dev); |
268 | void (*remove)(struct drm_device *dev); | 285 | void (*remove)(struct drm_device *drm_dev, struct device *dev); |
269 | int (*open)(struct drm_device *drm_dev, struct device *dev, | 286 | int (*open)(struct drm_device *drm_dev, struct device *dev, |
270 | struct drm_file *file); | 287 | struct drm_file *file); |
271 | void (*close)(struct drm_device *drm_dev, struct device *dev, | 288 | void (*close)(struct drm_device *drm_dev, struct device *dev, |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 39bd8abff3f1..e51503fbaf2b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c | |||
@@ -31,6 +31,7 @@ | |||
31 | 31 | ||
32 | #include "exynos_drm_drv.h" | 32 | #include "exynos_drm_drv.h" |
33 | #include "exynos_drm_encoder.h" | 33 | #include "exynos_drm_encoder.h" |
34 | #include "exynos_drm_connector.h" | ||
34 | 35 | ||
35 | #define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\ | 36 | #define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\ |
36 | drm_encoder) | 37 | drm_encoder) |
@@ -44,26 +45,23 @@ | |||
44 | * @dpms: store the encoder dpms value. | 45 | * @dpms: store the encoder dpms value. |
45 | */ | 46 | */ |
46 | struct exynos_drm_encoder { | 47 | struct exynos_drm_encoder { |
48 | struct drm_crtc *old_crtc; | ||
47 | struct drm_encoder drm_encoder; | 49 | struct drm_encoder drm_encoder; |
48 | struct exynos_drm_manager *manager; | 50 | struct exynos_drm_manager *manager; |
49 | int dpms; | 51 | int dpms; |
50 | }; | 52 | }; |
51 | 53 | ||
52 | static void exynos_drm_display_power(struct drm_encoder *encoder, int mode) | 54 | static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode) |
53 | { | 55 | { |
54 | struct drm_device *dev = encoder->dev; | 56 | struct drm_device *dev = encoder->dev; |
55 | struct drm_connector *connector; | 57 | struct drm_connector *connector; |
56 | struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); | ||
57 | 58 | ||
58 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 59 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
59 | if (connector->encoder == encoder) { | 60 | if (exynos_drm_best_encoder(connector) == encoder) { |
60 | struct exynos_drm_display_ops *display_ops = | ||
61 | manager->display_ops; | ||
62 | |||
63 | DRM_DEBUG_KMS("connector[%d] dpms[%d]\n", | 61 | DRM_DEBUG_KMS("connector[%d] dpms[%d]\n", |
64 | connector->base.id, mode); | 62 | connector->base.id, mode); |
65 | if (display_ops && display_ops->power_on) | 63 | |
66 | display_ops->power_on(manager->dev, mode); | 64 | exynos_drm_display_power(connector, mode); |
67 | } | 65 | } |
68 | } | 66 | } |
69 | } | 67 | } |
@@ -88,13 +86,13 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode) | |||
88 | case DRM_MODE_DPMS_ON: | 86 | case DRM_MODE_DPMS_ON: |
89 | if (manager_ops && manager_ops->apply) | 87 | if (manager_ops && manager_ops->apply) |
90 | manager_ops->apply(manager->dev); | 88 | manager_ops->apply(manager->dev); |
91 | exynos_drm_display_power(encoder, mode); | 89 | exynos_drm_connector_power(encoder, mode); |
92 | exynos_encoder->dpms = mode; | 90 | exynos_encoder->dpms = mode; |
93 | break; | 91 | break; |
94 | case DRM_MODE_DPMS_STANDBY: | 92 | case DRM_MODE_DPMS_STANDBY: |
95 | case DRM_MODE_DPMS_SUSPEND: | 93 | case DRM_MODE_DPMS_SUSPEND: |
96 | case DRM_MODE_DPMS_OFF: | 94 | case DRM_MODE_DPMS_OFF: |
97 | exynos_drm_display_power(encoder, mode); | 95 | exynos_drm_connector_power(encoder, mode); |
98 | exynos_encoder->dpms = mode; | 96 | exynos_encoder->dpms = mode; |
99 | break; | 97 | break; |
100 | default: | 98 | default: |
@@ -127,24 +125,74 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder, | |||
127 | return true; | 125 | return true; |
128 | } | 126 | } |
129 | 127 | ||
128 | static void disable_plane_to_crtc(struct drm_device *dev, | ||
129 | struct drm_crtc *old_crtc, | ||
130 | struct drm_crtc *new_crtc) | ||
131 | { | ||
132 | struct drm_plane *plane; | ||
133 | |||
134 | /* | ||
135 | * if old_crtc isn't same as encoder->crtc then it means that | ||
136 | * user changed crtc id to another one so the plane to old_crtc | ||
137 | * should be disabled and plane->crtc should be set to new_crtc | ||
138 | * (encoder->crtc) | ||
139 | */ | ||
140 | list_for_each_entry(plane, &dev->mode_config.plane_list, head) { | ||
141 | if (plane->crtc == old_crtc) { | ||
142 | /* | ||
143 | * do not change below call order. | ||
144 | * | ||
145 | * plane->funcs->disable_plane call checks | ||
146 | * if encoder->crtc is same as plane->crtc and if same | ||
147 | * then overlay_ops->disable callback will be called | ||
148 | * to diasble current hw overlay so plane->crtc should | ||
149 | * have new_crtc because new_crtc was set to | ||
150 | * encoder->crtc in advance. | ||
151 | */ | ||
152 | plane->crtc = new_crtc; | ||
153 | plane->funcs->disable_plane(plane); | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | |||
130 | static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder, | 158 | static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder, |
131 | struct drm_display_mode *mode, | 159 | struct drm_display_mode *mode, |
132 | struct drm_display_mode *adjusted_mode) | 160 | struct drm_display_mode *adjusted_mode) |
133 | { | 161 | { |
134 | struct drm_device *dev = encoder->dev; | 162 | struct drm_device *dev = encoder->dev; |
135 | struct drm_connector *connector; | 163 | struct drm_connector *connector; |
136 | struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); | 164 | struct exynos_drm_manager *manager; |
137 | struct exynos_drm_manager_ops *manager_ops = manager->ops; | 165 | struct exynos_drm_manager_ops *manager_ops; |
138 | 166 | ||
139 | DRM_DEBUG_KMS("%s\n", __FILE__); | 167 | DRM_DEBUG_KMS("%s\n", __FILE__); |
140 | 168 | ||
141 | exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_ON); | ||
142 | |||
143 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 169 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
144 | if (connector->encoder == encoder) | 170 | if (connector->encoder == encoder) { |
171 | struct exynos_drm_encoder *exynos_encoder; | ||
172 | |||
173 | exynos_encoder = to_exynos_encoder(encoder); | ||
174 | |||
175 | if (exynos_encoder->old_crtc != encoder->crtc && | ||
176 | exynos_encoder->old_crtc) { | ||
177 | |||
178 | /* | ||
179 | * disable a plane to old crtc and change | ||
180 | * crtc of the plane to new one. | ||
181 | */ | ||
182 | disable_plane_to_crtc(dev, | ||
183 | exynos_encoder->old_crtc, | ||
184 | encoder->crtc); | ||
185 | } | ||
186 | |||
187 | manager = exynos_drm_get_manager(encoder); | ||
188 | manager_ops = manager->ops; | ||
189 | |||
145 | if (manager_ops && manager_ops->mode_set) | 190 | if (manager_ops && manager_ops->mode_set) |
146 | manager_ops->mode_set(manager->dev, | 191 | manager_ops->mode_set(manager->dev, |
147 | adjusted_mode); | 192 | adjusted_mode); |
193 | |||
194 | exynos_encoder->old_crtc = encoder->crtc; | ||
195 | } | ||
148 | } | 196 | } |
149 | } | 197 | } |
150 | 198 | ||
@@ -166,12 +214,27 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder) | |||
166 | manager_ops->commit(manager->dev); | 214 | manager_ops->commit(manager->dev); |
167 | } | 215 | } |
168 | 216 | ||
217 | static void exynos_drm_encoder_disable(struct drm_encoder *encoder) | ||
218 | { | ||
219 | struct drm_plane *plane; | ||
220 | struct drm_device *dev = encoder->dev; | ||
221 | |||
222 | exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); | ||
223 | |||
224 | /* all planes connected to this encoder should be also disabled. */ | ||
225 | list_for_each_entry(plane, &dev->mode_config.plane_list, head) { | ||
226 | if (plane->crtc == encoder->crtc) | ||
227 | plane->funcs->disable_plane(plane); | ||
228 | } | ||
229 | } | ||
230 | |||
169 | static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { | 231 | static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { |
170 | .dpms = exynos_drm_encoder_dpms, | 232 | .dpms = exynos_drm_encoder_dpms, |
171 | .mode_fixup = exynos_drm_encoder_mode_fixup, | 233 | .mode_fixup = exynos_drm_encoder_mode_fixup, |
172 | .mode_set = exynos_drm_encoder_mode_set, | 234 | .mode_set = exynos_drm_encoder_mode_set, |
173 | .prepare = exynos_drm_encoder_prepare, | 235 | .prepare = exynos_drm_encoder_prepare, |
174 | .commit = exynos_drm_encoder_commit, | 236 | .commit = exynos_drm_encoder_commit, |
237 | .disable = exynos_drm_encoder_disable, | ||
175 | }; | 238 | }; |
176 | 239 | ||
177 | static void exynos_drm_encoder_destroy(struct drm_encoder *encoder) | 240 | static void exynos_drm_encoder_destroy(struct drm_encoder *encoder) |
@@ -338,6 +401,19 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data) | |||
338 | manager_ops->dpms(manager->dev, mode); | 401 | manager_ops->dpms(manager->dev, mode); |
339 | 402 | ||
340 | /* | 403 | /* |
404 | * set current mode to new one so that data aren't updated into | ||
405 | * registers by drm_helper_connector_dpms two times. | ||
406 | * | ||
407 | * in case that drm_crtc_helper_set_mode() is called, | ||
408 | * overlay_ops->commit() and manager_ops->commit() callbacks | ||
409 | * can be called two times, first at drm_crtc_helper_set_mode() | ||
410 | * and second at drm_helper_connector_dpms(). | ||
411 | * so with this setting, when drm_helper_connector_dpms() is called | ||
412 | * encoder->funcs->dpms() will be ignored. | ||
413 | */ | ||
414 | exynos_encoder->dpms = mode; | ||
415 | |||
416 | /* | ||
341 | * if this condition is ok then it means that the crtc is already | 417 | * if this condition is ok then it means that the crtc is already |
342 | * detached from encoder and last function for detaching is properly | 418 | * detached from encoder and last function for detaching is properly |
343 | * done, so clear pipe from manager to prevent repeated call. | 419 | * done, so clear pipe from manager to prevent repeated call. |
@@ -422,4 +498,14 @@ void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data) | |||
422 | 498 | ||
423 | if (overlay_ops && overlay_ops->disable) | 499 | if (overlay_ops && overlay_ops->disable) |
424 | overlay_ops->disable(manager->dev, zpos); | 500 | overlay_ops->disable(manager->dev, zpos); |
501 | |||
502 | /* | ||
503 | * wait for vblank interrupt | ||
504 | * - this makes sure that hardware overlay is disabled to avoid | ||
505 | * for the dma accesses to memory after gem buffer was released | ||
506 | * because the setting for disabling the overlay will be updated | ||
507 | * at vsync. | ||
508 | */ | ||
509 | if (overlay_ops->wait_for_vblank) | ||
510 | overlay_ops->wait_for_vblank(manager->dev); | ||
425 | } | 511 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 53afcc5f0945..4ef4cd3f9936 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c | |||
@@ -41,10 +41,12 @@ | |||
41 | * exynos specific framebuffer structure. | 41 | * exynos specific framebuffer structure. |
42 | * | 42 | * |
43 | * @fb: drm framebuffer obejct. | 43 | * @fb: drm framebuffer obejct. |
44 | * @buf_cnt: a buffer count to drm framebuffer. | ||
44 | * @exynos_gem_obj: array of exynos specific gem object containing a gem object. | 45 | * @exynos_gem_obj: array of exynos specific gem object containing a gem object. |
45 | */ | 46 | */ |
46 | struct exynos_drm_fb { | 47 | struct exynos_drm_fb { |
47 | struct drm_framebuffer fb; | 48 | struct drm_framebuffer fb; |
49 | unsigned int buf_cnt; | ||
48 | struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER]; | 50 | struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER]; |
49 | }; | 51 | }; |
50 | 52 | ||
@@ -101,6 +103,25 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = { | |||
101 | .dirty = exynos_drm_fb_dirty, | 103 | .dirty = exynos_drm_fb_dirty, |
102 | }; | 104 | }; |
103 | 105 | ||
106 | void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb, | ||
107 | unsigned int cnt) | ||
108 | { | ||
109 | struct exynos_drm_fb *exynos_fb; | ||
110 | |||
111 | exynos_fb = to_exynos_fb(fb); | ||
112 | |||
113 | exynos_fb->buf_cnt = cnt; | ||
114 | } | ||
115 | |||
116 | unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb) | ||
117 | { | ||
118 | struct exynos_drm_fb *exynos_fb; | ||
119 | |||
120 | exynos_fb = to_exynos_fb(fb); | ||
121 | |||
122 | return exynos_fb->buf_cnt; | ||
123 | } | ||
124 | |||
104 | struct drm_framebuffer * | 125 | struct drm_framebuffer * |
105 | exynos_drm_framebuffer_init(struct drm_device *dev, | 126 | exynos_drm_framebuffer_init(struct drm_device *dev, |
106 | struct drm_mode_fb_cmd2 *mode_cmd, | 127 | struct drm_mode_fb_cmd2 *mode_cmd, |
@@ -127,6 +148,43 @@ exynos_drm_framebuffer_init(struct drm_device *dev, | |||
127 | return &exynos_fb->fb; | 148 | return &exynos_fb->fb; |
128 | } | 149 | } |
129 | 150 | ||
151 | static u32 exynos_drm_format_num_buffers(struct drm_mode_fb_cmd2 *mode_cmd) | ||
152 | { | ||
153 | unsigned int cnt = 0; | ||
154 | |||
155 | if (mode_cmd->pixel_format != DRM_FORMAT_NV12) | ||
156 | return drm_format_num_planes(mode_cmd->pixel_format); | ||
157 | |||
158 | while (cnt != MAX_FB_BUFFER) { | ||
159 | if (!mode_cmd->handles[cnt]) | ||
160 | break; | ||
161 | cnt++; | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * check if NV12 or NV12M. | ||
166 | * | ||
167 | * NV12 | ||
168 | * handles[0] = base1, offsets[0] = 0 | ||
169 | * handles[1] = base1, offsets[1] = Y_size | ||
170 | * | ||
171 | * NV12M | ||
172 | * handles[0] = base1, offsets[0] = 0 | ||
173 | * handles[1] = base2, offsets[1] = 0 | ||
174 | */ | ||
175 | if (cnt == 2) { | ||
176 | /* | ||
177 | * in case of NV12 format, offsets[1] is not 0 and | ||
178 | * handles[0] is same as handles[1]. | ||
179 | */ | ||
180 | if (mode_cmd->offsets[1] && | ||
181 | mode_cmd->handles[0] == mode_cmd->handles[1]) | ||
182 | cnt = 1; | ||
183 | } | ||
184 | |||
185 | return cnt; | ||
186 | } | ||
187 | |||
130 | static struct drm_framebuffer * | 188 | static struct drm_framebuffer * |
131 | exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, | 189 | exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, |
132 | struct drm_mode_fb_cmd2 *mode_cmd) | 190 | struct drm_mode_fb_cmd2 *mode_cmd) |
@@ -134,7 +192,6 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, | |||
134 | struct drm_gem_object *obj; | 192 | struct drm_gem_object *obj; |
135 | struct drm_framebuffer *fb; | 193 | struct drm_framebuffer *fb; |
136 | struct exynos_drm_fb *exynos_fb; | 194 | struct exynos_drm_fb *exynos_fb; |
137 | int nr; | ||
138 | int i; | 195 | int i; |
139 | 196 | ||
140 | DRM_DEBUG_KMS("%s\n", __FILE__); | 197 | DRM_DEBUG_KMS("%s\n", __FILE__); |
@@ -152,9 +209,11 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, | |||
152 | } | 209 | } |
153 | 210 | ||
154 | exynos_fb = to_exynos_fb(fb); | 211 | exynos_fb = to_exynos_fb(fb); |
155 | nr = exynos_drm_format_num_buffers(fb->pixel_format); | 212 | exynos_fb->buf_cnt = exynos_drm_format_num_buffers(mode_cmd); |
213 | |||
214 | DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt); | ||
156 | 215 | ||
157 | for (i = 1; i < nr; i++) { | 216 | for (i = 1; i < exynos_fb->buf_cnt; i++) { |
158 | obj = drm_gem_object_lookup(dev, file_priv, | 217 | obj = drm_gem_object_lookup(dev, file_priv, |
159 | mode_cmd->handles[i]); | 218 | mode_cmd->handles[i]); |
160 | if (!obj) { | 219 | if (!obj) { |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h index 50823756cdea..96262e54f76d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.h +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h | |||
@@ -28,19 +28,6 @@ | |||
28 | #ifndef _EXYNOS_DRM_FB_H_ | 28 | #ifndef _EXYNOS_DRM_FB_H_ |
29 | #define _EXYNOS_DRM_FB_H | 29 | #define _EXYNOS_DRM_FB_H |
30 | 30 | ||
31 | static inline int exynos_drm_format_num_buffers(uint32_t format) | ||
32 | { | ||
33 | switch (format) { | ||
34 | case DRM_FORMAT_NV12: | ||
35 | case DRM_FORMAT_NV12MT: | ||
36 | return 2; | ||
37 | case DRM_FORMAT_YUV420: | ||
38 | return 3; | ||
39 | default: | ||
40 | return 1; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | struct drm_framebuffer * | 31 | struct drm_framebuffer * |
45 | exynos_drm_framebuffer_init(struct drm_device *dev, | 32 | exynos_drm_framebuffer_init(struct drm_device *dev, |
46 | struct drm_mode_fb_cmd2 *mode_cmd, | 33 | struct drm_mode_fb_cmd2 *mode_cmd, |
@@ -52,4 +39,11 @@ struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb, | |||
52 | 39 | ||
53 | void exynos_drm_mode_config_init(struct drm_device *dev); | 40 | void exynos_drm_mode_config_init(struct drm_device *dev); |
54 | 41 | ||
42 | /* set a buffer count to drm framebuffer. */ | ||
43 | void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb, | ||
44 | unsigned int cnt); | ||
45 | |||
46 | /* get a buffer count to drm framebuffer. */ | ||
47 | unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb); | ||
48 | |||
55 | #endif | 49 | #endif |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index bd4ff6348239..67eb6ba56edf 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c | |||
@@ -79,6 +79,9 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, | |||
79 | return -EFAULT; | 79 | return -EFAULT; |
80 | } | 80 | } |
81 | 81 | ||
82 | /* buffer count to framebuffer always is 1 at booting time. */ | ||
83 | exynos_drm_fb_set_buf_cnt(fb, 1); | ||
84 | |||
82 | offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); | 85 | offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); |
83 | offset += fbi->var.yoffset * fb->pitches[0]; | 86 | offset += fbi->var.yoffset * fb->pitches[0]; |
84 | 87 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 58d50e368a58..a32837951dd2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
@@ -57,6 +57,18 @@ | |||
57 | 57 | ||
58 | #define get_fimd_context(dev) platform_get_drvdata(to_platform_device(dev)) | 58 | #define get_fimd_context(dev) platform_get_drvdata(to_platform_device(dev)) |
59 | 59 | ||
60 | struct fimd_driver_data { | ||
61 | unsigned int timing_base; | ||
62 | }; | ||
63 | |||
64 | struct fimd_driver_data exynos4_fimd_driver_data = { | ||
65 | .timing_base = 0x0, | ||
66 | }; | ||
67 | |||
68 | struct fimd_driver_data exynos5_fimd_driver_data = { | ||
69 | .timing_base = 0x20000, | ||
70 | }; | ||
71 | |||
60 | struct fimd_win_data { | 72 | struct fimd_win_data { |
61 | unsigned int offset_x; | 73 | unsigned int offset_x; |
62 | unsigned int offset_y; | 74 | unsigned int offset_y; |
@@ -91,6 +103,13 @@ struct fimd_context { | |||
91 | struct exynos_drm_panel_info *panel; | 103 | struct exynos_drm_panel_info *panel; |
92 | }; | 104 | }; |
93 | 105 | ||
106 | static inline struct fimd_driver_data *drm_fimd_get_driver_data( | ||
107 | struct platform_device *pdev) | ||
108 | { | ||
109 | return (struct fimd_driver_data *) | ||
110 | platform_get_device_id(pdev)->driver_data; | ||
111 | } | ||
112 | |||
94 | static bool fimd_display_is_connected(struct device *dev) | 113 | static bool fimd_display_is_connected(struct device *dev) |
95 | { | 114 | { |
96 | DRM_DEBUG_KMS("%s\n", __FILE__); | 115 | DRM_DEBUG_KMS("%s\n", __FILE__); |
@@ -194,32 +213,35 @@ static void fimd_commit(struct device *dev) | |||
194 | struct fimd_context *ctx = get_fimd_context(dev); | 213 | struct fimd_context *ctx = get_fimd_context(dev); |
195 | struct exynos_drm_panel_info *panel = ctx->panel; | 214 | struct exynos_drm_panel_info *panel = ctx->panel; |
196 | struct fb_videomode *timing = &panel->timing; | 215 | struct fb_videomode *timing = &panel->timing; |
216 | struct fimd_driver_data *driver_data; | ||
217 | struct platform_device *pdev = to_platform_device(dev); | ||
197 | u32 val; | 218 | u32 val; |
198 | 219 | ||
220 | driver_data = drm_fimd_get_driver_data(pdev); | ||
199 | if (ctx->suspended) | 221 | if (ctx->suspended) |
200 | return; | 222 | return; |
201 | 223 | ||
202 | DRM_DEBUG_KMS("%s\n", __FILE__); | 224 | DRM_DEBUG_KMS("%s\n", __FILE__); |
203 | 225 | ||
204 | /* setup polarity values from machine code. */ | 226 | /* setup polarity values from machine code. */ |
205 | writel(ctx->vidcon1, ctx->regs + VIDCON1); | 227 | writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); |
206 | 228 | ||
207 | /* setup vertical timing values. */ | 229 | /* setup vertical timing values. */ |
208 | val = VIDTCON0_VBPD(timing->upper_margin - 1) | | 230 | val = VIDTCON0_VBPD(timing->upper_margin - 1) | |
209 | VIDTCON0_VFPD(timing->lower_margin - 1) | | 231 | VIDTCON0_VFPD(timing->lower_margin - 1) | |
210 | VIDTCON0_VSPW(timing->vsync_len - 1); | 232 | VIDTCON0_VSPW(timing->vsync_len - 1); |
211 | writel(val, ctx->regs + VIDTCON0); | 233 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); |
212 | 234 | ||
213 | /* setup horizontal timing values. */ | 235 | /* setup horizontal timing values. */ |
214 | val = VIDTCON1_HBPD(timing->left_margin - 1) | | 236 | val = VIDTCON1_HBPD(timing->left_margin - 1) | |
215 | VIDTCON1_HFPD(timing->right_margin - 1) | | 237 | VIDTCON1_HFPD(timing->right_margin - 1) | |
216 | VIDTCON1_HSPW(timing->hsync_len - 1); | 238 | VIDTCON1_HSPW(timing->hsync_len - 1); |
217 | writel(val, ctx->regs + VIDTCON1); | 239 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); |
218 | 240 | ||
219 | /* setup horizontal and vertical display size. */ | 241 | /* setup horizontal and vertical display size. */ |
220 | val = VIDTCON2_LINEVAL(timing->yres - 1) | | 242 | val = VIDTCON2_LINEVAL(timing->yres - 1) | |
221 | VIDTCON2_HOZVAL(timing->xres - 1); | 243 | VIDTCON2_HOZVAL(timing->xres - 1); |
222 | writel(val, ctx->regs + VIDTCON2); | 244 | writel(val, ctx->regs + driver_data->timing_base + VIDTCON2); |
223 | 245 | ||
224 | /* setup clock source, clock divider, enable dma. */ | 246 | /* setup clock source, clock divider, enable dma. */ |
225 | val = ctx->vidcon0; | 247 | val = ctx->vidcon0; |
@@ -570,10 +592,22 @@ static void fimd_win_disable(struct device *dev, int zpos) | |||
570 | win_data->enabled = false; | 592 | win_data->enabled = false; |
571 | } | 593 | } |
572 | 594 | ||
595 | static void fimd_wait_for_vblank(struct device *dev) | ||
596 | { | ||
597 | struct fimd_context *ctx = get_fimd_context(dev); | ||
598 | int ret; | ||
599 | |||
600 | ret = wait_for((__raw_readl(ctx->regs + VIDCON1) & | ||
601 | VIDCON1_VSTATUS_VSYNC), 50); | ||
602 | if (ret < 0) | ||
603 | DRM_DEBUG_KMS("vblank wait timed out.\n"); | ||
604 | } | ||
605 | |||
573 | static struct exynos_drm_overlay_ops fimd_overlay_ops = { | 606 | static struct exynos_drm_overlay_ops fimd_overlay_ops = { |
574 | .mode_set = fimd_win_mode_set, | 607 | .mode_set = fimd_win_mode_set, |
575 | .commit = fimd_win_commit, | 608 | .commit = fimd_win_commit, |
576 | .disable = fimd_win_disable, | 609 | .disable = fimd_win_disable, |
610 | .wait_for_vblank = fimd_wait_for_vblank, | ||
577 | }; | 611 | }; |
578 | 612 | ||
579 | static struct exynos_drm_manager fimd_manager = { | 613 | static struct exynos_drm_manager fimd_manager = { |
@@ -678,7 +712,7 @@ static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | |||
678 | return 0; | 712 | return 0; |
679 | } | 713 | } |
680 | 714 | ||
681 | static void fimd_subdrv_remove(struct drm_device *drm_dev) | 715 | static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev) |
682 | { | 716 | { |
683 | DRM_DEBUG_KMS("%s\n", __FILE__); | 717 | DRM_DEBUG_KMS("%s\n", __FILE__); |
684 | 718 | ||
@@ -747,16 +781,10 @@ static void fimd_clear_win(struct fimd_context *ctx, int win) | |||
747 | writel(val, ctx->regs + SHADOWCON); | 781 | writel(val, ctx->regs + SHADOWCON); |
748 | } | 782 | } |
749 | 783 | ||
750 | static int fimd_power_on(struct fimd_context *ctx, bool enable) | 784 | static int fimd_clock(struct fimd_context *ctx, bool enable) |
751 | { | 785 | { |
752 | struct exynos_drm_subdrv *subdrv = &ctx->subdrv; | ||
753 | struct device *dev = subdrv->dev; | ||
754 | |||
755 | DRM_DEBUG_KMS("%s\n", __FILE__); | 786 | DRM_DEBUG_KMS("%s\n", __FILE__); |
756 | 787 | ||
757 | if (enable != false && enable != true) | ||
758 | return -EINVAL; | ||
759 | |||
760 | if (enable) { | 788 | if (enable) { |
761 | int ret; | 789 | int ret; |
762 | 790 | ||
@@ -769,18 +797,31 @@ static int fimd_power_on(struct fimd_context *ctx, bool enable) | |||
769 | clk_disable(ctx->bus_clk); | 797 | clk_disable(ctx->bus_clk); |
770 | return ret; | 798 | return ret; |
771 | } | 799 | } |
800 | } else { | ||
801 | clk_disable(ctx->lcd_clk); | ||
802 | clk_disable(ctx->bus_clk); | ||
803 | } | ||
804 | |||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | static int fimd_activate(struct fimd_context *ctx, bool enable) | ||
809 | { | ||
810 | if (enable) { | ||
811 | int ret; | ||
812 | struct device *dev = ctx->subdrv.dev; | ||
813 | |||
814 | ret = fimd_clock(ctx, true); | ||
815 | if (ret < 0) | ||
816 | return ret; | ||
772 | 817 | ||
773 | ctx->suspended = false; | 818 | ctx->suspended = false; |
774 | 819 | ||
775 | /* if vblank was enabled status, enable it again. */ | 820 | /* if vblank was enabled status, enable it again. */ |
776 | if (test_and_clear_bit(0, &ctx->irq_flags)) | 821 | if (test_and_clear_bit(0, &ctx->irq_flags)) |
777 | fimd_enable_vblank(dev); | 822 | fimd_enable_vblank(dev); |
778 | |||
779 | fimd_apply(dev); | ||
780 | } else { | 823 | } else { |
781 | clk_disable(ctx->lcd_clk); | 824 | fimd_clock(ctx, false); |
782 | clk_disable(ctx->bus_clk); | ||
783 | |||
784 | ctx->suspended = true; | 825 | ctx->suspended = true; |
785 | } | 826 | } |
786 | 827 | ||
@@ -930,15 +971,15 @@ static int fimd_suspend(struct device *dev) | |||
930 | { | 971 | { |
931 | struct fimd_context *ctx = get_fimd_context(dev); | 972 | struct fimd_context *ctx = get_fimd_context(dev); |
932 | 973 | ||
933 | if (pm_runtime_suspended(dev)) | ||
934 | return 0; | ||
935 | |||
936 | /* | 974 | /* |
937 | * do not use pm_runtime_suspend(). if pm_runtime_suspend() is | 975 | * do not use pm_runtime_suspend(). if pm_runtime_suspend() is |
938 | * called here, an error would be returned by that interface | 976 | * called here, an error would be returned by that interface |
939 | * because the usage_count of pm runtime is more than 1. | 977 | * because the usage_count of pm runtime is more than 1. |
940 | */ | 978 | */ |
941 | return fimd_power_on(ctx, false); | 979 | if (!pm_runtime_suspended(dev)) |
980 | return fimd_activate(ctx, false); | ||
981 | |||
982 | return 0; | ||
942 | } | 983 | } |
943 | 984 | ||
944 | static int fimd_resume(struct device *dev) | 985 | static int fimd_resume(struct device *dev) |
@@ -950,8 +991,21 @@ static int fimd_resume(struct device *dev) | |||
950 | * of pm runtime would still be 1 so in this case, fimd driver | 991 | * of pm runtime would still be 1 so in this case, fimd driver |
951 | * should be on directly not drawing on pm runtime interface. | 992 | * should be on directly not drawing on pm runtime interface. |
952 | */ | 993 | */ |
953 | if (!pm_runtime_suspended(dev)) | 994 | if (pm_runtime_suspended(dev)) { |
954 | return fimd_power_on(ctx, true); | 995 | int ret; |
996 | |||
997 | ret = fimd_activate(ctx, true); | ||
998 | if (ret < 0) | ||
999 | return ret; | ||
1000 | |||
1001 | /* | ||
1002 | * in case of dpms on(standby), fimd_apply function will | ||
1003 | * be called by encoder's dpms callback to update fimd's | ||
1004 | * registers but in case of sleep wakeup, it's not. | ||
1005 | * so fimd_apply function should be called at here. | ||
1006 | */ | ||
1007 | fimd_apply(dev); | ||
1008 | } | ||
955 | 1009 | ||
956 | return 0; | 1010 | return 0; |
957 | } | 1011 | } |
@@ -964,7 +1018,7 @@ static int fimd_runtime_suspend(struct device *dev) | |||
964 | 1018 | ||
965 | DRM_DEBUG_KMS("%s\n", __FILE__); | 1019 | DRM_DEBUG_KMS("%s\n", __FILE__); |
966 | 1020 | ||
967 | return fimd_power_on(ctx, false); | 1021 | return fimd_activate(ctx, false); |
968 | } | 1022 | } |
969 | 1023 | ||
970 | static int fimd_runtime_resume(struct device *dev) | 1024 | static int fimd_runtime_resume(struct device *dev) |
@@ -973,10 +1027,22 @@ static int fimd_runtime_resume(struct device *dev) | |||
973 | 1027 | ||
974 | DRM_DEBUG_KMS("%s\n", __FILE__); | 1028 | DRM_DEBUG_KMS("%s\n", __FILE__); |
975 | 1029 | ||
976 | return fimd_power_on(ctx, true); | 1030 | return fimd_activate(ctx, true); |
977 | } | 1031 | } |
978 | #endif | 1032 | #endif |
979 | 1033 | ||
1034 | static struct platform_device_id fimd_driver_ids[] = { | ||
1035 | { | ||
1036 | .name = "exynos4-fb", | ||
1037 | .driver_data = (unsigned long)&exynos4_fimd_driver_data, | ||
1038 | }, { | ||
1039 | .name = "exynos5-fb", | ||
1040 | .driver_data = (unsigned long)&exynos5_fimd_driver_data, | ||
1041 | }, | ||
1042 | {}, | ||
1043 | }; | ||
1044 | MODULE_DEVICE_TABLE(platform, fimd_driver_ids); | ||
1045 | |||
980 | static const struct dev_pm_ops fimd_pm_ops = { | 1046 | static const struct dev_pm_ops fimd_pm_ops = { |
981 | SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume) | 1047 | SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume) |
982 | SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL) | 1048 | SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL) |
@@ -985,6 +1051,7 @@ static const struct dev_pm_ops fimd_pm_ops = { | |||
985 | struct platform_driver fimd_driver = { | 1051 | struct platform_driver fimd_driver = { |
986 | .probe = fimd_probe, | 1052 | .probe = fimd_probe, |
987 | .remove = __devexit_p(fimd_remove), | 1053 | .remove = __devexit_p(fimd_remove), |
1054 | .id_table = fimd_driver_ids, | ||
988 | .driver = { | 1055 | .driver = { |
989 | .name = "exynos4-fb", | 1056 | .name = "exynos4-fb", |
990 | .owner = THIS_MODULE, | 1057 | .owner = THIS_MODULE, |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index bc2a2e9be8eb..f7aab24ea46c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c | |||
@@ -122,6 +122,7 @@ struct g2d_runqueue_node { | |||
122 | struct list_head list; | 122 | struct list_head list; |
123 | struct list_head run_cmdlist; | 123 | struct list_head run_cmdlist; |
124 | struct list_head event_list; | 124 | struct list_head event_list; |
125 | pid_t pid; | ||
125 | struct completion complete; | 126 | struct completion complete; |
126 | int async; | 127 | int async; |
127 | }; | 128 | }; |
@@ -164,8 +165,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) | |||
164 | return -ENOMEM; | 165 | return -ENOMEM; |
165 | } | 166 | } |
166 | 167 | ||
167 | node = kcalloc(G2D_CMDLIST_NUM, G2D_CMDLIST_NUM * sizeof(*node), | 168 | node = kcalloc(G2D_CMDLIST_NUM, sizeof(*node), GFP_KERNEL); |
168 | GFP_KERNEL); | ||
169 | if (!node) { | 169 | if (!node) { |
170 | dev_err(dev, "failed to allocate memory\n"); | 170 | dev_err(dev, "failed to allocate memory\n"); |
171 | ret = -ENOMEM; | 171 | ret = -ENOMEM; |
@@ -679,6 +679,7 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, | |||
679 | } | 679 | } |
680 | 680 | ||
681 | mutex_lock(&g2d->runqueue_mutex); | 681 | mutex_lock(&g2d->runqueue_mutex); |
682 | runqueue_node->pid = current->pid; | ||
682 | list_add_tail(&runqueue_node->list, &g2d->runqueue); | 683 | list_add_tail(&runqueue_node->list, &g2d->runqueue); |
683 | if (!g2d->runqueue_node) | 684 | if (!g2d->runqueue_node) |
684 | g2d_exec_runqueue(g2d); | 685 | g2d_exec_runqueue(g2d); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index c3d3a5e4f109..c3b9e2b45185 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c | |||
@@ -29,6 +29,11 @@ | |||
29 | #define get_ctx_from_subdrv(subdrv) container_of(subdrv,\ | 29 | #define get_ctx_from_subdrv(subdrv) container_of(subdrv,\ |
30 | struct drm_hdmi_context, subdrv); | 30 | struct drm_hdmi_context, subdrv); |
31 | 31 | ||
32 | /* Common hdmi subdrv needs to access the hdmi and mixer though context. | ||
33 | * These should be initialied by the repective drivers */ | ||
34 | static struct exynos_drm_hdmi_context *hdmi_ctx; | ||
35 | static struct exynos_drm_hdmi_context *mixer_ctx; | ||
36 | |||
32 | /* these callback points shoud be set by specific drivers. */ | 37 | /* these callback points shoud be set by specific drivers. */ |
33 | static struct exynos_hdmi_ops *hdmi_ops; | 38 | static struct exynos_hdmi_ops *hdmi_ops; |
34 | static struct exynos_mixer_ops *mixer_ops; | 39 | static struct exynos_mixer_ops *mixer_ops; |
@@ -41,6 +46,18 @@ struct drm_hdmi_context { | |||
41 | bool enabled[MIXER_WIN_NR]; | 46 | bool enabled[MIXER_WIN_NR]; |
42 | }; | 47 | }; |
43 | 48 | ||
49 | void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx) | ||
50 | { | ||
51 | if (ctx) | ||
52 | hdmi_ctx = ctx; | ||
53 | } | ||
54 | |||
55 | void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx) | ||
56 | { | ||
57 | if (ctx) | ||
58 | mixer_ctx = ctx; | ||
59 | } | ||
60 | |||
44 | void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops) | 61 | void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops) |
45 | { | 62 | { |
46 | DRM_DEBUG_KMS("%s\n", __FILE__); | 63 | DRM_DEBUG_KMS("%s\n", __FILE__); |
@@ -274,10 +291,21 @@ static void drm_mixer_disable(struct device *subdrv_dev, int zpos) | |||
274 | ctx->enabled[win] = false; | 291 | ctx->enabled[win] = false; |
275 | } | 292 | } |
276 | 293 | ||
294 | static void drm_mixer_wait_for_vblank(struct device *subdrv_dev) | ||
295 | { | ||
296 | struct drm_hdmi_context *ctx = to_context(subdrv_dev); | ||
297 | |||
298 | DRM_DEBUG_KMS("%s\n", __FILE__); | ||
299 | |||
300 | if (mixer_ops && mixer_ops->wait_for_vblank) | ||
301 | mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx); | ||
302 | } | ||
303 | |||
277 | static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = { | 304 | static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = { |
278 | .mode_set = drm_mixer_mode_set, | 305 | .mode_set = drm_mixer_mode_set, |
279 | .commit = drm_mixer_commit, | 306 | .commit = drm_mixer_commit, |
280 | .disable = drm_mixer_disable, | 307 | .disable = drm_mixer_disable, |
308 | .wait_for_vblank = drm_mixer_wait_for_vblank, | ||
281 | }; | 309 | }; |
282 | 310 | ||
283 | static struct exynos_drm_manager hdmi_manager = { | 311 | static struct exynos_drm_manager hdmi_manager = { |
@@ -292,46 +320,30 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev, | |||
292 | { | 320 | { |
293 | struct exynos_drm_subdrv *subdrv = to_subdrv(dev); | 321 | struct exynos_drm_subdrv *subdrv = to_subdrv(dev); |
294 | struct drm_hdmi_context *ctx; | 322 | struct drm_hdmi_context *ctx; |
295 | struct platform_device *pdev = to_platform_device(dev); | ||
296 | struct exynos_drm_common_hdmi_pd *pd; | ||
297 | 323 | ||
298 | DRM_DEBUG_KMS("%s\n", __FILE__); | 324 | DRM_DEBUG_KMS("%s\n", __FILE__); |
299 | 325 | ||
300 | pd = pdev->dev.platform_data; | 326 | if (!hdmi_ctx) { |
301 | 327 | DRM_ERROR("hdmi context not initialized.\n"); | |
302 | if (!pd) { | ||
303 | DRM_DEBUG_KMS("platform data is null.\n"); | ||
304 | return -EFAULT; | ||
305 | } | ||
306 | |||
307 | if (!pd->hdmi_dev) { | ||
308 | DRM_DEBUG_KMS("hdmi device is null.\n"); | ||
309 | return -EFAULT; | 328 | return -EFAULT; |
310 | } | 329 | } |
311 | 330 | ||
312 | if (!pd->mixer_dev) { | 331 | if (!mixer_ctx) { |
313 | DRM_DEBUG_KMS("mixer device is null.\n"); | 332 | DRM_ERROR("mixer context not initialized.\n"); |
314 | return -EFAULT; | 333 | return -EFAULT; |
315 | } | 334 | } |
316 | 335 | ||
317 | ctx = get_ctx_from_subdrv(subdrv); | 336 | ctx = get_ctx_from_subdrv(subdrv); |
318 | 337 | ||
319 | ctx->hdmi_ctx = (struct exynos_drm_hdmi_context *) | 338 | if (!ctx) { |
320 | to_context(pd->hdmi_dev); | 339 | DRM_ERROR("no drm hdmi context.\n"); |
321 | if (!ctx->hdmi_ctx) { | ||
322 | DRM_DEBUG_KMS("hdmi context is null.\n"); | ||
323 | return -EFAULT; | 340 | return -EFAULT; |
324 | } | 341 | } |
325 | 342 | ||
326 | ctx->hdmi_ctx->drm_dev = drm_dev; | 343 | ctx->hdmi_ctx = hdmi_ctx; |
327 | 344 | ctx->mixer_ctx = mixer_ctx; | |
328 | ctx->mixer_ctx = (struct exynos_drm_hdmi_context *) | ||
329 | to_context(pd->mixer_dev); | ||
330 | if (!ctx->mixer_ctx) { | ||
331 | DRM_DEBUG_KMS("mixer context is null.\n"); | ||
332 | return -EFAULT; | ||
333 | } | ||
334 | 345 | ||
346 | ctx->hdmi_ctx->drm_dev = drm_dev; | ||
335 | ctx->mixer_ctx->drm_dev = drm_dev; | 347 | ctx->mixer_ctx->drm_dev = drm_dev; |
336 | 348 | ||
337 | return 0; | 349 | return 0; |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h index a91c42088e42..2da5ffd3a059 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h | |||
@@ -67,11 +67,14 @@ struct exynos_mixer_ops { | |||
67 | void (*dpms)(void *ctx, int mode); | 67 | void (*dpms)(void *ctx, int mode); |
68 | 68 | ||
69 | /* overlay */ | 69 | /* overlay */ |
70 | void (*wait_for_vblank)(void *ctx); | ||
70 | void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay); | 71 | void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay); |
71 | void (*win_commit)(void *ctx, int zpos); | 72 | void (*win_commit)(void *ctx, int zpos); |
72 | void (*win_disable)(void *ctx, int zpos); | 73 | void (*win_disable)(void *ctx, int zpos); |
73 | }; | 74 | }; |
74 | 75 | ||
76 | void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx); | ||
77 | void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx); | ||
75 | void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops); | 78 | void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops); |
76 | void exynos_mixer_ops_register(struct exynos_mixer_ops *ops); | 79 | void exynos_mixer_ops_register(struct exynos_mixer_ops *ops); |
77 | #endif | 80 | #endif |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 03b472b43013..60b877a388c2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c | |||
@@ -32,6 +32,42 @@ static const uint32_t formats[] = { | |||
32 | DRM_FORMAT_NV12MT, | 32 | DRM_FORMAT_NV12MT, |
33 | }; | 33 | }; |
34 | 34 | ||
35 | /* | ||
36 | * This function is to get X or Y size shown via screen. This needs length and | ||
37 | * start position of CRTC. | ||
38 | * | ||
39 | * <--- length ---> | ||
40 | * CRTC ---------------- | ||
41 | * ^ start ^ end | ||
42 | * | ||
43 | * There are six cases from a to b. | ||
44 | * | ||
45 | * <----- SCREEN -----> | ||
46 | * 0 last | ||
47 | * ----------|------------------|---------- | ||
48 | * CRTCs | ||
49 | * a ------- | ||
50 | * b ------- | ||
51 | * c -------------------------- | ||
52 | * d -------- | ||
53 | * e ------- | ||
54 | * f ------- | ||
55 | */ | ||
56 | static int exynos_plane_get_size(int start, unsigned length, unsigned last) | ||
57 | { | ||
58 | int end = start + length; | ||
59 | int size = 0; | ||
60 | |||
61 | if (start <= 0) { | ||
62 | if (end > 0) | ||
63 | size = min_t(unsigned, end, last); | ||
64 | } else if (start <= last) { | ||
65 | size = min_t(unsigned, last - start, length); | ||
66 | } | ||
67 | |||
68 | return size; | ||
69 | } | ||
70 | |||
35 | int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, | 71 | int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, |
36 | struct drm_framebuffer *fb, int crtc_x, int crtc_y, | 72 | struct drm_framebuffer *fb, int crtc_x, int crtc_y, |
37 | unsigned int crtc_w, unsigned int crtc_h, | 73 | unsigned int crtc_w, unsigned int crtc_h, |
@@ -47,7 +83,7 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, | |||
47 | 83 | ||
48 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | 84 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); |
49 | 85 | ||
50 | nr = exynos_drm_format_num_buffers(fb->pixel_format); | 86 | nr = exynos_drm_fb_get_buf_cnt(fb); |
51 | for (i = 0; i < nr; i++) { | 87 | for (i = 0; i < nr; i++) { |
52 | struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i); | 88 | struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i); |
53 | 89 | ||
@@ -64,8 +100,24 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, | |||
64 | (unsigned long)overlay->dma_addr[i]); | 100 | (unsigned long)overlay->dma_addr[i]); |
65 | } | 101 | } |
66 | 102 | ||
67 | actual_w = min((unsigned)(crtc->mode.hdisplay - crtc_x), crtc_w); | 103 | actual_w = exynos_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay); |
68 | actual_h = min((unsigned)(crtc->mode.vdisplay - crtc_y), crtc_h); | 104 | actual_h = exynos_plane_get_size(crtc_y, crtc_h, crtc->mode.vdisplay); |
105 | |||
106 | if (crtc_x < 0) { | ||
107 | if (actual_w) | ||
108 | src_x -= crtc_x; | ||
109 | else | ||
110 | src_x += crtc_w; | ||
111 | crtc_x = 0; | ||
112 | } | ||
113 | |||
114 | if (crtc_y < 0) { | ||
115 | if (actual_h) | ||
116 | src_y -= crtc_y; | ||
117 | else | ||
118 | src_y += crtc_h; | ||
119 | crtc_y = 0; | ||
120 | } | ||
69 | 121 | ||
70 | /* set drm framebuffer data. */ | 122 | /* set drm framebuffer data. */ |
71 | overlay->fb_x = src_x; | 123 | overlay->fb_x = src_x; |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 8fe431ae537b..e4b8a8f741f7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c | |||
@@ -56,6 +56,7 @@ struct vidi_context { | |||
56 | unsigned int connected; | 56 | unsigned int connected; |
57 | bool vblank_on; | 57 | bool vblank_on; |
58 | bool suspended; | 58 | bool suspended; |
59 | bool direct_vblank; | ||
59 | struct work_struct work; | 60 | struct work_struct work; |
60 | struct mutex lock; | 61 | struct mutex lock; |
61 | }; | 62 | }; |
@@ -224,6 +225,15 @@ static int vidi_enable_vblank(struct device *dev) | |||
224 | if (!test_and_set_bit(0, &ctx->irq_flags)) | 225 | if (!test_and_set_bit(0, &ctx->irq_flags)) |
225 | ctx->vblank_on = true; | 226 | ctx->vblank_on = true; |
226 | 227 | ||
228 | ctx->direct_vblank = true; | ||
229 | |||
230 | /* | ||
231 | * in case of page flip request, vidi_finish_pageflip function | ||
232 | * will not be called because direct_vblank is true and then | ||
233 | * that function will be called by overlay_ops->commit callback | ||
234 | */ | ||
235 | schedule_work(&ctx->work); | ||
236 | |||
227 | return 0; | 237 | return 0; |
228 | } | 238 | } |
229 | 239 | ||
@@ -425,7 +435,17 @@ static void vidi_fake_vblank_handler(struct work_struct *work) | |||
425 | /* refresh rate is about 50Hz. */ | 435 | /* refresh rate is about 50Hz. */ |
426 | usleep_range(16000, 20000); | 436 | usleep_range(16000, 20000); |
427 | 437 | ||
428 | drm_handle_vblank(subdrv->drm_dev, manager->pipe); | 438 | mutex_lock(&ctx->lock); |
439 | |||
440 | if (ctx->direct_vblank) { | ||
441 | drm_handle_vblank(subdrv->drm_dev, manager->pipe); | ||
442 | ctx->direct_vblank = false; | ||
443 | mutex_unlock(&ctx->lock); | ||
444 | return; | ||
445 | } | ||
446 | |||
447 | mutex_unlock(&ctx->lock); | ||
448 | |||
429 | vidi_finish_pageflip(subdrv->drm_dev, manager->pipe); | 449 | vidi_finish_pageflip(subdrv->drm_dev, manager->pipe); |
430 | } | 450 | } |
431 | 451 | ||
@@ -453,7 +473,7 @@ static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | |||
453 | return 0; | 473 | return 0; |
454 | } | 474 | } |
455 | 475 | ||
456 | static void vidi_subdrv_remove(struct drm_device *drm_dev) | 476 | static void vidi_subdrv_remove(struct drm_device *drm_dev, struct device *dev) |
457 | { | 477 | { |
458 | DRM_DEBUG_KMS("%s\n", __FILE__); | 478 | DRM_DEBUG_KMS("%s\n", __FILE__); |
459 | 479 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index e1c53956aa27..2c115f8a62a3 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c | |||
@@ -32,6 +32,9 @@ | |||
32 | #include <linux/pm_runtime.h> | 32 | #include <linux/pm_runtime.h> |
33 | #include <linux/clk.h> | 33 | #include <linux/clk.h> |
34 | #include <linux/regulator/consumer.h> | 34 | #include <linux/regulator/consumer.h> |
35 | #include <linux/io.h> | ||
36 | #include <linux/of_gpio.h> | ||
37 | #include <plat/gpio-cfg.h> | ||
35 | 38 | ||
36 | #include <drm/exynos_drm.h> | 39 | #include <drm/exynos_drm.h> |
37 | 40 | ||
@@ -40,10 +43,18 @@ | |||
40 | 43 | ||
41 | #include "exynos_hdmi.h" | 44 | #include "exynos_hdmi.h" |
42 | 45 | ||
46 | #include <linux/gpio.h> | ||
47 | #include <media/s5p_hdmi.h> | ||
48 | |||
43 | #define MAX_WIDTH 1920 | 49 | #define MAX_WIDTH 1920 |
44 | #define MAX_HEIGHT 1080 | 50 | #define MAX_HEIGHT 1080 |
45 | #define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev)) | 51 | #define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev)) |
46 | 52 | ||
53 | enum hdmi_type { | ||
54 | HDMI_TYPE13, | ||
55 | HDMI_TYPE14, | ||
56 | }; | ||
57 | |||
47 | struct hdmi_resources { | 58 | struct hdmi_resources { |
48 | struct clk *hdmi; | 59 | struct clk *hdmi; |
49 | struct clk *sclk_hdmi; | 60 | struct clk *sclk_hdmi; |
@@ -59,13 +70,12 @@ struct hdmi_context { | |||
59 | struct drm_device *drm_dev; | 70 | struct drm_device *drm_dev; |
60 | bool hpd; | 71 | bool hpd; |
61 | bool powered; | 72 | bool powered; |
62 | bool is_v13; | ||
63 | bool dvi_mode; | 73 | bool dvi_mode; |
64 | struct mutex hdmi_mutex; | 74 | struct mutex hdmi_mutex; |
65 | 75 | ||
66 | void __iomem *regs; | 76 | void __iomem *regs; |
67 | unsigned int external_irq; | 77 | int external_irq; |
68 | unsigned int internal_irq; | 78 | int internal_irq; |
69 | 79 | ||
70 | struct i2c_client *ddc_port; | 80 | struct i2c_client *ddc_port; |
71 | struct i2c_client *hdmiphy_port; | 81 | struct i2c_client *hdmiphy_port; |
@@ -76,8 +86,9 @@ struct hdmi_context { | |||
76 | struct hdmi_resources res; | 86 | struct hdmi_resources res; |
77 | void *parent_ctx; | 87 | void *parent_ctx; |
78 | 88 | ||
79 | void (*cfg_hpd)(bool external); | 89 | int hpd_gpio; |
80 | int (*get_hpd)(void); | 90 | |
91 | enum hdmi_type type; | ||
81 | }; | 92 | }; |
82 | 93 | ||
83 | /* HDMI Version 1.3 */ | 94 | /* HDMI Version 1.3 */ |
@@ -1209,7 +1220,7 @@ static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix) | |||
1209 | 1220 | ||
1210 | static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix) | 1221 | static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix) |
1211 | { | 1222 | { |
1212 | if (hdata->is_v13) | 1223 | if (hdata->type == HDMI_TYPE13) |
1213 | hdmi_v13_regs_dump(hdata, prefix); | 1224 | hdmi_v13_regs_dump(hdata, prefix); |
1214 | else | 1225 | else |
1215 | hdmi_v14_regs_dump(hdata, prefix); | 1226 | hdmi_v14_regs_dump(hdata, prefix); |
@@ -1250,7 +1261,7 @@ static int hdmi_v14_conf_index(struct drm_display_mode *mode) | |||
1250 | static int hdmi_conf_index(struct hdmi_context *hdata, | 1261 | static int hdmi_conf_index(struct hdmi_context *hdata, |
1251 | struct drm_display_mode *mode) | 1262 | struct drm_display_mode *mode) |
1252 | { | 1263 | { |
1253 | if (hdata->is_v13) | 1264 | if (hdata->type == HDMI_TYPE13) |
1254 | return hdmi_v13_conf_index(mode); | 1265 | return hdmi_v13_conf_index(mode); |
1255 | 1266 | ||
1256 | return hdmi_v14_conf_index(mode); | 1267 | return hdmi_v14_conf_index(mode); |
@@ -1346,7 +1357,7 @@ static int hdmi_check_timing(void *ctx, void *timing) | |||
1346 | check_timing->yres, check_timing->refresh, | 1357 | check_timing->yres, check_timing->refresh, |
1347 | check_timing->vmode); | 1358 | check_timing->vmode); |
1348 | 1359 | ||
1349 | if (hdata->is_v13) | 1360 | if (hdata->type == HDMI_TYPE13) |
1350 | return hdmi_v13_check_timing(check_timing); | 1361 | return hdmi_v13_check_timing(check_timing); |
1351 | else | 1362 | else |
1352 | return hdmi_v14_check_timing(check_timing); | 1363 | return hdmi_v14_check_timing(check_timing); |
@@ -1412,7 +1423,7 @@ static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr) | |||
1412 | hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]); | 1423 | hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]); |
1413 | hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]); | 1424 | hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]); |
1414 | 1425 | ||
1415 | if (hdata->is_v13) | 1426 | if (hdata->type == HDMI_TYPE13) |
1416 | hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4); | 1427 | hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4); |
1417 | else | 1428 | else |
1418 | hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); | 1429 | hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); |
@@ -1516,7 +1527,7 @@ static void hdmi_conf_reset(struct hdmi_context *hdata) | |||
1516 | { | 1527 | { |
1517 | u32 reg; | 1528 | u32 reg; |
1518 | 1529 | ||
1519 | if (hdata->is_v13) | 1530 | if (hdata->type == HDMI_TYPE13) |
1520 | reg = HDMI_V13_CORE_RSTOUT; | 1531 | reg = HDMI_V13_CORE_RSTOUT; |
1521 | else | 1532 | else |
1522 | reg = HDMI_CORE_RSTOUT; | 1533 | reg = HDMI_CORE_RSTOUT; |
@@ -1530,12 +1541,9 @@ static void hdmi_conf_reset(struct hdmi_context *hdata) | |||
1530 | 1541 | ||
1531 | static void hdmi_conf_init(struct hdmi_context *hdata) | 1542 | static void hdmi_conf_init(struct hdmi_context *hdata) |
1532 | { | 1543 | { |
1533 | /* enable HPD interrupts */ | 1544 | /* disable HPD interrupts */ |
1534 | hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL | | 1545 | hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL | |
1535 | HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG); | 1546 | HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG); |
1536 | mdelay(10); | ||
1537 | hdmi_reg_writemask(hdata, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL | | ||
1538 | HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG); | ||
1539 | 1547 | ||
1540 | /* choose HDMI mode */ | 1548 | /* choose HDMI mode */ |
1541 | hdmi_reg_writemask(hdata, HDMI_MODE_SEL, | 1549 | hdmi_reg_writemask(hdata, HDMI_MODE_SEL, |
@@ -1551,7 +1559,7 @@ static void hdmi_conf_init(struct hdmi_context *hdata) | |||
1551 | HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS); | 1559 | HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS); |
1552 | } | 1560 | } |
1553 | 1561 | ||
1554 | if (hdata->is_v13) { | 1562 | if (hdata->type == HDMI_TYPE13) { |
1555 | /* choose bluescreen (fecal) color */ | 1563 | /* choose bluescreen (fecal) color */ |
1556 | hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12); | 1564 | hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12); |
1557 | hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34); | 1565 | hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34); |
@@ -1833,7 +1841,7 @@ static void hdmi_v14_timing_apply(struct hdmi_context *hdata) | |||
1833 | 1841 | ||
1834 | static void hdmi_timing_apply(struct hdmi_context *hdata) | 1842 | static void hdmi_timing_apply(struct hdmi_context *hdata) |
1835 | { | 1843 | { |
1836 | if (hdata->is_v13) | 1844 | if (hdata->type == HDMI_TYPE13) |
1837 | hdmi_v13_timing_apply(hdata); | 1845 | hdmi_v13_timing_apply(hdata); |
1838 | else | 1846 | else |
1839 | hdmi_v14_timing_apply(hdata); | 1847 | hdmi_v14_timing_apply(hdata); |
@@ -1855,7 +1863,7 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata) | |||
1855 | if (hdata->hdmiphy_port) | 1863 | if (hdata->hdmiphy_port) |
1856 | i2c_master_send(hdata->hdmiphy_port, buffer, 2); | 1864 | i2c_master_send(hdata->hdmiphy_port, buffer, 2); |
1857 | 1865 | ||
1858 | if (hdata->is_v13) | 1866 | if (hdata->type == HDMI_TYPE13) |
1859 | reg = HDMI_V13_PHY_RSTOUT; | 1867 | reg = HDMI_V13_PHY_RSTOUT; |
1860 | else | 1868 | else |
1861 | reg = HDMI_PHY_RSTOUT; | 1869 | reg = HDMI_PHY_RSTOUT; |
@@ -1882,7 +1890,7 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) | |||
1882 | } | 1890 | } |
1883 | 1891 | ||
1884 | /* pixel clock */ | 1892 | /* pixel clock */ |
1885 | if (hdata->is_v13) | 1893 | if (hdata->type == HDMI_TYPE13) |
1886 | hdmiphy_data = hdmi_v13_confs[hdata->cur_conf].hdmiphy_data; | 1894 | hdmiphy_data = hdmi_v13_confs[hdata->cur_conf].hdmiphy_data; |
1887 | else | 1895 | else |
1888 | hdmiphy_data = hdmi_confs[hdata->cur_conf].hdmiphy_data; | 1896 | hdmiphy_data = hdmi_confs[hdata->cur_conf].hdmiphy_data; |
@@ -1950,7 +1958,7 @@ static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector, | |||
1950 | 1958 | ||
1951 | drm_mode_set_crtcinfo(adjusted_mode, 0); | 1959 | drm_mode_set_crtcinfo(adjusted_mode, 0); |
1952 | 1960 | ||
1953 | if (hdata->is_v13) | 1961 | if (hdata->type == HDMI_TYPE13) |
1954 | index = hdmi_v13_conf_index(adjusted_mode); | 1962 | index = hdmi_v13_conf_index(adjusted_mode); |
1955 | else | 1963 | else |
1956 | index = hdmi_v14_conf_index(adjusted_mode); | 1964 | index = hdmi_v14_conf_index(adjusted_mode); |
@@ -1964,7 +1972,7 @@ static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector, | |||
1964 | * to adjusted_mode. | 1972 | * to adjusted_mode. |
1965 | */ | 1973 | */ |
1966 | list_for_each_entry(m, &connector->modes, head) { | 1974 | list_for_each_entry(m, &connector->modes, head) { |
1967 | if (hdata->is_v13) | 1975 | if (hdata->type == HDMI_TYPE13) |
1968 | index = hdmi_v13_conf_index(m); | 1976 | index = hdmi_v13_conf_index(m); |
1969 | else | 1977 | else |
1970 | index = hdmi_v14_conf_index(m); | 1978 | index = hdmi_v14_conf_index(m); |
@@ -2024,8 +2032,6 @@ static void hdmi_poweron(struct hdmi_context *hdata) | |||
2024 | 2032 | ||
2025 | hdata->powered = true; | 2033 | hdata->powered = true; |
2026 | 2034 | ||
2027 | if (hdata->cfg_hpd) | ||
2028 | hdata->cfg_hpd(true); | ||
2029 | mutex_unlock(&hdata->hdmi_mutex); | 2035 | mutex_unlock(&hdata->hdmi_mutex); |
2030 | 2036 | ||
2031 | pm_runtime_get_sync(hdata->dev); | 2037 | pm_runtime_get_sync(hdata->dev); |
@@ -2061,8 +2067,6 @@ static void hdmi_poweroff(struct hdmi_context *hdata) | |||
2061 | pm_runtime_put_sync(hdata->dev); | 2067 | pm_runtime_put_sync(hdata->dev); |
2062 | 2068 | ||
2063 | mutex_lock(&hdata->hdmi_mutex); | 2069 | mutex_lock(&hdata->hdmi_mutex); |
2064 | if (hdata->cfg_hpd) | ||
2065 | hdata->cfg_hpd(false); | ||
2066 | 2070 | ||
2067 | hdata->powered = false; | 2071 | hdata->powered = false; |
2068 | 2072 | ||
@@ -2110,17 +2114,13 @@ static irqreturn_t hdmi_external_irq_thread(int irq, void *arg) | |||
2110 | struct exynos_drm_hdmi_context *ctx = arg; | 2114 | struct exynos_drm_hdmi_context *ctx = arg; |
2111 | struct hdmi_context *hdata = ctx->ctx; | 2115 | struct hdmi_context *hdata = ctx->ctx; |
2112 | 2116 | ||
2113 | if (!hdata->get_hpd) | ||
2114 | goto out; | ||
2115 | |||
2116 | mutex_lock(&hdata->hdmi_mutex); | 2117 | mutex_lock(&hdata->hdmi_mutex); |
2117 | hdata->hpd = hdata->get_hpd(); | 2118 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); |
2118 | mutex_unlock(&hdata->hdmi_mutex); | 2119 | mutex_unlock(&hdata->hdmi_mutex); |
2119 | 2120 | ||
2120 | if (ctx->drm_dev) | 2121 | if (ctx->drm_dev) |
2121 | drm_helper_hpd_irq_event(ctx->drm_dev); | 2122 | drm_helper_hpd_irq_event(ctx->drm_dev); |
2122 | 2123 | ||
2123 | out: | ||
2124 | return IRQ_HANDLED; | 2124 | return IRQ_HANDLED; |
2125 | } | 2125 | } |
2126 | 2126 | ||
@@ -2143,18 +2143,9 @@ static irqreturn_t hdmi_internal_irq_thread(int irq, void *arg) | |||
2143 | HDMI_INTC_FLAG_HPD_PLUG); | 2143 | HDMI_INTC_FLAG_HPD_PLUG); |
2144 | } | 2144 | } |
2145 | 2145 | ||
2146 | mutex_lock(&hdata->hdmi_mutex); | ||
2147 | hdata->hpd = hdmi_reg_read(hdata, HDMI_HPD_STATUS); | ||
2148 | if (hdata->powered && hdata->hpd) { | ||
2149 | mutex_unlock(&hdata->hdmi_mutex); | ||
2150 | goto out; | ||
2151 | } | ||
2152 | mutex_unlock(&hdata->hdmi_mutex); | ||
2153 | |||
2154 | if (ctx->drm_dev) | 2146 | if (ctx->drm_dev) |
2155 | drm_helper_hpd_irq_event(ctx->drm_dev); | 2147 | drm_helper_hpd_irq_event(ctx->drm_dev); |
2156 | 2148 | ||
2157 | out: | ||
2158 | return IRQ_HANDLED; | 2149 | return IRQ_HANDLED; |
2159 | } | 2150 | } |
2160 | 2151 | ||
@@ -2262,18 +2253,89 @@ void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy) | |||
2262 | hdmi_hdmiphy = hdmiphy; | 2253 | hdmi_hdmiphy = hdmiphy; |
2263 | } | 2254 | } |
2264 | 2255 | ||
2256 | #ifdef CONFIG_OF | ||
2257 | static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata | ||
2258 | (struct device *dev) | ||
2259 | { | ||
2260 | struct device_node *np = dev->of_node; | ||
2261 | struct s5p_hdmi_platform_data *pd; | ||
2262 | enum of_gpio_flags flags; | ||
2263 | u32 value; | ||
2264 | |||
2265 | pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); | ||
2266 | if (!pd) { | ||
2267 | DRM_ERROR("memory allocation for pdata failed\n"); | ||
2268 | goto err_data; | ||
2269 | } | ||
2270 | |||
2271 | if (!of_find_property(np, "hpd-gpio", &value)) { | ||
2272 | DRM_ERROR("no hpd gpio property found\n"); | ||
2273 | goto err_data; | ||
2274 | } | ||
2275 | |||
2276 | pd->hpd_gpio = of_get_named_gpio_flags(np, "hpd-gpio", 0, &flags); | ||
2277 | |||
2278 | return pd; | ||
2279 | |||
2280 | err_data: | ||
2281 | return NULL; | ||
2282 | } | ||
2283 | #else | ||
2284 | static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata | ||
2285 | (struct device *dev) | ||
2286 | { | ||
2287 | return NULL; | ||
2288 | } | ||
2289 | #endif | ||
2290 | |||
2291 | static struct platform_device_id hdmi_driver_types[] = { | ||
2292 | { | ||
2293 | .name = "s5pv210-hdmi", | ||
2294 | .driver_data = HDMI_TYPE13, | ||
2295 | }, { | ||
2296 | .name = "exynos4-hdmi", | ||
2297 | .driver_data = HDMI_TYPE13, | ||
2298 | }, { | ||
2299 | .name = "exynos4-hdmi14", | ||
2300 | .driver_data = HDMI_TYPE14, | ||
2301 | }, { | ||
2302 | .name = "exynos5-hdmi", | ||
2303 | .driver_data = HDMI_TYPE14, | ||
2304 | }, { | ||
2305 | /* end node */ | ||
2306 | } | ||
2307 | }; | ||
2308 | |||
2309 | static struct of_device_id hdmi_match_types[] = { | ||
2310 | { | ||
2311 | .compatible = "samsung,exynos5-hdmi", | ||
2312 | .data = (void *)HDMI_TYPE14, | ||
2313 | }, { | ||
2314 | /* end node */ | ||
2315 | } | ||
2316 | }; | ||
2317 | |||
2265 | static int __devinit hdmi_probe(struct platform_device *pdev) | 2318 | static int __devinit hdmi_probe(struct platform_device *pdev) |
2266 | { | 2319 | { |
2267 | struct device *dev = &pdev->dev; | 2320 | struct device *dev = &pdev->dev; |
2268 | struct exynos_drm_hdmi_context *drm_hdmi_ctx; | 2321 | struct exynos_drm_hdmi_context *drm_hdmi_ctx; |
2269 | struct hdmi_context *hdata; | 2322 | struct hdmi_context *hdata; |
2270 | struct exynos_drm_hdmi_pdata *pdata; | 2323 | struct s5p_hdmi_platform_data *pdata; |
2271 | struct resource *res; | 2324 | struct resource *res; |
2272 | int ret; | 2325 | int ret; |
2273 | 2326 | ||
2274 | DRM_DEBUG_KMS("[%d]\n", __LINE__); | 2327 | DRM_DEBUG_KMS("[%d]\n", __LINE__); |
2275 | 2328 | ||
2276 | pdata = pdev->dev.platform_data; | 2329 | if (pdev->dev.of_node) { |
2330 | pdata = drm_hdmi_dt_parse_pdata(dev); | ||
2331 | if (IS_ERR(pdata)) { | ||
2332 | DRM_ERROR("failed to parse dt\n"); | ||
2333 | return PTR_ERR(pdata); | ||
2334 | } | ||
2335 | } else { | ||
2336 | pdata = pdev->dev.platform_data; | ||
2337 | } | ||
2338 | |||
2277 | if (!pdata) { | 2339 | if (!pdata) { |
2278 | DRM_ERROR("no platform data specified\n"); | 2340 | DRM_ERROR("no platform data specified\n"); |
2279 | return -EINVAL; | 2341 | return -EINVAL; |
@@ -2300,18 +2362,33 @@ static int __devinit hdmi_probe(struct platform_device *pdev) | |||
2300 | 2362 | ||
2301 | platform_set_drvdata(pdev, drm_hdmi_ctx); | 2363 | platform_set_drvdata(pdev, drm_hdmi_ctx); |
2302 | 2364 | ||
2303 | hdata->is_v13 = pdata->is_v13; | 2365 | if (dev->of_node) { |
2304 | hdata->cfg_hpd = pdata->cfg_hpd; | 2366 | const struct of_device_id *match; |
2305 | hdata->get_hpd = pdata->get_hpd; | 2367 | match = of_match_node(of_match_ptr(hdmi_match_types), |
2368 | pdev->dev.of_node); | ||
2369 | hdata->type = (enum hdmi_type)match->data; | ||
2370 | } else { | ||
2371 | hdata->type = (enum hdmi_type)platform_get_device_id | ||
2372 | (pdev)->driver_data; | ||
2373 | } | ||
2374 | |||
2375 | hdata->hpd_gpio = pdata->hpd_gpio; | ||
2306 | hdata->dev = dev; | 2376 | hdata->dev = dev; |
2307 | 2377 | ||
2308 | ret = hdmi_resources_init(hdata); | 2378 | ret = hdmi_resources_init(hdata); |
2379 | |||
2309 | if (ret) { | 2380 | if (ret) { |
2310 | ret = -EINVAL; | 2381 | ret = -EINVAL; |
2382 | DRM_ERROR("hdmi_resources_init failed\n"); | ||
2311 | goto err_data; | 2383 | goto err_data; |
2312 | } | 2384 | } |
2313 | 2385 | ||
2314 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 2386 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
2387 | if (!res) { | ||
2388 | DRM_ERROR("failed to find registers\n"); | ||
2389 | ret = -ENOENT; | ||
2390 | goto err_resource; | ||
2391 | } | ||
2315 | 2392 | ||
2316 | hdata->regs = devm_request_and_ioremap(&pdev->dev, res); | 2393 | hdata->regs = devm_request_and_ioremap(&pdev->dev, res); |
2317 | if (!hdata->regs) { | 2394 | if (!hdata->regs) { |
@@ -2320,11 +2397,17 @@ static int __devinit hdmi_probe(struct platform_device *pdev) | |||
2320 | goto err_resource; | 2397 | goto err_resource; |
2321 | } | 2398 | } |
2322 | 2399 | ||
2400 | ret = gpio_request(hdata->hpd_gpio, "HPD"); | ||
2401 | if (ret) { | ||
2402 | DRM_ERROR("failed to request HPD gpio\n"); | ||
2403 | goto err_resource; | ||
2404 | } | ||
2405 | |||
2323 | /* DDC i2c driver */ | 2406 | /* DDC i2c driver */ |
2324 | if (i2c_add_driver(&ddc_driver)) { | 2407 | if (i2c_add_driver(&ddc_driver)) { |
2325 | DRM_ERROR("failed to register ddc i2c driver\n"); | 2408 | DRM_ERROR("failed to register ddc i2c driver\n"); |
2326 | ret = -ENOENT; | 2409 | ret = -ENOENT; |
2327 | goto err_resource; | 2410 | goto err_gpio; |
2328 | } | 2411 | } |
2329 | 2412 | ||
2330 | hdata->ddc_port = hdmi_ddc; | 2413 | hdata->ddc_port = hdmi_ddc; |
@@ -2338,32 +2421,31 @@ static int __devinit hdmi_probe(struct platform_device *pdev) | |||
2338 | 2421 | ||
2339 | hdata->hdmiphy_port = hdmi_hdmiphy; | 2422 | hdata->hdmiphy_port = hdmi_hdmiphy; |
2340 | 2423 | ||
2341 | hdata->external_irq = platform_get_irq_byname(pdev, "external_irq"); | 2424 | hdata->external_irq = gpio_to_irq(hdata->hpd_gpio); |
2342 | if (hdata->external_irq < 0) { | 2425 | if (hdata->external_irq < 0) { |
2343 | DRM_ERROR("failed to get platform irq\n"); | 2426 | DRM_ERROR("failed to get GPIO external irq\n"); |
2344 | ret = hdata->external_irq; | 2427 | ret = hdata->external_irq; |
2345 | goto err_hdmiphy; | 2428 | goto err_hdmiphy; |
2346 | } | 2429 | } |
2347 | 2430 | ||
2348 | hdata->internal_irq = platform_get_irq_byname(pdev, "internal_irq"); | 2431 | hdata->internal_irq = platform_get_irq(pdev, 0); |
2349 | if (hdata->internal_irq < 0) { | 2432 | if (hdata->internal_irq < 0) { |
2350 | DRM_ERROR("failed to get platform internal irq\n"); | 2433 | DRM_ERROR("failed to get platform internal irq\n"); |
2351 | ret = hdata->internal_irq; | 2434 | ret = hdata->internal_irq; |
2352 | goto err_hdmiphy; | 2435 | goto err_hdmiphy; |
2353 | } | 2436 | } |
2354 | 2437 | ||
2438 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); | ||
2439 | |||
2355 | ret = request_threaded_irq(hdata->external_irq, NULL, | 2440 | ret = request_threaded_irq(hdata->external_irq, NULL, |
2356 | hdmi_external_irq_thread, IRQF_TRIGGER_RISING | | 2441 | hdmi_external_irq_thread, IRQF_TRIGGER_RISING | |
2357 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 2442 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
2358 | "hdmi_external", drm_hdmi_ctx); | 2443 | "hdmi_external", drm_hdmi_ctx); |
2359 | if (ret) { | 2444 | if (ret) { |
2360 | DRM_ERROR("failed to register hdmi internal interrupt\n"); | 2445 | DRM_ERROR("failed to register hdmi external interrupt\n"); |
2361 | goto err_hdmiphy; | 2446 | goto err_hdmiphy; |
2362 | } | 2447 | } |
2363 | 2448 | ||
2364 | if (hdata->cfg_hpd) | ||
2365 | hdata->cfg_hpd(false); | ||
2366 | |||
2367 | ret = request_threaded_irq(hdata->internal_irq, NULL, | 2449 | ret = request_threaded_irq(hdata->internal_irq, NULL, |
2368 | hdmi_internal_irq_thread, IRQF_ONESHOT, | 2450 | hdmi_internal_irq_thread, IRQF_ONESHOT, |
2369 | "hdmi_internal", drm_hdmi_ctx); | 2451 | "hdmi_internal", drm_hdmi_ctx); |
@@ -2372,6 +2454,9 @@ static int __devinit hdmi_probe(struct platform_device *pdev) | |||
2372 | goto err_free_irq; | 2454 | goto err_free_irq; |
2373 | } | 2455 | } |
2374 | 2456 | ||
2457 | /* Attach HDMI Driver to common hdmi. */ | ||
2458 | exynos_hdmi_drv_attach(drm_hdmi_ctx); | ||
2459 | |||
2375 | /* register specific callbacks to common hdmi. */ | 2460 | /* register specific callbacks to common hdmi. */ |
2376 | exynos_hdmi_ops_register(&hdmi_ops); | 2461 | exynos_hdmi_ops_register(&hdmi_ops); |
2377 | 2462 | ||
@@ -2385,6 +2470,8 @@ err_hdmiphy: | |||
2385 | i2c_del_driver(&hdmiphy_driver); | 2470 | i2c_del_driver(&hdmiphy_driver); |
2386 | err_ddc: | 2471 | err_ddc: |
2387 | i2c_del_driver(&ddc_driver); | 2472 | i2c_del_driver(&ddc_driver); |
2473 | err_gpio: | ||
2474 | gpio_free(hdata->hpd_gpio); | ||
2388 | err_resource: | 2475 | err_resource: |
2389 | hdmi_resources_cleanup(hdata); | 2476 | hdmi_resources_cleanup(hdata); |
2390 | err_data: | 2477 | err_data: |
@@ -2402,6 +2489,9 @@ static int __devexit hdmi_remove(struct platform_device *pdev) | |||
2402 | pm_runtime_disable(dev); | 2489 | pm_runtime_disable(dev); |
2403 | 2490 | ||
2404 | free_irq(hdata->internal_irq, hdata); | 2491 | free_irq(hdata->internal_irq, hdata); |
2492 | free_irq(hdata->external_irq, hdata); | ||
2493 | |||
2494 | gpio_free(hdata->hpd_gpio); | ||
2405 | 2495 | ||
2406 | hdmi_resources_cleanup(hdata); | 2496 | hdmi_resources_cleanup(hdata); |
2407 | 2497 | ||
@@ -2447,9 +2537,11 @@ static SIMPLE_DEV_PM_OPS(hdmi_pm_ops, hdmi_suspend, hdmi_resume); | |||
2447 | struct platform_driver hdmi_driver = { | 2537 | struct platform_driver hdmi_driver = { |
2448 | .probe = hdmi_probe, | 2538 | .probe = hdmi_probe, |
2449 | .remove = __devexit_p(hdmi_remove), | 2539 | .remove = __devexit_p(hdmi_remove), |
2540 | .id_table = hdmi_driver_types, | ||
2450 | .driver = { | 2541 | .driver = { |
2451 | .name = "exynos4-hdmi", | 2542 | .name = "exynos-hdmi", |
2452 | .owner = THIS_MODULE, | 2543 | .owner = THIS_MODULE, |
2453 | .pm = &hdmi_pm_ops, | 2544 | .pm = &hdmi_pm_ops, |
2545 | .of_match_table = hdmi_match_types, | ||
2454 | }, | 2546 | }, |
2455 | }; | 2547 | }; |
diff --git a/drivers/gpu/drm/exynos/exynos_hdmiphy.c b/drivers/gpu/drm/exynos/exynos_hdmiphy.c index 0a8162b7de3d..27d1720f1bbd 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmiphy.c +++ b/drivers/gpu/drm/exynos/exynos_hdmiphy.c | |||
@@ -42,13 +42,23 @@ static int hdmiphy_remove(struct i2c_client *client) | |||
42 | 42 | ||
43 | static const struct i2c_device_id hdmiphy_id[] = { | 43 | static const struct i2c_device_id hdmiphy_id[] = { |
44 | { "s5p_hdmiphy", 0 }, | 44 | { "s5p_hdmiphy", 0 }, |
45 | { "exynos5-hdmiphy", 0 }, | ||
45 | { }, | 46 | { }, |
46 | }; | 47 | }; |
47 | 48 | ||
49 | static struct of_device_id hdmiphy_match_types[] = { | ||
50 | { | ||
51 | .compatible = "samsung,exynos5-hdmiphy", | ||
52 | }, { | ||
53 | /* end node */ | ||
54 | } | ||
55 | }; | ||
56 | |||
48 | struct i2c_driver hdmiphy_driver = { | 57 | struct i2c_driver hdmiphy_driver = { |
49 | .driver = { | 58 | .driver = { |
50 | .name = "s5p-hdmiphy", | 59 | .name = "exynos-hdmiphy", |
51 | .owner = THIS_MODULE, | 60 | .owner = THIS_MODULE, |
61 | .of_match_table = hdmiphy_match_types, | ||
52 | }, | 62 | }, |
53 | .id_table = hdmiphy_id, | 63 | .id_table = hdmiphy_id, |
54 | .probe = hdmiphy_probe, | 64 | .probe = hdmiphy_probe, |
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index e6098f247a5d..614b2e9ac462 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
@@ -73,16 +73,28 @@ struct mixer_resources { | |||
73 | struct clk *sclk_dac; | 73 | struct clk *sclk_dac; |
74 | }; | 74 | }; |
75 | 75 | ||
76 | enum mixer_version_id { | ||
77 | MXR_VER_0_0_0_16, | ||
78 | MXR_VER_16_0_33_0, | ||
79 | }; | ||
80 | |||
76 | struct mixer_context { | 81 | struct mixer_context { |
77 | struct device *dev; | 82 | struct device *dev; |
78 | int pipe; | 83 | int pipe; |
79 | bool interlace; | 84 | bool interlace; |
80 | bool powered; | 85 | bool powered; |
86 | bool vp_enabled; | ||
81 | u32 int_en; | 87 | u32 int_en; |
82 | 88 | ||
83 | struct mutex mixer_mutex; | 89 | struct mutex mixer_mutex; |
84 | struct mixer_resources mixer_res; | 90 | struct mixer_resources mixer_res; |
85 | struct hdmi_win_data win_data[MIXER_WIN_NR]; | 91 | struct hdmi_win_data win_data[MIXER_WIN_NR]; |
92 | enum mixer_version_id mxr_ver; | ||
93 | }; | ||
94 | |||
95 | struct mixer_drv_data { | ||
96 | enum mixer_version_id version; | ||
97 | bool is_vp_enabled; | ||
86 | }; | 98 | }; |
87 | 99 | ||
88 | static const u8 filter_y_horiz_tap8[] = { | 100 | static const u8 filter_y_horiz_tap8[] = { |
@@ -251,7 +263,8 @@ static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable) | |||
251 | mixer_reg_writemask(res, MXR_STATUS, enable ? | 263 | mixer_reg_writemask(res, MXR_STATUS, enable ? |
252 | MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE); | 264 | MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE); |
253 | 265 | ||
254 | vp_reg_write(res, VP_SHADOW_UPDATE, enable ? | 266 | if (ctx->vp_enabled) |
267 | vp_reg_write(res, VP_SHADOW_UPDATE, enable ? | ||
255 | VP_SHADOW_UPDATE_ENABLE : 0); | 268 | VP_SHADOW_UPDATE_ENABLE : 0); |
256 | } | 269 | } |
257 | 270 | ||
@@ -333,8 +346,11 @@ static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable) | |||
333 | mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE); | 346 | mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE); |
334 | break; | 347 | break; |
335 | case 2: | 348 | case 2: |
336 | vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON); | 349 | if (ctx->vp_enabled) { |
337 | mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_VP_ENABLE); | 350 | vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON); |
351 | mixer_reg_writemask(res, MXR_CFG, val, | ||
352 | MXR_CFG_VP_ENABLE); | ||
353 | } | ||
338 | break; | 354 | break; |
339 | } | 355 | } |
340 | } | 356 | } |
@@ -465,6 +481,18 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) | |||
465 | vp_regs_dump(ctx); | 481 | vp_regs_dump(ctx); |
466 | } | 482 | } |
467 | 483 | ||
484 | static void mixer_layer_update(struct mixer_context *ctx) | ||
485 | { | ||
486 | struct mixer_resources *res = &ctx->mixer_res; | ||
487 | u32 val; | ||
488 | |||
489 | val = mixer_reg_read(res, MXR_CFG); | ||
490 | |||
491 | /* allow one update per vsync only */ | ||
492 | if (!(val & MXR_CFG_LAYER_UPDATE_COUNT_MASK)) | ||
493 | mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE); | ||
494 | } | ||
495 | |||
468 | static void mixer_graph_buffer(struct mixer_context *ctx, int win) | 496 | static void mixer_graph_buffer(struct mixer_context *ctx, int win) |
469 | { | 497 | { |
470 | struct mixer_resources *res = &ctx->mixer_res; | 498 | struct mixer_resources *res = &ctx->mixer_res; |
@@ -545,6 +573,11 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) | |||
545 | mixer_cfg_scan(ctx, win_data->mode_height); | 573 | mixer_cfg_scan(ctx, win_data->mode_height); |
546 | mixer_cfg_rgb_fmt(ctx, win_data->mode_height); | 574 | mixer_cfg_rgb_fmt(ctx, win_data->mode_height); |
547 | mixer_cfg_layer(ctx, win, true); | 575 | mixer_cfg_layer(ctx, win, true); |
576 | |||
577 | /* layer update mandatory for mixer 16.0.33.0 */ | ||
578 | if (ctx->mxr_ver == MXR_VER_16_0_33_0) | ||
579 | mixer_layer_update(ctx); | ||
580 | |||
548 | mixer_run(ctx); | 581 | mixer_run(ctx); |
549 | 582 | ||
550 | mixer_vsync_set_update(ctx, true); | 583 | mixer_vsync_set_update(ctx, true); |
@@ -592,7 +625,8 @@ static void mixer_win_reset(struct mixer_context *ctx) | |||
592 | */ | 625 | */ |
593 | val = MXR_LAYER_CFG_GRP1_VAL(3); | 626 | val = MXR_LAYER_CFG_GRP1_VAL(3); |
594 | val |= MXR_LAYER_CFG_GRP0_VAL(2); | 627 | val |= MXR_LAYER_CFG_GRP0_VAL(2); |
595 | val |= MXR_LAYER_CFG_VP_VAL(1); | 628 | if (ctx->vp_enabled) |
629 | val |= MXR_LAYER_CFG_VP_VAL(1); | ||
596 | mixer_reg_write(res, MXR_LAYER_CFG, val); | 630 | mixer_reg_write(res, MXR_LAYER_CFG, val); |
597 | 631 | ||
598 | /* setting background color */ | 632 | /* setting background color */ |
@@ -615,14 +649,17 @@ static void mixer_win_reset(struct mixer_context *ctx) | |||
615 | val = MXR_GRP_CFG_ALPHA_VAL(0); | 649 | val = MXR_GRP_CFG_ALPHA_VAL(0); |
616 | mixer_reg_write(res, MXR_VIDEO_CFG, val); | 650 | mixer_reg_write(res, MXR_VIDEO_CFG, val); |
617 | 651 | ||
618 | /* configuration of Video Processor Registers */ | 652 | if (ctx->vp_enabled) { |
619 | vp_win_reset(ctx); | 653 | /* configuration of Video Processor Registers */ |
620 | vp_default_filter(res); | 654 | vp_win_reset(ctx); |
655 | vp_default_filter(res); | ||
656 | } | ||
621 | 657 | ||
622 | /* disable all layers */ | 658 | /* disable all layers */ |
623 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE); | 659 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE); |
624 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE); | 660 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE); |
625 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE); | 661 | if (ctx->vp_enabled) |
662 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE); | ||
626 | 663 | ||
627 | mixer_vsync_set_update(ctx, true); | 664 | mixer_vsync_set_update(ctx, true); |
628 | spin_unlock_irqrestore(&res->reg_slock, flags); | 665 | spin_unlock_irqrestore(&res->reg_slock, flags); |
@@ -645,8 +682,10 @@ static void mixer_poweron(struct mixer_context *ctx) | |||
645 | pm_runtime_get_sync(ctx->dev); | 682 | pm_runtime_get_sync(ctx->dev); |
646 | 683 | ||
647 | clk_enable(res->mixer); | 684 | clk_enable(res->mixer); |
648 | clk_enable(res->vp); | 685 | if (ctx->vp_enabled) { |
649 | clk_enable(res->sclk_mixer); | 686 | clk_enable(res->vp); |
687 | clk_enable(res->sclk_mixer); | ||
688 | } | ||
650 | 689 | ||
651 | mixer_reg_write(res, MXR_INT_EN, ctx->int_en); | 690 | mixer_reg_write(res, MXR_INT_EN, ctx->int_en); |
652 | mixer_win_reset(ctx); | 691 | mixer_win_reset(ctx); |
@@ -666,8 +705,10 @@ static void mixer_poweroff(struct mixer_context *ctx) | |||
666 | ctx->int_en = mixer_reg_read(res, MXR_INT_EN); | 705 | ctx->int_en = mixer_reg_read(res, MXR_INT_EN); |
667 | 706 | ||
668 | clk_disable(res->mixer); | 707 | clk_disable(res->mixer); |
669 | clk_disable(res->vp); | 708 | if (ctx->vp_enabled) { |
670 | clk_disable(res->sclk_mixer); | 709 | clk_disable(res->vp); |
710 | clk_disable(res->sclk_mixer); | ||
711 | } | ||
671 | 712 | ||
672 | pm_runtime_put_sync(ctx->dev); | 713 | pm_runtime_put_sync(ctx->dev); |
673 | 714 | ||
@@ -726,6 +767,18 @@ static void mixer_dpms(void *ctx, int mode) | |||
726 | } | 767 | } |
727 | } | 768 | } |
728 | 769 | ||
770 | static void mixer_wait_for_vblank(void *ctx) | ||
771 | { | ||
772 | struct mixer_context *mixer_ctx = ctx; | ||
773 | struct mixer_resources *res = &mixer_ctx->mixer_res; | ||
774 | int ret; | ||
775 | |||
776 | ret = wait_for((mixer_reg_read(res, MXR_INT_STATUS) & | ||
777 | MXR_INT_STATUS_VSYNC), 50); | ||
778 | if (ret < 0) | ||
779 | DRM_DEBUG_KMS("vblank wait timed out.\n"); | ||
780 | } | ||
781 | |||
729 | static void mixer_win_mode_set(void *ctx, | 782 | static void mixer_win_mode_set(void *ctx, |
730 | struct exynos_drm_overlay *overlay) | 783 | struct exynos_drm_overlay *overlay) |
731 | { | 784 | { |
@@ -788,7 +841,7 @@ static void mixer_win_commit(void *ctx, int win) | |||
788 | 841 | ||
789 | DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); | 842 | DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); |
790 | 843 | ||
791 | if (win > 1) | 844 | if (win > 1 && mixer_ctx->vp_enabled) |
792 | vp_video_buffer(mixer_ctx, win); | 845 | vp_video_buffer(mixer_ctx, win); |
793 | else | 846 | else |
794 | mixer_graph_buffer(mixer_ctx, win); | 847 | mixer_graph_buffer(mixer_ctx, win); |
@@ -818,6 +871,7 @@ static struct exynos_mixer_ops mixer_ops = { | |||
818 | .dpms = mixer_dpms, | 871 | .dpms = mixer_dpms, |
819 | 872 | ||
820 | /* overlay */ | 873 | /* overlay */ |
874 | .wait_for_vblank = mixer_wait_for_vblank, | ||
821 | .win_mode_set = mixer_win_mode_set, | 875 | .win_mode_set = mixer_win_mode_set, |
822 | .win_commit = mixer_win_commit, | 876 | .win_commit = mixer_win_commit, |
823 | .win_disable = mixer_win_disable, | 877 | .win_disable = mixer_win_disable, |
@@ -923,39 +977,20 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx, | |||
923 | ret = -ENODEV; | 977 | ret = -ENODEV; |
924 | goto fail; | 978 | goto fail; |
925 | } | 979 | } |
926 | mixer_res->vp = clk_get(dev, "vp"); | 980 | |
927 | if (IS_ERR_OR_NULL(mixer_res->vp)) { | ||
928 | dev_err(dev, "failed to get clock 'vp'\n"); | ||
929 | ret = -ENODEV; | ||
930 | goto fail; | ||
931 | } | ||
932 | mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer"); | ||
933 | if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) { | ||
934 | dev_err(dev, "failed to get clock 'sclk_mixer'\n"); | ||
935 | ret = -ENODEV; | ||
936 | goto fail; | ||
937 | } | ||
938 | mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi"); | 981 | mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi"); |
939 | if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) { | 982 | if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) { |
940 | dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); | 983 | dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); |
941 | ret = -ENODEV; | 984 | ret = -ENODEV; |
942 | goto fail; | 985 | goto fail; |
943 | } | 986 | } |
944 | mixer_res->sclk_dac = clk_get(dev, "sclk_dac"); | 987 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
945 | if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) { | ||
946 | dev_err(dev, "failed to get clock 'sclk_dac'\n"); | ||
947 | ret = -ENODEV; | ||
948 | goto fail; | ||
949 | } | ||
950 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr"); | ||
951 | if (res == NULL) { | 988 | if (res == NULL) { |
952 | dev_err(dev, "get memory resource failed.\n"); | 989 | dev_err(dev, "get memory resource failed.\n"); |
953 | ret = -ENXIO; | 990 | ret = -ENXIO; |
954 | goto fail; | 991 | goto fail; |
955 | } | 992 | } |
956 | 993 | ||
957 | clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi); | ||
958 | |||
959 | mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start, | 994 | mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start, |
960 | resource_size(res)); | 995 | resource_size(res)); |
961 | if (mixer_res->mixer_regs == NULL) { | 996 | if (mixer_res->mixer_regs == NULL) { |
@@ -964,57 +999,126 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx, | |||
964 | goto fail; | 999 | goto fail; |
965 | } | 1000 | } |
966 | 1001 | ||
967 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp"); | 1002 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
968 | if (res == NULL) { | 1003 | if (res == NULL) { |
969 | dev_err(dev, "get memory resource failed.\n"); | 1004 | dev_err(dev, "get interrupt resource failed.\n"); |
970 | ret = -ENXIO; | 1005 | ret = -ENXIO; |
971 | goto fail; | 1006 | goto fail; |
972 | } | 1007 | } |
973 | 1008 | ||
974 | mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start, | 1009 | ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler, |
975 | resource_size(res)); | 1010 | 0, "drm_mixer", ctx); |
976 | if (mixer_res->vp_regs == NULL) { | 1011 | if (ret) { |
977 | dev_err(dev, "register mapping failed.\n"); | 1012 | dev_err(dev, "request interrupt failed.\n"); |
978 | ret = -ENXIO; | ||
979 | goto fail; | 1013 | goto fail; |
980 | } | 1014 | } |
1015 | mixer_res->irq = res->start; | ||
1016 | |||
1017 | return 0; | ||
981 | 1018 | ||
982 | res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq"); | 1019 | fail: |
1020 | if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) | ||
1021 | clk_put(mixer_res->sclk_hdmi); | ||
1022 | if (!IS_ERR_OR_NULL(mixer_res->mixer)) | ||
1023 | clk_put(mixer_res->mixer); | ||
1024 | return ret; | ||
1025 | } | ||
1026 | |||
1027 | static int __devinit vp_resources_init(struct exynos_drm_hdmi_context *ctx, | ||
1028 | struct platform_device *pdev) | ||
1029 | { | ||
1030 | struct mixer_context *mixer_ctx = ctx->ctx; | ||
1031 | struct device *dev = &pdev->dev; | ||
1032 | struct mixer_resources *mixer_res = &mixer_ctx->mixer_res; | ||
1033 | struct resource *res; | ||
1034 | int ret; | ||
1035 | |||
1036 | mixer_res->vp = clk_get(dev, "vp"); | ||
1037 | if (IS_ERR_OR_NULL(mixer_res->vp)) { | ||
1038 | dev_err(dev, "failed to get clock 'vp'\n"); | ||
1039 | ret = -ENODEV; | ||
1040 | goto fail; | ||
1041 | } | ||
1042 | mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer"); | ||
1043 | if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) { | ||
1044 | dev_err(dev, "failed to get clock 'sclk_mixer'\n"); | ||
1045 | ret = -ENODEV; | ||
1046 | goto fail; | ||
1047 | } | ||
1048 | mixer_res->sclk_dac = clk_get(dev, "sclk_dac"); | ||
1049 | if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) { | ||
1050 | dev_err(dev, "failed to get clock 'sclk_dac'\n"); | ||
1051 | ret = -ENODEV; | ||
1052 | goto fail; | ||
1053 | } | ||
1054 | |||
1055 | if (mixer_res->sclk_hdmi) | ||
1056 | clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi); | ||
1057 | |||
1058 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
983 | if (res == NULL) { | 1059 | if (res == NULL) { |
984 | dev_err(dev, "get interrupt resource failed.\n"); | 1060 | dev_err(dev, "get memory resource failed.\n"); |
985 | ret = -ENXIO; | 1061 | ret = -ENXIO; |
986 | goto fail; | 1062 | goto fail; |
987 | } | 1063 | } |
988 | 1064 | ||
989 | ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler, | 1065 | mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start, |
990 | 0, "drm_mixer", ctx); | 1066 | resource_size(res)); |
991 | if (ret) { | 1067 | if (mixer_res->vp_regs == NULL) { |
992 | dev_err(dev, "request interrupt failed.\n"); | 1068 | dev_err(dev, "register mapping failed.\n"); |
1069 | ret = -ENXIO; | ||
993 | goto fail; | 1070 | goto fail; |
994 | } | 1071 | } |
995 | mixer_res->irq = res->start; | ||
996 | 1072 | ||
997 | return 0; | 1073 | return 0; |
998 | 1074 | ||
999 | fail: | 1075 | fail: |
1000 | if (!IS_ERR_OR_NULL(mixer_res->sclk_dac)) | 1076 | if (!IS_ERR_OR_NULL(mixer_res->sclk_dac)) |
1001 | clk_put(mixer_res->sclk_dac); | 1077 | clk_put(mixer_res->sclk_dac); |
1002 | if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) | ||
1003 | clk_put(mixer_res->sclk_hdmi); | ||
1004 | if (!IS_ERR_OR_NULL(mixer_res->sclk_mixer)) | 1078 | if (!IS_ERR_OR_NULL(mixer_res->sclk_mixer)) |
1005 | clk_put(mixer_res->sclk_mixer); | 1079 | clk_put(mixer_res->sclk_mixer); |
1006 | if (!IS_ERR_OR_NULL(mixer_res->vp)) | 1080 | if (!IS_ERR_OR_NULL(mixer_res->vp)) |
1007 | clk_put(mixer_res->vp); | 1081 | clk_put(mixer_res->vp); |
1008 | if (!IS_ERR_OR_NULL(mixer_res->mixer)) | ||
1009 | clk_put(mixer_res->mixer); | ||
1010 | return ret; | 1082 | return ret; |
1011 | } | 1083 | } |
1012 | 1084 | ||
1085 | static struct mixer_drv_data exynos5_mxr_drv_data = { | ||
1086 | .version = MXR_VER_16_0_33_0, | ||
1087 | .is_vp_enabled = 0, | ||
1088 | }; | ||
1089 | |||
1090 | static struct mixer_drv_data exynos4_mxr_drv_data = { | ||
1091 | .version = MXR_VER_0_0_0_16, | ||
1092 | .is_vp_enabled = 1, | ||
1093 | }; | ||
1094 | |||
1095 | static struct platform_device_id mixer_driver_types[] = { | ||
1096 | { | ||
1097 | .name = "s5p-mixer", | ||
1098 | .driver_data = (unsigned long)&exynos4_mxr_drv_data, | ||
1099 | }, { | ||
1100 | .name = "exynos5-mixer", | ||
1101 | .driver_data = (unsigned long)&exynos5_mxr_drv_data, | ||
1102 | }, { | ||
1103 | /* end node */ | ||
1104 | } | ||
1105 | }; | ||
1106 | |||
1107 | static struct of_device_id mixer_match_types[] = { | ||
1108 | { | ||
1109 | .compatible = "samsung,exynos5-mixer", | ||
1110 | .data = &exynos5_mxr_drv_data, | ||
1111 | }, { | ||
1112 | /* end node */ | ||
1113 | } | ||
1114 | }; | ||
1115 | |||
1013 | static int __devinit mixer_probe(struct platform_device *pdev) | 1116 | static int __devinit mixer_probe(struct platform_device *pdev) |
1014 | { | 1117 | { |
1015 | struct device *dev = &pdev->dev; | 1118 | struct device *dev = &pdev->dev; |
1016 | struct exynos_drm_hdmi_context *drm_hdmi_ctx; | 1119 | struct exynos_drm_hdmi_context *drm_hdmi_ctx; |
1017 | struct mixer_context *ctx; | 1120 | struct mixer_context *ctx; |
1121 | struct mixer_drv_data *drv; | ||
1018 | int ret; | 1122 | int ret; |
1019 | 1123 | ||
1020 | dev_info(dev, "probe start\n"); | 1124 | dev_info(dev, "probe start\n"); |
@@ -1034,15 +1138,41 @@ static int __devinit mixer_probe(struct platform_device *pdev) | |||
1034 | 1138 | ||
1035 | mutex_init(&ctx->mixer_mutex); | 1139 | mutex_init(&ctx->mixer_mutex); |
1036 | 1140 | ||
1141 | if (dev->of_node) { | ||
1142 | const struct of_device_id *match; | ||
1143 | match = of_match_node(of_match_ptr(mixer_match_types), | ||
1144 | pdev->dev.of_node); | ||
1145 | drv = match->data; | ||
1146 | } else { | ||
1147 | drv = (struct mixer_drv_data *) | ||
1148 | platform_get_device_id(pdev)->driver_data; | ||
1149 | } | ||
1150 | |||
1037 | ctx->dev = &pdev->dev; | 1151 | ctx->dev = &pdev->dev; |
1038 | drm_hdmi_ctx->ctx = (void *)ctx; | 1152 | drm_hdmi_ctx->ctx = (void *)ctx; |
1153 | ctx->vp_enabled = drv->is_vp_enabled; | ||
1154 | ctx->mxr_ver = drv->version; | ||
1039 | 1155 | ||
1040 | platform_set_drvdata(pdev, drm_hdmi_ctx); | 1156 | platform_set_drvdata(pdev, drm_hdmi_ctx); |
1041 | 1157 | ||
1042 | /* acquire resources: regs, irqs, clocks */ | 1158 | /* acquire resources: regs, irqs, clocks */ |
1043 | ret = mixer_resources_init(drm_hdmi_ctx, pdev); | 1159 | ret = mixer_resources_init(drm_hdmi_ctx, pdev); |
1044 | if (ret) | 1160 | if (ret) { |
1161 | DRM_ERROR("mixer_resources_init failed\n"); | ||
1045 | goto fail; | 1162 | goto fail; |
1163 | } | ||
1164 | |||
1165 | if (ctx->vp_enabled) { | ||
1166 | /* acquire vp resources: regs, irqs, clocks */ | ||
1167 | ret = vp_resources_init(drm_hdmi_ctx, pdev); | ||
1168 | if (ret) { | ||
1169 | DRM_ERROR("vp_resources_init failed\n"); | ||
1170 | goto fail; | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | /* attach mixer driver to common hdmi. */ | ||
1175 | exynos_mixer_drv_attach(drm_hdmi_ctx); | ||
1046 | 1176 | ||
1047 | /* register specific callback point to common hdmi. */ | 1177 | /* register specific callback point to common hdmi. */ |
1048 | exynos_mixer_ops_register(&mixer_ops); | 1178 | exynos_mixer_ops_register(&mixer_ops); |
@@ -1082,10 +1212,12 @@ static SIMPLE_DEV_PM_OPS(mixer_pm_ops, mixer_suspend, NULL); | |||
1082 | 1212 | ||
1083 | struct platform_driver mixer_driver = { | 1213 | struct platform_driver mixer_driver = { |
1084 | .driver = { | 1214 | .driver = { |
1085 | .name = "s5p-mixer", | 1215 | .name = "exynos-mixer", |
1086 | .owner = THIS_MODULE, | 1216 | .owner = THIS_MODULE, |
1087 | .pm = &mixer_pm_ops, | 1217 | .pm = &mixer_pm_ops, |
1218 | .of_match_table = mixer_match_types, | ||
1088 | }, | 1219 | }, |
1089 | .probe = mixer_probe, | 1220 | .probe = mixer_probe, |
1090 | .remove = __devexit_p(mixer_remove), | 1221 | .remove = __devexit_p(mixer_remove), |
1222 | .id_table = mixer_driver_types, | ||
1091 | }; | 1223 | }; |
diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h index fd2f4d14cf6d..5d8dbc0301e6 100644 --- a/drivers/gpu/drm/exynos/regs-mixer.h +++ b/drivers/gpu/drm/exynos/regs-mixer.h | |||
@@ -69,6 +69,7 @@ | |||
69 | (((val) << (low_bit)) & MXR_MASK(high_bit, low_bit)) | 69 | (((val) << (low_bit)) & MXR_MASK(high_bit, low_bit)) |
70 | 70 | ||
71 | /* bits for MXR_STATUS */ | 71 | /* bits for MXR_STATUS */ |
72 | #define MXR_STATUS_SOFT_RESET (1 << 8) | ||
72 | #define MXR_STATUS_16_BURST (1 << 7) | 73 | #define MXR_STATUS_16_BURST (1 << 7) |
73 | #define MXR_STATUS_BURST_MASK (1 << 7) | 74 | #define MXR_STATUS_BURST_MASK (1 << 7) |
74 | #define MXR_STATUS_BIG_ENDIAN (1 << 3) | 75 | #define MXR_STATUS_BIG_ENDIAN (1 << 3) |
@@ -77,6 +78,8 @@ | |||
77 | #define MXR_STATUS_REG_RUN (1 << 0) | 78 | #define MXR_STATUS_REG_RUN (1 << 0) |
78 | 79 | ||
79 | /* bits for MXR_CFG */ | 80 | /* bits for MXR_CFG */ |
81 | #define MXR_CFG_LAYER_UPDATE (1 << 31) | ||
82 | #define MXR_CFG_LAYER_UPDATE_COUNT_MASK (3 << 29) | ||
80 | #define MXR_CFG_RGB601_0_255 (0 << 9) | 83 | #define MXR_CFG_RGB601_0_255 (0 << 9) |
81 | #define MXR_CFG_RGB601_16_235 (1 << 9) | 84 | #define MXR_CFG_RGB601_16_235 (1 << 9) |
82 | #define MXR_CFG_RGB709_0_255 (2 << 9) | 85 | #define MXR_CFG_RGB709_0_255 (2 << 9) |