aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorInki Dae <inki.dae@samsung.com>2012-03-16 05:47:04 -0400
committerDave Airlie <airlied@redhat.com>2012-03-20 05:40:21 -0400
commit1de425b0bdbc457dbd4a012760da4a3f204d0ab3 (patch)
treea86771193cec405ac212de6f0c6f3892a7a5530d /drivers/gpu
parent3ecd70b18cad5a5e04981f2a1d71e183f5d6ebc0 (diff)
drm/exynos: added mode_fixup feature and code clean.
this patch adds mode_fixup feature for hdmi module that specific driver changes current mode to driver desired mode properly. Signed-off-by: Inki Dae <inki.dae@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_connector.c25
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_encoder.c17
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.c28
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.h5
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c81
7 files changed, 157 insertions, 13 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 618bd4d87d28..ebdd71d50685 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -225,6 +225,29 @@ static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
225 .best_encoder = exynos_drm_best_encoder, 225 .best_encoder = exynos_drm_best_encoder,
226}; 226};
227 227
228static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
229 unsigned int max_width, unsigned int max_height)
230{
231 struct exynos_drm_connector *exynos_connector =
232 to_exynos_connector(connector);
233 struct exynos_drm_manager *manager = exynos_connector->manager;
234 struct exynos_drm_manager_ops *ops = manager->ops;
235 unsigned int width, height;
236
237 width = max_width;
238 height = max_height;
239
240 /*
241 * if specific driver want to find desired_mode using maxmum
242 * resolution then get max width and height from that driver.
243 */
244 if (ops && ops->get_max_resol)
245 ops->get_max_resol(manager->dev, &width, &height);
246
247 return drm_helper_probe_single_connector_modes(connector, width,
248 height);
249}
250
228/* get detection status of display device. */ 251/* get detection status of display device. */
229static enum drm_connector_status 252static enum drm_connector_status
230exynos_drm_connector_detect(struct drm_connector *connector, bool force) 253exynos_drm_connector_detect(struct drm_connector *connector, bool force)
@@ -262,7 +285,7 @@ static void exynos_drm_connector_destroy(struct drm_connector *connector)
262 285
263static struct drm_connector_funcs exynos_connector_funcs = { 286static struct drm_connector_funcs exynos_connector_funcs = {
264 .dpms = drm_helper_connector_dpms, 287 .dpms = drm_helper_connector_dpms,
265 .fill_modes = drm_helper_probe_single_connector_modes, 288 .fill_modes = exynos_drm_connector_fill_modes,
266 .detect = exynos_drm_connector_detect, 289 .detect = exynos_drm_connector_detect,
267 .destroy = exynos_drm_connector_destroy, 290 .destroy = exynos_drm_connector_destroy,
268}; 291};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index de818831a511..2d9a0e630d7f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -249,7 +249,11 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
249{ 249{
250 DRM_DEBUG_KMS("%s\n", __FILE__); 250 DRM_DEBUG_KMS("%s\n", __FILE__);
251 251
252 mode = adjusted_mode; 252 /*
253 * copy the mode data adjusted by mode_fixup() into crtc->mode
254 * so that hardware can be seet to proper mode.
255 */
256 memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
253 257
254 return exynos_drm_crtc_update(crtc); 258 return exynos_drm_crtc_update(crtc);
255} 259}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 13540de90bfc..4115a9f61d21 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -155,8 +155,10 @@ struct exynos_drm_display_ops {
155 * 155 *
156 * @dpms: control device power. 156 * @dpms: control device power.
157 * @apply: set timing, vblank and overlay data to registers. 157 * @apply: set timing, vblank and overlay data to registers.
158 * @mode_fixup: fix mode data comparing to hw specific display mode.
158 * @mode_set: convert drm_display_mode to hw specific display mode and 159 * @mode_set: convert drm_display_mode to hw specific display mode and
159 * would be called by encoder->mode_set(). 160 * would be called by encoder->mode_set().
161 * @get_max_resol: get maximum resolution to specific hardware.
160 * @commit: set current hw specific display mode to hw. 162 * @commit: set current hw specific display mode to hw.
161 * @enable_vblank: specific driver callback for enabling vblank interrupt. 163 * @enable_vblank: specific driver callback for enabling vblank interrupt.
162 * @disable_vblank: specific driver callback for disabling vblank interrupt. 164 * @disable_vblank: specific driver callback for disabling vblank interrupt.
@@ -164,7 +166,13 @@ struct exynos_drm_display_ops {
164struct exynos_drm_manager_ops { 166struct exynos_drm_manager_ops {
165 void (*dpms)(struct device *subdrv_dev, int mode); 167 void (*dpms)(struct device *subdrv_dev, int mode);
166 void (*apply)(struct device *subdrv_dev); 168 void (*apply)(struct device *subdrv_dev);
169 void (*mode_fixup)(struct device *subdrv_dev,
170 struct drm_connector *connector,
171 struct drm_display_mode *mode,
172 struct drm_display_mode *adjusted_mode);
167 void (*mode_set)(struct device *subdrv_dev, void *mode); 173 void (*mode_set)(struct device *subdrv_dev, void *mode);
174 void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width,
175 unsigned int *height);
168 void (*commit)(struct device *subdrv_dev); 176 void (*commit)(struct device *subdrv_dev);
169 int (*enable_vblank)(struct device *subdrv_dev); 177 int (*enable_vblank)(struct device *subdrv_dev);
170 void (*disable_vblank)(struct device *subdrv_dev); 178 void (*disable_vblank)(struct device *subdrv_dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index ef4754f1519b..45ca732858fb 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -111,9 +111,19 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
111 struct drm_display_mode *mode, 111 struct drm_display_mode *mode,
112 struct drm_display_mode *adjusted_mode) 112 struct drm_display_mode *adjusted_mode)
113{ 113{
114 struct drm_device *dev = encoder->dev;
115 struct drm_connector *connector;
116 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
117 struct exynos_drm_manager_ops *manager_ops = manager->ops;
118
114 DRM_DEBUG_KMS("%s\n", __FILE__); 119 DRM_DEBUG_KMS("%s\n", __FILE__);
115 120
116 /* drm framework doesn't check NULL. */ 121 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
122 if (connector->encoder == encoder)
123 if (manager_ops && manager_ops->mode_fixup)
124 manager_ops->mode_fixup(manager->dev, connector,
125 mode, adjusted_mode);
126 }
117 127
118 return true; 128 return true;
119} 129}
@@ -132,12 +142,11 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
132 142
133 DRM_DEBUG_KMS("%s\n", __FILE__); 143 DRM_DEBUG_KMS("%s\n", __FILE__);
134 144
135 mode = adjusted_mode;
136
137 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 145 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
138 if (connector->encoder == encoder) { 146 if (connector->encoder == encoder) {
139 if (manager_ops && manager_ops->mode_set) 147 if (manager_ops && manager_ops->mode_set)
140 manager_ops->mode_set(manager->dev, mode); 148 manager_ops->mode_set(manager->dev,
149 adjusted_mode);
141 150
142 if (overlay_ops && overlay_ops->mode_set) 151 if (overlay_ops && overlay_ops->mode_set)
143 overlay_ops->mode_set(manager->dev, overlay); 152 overlay_ops->mode_set(manager->dev, overlay);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index ed8a319ed84b..ed86bddf81da 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -155,6 +155,20 @@ static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
155 return hdmi_overlay_ops->disable_vblank(ctx->mixer_ctx->ctx); 155 return hdmi_overlay_ops->disable_vblank(ctx->mixer_ctx->ctx);
156} 156}
157 157
158static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
159 struct drm_connector *connector,
160 struct drm_display_mode *mode,
161 struct drm_display_mode *adjusted_mode)
162{
163 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
164
165 DRM_DEBUG_KMS("%s\n", __FILE__);
166
167 if (hdmi_manager_ops && hdmi_manager_ops->mode_fixup)
168 hdmi_manager_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector,
169 mode, adjusted_mode);
170}
171
158static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode) 172static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
159{ 173{
160 struct drm_hdmi_context *ctx = to_context(subdrv_dev); 174 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
@@ -165,6 +179,18 @@ static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
165 hdmi_manager_ops->mode_set(ctx->hdmi_ctx->ctx, mode); 179 hdmi_manager_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
166} 180}
167 181
182static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
183 unsigned int *width, unsigned int *height)
184{
185 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
186
187 DRM_DEBUG_KMS("%s\n", __FILE__);
188
189 if (hdmi_manager_ops && hdmi_manager_ops->get_max_resol)
190 hdmi_manager_ops->get_max_resol(ctx->hdmi_ctx->ctx, width,
191 height);
192}
193
168static void drm_hdmi_commit(struct device *subdrv_dev) 194static void drm_hdmi_commit(struct device *subdrv_dev)
169{ 195{
170 struct drm_hdmi_context *ctx = to_context(subdrv_dev); 196 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
@@ -200,7 +226,9 @@ static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
200 .dpms = drm_hdmi_dpms, 226 .dpms = drm_hdmi_dpms,
201 .enable_vblank = drm_hdmi_enable_vblank, 227 .enable_vblank = drm_hdmi_enable_vblank,
202 .disable_vblank = drm_hdmi_disable_vblank, 228 .disable_vblank = drm_hdmi_disable_vblank,
229 .mode_fixup = drm_hdmi_mode_fixup,
203 .mode_set = drm_hdmi_mode_set, 230 .mode_set = drm_hdmi_mode_set,
231 .get_max_resol = drm_hdmi_get_max_resol,
204 .commit = drm_hdmi_commit, 232 .commit = drm_hdmi_commit,
205}; 233};
206 234
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index 3c29f790ee45..44497cfb6c74 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -47,7 +47,12 @@ struct exynos_hdmi_display_ops {
47}; 47};
48 48
49struct exynos_hdmi_manager_ops { 49struct exynos_hdmi_manager_ops {
50 void (*mode_fixup)(void *ctx, struct drm_connector *connector,
51 struct drm_display_mode *mode,
52 struct drm_display_mode *adjusted_mode);
50 void (*mode_set)(void *ctx, void *mode); 53 void (*mode_set)(void *ctx, void *mode);
54 void (*get_max_resol)(void *ctx, unsigned int *width,
55 unsigned int *height);
51 void (*commit)(void *ctx); 56 void (*commit)(void *ctx);
52 void (*disable)(void *ctx); 57 void (*disable)(void *ctx);
53}; 58};
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 1cfe86e5d10e..6fe1e8993c92 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -41,6 +41,8 @@
41#include "exynos_hdmi.h" 41#include "exynos_hdmi.h"
42 42
43#define HDMI_OVERLAY_NUMBER 3 43#define HDMI_OVERLAY_NUMBER 3
44#define MAX_WIDTH 1920
45#define MAX_HEIGHT 1080
44#define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev)) 46#define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev))
45 47
46/* HDMI Version 1.3 */ 48/* HDMI Version 1.3 */
@@ -1126,7 +1128,7 @@ static int hdmi_v13_conf_index(struct drm_display_mode *mode)
1126 true : false)) 1128 true : false))
1127 return i; 1129 return i;
1128 1130
1129 return -1; 1131 return -EINVAL;
1130} 1132}
1131 1133
1132static int hdmi_v14_conf_index(struct drm_display_mode *mode) 1134static int hdmi_v14_conf_index(struct drm_display_mode *mode)
@@ -1142,7 +1144,7 @@ static int hdmi_v14_conf_index(struct drm_display_mode *mode)
1142 true : false)) 1144 true : false))
1143 return i; 1145 return i;
1144 1146
1145 return -1; 1147 return -EINVAL;
1146} 1148}
1147 1149
1148static int hdmi_conf_index(struct hdmi_context *hdata, 1150static int hdmi_conf_index(struct hdmi_context *hdata,
@@ -1150,8 +1152,8 @@ static int hdmi_conf_index(struct hdmi_context *hdata,
1150{ 1152{
1151 if (hdata->is_v13) 1153 if (hdata->is_v13)
1152 return hdmi_v13_conf_index(mode); 1154 return hdmi_v13_conf_index(mode);
1153 else 1155
1154 return hdmi_v14_conf_index(mode); 1156 return hdmi_v14_conf_index(mode);
1155} 1157}
1156 1158
1157static bool hdmi_is_connected(void *ctx) 1159static bool hdmi_is_connected(void *ctx)
@@ -1193,6 +1195,11 @@ static int hdmi_v13_check_timing(struct fb_videomode *check_timing)
1193{ 1195{
1194 int i; 1196 int i;
1195 1197
1198 DRM_DEBUG_KMS("valid mode : xres=%d, yres=%d, refresh=%d, intl=%d\n",
1199 check_timing->xres, check_timing->yres,
1200 check_timing->refresh, (check_timing->vmode &
1201 FB_VMODE_INTERLACED) ? true : false);
1202
1196 for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i) 1203 for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i)
1197 if (hdmi_v13_confs[i].width == check_timing->xres && 1204 if (hdmi_v13_confs[i].width == check_timing->xres &&
1198 hdmi_v13_confs[i].height == check_timing->yres && 1205 hdmi_v13_confs[i].height == check_timing->yres &&
@@ -1200,7 +1207,9 @@ static int hdmi_v13_check_timing(struct fb_videomode *check_timing)
1200 hdmi_v13_confs[i].interlace == 1207 hdmi_v13_confs[i].interlace ==
1201 ((check_timing->vmode & FB_VMODE_INTERLACED) ? 1208 ((check_timing->vmode & FB_VMODE_INTERLACED) ?
1202 true : false)) 1209 true : false))
1203 return 0; 1210 return 0;
1211
1212 /* TODO */
1204 1213
1205 return -EINVAL; 1214 return -EINVAL;
1206} 1215}
@@ -1209,14 +1218,21 @@ static int hdmi_v14_check_timing(struct fb_videomode *check_timing)
1209{ 1218{
1210 int i; 1219 int i;
1211 1220
1212 for (i = 0; i < ARRAY_SIZE(hdmi_confs); ++i) 1221 DRM_DEBUG_KMS("valid mode : xres=%d, yres=%d, refresh=%d, intl=%d\n",
1222 check_timing->xres, check_timing->yres,
1223 check_timing->refresh, (check_timing->vmode &
1224 FB_VMODE_INTERLACED) ? true : false);
1225
1226 for (i = 0; i < ARRAY_SIZE(hdmi_confs); i++)
1213 if (hdmi_confs[i].width == check_timing->xres && 1227 if (hdmi_confs[i].width == check_timing->xres &&
1214 hdmi_confs[i].height == check_timing->yres && 1228 hdmi_confs[i].height == check_timing->yres &&
1215 hdmi_confs[i].vrefresh == check_timing->refresh && 1229 hdmi_confs[i].vrefresh == check_timing->refresh &&
1216 hdmi_confs[i].interlace == 1230 hdmi_confs[i].interlace ==
1217 ((check_timing->vmode & FB_VMODE_INTERLACED) ? 1231 ((check_timing->vmode & FB_VMODE_INTERLACED) ?
1218 true : false)) 1232 true : false))
1219 return 0; 1233 return 0;
1234
1235 /* TODO */
1220 1236
1221 return -EINVAL; 1237 return -EINVAL;
1222} 1238}
@@ -1692,6 +1708,46 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
1692 hdmi_regs_dump(hdata, "start"); 1708 hdmi_regs_dump(hdata, "start");
1693} 1709}
1694 1710
1711static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector,
1712 struct drm_display_mode *mode,
1713 struct drm_display_mode *adjusted_mode)
1714{
1715 struct drm_display_mode *m;
1716 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
1717 int index;
1718
1719 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1720
1721 drm_mode_set_crtcinfo(adjusted_mode, 0);
1722
1723 if (hdata->is_v13)
1724 index = hdmi_v13_conf_index(adjusted_mode);
1725 else
1726 index = hdmi_v14_conf_index(adjusted_mode);
1727
1728 /* just return if user desired mode exists. */
1729 if (index >= 0)
1730 return;
1731
1732 /*
1733 * otherwise, find the most suitable mode among modes and change it
1734 * to adjusted_mode.
1735 */
1736 list_for_each_entry(m, &connector->modes, head) {
1737 if (hdata->is_v13)
1738 index = hdmi_v13_conf_index(m);
1739 else
1740 index = hdmi_v14_conf_index(m);
1741
1742 if (index >= 0) {
1743 DRM_INFO("desired mode doesn't exist so\n");
1744 DRM_INFO("use the most suitable mode among modes.\n");
1745 memcpy(adjusted_mode, m, sizeof(*m));
1746 break;
1747 }
1748 }
1749}
1750
1695static void hdmi_mode_set(void *ctx, void *mode) 1751static void hdmi_mode_set(void *ctx, void *mode)
1696{ 1752{
1697 struct hdmi_context *hdata = (struct hdmi_context *)ctx; 1753 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
@@ -1706,6 +1762,15 @@ static void hdmi_mode_set(void *ctx, void *mode)
1706 DRM_DEBUG_KMS("not supported mode\n"); 1762 DRM_DEBUG_KMS("not supported mode\n");
1707} 1763}
1708 1764
1765static void hdmi_get_max_resol(void *ctx, unsigned int *width,
1766 unsigned int *height)
1767{
1768 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1769
1770 *width = MAX_WIDTH;
1771 *height = MAX_HEIGHT;
1772}
1773
1709static void hdmi_commit(void *ctx) 1774static void hdmi_commit(void *ctx)
1710{ 1775{
1711 struct hdmi_context *hdata = (struct hdmi_context *)ctx; 1776 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
@@ -1730,7 +1795,9 @@ static void hdmi_disable(void *ctx)
1730} 1795}
1731 1796
1732static struct exynos_hdmi_manager_ops manager_ops = { 1797static struct exynos_hdmi_manager_ops manager_ops = {
1798 .mode_fixup = hdmi_mode_fixup,
1733 .mode_set = hdmi_mode_set, 1799 .mode_set = hdmi_mode_set,
1800 .get_max_resol = hdmi_get_max_resol,
1734 .commit = hdmi_commit, 1801 .commit = hdmi_commit,
1735 .disable = hdmi_disable, 1802 .disable = hdmi_disable,
1736}; 1803};