aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2015-08-03 07:16:26 -0400
committerThierry Reding <treding@nvidia.com>2015-08-13 07:49:36 -0400
commit003fc848774fcc7b7f14a2b4f3e6411764f43fc0 (patch)
treeea443f498c39e743994625aeeb60eed1e26e992f
parent850bab448034f0a601727fe266afd0ef64fef6dc (diff)
drm/tegra: dc: Implement atomic DPMS
Move all code into the new canonical ->disable() and ->enable() helper callbacks so that they play extra nice with atomic DPMS. Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/gpu/drm/tegra/dc.c202
1 files changed, 102 insertions, 100 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index d60aa87d5152..7346ad162cab 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -1063,91 +1063,6 @@ static const struct drm_crtc_funcs tegra_crtc_funcs = {
1063 .atomic_destroy_state = tegra_crtc_atomic_destroy_state, 1063 .atomic_destroy_state = tegra_crtc_atomic_destroy_state,
1064}; 1064};
1065 1065
1066static void tegra_dc_stop(struct tegra_dc *dc)
1067{
1068 u32 value;
1069
1070 /* stop the display controller */
1071 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
1072 value &= ~DISP_CTRL_MODE_MASK;
1073 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
1074
1075 tegra_dc_commit(dc);
1076}
1077
1078static bool tegra_dc_idle(struct tegra_dc *dc)
1079{
1080 u32 value;
1081
1082 value = tegra_dc_readl_active(dc, DC_CMD_DISPLAY_COMMAND);
1083
1084 return (value & DISP_CTRL_MODE_MASK) == 0;
1085}
1086
1087static int tegra_dc_wait_idle(struct tegra_dc *dc, unsigned long timeout)
1088{
1089 timeout = jiffies + msecs_to_jiffies(timeout);
1090
1091 while (time_before(jiffies, timeout)) {
1092 if (tegra_dc_idle(dc))
1093 return 0;
1094
1095 usleep_range(1000, 2000);
1096 }
1097
1098 dev_dbg(dc->dev, "timeout waiting for DC to become idle\n");
1099 return -ETIMEDOUT;
1100}
1101
1102static void tegra_crtc_disable(struct drm_crtc *crtc)
1103{
1104 struct tegra_dc *dc = to_tegra_dc(crtc);
1105 u32 value;
1106
1107 if (!tegra_dc_idle(dc)) {
1108 tegra_dc_stop(dc);
1109
1110 /*
1111 * Ignore the return value, there isn't anything useful to do
1112 * in case this fails.
1113 */
1114 tegra_dc_wait_idle(dc, 100);
1115 }
1116
1117 /*
1118 * This should really be part of the RGB encoder driver, but clearing
1119 * these bits has the side-effect of stopping the display controller.
1120 * When that happens no VBLANK interrupts will be raised. At the same
1121 * time the encoder is disabled before the display controller, so the
1122 * above code is always going to timeout waiting for the controller
1123 * to go idle.
1124 *
1125 * Given the close coupling between the RGB encoder and the display
1126 * controller doing it here is still kind of okay. None of the other
1127 * encoder drivers require these bits to be cleared.
1128 *
1129 * XXX: Perhaps given that the display controller is switched off at
1130 * this point anyway maybe clearing these bits isn't even useful for
1131 * the RGB encoder?
1132 */
1133 if (dc->rgb) {
1134 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
1135 value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
1136 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
1137 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
1138 }
1139
1140 tegra_dc_stats_reset(&dc->stats);
1141 drm_crtc_vblank_off(crtc);
1142}
1143
1144static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc,
1145 const struct drm_display_mode *mode,
1146 struct drm_display_mode *adjusted)
1147{
1148 return true;
1149}
1150
1151static int tegra_dc_set_timings(struct tegra_dc *dc, 1066static int tegra_dc_set_timings(struct tegra_dc *dc,
1152 struct drm_display_mode *mode) 1067 struct drm_display_mode *mode)
1153{ 1068{
@@ -1241,7 +1156,85 @@ static void tegra_dc_commit_state(struct tegra_dc *dc,
1241 tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); 1156 tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
1242} 1157}
1243 1158
1244static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc) 1159static void tegra_dc_stop(struct tegra_dc *dc)
1160{
1161 u32 value;
1162
1163 /* stop the display controller */
1164 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
1165 value &= ~DISP_CTRL_MODE_MASK;
1166 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
1167
1168 tegra_dc_commit(dc);
1169}
1170
1171static bool tegra_dc_idle(struct tegra_dc *dc)
1172{
1173 u32 value;
1174
1175 value = tegra_dc_readl_active(dc, DC_CMD_DISPLAY_COMMAND);
1176
1177 return (value & DISP_CTRL_MODE_MASK) == 0;
1178}
1179
1180static int tegra_dc_wait_idle(struct tegra_dc *dc, unsigned long timeout)
1181{
1182 timeout = jiffies + msecs_to_jiffies(timeout);
1183
1184 while (time_before(jiffies, timeout)) {
1185 if (tegra_dc_idle(dc))
1186 return 0;
1187
1188 usleep_range(1000, 2000);
1189 }
1190
1191 dev_dbg(dc->dev, "timeout waiting for DC to become idle\n");
1192 return -ETIMEDOUT;
1193}
1194
1195static void tegra_crtc_disable(struct drm_crtc *crtc)
1196{
1197 struct tegra_dc *dc = to_tegra_dc(crtc);
1198 u32 value;
1199
1200 if (!tegra_dc_idle(dc)) {
1201 tegra_dc_stop(dc);
1202
1203 /*
1204 * Ignore the return value, there isn't anything useful to do
1205 * in case this fails.
1206 */
1207 tegra_dc_wait_idle(dc, 100);
1208 }
1209
1210 /*
1211 * This should really be part of the RGB encoder driver, but clearing
1212 * these bits has the side-effect of stopping the display controller.
1213 * When that happens no VBLANK interrupts will be raised. At the same
1214 * time the encoder is disabled before the display controller, so the
1215 * above code is always going to timeout waiting for the controller
1216 * to go idle.
1217 *
1218 * Given the close coupling between the RGB encoder and the display
1219 * controller doing it here is still kind of okay. None of the other
1220 * encoder drivers require these bits to be cleared.
1221 *
1222 * XXX: Perhaps given that the display controller is switched off at
1223 * this point anyway maybe clearing these bits isn't even useful for
1224 * the RGB encoder?
1225 */
1226 if (dc->rgb) {
1227 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
1228 value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
1229 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
1230 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
1231 }
1232
1233 tegra_dc_stats_reset(&dc->stats);
1234 drm_crtc_vblank_off(crtc);
1235}
1236
1237static void tegra_crtc_enable(struct drm_crtc *crtc)
1245{ 1238{
1246 struct drm_display_mode *mode = &crtc->state->adjusted_mode; 1239 struct drm_display_mode *mode = &crtc->state->adjusted_mode;
1247 struct tegra_dc_state *state = to_dc_state(crtc->state); 1240 struct tegra_dc_state *state = to_dc_state(crtc->state);
@@ -1271,15 +1264,7 @@ static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
1271 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); 1264 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
1272 1265
1273 tegra_dc_commit(dc); 1266 tegra_dc_commit(dc);
1274}
1275 1267
1276static void tegra_crtc_prepare(struct drm_crtc *crtc)
1277{
1278 drm_crtc_vblank_off(crtc);
1279}
1280
1281static void tegra_crtc_commit(struct drm_crtc *crtc)
1282{
1283 drm_crtc_vblank_on(crtc); 1268 drm_crtc_vblank_on(crtc);
1284} 1269}
1285 1270
@@ -1314,10 +1299,7 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc)
1314 1299
1315static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { 1300static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
1316 .disable = tegra_crtc_disable, 1301 .disable = tegra_crtc_disable,
1317 .mode_fixup = tegra_crtc_mode_fixup, 1302 .enable = tegra_crtc_enable,
1318 .mode_set_nofb = tegra_crtc_mode_set_nofb,
1319 .prepare = tegra_crtc_prepare,
1320 .commit = tegra_crtc_commit,
1321 .atomic_check = tegra_crtc_atomic_check, 1303 .atomic_check = tegra_crtc_atomic_check,
1322 .atomic_begin = tegra_crtc_atomic_begin, 1304 .atomic_begin = tegra_crtc_atomic_begin,
1323 .atomic_flush = tegra_crtc_atomic_flush, 1305 .atomic_flush = tegra_crtc_atomic_flush,
@@ -1368,6 +1350,14 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data)
1368{ 1350{
1369 struct drm_info_node *node = s->private; 1351 struct drm_info_node *node = s->private;
1370 struct tegra_dc *dc = node->info_ent->data; 1352 struct tegra_dc *dc = node->info_ent->data;
1353 int err = 0;
1354
1355 drm_modeset_lock_crtc(&dc->base, NULL);
1356
1357 if (!dc->base.state->active) {
1358 err = -EBUSY;
1359 goto unlock;
1360 }
1371 1361
1372#define DUMP_REG(name) \ 1362#define DUMP_REG(name) \
1373 seq_printf(s, "%-40s %#05x %08x\n", #name, name, \ 1363 seq_printf(s, "%-40s %#05x %08x\n", #name, name, \
@@ -1588,15 +1578,25 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data)
1588 1578
1589#undef DUMP_REG 1579#undef DUMP_REG
1590 1580
1591 return 0; 1581unlock:
1582 drm_modeset_unlock_crtc(&dc->base);
1583 return err;
1592} 1584}
1593 1585
1594static int tegra_dc_show_crc(struct seq_file *s, void *data) 1586static int tegra_dc_show_crc(struct seq_file *s, void *data)
1595{ 1587{
1596 struct drm_info_node *node = s->private; 1588 struct drm_info_node *node = s->private;
1597 struct tegra_dc *dc = node->info_ent->data; 1589 struct tegra_dc *dc = node->info_ent->data;
1590 int err = 0;
1598 u32 value; 1591 u32 value;
1599 1592
1593 drm_modeset_lock_crtc(&dc->base, NULL);
1594
1595 if (!dc->base.state->active) {
1596 err = -EBUSY;
1597 goto unlock;
1598 }
1599
1600 value = DC_COM_CRC_CONTROL_ACTIVE_DATA | DC_COM_CRC_CONTROL_ENABLE; 1600 value = DC_COM_CRC_CONTROL_ACTIVE_DATA | DC_COM_CRC_CONTROL_ENABLE;
1601 tegra_dc_writel(dc, value, DC_COM_CRC_CONTROL); 1601 tegra_dc_writel(dc, value, DC_COM_CRC_CONTROL);
1602 tegra_dc_commit(dc); 1602 tegra_dc_commit(dc);
@@ -1609,7 +1609,9 @@ static int tegra_dc_show_crc(struct seq_file *s, void *data)
1609 1609
1610 tegra_dc_writel(dc, 0, DC_COM_CRC_CONTROL); 1610 tegra_dc_writel(dc, 0, DC_COM_CRC_CONTROL);
1611 1611
1612 return 0; 1612unlock:
1613 drm_modeset_unlock_crtc(&dc->base);
1614 return err;
1613} 1615}
1614 1616
1615static int tegra_dc_show_stats(struct seq_file *s, void *data) 1617static int tegra_dc_show_stats(struct seq_file *s, void *data)