drm/tegra: Update to Linux v6.8

Update the Tegra DRM driver to align with the upstream Linux v6.8 kernel
preserving all the downstream changes that still need to be upstreamed.

JIRA LINQPJ14-47

Change-Id: If0a9149bcfa2fd6276ac8100933abc3d532a5ddc
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3333320
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Jon Hunter
2025-03-26 11:04:06 +00:00
parent 8a28999d28
commit 13834d4e13
20 changed files with 162 additions and 129 deletions

View File

@@ -13,6 +13,7 @@
#include <linux/iommu.h> #include <linux/iommu.h>
#include <linux/interconnect.h> #include <linux/interconnect.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
@@ -2397,7 +2398,6 @@ static int tegra_crtc_calculate_memory_bandwidth(struct drm_crtc *crtc,
const struct tegra_plane_state *tegra_state; const struct tegra_plane_state *tegra_state;
const struct drm_plane_state *plane_state; const struct drm_plane_state *plane_state;
struct tegra_dc *dc = to_tegra_dc(crtc); struct tegra_dc *dc = to_tegra_dc(crtc);
const struct drm_crtc_state *old_state;
struct drm_crtc_state *new_state; struct drm_crtc_state *new_state;
struct tegra_plane *tegra; struct tegra_plane *tegra;
struct drm_plane *plane; struct drm_plane *plane;
@@ -2412,7 +2412,6 @@ static int tegra_crtc_calculate_memory_bandwidth(struct drm_crtc *crtc,
return 0; return 0;
new_state = drm_atomic_get_new_crtc_state(state, crtc); new_state = drm_atomic_get_new_crtc_state(state, crtc);
old_state = drm_atomic_get_old_crtc_state(state, crtc);
/* /*
* For overlapping planes pixel's data is fetched for each plane at * For overlapping planes pixel's data is fetched for each plane at

View File

@@ -10,8 +10,8 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h> #include <linux/pinctrl/pinmux.h>
@@ -462,7 +462,6 @@ static const struct pinmux_ops tegra_dpaux_pinmux_ops = {
static int tegra_dpaux_probe(struct platform_device *pdev) static int tegra_dpaux_probe(struct platform_device *pdev)
{ {
struct tegra_dpaux *dpaux; struct tegra_dpaux *dpaux;
struct resource *regs;
u32 value; u32 value;
int err; int err;
@@ -476,14 +475,13 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&dpaux->list); INIT_LIST_HEAD(&dpaux->list);
dpaux->dev = &pdev->dev; dpaux->dev = &pdev->dev;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); dpaux->regs = devm_platform_ioremap_resource(pdev, 0);
dpaux->regs = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(dpaux->regs)) if (IS_ERR(dpaux->regs))
return PTR_ERR(dpaux->regs); return PTR_ERR(dpaux->regs);
dpaux->irq = platform_get_irq(pdev, 0); dpaux->irq = platform_get_irq(pdev, 0);
if (dpaux->irq < 0) if (dpaux->irq < 0)
return -ENXIO; return dpaux->irq;
if (!pdev->dev.pm_domain) { if (!pdev->dev.pm_domain) {
dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux"); dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux");
@@ -613,7 +611,6 @@ static int tegra_dpaux_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int tegra_dpaux_suspend(struct device *dev) static int tegra_dpaux_suspend(struct device *dev)
{ {
struct tegra_dpaux *dpaux = dev_get_drvdata(dev); struct tegra_dpaux *dpaux = dev_get_drvdata(dev);
@@ -672,10 +669,9 @@ disable_clk:
clk_disable_unprepare(dpaux->clk); clk_disable_unprepare(dpaux->clk);
return err; return err;
} }
#endif
static const struct dev_pm_ops tegra_dpaux_pm_ops = { static const struct dev_pm_ops tegra_dpaux_pm_ops = {
SET_RUNTIME_PM_OPS(tegra_dpaux_suspend, tegra_dpaux_resume, NULL) RUNTIME_PM_OPS(tegra_dpaux_suspend, tegra_dpaux_resume, NULL)
}; };
static const struct tegra_dpaux_soc tegra124_dpaux_soc = { static const struct tegra_dpaux_soc tegra124_dpaux_soc = {
@@ -721,7 +717,7 @@ struct platform_driver tegra_dpaux_driver = {
.driver = { .driver = {
.name = "tegra-dpaux", .name = "tegra-dpaux",
.of_match_table = tegra_dpaux_of_match, .of_match_table = tegra_dpaux_of_match,
.pm = &tegra_dpaux_pm_ops, .pm = pm_ptr(&tegra_dpaux_pm_ops),
}, },
.probe = tegra_dpaux_probe, .probe = tegra_dpaux_probe,
.remove = tegra_dpaux_remove_wrapper, .remove = tegra_dpaux_remove_wrapper,

View File

@@ -814,7 +814,8 @@ int host1x_client_iommu_attach(struct host1x_client *client)
* not the shared IOMMU domain, don't try to attach it to a different * not the shared IOMMU domain, don't try to attach it to a different
* domain. This allows using the IOMMU-backed DMA API. * domain. This allows using the IOMMU-backed DMA API.
*/ */
if (domain && domain != tegra->domain) if (domain && domain->type != IOMMU_DOMAIN_IDENTITY &&
domain != tegra->domain)
return 0; return 0;
if (tegra->domain) { if (tegra->domain) {
@@ -984,6 +985,10 @@ static bool host1x_drm_wants_iommu(struct host1x_device *dev)
struct host1x *host1x = dev_get_drvdata(dev->dev.parent); struct host1x *host1x = dev_get_drvdata(dev->dev.parent);
struct iommu_domain *domain; struct iommu_domain *domain;
/* Our IOMMU usage policy doesn't currently play well with GART */
if (of_machine_is_compatible("nvidia,tegra20"))
return false;
/* /*
* If the Tegra DRM clients are backed by an IOMMU, push buffers are * If the Tegra DRM clients are backed by an IOMMU, push buffers are
* likely to be allocated beyond the 32-bit boundary if sufficient * likely to be allocated beyond the 32-bit boundary if sufficient
@@ -1161,6 +1166,15 @@ static int host1x_drm_probe(struct host1x_device *dev)
drm_mode_config_reset(drm); drm_mode_config_reset(drm);
/*
* Only take over from a potential firmware framebuffer if any CRTCs
* have been registered. This must not be a fatal error because there
* are other accelerators that are exposed via this driver.
*
* Another case where this happens is on Tegra234 where the display
* hardware is no longer part of the host1x complex, so this driver
* will not expose any modesetting features.
*/
if (drm->mode_config.num_crtc > 0) { if (drm->mode_config.num_crtc > 0) {
#if defined(NV_APERTURE_REMOVE_ALL_CONFLICTING_DEVICES_PRESENT) /* Linux v6.0 */ #if defined(NV_APERTURE_REMOVE_ALL_CONFLICTING_DEVICES_PRESENT) /* Linux v6.0 */
err = aperture_remove_all_conflicting_devices(tegra_drm_driver.name); err = aperture_remove_all_conflicting_devices(tegra_drm_driver.name);
@@ -1173,6 +1187,12 @@ static int host1x_drm_probe(struct host1x_device *dev)
#endif #endif
if (err < 0) if (err < 0)
goto hub; goto hub;
} else {
/*
* Indicate to userspace that this doesn't expose any display
* capabilities.
*/
drm->driver_features &= ~(DRIVER_MODESET | DRIVER_ATOMIC);
} }
err = drm_dev_register(drm, 0); err = drm_dev_register(drm, 0);

View File

@@ -138,9 +138,6 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra,
int host1x_client_iommu_attach(struct host1x_client *client); int host1x_client_iommu_attach(struct host1x_client *client);
void host1x_client_iommu_detach(struct host1x_client *client); void host1x_client_iommu_detach(struct host1x_client *client);
int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm);
int tegra_drm_exit(struct tegra_drm *tegra);
void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, dma_addr_t *iova); void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, dma_addr_t *iova);
void tegra_drm_free(struct tegra_drm *tegra, size_t size, void *virt, void tegra_drm_free(struct tegra_drm *tegra, size_t size, void *virt,
dma_addr_t iova); dma_addr_t iova);

View File

@@ -920,6 +920,15 @@ static void tegra_dsi_encoder_enable(struct drm_encoder *encoder)
u32 value; u32 value;
int err; int err;
/* If the bootloader enabled DSI it needs to be disabled
* in order for the panel initialization commands to be
* properly sent.
*/
value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
if (value & DSI_POWER_CONTROL_ENABLE)
tegra_dsi_disable(dsi);
err = tegra_dsi_prepare(dsi); err = tegra_dsi_prepare(dsi);
if (err < 0) { if (err < 0) {
dev_err(dsi->dev, "failed to prepare: %d\n", err); dev_err(dsi->dev, "failed to prepare: %d\n", err);
@@ -1597,28 +1606,24 @@ static int tegra_dsi_probe(struct platform_device *pdev)
} }
dsi->clk = devm_clk_get(&pdev->dev, NULL); dsi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dsi->clk)) { if (IS_ERR(dsi->clk))
dev_err(&pdev->dev, "cannot get DSI clock\n"); return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk),
return PTR_ERR(dsi->clk); "cannot get DSI clock\n");
}
dsi->clk_lp = devm_clk_get(&pdev->dev, "lp"); dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
if (IS_ERR(dsi->clk_lp)) { if (IS_ERR(dsi->clk_lp))
dev_err(&pdev->dev, "cannot get low-power clock\n"); return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp),
return PTR_ERR(dsi->clk_lp); "cannot get low-power clock\n");
}
dsi->clk_parent = devm_clk_get(&pdev->dev, "parent"); dsi->clk_parent = devm_clk_get(&pdev->dev, "parent");
if (IS_ERR(dsi->clk_parent)) { if (IS_ERR(dsi->clk_parent))
dev_err(&pdev->dev, "cannot get parent clock\n"); return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_parent),
return PTR_ERR(dsi->clk_parent); "cannot get parent clock\n");
}
dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi"); dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
if (IS_ERR(dsi->vdd)) { if (IS_ERR(dsi->vdd))
dev_err(&pdev->dev, "cannot get VDD supply\n"); return dev_err_probe(&pdev->dev, PTR_ERR(dsi->vdd),
return PTR_ERR(dsi->vdd); "cannot get VDD supply\n");
}
err = tegra_dsi_setup_clocks(dsi); err = tegra_dsi_setup_clocks(dsi);
if (err < 0) { if (err < 0) {

View File

@@ -3,7 +3,7 @@
* Copyright (C) 2012-2013 Avionic Design GmbH * Copyright (C) 2012-2013 Avionic Design GmbH
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
* *
* Based on the KMS/FB CMA helpers * Based on the KMS/FB DMA helpers
* Copyright (C) 2012 Analog Devices Inc. * Copyright (C) 2012 Analog Devices Inc.
*/ */

View File

@@ -10,6 +10,7 @@
#include <nvidia/conftest.h> #include <nvidia/conftest.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/fb.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
@@ -161,7 +162,8 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
#if defined(NV_DRM_MODE_CONFIG_STRUCT_HAS_FB_BASE_ARG) /* Linux v6.2 */ #if defined(NV_DRM_MODE_CONFIG_STRUCT_HAS_FB_BASE_ARG) /* Linux v6.2 */
drm->mode_config.fb_base = (resource_size_t)bo->iova; drm->mode_config.fb_base = (resource_size_t)bo->iova;
#endif #endif
info->screen_base = (void __iomem *)bo->vaddr + offset; info->flags |= FBINFO_VIRTFB;
info->screen_buffer = bo->vaddr + offset;
info->screen_size = size; info->screen_size = size;
info->fix.smem_start = (unsigned long)(bo->iova + offset); info->fix.smem_start = (unsigned long)(bo->iova + offset);
info->fix.smem_len = size; info->fix.smem_len = size;

View File

@@ -183,21 +183,30 @@ static void *tegra_bo_mmap(struct host1x_bo *bo)
{ {
struct tegra_bo *obj = host1x_to_tegra_bo(bo); struct tegra_bo *obj = host1x_to_tegra_bo(bo);
#if defined(NV_LINUX_IOSYS_MAP_H_PRESENT) #if defined(NV_LINUX_IOSYS_MAP_H_PRESENT)
struct iosys_map map = {0}; struct iosys_map map = { 0 };
#else #else
struct dma_buf_map map = {0}; struct dma_buf_map map = { 0 };
#endif #endif
void *vaddr;
int ret; int ret;
if (obj->vaddr) { if (obj->vaddr)
return obj->vaddr; return obj->vaddr;
} else if (obj->dma_buf) {
if (obj->dma_buf) {
ret = dma_buf_vmap(obj->dma_buf, &map); ret = dma_buf_vmap(obj->dma_buf, &map);
return ret ? NULL : map.vaddr; if (ret < 0)
} else { return ERR_PTR(ret);
return vmap(obj->pages, obj->num_pages, VM_MAP,
pgprot_writecombine(PAGE_KERNEL)); return map.vaddr;
} }
vaddr = vmap(obj->pages, obj->num_pages, VM_MAP,
pgprot_writecombine(PAGE_KERNEL));
if (!vaddr)
return ERR_PTR(-ENOMEM);
return vaddr;
} }
static void tegra_bo_munmap(struct host1x_bo *bo, void *addr) static void tegra_bo_munmap(struct host1x_bo *bo, void *addr)
@@ -211,10 +220,11 @@ static void tegra_bo_munmap(struct host1x_bo *bo, void *addr)
if (obj->vaddr) if (obj->vaddr)
return; return;
else if (obj->dma_buf)
if (obj->dma_buf)
dma_buf_vunmap(obj->dma_buf, &map); dma_buf_vunmap(obj->dma_buf, &map);
else
vunmap(addr); vunmap(addr);
} }
static struct host1x_bo *tegra_bo_get(struct host1x_bo *bo) static struct host1x_bo *tegra_bo_get(struct host1x_bo *bo)

View File

@@ -298,7 +298,6 @@ static int gr2d_remove(struct platform_device *pdev)
struct gr2d *gr2d = platform_get_drvdata(pdev); struct gr2d *gr2d = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
host1x_client_unregister(&gr2d->client.base); host1x_client_unregister(&gr2d->client.base);
return 0; return 0;

View File

@@ -11,6 +11,7 @@
#include <linux/host1x-next.h> #include <linux/host1x-next.h>
#include <linux/iommu.h> #include <linux/iommu.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
@@ -570,7 +571,6 @@ static int gr3d_remove(struct platform_device *pdev)
struct gr3d *gr3d = platform_get_drvdata(pdev); struct gr3d *gr3d = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
host1x_client_unregister(&gr3d->client.base); host1x_client_unregister(&gr3d->client.base);
return 0; return 0;

View File

@@ -12,7 +12,9 @@
#include <linux/hdmi.h> #include <linux/hdmi.h>
#include <linux/math64.h> #include <linux/math64.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h> #include <linux/pm_opp.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
@@ -21,6 +23,7 @@
#include <soc/tegra/common.h> #include <soc/tegra/common.h>
#include <sound/hdmi-codec.h> #include <sound/hdmi-codec.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_debugfs.h> #include <drm/drm_debugfs.h>
@@ -872,14 +875,7 @@ static int tegra_hdmi_reconfigure_audio(struct tegra_hdmi *hdmi)
static bool tegra_output_is_hdmi(struct tegra_output *output) static bool tegra_output_is_hdmi(struct tegra_output *output)
{ {
struct edid *edid; return output->connector.display_info.is_hdmi;
if (!output->connector.edid_blob_ptr)
return false;
edid = (struct edid *)output->connector.edid_blob_ptr->data;
return drm_detect_hdmi_monitor(edid);
} }
static enum drm_connector_status static enum drm_connector_status
@@ -1561,26 +1557,47 @@ static int tegra_hdmi_init(struct host1x_client *client)
{ {
struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
struct drm_device *drm = dev_get_drvdata(client->host); struct drm_device *drm = dev_get_drvdata(client->host);
struct drm_connector *connector;
int err; int err;
hdmi->output.dev = client->dev; hdmi->output.dev = client->dev;
drm_connector_init_with_ddc(drm, &hdmi->output.connector,
&tegra_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA,
hdmi->output.ddc);
drm_connector_helper_add(&hdmi->output.connector,
&tegra_hdmi_connector_helper_funcs);
hdmi->output.connector.dpms = DRM_MODE_DPMS_OFF;
drm_simple_encoder_init(drm, &hdmi->output.encoder, drm_simple_encoder_init(drm, &hdmi->output.encoder,
DRM_MODE_ENCODER_TMDS); DRM_MODE_ENCODER_TMDS);
drm_encoder_helper_add(&hdmi->output.encoder, drm_encoder_helper_add(&hdmi->output.encoder,
&tegra_hdmi_encoder_helper_funcs); &tegra_hdmi_encoder_helper_funcs);
drm_connector_attach_encoder(&hdmi->output.connector, if (hdmi->output.bridge) {
&hdmi->output.encoder); err = drm_bridge_attach(&hdmi->output.encoder, hdmi->output.bridge,
drm_connector_register(&hdmi->output.connector); NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (err) {
dev_err(client->dev, "failed to attach bridge: %d\n",
err);
return err;
}
connector = drm_bridge_connector_init(drm, &hdmi->output.encoder);
if (IS_ERR(connector)) {
dev_err(client->dev,
"failed to initialize bridge connector: %pe\n",
connector);
return PTR_ERR(connector);
}
drm_connector_attach_encoder(connector, &hdmi->output.encoder);
} else {
drm_connector_init_with_ddc(drm, &hdmi->output.connector,
&tegra_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA,
hdmi->output.ddc);
drm_connector_helper_add(&hdmi->output.connector,
&tegra_hdmi_connector_helper_funcs);
hdmi->output.connector.dpms = DRM_MODE_DPMS_OFF;
drm_connector_attach_encoder(&hdmi->output.connector,
&hdmi->output.encoder);
drm_connector_register(&hdmi->output.connector);
}
err = tegra_output_init(drm, &hdmi->output); err = tegra_output_init(drm, &hdmi->output);
if (err < 0) { if (err < 0) {
@@ -1786,7 +1803,6 @@ static irqreturn_t tegra_hdmi_irq(int irq, void *data)
static int tegra_hdmi_probe(struct platform_device *pdev) static int tegra_hdmi_probe(struct platform_device *pdev)
{ {
struct tegra_hdmi *hdmi; struct tegra_hdmi *hdmi;
struct resource *regs;
int err; int err;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
@@ -1848,8 +1864,7 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
if (err < 0) if (err < 0)
return err; return err;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); hdmi->regs = devm_platform_ioremap_resource(pdev, 0);
hdmi->regs = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(hdmi->regs)) if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs); return PTR_ERR(hdmi->regs);

View File

@@ -11,7 +11,6 @@
#include <linux/host1x-next.h> #include <linux/host1x-next.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
@@ -1104,7 +1103,7 @@ static int tegra_display_hub_probe(struct platform_device *pdev)
for (i = 0; i < hub->soc->num_wgrps; i++) { for (i = 0; i < hub->soc->num_wgrps; i++) {
struct tegra_windowgroup *wgrp = &hub->wgrps[i]; struct tegra_windowgroup *wgrp = &hub->wgrps[i];
char id[8]; char id[16];
snprintf(id, sizeof(id), "wgrp%u", i); snprintf(id, sizeof(id), "wgrp%u", i);
mutex_init(&wgrp->lock); mutex_init(&wgrp->lock);

View File

@@ -18,7 +18,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_opp.h> #include <linux/pm_opp.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
@@ -501,6 +500,8 @@ static int nvdec_load_falcon_firmware(struct nvdec *nvdec)
return err; return err;
} else { } else {
virt = tegra_drm_alloc(tegra, size, &iova); virt = tegra_drm_alloc(tegra, size, &iova);
if (IS_ERR(virt))
return PTR_ERR(virt);
} }
nvdec->falcon.firmware.virt = virt; nvdec->falcon.firmware.virt = virt;
@@ -955,7 +956,6 @@ static int nvdec_remove(struct platform_device *pdev)
host1x_actmon_unregister(&nvdec->client.base); host1x_actmon_unregister(&nvdec->client.base);
host1x_client_unregister(&nvdec->client.base); host1x_client_unregister(&nvdec->client.base);
falcon_exit(&nvdec->falcon); falcon_exit(&nvdec->falcon);
return 0; return 0;

View File

@@ -137,10 +137,10 @@ int tegra_output_probe(struct tegra_output *output)
} }
output->hpd_gpio = devm_fwnode_gpiod_get(output->dev, output->hpd_gpio = devm_fwnode_gpiod_get(output->dev,
of_fwnode_handle(output->of_node), of_fwnode_handle(output->of_node),
"nvidia,hpd", "nvidia,hpd",
GPIOD_IN, GPIOD_IN,
"HDMI hotplug detect"); "HDMI hotplug detect");
if (IS_ERR(output->hpd_gpio)) { if (IS_ERR(output->hpd_gpio)) {
if (PTR_ERR(output->hpd_gpio) != -ENOENT) if (PTR_ERR(output->hpd_gpio) != -ENOENT)
return PTR_ERR(output->hpd_gpio); return PTR_ERR(output->hpd_gpio);

View File

@@ -778,21 +778,17 @@ int tegra_plane_interconnect_init(struct tegra_plane *plane)
plane->icc_mem = devm_of_icc_get(dev, icc_name); plane->icc_mem = devm_of_icc_get(dev, icc_name);
err = PTR_ERR_OR_ZERO(plane->icc_mem); err = PTR_ERR_OR_ZERO(plane->icc_mem);
if (err) { if (err)
dev_err_probe(dev, err, "failed to get %s interconnect\n", return dev_err_probe(dev, err, "failed to get %s interconnect\n",
icc_name); icc_name);
return err;
}
/* plane B on T20/30 has a dedicated memory client for a 6-tap vertical filter */ /* plane B on T20/30 has a dedicated memory client for a 6-tap vertical filter */
if (plane->index == 1 && dc->soc->has_win_b_vfilter_mem_client) { if (plane->index == 1 && dc->soc->has_win_b_vfilter_mem_client) {
plane->icc_mem_vfilter = devm_of_icc_get(dev, "winb-vfilter"); plane->icc_mem_vfilter = devm_of_icc_get(dev, "winb-vfilter");
err = PTR_ERR_OR_ZERO(plane->icc_mem_vfilter); err = PTR_ERR_OR_ZERO(plane->icc_mem_vfilter);
if (err) { if (err)
dev_err_probe(dev, err, "failed to get %s interconnect\n", return dev_err_probe(dev, err, "failed to get %s interconnect\n",
"winb-vfilter"); "winb-vfilter");
return err;
}
} }
return 0; return 0;

View File

@@ -99,6 +99,7 @@ static void tegra_rgb_encoder_disable(struct drm_encoder *encoder)
static void tegra_rgb_encoder_enable(struct drm_encoder *encoder) static void tegra_rgb_encoder_enable(struct drm_encoder *encoder)
{ {
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
struct tegra_output *output = encoder_to_output(encoder); struct tegra_output *output = encoder_to_output(encoder);
struct tegra_rgb *rgb = to_rgb(output); struct tegra_rgb *rgb = to_rgb(output);
u32 value; u32 value;
@@ -108,10 +109,19 @@ static void tegra_rgb_encoder_enable(struct drm_encoder *encoder)
value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL; value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL;
tegra_dc_writel(rgb->dc, value, DC_DISP_DATA_ENABLE_OPTIONS); tegra_dc_writel(rgb->dc, value, DC_DISP_DATA_ENABLE_OPTIONS);
/* XXX: parameterize? */ /* configure H- and V-sync signal polarities */
value = tegra_dc_readl(rgb->dc, DC_COM_PIN_OUTPUT_POLARITY(1)); value = tegra_dc_readl(rgb->dc, DC_COM_PIN_OUTPUT_POLARITY(1));
value &= ~LVS_OUTPUT_POLARITY_LOW;
value &= ~LHS_OUTPUT_POLARITY_LOW; if (mode->flags & DRM_MODE_FLAG_NHSYNC)
value |= LHS_OUTPUT_POLARITY_LOW;
else
value &= ~LHS_OUTPUT_POLARITY_LOW;
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
value |= LVS_OUTPUT_POLARITY_LOW;
else
value &= ~LVS_OUTPUT_POLARITY_LOW;
tegra_dc_writel(rgb->dc, value, DC_COM_PIN_OUTPUT_POLARITY(1)); tegra_dc_writel(rgb->dc, value, DC_COM_PIN_OUTPUT_POLARITY(1));
/* XXX: parameterize? */ /* XXX: parameterize? */

View File

@@ -10,6 +10,7 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
@@ -601,6 +602,9 @@ static u8 tegra_clk_sor_pad_get_parent(struct clk_hw *hw)
} }
static const struct clk_ops tegra_clk_sor_pad_ops = { static const struct clk_ops tegra_clk_sor_pad_ops = {
#if defined(NV_CLK_HW_DETERMINE_RATE_NO_REPARENT_PRESENT) /* Linux 6.4 */
.determine_rate = clk_hw_determine_rate_no_reparent,
#endif
.set_parent = tegra_clk_sor_pad_set_parent, .set_parent = tegra_clk_sor_pad_set_parent,
.get_parent = tegra_clk_sor_pad_get_parent, .get_parent = tegra_clk_sor_pad_get_parent,
}; };
@@ -1168,7 +1172,7 @@ static int tegra_sor_compute_config(struct tegra_sor *sor,
struct drm_dp_link *link) struct drm_dp_link *link)
{ {
const u64 f = 100000, link_rate = link->rate * 1000; const u64 f = 100000, link_rate = link->rate * 1000;
const u64 pclk = mode->clock * 1000; const u64 pclk = (u64)mode->clock * 1000;
u64 input, output, watermark, num; u64 input, output, watermark, num;
struct tegra_sor_params params; struct tegra_sor_params params;
u32 num_syms_per_line; u32 num_syms_per_line;
@@ -1726,7 +1730,6 @@ static void tegra_sor_early_unregister(struct drm_connector *connector)
connector->debugfs_entry, connector->debugfs_entry,
connector->dev->primary); connector->dev->primary);
#else #else
drm_debugfs_remove_files(sor->debugfs_files, count, drm_debugfs_remove_files(sor->debugfs_files, count,
connector->dev->primary); connector->dev->primary);
#endif #endif
@@ -3000,11 +3003,9 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
int err; int err;
sor->avdd_io_supply = devm_regulator_get(sor->dev, "avdd-io-hdmi-dp"); sor->avdd_io_supply = devm_regulator_get(sor->dev, "avdd-io-hdmi-dp");
if (IS_ERR(sor->avdd_io_supply)) { if (IS_ERR(sor->avdd_io_supply))
dev_err(sor->dev, "cannot get AVDD I/O supply: %ld\n", return dev_err_probe(sor->dev, PTR_ERR(sor->avdd_io_supply),
PTR_ERR(sor->avdd_io_supply)); "cannot get AVDD I/O supply\n");
return PTR_ERR(sor->avdd_io_supply);
}
err = tegra_sor_enable_regulator(sor, sor->avdd_io_supply); err = tegra_sor_enable_regulator(sor, sor->avdd_io_supply);
if (err < 0) { if (err < 0) {
@@ -3014,11 +3015,9 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
} }
sor->vdd_pll_supply = devm_regulator_get(sor->dev, "vdd-hdmi-dp-pll"); sor->vdd_pll_supply = devm_regulator_get(sor->dev, "vdd-hdmi-dp-pll");
if (IS_ERR(sor->vdd_pll_supply)) { if (IS_ERR(sor->vdd_pll_supply))
dev_err(sor->dev, "cannot get VDD PLL supply: %ld\n", return dev_err_probe(sor->dev, PTR_ERR(sor->vdd_pll_supply),
PTR_ERR(sor->vdd_pll_supply)); "cannot get VDD PLL supply\n");
return PTR_ERR(sor->vdd_pll_supply);
}
err = tegra_sor_enable_regulator(sor, sor->vdd_pll_supply); err = tegra_sor_enable_regulator(sor, sor->vdd_pll_supply);
if (err < 0) { if (err < 0) {
@@ -3028,11 +3027,9 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
} }
sor->hdmi_supply = devm_regulator_get(sor->dev, "hdmi"); sor->hdmi_supply = devm_regulator_get(sor->dev, "hdmi");
if (IS_ERR(sor->hdmi_supply)) { if (IS_ERR(sor->hdmi_supply))
dev_err(sor->dev, "cannot get HDMI supply: %ld\n", return dev_err_probe(sor->dev, PTR_ERR(sor->hdmi_supply),
PTR_ERR(sor->hdmi_supply)); "cannot get HDMI supply\n");
return PTR_ERR(sor->hdmi_supply);
}
err = tegra_sor_enable_regulator(sor, sor->hdmi_supply); err = tegra_sor_enable_regulator(sor, sor->hdmi_supply);
if (err < 0) { if (err < 0) {
@@ -3754,7 +3751,6 @@ static int tegra_sor_probe(struct platform_device *pdev)
{ {
struct device_node *np; struct device_node *np;
struct tegra_sor *sor; struct tegra_sor *sor;
struct resource *regs;
int err; int err;
sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL); sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL);
@@ -3827,8 +3823,7 @@ static int tegra_sor_probe(struct platform_device *pdev)
} }
} }
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); sor->regs = devm_platform_ioremap_resource(pdev, 0);
sor->regs = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(sor->regs)) { if (IS_ERR(sor->regs)) {
err = PTR_ERR(sor->regs); err = PTR_ERR(sor->regs);
goto remove; goto remove;

View File

@@ -175,14 +175,9 @@ static void *alloc_copy_user_array(void __user *from, size_t count, size_t size)
if (copy_len > 0x4000) if (copy_len > 0x4000)
return ERR_PTR(-E2BIG); return ERR_PTR(-E2BIG);
data = kvmalloc(copy_len, GFP_KERNEL); data = vmemdup_user(from, copy_len);
if (!data) if (IS_ERR(data))
return ERR_PTR(-ENOMEM); return ERR_CAST(data);
if (copy_from_user(data, from, copy_len)) {
kvfree(data);
return ERR_PTR(-EFAULT);
}
return data; return data;
} }
@@ -738,21 +733,13 @@ int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
host1x_memory_context_get(job->memory_context); host1x_memory_context_get(job->memory_context);
} }
} else if (context->client->ops->get_streamid_offset) { } else if (context->client->ops->get_streamid_offset) {
#ifdef CONFIG_IOMMU_API
struct iommu_fwspec *spec;
/* /*
* Job submission will need to temporarily change stream ID, * Job submission will need to temporarily change stream ID,
* so need to tell it what to change it back to. * so need to tell it what to change it back to.
*/ */
spec = dev_iommu_fwspec_get(context->client->base.dev); if (!tegra_dev_iommu_get_stream_id(context->client->base.dev,
if (spec && spec->num_ids > 0) &job->engine_fallback_streamid))
job->engine_fallback_streamid = spec->ids[0] & 0xffff; job->engine_fallback_streamid = TEGRA_STREAM_ID_BYPASS;
else
job->engine_fallback_streamid = 0x7f;
#else
job->engine_fallback_streamid = 0x7f;
#endif
} }
/* Boot engine, if necessary. */ /* Boot engine, if necessary. */

View File

@@ -16,7 +16,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_opp.h> #include <linux/pm_opp.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>

View File

@@ -737,6 +737,10 @@ static void host1x_setup_virtualization_tables(struct host1x *host)
static bool host1x_wants_iommu(struct host1x *host1x) static bool host1x_wants_iommu(struct host1x *host1x)
{ {
/* Our IOMMU usage policy doesn't currently play well with GART */
if (of_machine_is_compatible("nvidia,tegra20"))
return false;
/* /*
* If we support addressing a maximum of 32 bits of physical memory * If we support addressing a maximum of 32 bits of physical memory
* and if the host1x firewall is enabled, there's no need to enable * and if the host1x firewall is enabled, there's no need to enable