diff options
author | Thierry Reding <treding@nvidia.com> | 2015-08-03 07:16:26 -0400 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2015-08-13 07:49:36 -0400 |
commit | 003fc848774fcc7b7f14a2b4f3e6411764f43fc0 (patch) | |
tree | ea443f498c39e743994625aeeb60eed1e26e992f | |
parent | 850bab448034f0a601727fe266afd0ef64fef6dc (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.c | 202 |
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 | ||
1066 | static 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 | |||
1078 | static 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 | |||
1087 | static 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 | |||
1102 | static 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 | |||
1144 | static 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 | |||
1151 | static int tegra_dc_set_timings(struct tegra_dc *dc, | 1066 | static 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 | ||
1244 | static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc) | 1159 | static 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 | |||
1171 | static 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 | |||
1180 | static 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 | |||
1195 | static 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 | |||
1237 | static 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 | ||
1276 | static void tegra_crtc_prepare(struct drm_crtc *crtc) | ||
1277 | { | ||
1278 | drm_crtc_vblank_off(crtc); | ||
1279 | } | ||
1280 | |||
1281 | static 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 | ||
1315 | static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { | 1300 | static 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; | 1581 | unlock: |
1582 | drm_modeset_unlock_crtc(&dc->base); | ||
1583 | return err; | ||
1592 | } | 1584 | } |
1593 | 1585 | ||
1594 | static int tegra_dc_show_crc(struct seq_file *s, void *data) | 1586 | static 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; | 1612 | unlock: |
1613 | drm_modeset_unlock_crtc(&dc->base); | ||
1614 | return err; | ||
1613 | } | 1615 | } |
1614 | 1616 | ||
1615 | static int tegra_dc_show_stats(struct seq_file *s, void *data) | 1617 | static int tegra_dc_show_stats(struct seq_file *s, void *data) |