diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c277b198fa3fa2..c472c663bc139f 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -451,7 +451,7 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p, drm_printf(p, "\tactive_changed=%d\n", state->active_changed); drm_printf(p, "\tconnectors_changed=%d\n", state->connectors_changed); drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed); - drm_printf(p, "\tplane_mask=%x\n", state->plane_mask); + drm_printf(p, "\tplane_mask=%llx\n", state->plane_mask); drm_printf(p, "\tconnector_mask=%x\n", state->connector_mask); drm_printf(p, "\tencoder_mask=%x\n", state->encoder_mask); drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode)); diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 3c5375016d7374..ad7774c94be497 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -811,6 +811,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, state->max_requested_bpc = val; } else if (property == connector->privacy_screen_sw_state_property) { state->privacy_screen_sw_state = val; + } else if (property == connector->rotation_property) { + state->rotation = val; } else if (connector->funcs->atomic_set_property) { return connector->funcs->atomic_set_property(connector, state, property, val); @@ -900,6 +902,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector, *val = state->max_requested_bpc; } else if (property == connector->privacy_screen_sw_state_property) { *val = state->privacy_screen_sw_state; + } else if (property == connector->rotation_property) { + *val = state->rotation; } else if (connector->funcs->atomic_get_property) { return connector->funcs->atomic_get_property(connector, state, property, val); diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 6e74de8334663c..4e63000713dbfd 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -235,6 +235,16 @@ int drm_plane_create_alpha_property(struct drm_plane *plane) } EXPORT_SYMBOL(drm_plane_create_alpha_property); +static const struct drm_prop_enum_list drm_rotate_props[] = { + { __builtin_ffs(DRM_MODE_ROTATE_0) - 1, "rotate-0" }, + { __builtin_ffs(DRM_MODE_ROTATE_90) - 1, "rotate-90" }, + { __builtin_ffs(DRM_MODE_ROTATE_180) - 1, "rotate-180" }, + { __builtin_ffs(DRM_MODE_ROTATE_270) - 1, "rotate-270" }, + { __builtin_ffs(DRM_MODE_REFLECT_X) - 1, "reflect-x" }, + { __builtin_ffs(DRM_MODE_REFLECT_Y) - 1, "reflect-y" }, + { __builtin_ffs(DRM_MODE_TRANSPOSE) - 1, "transpose" }, +}; + /** * drm_plane_create_rotation_property - create a new rotation property * @plane: drm plane @@ -263,6 +273,8 @@ EXPORT_SYMBOL(drm_plane_create_alpha_property); * "reflect-x" * DRM_MODE_REFLECT_Y: * "reflect-y" + * DRM_MODE_TRANSPOSE: + * "transpose" * * Rotation is the specified amount in degrees in counter clockwise direction, * the X and Y axis are within the source rectangle, i.e. the X/Y axis before @@ -273,14 +285,6 @@ int drm_plane_create_rotation_property(struct drm_plane *plane, unsigned int rotation, unsigned int supported_rotations) { - static const struct drm_prop_enum_list props[] = { - { __builtin_ffs(DRM_MODE_ROTATE_0) - 1, "rotate-0" }, - { __builtin_ffs(DRM_MODE_ROTATE_90) - 1, "rotate-90" }, - { __builtin_ffs(DRM_MODE_ROTATE_180) - 1, "rotate-180" }, - { __builtin_ffs(DRM_MODE_ROTATE_270) - 1, "rotate-270" }, - { __builtin_ffs(DRM_MODE_REFLECT_X) - 1, "reflect-x" }, - { __builtin_ffs(DRM_MODE_REFLECT_Y) - 1, "reflect-y" }, - }; struct drm_property *prop; WARN_ON((supported_rotations & DRM_MODE_ROTATE_MASK) == 0); @@ -288,7 +292,8 @@ int drm_plane_create_rotation_property(struct drm_plane *plane, WARN_ON(rotation & ~supported_rotations); prop = drm_property_create_bitmask(plane->dev, 0, "rotation", - props, ARRAY_SIZE(props), + drm_rotate_props, + ARRAY_SIZE(drm_rotate_props), supported_rotations); if (!prop) return -ENOMEM; @@ -304,6 +309,34 @@ int drm_plane_create_rotation_property(struct drm_plane *plane, } EXPORT_SYMBOL(drm_plane_create_rotation_property); +int drm_connector_create_rotation_property(struct drm_connector *conn, + unsigned int rotation, + unsigned int supported_rotations) +{ + struct drm_property *prop; + + WARN_ON((supported_rotations & DRM_MODE_ROTATE_MASK) == 0); + WARN_ON(!is_power_of_2(rotation & DRM_MODE_ROTATE_MASK)); + WARN_ON(rotation & ~supported_rotations); + + prop = drm_property_create_bitmask(conn->dev, 0, "rotation", + drm_rotate_props, + ARRAY_SIZE(drm_rotate_props), + supported_rotations); + if (!prop) + return -ENOMEM; + + drm_object_attach_property(&conn->base, prop, rotation); + + if (conn->state) + conn->state->rotation = rotation; + + conn->rotation_property = prop; + + return 0; +} +EXPORT_SYMBOL(drm_connector_create_rotation_property); + /** * drm_rotation_simplify() - Try to simplify the rotation * @rotation: Rotation to be simplified diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 476ea750acf4a1..09cd1df2d6c4a4 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -361,7 +361,8 @@ static int __drm_connector_init(struct drm_device *dev, drm_object_attach_property(&connector->base, config->non_desktop_property, - 0); + (connector_type != DRM_MODE_CONNECTOR_VIRTUAL && + connector_type != DRM_MODE_CONNECTOR_WRITEBACK) ? 0 : 1); drm_object_attach_property(&connector->base, config->tile_property, 0); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 1955eaeba0ab7c..8e53a46b570874 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -959,7 +959,7 @@ static int atomic_remove_fb(struct drm_framebuffer *fb) struct drm_connector *conn __maybe_unused; struct drm_connector_state *conn_state; int i, ret; - unsigned plane_mask; + u64 plane_mask; bool disable_crtcs = false; retry_disable: diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 87eb591fe9b5b8..02d1f7afbbe2e3 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -636,7 +636,7 @@ void drm_mode_config_validate(struct drm_device *dev) struct drm_encoder *encoder; struct drm_crtc *crtc; struct drm_plane *plane; - u32 primary_with_crtc = 0, cursor_with_crtc = 0; + u64 primary_with_crtc = 0, cursor_with_crtc = 0; unsigned int num_primary = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 311e179904a2ab..38901eb3a5ad2a 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -249,7 +249,7 @@ static int __drm_universal_plane_init(struct drm_device *dev, int ret; /* plane index is used with 32bit bitmasks */ - if (WARN_ON(config->num_total_plane >= 32)) + if (WARN_ON(config->num_total_plane >= 64)) return -EINVAL; /* diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c index 89585b31b985e1..45213c228d3323 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c @@ -230,7 +230,7 @@ static int ipu_crtc_atomic_check(struct drm_crtc *crtc, { struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - u32 primary_plane_mask = drm_plane_mask(crtc->primary); + u64 primary_plane_mask = drm_plane_mask(crtc->primary); if (crtc_state->active && (primary_plane_mask & crtc_state->plane_mask) == 0) return -EINVAL; diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index acedc1b89f2e08..fdd6ba310324e2 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -265,7 +265,11 @@ static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst) { if (dst == src >> 16) return VC4_SCALING_NONE; - if (3 * dst >= 2 * (src >> 16)) + + if (src <= (1 << 16)) + /* Source rectangle <= 1 pixel can use TPZ for resize/upscale */ + return VC4_SCALING_TPZ; + else if (3 * dst >= 2 * (src >> 16)) return VC4_SCALING_PPF; else return VC4_SCALING_TPZ; @@ -592,12 +596,17 @@ static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst) WARN_ON_ONCE(vc4->gen > VC4_GEN_6); - scale = src / dst; + if ((dst << 16) < src) { + scale = src / dst; - /* The specs note that while the reciprocal would be defined - * as (1<<32)/scale, ~0 is close enough. - */ - recip = ~0 / scale; + /* The specs note that while the reciprocal would be defined + * as (1<<32)/scale, ~0 is close enough. + */ + recip = ~0 / scale; + } else { + scale = (1 << 16) + 1; + recip = (1 << 16) - 1; + } vc4_dlist_write(vc4_state, /* @@ -1291,7 +1300,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, width = vc4_state->src_w[0] >> 16; height = vc4_state->src_h[0] >> 16; - if (!width || !height || !vc4_state->crtc_w || !vc4_state->crtc_h) { + if (!vc4_state->src_w[0] || !vc4_state->src_h[0] || + !vc4_state->crtc_w || !vc4_state->crtc_h) { /* 0 source size probably means the plane is offscreen */ vc4_state->dlist_initialized = 1; return 0; @@ -1829,7 +1839,8 @@ static int vc6_plane_mode_set(struct drm_plane *plane, width = vc4_state->src_w[0] >> 16; height = vc4_state->src_h[0] >> 16; - if (!width || !height || !vc4_state->crtc_w || !vc4_state->crtc_h) { + if (!vc4_state->src_w[0] || !vc4_state->src_h[0] || + !vc4_state->crtc_w || !vc4_state->crtc_h) { /* 0 source size probably means the plane is offscreen. * 0 destination size is a redundant plane. */ @@ -2647,12 +2658,27 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, } #define VC4_NUM_OVERLAY_PLANES 16 +#define VC4_NUM_TXP_OVERLAY_PLANES 32 int vc4_plane_create_additional_planes(struct drm_device *drm) { struct drm_plane *cursor_plane; struct drm_crtc *crtc; unsigned int i; + struct drm_crtc *txp_crtc; + uint32_t non_txp_crtc_mask; + + drm_for_each_crtc(crtc, drm) { + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + + if (vc4_crtc->feeds_txp) { + txp_crtc = crtc; + break; + } + } + + non_txp_crtc_mask = GENMASK(drm->mode_config.num_crtc - 1, 0) - + drm_crtc_mask(txp_crtc); /* Set up some arbitrary number of planes. We're not limited * by a set number of physical registers, just the space in @@ -2666,7 +2692,22 @@ int vc4_plane_create_additional_planes(struct drm_device *drm) for (i = 0; i < VC4_NUM_OVERLAY_PLANES; i++) { struct drm_plane *plane = vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, - GENMASK(drm->mode_config.num_crtc - 1, 0)); + non_txp_crtc_mask); + + if (IS_ERR(plane)) + continue; + + /* Create zpos property. Max of all the overlays + 1 primary + + * 1 cursor plane on a crtc. + */ + drm_plane_create_zpos_property(plane, i + 1, 1, + VC4_NUM_OVERLAY_PLANES + 1); + } + + for (i = 0; i < VC4_NUM_TXP_OVERLAY_PLANES; i++) { + struct drm_plane *plane = + vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, + drm_crtc_mask(txp_crtc)); if (IS_ERR(plane)) continue; diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c index b87d5f8ad4b8f0..d46f205d15a309 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -259,10 +260,15 @@ static int vc4_txp_connector_atomic_check(struct drm_connector *conn, crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); fb = conn_state->writeback_job->fb; - if (fb->width != crtc_state->mode.hdisplay || - fb->height != crtc_state->mode.vdisplay) { - DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n", - fb->width, fb->height); + if ((conn_state->rotation == DRM_MODE_ROTATE_0 && + fb->width != crtc_state->mode.hdisplay && + fb->height != crtc_state->mode.vdisplay) || + (conn_state->rotation == (DRM_MODE_ROTATE_0 | DRM_MODE_TRANSPOSE) && + fb->width != crtc_state->mode.vdisplay && + fb->height != crtc_state->mode.hdisplay)) { + DRM_DEBUG_KMS("Invalid framebuffer size %ux%u vs mode %ux%u\n", + fb->width, fb->height, + crtc_state->mode.hdisplay, crtc_state->mode.vdisplay); return -EINVAL; } @@ -330,6 +336,9 @@ static void vc4_txp_connector_atomic_commit(struct drm_connector *conn, */ ctrl |= TXP_ALPHA_INVERT; + if (conn_state->rotation & DRM_MODE_TRANSPOSE) + ctrl |= TXP_TRANSPOSE; + if (!drm_dev_enter(drm, &idx)) return; @@ -608,6 +617,10 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; + drm_connector_create_rotation_property(&txp->connector.base, DRM_MODE_ROTATE_0, + DRM_MODE_ROTATE_0 | + DRM_MODE_TRANSPOSE); + ret = devm_request_irq(dev, irq, vc4_txp_interrupt, 0, dev_name(dev), txp); if (ret) diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h index 88bdfec3bd8848..a84c58f3f13cdc 100644 --- a/include/drm/drm_blend.h +++ b/include/drm/drm_blend.h @@ -34,6 +34,7 @@ struct drm_device; struct drm_atomic_state; struct drm_plane; +struct drm_connector; static inline bool drm_rotation_90_or_270(unsigned int rotation) { @@ -58,4 +59,8 @@ int drm_atomic_normalize_zpos(struct drm_device *dev, struct drm_atomic_state *state); int drm_plane_create_blend_mode_property(struct drm_plane *plane, unsigned int supported_modes); + +int drm_connector_create_rotation_property(struct drm_connector *conn, + unsigned int rotation, + unsigned int supported_rotations); #endif diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 67d47a3b3d095e..4e405c9880a6e4 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1029,6 +1029,11 @@ struct drm_connector_state { * DRM blob property for HDR output metadata */ struct drm_property_blob *hdr_output_metadata; + + /** + * @rotation: Connector property to rotate the maximum output image. + */ + u32 rotation; }; /** @@ -1696,6 +1701,12 @@ struct drm_connector { */ struct drm_property *privacy_screen_hw_state_property; + /** + * @rotation_property: Optional DRM property controlling rotation of the + * output. + */ + struct drm_property *rotation_property; + #define DRM_CONNECTOR_POLL_HPD (1 << 0) #define DRM_CONNECTOR_POLL_CONNECT (1 << 1) #define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 8b48a1974da314..dd7ad1a44717e8 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -192,7 +192,7 @@ struct drm_crtc_state { * @plane_mask: Bitmask of drm_plane_mask(plane) of planes attached to * this CRTC. */ - u32 plane_mask; + u64 plane_mask; /** * @connector_mask: Bitmask of drm_connector_mask(connector) of diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index e4000d2f148d43..5cf70d548e29b8 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -915,9 +915,9 @@ static inline unsigned int drm_plane_index(const struct drm_plane *plane) * drm_plane_mask - find the mask of a registered plane * @plane: plane to find mask for */ -static inline u32 drm_plane_mask(const struct drm_plane *plane) +static inline u64 drm_plane_mask(const struct drm_plane *plane) { - return 1 << drm_plane_index(plane); + return 1ULL << drm_plane_index(plane); } struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx); diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index ea1b639bcb2883..25f563cb853dc8 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -203,6 +203,7 @@ extern "C" { */ #define DRM_MODE_REFLECT_X (1<<4) #define DRM_MODE_REFLECT_Y (1<<5) +#define DRM_MODE_TRANSPOSE (1<<6) /* * DRM_MODE_REFLECT_MASK