Files
linux-nv-oot/drivers/platform/tegra/dce/dce-module.c
Jon Hunter 74c0a6d16d drivers: Drop inline from driver remove wrapper
The driver remove function is a function pointer and therefore, it does
not make sense to define the function as an 'inline'. Update the
coccinelle script and drivers to remove the inline statement.

Bug 4749580

Change-Id: Ia03691b75c4edffe609f27468b911a92a5ddbd68
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3233980
(cherry picked from commit 2c3a31c9b72785ee35ad079422b624f59a35f622)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3276870
Reviewed-by: Brad Griffis <bgriffis@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
2025-01-06 06:09:10 -08:00

338 lines
7.3 KiB
C

// SPDX-FileCopyrightText: Copyright (c) 2019-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0-only
#include <nvidia/conftest.h>
#include <dce.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/device.h>
/**
* The following platform info is needed for backdoor
* booting of dce.
*/
static const struct dce_platform_data t234_dce_platform_data = {
.stream_id = 0x08,
.phys_stream_id = 0x7f,
.fw_carveout_id = 9,
.hsp_id = 0x0,
.fw_vmindex = 0,
.fw_name = "display-t234-dce.bin",
.fw_dce_addr = 0x40000000,
.fw_info_valid = true,
.use_physical_id = false,
};
__weak const struct of_device_id tegra_dce_of_match[] = {
{
.compatible = "nvidia,tegra234-dce",
.data = (struct dce_platform_data *)&t234_dce_platform_data
},
{ },
};
MODULE_DEVICE_TABLE(of, tegra_dce_of_match);
/**
* dce_get_pdata_dce - inline function to get the tegra_dce pointer
* from platform devicve.
*
* @pdev : Pointer to the platform device data structure.
*
* Return : Pointer pointing to tegra_dce data structure.
*/
static inline struct tegra_dce *dce_get_pdata_dce(struct platform_device *pdev)
{
return (&((struct dce_device *)dev_get_drvdata(&pdev->dev))->d);
}
/**
* dce_get_tegra_dce_from_dev - inline function to get the tegra_dce pointer
* from devicve struct.
*
* @pdev : Pointer to the device data structure.
*
* Return : Pointer pointing to tegra_dce data structure.
*/
static inline struct tegra_dce *dce_get_tegra_dce_from_dev(struct device *dev)
{
return (&((struct dce_device *)dev_get_drvdata(dev))->d);
}
/**
* dce_init_dev_data - Function to initialize the dce device data structure.
*
* @pdev : Pointer to Linux's platform device used for registering DCE.
*
* Primarily used during initialization sequence and is expected to be called
* from probe only.
*
* Return : 0 if success else the corresponding error value.
*/
static int dce_init_dev_data(struct platform_device *pdev, struct dce_platform_data *pdata)
{
struct device *dev = &pdev->dev;
struct dce_device *d_dev = NULL;
d_dev = devm_kzalloc(dev, sizeof(*d_dev), GFP_KERNEL);
if (!d_dev)
return -ENOMEM;
d_dev->dev = dev;
d_dev->pdata = pdata;
d_dev->regs = of_iomap(dev->of_node, 0);
if (!d_dev->regs) {
dev_err(dev, "failed to map dce cluster IO space\n");
return -EINVAL;
}
dev_set_drvdata(dev, d_dev);
return 0;
}
/**
* dce_isr - Handles dce interrupts
*/
static irqreturn_t dce_isr(int irq, void *data)
{
struct tegra_dce *d = data;
dce_mailbox_isr(d);
return IRQ_HANDLED;
}
static void dce_set_irqs(struct platform_device *pdev, bool en)
{
int i = 0;
struct tegra_dce *d;
struct dce_device *d_dev = NULL;
d_dev = dev_get_drvdata(&pdev->dev);
d = dce_get_pdata_dce(pdev);
for (i = 0; i < d_dev->max_cpu_irqs; i++) {
if (en)
enable_irq(d->irq[i]);
else
disable_irq(d->irq[i]);
}
}
/**
* dce_req_interrupts - function to initialize CPU irqs for DCE cpu driver.
*
* @pdev : Pointet to Dce Linux Platform Device.
*
* Return : 0 if success else the corresponding error value.
*/
static int dce_req_interrupts(struct platform_device *pdev)
{
int i = 0;
int ret = 0;
int no_ints = 0;
struct tegra_dce *d;
struct dce_device *d_dev = NULL;
d_dev = dev_get_drvdata(&pdev->dev);
d = dce_get_pdata_dce(pdev);
no_ints = platform_irq_count(pdev);
if (no_ints == 0) {
dev_err(&pdev->dev,
"Invalid number of interrupts configured = %d",
no_ints);
return -EINVAL;
}
d_dev->max_cpu_irqs = no_ints;
for (i = 0; i < no_ints; i++) {
ret = platform_get_irq(pdev, i);
if (ret < 0) {
dev_err(&pdev->dev,
"Getting dce intr lines failed with ret = %d",
ret);
return ret;
}
d->irq[i] = ret;
ret = devm_request_threaded_irq(&pdev->dev, d->irq[i],
NULL, dce_isr, IRQF_ONESHOT, "tegra_dce_isr",
d);
if (ret) {
dev_err(&pdev->dev,
"failed to request irq @ with ret = %d\n",
ret);
}
disable_irq(d->irq[i]);
}
return ret;
}
static int match_display_dev(struct device *dev, const void *data)
{
if ((dev != NULL) && (dev->of_node != NULL)) {
if (of_device_is_compatible(dev->of_node, "nvidia,tegra234-display"))
return 1;
}
return 0;
}
static int tegra_dce_probe(struct platform_device *pdev)
{
int err = 0;
struct tegra_dce *d = NULL;
struct device *dev = &pdev->dev;
struct dce_platform_data *pdata = NULL;
const struct of_device_id *match = NULL;
struct device *c_dev;
struct device_link *link;
match = of_match_device(tegra_dce_of_match, dev);
if (!match) {
dev_info(dev, "no device match found\n");
return -ENODEV;
}
pdata = (struct dce_platform_data *)match->data;
WARN_ON(!pdata);
if (!pdata) {
dev_info(dev, "no platform data\n");
err = -ENODATA;
goto err_get_pdata;
}
err = dce_init_dev_data(pdev, pdata);
if (err) {
dev_err(dev, "failed to init device data with err = %d\n",
err);
goto os_init_err;
}
err = dce_req_interrupts(pdev);
if (err) {
dev_err(dev, "failed to get interrupts with err = %d\n",
err);
goto req_intr_err;
}
d = dce_get_pdata_dce(pdev);
/**
* TODO: Get HSP_ID from DT
*/
d->hsp_id = pdata->hsp_id;
err = dce_driver_init(d);
if (err) {
dce_err(d, "DCE Driver Init Failed");
goto err_driver_init;
}
dce_set_irqs(pdev, true);
#ifdef CONFIG_DEBUG_FS
dce_init_debug(d);
#endif
c_dev = bus_find_device(&platform_bus_type, NULL, NULL, match_display_dev);
if (c_dev != NULL) {
dce_info(d, "Found display consumer device");
link = device_link_add(c_dev, dev,
DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER);
if (link == NULL) {
dce_err(d, "Failed to create device link to %s\n", dev_name(c_dev));
return -EINVAL;
}
}
/**
* FIXME: Allow tegra_dce.ko unloading.
*/
if (!try_module_get(THIS_MODULE)) {
dce_info(d, "Failed to get lock of DCE Module.\n");
dce_info(d, "modprobe --remove of kernel modules depending on tegra_dce.ko will fail.\n");
}
return 0;
req_intr_err:
os_init_err:
err_get_pdata:
err_driver_init:
return err;
}
static int tegra_dce_remove(struct platform_device *pdev)
{
/* TODO */
struct tegra_dce *d =
dce_get_pdata_dce(pdev);
#ifdef CONFIG_DEBUG_FS
dce_remove_debug(d);
#endif
dce_set_irqs(pdev, false);
dce_driver_deinit(d);
return 0;
}
#ifdef CONFIG_PM
static int dce_pm_suspend(struct device *dev)
{
struct tegra_dce *d = dce_get_tegra_dce_from_dev(dev);
return dce_pm_enter_sc7(d);
}
static int dce_pm_resume(struct device *dev)
{
struct tegra_dce *d = dce_get_tegra_dce_from_dev(dev);
return dce_pm_exit_sc7(d);
}
static const struct dev_pm_ops dce_pm_ops = {
.suspend = dce_pm_suspend,
.resume = dce_pm_resume,
};
#endif
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_dce_remove_wrapper(struct platform_device *pdev)
{
tegra_dce_remove(pdev);
}
#else
static int tegra_dce_remove_wrapper(struct platform_device *pdev)
{
return tegra_dce_remove(pdev);
}
#endif
static struct platform_driver tegra_dce_driver = {
.driver = {
.name = "tegra-dce",
.of_match_table =
of_match_ptr(tegra_dce_of_match),
#ifdef CONFIG_PM
.pm = &dce_pm_ops,
#endif
},
.probe = tegra_dce_probe,
.remove = tegra_dce_remove_wrapper,
};
module_platform_driver(tegra_dce_driver);
MODULE_DESCRIPTION("DCE Linux driver");
MODULE_AUTHOR("NVIDIA");
MODULE_LICENSE("GPL v2");