Update Linux to v5.10.109
Sourced from [1]
[1] https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.109.tar.xz
Change-Id: I19bca9fc6762d4e63bcf3e4cba88bbe560d9c76c
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index c410221..ceb8633 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -135,7 +135,7 @@
default:
WARN_ON_ONCE(1);
- /* fallthrough */
+ fallthrough;
case 4:
max = 4;
break;
@@ -368,6 +368,12 @@
h_size = window->src.w * bpp;
v_size = window->src.h;
+ if (window->reflect_x)
+ h_offset += (window->src.w - 1) * bpp;
+
+ if (window->reflect_y)
+ v_offset += window->src.h - 1;
+
value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size);
tegra_plane_writel(plane, value, DC_WIN_PRESCALED_SIZE);
@@ -404,9 +410,6 @@
tegra_plane_writel(plane, window->stride[0], DC_WIN_LINE_STRIDE);
}
- if (window->bottom_up)
- v_offset += window->src.h - 1;
-
tegra_plane_writel(plane, h_offset, DC_WINBUF_ADDR_H_OFFSET);
tegra_plane_writel(plane, v_offset, DC_WINBUF_ADDR_V_OFFSET);
@@ -470,7 +473,10 @@
value |= COLOR_EXPAND;
}
- if (window->bottom_up)
+ if (window->reflect_x)
+ value |= H_DIRECTION;
+
+ if (window->reflect_y)
value |= V_DIRECTION;
if (tegra_plane_use_horizontal_filtering(plane, window)) {
@@ -601,7 +607,10 @@
struct drm_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;
+ unsigned int supported_rotation = DRM_MODE_ROTATE_0 |
+ DRM_MODE_REFLECT_X |
+ DRM_MODE_REFLECT_Y;
+ unsigned int rotation = state->rotation;
struct tegra_bo_tiling *tiling = &plane_state->tiling;
struct tegra_plane *tegra = to_tegra_plane(plane);
struct tegra_dc *dc = to_tegra_dc(state->crtc);
@@ -639,12 +648,26 @@
return -EINVAL;
}
- rotation = drm_rotation_simplify(state->rotation, rotation);
+ /*
+ * Older userspace used custom BO flag in order to specify the Y
+ * reflection, while modern userspace uses the generic DRM rotation
+ * property in order to achieve the same result. The legacy BO flag
+ * duplicates the DRM rotation property when both are set.
+ */
+ if (tegra_fb_is_bottom_up(state->fb))
+ rotation |= DRM_MODE_REFLECT_Y;
+
+ rotation = drm_rotation_simplify(rotation, supported_rotation);
+
+ if (rotation & DRM_MODE_REFLECT_X)
+ plane_state->reflect_x = true;
+ else
+ plane_state->reflect_x = false;
if (rotation & DRM_MODE_REFLECT_Y)
- plane_state->bottom_up = true;
+ plane_state->reflect_y = true;
else
- plane_state->bottom_up = false;
+ plane_state->reflect_y = false;
/*
* Tegra doesn't support different strides for U and V planes so we
@@ -706,7 +729,8 @@
window.dst.w = drm_rect_width(&plane->state->dst);
window.dst.h = drm_rect_height(&plane->state->dst);
window.bits_per_pixel = fb->format->cpp[0] * 8;
- window.bottom_up = tegra_fb_is_bottom_up(fb) || state->bottom_up;
+ window.reflect_x = state->reflect_x;
+ window.reflect_y = state->reflect_y;
/* copy from state */
window.zpos = plane->state->normalized_zpos;
@@ -715,9 +739,7 @@
window.swap = state->swap;
for (i = 0; i < fb->format->num_planes; i++) {
- struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
-
- window.base[i] = bo->paddr + fb->offsets[i];
+ window.base[i] = state->iova[i] + fb->offsets[i];
/*
* Tegra uses a shared stride for UV planes. Framebuffers are
@@ -732,6 +754,8 @@
}
static const struct drm_plane_helper_funcs tegra_plane_helper_funcs = {
+ .prepare_fb = tegra_plane_prepare_fb,
+ .cleanup_fb = tegra_plane_cleanup_fb,
.atomic_check = tegra_plane_atomic_check,
.atomic_disable = tegra_plane_atomic_disable,
.atomic_update = tegra_plane_atomic_update,
@@ -792,6 +816,8 @@
err = drm_plane_create_rotation_property(&plane->base,
DRM_MODE_ROTATE_0,
DRM_MODE_ROTATE_0 |
+ DRM_MODE_ROTATE_180 |
+ DRM_MODE_REFLECT_X |
DRM_MODE_REFLECT_Y);
if (err < 0)
dev_err(dc->dev, "failed to create rotation property: %d\n",
@@ -837,16 +863,15 @@
static void tegra_cursor_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
- struct tegra_bo *bo = tegra_fb_get_plane(plane->state->fb, 0);
+ struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
- struct drm_plane_state *state = plane->state;
u32 value = CURSOR_CLIP_DISPLAY;
/* rien ne va plus */
if (!plane->state->crtc || !plane->state->fb)
return;
- switch (state->crtc_w) {
+ switch (plane->state->crtc_w) {
case 32:
value |= CURSOR_SIZE_32x32;
break;
@@ -864,16 +889,16 @@
break;
default:
- WARN(1, "cursor size %ux%u not supported\n", state->crtc_w,
- state->crtc_h);
+ WARN(1, "cursor size %ux%u not supported\n",
+ plane->state->crtc_w, plane->state->crtc_h);
return;
}
- value |= (bo->paddr >> 10) & 0x3fffff;
+ value |= (state->iova[0] >> 10) & 0x3fffff;
tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- value = (bo->paddr >> 32) & 0x3;
+ value = (state->iova[0] >> 32) & 0x3;
tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI);
#endif
@@ -892,7 +917,8 @@
tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
/* position the cursor */
- value = (state->crtc_y & 0x3fff) << 16 | (state->crtc_x & 0x3fff);
+ value = (plane->state->crtc_y & 0x3fff) << 16 |
+ (plane->state->crtc_x & 0x3fff);
tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
}
@@ -914,6 +940,8 @@
}
static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = {
+ .prepare_fb = tegra_plane_prepare_fb,
+ .cleanup_fb = tegra_plane_cleanup_fb,
.atomic_check = tegra_cursor_atomic_check,
.atomic_update = tegra_cursor_atomic_update,
.atomic_disable = tegra_cursor_atomic_disable,
@@ -960,6 +988,7 @@
}
drm_plane_helper_add(&plane->base, &tegra_cursor_plane_helper_funcs);
+ drm_plane_create_zpos_immutable_property(&plane->base, 255);
return &plane->base;
}
@@ -1083,6 +1112,8 @@
err = drm_plane_create_rotation_property(&plane->base,
DRM_MODE_ROTATE_0,
DRM_MODE_ROTATE_0 |
+ DRM_MODE_ROTATE_180 |
+ DRM_MODE_REFLECT_X |
DRM_MODE_REFLECT_Y);
if (err < 0)
dev_err(dc->dev, "failed to create rotation property: %d\n",
@@ -1172,7 +1203,6 @@
tegra_crtc_atomic_destroy_state(crtc, crtc->state);
__drm_atomic_helper_crtc_reset(crtc, &state->base);
- drm_crtc_vblank_reset(crtc);
}
static struct drm_crtc_state *
@@ -1500,7 +1530,6 @@
struct drm_minor *minor = crtc->dev->primary;
struct dentry *root;
struct tegra_dc *dc = to_tegra_dc(crtc);
- int err;
#ifdef CONFIG_DEBUG_FS
root = crtc->debugfs_entry;
@@ -1516,17 +1545,9 @@
for (i = 0; i < count; i++)
dc->debugfs_files[i].data = dc;
- err = drm_debugfs_create_files(dc->debugfs_files, count, root, minor);
- if (err < 0)
- goto free;
+ drm_debugfs_create_files(dc->debugfs_files, count, root, minor);
return 0;
-
-free:
- kfree(dc->debugfs_files);
- dc->debugfs_files = NULL;
-
- return err;
}
static void tegra_dc_early_unregister(struct drm_crtc *crtc)
@@ -1731,6 +1752,7 @@
{
struct tegra_dc *dc = to_tegra_dc(crtc);
u32 value;
+ int err;
if (!tegra_dc_idle(dc)) {
tegra_dc_stop(dc);
@@ -1777,7 +1799,9 @@
spin_unlock_irq(&crtc->dev->event_lock);
- pm_runtime_put_sync(dc->dev);
+ err = host1x_client_suspend(&dc->client);
+ if (err < 0)
+ dev_err(dc->dev, "failed to suspend: %d\n", err);
}
static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
@@ -1787,8 +1811,13 @@
struct tegra_dc_state *state = to_dc_state(crtc->state);
struct tegra_dc *dc = to_tegra_dc(crtc);
u32 value;
+ int err;
- pm_runtime_get_sync(dc->dev);
+ err = host1x_client_resume(&dc->client);
+ if (err < 0) {
+ dev_err(dc->dev, "failed to resume: %d\n", err);
+ return;
+ }
/* initialize display controller */
if (dc->syncpt) {
@@ -2000,7 +2029,7 @@
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->host);
unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
struct tegra_dc *dc = host1x_client_to_dc(client);
struct tegra_drm *tegra = drm->dev_private;
@@ -2016,13 +2045,21 @@
if (!tegra_dc_has_window_groups(dc))
return 0;
+ /*
+ * Set the display hub as the host1x client parent for the display
+ * controller. This is needed for the runtime reference counting that
+ * ensures the display hub is always powered when any of the display
+ * controllers are.
+ */
+ if (dc->soc->has_nvdisplay)
+ client->parent = &tegra->hub->client;
+
dc->syncpt = host1x_syncpt_request(client, flags);
if (!dc->syncpt)
dev_warn(dc->dev, "failed to allocate syncpoint\n");
- dc->group = host1x_client_iommu_attach(client, true);
- if (IS_ERR(dc->group)) {
- err = PTR_ERR(dc->group);
+ err = host1x_client_iommu_attach(client);
+ if (err < 0 && err != -ENODEV) {
dev_err(client->dev, "failed to attach to domain: %d\n", err);
return err;
}
@@ -2080,6 +2117,12 @@
goto cleanup;
}
+ /*
+ * Inherit the DMA parameters (such as maximum segment size) from the
+ * parent host1x device.
+ */
+ client->dev->dma_parms = client->host->dma_parms;
+
return 0;
cleanup:
@@ -2089,7 +2132,7 @@
if (!IS_ERR(primary))
drm_plane_cleanup(primary);
- host1x_client_iommu_detach(client, dc->group);
+ host1x_client_iommu_detach(client);
host1x_syncpt_free(dc->syncpt);
return err;
@@ -2103,6 +2146,9 @@
if (!tegra_dc_has_window_groups(dc))
return 0;
+ /* avoid a dangling pointer just in case this disappears */
+ client->dev->dma_parms = NULL;
+
devm_free_irq(dc->dev, dc->irq, dc);
err = tegra_dc_rgb_exit(dc);
@@ -2111,15 +2157,80 @@
return err;
}
- host1x_client_iommu_detach(client, dc->group);
+ host1x_client_iommu_detach(client);
host1x_syncpt_free(dc->syncpt);
return 0;
}
+static int tegra_dc_runtime_suspend(struct host1x_client *client)
+{
+ struct tegra_dc *dc = host1x_client_to_dc(client);
+ struct device *dev = client->dev;
+ int err;
+
+ err = reset_control_assert(dc->rst);
+ if (err < 0) {
+ dev_err(dev, "failed to assert reset: %d\n", err);
+ return err;
+ }
+
+ if (dc->soc->has_powergate)
+ tegra_powergate_power_off(dc->powergate);
+
+ clk_disable_unprepare(dc->clk);
+ pm_runtime_put_sync(dev);
+
+ return 0;
+}
+
+static int tegra_dc_runtime_resume(struct host1x_client *client)
+{
+ struct tegra_dc *dc = host1x_client_to_dc(client);
+ struct device *dev = client->dev;
+ int err;
+
+ err = pm_runtime_resume_and_get(dev);
+ if (err < 0) {
+ dev_err(dev, "failed to get runtime PM: %d\n", err);
+ return err;
+ }
+
+ if (dc->soc->has_powergate) {
+ err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
+ dc->rst);
+ if (err < 0) {
+ dev_err(dev, "failed to power partition: %d\n", err);
+ goto put_rpm;
+ }
+ } else {
+ err = clk_prepare_enable(dc->clk);
+ if (err < 0) {
+ dev_err(dev, "failed to enable clock: %d\n", err);
+ goto put_rpm;
+ }
+
+ err = reset_control_deassert(dc->rst);
+ if (err < 0) {
+ dev_err(dev, "failed to deassert reset: %d\n", err);
+ goto disable_clk;
+ }
+ }
+
+ return 0;
+
+disable_clk:
+ clk_disable_unprepare(dc->clk);
+put_rpm:
+ pm_runtime_put_sync(dev);
+ return err;
+}
+
static const struct host1x_client_ops dc_client_ops = {
.init = tegra_dc_init,
.exit = tegra_dc_exit,
+ .suspend = tegra_dc_runtime_suspend,
+ .resume = tegra_dc_runtime_resume,
};
static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
@@ -2394,22 +2505,18 @@
* POWER_CONTROL registers during CRTC enabling.
*/
if (dc->soc->coupled_pm && dc->pipe == 1) {
- u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_CONSUMER;
- struct device_link *link;
- struct device *partner;
+ struct device *companion;
+ struct tegra_dc *parent;
- partner = driver_find_device(dc->dev->driver, NULL, NULL,
- tegra_dc_match_by_pipe);
- if (!partner)
+ companion = driver_find_device(dc->dev->driver, NULL, (const void *)0,
+ tegra_dc_match_by_pipe);
+ if (!companion)
return -EPROBE_DEFER;
- link = device_link_add(dc->dev, partner, flags);
- if (!link) {
- dev_err(dc->dev, "failed to link controllers\n");
- return -EINVAL;
- }
+ parent = dev_get_drvdata(companion);
+ dc->client.parent = &parent->client;
- dev_dbg(dc->dev, "coupled to %s\n", dev_name(partner));
+ dev_dbg(dc->dev, "coupled to %s\n", dev_name(companion));
}
return 0;
@@ -2417,7 +2524,6 @@
static int tegra_dc_probe(struct platform_device *pdev)
{
- struct resource *regs;
struct tegra_dc *dc;
int err;
@@ -2474,20 +2580,23 @@
tegra_powergate_power_off(dc->powergate);
}
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dc->regs = devm_ioremap_resource(&pdev->dev, regs);
+ dc->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dc->regs))
return PTR_ERR(dc->regs);
dc->irq = platform_get_irq(pdev, 0);
- if (dc->irq < 0) {
- dev_err(&pdev->dev, "failed to get IRQ\n");
+ if (dc->irq < 0)
return -ENXIO;
- }
err = tegra_dc_rgb_probe(dc);
if (err < 0 && err != -ENODEV) {
- dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err);
+ const char *level = KERN_ERR;
+
+ if (err == -EPROBE_DEFER)
+ level = KERN_DEBUG;
+
+ dev_printk(level, dc->dev, "failed to probe RGB output: %d\n",
+ err);
return err;
}
@@ -2502,10 +2611,16 @@
if (err < 0) {
dev_err(&pdev->dev, "failed to register host1x client: %d\n",
err);
- return err;
+ goto disable_pm;
}
return 0;
+
+disable_pm:
+ pm_runtime_disable(&pdev->dev);
+ tegra_dc_rgb_remove(dc);
+
+ return err;
}
static int tegra_dc_remove(struct platform_device *pdev)
@@ -2531,65 +2646,10 @@
return 0;
}
-#ifdef CONFIG_PM
-static int tegra_dc_suspend(struct device *dev)
-{
- struct tegra_dc *dc = dev_get_drvdata(dev);
- int err;
-
- err = reset_control_assert(dc->rst);
- if (err < 0) {
- dev_err(dev, "failed to assert reset: %d\n", err);
- return err;
- }
-
- if (dc->soc->has_powergate)
- tegra_powergate_power_off(dc->powergate);
-
- clk_disable_unprepare(dc->clk);
-
- return 0;
-}
-
-static int tegra_dc_resume(struct device *dev)
-{
- struct tegra_dc *dc = dev_get_drvdata(dev);
- int err;
-
- if (dc->soc->has_powergate) {
- err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
- dc->rst);
- if (err < 0) {
- dev_err(dev, "failed to power partition: %d\n", err);
- return err;
- }
- } else {
- err = clk_prepare_enable(dc->clk);
- if (err < 0) {
- dev_err(dev, "failed to enable clock: %d\n", err);
- return err;
- }
-
- err = reset_control_deassert(dc->rst);
- if (err < 0) {
- dev_err(dev, "failed to deassert reset: %d\n", err);
- return err;
- }
- }
-
- return 0;
-}
-#endif
-
-static const struct dev_pm_ops tegra_dc_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra_dc_suspend, tegra_dc_resume, NULL)
-};
-
struct platform_driver tegra_dc_driver = {
.driver = {
.name = "tegra-dc",
.of_match_table = tegra_dc_of_match,
- .pm = &tegra_dc_pm_ops,
},
.probe = tegra_dc_probe,
.remove = tegra_dc_remove,