|
@@ -163,28 +163,89 @@ static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane)
|
|
BLEND_COLOR_KEY_NONE;
|
|
BLEND_COLOR_KEY_NONE;
|
|
u32 blendnokey = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255);
|
|
u32 blendnokey = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255);
|
|
struct tegra_plane_state *state;
|
|
struct tegra_plane_state *state;
|
|
|
|
+ u32 blending[2];
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
|
|
+ /* disable blending for non-overlapping case */
|
|
|
|
+ tegra_plane_writel(plane, blendnokey, DC_WIN_BLEND_NOKEY);
|
|
|
|
+ tegra_plane_writel(plane, foreground, DC_WIN_BLEND_1WIN);
|
|
|
|
+
|
|
state = to_tegra_plane_state(plane->base.state);
|
|
state = to_tegra_plane_state(plane->base.state);
|
|
|
|
|
|
- /* alpha contribution is 1 minus sum of overlapping windows */
|
|
|
|
- for (i = 0; i < 3; i++) {
|
|
|
|
- if (state->dependent[i])
|
|
|
|
- background[i] |= BLEND_CONTROL_DEPENDENT;
|
|
|
|
- }
|
|
|
|
|
|
+ if (state->opaque) {
|
|
|
|
+ /*
|
|
|
|
+ * Since custom fix-weight blending isn't utilized and weight
|
|
|
|
+ * of top window is set to max, we can enforce dependent
|
|
|
|
+ * blending which in this case results in transparent bottom
|
|
|
|
+ * window if top window is opaque and if top window enables
|
|
|
|
+ * alpha blending, then bottom window is getting alpha value
|
|
|
|
+ * of 1 minus the sum of alpha components of the overlapping
|
|
|
|
+ * plane.
|
|
|
|
+ */
|
|
|
|
+ background[0] |= BLEND_CONTROL_DEPENDENT;
|
|
|
|
+ background[1] |= BLEND_CONTROL_DEPENDENT;
|
|
|
|
|
|
- /* enable alpha blending if pixel format has an alpha component */
|
|
|
|
- if (!state->opaque)
|
|
|
|
|
|
+ /*
|
|
|
|
+ * The region where three windows overlap is the intersection
|
|
|
|
+ * of the two regions where two windows overlap. It contributes
|
|
|
|
+ * to the area if all of the windows on top of it have an alpha
|
|
|
|
+ * component.
|
|
|
|
+ */
|
|
|
|
+ switch (state->base.normalized_zpos) {
|
|
|
|
+ case 0:
|
|
|
|
+ if (state->blending[0].alpha &&
|
|
|
|
+ state->blending[1].alpha)
|
|
|
|
+ background[2] |= BLEND_CONTROL_DEPENDENT;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 1:
|
|
|
|
+ background[2] |= BLEND_CONTROL_DEPENDENT;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ /*
|
|
|
|
+ * Enable alpha blending if pixel format has an alpha
|
|
|
|
+ * component.
|
|
|
|
+ */
|
|
foreground |= BLEND_CONTROL_ALPHA;
|
|
foreground |= BLEND_CONTROL_ALPHA;
|
|
|
|
|
|
- /*
|
|
|
|
- * Disable blending and assume Window A is the bottom-most window,
|
|
|
|
- * Window C is the top-most window and Window B is in the middle.
|
|
|
|
- */
|
|
|
|
- tegra_plane_writel(plane, blendnokey, DC_WIN_BLEND_NOKEY);
|
|
|
|
- tegra_plane_writel(plane, foreground, DC_WIN_BLEND_1WIN);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If any of the windows on top of this window is opaque, it
|
|
|
|
+ * will completely conceal this window within that area. If
|
|
|
|
+ * top window has an alpha component, it is blended over the
|
|
|
|
+ * bottom window.
|
|
|
|
+ */
|
|
|
|
+ for (i = 0; i < 2; i++) {
|
|
|
|
+ if (state->blending[i].alpha &&
|
|
|
|
+ state->blending[i].top)
|
|
|
|
+ background[i] |= BLEND_CONTROL_DEPENDENT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ switch (state->base.normalized_zpos) {
|
|
|
|
+ case 0:
|
|
|
|
+ if (state->blending[0].alpha &&
|
|
|
|
+ state->blending[1].alpha)
|
|
|
|
+ background[2] |= BLEND_CONTROL_DEPENDENT;
|
|
|
|
+ break;
|
|
|
|
|
|
- switch (plane->index) {
|
|
|
|
|
|
+ case 1:
|
|
|
|
+ /*
|
|
|
|
+ * When both middle and topmost windows have an alpha,
|
|
|
|
+ * these windows a mixed together and then the result
|
|
|
|
+ * is blended over the bottom window.
|
|
|
|
+ */
|
|
|
|
+ if (state->blending[0].alpha &&
|
|
|
|
+ state->blending[0].top)
|
|
|
|
+ background[2] |= BLEND_CONTROL_ALPHA;
|
|
|
|
+
|
|
|
|
+ if (state->blending[1].alpha &&
|
|
|
|
+ state->blending[1].top)
|
|
|
|
+ background[2] |= BLEND_CONTROL_ALPHA;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ switch (state->base.normalized_zpos) {
|
|
case 0:
|
|
case 0:
|
|
tegra_plane_writel(plane, background[0], DC_WIN_BLEND_2WIN_X);
|
|
tegra_plane_writel(plane, background[0], DC_WIN_BLEND_2WIN_X);
|
|
tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y);
|
|
tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y);
|
|
@@ -192,8 +253,21 @@ static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane)
|
|
break;
|
|
break;
|
|
|
|
|
|
case 1:
|
|
case 1:
|
|
- tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_X);
|
|
|
|
- tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If window B / C is topmost, then X / Y registers are
|
|
|
|
+ * matching the order of blending[...] state indices,
|
|
|
|
+ * otherwise a swap is required.
|
|
|
|
+ */
|
|
|
|
+ if (!state->blending[0].top && state->blending[1].top) {
|
|
|
|
+ blending[0] = foreground;
|
|
|
|
+ blending[1] = background[1];
|
|
|
|
+ } else {
|
|
|
|
+ blending[0] = background[0];
|
|
|
|
+ blending[1] = foreground;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ tegra_plane_writel(plane, blending[0], DC_WIN_BLEND_2WIN_X);
|
|
|
|
+ tegra_plane_writel(plane, blending[1], DC_WIN_BLEND_2WIN_Y);
|
|
tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY);
|
|
tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY);
|
|
break;
|
|
break;
|
|
|
|
|
|
@@ -224,6 +298,39 @@ static void tegra_plane_setup_blending(struct tegra_plane *plane,
|
|
tegra_plane_writel(plane, value, DC_WIN_BLEND_LAYER_CONTROL);
|
|
tegra_plane_writel(plane, value, DC_WIN_BLEND_LAYER_CONTROL);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool
|
|
|
|
+tegra_plane_use_horizontal_filtering(struct tegra_plane *plane,
|
|
|
|
+ const struct tegra_dc_window *window)
|
|
|
|
+{
|
|
|
|
+ struct tegra_dc *dc = plane->dc;
|
|
|
|
+
|
|
|
|
+ if (window->src.w == window->dst.w)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if (plane->index == 0 && dc->soc->has_win_a_without_filters)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool
|
|
|
|
+tegra_plane_use_vertical_filtering(struct tegra_plane *plane,
|
|
|
|
+ const struct tegra_dc_window *window)
|
|
|
|
+{
|
|
|
|
+ struct tegra_dc *dc = plane->dc;
|
|
|
|
+
|
|
|
|
+ if (window->src.h == window->dst.h)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if (plane->index == 0 && dc->soc->has_win_a_without_filters)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if (plane->index == 2 && dc->soc->has_win_c_without_vert_filter)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
static void tegra_dc_setup_window(struct tegra_plane *plane,
|
|
static void tegra_dc_setup_window(struct tegra_plane *plane,
|
|
const struct tegra_dc_window *window)
|
|
const struct tegra_dc_window *window)
|
|
{
|
|
{
|
|
@@ -361,12 +468,50 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
|
|
if (window->bottom_up)
|
|
if (window->bottom_up)
|
|
value |= V_DIRECTION;
|
|
value |= V_DIRECTION;
|
|
|
|
|
|
|
|
+ if (tegra_plane_use_horizontal_filtering(plane, window)) {
|
|
|
|
+ /*
|
|
|
|
+ * Enable horizontal 6-tap filter and set filtering
|
|
|
|
+ * coefficients to the default values defined in TRM.
|
|
|
|
+ */
|
|
|
|
+ tegra_plane_writel(plane, 0x00008000, DC_WIN_H_FILTER_P(0));
|
|
|
|
+ tegra_plane_writel(plane, 0x3e087ce1, DC_WIN_H_FILTER_P(1));
|
|
|
|
+ tegra_plane_writel(plane, 0x3b117ac1, DC_WIN_H_FILTER_P(2));
|
|
|
|
+ tegra_plane_writel(plane, 0x591b73aa, DC_WIN_H_FILTER_P(3));
|
|
|
|
+ tegra_plane_writel(plane, 0x57256d9a, DC_WIN_H_FILTER_P(4));
|
|
|
|
+ tegra_plane_writel(plane, 0x552f668b, DC_WIN_H_FILTER_P(5));
|
|
|
|
+ tegra_plane_writel(plane, 0x73385e8b, DC_WIN_H_FILTER_P(6));
|
|
|
|
+ tegra_plane_writel(plane, 0x72435583, DC_WIN_H_FILTER_P(7));
|
|
|
|
+ tegra_plane_writel(plane, 0x714c4c8b, DC_WIN_H_FILTER_P(8));
|
|
|
|
+ tegra_plane_writel(plane, 0x70554393, DC_WIN_H_FILTER_P(9));
|
|
|
|
+ tegra_plane_writel(plane, 0x715e389b, DC_WIN_H_FILTER_P(10));
|
|
|
|
+ tegra_plane_writel(plane, 0x71662faa, DC_WIN_H_FILTER_P(11));
|
|
|
|
+ tegra_plane_writel(plane, 0x536d25ba, DC_WIN_H_FILTER_P(12));
|
|
|
|
+ tegra_plane_writel(plane, 0x55731bca, DC_WIN_H_FILTER_P(13));
|
|
|
|
+ tegra_plane_writel(plane, 0x387a11d9, DC_WIN_H_FILTER_P(14));
|
|
|
|
+ tegra_plane_writel(plane, 0x3c7c08f1, DC_WIN_H_FILTER_P(15));
|
|
|
|
+
|
|
|
|
+ value |= H_FILTER;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (tegra_plane_use_vertical_filtering(plane, window)) {
|
|
|
|
+ unsigned int i, k;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Enable vertical 2-tap filter and set filtering
|
|
|
|
+ * coefficients to the default values defined in TRM.
|
|
|
|
+ */
|
|
|
|
+ for (i = 0, k = 128; i < 16; i++, k -= 8)
|
|
|
|
+ tegra_plane_writel(plane, k, DC_WIN_V_FILTER_P(i));
|
|
|
|
+
|
|
|
|
+ value |= V_FILTER;
|
|
|
|
+ }
|
|
|
|
+
|
|
tegra_plane_writel(plane, value, DC_WIN_WIN_OPTIONS);
|
|
tegra_plane_writel(plane, value, DC_WIN_WIN_OPTIONS);
|
|
|
|
|
|
- if (dc->soc->supports_blending)
|
|
|
|
- tegra_plane_setup_blending(plane, window);
|
|
|
|
- else
|
|
|
|
|
|
+ if (dc->soc->has_legacy_blending)
|
|
tegra_plane_setup_blending_legacy(plane);
|
|
tegra_plane_setup_blending_legacy(plane);
|
|
|
|
+ else
|
|
|
|
+ tegra_plane_setup_blending(plane, window);
|
|
}
|
|
}
|
|
|
|
|
|
static const u32 tegra20_primary_formats[] = {
|
|
static const u32 tegra20_primary_formats[] = {
|
|
@@ -451,17 +596,18 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
|
|
struct drm_plane_state *state)
|
|
struct drm_plane_state *state)
|
|
{
|
|
{
|
|
struct tegra_plane_state *plane_state = to_tegra_plane_state(state);
|
|
struct tegra_plane_state *plane_state = to_tegra_plane_state(state);
|
|
|
|
+ unsigned int rotation = DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y;
|
|
struct tegra_bo_tiling *tiling = &plane_state->tiling;
|
|
struct tegra_bo_tiling *tiling = &plane_state->tiling;
|
|
struct tegra_plane *tegra = to_tegra_plane(plane);
|
|
struct tegra_plane *tegra = to_tegra_plane(plane);
|
|
struct tegra_dc *dc = to_tegra_dc(state->crtc);
|
|
struct tegra_dc *dc = to_tegra_dc(state->crtc);
|
|
- unsigned int format;
|
|
|
|
int err;
|
|
int err;
|
|
|
|
|
|
/* no need for further checks if the plane is being disabled */
|
|
/* no need for further checks if the plane is being disabled */
|
|
if (!state->crtc)
|
|
if (!state->crtc)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- err = tegra_plane_format(state->fb->format->format, &format,
|
|
|
|
|
|
+ err = tegra_plane_format(state->fb->format->format,
|
|
|
|
+ &plane_state->format,
|
|
&plane_state->swap);
|
|
&plane_state->swap);
|
|
if (err < 0)
|
|
if (err < 0)
|
|
return err;
|
|
return err;
|
|
@@ -472,22 +618,12 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
|
|
* the corresponding opaque formats. However, the opaque formats can
|
|
* the corresponding opaque formats. However, the opaque formats can
|
|
* be emulated by disabling alpha blending for the plane.
|
|
* be emulated by disabling alpha blending for the plane.
|
|
*/
|
|
*/
|
|
- if (!dc->soc->supports_blending) {
|
|
|
|
- if (!tegra_plane_format_has_alpha(format)) {
|
|
|
|
- err = tegra_plane_format_get_alpha(format, &format);
|
|
|
|
- if (err < 0)
|
|
|
|
- return err;
|
|
|
|
-
|
|
|
|
- plane_state->opaque = true;
|
|
|
|
- } else {
|
|
|
|
- plane_state->opaque = false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- tegra_plane_check_dependent(tegra, plane_state);
|
|
|
|
|
|
+ if (dc->soc->has_legacy_blending) {
|
|
|
|
+ err = tegra_plane_setup_legacy_state(tegra, plane_state);
|
|
|
|
+ if (err < 0)
|
|
|
|
+ return err;
|
|
}
|
|
}
|
|
|
|
|
|
- plane_state->format = format;
|
|
|
|
-
|
|
|
|
err = tegra_fb_get_tiling(state->fb, tiling);
|
|
err = tegra_fb_get_tiling(state->fb, tiling);
|
|
if (err < 0)
|
|
if (err < 0)
|
|
return err;
|
|
return err;
|
|
@@ -498,6 +634,13 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ rotation = drm_rotation_simplify(state->rotation, rotation);
|
|
|
|
+
|
|
|
|
+ if (rotation & DRM_MODE_REFLECT_Y)
|
|
|
|
+ plane_state->bottom_up = true;
|
|
|
|
+ else
|
|
|
|
+ plane_state->bottom_up = false;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Tegra doesn't support different strides for U and V planes so we
|
|
* Tegra doesn't support different strides for U and V planes so we
|
|
* error out if the user tries to display a framebuffer with such a
|
|
* error out if the user tries to display a framebuffer with such a
|
|
@@ -558,7 +701,7 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
|
|
window.dst.w = drm_rect_width(&plane->state->dst);
|
|
window.dst.w = drm_rect_width(&plane->state->dst);
|
|
window.dst.h = drm_rect_height(&plane->state->dst);
|
|
window.dst.h = drm_rect_height(&plane->state->dst);
|
|
window.bits_per_pixel = fb->format->cpp[0] * 8;
|
|
window.bits_per_pixel = fb->format->cpp[0] * 8;
|
|
- window.bottom_up = tegra_fb_is_bottom_up(fb);
|
|
|
|
|
|
+ window.bottom_up = tegra_fb_is_bottom_up(fb) || state->bottom_up;
|
|
|
|
|
|
/* copy from state */
|
|
/* copy from state */
|
|
window.zpos = plane->state->normalized_zpos;
|
|
window.zpos = plane->state->normalized_zpos;
|
|
@@ -639,9 +782,15 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm,
|
|
}
|
|
}
|
|
|
|
|
|
drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs);
|
|
drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs);
|
|
|
|
+ drm_plane_create_zpos_property(&plane->base, plane->index, 0, 255);
|
|
|
|
|
|
- if (dc->soc->supports_blending)
|
|
|
|
- drm_plane_create_zpos_property(&plane->base, 0, 0, 255);
|
|
|
|
|
|
+ err = drm_plane_create_rotation_property(&plane->base,
|
|
|
|
+ DRM_MODE_ROTATE_0,
|
|
|
|
+ DRM_MODE_ROTATE_0 |
|
|
|
|
+ DRM_MODE_REFLECT_Y);
|
|
|
|
+ if (err < 0)
|
|
|
|
+ dev_err(dc->dev, "failed to create rotation property: %d\n",
|
|
|
|
+ err);
|
|
|
|
|
|
return &plane->base;
|
|
return &plane->base;
|
|
}
|
|
}
|
|
@@ -918,9 +1067,15 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
|
|
}
|
|
}
|
|
|
|
|
|
drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs);
|
|
drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs);
|
|
|
|
+ drm_plane_create_zpos_property(&plane->base, plane->index, 0, 255);
|
|
|
|
|
|
- if (dc->soc->supports_blending)
|
|
|
|
- drm_plane_create_zpos_property(&plane->base, 0, 0, 255);
|
|
|
|
|
|
+ err = drm_plane_create_rotation_property(&plane->base,
|
|
|
|
+ DRM_MODE_ROTATE_0,
|
|
|
|
+ DRM_MODE_ROTATE_0 |
|
|
|
|
+ DRM_MODE_REFLECT_Y);
|
|
|
|
+ if (err < 0)
|
|
|
|
+ dev_err(dc->dev, "failed to create rotation property: %d\n",
|
|
|
|
+ err);
|
|
|
|
|
|
return &plane->base;
|
|
return &plane->base;
|
|
}
|
|
}
|
|
@@ -1826,7 +1981,6 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
|
|
static int tegra_dc_init(struct host1x_client *client)
|
|
static int tegra_dc_init(struct host1x_client *client)
|
|
{
|
|
{
|
|
struct drm_device *drm = dev_get_drvdata(client->parent);
|
|
struct drm_device *drm = dev_get_drvdata(client->parent);
|
|
- struct iommu_group *group = iommu_group_get(client->dev);
|
|
|
|
unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
|
|
unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
|
|
struct tegra_dc *dc = host1x_client_to_dc(client);
|
|
struct tegra_dc *dc = host1x_client_to_dc(client);
|
|
struct tegra_drm *tegra = drm->dev_private;
|
|
struct tegra_drm *tegra = drm->dev_private;
|
|
@@ -1838,20 +1992,11 @@ static int tegra_dc_init(struct host1x_client *client)
|
|
if (!dc->syncpt)
|
|
if (!dc->syncpt)
|
|
dev_warn(dc->dev, "failed to allocate syncpoint\n");
|
|
dev_warn(dc->dev, "failed to allocate syncpoint\n");
|
|
|
|
|
|
- if (group && tegra->domain) {
|
|
|
|
- if (group != tegra->group) {
|
|
|
|
- err = iommu_attach_group(tegra->domain, group);
|
|
|
|
- if (err < 0) {
|
|
|
|
- dev_err(dc->dev,
|
|
|
|
- "failed to attach to domain: %d\n",
|
|
|
|
- err);
|
|
|
|
- return err;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- tegra->group = group;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- dc->domain = tegra->domain;
|
|
|
|
|
|
+ dc->group = host1x_client_iommu_attach(client, true);
|
|
|
|
+ if (IS_ERR(dc->group)) {
|
|
|
|
+ err = PTR_ERR(dc->group);
|
|
|
|
+ dev_err(client->dev, "failed to attach to domain: %d\n", err);
|
|
|
|
+ return err;
|
|
}
|
|
}
|
|
|
|
|
|
if (dc->soc->wgrps)
|
|
if (dc->soc->wgrps)
|
|
@@ -1916,24 +2061,15 @@ cleanup:
|
|
if (!IS_ERR(primary))
|
|
if (!IS_ERR(primary))
|
|
drm_plane_cleanup(primary);
|
|
drm_plane_cleanup(primary);
|
|
|
|
|
|
- if (group && dc->domain) {
|
|
|
|
- if (group == tegra->group) {
|
|
|
|
- iommu_detach_group(dc->domain, group);
|
|
|
|
- tegra->group = NULL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- dc->domain = NULL;
|
|
|
|
- }
|
|
|
|
|
|
+ host1x_client_iommu_detach(client, dc->group);
|
|
|
|
+ host1x_syncpt_free(dc->syncpt);
|
|
|
|
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
static int tegra_dc_exit(struct host1x_client *client)
|
|
static int tegra_dc_exit(struct host1x_client *client)
|
|
{
|
|
{
|
|
- struct drm_device *drm = dev_get_drvdata(client->parent);
|
|
|
|
- struct iommu_group *group = iommu_group_get(client->dev);
|
|
|
|
struct tegra_dc *dc = host1x_client_to_dc(client);
|
|
struct tegra_dc *dc = host1x_client_to_dc(client);
|
|
- struct tegra_drm *tegra = drm->dev_private;
|
|
|
|
int err;
|
|
int err;
|
|
|
|
|
|
devm_free_irq(dc->dev, dc->irq, dc);
|
|
devm_free_irq(dc->dev, dc->irq, dc);
|
|
@@ -1944,15 +2080,7 @@ static int tegra_dc_exit(struct host1x_client *client)
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
- if (group && dc->domain) {
|
|
|
|
- if (group == tegra->group) {
|
|
|
|
- iommu_detach_group(dc->domain, group);
|
|
|
|
- tegra->group = NULL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- dc->domain = NULL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ host1x_client_iommu_detach(client, dc->group);
|
|
host1x_syncpt_free(dc->syncpt);
|
|
host1x_syncpt_free(dc->syncpt);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -1968,7 +2096,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
|
|
.supports_interlacing = false,
|
|
.supports_interlacing = false,
|
|
.supports_cursor = false,
|
|
.supports_cursor = false,
|
|
.supports_block_linear = false,
|
|
.supports_block_linear = false,
|
|
- .supports_blending = false,
|
|
|
|
|
|
+ .has_legacy_blending = true,
|
|
.pitch_align = 8,
|
|
.pitch_align = 8,
|
|
.has_powergate = false,
|
|
.has_powergate = false,
|
|
.coupled_pm = true,
|
|
.coupled_pm = true,
|
|
@@ -1978,6 +2106,8 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
|
|
.num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats),
|
|
.num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats),
|
|
.overlay_formats = tegra20_overlay_formats,
|
|
.overlay_formats = tegra20_overlay_formats,
|
|
.modifiers = tegra20_modifiers,
|
|
.modifiers = tegra20_modifiers,
|
|
|
|
+ .has_win_a_without_filters = true,
|
|
|
|
+ .has_win_c_without_vert_filter = true,
|
|
};
|
|
};
|
|
|
|
|
|
static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
|
|
static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
|
|
@@ -1985,7 +2115,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
|
|
.supports_interlacing = false,
|
|
.supports_interlacing = false,
|
|
.supports_cursor = false,
|
|
.supports_cursor = false,
|
|
.supports_block_linear = false,
|
|
.supports_block_linear = false,
|
|
- .supports_blending = false,
|
|
|
|
|
|
+ .has_legacy_blending = true,
|
|
.pitch_align = 8,
|
|
.pitch_align = 8,
|
|
.has_powergate = false,
|
|
.has_powergate = false,
|
|
.coupled_pm = false,
|
|
.coupled_pm = false,
|
|
@@ -1995,6 +2125,8 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
|
|
.num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats),
|
|
.num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats),
|
|
.overlay_formats = tegra20_overlay_formats,
|
|
.overlay_formats = tegra20_overlay_formats,
|
|
.modifiers = tegra20_modifiers,
|
|
.modifiers = tegra20_modifiers,
|
|
|
|
+ .has_win_a_without_filters = false,
|
|
|
|
+ .has_win_c_without_vert_filter = false,
|
|
};
|
|
};
|
|
|
|
|
|
static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
|
|
static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
|
|
@@ -2002,7 +2134,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
|
|
.supports_interlacing = false,
|
|
.supports_interlacing = false,
|
|
.supports_cursor = false,
|
|
.supports_cursor = false,
|
|
.supports_block_linear = false,
|
|
.supports_block_linear = false,
|
|
- .supports_blending = false,
|
|
|
|
|
|
+ .has_legacy_blending = true,
|
|
.pitch_align = 64,
|
|
.pitch_align = 64,
|
|
.has_powergate = true,
|
|
.has_powergate = true,
|
|
.coupled_pm = false,
|
|
.coupled_pm = false,
|
|
@@ -2012,6 +2144,8 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
|
|
.num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats),
|
|
.num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats),
|
|
.overlay_formats = tegra114_overlay_formats,
|
|
.overlay_formats = tegra114_overlay_formats,
|
|
.modifiers = tegra20_modifiers,
|
|
.modifiers = tegra20_modifiers,
|
|
|
|
+ .has_win_a_without_filters = false,
|
|
|
|
+ .has_win_c_without_vert_filter = false,
|
|
};
|
|
};
|
|
|
|
|
|
static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
|
|
static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
|
|
@@ -2019,7 +2153,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
|
|
.supports_interlacing = true,
|
|
.supports_interlacing = true,
|
|
.supports_cursor = true,
|
|
.supports_cursor = true,
|
|
.supports_block_linear = true,
|
|
.supports_block_linear = true,
|
|
- .supports_blending = true,
|
|
|
|
|
|
+ .has_legacy_blending = false,
|
|
.pitch_align = 64,
|
|
.pitch_align = 64,
|
|
.has_powergate = true,
|
|
.has_powergate = true,
|
|
.coupled_pm = false,
|
|
.coupled_pm = false,
|
|
@@ -2029,6 +2163,8 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
|
|
.num_overlay_formats = ARRAY_SIZE(tegra124_overlay_formats),
|
|
.num_overlay_formats = ARRAY_SIZE(tegra124_overlay_formats),
|
|
.overlay_formats = tegra124_overlay_formats,
|
|
.overlay_formats = tegra124_overlay_formats,
|
|
.modifiers = tegra124_modifiers,
|
|
.modifiers = tegra124_modifiers,
|
|
|
|
+ .has_win_a_without_filters = false,
|
|
|
|
+ .has_win_c_without_vert_filter = false,
|
|
};
|
|
};
|
|
|
|
|
|
static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
|
|
static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
|
|
@@ -2036,7 +2172,7 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
|
|
.supports_interlacing = true,
|
|
.supports_interlacing = true,
|
|
.supports_cursor = true,
|
|
.supports_cursor = true,
|
|
.supports_block_linear = true,
|
|
.supports_block_linear = true,
|
|
- .supports_blending = true,
|
|
|
|
|
|
+ .has_legacy_blending = false,
|
|
.pitch_align = 64,
|
|
.pitch_align = 64,
|
|
.has_powergate = true,
|
|
.has_powergate = true,
|
|
.coupled_pm = false,
|
|
.coupled_pm = false,
|
|
@@ -2046,6 +2182,8 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
|
|
.num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats),
|
|
.num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats),
|
|
.overlay_formats = tegra114_overlay_formats,
|
|
.overlay_formats = tegra114_overlay_formats,
|
|
.modifiers = tegra124_modifiers,
|
|
.modifiers = tegra124_modifiers,
|
|
|
|
+ .has_win_a_without_filters = false,
|
|
|
|
+ .has_win_c_without_vert_filter = false,
|
|
};
|
|
};
|
|
|
|
|
|
static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = {
|
|
static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = {
|
|
@@ -2087,7 +2225,7 @@ static const struct tegra_dc_soc_info tegra186_dc_soc_info = {
|
|
.supports_interlacing = true,
|
|
.supports_interlacing = true,
|
|
.supports_cursor = true,
|
|
.supports_cursor = true,
|
|
.supports_block_linear = true,
|
|
.supports_block_linear = true,
|
|
- .supports_blending = true,
|
|
|
|
|
|
+ .has_legacy_blending = false,
|
|
.pitch_align = 64,
|
|
.pitch_align = 64,
|
|
.has_powergate = false,
|
|
.has_powergate = false,
|
|
.coupled_pm = false,
|
|
.coupled_pm = false,
|