diff options
Diffstat (limited to 'drivers/gpu/drm/sun4i')
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_backend.c | 119 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_backend.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_drv.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_frontend.c | 429 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_frontend.h | 63 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_layer.c | 43 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.c | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 2 |
11 files changed, 616 insertions, 92 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index bf49c55b0f2c..892197f52557 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -45,24 +45,6 @@ static const u32 sunxi_rgb2yuv_coef[12] = { 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 }; -/* - * These coefficients are taken from the A33 BSP from Allwinner. - * - * The formula is for each component, each coefficient being multiplied by - * 1024 and each constant being multiplied by 16: - * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135 - * R = 1.164 * Y + 1.596 * V - 222 - * B = 1.164 * Y + 2.018 * U + 276 - * - * This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255], - * following the BT601 spec. - */ -static const u32 sunxi_bt601_yuv2rgb_coef[12] = { - 0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877, - 0x000004a7, 0x00000000, 0x00000662, 0x00003211, - 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1, -}; - static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) { int i; @@ -155,6 +137,36 @@ static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode) return 0; } +static const uint32_t sun4i_backend_formats[] = { + DRM_FORMAT_ARGB1555, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGBA4444, + DRM_FORMAT_RGBA5551, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, +}; + +bool sun4i_backend_format_is_supported(uint32_t fmt, uint64_t modifier) +{ + unsigned int i; + + if (modifier != DRM_FORMAT_MOD_LINEAR) + return false; + + for (i = 0; i < ARRAY_SIZE(sun4i_backend_formats); i++) + if (sun4i_backend_formats[i] == fmt) + return true; + + return false; +} + int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, int layer, struct drm_plane *plane) { @@ -211,7 +223,8 @@ static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend, SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN); /* TODO: Add support for the multi-planar YUV formats */ - if (format->num_planes == 1) + if (drm_format_info_is_yuv_packed(format) && + drm_format_info_is_yuv_sampling_422(format)) val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422; else DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", fmt); @@ -395,6 +408,15 @@ int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer, return 0; } +void sun4i_backend_cleanup_layer(struct sun4i_backend *backend, + int layer) +{ + regmap_update_bits(backend->engine.regs, + SUN4I_BACKEND_ATTCTL_REG0(layer), + SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN | + SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0); +} + static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state) { u16 src_h = state->src_h >> 16; @@ -413,11 +435,50 @@ static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state) { struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane); struct sun4i_backend *backend = layer->backend; + uint32_t format = state->fb->format->format; + uint64_t modifier = state->fb->modifier; if (IS_ERR(backend->frontend)) return false; - return sun4i_backend_plane_uses_scaler(state); + if (!sun4i_frontend_format_is_supported(format, modifier)) + return false; + + if (!sun4i_backend_format_is_supported(format, modifier)) + return true; + + /* + * TODO: The backend alone allows 2x and 4x integer scaling, including + * support for an alpha component (which the frontend doesn't support). + * Use the backend directly instead of the frontend in this case, with + * another test to return false. + */ + + if (sun4i_backend_plane_uses_scaler(state)) + return true; + + /* + * Here the format is supported by both the frontend and the backend + * and no frontend scaling is required, so use the backend directly. + */ + return false; +} + +static bool sun4i_backend_plane_is_supported(struct drm_plane_state *state, + bool *uses_frontend) +{ + if (sun4i_backend_plane_uses_frontend(state)) { + *uses_frontend = true; + return true; + } + + *uses_frontend = false; + + /* Scaling is not supported without the frontend. */ + if (sun4i_backend_plane_uses_scaler(state)) + return false; + + return true; } static void sun4i_backend_atomic_begin(struct sunxi_engine *engine, @@ -460,14 +521,19 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, struct drm_framebuffer *fb = plane_state->fb; struct drm_format_name_buf format_name; - if (sun4i_backend_plane_uses_frontend(plane_state)) { + if (!sun4i_backend_plane_is_supported(plane_state, + &layer_state->uses_frontend)) + return -EINVAL; + + if (layer_state->uses_frontend) { DRM_DEBUG_DRIVER("Using the frontend for plane %d\n", plane->index); - - layer_state->uses_frontend = true; num_frontend_planes++; } else { - layer_state->uses_frontend = false; + if (fb->format->is_yuv) { + DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); + num_yuv_planes++; + } } DRM_DEBUG_DRIVER("Plane FB format is %s\n", @@ -476,11 +542,6 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE)) num_alpha_planes++; - if (fb->format->is_yuv) { - DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); - num_yuv_planes++; - } - DRM_DEBUG_DRIVER("Plane zpos is %d\n", plane_state->normalized_zpos); diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h index e3d4c6035eb2..01f66463271b 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.h +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h @@ -198,6 +198,7 @@ engine_to_sun4i_backend(struct sunxi_engine *engine) void sun4i_backend_layer_enable(struct sun4i_backend *backend, int layer, bool enable); +bool sun4i_backend_format_is_supported(uint32_t fmt, uint64_t modifier); int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, int layer, struct drm_plane *plane); int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, @@ -208,5 +209,7 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend, int layer, uint32_t in_fmt); int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer, struct drm_plane *plane); +void sun4i_backend_cleanup_layer(struct sun4i_backend *backend, + int layer); #endif /* _SUN4I_BACKEND_H_ */ diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index ef773d36baf0..93da837194cf 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -28,6 +28,16 @@ #include "sun4i_tcon.h" #include "sun8i_tcon_top.h" +static int drm_sun4i_gem_dumb_create(struct drm_file *file_priv, + struct drm_device *drm, + struct drm_mode_create_dumb *args) +{ + /* The hardware only allows even pitches for YUV buffers. */ + args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), 2); + + return drm_gem_cma_dumb_create_internal(file_priv, drm, args); +} + DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops); static struct drm_driver sun4i_drv_driver = { @@ -42,7 +52,7 @@ static struct drm_driver sun4i_drv_driver = { .minor = 0, /* GEM Operations */ - .dumb_create = drm_gem_cma_dumb_create, + .dumb_create = drm_sun4i_gem_dumb_create, .gem_free_object_unlocked = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, @@ -87,6 +97,7 @@ static int sun4i_drv_bind(struct device *dev) } drm_mode_config_init(drm); + drm->mode_config.allow_fb_modifiers = true; ret = component_bind_all(drm->dev, drm); if (ret) { @@ -400,6 +411,7 @@ static const struct of_device_id sun4i_drv_of_table[] = { { .compatible = "allwinner,sun8i-v3s-display-engine" }, { .compatible = "allwinner,sun9i-a80-display-engine" }, { .compatible = "allwinner,sun50i-a64-display-engine" }, + { .compatible = "allwinner,sun50i-h6-display-engine" }, { } }; MODULE_DEVICE_TABLE(of, sun4i_drv_of_table); diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c index ddf6cfa6dd23..e8239d4d4dd5 100644 --- a/drivers/gpu/drm/sun4i/sun4i_frontend.c +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c @@ -10,6 +10,7 @@ #include <linux/clk.h> #include <linux/component.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> @@ -48,10 +49,38 @@ static const u32 sun4i_frontend_horz_coef[64] = { 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42, }; +/* + * These coefficients are taken from the A33 BSP from Allwinner. + * + * The first three values of each row are coded as 13-bit signed fixed-point + * numbers, with 10 bits for the fractional part. The fourth value is a + * constant coded as a 14-bit signed fixed-point number with 4 bits for the + * fractional part. + * + * The values in table order give the following colorspace translation: + * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135 + * R = 1.164 * Y + 1.596 * V - 222 + * B = 1.164 * Y + 2.018 * U + 276 + * + * This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255], + * following the BT601 spec. + */ +const u32 sunxi_bt601_yuv2rgb_coef[12] = { + 0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877, + 0x000004a7, 0x00000000, 0x00000662, 0x00003211, + 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1, +}; +EXPORT_SYMBOL(sunxi_bt601_yuv2rgb_coef); + static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend) { int i; + if (frontend->data->has_coef_access_ctrl) + regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, + SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL, + SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL); + for (i = 0; i < 32; i++) { regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i), sun4i_frontend_horz_coef[2 * i]); @@ -67,9 +96,11 @@ static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend) sun4i_frontend_vert_coef[i]); } - regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, - SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL, - SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL); + if (frontend->data->has_coef_rdy) + regmap_write_bits(frontend->regs, + SUN4I_FRONTEND_FRM_CTRL_REG, + SUN4I_FRONTEND_FRM_CTRL_COEF_RDY, + SUN4I_FRONTEND_FRM_CTRL_COEF_RDY); } int sun4i_frontend_init(struct sun4i_frontend *frontend) @@ -84,31 +115,226 @@ void sun4i_frontend_exit(struct sun4i_frontend *frontend) } EXPORT_SYMBOL(sun4i_frontend_exit); +static bool sun4i_frontend_format_chroma_requires_swap(uint32_t fmt) +{ + switch (fmt) { + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YVU444: + return true; + + default: + return false; + } +} + +static bool sun4i_frontend_format_supports_tiling(uint32_t fmt) +{ + switch (fmt) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV61: + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YVU411: + return true; + + default: + return false; + } +} + void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, struct drm_plane *plane) { struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; + unsigned int strides[3] = {}; + dma_addr_t paddr; + bool swap; + + if (fb->modifier == DRM_FORMAT_MOD_ALLWINNER_TILED) { + unsigned int width = state->src_w >> 16; + unsigned int offset; + + strides[0] = SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[0]); + + /* + * The X1 offset is the offset to the bottom-right point in the + * end tile, which is the final pixel (at offset width - 1) + * within the end tile (with a 32-byte mask). + */ + offset = (width - 1) & (32 - 1); + + regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF0_REG, + SUN4I_FRONTEND_TB_OFF_X1(offset)); + + if (fb->format->num_planes > 1) { + strides[1] = + SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[1]); + + regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF1_REG, + SUN4I_FRONTEND_TB_OFF_X1(offset)); + } + + if (fb->format->num_planes > 2) { + strides[2] = + SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[2]); + + regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF2_REG, + SUN4I_FRONTEND_TB_OFF_X1(offset)); + } + } else { + strides[0] = fb->pitches[0]; + + if (fb->format->num_planes > 1) + strides[1] = fb->pitches[1]; + + if (fb->format->num_planes > 2) + strides[2] = fb->pitches[2]; + } /* Set the line width */ DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]); regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG, - fb->pitches[0]); + strides[0]); + + if (fb->format->num_planes > 1) + regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD1_REG, + strides[1]); + + if (fb->format->num_planes > 2) + regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD2_REG, + strides[2]); + + /* Some planar formats require chroma channel swapping by hand. */ + swap = sun4i_frontend_format_chroma_requires_swap(fb->format->format); /* Set the physical address of the buffer in memory */ paddr = drm_fb_cma_get_gem_addr(fb, state, 0); paddr -= PHYS_OFFSET; - DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); + DRM_DEBUG_DRIVER("Setting buffer #0 address to %pad\n", &paddr); regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr); + + if (fb->format->num_planes > 1) { + paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 2 : 1); + paddr -= PHYS_OFFSET; + DRM_DEBUG_DRIVER("Setting buffer #1 address to %pad\n", &paddr); + regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR1_REG, + paddr); + } + + if (fb->format->num_planes > 2) { + paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 1 : 2); + paddr -= PHYS_OFFSET; + DRM_DEBUG_DRIVER("Setting buffer #2 address to %pad\n", &paddr); + regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR2_REG, + paddr); + } } EXPORT_SYMBOL(sun4i_frontend_update_buffer); -static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val) +static int +sun4i_frontend_drm_format_to_input_fmt(const struct drm_format_info *format, + u32 *val) { - switch (fmt) { - case DRM_FORMAT_ARGB8888: - *val = 5; + if (!format->is_yuv) + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB; + else if (drm_format_info_is_yuv_sampling_411(format)) + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411; + else if (drm_format_info_is_yuv_sampling_420(format)) + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420; + else if (drm_format_info_is_yuv_sampling_422(format)) + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422; + else if (drm_format_info_is_yuv_sampling_444(format)) + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444; + else + return -EINVAL; + + return 0; +} + +static int +sun4i_frontend_drm_format_to_input_mode(const struct drm_format_info *format, + uint64_t modifier, u32 *val) +{ + bool tiled = (modifier == DRM_FORMAT_MOD_ALLWINNER_TILED); + + switch (format->num_planes) { + case 1: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED; + return 0; + + case 2: + *val = tiled ? SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_SEMIPLANAR + : SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR; + return 0; + + case 3: + *val = tiled ? SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_PLANAR + : SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR; + return 0; + + default: + return -EINVAL; + } +} + +static int +sun4i_frontend_drm_format_to_input_sequence(const struct drm_format_info *format, + u32 *val) +{ + /* Planar formats have an explicit input sequence. */ + if (drm_format_info_is_yuv_planar(format)) { + *val = 0; + return 0; + } + + switch (format->format) { + case DRM_FORMAT_BGRX8888: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX; + return 0; + + case DRM_FORMAT_NV12: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV; + return 0; + + case DRM_FORMAT_NV16: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV; + return 0; + + case DRM_FORMAT_NV21: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU; + return 0; + + case DRM_FORMAT_NV61: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU; + return 0; + + case DRM_FORMAT_UYVY: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UYVY; + return 0; + + case DRM_FORMAT_VYUY: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VYUY; + return 0; + + case DRM_FORMAT_XRGB8888: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB; + return 0; + + case DRM_FORMAT_YUYV: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YUYV; + return 0; + + case DRM_FORMAT_YVYU: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YVYU; return 0; default: @@ -119,9 +345,12 @@ static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val) static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val) { switch (fmt) { + case DRM_FORMAT_BGRX8888: + *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888; + return 0; + case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ARGB8888: - *val = 2; + *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888; return 0; default: @@ -129,22 +358,76 @@ static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val) } } +static const uint32_t sun4i_frontend_formats[] = { + DRM_FORMAT_BGRX8888, + DRM_FORMAT_NV12, + DRM_FORMAT_NV16, + DRM_FORMAT_NV21, + DRM_FORMAT_NV61, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUV411, + DRM_FORMAT_YUV420, + DRM_FORMAT_YUV422, + DRM_FORMAT_YUV444, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVU411, + DRM_FORMAT_YVU420, + DRM_FORMAT_YVU422, + DRM_FORMAT_YVU444, + DRM_FORMAT_YVYU, +}; + +bool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier) +{ + unsigned int i; + + if (modifier == DRM_FORMAT_MOD_ALLWINNER_TILED) + return sun4i_frontend_format_supports_tiling(fmt); + else if (modifier != DRM_FORMAT_MOD_LINEAR) + return false; + + for (i = 0; i < ARRAY_SIZE(sun4i_frontend_formats); i++) + if (sun4i_frontend_formats[i] == fmt) + return true; + + return false; +} +EXPORT_SYMBOL(sun4i_frontend_format_is_supported); + int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, struct drm_plane *plane, uint32_t out_fmt) { struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; + const struct drm_format_info *format = fb->format; + uint64_t modifier = fb->modifier; u32 out_fmt_val; - u32 in_fmt_val; + u32 in_fmt_val, in_mod_val, in_ps_val; + unsigned int i; + u32 bypass; int ret; - ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format, - &in_fmt_val); + ret = sun4i_frontend_drm_format_to_input_fmt(format, &in_fmt_val); if (ret) { DRM_DEBUG_DRIVER("Invalid input format\n"); return ret; } + ret = sun4i_frontend_drm_format_to_input_mode(format, modifier, + &in_mod_val); + if (ret) { + DRM_DEBUG_DRIVER("Invalid input mode\n"); + return ret; + } + + ret = sun4i_frontend_drm_format_to_input_sequence(format, &in_ps_val); + if (ret) { + DRM_DEBUG_DRIVER("Invalid pixel sequence\n"); + return ret; + } + ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val); if (ret) { DRM_DEBUG_DRIVER("Invalid output format\n"); @@ -155,17 +438,42 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, * I have no idea what this does exactly, but it seems to be * related to the scaler FIR filter phase parameters. */ - regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400); - regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400); - regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400); - regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400); - regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400); - regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, + frontend->data->ch_phase[0].horzphase); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, + frontend->data->ch_phase[1].horzphase); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, + frontend->data->ch_phase[0].vertphase[0]); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, + frontend->data->ch_phase[1].vertphase[0]); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, + frontend->data->ch_phase[0].vertphase[1]); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, + frontend->data->ch_phase[1].vertphase[1]); + + /* + * Checking the input format is sufficient since we currently only + * support RGB output formats to the backend. If YUV output formats + * ever get supported, an YUV input and output would require bypassing + * the CSC engine too. + */ + if (format->is_yuv) { + /* Setup the CSC engine for YUV to RGB conversion. */ + bypass = 0; + + for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++) + regmap_write(frontend->regs, + SUN4I_FRONTEND_CSC_COEF_REG(i), + sunxi_bt601_yuv2rgb_coef[i]); + } else { + bypass = SUN4I_FRONTEND_BYPASS_CSC_EN; + } + + regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG, + SUN4I_FRONTEND_BYPASS_CSC_EN, bypass); regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, - SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) | - SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(in_fmt_val) | - SUN4I_FRONTEND_INPUT_FMT_PS(1)); + in_mod_val | in_fmt_val | in_ps_val); /* * TODO: It look like the A31 and A80 at least will need the @@ -173,7 +481,7 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, * ARGB8888). */ regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, - SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(out_fmt_val)); + out_fmt_val); return 0; } @@ -183,16 +491,24 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend, struct drm_plane *plane) { struct drm_plane_state *state = plane->state; + struct drm_framebuffer *fb = state->fb; + uint32_t luma_width, luma_height; + uint32_t chroma_width, chroma_height; /* Set height and width */ DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n", state->crtc_w, state->crtc_h); + + luma_width = state->src_w >> 16; + luma_height = state->src_h >> 16; + + chroma_width = DIV_ROUND_UP(luma_width, fb->format->hsub); + chroma_height = DIV_ROUND_UP(luma_height, fb->format->vsub); + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG, - SUN4I_FRONTEND_INSIZE(state->src_h >> 16, - state->src_w >> 16)); + SUN4I_FRONTEND_INSIZE(luma_height, luma_width)); regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG, - SUN4I_FRONTEND_INSIZE(state->src_h >> 16, - state->src_w >> 16)); + SUN4I_FRONTEND_INSIZE(chroma_height, chroma_width)); regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG, SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); @@ -200,14 +516,14 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend, SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG, - state->src_w / state->crtc_w); + (luma_width << 16) / state->crtc_w); regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG, - state->src_w / state->crtc_w); + (chroma_width << 16) / state->crtc_w); regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG, - state->src_h / state->crtc_h); + (luma_height << 16) / state->crtc_h); regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG, - state->src_h / state->crtc_h); + (chroma_height << 16) / state->crtc_h); regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, SUN4I_FRONTEND_FRM_CTRL_REG_RDY, @@ -250,6 +566,10 @@ static int sun4i_frontend_bind(struct device *dev, struct device *master, frontend->dev = dev; frontend->node = dev->of_node; + frontend->data = of_device_get_match_data(dev); + if (!frontend->data) + return -ENODEV; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) @@ -339,10 +659,6 @@ static int sun4i_frontend_runtime_resume(struct device *dev) SUN4I_FRONTEND_EN_EN, SUN4I_FRONTEND_EN_EN); - regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG, - SUN4I_FRONTEND_BYPASS_CSC_EN, - SUN4I_FRONTEND_BYPASS_CSC_EN); - sun4i_frontend_scaler_init(frontend); return 0; @@ -366,8 +682,47 @@ static const struct dev_pm_ops sun4i_frontend_pm_ops = { .runtime_suspend = sun4i_frontend_runtime_suspend, }; +static const struct sun4i_frontend_data sun4i_a10_frontend = { + .ch_phase = { + { + .horzphase = 0, + .vertphase = { 0, 0 }, + }, + { + .horzphase = 0xfc000, + .vertphase = { 0xfc000, 0xfc000 }, + }, + }, + .has_coef_rdy = true, +}; + +static const struct sun4i_frontend_data sun8i_a33_frontend = { + .ch_phase = { + { + .horzphase = 0x400, + .vertphase = { 0x400, 0x400 }, + }, + { + .horzphase = 0x400, + .vertphase = { 0x400, 0x400 }, + }, + }, + .has_coef_access_ctrl = true, +}; + const struct of_device_id sun4i_frontend_of_table[] = { - { .compatible = "allwinner,sun8i-a33-display-frontend" }, + { + .compatible = "allwinner,sun4i-a10-display-frontend", + .data = &sun4i_a10_frontend + }, + { + .compatible = "allwinner,sun7i-a20-display-frontend", + .data = &sun4i_a10_frontend + }, + { + .compatible = "allwinner,sun8i-a33-display-frontend", + .data = &sun8i_a33_frontend + }, { } }; EXPORT_SYMBOL(sun4i_frontend_of_table); diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h index 02661ce81f3e..0c382c1ddb0f 100644 --- a/drivers/gpu/drm/sun4i/sun4i_frontend.h +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h @@ -22,16 +22,57 @@ #define SUN4I_FRONTEND_BYPASS_CSC_EN BIT(1) #define SUN4I_FRONTEND_BUF_ADDR0_REG 0x020 +#define SUN4I_FRONTEND_BUF_ADDR1_REG 0x024 +#define SUN4I_FRONTEND_BUF_ADDR2_REG 0x028 + +#define SUN4I_FRONTEND_TB_OFF0_REG 0x030 +#define SUN4I_FRONTEND_TB_OFF1_REG 0x034 +#define SUN4I_FRONTEND_TB_OFF2_REG 0x038 +#define SUN4I_FRONTEND_TB_OFF_X1(x1) ((x1) << 16) +#define SUN4I_FRONTEND_TB_OFF_Y0(y0) ((y0) << 8) +#define SUN4I_FRONTEND_TB_OFF_X0(x0) (x0) #define SUN4I_FRONTEND_LINESTRD0_REG 0x040 +#define SUN4I_FRONTEND_LINESTRD1_REG 0x044 +#define SUN4I_FRONTEND_LINESTRD2_REG 0x048 + +/* + * In tiled mode, the stride is defined as the distance between the start of the + * end line of the current tile and the start of the first line in the next + * vertical tile. + * + * Tiles are represented in row-major order, thus the end line of current tile + * starts at: 31 * 32 (31 lines of 32 cols), the next vertical tile starts at: + * 32-bit-aligned-width * 32 and the distance is: + * 32 * (32-bit-aligned-width - 31). + */ +#define SUN4I_FRONTEND_LINESTRD_TILED(stride) (((stride) - 31) * 32) #define SUN4I_FRONTEND_INPUT_FMT_REG 0x04c -#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod) ((mod) << 8) -#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt) ((fmt) << 4) -#define SUN4I_FRONTEND_INPUT_FMT_PS(ps) (ps) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR (0 << 8) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED (1 << 8) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR (2 << 8) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_PLANAR (4 << 8) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_SEMIPLANAR (6 << 8) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444 (0 << 4) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422 (1 << 4) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420 (2 << 4) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411 (3 << 4) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB (5 << 4) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UYVY 0 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YUYV 1 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VYUY 2 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YVYU 3 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV 0 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU 1 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX 0 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB 1 #define SUN4I_FRONTEND_OUTPUT_FMT_REG 0x05c -#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt) (fmt) +#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888 1 +#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888 2 + +#define SUN4I_FRONTEND_CSC_COEF_REG(c) (0x070 + (0x4 * (c))) #define SUN4I_FRONTEND_CH0_INSIZE_REG 0x100 #define SUN4I_FRONTEND_INSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1))) @@ -71,6 +112,16 @@ struct drm_plane; struct regmap; struct reset_control; +struct sun4i_frontend_data { + bool has_coef_access_ctrl; + bool has_coef_rdy; + + struct { + u32 horzphase; + u32 vertphase[2]; + } ch_phase[2]; +}; + struct sun4i_frontend { struct list_head list; struct device *dev; @@ -81,9 +132,12 @@ struct sun4i_frontend { struct clk *ram_clk; struct regmap *regs; struct reset_control *reset; + + const struct sun4i_frontend_data *data; }; extern const struct of_device_id sun4i_frontend_of_table[]; +extern const u32 sunxi_bt601_yuv2rgb_coef[12]; int sun4i_frontend_init(struct sun4i_frontend *frontend); void sun4i_frontend_exit(struct sun4i_frontend *frontend); @@ -95,5 +149,6 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend, struct drm_plane *plane); int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, struct drm_plane *plane, uint32_t out_fmt); +bool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier); #endif /* _SUN4I_FRONTEND_H_ */ diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c index 061d2e0d9011..554a6f4561f3 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c @@ -52,7 +52,8 @@ static int sun4i_hdmi_setup_avi_infoframes(struct sun4i_hdmi *hdmi, u8 buffer[17]; int i, ret; - ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, + &hdmi->connector, mode); if (ret < 0) { DRM_ERROR("Failed to get infoframes from mode\n"); return ret; diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 78f77af8805a..c5a999ca1d72 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -12,6 +12,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_plane_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> #include <drm/drmP.h> #include "sun4i_backend.h" @@ -92,14 +93,16 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane, struct sun4i_backend *backend = layer->backend; struct sun4i_frontend *frontend = backend->frontend; + sun4i_backend_cleanup_layer(backend, layer->id); + if (layer_state->uses_frontend) { sun4i_frontend_init(frontend); sun4i_frontend_update_coord(frontend, plane); sun4i_frontend_update_buffer(frontend, plane); sun4i_frontend_update_formats(frontend, plane, - DRM_FORMAT_ARGB8888); + DRM_FORMAT_XRGB8888); sun4i_backend_update_layer_frontend(backend, layer->id, - DRM_FORMAT_ARGB8888); + DRM_FORMAT_XRGB8888); sun4i_frontend_enable(frontend); } else { sun4i_backend_update_layer_formats(backend, layer->id, plane); @@ -111,7 +114,15 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane, sun4i_backend_layer_enable(backend, layer->id, true); } +static bool sun4i_layer_format_mod_supported(struct drm_plane *plane, + uint32_t format, uint64_t modifier) +{ + return sun4i_backend_format_is_supported(format, modifier) || + sun4i_frontend_format_is_supported(format, modifier); +} + static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = { + .prepare_fb = drm_gem_fb_prepare_fb, .atomic_disable = sun4i_backend_layer_atomic_disable, .atomic_update = sun4i_backend_layer_atomic_update, }; @@ -123,23 +134,43 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = { .disable_plane = drm_atomic_helper_disable_plane, .reset = sun4i_backend_layer_reset, .update_plane = drm_atomic_helper_update_plane, + .format_mod_supported = sun4i_layer_format_mod_supported, }; -static const uint32_t sun4i_backend_layer_formats[] = { +static const uint32_t sun4i_layer_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_ARGB4444, DRM_FORMAT_ARGB1555, + DRM_FORMAT_BGRX8888, DRM_FORMAT_RGBA5551, DRM_FORMAT_RGBA4444, DRM_FORMAT_RGB888, DRM_FORMAT_RGB565, + DRM_FORMAT_NV12, + DRM_FORMAT_NV16, + DRM_FORMAT_NV21, + DRM_FORMAT_NV61, DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUV411, + DRM_FORMAT_YUV420, + DRM_FORMAT_YUV422, + DRM_FORMAT_YUV444, DRM_FORMAT_YUYV, + DRM_FORMAT_YVU411, + DRM_FORMAT_YVU420, + DRM_FORMAT_YVU422, + DRM_FORMAT_YVU444, DRM_FORMAT_YVYU, }; +static const uint64_t sun4i_layer_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_ALLWINNER_TILED, + DRM_FORMAT_MOD_INVALID +}; + static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, struct sun4i_backend *backend, enum drm_plane_type type) @@ -154,9 +185,9 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, /* possible crtcs are set later */ ret = drm_universal_plane_init(drm, &layer->plane, 0, &sun4i_backend_layer_funcs, - sun4i_backend_layer_formats, - ARRAY_SIZE(sun4i_backend_layer_formats), - NULL, type, NULL); + sun4i_layer_formats, + ARRAY_SIZE(sun4i_layer_formats), + sun4i_layer_modifiers, type, NULL); if (ret) { dev_err(drm->dev, "Couldn't initialize layer\n"); return ERR_PTR(ret); diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index f949287d926c..0420f5c978b9 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -478,8 +478,11 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon, } static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, + const struct drm_encoder *encoder, const struct drm_display_mode *mode) { + struct drm_connector *connector = sun4i_tcon_get_connector(encoder); + struct drm_display_info display_info = connector->display_info; unsigned int bp, hsync, vsync; u8 clk_delay; u32 val = 0; @@ -491,8 +494,7 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, sun4i_tcon0_mode_set_common(tcon, mode); /* Set dithering if needed */ - if (tcon->panel) - sun4i_tcon0_mode_set_dithering(tcon, tcon->panel->connector); + sun4i_tcon0_mode_set_dithering(tcon, connector); /* Adjust clock delay */ clk_delay = sun4i_tcon_get_clk_delay(mode, 0); @@ -541,6 +543,9 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, if (mode->flags & DRM_MODE_FLAG_PVSYNC) val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; + if (display_info.bus_flags & DRM_BUS_FLAG_DE_LOW) + val |= SUN4I_TCON0_IO_POL_DE_NEGATIVE; + /* * On A20 and similar SoCs, the only way to achieve Positive Edge * (Rising Edge), is setting dclk clock phase to 2/3(240°). @@ -556,20 +561,16 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, * Following code is a way to avoid quirks all around TCON * and DOTCLOCK drivers. */ - if (tcon->panel) { - struct drm_panel *panel = tcon->panel; - struct drm_connector *connector = panel->connector; - struct drm_display_info display_info = connector->display_info; + if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE) + clk_set_phase(tcon->dclk, 240); - if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE) - clk_set_phase(tcon->dclk, 240); - - if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE) - clk_set_phase(tcon->dclk, 0); - } + if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE) + clk_set_phase(tcon->dclk, 0); regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, - SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE, + SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | + SUN4I_TCON0_IO_POL_VSYNC_POSITIVE | + SUN4I_TCON0_IO_POL_DE_NEGATIVE, val); /* Map output pins to channel 0 */ @@ -684,7 +685,7 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, sun4i_tcon0_mode_set_lvds(tcon, encoder, mode); break; case DRM_MODE_ENCODER_NONE: - sun4i_tcon0_mode_set_rgb(tcon, mode); + sun4i_tcon0_mode_set_rgb(tcon, encoder, mode); sun4i_tcon_set_mux(tcon, 0, encoder); break; case DRM_MODE_ENCODER_TVDAC: diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index 3d492c8be1fc..b5214d71610f 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -116,6 +116,7 @@ #define SUN4I_TCON0_IO_POL_REG 0x88 #define SUN4I_TCON0_IO_POL_DCLK_PHASE(phase) ((phase & 3) << 28) +#define SUN4I_TCON0_IO_POL_DE_NEGATIVE BIT(27) #define SUN4I_TCON0_IO_POL_HSYNC_POSITIVE BIT(25) #define SUN4I_TCON0_IO_POL_VSYNC_POSITIVE BIT(24) diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c index e3fc8fa920fb..18534263a05d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c @@ -19,6 +19,7 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_plane_helper.h> #include <drm/drmP.h> @@ -300,6 +301,7 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane, } static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = { + .prepare_fb = drm_gem_fb_prepare_fb, .atomic_check = sun8i_ui_layer_atomic_check, .atomic_disable = sun8i_ui_layer_atomic_disable, .atomic_update = sun8i_ui_layer_atomic_update, diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c index 4249edfb47ed..87be898f9b7a 100644 --- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c @@ -13,6 +13,7 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_plane_helper.h> #include <drm/drmP.h> @@ -336,6 +337,7 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane, } static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = { + .prepare_fb = drm_gem_fb_prepare_fb, .atomic_check = sun8i_vi_layer_atomic_check, .atomic_disable = sun8i_vi_layer_atomic_disable, .atomic_update = sun8i_vi_layer_atomic_update, |