]> Git Repo - linux.git/blob - drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
drm/amd/powerplay: implement sysfs of pp_cur_state function
[linux.git] / drivers / gpu / drm / tinydrm / core / tinydrm-pipe.c
1 /*
2  * Copyright (C) 2016 Noralf Trønnes
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  */
9
10 #include <drm/drm_atomic_helper.h>
11 #include <drm/drm_drv.h>
12 #include <drm/drm_gem_framebuffer_helper.h>
13 #include <drm/drm_modes.h>
14 #include <drm/drm_probe_helper.h>
15 #include <drm/drm_print.h>
16 #include <drm/tinydrm/tinydrm.h>
17
18 struct tinydrm_connector {
19         struct drm_connector base;
20         struct drm_display_mode mode;
21 };
22
23 static inline struct tinydrm_connector *
24 to_tinydrm_connector(struct drm_connector *connector)
25 {
26         return container_of(connector, struct tinydrm_connector, base);
27 }
28
29 static int tinydrm_connector_get_modes(struct drm_connector *connector)
30 {
31         struct tinydrm_connector *tconn = to_tinydrm_connector(connector);
32         struct drm_display_mode *mode;
33
34         mode = drm_mode_duplicate(connector->dev, &tconn->mode);
35         if (!mode) {
36                 DRM_ERROR("Failed to duplicate mode\n");
37                 return 0;
38         }
39
40         if (mode->name[0] == '\0')
41                 drm_mode_set_name(mode);
42
43         mode->type |= DRM_MODE_TYPE_PREFERRED;
44         drm_mode_probed_add(connector, mode);
45
46         if (mode->width_mm) {
47                 connector->display_info.width_mm = mode->width_mm;
48                 connector->display_info.height_mm = mode->height_mm;
49         }
50
51         return 1;
52 }
53
54 static const struct drm_connector_helper_funcs tinydrm_connector_hfuncs = {
55         .get_modes = tinydrm_connector_get_modes,
56 };
57
58 static enum drm_connector_status
59 tinydrm_connector_detect(struct drm_connector *connector, bool force)
60 {
61         if (drm_dev_is_unplugged(connector->dev))
62                 return connector_status_disconnected;
63
64         return connector->status;
65 }
66
67 static void tinydrm_connector_destroy(struct drm_connector *connector)
68 {
69         struct tinydrm_connector *tconn = to_tinydrm_connector(connector);
70
71         drm_connector_cleanup(connector);
72         kfree(tconn);
73 }
74
75 static const struct drm_connector_funcs tinydrm_connector_funcs = {
76         .reset = drm_atomic_helper_connector_reset,
77         .detect = tinydrm_connector_detect,
78         .fill_modes = drm_helper_probe_single_connector_modes,
79         .destroy = tinydrm_connector_destroy,
80         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
81         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
82 };
83
84 struct drm_connector *
85 tinydrm_connector_create(struct drm_device *drm,
86                          const struct drm_display_mode *mode,
87                          int connector_type)
88 {
89         struct tinydrm_connector *tconn;
90         struct drm_connector *connector;
91         int ret;
92
93         tconn = kzalloc(sizeof(*tconn), GFP_KERNEL);
94         if (!tconn)
95                 return ERR_PTR(-ENOMEM);
96
97         drm_mode_copy(&tconn->mode, mode);
98         connector = &tconn->base;
99
100         drm_connector_helper_add(connector, &tinydrm_connector_hfuncs);
101         ret = drm_connector_init(drm, connector, &tinydrm_connector_funcs,
102                                  connector_type);
103         if (ret) {
104                 kfree(tconn);
105                 return ERR_PTR(ret);
106         }
107
108         connector->status = connector_status_connected;
109
110         return connector;
111 }
112
113 static int tinydrm_rotate_mode(struct drm_display_mode *mode,
114                                unsigned int rotation)
115 {
116         if (rotation == 0 || rotation == 180) {
117                 return 0;
118         } else if (rotation == 90 || rotation == 270) {
119                 swap(mode->hdisplay, mode->vdisplay);
120                 swap(mode->hsync_start, mode->vsync_start);
121                 swap(mode->hsync_end, mode->vsync_end);
122                 swap(mode->htotal, mode->vtotal);
123                 swap(mode->width_mm, mode->height_mm);
124                 return 0;
125         } else {
126                 return -EINVAL;
127         }
128 }
129
130 /**
131  * tinydrm_display_pipe_init - Initialize display pipe
132  * @tdev: tinydrm device
133  * @funcs: Display pipe functions
134  * @connector_type: Connector type
135  * @formats: Array of supported formats (DRM_FORMAT\_\*)
136  * @format_count: Number of elements in @formats
137  * @mode: Supported mode
138  * @rotation: Initial @mode rotation in degrees Counter Clock Wise
139  *
140  * This function sets up a &drm_simple_display_pipe with a &drm_connector that
141  * has one fixed &drm_display_mode which is rotated according to @rotation.
142  *
143  * Returns:
144  * Zero on success, negative error code on failure.
145  */
146 int
147 tinydrm_display_pipe_init(struct tinydrm_device *tdev,
148                           const struct drm_simple_display_pipe_funcs *funcs,
149                           int connector_type,
150                           const uint32_t *formats,
151                           unsigned int format_count,
152                           const struct drm_display_mode *mode,
153                           unsigned int rotation)
154 {
155         struct drm_device *drm = tdev->drm;
156         struct drm_display_mode mode_copy;
157         struct drm_connector *connector;
158         int ret;
159         static const uint64_t modifiers[] = {
160                 DRM_FORMAT_MOD_LINEAR,
161                 DRM_FORMAT_MOD_INVALID
162         };
163
164         drm_mode_copy(&mode_copy, mode);
165         ret = tinydrm_rotate_mode(&mode_copy, rotation);
166         if (ret) {
167                 DRM_ERROR("Illegal rotation value %u\n", rotation);
168                 return -EINVAL;
169         }
170
171         drm->mode_config.min_width = mode_copy.hdisplay;
172         drm->mode_config.max_width = mode_copy.hdisplay;
173         drm->mode_config.min_height = mode_copy.vdisplay;
174         drm->mode_config.max_height = mode_copy.vdisplay;
175
176         connector = tinydrm_connector_create(drm, &mode_copy, connector_type);
177         if (IS_ERR(connector))
178                 return PTR_ERR(connector);
179
180         return drm_simple_display_pipe_init(drm, &tdev->pipe, funcs, formats,
181                                             format_count, modifiers, connector);
182 }
183 EXPORT_SYMBOL(tinydrm_display_pipe_init);
This page took 0.044432 seconds and 4 git commands to generate.