| @@ -107,12 +107,27 @@ void sun4i_frontend_exit(struct sun4i_frontend *frontend) · 106 unmodified lines |
| 107 | 107 | } |
| 108 | 108 | EXPORT_SYMBOL(sun4i_frontend_exit); |
| 109 | 109 | |
| 110 | +static bool sun4i_frontend_format_chroma_requires_swap(uint32_t fmt) |
| 111 | +{ |
| 112 | + switch (fmt) { |
| 113 | + case DRM_FORMAT_YVU411: |
| 114 | + case DRM_FORMAT_YVU420: |
| 115 | + case DRM_FORMAT_YVU422: |
| 116 | + case DRM_FORMAT_YVU444: |
| 117 | + return true; |
| 118 | + |
| 119 | + default: |
| 120 | + return false; |
| 121 | + } |
| 122 | +} |
| 123 | + |
| 110 | 124 | void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, |
| 111 | 125 | struct drm_plane *plane) |
| 112 | 126 | { |
| 113 | 127 | struct drm_plane_state *state = plane->state; |
| 114 | 128 | struct drm_framebuffer *fb = state->fb; |
| 115 | 129 | dma_addr_t paddr; |
| 130 | + bool swap; |
| 116 | 131 | |
| 117 | 132 | /* Set the line width */ |
| 118 | 133 | DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]); |
| @@ -123,6 +138,13 @@ void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, · 4 unmodified lines |
| 123 | 138 | regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD1_REG, |
| 124 | 139 | fb->pitches[1]); |
| 125 | 140 | |
| 141 | + if (fb->format->num_planes > 2) |
| 142 | + regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD2_REG, |
| 143 | + fb->pitches[2]); |
| 144 | + |
| 145 | + /* Some planar formats require chroma channel swapping by hand. */ |
| 146 | + swap = sun4i_frontend_format_chroma_requires_swap(fb->format->format); |
| 147 | + |
| 126 | 148 | /* Set the physical address of the buffer in memory */ |
| 127 | 149 | paddr = drm_fb_cma_get_gem_addr(fb, state, 0); |
| 128 | 150 | paddr -= PHYS_OFFSET; |
| @@ -130,12 +152,20 @@ void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, · 1 unmodified line |
| 130 | 152 | regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr); |
| 131 | 153 | |
| 132 | 154 | if (fb->format->num_planes > 1) { |
| 133 | | − paddr = drm_fb_cma_get_gem_addr(fb, state, 1); |
| 155 | + paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 2 : 1); |
| 134 | 156 | paddr -= PHYS_OFFSET; |
| 135 | 157 | DRM_DEBUG_DRIVER("Setting buffer #1 address to %pad\n", &paddr); |
| 136 | 158 | regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR1_REG, |
| 137 | 159 | paddr); |
| 138 | 160 | } |
| 161 | + |
| 162 | + if (fb->format->num_planes > 2) { |
| 163 | + paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 1 : 2); |
| 164 | + paddr -= PHYS_OFFSET; |
| 165 | + DRM_DEBUG_DRIVER("Setting buffer #2 address to %pad\n", &paddr); |
| 166 | + regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR2_REG, |
| 167 | + paddr); |
| 168 | + } |
| 139 | 169 | } |
| 140 | 170 | EXPORT_SYMBOL(sun4i_frontend_update_buffer); |
| 141 | 171 | |
| @@ -145,10 +175,14 @@ sun4i_frontend_drm_format_to_input_fmt(const struct drm_format_info *format, · 3 unmodified lines |
| 145 | 175 | { |
| 146 | 176 | if (!format->is_yuv) |
| 147 | 177 | *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB; |
| 178 | + else if (drm_format_info_is_yuv_sampling_411(format)) |
| 179 | + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411; |
| 148 | 180 | else if (drm_format_info_is_yuv_sampling_420(format)) |
| 149 | 181 | *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420; |
| 150 | 182 | else if (drm_format_info_is_yuv_sampling_422(format)) |
| 151 | 183 | *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422; |
| 184 | + else if (drm_format_info_is_yuv_sampling_444(format)) |
| 185 | + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444; |
| 152 | 186 | else |
| 153 | 187 | return -EINVAL; |
| 154 | 188 | |
| @@ -168,6 +202,10 @@ sun4i_frontend_drm_format_to_input_mode(const struct drm_format_info *format, · 13 unmodified lines |
| 168 | 202 | *val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR; |
| 169 | 203 | return 0; |
| 170 | 204 | |
| 205 | + case 3: |
| 206 | + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR; |
| 207 | + return 0; |
| 208 | + |
| 171 | 209 | default: |
| 172 | 210 | return -EINVAL; |
| 173 | 211 | } |
| @@ -177,6 +215,12 @@ static int · 3 unmodified lines |
| 177 | 215 | sun4i_frontend_drm_format_to_input_sequence(const struct drm_format_info *format, |
| 178 | 216 | u32 *val) |
| 179 | 217 | { |
| 218 | + /* Planar formats have an explicit input sequence. */ |
| 219 | + if (drm_format_info_is_yuv_planar(format)) { |
| 220 | + *val = 0; |
| 221 | + return 0; |
| 222 | + } |
| 223 | + |
| 180 | 224 | switch (format->format) { |
| 181 | 225 | case DRM_FORMAT_BGRX8888: |
| 182 | 226 | *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX; |
| @@ -248,7 +292,15 @@ static const uint32_t sun4i_frontend_formats[] = { · 65 unmodified lines |
| 248 | 292 | DRM_FORMAT_UYVY, |
| 249 | 293 | DRM_FORMAT_VYUY, |
| 250 | 294 | DRM_FORMAT_XRGB8888, |
| 295 | + DRM_FORMAT_YUV411, |
| 296 | + DRM_FORMAT_YUV420, |
| 297 | + DRM_FORMAT_YUV422, |
| 298 | + DRM_FORMAT_YUV444, |
| 251 | 299 | DRM_FORMAT_YUYV, |
| 300 | + DRM_FORMAT_YVU411, |
| 301 | + DRM_FORMAT_YVU420, |
| 302 | + DRM_FORMAT_YVU422, |
| 303 | + DRM_FORMAT_YVU444, |
| 252 | 304 | DRM_FORMAT_YVYU, |
| 253 | 305 | }; |
| 254 | 306 | |