diff options
-rw-r--r-- | drivers/gpu/drm/armada/armada_crtc.c | 118 |
1 files changed, 117 insertions, 1 deletions
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 9958f2d3d0e8..8b66377a4890 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c | |||
@@ -1138,6 +1138,122 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { | |||
1138 | .disable_vblank = armada_drm_crtc_disable_vblank, | 1138 | .disable_vblank = armada_drm_crtc_disable_vblank, |
1139 | }; | 1139 | }; |
1140 | 1140 | ||
1141 | static void armada_drm_primary_update_state(struct drm_plane_state *state, | ||
1142 | struct armada_regs *regs) | ||
1143 | { | ||
1144 | struct armada_plane *dplane = drm_to_armada_plane(state->plane); | ||
1145 | struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc); | ||
1146 | struct armada_framebuffer *dfb = drm_fb_to_armada_fb(state->fb); | ||
1147 | bool was_disabled; | ||
1148 | unsigned int idx = 0; | ||
1149 | u32 val; | ||
1150 | |||
1151 | val = CFG_GRA_FMT(dfb->fmt) | CFG_GRA_MOD(dfb->mod); | ||
1152 | if (dfb->fmt > CFG_420) | ||
1153 | val |= CFG_PALETTE_ENA; | ||
1154 | if (state->visible) | ||
1155 | val |= CFG_GRA_ENA; | ||
1156 | if (drm_rect_width(&state->src) >> 16 != drm_rect_width(&state->dst)) | ||
1157 | val |= CFG_GRA_HSMOOTH; | ||
1158 | |||
1159 | was_disabled = !(dplane->state.ctrl0 & CFG_GRA_ENA); | ||
1160 | if (was_disabled) | ||
1161 | armada_reg_queue_mod(regs, idx, | ||
1162 | 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); | ||
1163 | |||
1164 | dplane->state.ctrl0 = val; | ||
1165 | dplane->state.src_hw = (drm_rect_height(&state->src) & 0xffff0000) | | ||
1166 | drm_rect_width(&state->src) >> 16; | ||
1167 | dplane->state.dst_hw = drm_rect_height(&state->dst) << 16 | | ||
1168 | drm_rect_width(&state->dst); | ||
1169 | dplane->state.dst_yx = state->dst.y1 << 16 | state->dst.x1; | ||
1170 | |||
1171 | armada_drm_gra_plane_regs(regs + idx, &dfb->fb, &dplane->state, | ||
1172 | state->src.x1 >> 16, state->src.y1 >> 16, | ||
1173 | dcrtc->interlaced); | ||
1174 | |||
1175 | dplane->state.vsync_update = !was_disabled; | ||
1176 | dplane->state.changed = true; | ||
1177 | } | ||
1178 | |||
1179 | static int armada_drm_primary_update(struct drm_plane *plane, | ||
1180 | struct drm_crtc *crtc, struct drm_framebuffer *fb, | ||
1181 | int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, | ||
1182 | uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, | ||
1183 | struct drm_modeset_acquire_ctx *ctx) | ||
1184 | { | ||
1185 | struct armada_plane *dplane = drm_to_armada_plane(plane); | ||
1186 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); | ||
1187 | struct armada_plane_work *work; | ||
1188 | struct drm_plane_state state = { | ||
1189 | .plane = plane, | ||
1190 | .crtc = crtc, | ||
1191 | .fb = fb, | ||
1192 | .src_x = src_x, | ||
1193 | .src_y = src_y, | ||
1194 | .src_w = src_w, | ||
1195 | .src_h = src_h, | ||
1196 | .crtc_x = crtc_x, | ||
1197 | .crtc_y = crtc_y, | ||
1198 | .crtc_w = crtc_w, | ||
1199 | .crtc_h = crtc_h, | ||
1200 | .rotation = DRM_MODE_ROTATE_0, | ||
1201 | }; | ||
1202 | const struct drm_rect clip = { | ||
1203 | .x2 = crtc->mode.hdisplay, | ||
1204 | .y2 = crtc->mode.vdisplay, | ||
1205 | }; | ||
1206 | int ret; | ||
1207 | |||
1208 | ret = drm_plane_helper_check_state(&state, &clip, 0, INT_MAX, true, | ||
1209 | false); | ||
1210 | if (ret) | ||
1211 | return ret; | ||
1212 | |||
1213 | work = &dplane->works[dplane->next_work]; | ||
1214 | work->fn = armada_drm_crtc_complete_frame_work; | ||
1215 | |||
1216 | if (plane->fb != fb) { | ||
1217 | /* | ||
1218 | * Take a reference on the new framebuffer - we want to | ||
1219 | * hold on to it while the hardware is displaying it. | ||
1220 | */ | ||
1221 | drm_framebuffer_reference(fb); | ||
1222 | |||
1223 | work->old_fb = plane->fb; | ||
1224 | } else { | ||
1225 | work->old_fb = NULL; | ||
1226 | } | ||
1227 | |||
1228 | armada_drm_primary_update_state(&state, work->regs); | ||
1229 | |||
1230 | if (!dplane->state.changed) | ||
1231 | return 0; | ||
1232 | |||
1233 | /* Wait for pending work to complete */ | ||
1234 | if (armada_drm_plane_work_wait(dplane, HZ / 10) == 0) | ||
1235 | armada_drm_plane_work_cancel(dcrtc, dplane); | ||
1236 | |||
1237 | if (!dplane->state.vsync_update) { | ||
1238 | work->fn(dcrtc, work); | ||
1239 | if (work->old_fb) | ||
1240 | drm_framebuffer_unreference(work->old_fb); | ||
1241 | return 0; | ||
1242 | } | ||
1243 | |||
1244 | /* Queue it for update on the next interrupt if we are enabled */ | ||
1245 | ret = armada_drm_plane_work_queue(dcrtc, work); | ||
1246 | if (ret) { | ||
1247 | work->fn(dcrtc, work); | ||
1248 | if (work->old_fb) | ||
1249 | drm_framebuffer_unreference(work->old_fb); | ||
1250 | } | ||
1251 | |||
1252 | dplane->next_work = !dplane->next_work; | ||
1253 | |||
1254 | return 0; | ||
1255 | } | ||
1256 | |||
1141 | int armada_drm_plane_disable(struct drm_plane *plane, | 1257 | int armada_drm_plane_disable(struct drm_plane *plane, |
1142 | struct drm_modeset_acquire_ctx *ctx) | 1258 | struct drm_modeset_acquire_ctx *ctx) |
1143 | { | 1259 | { |
@@ -1199,7 +1315,7 @@ int armada_drm_plane_disable(struct drm_plane *plane, | |||
1199 | } | 1315 | } |
1200 | 1316 | ||
1201 | static const struct drm_plane_funcs armada_primary_plane_funcs = { | 1317 | static const struct drm_plane_funcs armada_primary_plane_funcs = { |
1202 | .update_plane = drm_primary_helper_update, | 1318 | .update_plane = armada_drm_primary_update, |
1203 | .disable_plane = armada_drm_plane_disable, | 1319 | .disable_plane = armada_drm_plane_disable, |
1204 | .destroy = drm_primary_helper_destroy, | 1320 | .destroy = drm_primary_helper_destroy, |
1205 | }; | 1321 | }; |