diff options
Diffstat (limited to 'drivers/gpu/drm/sun4i')
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_backend.c | 154 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_backend.h | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_drv.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_layer.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_lvds.c | 55 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_rgb.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.c | 52 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun6i_drc.c | 1 |
9 files changed, 297 insertions, 8 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 092ade4ff6a5..9bad54f3de38 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -42,6 +42,56 @@ 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 inline bool sun4i_backend_format_is_planar_yuv(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YUV444: + return true; + default: + return false; + } +} + +static inline bool sun4i_backend_format_is_packed_yuv422(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + return true; + + default: + return false; + } +} + +static inline bool sun4i_backend_format_is_yuv(uint32_t format) +{ + return sun4i_backend_format_is_planar_yuv(format) || + sun4i_backend_format_is_packed_yuv422(format); +} + static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) { int i; @@ -166,6 +216,61 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, return 0; } +static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend, + int layer, struct drm_plane *plane) +{ + struct drm_plane_state *state = plane->state; + struct drm_framebuffer *fb = state->fb; + uint32_t format = fb->format->format; + u32 val = SUN4I_BACKEND_IYUVCTL_EN; + int i; + + for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++) + regmap_write(backend->engine.regs, + SUN4I_BACKEND_YGCOEF_REG(i), + sunxi_bt601_yuv2rgb_coef[i]); + + /* + * We should do that only for a single plane, but the + * framebuffer's atomic_check has our back on this. + */ + regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer), + SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, + SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN); + + /* TODO: Add support for the multi-planar YUV formats */ + if (sun4i_backend_format_is_packed_yuv422(format)) + val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422; + else + DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", format); + + /* + * Allwinner seems to list the pixel sequence from right to left, while + * DRM lists it from left to right. + */ + switch (format) { + case DRM_FORMAT_YUYV: + val |= SUN4I_BACKEND_IYUVCTL_FBPS_VYUY; + break; + case DRM_FORMAT_YVYU: + val |= SUN4I_BACKEND_IYUVCTL_FBPS_UYVY; + break; + case DRM_FORMAT_UYVY: + val |= SUN4I_BACKEND_IYUVCTL_FBPS_YVYU; + break; + case DRM_FORMAT_VYUY: + val |= SUN4I_BACKEND_IYUVCTL_FBPS_YUYV; + break; + default: + DRM_DEBUG_DRIVER("Unsupported YUV pixel sequence (0x%x)\n", + format); + } + + regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVCTL_REG, val); + + return 0; +} + int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, int layer, struct drm_plane *plane) { @@ -175,6 +280,10 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, u32 val; int ret; + /* Clear the YUV mode */ + regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer), + SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0); + if (plane->state->crtc) interlaced = plane->state->crtc->state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE; @@ -186,6 +295,9 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n", interlaced ? "on" : "off"); + if (sun4i_backend_format_is_yuv(fb->format->format)) + return sun4i_backend_update_yuv_format(backend, layer, plane); + ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val); if (ret) { DRM_DEBUG_DRIVER("Invalid format\n"); @@ -223,6 +335,21 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend, return 0; } +static int sun4i_backend_update_yuv_buffer(struct sun4i_backend *backend, + struct drm_framebuffer *fb, + dma_addr_t paddr) +{ + /* TODO: Add support for the multi-planar YUV formats */ + DRM_DEBUG_DRIVER("Setting packed YUV buffer address to %pad\n", &paddr); + regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVADD_REG(0), paddr); + + DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8); + regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVLINEWIDTH_REG(0), + fb->pitches[0] * 8); + + return 0; +} + int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, int layer, struct drm_plane *plane) { @@ -248,6 +375,9 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, */ paddr -= PHYS_OFFSET; + if (sun4i_backend_format_is_yuv(fb->format->format)) + return sun4i_backend_update_yuv_buffer(backend, fb, paddr); + /* Write the 32 lower bits of the address (in bits) */ lo_paddr = paddr << 3; DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr); @@ -330,6 +460,7 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, unsigned int num_planes = 0; unsigned int num_alpha_planes = 0; unsigned int num_frontend_planes = 0; + unsigned int num_yuv_planes = 0; unsigned int current_pipe = 0; unsigned int i; @@ -362,6 +493,11 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, if (fb->format->has_alpha) num_alpha_planes++; + if (sun4i_backend_format_is_yuv(fb->format->format)) { + DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); + num_yuv_planes++; + } + DRM_DEBUG_DRIVER("Plane zpos is %d\n", plane_state->normalized_zpos); @@ -430,13 +566,20 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, s_state->pipe = current_pipe; } + /* We can only have a single YUV plane at a time */ + if (num_yuv_planes > SUN4I_BACKEND_NUM_YUV_PLANES) { + DRM_DEBUG_DRIVER("Too many planes with YUV, rejecting...\n"); + return -EINVAL; + } + if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) { DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n"); return -EINVAL; } - DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video\n", - num_planes, num_alpha_planes, num_frontend_planes); + DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video, %u YUV\n", + num_planes, num_alpha_planes, num_frontend_planes, + num_yuv_planes); return 0; } @@ -793,6 +936,9 @@ static const struct sun4i_backend_quirks sun7i_backend_quirks = { static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = { }; +static const struct sun4i_backend_quirks sun9i_backend_quirks = { +}; + static const struct of_device_id sun4i_backend_of_table[] = { { .compatible = "allwinner,sun4i-a10-display-backend", @@ -814,6 +960,10 @@ static const struct of_device_id sun4i_backend_of_table[] = { .compatible = "allwinner,sun8i-a33-display-backend", .data = &sun8i_a33_backend_quirks, }, + { + .compatible = "allwinner,sun9i-a80-display-backend", + .data = &sun9i_backend_quirks, + }, { } }; MODULE_DEVICE_TABLE(of, sun4i_backend_of_table); diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h index 52e77591186a..316f2179e9e1 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.h +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h @@ -72,6 +72,7 @@ #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15) #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10) #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10) +#define SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN BIT(2) #define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1) #define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l))) @@ -110,7 +111,23 @@ #define SUN4I_BACKEND_SPREN_REG 0x900 #define SUN4I_BACKEND_SPRFMTCTL_REG 0x908 #define SUN4I_BACKEND_SPRALPHACTL_REG 0x90c + #define SUN4I_BACKEND_IYUVCTL_REG 0x920 +#define SUN4I_BACKEND_IYUVCTL_FBFMT_MASK GENMASK(14, 12) +#define SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV444 (4 << 12) +#define SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422 (3 << 12) +#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV444 (2 << 12) +#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV222 (1 << 12) +#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV111 (0 << 12) +#define SUN4I_BACKEND_IYUVCTL_FBPS_MASK GENMASK(9, 8) +#define SUN4I_BACKEND_IYUVCTL_FBPS_YVYU (3 << 8) +#define SUN4I_BACKEND_IYUVCTL_FBPS_VYUY (2 << 8) +#define SUN4I_BACKEND_IYUVCTL_FBPS_YUYV (1 << 8) +#define SUN4I_BACKEND_IYUVCTL_FBPS_UYVY (0 << 8) +#define SUN4I_BACKEND_IYUVCTL_FBPS_VUYA (1 << 8) +#define SUN4I_BACKEND_IYUVCTL_FBPS_AYUV (0 << 8) +#define SUN4I_BACKEND_IYUVCTL_EN BIT(0) + #define SUN4I_BACKEND_IYUVADD_REG(c) (0x930 + (0x4 * (c))) #define SUN4I_BACKEND_IYUVLINEWIDTH_REG(c) (0x940 + (0x4 * (c))) @@ -149,6 +166,7 @@ #define SUN4I_BACKEND_NUM_LAYERS 4 #define SUN4I_BACKEND_NUM_ALPHA_LAYERS 1 #define SUN4I_BACKEND_NUM_FRONTEND_LAYERS 1 +#define SUN4I_BACKEND_NUM_YUV_PLANES 1 struct sun4i_backend { struct sunxi_engine engine; diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index a0f43b81c64c..7f0705ef9f4e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -176,7 +176,13 @@ static bool sun4i_drv_node_is_frontend(struct device_node *node) of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") || of_device_is_compatible(node, "allwinner,sun6i-a31-display-frontend") || of_device_is_compatible(node, "allwinner,sun7i-a20-display-frontend") || - of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend"); + of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend") || + of_device_is_compatible(node, "allwinner,sun9i-a80-display-frontend"); +} + +static bool sun4i_drv_node_is_deu(struct device_node *node) +{ + return of_device_is_compatible(node, "allwinner,sun9i-a80-deu"); } static bool sun4i_drv_node_is_supported_frontend(struct device_node *node) @@ -257,7 +263,8 @@ static int sun4i_drv_add_endpoints(struct device *dev, * enabled frontend supported by the driver, we add it to our * component list. */ - if (!sun4i_drv_node_is_frontend(node) || + if (!(sun4i_drv_node_is_frontend(node) || + sun4i_drv_node_is_deu(node)) || (sun4i_drv_node_is_supported_frontend(node) && of_device_is_available(node))) { /* Add current component */ @@ -361,6 +368,7 @@ static const struct of_device_id sun4i_drv_of_table[] = { { .compatible = "allwinner,sun8i-a83t-display-engine" }, { .compatible = "allwinner,sun8i-h3-display-engine" }, { .compatible = "allwinner,sun8i-v3s-display-engine" }, + { .compatible = "allwinner,sun9i-a80-display-engine" }, { } }; MODULE_DEVICE_TABLE(of, sun4i_drv_of_table); diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 33ad377569ec..2949a3c912c1 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -134,7 +134,11 @@ static const uint32_t sun4i_backend_layer_formats[] = { DRM_FORMAT_RGBA4444, DRM_FORMAT_RGB888, DRM_FORMAT_RGB565, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, }; static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c index be3f14d7746d..bffff4c9fbf5 100644 --- a/drivers/gpu/drm/sun4i/sun4i_lvds.c +++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c @@ -94,9 +94,64 @@ static void sun4i_lvds_encoder_disable(struct drm_encoder *encoder) } } +static enum drm_mode_status sun4i_lvds_encoder_mode_valid(struct drm_encoder *crtc, + const struct drm_display_mode *mode) +{ + struct sun4i_lvds *lvds = drm_encoder_to_sun4i_lvds(crtc); + struct sun4i_tcon *tcon = lvds->tcon; + u32 hsync = mode->hsync_end - mode->hsync_start; + u32 vsync = mode->vsync_end - mode->vsync_start; + unsigned long rate = mode->clock * 1000; + long rounded_rate; + + DRM_DEBUG_DRIVER("Validating modes...\n"); + + if (hsync < 1) + return MODE_HSYNC_NARROW; + + if (hsync > 0x3ff) + return MODE_HSYNC_WIDE; + + if ((mode->hdisplay < 1) || (mode->htotal < 1)) + return MODE_H_ILLEGAL; + + if ((mode->hdisplay > 0x7ff) || (mode->htotal > 0xfff)) + return MODE_BAD_HVALUE; + + DRM_DEBUG_DRIVER("Horizontal parameters OK\n"); + + if (vsync < 1) + return MODE_VSYNC_NARROW; + + if (vsync > 0x3ff) + return MODE_VSYNC_WIDE; + + if ((mode->vdisplay < 1) || (mode->vtotal < 1)) + return MODE_V_ILLEGAL; + + if ((mode->vdisplay > 0x7ff) || (mode->vtotal > 0xfff)) + return MODE_BAD_VVALUE; + + DRM_DEBUG_DRIVER("Vertical parameters OK\n"); + + tcon->dclk_min_div = 7; + tcon->dclk_max_div = 7; + rounded_rate = clk_round_rate(tcon->dclk, rate); + if (rounded_rate < rate) + return MODE_CLOCK_LOW; + + if (rounded_rate > rate) + return MODE_CLOCK_HIGH; + + DRM_DEBUG_DRIVER("Clock rate OK\n"); + + return MODE_OK; +} + static const struct drm_encoder_helper_funcs sun4i_lvds_enc_helper_funcs = { .disable = sun4i_lvds_encoder_disable, .enable = sun4i_lvds_encoder_enable, + .mode_valid = sun4i_lvds_encoder_mode_valid, }; static const struct drm_encoder_funcs sun4i_lvds_enc_funcs = { diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index 832f8f9bc47f..a2a697a099e6 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c @@ -52,10 +52,10 @@ static int sun4i_rgb_get_modes(struct drm_connector *connector) return drm_panel_get_modes(tcon->panel); } -static int sun4i_rgb_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status sun4i_rgb_mode_valid(struct drm_encoder *crtc, + const struct drm_display_mode *mode) { - struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector); + struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(crtc); struct sun4i_tcon *tcon = rgb->tcon; u32 hsync = mode->hsync_end - mode->hsync_start; u32 vsync = mode->vsync_end - mode->vsync_start; @@ -106,7 +106,6 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector, static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = { .get_modes = sun4i_rgb_get_modes, - .mode_valid = sun4i_rgb_mode_valid, }; static void @@ -156,6 +155,7 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder) static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = { .disable = sun4i_rgb_encoder_disable, .enable = sun4i_rgb_encoder_enable, + .mode_valid = sun4i_rgb_mode_valid, }; static void sun4i_rgb_enc_destroy(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 0d6c5ed44795..1a114e380f13 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -17,6 +17,7 @@ #include <drm/drm_encoder.h> #include <drm/drm_modes.h> #include <drm/drm_of.h> +#include <drm/drm_panel.h> #include <uapi/drm/drm_mode.h> @@ -343,6 +344,9 @@ 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_display_mode *mode) { + struct drm_panel *panel = tcon->panel; + struct drm_connector *connector = panel->connector; + struct drm_display_info display_info = connector->display_info; unsigned int bp, hsync, vsync; u8 clk_delay; u32 val = 0; @@ -400,6 +404,27 @@ 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; + /* + * On A20 and similar SoCs, the only way to achieve Positive Edge + * (Rising Edge), is setting dclk clock phase to 2/3(240°). + * By default TCON works in Negative Edge(Falling Edge), + * this is why phase is set to 0 in that case. + * Unfortunately there's no way to logically invert dclk through + * IO_POL register. + * The only acceptable way to work, triple checked with scope, + * is using clock phase set to 0° for Negative Edge and set to 240° + * for Positive Edge. + * On A33 and similar SoCs there would be a 90° phase option, + * but it divides also dclk by 2. + * Following code is a way to avoid quirks all around TCON + * and DOTCLOCK drivers. + */ + 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); + regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE, val); @@ -850,6 +875,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, struct sunxi_engine *engine; struct device_node *remote; struct sun4i_tcon *tcon; + struct reset_control *edp_rstc; bool has_lvds_rst, has_lvds_alt, can_lvds; int ret; @@ -874,6 +900,20 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, return PTR_ERR(tcon->lcd_rst); } + if (tcon->quirks->needs_edp_reset) { + edp_rstc = devm_reset_control_get_shared(dev, "edp"); + if (IS_ERR(edp_rstc)) { + dev_err(dev, "Couldn't get edp reset line\n"); + return PTR_ERR(edp_rstc); + } + + ret = reset_control_deassert(edp_rstc); + if (ret) { + dev_err(dev, "Couldn't deassert edp reset line\n"); + return ret; + } + } + /* Make sure our TCON is reset */ ret = reset_control_reset(tcon->lcd_rst); if (ret) { @@ -1166,6 +1206,16 @@ static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { .has_channel_0 = true, }; +static const struct sun4i_tcon_quirks sun9i_a80_tcon_lcd_quirks = { + .has_channel_0 = true, + .needs_edp_reset = true, +}; + +static const struct sun4i_tcon_quirks sun9i_a80_tcon_tv_quirks = { + .has_channel_1 = true, + .needs_edp_reset = true, +}; + /* sun4i_drv uses this list to check if a device node is a TCON */ const struct of_device_id sun4i_tcon_of_table[] = { { .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks }, @@ -1177,6 +1227,8 @@ const struct of_device_id sun4i_tcon_of_table[] = { { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks }, { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks }, { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks }, + { .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks }, + { .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks }, { } }; MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table); diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index 78d55e7cd2b3..d3a945b7bb60 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -176,6 +176,7 @@ struct sun4i_tcon_quirks { bool has_channel_1; /* a33 does not have channel 1 */ bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */ bool needs_de_be_mux; /* sun6i needs mux to select backend */ + bool needs_edp_reset; /* a80 edp reset needed for tcon0 access */ /* callback to handle tcon muxing options */ int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *); diff --git a/drivers/gpu/drm/sun4i/sun6i_drc.c b/drivers/gpu/drm/sun4i/sun6i_drc.c index 09bba853e2a4..b5e071a49045 100644 --- a/drivers/gpu/drm/sun4i/sun6i_drc.c +++ b/drivers/gpu/drm/sun4i/sun6i_drc.c @@ -101,6 +101,7 @@ static const struct of_device_id sun6i_drc_of_table[] = { { .compatible = "allwinner,sun6i-a31-drc" }, { .compatible = "allwinner,sun6i-a31s-drc" }, { .compatible = "allwinner,sun8i-a33-drc" }, + { .compatible = "allwinner,sun9i-a80-drc" }, { } }; MODULE_DEVICE_TABLE(of, sun6i_drc_of_table); |