diff options
Diffstat (limited to 'drivers/gpu/drm/sun4i/sun4i_frontend.c')
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_frontend.c | 113 |
1 files changed, 90 insertions, 23 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c index ddf6cfa6dd23..1a7ebc45747e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_frontend.c +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c | |||
@@ -107,8 +107,34 @@ EXPORT_SYMBOL(sun4i_frontend_update_buffer); | |||
107 | static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val) | 107 | static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val) |
108 | { | 108 | { |
109 | switch (fmt) { | 109 | switch (fmt) { |
110 | case DRM_FORMAT_ARGB8888: | 110 | case DRM_FORMAT_XRGB8888: |
111 | *val = 5; | 111 | *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB; |
112 | return 0; | ||
113 | |||
114 | default: | ||
115 | return -EINVAL; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static int sun4i_frontend_drm_format_to_input_mode(uint32_t fmt, u32 *val) | ||
120 | { | ||
121 | if (drm_format_num_planes(fmt) == 1) | ||
122 | *val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED; | ||
123 | else | ||
124 | return -EINVAL; | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int sun4i_frontend_drm_format_to_input_sequence(uint32_t fmt, u32 *val) | ||
130 | { | ||
131 | switch (fmt) { | ||
132 | case DRM_FORMAT_BGRX8888: | ||
133 | *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX; | ||
134 | return 0; | ||
135 | |||
136 | case DRM_FORMAT_XRGB8888: | ||
137 | *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB; | ||
112 | return 0; | 138 | return 0; |
113 | 139 | ||
114 | default: | 140 | default: |
@@ -119,9 +145,12 @@ static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val) | |||
119 | static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val) | 145 | static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val) |
120 | { | 146 | { |
121 | switch (fmt) { | 147 | switch (fmt) { |
148 | case DRM_FORMAT_BGRX8888: | ||
149 | *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888; | ||
150 | return 0; | ||
151 | |||
122 | case DRM_FORMAT_XRGB8888: | 152 | case DRM_FORMAT_XRGB8888: |
123 | case DRM_FORMAT_ARGB8888: | 153 | *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888; |
124 | *val = 2; | ||
125 | return 0; | 154 | return 0; |
126 | 155 | ||
127 | default: | 156 | default: |
@@ -129,22 +158,54 @@ static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val) | |||
129 | } | 158 | } |
130 | } | 159 | } |
131 | 160 | ||
161 | static const uint32_t sun4i_frontend_formats[] = { | ||
162 | DRM_FORMAT_BGRX8888, | ||
163 | DRM_FORMAT_XRGB8888, | ||
164 | }; | ||
165 | |||
166 | bool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier) | ||
167 | { | ||
168 | unsigned int i; | ||
169 | |||
170 | if (modifier != DRM_FORMAT_MOD_LINEAR) | ||
171 | return false; | ||
172 | |||
173 | for (i = 0; i < ARRAY_SIZE(sun4i_frontend_formats); i++) | ||
174 | if (sun4i_frontend_formats[i] == fmt) | ||
175 | return true; | ||
176 | |||
177 | return false; | ||
178 | } | ||
179 | EXPORT_SYMBOL(sun4i_frontend_format_is_supported); | ||
180 | |||
132 | int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, | 181 | int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, |
133 | struct drm_plane *plane, uint32_t out_fmt) | 182 | struct drm_plane *plane, uint32_t out_fmt) |
134 | { | 183 | { |
135 | struct drm_plane_state *state = plane->state; | 184 | struct drm_plane_state *state = plane->state; |
136 | struct drm_framebuffer *fb = state->fb; | 185 | struct drm_framebuffer *fb = state->fb; |
186 | uint32_t format = fb->format->format; | ||
137 | u32 out_fmt_val; | 187 | u32 out_fmt_val; |
138 | u32 in_fmt_val; | 188 | u32 in_fmt_val, in_mod_val, in_ps_val; |
139 | int ret; | 189 | int ret; |
140 | 190 | ||
141 | ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format, | 191 | ret = sun4i_frontend_drm_format_to_input_fmt(format, &in_fmt_val); |
142 | &in_fmt_val); | ||
143 | if (ret) { | 192 | if (ret) { |
144 | DRM_DEBUG_DRIVER("Invalid input format\n"); | 193 | DRM_DEBUG_DRIVER("Invalid input format\n"); |
145 | return ret; | 194 | return ret; |
146 | } | 195 | } |
147 | 196 | ||
197 | ret = sun4i_frontend_drm_format_to_input_mode(format, &in_mod_val); | ||
198 | if (ret) { | ||
199 | DRM_DEBUG_DRIVER("Invalid input mode\n"); | ||
200 | return ret; | ||
201 | } | ||
202 | |||
203 | ret = sun4i_frontend_drm_format_to_input_sequence(format, &in_ps_val); | ||
204 | if (ret) { | ||
205 | DRM_DEBUG_DRIVER("Invalid pixel sequence\n"); | ||
206 | return ret; | ||
207 | } | ||
208 | |||
148 | ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val); | 209 | ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val); |
149 | if (ret) { | 210 | if (ret) { |
150 | DRM_DEBUG_DRIVER("Invalid output format\n"); | 211 | DRM_DEBUG_DRIVER("Invalid output format\n"); |
@@ -162,10 +223,12 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, | |||
162 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400); | 223 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400); |
163 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400); | 224 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400); |
164 | 225 | ||
226 | regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG, | ||
227 | SUN4I_FRONTEND_BYPASS_CSC_EN, | ||
228 | SUN4I_FRONTEND_BYPASS_CSC_EN); | ||
229 | |||
165 | regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, | 230 | regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, |
166 | SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) | | 231 | in_mod_val | in_fmt_val | in_ps_val); |
167 | SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(in_fmt_val) | | ||
168 | SUN4I_FRONTEND_INPUT_FMT_PS(1)); | ||
169 | 232 | ||
170 | /* | 233 | /* |
171 | * TODO: It look like the A31 and A80 at least will need the | 234 | * TODO: It look like the A31 and A80 at least will need the |
@@ -173,7 +236,7 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, | |||
173 | * ARGB8888). | 236 | * ARGB8888). |
174 | */ | 237 | */ |
175 | regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, | 238 | regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, |
176 | SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(out_fmt_val)); | 239 | out_fmt_val); |
177 | 240 | ||
178 | return 0; | 241 | return 0; |
179 | } | 242 | } |
@@ -183,16 +246,24 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend, | |||
183 | struct drm_plane *plane) | 246 | struct drm_plane *plane) |
184 | { | 247 | { |
185 | struct drm_plane_state *state = plane->state; | 248 | struct drm_plane_state *state = plane->state; |
249 | struct drm_framebuffer *fb = state->fb; | ||
250 | uint32_t luma_width, luma_height; | ||
251 | uint32_t chroma_width, chroma_height; | ||
186 | 252 | ||
187 | /* Set height and width */ | 253 | /* Set height and width */ |
188 | DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n", | 254 | DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n", |
189 | state->crtc_w, state->crtc_h); | 255 | state->crtc_w, state->crtc_h); |
256 | |||
257 | luma_width = state->src_w >> 16; | ||
258 | luma_height = state->src_h >> 16; | ||
259 | |||
260 | chroma_width = DIV_ROUND_UP(luma_width, fb->format->hsub); | ||
261 | chroma_height = DIV_ROUND_UP(luma_height, fb->format->vsub); | ||
262 | |||
190 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG, | 263 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG, |
191 | SUN4I_FRONTEND_INSIZE(state->src_h >> 16, | 264 | SUN4I_FRONTEND_INSIZE(luma_height, luma_width)); |
192 | state->src_w >> 16)); | ||
193 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG, | 265 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG, |
194 | SUN4I_FRONTEND_INSIZE(state->src_h >> 16, | 266 | SUN4I_FRONTEND_INSIZE(chroma_height, chroma_width)); |
195 | state->src_w >> 16)); | ||
196 | 267 | ||
197 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG, | 268 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG, |
198 | SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); | 269 | SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); |
@@ -200,14 +271,14 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend, | |||
200 | SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); | 271 | SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); |
201 | 272 | ||
202 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG, | 273 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG, |
203 | state->src_w / state->crtc_w); | 274 | (luma_width << 16) / state->crtc_w); |
204 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG, | 275 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG, |
205 | state->src_w / state->crtc_w); | 276 | (chroma_width << 16) / state->crtc_w); |
206 | 277 | ||
207 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG, | 278 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG, |
208 | state->src_h / state->crtc_h); | 279 | (luma_height << 16) / state->crtc_h); |
209 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG, | 280 | regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG, |
210 | state->src_h / state->crtc_h); | 281 | (chroma_height << 16) / state->crtc_h); |
211 | 282 | ||
212 | regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, | 283 | regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, |
213 | SUN4I_FRONTEND_FRM_CTRL_REG_RDY, | 284 | SUN4I_FRONTEND_FRM_CTRL_REG_RDY, |
@@ -339,10 +410,6 @@ static int sun4i_frontend_runtime_resume(struct device *dev) | |||
339 | SUN4I_FRONTEND_EN_EN, | 410 | SUN4I_FRONTEND_EN_EN, |
340 | SUN4I_FRONTEND_EN_EN); | 411 | SUN4I_FRONTEND_EN_EN); |
341 | 412 | ||
342 | regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG, | ||
343 | SUN4I_FRONTEND_BYPASS_CSC_EN, | ||
344 | SUN4I_FRONTEND_BYPASS_CSC_EN); | ||
345 | |||
346 | sun4i_frontend_scaler_init(frontend); | 413 | sun4i_frontend_scaler_init(frontend); |
347 | 414 | ||
348 | return 0; | 415 | return 0; |