Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/armada: use old_state for update tracking in atomic_update()

Rather than tracking the register state, we can now check the previous
state and decide which registers need updating from that since the old
plane state indicates the previous state which was programmed into the
hardware.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>

+150 -179
+60 -56
drivers/gpu/drm/armada/armada_crtc.c
··· 1114 1114 return 0; 1115 1115 } 1116 1116 1117 - static unsigned int armada_drm_primary_update_state( 1118 - struct drm_plane_state *state, struct armada_regs *regs) 1119 - { 1120 - struct armada_plane *dplane = drm_to_armada_plane(state->plane); 1121 - struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc); 1122 - struct armada_framebuffer *dfb = drm_fb_to_armada_fb(state->fb); 1123 - bool was_disabled; 1124 - unsigned int idx = 0; 1125 - u32 val; 1126 - 1127 - val = CFG_GRA_FMT(dfb->fmt) | CFG_GRA_MOD(dfb->mod); 1128 - if (dfb->fmt > CFG_420) 1129 - val |= CFG_PALETTE_ENA; 1130 - if (state->visible) 1131 - val |= CFG_GRA_ENA; 1132 - if (drm_rect_width(&state->src) >> 16 != drm_rect_width(&state->dst)) 1133 - val |= CFG_GRA_HSMOOTH; 1134 - if (dcrtc->interlaced) 1135 - val |= CFG_GRA_FTOGGLE; 1136 - 1137 - was_disabled = !(dplane->state.ctrl0 & CFG_GRA_ENA); 1138 - if (was_disabled) 1139 - armada_reg_queue_mod(regs, idx, 1140 - 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); 1141 - 1142 - dplane->state.ctrl0 = val; 1143 - dplane->state.src_hw = armada_rect_hw_fp(&state->src); 1144 - dplane->state.dst_hw = armada_rect_hw(&state->dst); 1145 - dplane->state.dst_yx = armada_rect_yx(&state->dst); 1146 - 1147 - idx += armada_drm_crtc_calc_fb(&dfb->fb, state->src.x1 >> 16, 1148 - state->src.y1 >> 16, regs + idx, 1149 - dcrtc->interlaced); 1150 - armada_reg_queue_set(regs, idx, dplane->state.dst_yx, 1151 - LCD_SPU_GRA_OVSA_HPXL_VLN); 1152 - armada_reg_queue_set(regs, idx, dplane->state.src_hw, 1153 - LCD_SPU_GRA_HPXL_VLN); 1154 - armada_reg_queue_set(regs, idx, dplane->state.dst_hw, 1155 - LCD_SPU_GZM_HPXL_VLN); 1156 - armada_reg_queue_mod(regs, idx, dplane->state.ctrl0, CFG_GRAFORMAT | 1157 - CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | 1158 - CFG_SWAPYU | CFG_YUV2RGB) | 1159 - CFG_PALETTE_ENA | CFG_GRA_FTOGGLE | 1160 - CFG_GRA_HSMOOTH | CFG_GRA_ENA, 1161 - LCD_SPU_DMA_CTRL0); 1162 - 1163 - dplane->state.vsync_update = !was_disabled; 1164 - dplane->state.changed = true; 1165 - 1166 - return idx; 1167 - } 1168 - 1169 1117 static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, 1170 1118 struct drm_plane_state *old_state) 1171 1119 { 1172 1120 struct drm_plane_state *state = plane->state; 1173 1121 struct armada_crtc *dcrtc; 1174 1122 struct armada_regs *regs; 1123 + u32 cfg, cfg_mask, val; 1124 + unsigned int idx; 1175 1125 1176 1126 DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); 1177 1127 ··· 1137 1187 dcrtc = drm_to_armada_crtc(state->crtc); 1138 1188 regs = dcrtc->regs + dcrtc->regs_idx; 1139 1189 1140 - dcrtc->regs_idx += armada_drm_primary_update_state(state, regs); 1190 + idx = 0; 1191 + if (!old_state->visible && state->visible) { 1192 + val = CFG_PDWN64x66; 1193 + if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420) 1194 + val |= CFG_PDWN256x24; 1195 + armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1); 1196 + } 1197 + val = armada_rect_hw_fp(&state->src); 1198 + if (armada_rect_hw_fp(&old_state->src) != val) 1199 + armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN); 1200 + val = armada_rect_yx(&state->dst); 1201 + if (armada_rect_yx(&old_state->dst) != val) 1202 + armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN); 1203 + val = armada_rect_hw(&state->dst); 1204 + if (armada_rect_hw(&old_state->dst) != val) 1205 + armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN); 1206 + if (old_state->src.x1 != state->src.x1 || 1207 + old_state->src.y1 != state->src.y1 || 1208 + old_state->fb != state->fb) { 1209 + idx += armada_drm_crtc_calc_fb(state->fb, 1210 + state->src.x1 >> 16, 1211 + state->src.y1 >> 16, 1212 + regs + idx, 1213 + dcrtc->interlaced); 1214 + } 1215 + if (old_state->fb != state->fb) { 1216 + cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | 1217 + CFG_GRA_MOD(drm_fb_to_armada_fb(state->fb)->mod); 1218 + if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420) 1219 + cfg |= CFG_PALETTE_ENA; 1220 + if (state->visible) 1221 + cfg |= CFG_GRA_ENA; 1222 + if (dcrtc->interlaced) 1223 + cfg |= CFG_GRA_FTOGGLE; 1224 + cfg_mask = CFG_GRAFORMAT | 1225 + CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | 1226 + CFG_SWAPYU | CFG_YUV2RGB) | 1227 + CFG_PALETTE_ENA | CFG_GRA_FTOGGLE | 1228 + CFG_GRA_ENA; 1229 + } else if (old_state->visible != state->visible) { 1230 + cfg = state->visible ? CFG_GRA_ENA : 0; 1231 + cfg_mask = CFG_GRA_ENA; 1232 + } else { 1233 + cfg = cfg_mask = 0; 1234 + } 1235 + if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) || 1236 + drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) { 1237 + cfg_mask |= CFG_GRA_HSMOOTH; 1238 + if (drm_rect_width(&state->src) >> 16 != 1239 + drm_rect_width(&state->dst)) 1240 + cfg |= CFG_GRA_HSMOOTH; 1241 + } 1242 + 1243 + if (cfg_mask) 1244 + armada_reg_queue_mod(regs, idx, cfg, cfg_mask, 1245 + LCD_SPU_DMA_CTRL0); 1246 + 1247 + dcrtc->regs_idx += idx; 1141 1248 } 1142 1249 1143 1250 static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane, 1144 1251 struct drm_plane_state *old_state) 1145 1252 { 1146 - struct armada_plane *dplane = drm_to_armada_plane(plane); 1147 1253 struct armada_crtc *dcrtc; 1148 1254 struct armada_regs *regs; 1149 1255 unsigned int idx = 0; ··· 1213 1207 plane->base.id, plane->name, 1214 1208 old_state->crtc->base.id, old_state->crtc->name, 1215 1209 old_state->fb->base.id); 1216 - 1217 - dplane->state.ctrl0 &= ~CFG_GRA_ENA; 1218 1210 1219 1211 dcrtc = drm_to_armada_crtc(old_state->crtc); 1220 1212 regs = dcrtc->regs + dcrtc->regs_idx;
-12
drivers/gpu/drm/armada/armada_crtc.h
··· 45 45 struct armada_regs regs[14]; 46 46 }; 47 47 48 - struct armada_plane_state { 49 - u16 src_x; 50 - u16 src_y; 51 - u32 src_hw; 52 - u32 dst_hw; 53 - u32 dst_yx; 54 - u32 ctrl0; 55 - bool changed; 56 - bool vsync_update; 57 - }; 58 - 59 48 struct armada_plane { 60 49 struct drm_plane base; 61 50 wait_queue_head_t frame_wait; 62 51 bool next_work; 63 52 struct armada_plane_work works[2]; 64 53 struct armada_plane_work *work; 65 - struct armada_plane_state state; 66 54 }; 67 55 #define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) 68 56
+90 -111
drivers/gpu/drm/armada/armada_overlay.c
··· 35 35 36 36 struct armada_ovl_plane { 37 37 struct armada_plane base; 38 + bool wait_vblank; 38 39 struct armada_ovl_plane_properties prop; 39 40 }; 40 41 #define drm_to_armada_ovl_plane(p) \ ··· 81 80 spin_unlock_irqrestore(&dcrtc->irq_lock, flags); 82 81 } 83 82 84 - static unsigned int armada_ovl_plane_update_state(struct drm_plane_state *state, 85 - struct armada_regs *regs) 86 - { 87 - struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(state->plane); 88 - struct armada_framebuffer *dfb = drm_fb_to_armada_fb(state->fb); 89 - const struct drm_format_info *format; 90 - unsigned int idx = 0; 91 - bool fb_changed; 92 - u32 val, ctrl0; 93 - u16 src_x, src_y; 94 - 95 - ctrl0 = CFG_DMA_FMT(dfb->fmt) | CFG_DMA_MOD(dfb->mod) | CFG_CBSH_ENA; 96 - if (state->visible) 97 - ctrl0 |= CFG_DMA_ENA; 98 - if (drm_rect_width(&state->src) >> 16 != drm_rect_width(&state->dst)) 99 - ctrl0 |= CFG_DMA_HSMOOTH; 100 - 101 - /* 102 - * Shifting a YUV packed format image by one pixel causes the U/V 103 - * planes to swap. Compensate for it by also toggling the UV swap. 104 - */ 105 - format = dfb->fb.format; 106 - if (format->num_planes == 1 && state->src.x1 >> 16 & (format->hsub - 1)) 107 - ctrl0 ^= CFG_DMA_MOD(CFG_SWAPUV); 108 - 109 - if (~dplane->base.state.ctrl0 & ctrl0 & CFG_DMA_ENA) { 110 - /* Power up the Y/U/V FIFOs on ENA 0->1 transitions */ 111 - armada_reg_queue_mod(regs, idx, 112 - 0, CFG_PDWN16x66 | CFG_PDWN32x66, 113 - LCD_SPU_SRAM_PARA1); 114 - } 115 - 116 - fb_changed = dplane->base.base.fb != &dfb->fb || 117 - dplane->base.state.src_x != state->src.x1 >> 16 || 118 - dplane->base.state.src_y != state->src.y1 >> 16; 119 - 120 - dplane->base.state.vsync_update = fb_changed; 121 - 122 - /* FIXME: overlay on an interlaced display */ 123 - if (fb_changed) { 124 - u32 addrs[3]; 125 - 126 - dplane->base.state.src_y = src_y = state->src.y1 >> 16; 127 - dplane->base.state.src_x = src_x = state->src.x1 >> 16; 128 - 129 - armada_drm_plane_calc_addrs(addrs, &dfb->fb, src_x, src_y); 130 - 131 - armada_reg_queue_set(regs, idx, addrs[0], 132 - LCD_SPU_DMA_START_ADDR_Y0); 133 - armada_reg_queue_set(regs, idx, addrs[1], 134 - LCD_SPU_DMA_START_ADDR_U0); 135 - armada_reg_queue_set(regs, idx, addrs[2], 136 - LCD_SPU_DMA_START_ADDR_V0); 137 - armada_reg_queue_set(regs, idx, addrs[0], 138 - LCD_SPU_DMA_START_ADDR_Y1); 139 - armada_reg_queue_set(regs, idx, addrs[1], 140 - LCD_SPU_DMA_START_ADDR_U1); 141 - armada_reg_queue_set(regs, idx, addrs[2], 142 - LCD_SPU_DMA_START_ADDR_V1); 143 - 144 - val = dfb->fb.pitches[0] << 16 | dfb->fb.pitches[0]; 145 - armada_reg_queue_set(regs, idx, val, 146 - LCD_SPU_DMA_PITCH_YC); 147 - val = dfb->fb.pitches[1] << 16 | dfb->fb.pitches[2]; 148 - armada_reg_queue_set(regs, idx, val, 149 - LCD_SPU_DMA_PITCH_UV); 150 - } 151 - 152 - val = armada_rect_hw_fp(&state->src); 153 - if (dplane->base.state.src_hw != val) { 154 - dplane->base.state.src_hw = val; 155 - armada_reg_queue_set(regs, idx, val, 156 - LCD_SPU_DMA_HPXL_VLN); 157 - } 158 - 159 - val = armada_rect_hw(&state->dst); 160 - if (dplane->base.state.dst_hw != val) { 161 - dplane->base.state.dst_hw = val; 162 - armada_reg_queue_set(regs, idx, val, 163 - LCD_SPU_DZM_HPXL_VLN); 164 - } 165 - 166 - val = armada_rect_yx(&state->dst); 167 - if (dplane->base.state.dst_yx != val) { 168 - dplane->base.state.dst_yx = val; 169 - armada_reg_queue_set(regs, idx, val, 170 - LCD_SPU_DMA_OVSA_HPXL_VLN); 171 - } 172 - 173 - if (dplane->base.state.ctrl0 != ctrl0) { 174 - dplane->base.state.ctrl0 = ctrl0; 175 - armada_reg_queue_mod(regs, idx, ctrl0, 176 - CFG_CBSH_ENA | CFG_DMAFORMAT | CFG_DMA_FTOGGLE | 177 - CFG_DMA_HSMOOTH | CFG_DMA_TSTMODE | 178 - CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV | CFG_SWAPYU | 179 - CFG_YUV2RGB) | CFG_DMA_ENA, 180 - LCD_SPU_DMA_CTRL0); 181 - dplane->base.state.vsync_update = true; 182 - } 183 - 184 - dplane->base.state.changed = idx != 0; 185 - 186 - return idx; 187 - } 188 - 189 83 static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, 190 84 struct drm_plane_state *old_state) 191 85 { 192 86 struct drm_plane_state *state = plane->state; 193 87 struct armada_crtc *dcrtc; 194 88 struct armada_regs *regs; 89 + unsigned int idx; 90 + u32 cfg, cfg_mask, val; 195 91 196 92 DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); 197 93 ··· 104 206 dcrtc = drm_to_armada_crtc(state->crtc); 105 207 regs = dcrtc->regs + dcrtc->regs_idx; 106 208 107 - dcrtc->regs_idx += armada_ovl_plane_update_state(state, regs); 209 + drm_to_armada_ovl_plane(plane)->wait_vblank = false; 210 + 211 + idx = 0; 212 + if (!old_state->visible && state->visible) 213 + armada_reg_queue_mod(regs, idx, 214 + 0, CFG_PDWN16x66 | CFG_PDWN32x66, 215 + LCD_SPU_SRAM_PARA1); 216 + val = armada_rect_hw_fp(&state->src); 217 + if (armada_rect_hw_fp(&old_state->src) != val) 218 + armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN); 219 + val = armada_rect_yx(&state->dst); 220 + if (armada_rect_yx(&old_state->dst) != val) 221 + armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN); 222 + val = armada_rect_hw(&state->dst); 223 + if (armada_rect_hw(&old_state->dst) != val) 224 + armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN); 225 + /* FIXME: overlay on an interlaced display */ 226 + if (old_state->src.x1 != state->src.x1 || 227 + old_state->src.y1 != state->src.y1 || 228 + old_state->fb != state->fb) { 229 + const struct drm_format_info *format; 230 + u16 src_x = state->src.x1 >> 16; 231 + u16 src_y = state->src.y1 >> 16; 232 + u32 addrs[3]; 233 + 234 + armada_drm_plane_calc_addrs(addrs, state->fb, src_x, src_y); 235 + 236 + armada_reg_queue_set(regs, idx, addrs[0], 237 + LCD_SPU_DMA_START_ADDR_Y0); 238 + armada_reg_queue_set(regs, idx, addrs[1], 239 + LCD_SPU_DMA_START_ADDR_U0); 240 + armada_reg_queue_set(regs, idx, addrs[2], 241 + LCD_SPU_DMA_START_ADDR_V0); 242 + armada_reg_queue_set(regs, idx, addrs[0], 243 + LCD_SPU_DMA_START_ADDR_Y1); 244 + armada_reg_queue_set(regs, idx, addrs[1], 245 + LCD_SPU_DMA_START_ADDR_U1); 246 + armada_reg_queue_set(regs, idx, addrs[2], 247 + LCD_SPU_DMA_START_ADDR_V1); 248 + 249 + val = state->fb->pitches[0] << 16 | state->fb->pitches[0]; 250 + armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC); 251 + val = state->fb->pitches[1] << 16 | state->fb->pitches[2]; 252 + armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV); 253 + 254 + cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | 255 + CFG_DMA_MOD(drm_fb_to_armada_fb(state->fb)->mod) | 256 + CFG_CBSH_ENA; 257 + if (state->visible) 258 + cfg |= CFG_DMA_ENA; 259 + 260 + /* 261 + * Shifting a YUV packed format image by one pixel causes the 262 + * U/V planes to swap. Compensate for it by also toggling 263 + * the UV swap. 264 + */ 265 + format = state->fb->format; 266 + if (format->num_planes == 1 && src_x & (format->hsub - 1)) 267 + cfg ^= CFG_DMA_MOD(CFG_SWAPUV); 268 + cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT | 269 + CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV | 270 + CFG_SWAPYU | CFG_YUV2RGB) | 271 + CFG_DMA_FTOGGLE | CFG_DMA_TSTMODE | 272 + CFG_DMA_ENA; 273 + 274 + drm_to_armada_ovl_plane(plane)->wait_vblank = true; 275 + } else if (old_state->visible != state->visible) { 276 + cfg = state->visible ? CFG_DMA_ENA : 0; 277 + cfg_mask = CFG_DMA_ENA; 278 + } else { 279 + cfg = cfg_mask = 0; 280 + } 281 + if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) || 282 + drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) { 283 + cfg_mask |= CFG_DMA_HSMOOTH; 284 + if (drm_rect_width(&state->src) >> 16 != 285 + drm_rect_width(&state->dst)) 286 + cfg |= CFG_DMA_HSMOOTH; 287 + } 288 + 289 + if (cfg_mask) 290 + armada_reg_queue_mod(regs, idx, cfg, cfg_mask, 291 + LCD_SPU_DMA_CTRL0); 292 + 293 + dcrtc->regs_idx += idx; 108 294 } 109 295 110 296 static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane, 111 297 struct drm_plane_state *old_state) 112 298 { 113 - struct armada_plane *dplane = drm_to_armada_plane(plane); 114 299 struct armada_crtc *dcrtc; 115 300 struct armada_regs *regs; 116 301 unsigned int idx = 0; ··· 207 226 plane->base.id, plane->name, 208 227 old_state->crtc->base.id, old_state->crtc->name, 209 228 old_state->fb->base.id); 210 - 211 - dplane->state.ctrl0 &= ~CFG_DMA_ENA; 212 229 213 230 dcrtc = drm_to_armada_crtc(old_state->crtc); 214 231 regs = dcrtc->regs + dcrtc->regs_idx; ··· 267 288 plane_funcs->atomic_update(plane, state); 268 289 269 290 /* If nothing was updated, short-circuit */ 270 - if (!dplane->base.state.changed) 291 + if (dcrtc->regs_idx == 0) 271 292 goto put_state; 272 293 273 294 armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); ··· 277 298 armada_drm_plane_work_cancel(dcrtc, &dplane->base); 278 299 279 300 /* Just updating the position/size? */ 280 - if (!dplane->base.state.vsync_update) { 301 + if (!dplane->wait_vblank) { 281 302 armada_ovl_plane_work(dcrtc, work); 282 303 goto put_state; 283 304 }