mirror of https://gitee.com/openkylin/linux.git
drm/tegra: Fixes for v5.13-rc5
The most important change here fixes a race condition that causes either HDA or (more frequently) display to malfunction because they race for enabling the SOR power domain at probe time. Other than that, there's a couple of build warnings for issues introduced in v5.13 as well as some minor fixes, such as reference leak plugs. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEiOrDCAFJzPfAjcif3SOs138+s6EFAmC46msTHHRyZWRpbmdA bnZpZGlhLmNvbQAKCRDdI6zXfz6zocHxEACTS0lR63rULGmYV/+spAC9yOBeLkBQ ElHHt2L9QL3yMLVAsozoPZLQDBszuAepeMYXNtP7H+XjBjxloHi1kn1yS8TNfhRD HZhyTdyUWAuSGvcm/wyk9QWimoQ75/Q+JTooxedtOjFZBTjx18sRjCV9DQwrr6sN iq/RbAVWcrJ5fL80Yh/wY1DegEA+aRrb+Owm3lmXQ1oPJJFL7VpALWrXcb5yGMIL 2utnKFGML3llRYlUAESWd03By64ZvsGxFDQiHHpjEKlG0SpZbosGqYmMjBXKloE3 zXzeJ4dnhkbFdEGLip5qdoLRf4p0Dbm70njBfXXEUu9629FgChGCAbz7rOogLxts OADDtq/n3xaLnhAoSdtQvDgPtPob21+vgKGp8JbdAjdoqvCA+5u+TDfUxPU54/oe FCOPoayHCE3qSY5UMzPrzdkuBpXi+a5VF9HRwsYn09wE0TOncPo4fwyJJqKmUn9r lTwFKrAfrIEk6EXgZUgxPGfROnUrYDrfYZNlyODIj3I/G3LT0wTe4ynNmEi6aQp9 YxEqOkoVrljzBKuQCDjjSg3BEWZmmkP2Zn1IcKreuaK37qcQFgoXAd6PzcQBPsus f8Y1gOXRC6TL+3ZFyoInb7kkceU2VRdQpXpsd+OfcCDUIo2yN+VceVE2pNqiNCzD wWt0TjIPnrw9sA== =K0PC -----END PGP SIGNATURE----- Merge tag 'drm/tegra/for-5.13-rc5' of ssh://git.freedesktop.org/git/tegra/linux into drm-fixes drm/tegra: Fixes for v5.13-rc5 The most important change here fixes a race condition that causes either HDA or (more frequently) display to malfunction because they race for enabling the SOR power domain at probe time. Other than that, there's a couple of build warnings for issues introduced in v5.13 as well as some minor fixes, such as reference leak plugs. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thierry Reding <thierry.reding@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210603144624.788861-1-thierry.reding@gmail.com
This commit is contained in:
commit
37e2f2e800
|
@ -25,7 +25,7 @@
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
/* XXX move to include/uapi/drm/drm_fourcc.h? */
|
/* XXX move to include/uapi/drm/drm_fourcc.h? */
|
||||||
#define DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT BIT(22)
|
#define DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT BIT_ULL(22)
|
||||||
|
|
||||||
struct reset_control;
|
struct reset_control;
|
||||||
|
|
||||||
|
|
|
@ -510,7 +510,7 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
|
||||||
* dGPU sector layout.
|
* dGPU sector layout.
|
||||||
*/
|
*/
|
||||||
if (tegra_plane_state->tiling.sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU)
|
if (tegra_plane_state->tiling.sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU)
|
||||||
base |= BIT(39);
|
base |= BIT_ULL(39);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tegra_plane_writel(p, tegra_plane_state->format, DC_WIN_COLOR_DEPTH);
|
tegra_plane_writel(p, tegra_plane_state->format, DC_WIN_COLOR_DEPTH);
|
||||||
|
|
|
@ -3125,21 +3125,21 @@ static int tegra_sor_init(struct host1x_client *client)
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(sor->dev, "failed to acquire SOR reset: %d\n",
|
dev_err(sor->dev, "failed to acquire SOR reset: %d\n",
|
||||||
err);
|
err);
|
||||||
return err;
|
goto rpm_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = reset_control_assert(sor->rst);
|
err = reset_control_assert(sor->rst);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(sor->dev, "failed to assert SOR reset: %d\n",
|
dev_err(sor->dev, "failed to assert SOR reset: %d\n",
|
||||||
err);
|
err);
|
||||||
return err;
|
goto rpm_put;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = clk_prepare_enable(sor->clk);
|
err = clk_prepare_enable(sor->clk);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(sor->dev, "failed to enable clock: %d\n", err);
|
dev_err(sor->dev, "failed to enable clock: %d\n", err);
|
||||||
return err;
|
goto rpm_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
usleep_range(1000, 3000);
|
usleep_range(1000, 3000);
|
||||||
|
@ -3150,7 +3150,7 @@ static int tegra_sor_init(struct host1x_client *client)
|
||||||
dev_err(sor->dev, "failed to deassert SOR reset: %d\n",
|
dev_err(sor->dev, "failed to deassert SOR reset: %d\n",
|
||||||
err);
|
err);
|
||||||
clk_disable_unprepare(sor->clk);
|
clk_disable_unprepare(sor->clk);
|
||||||
return err;
|
goto rpm_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_control_release(sor->rst);
|
reset_control_release(sor->rst);
|
||||||
|
@ -3171,6 +3171,12 @@ static int tegra_sor_init(struct host1x_client *client)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
rpm_put:
|
||||||
|
if (sor->rst)
|
||||||
|
pm_runtime_put(sor->dev);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tegra_sor_exit(struct host1x_client *client)
|
static int tegra_sor_exit(struct host1x_client *client)
|
||||||
|
@ -3739,12 +3745,8 @@ static int tegra_sor_probe(struct platform_device *pdev)
|
||||||
if (!sor->aux)
|
if (!sor->aux)
|
||||||
return -EPROBE_DEFER;
|
return -EPROBE_DEFER;
|
||||||
|
|
||||||
if (get_device(&sor->aux->ddc.dev)) {
|
if (get_device(sor->aux->dev))
|
||||||
if (try_module_get(sor->aux->ddc.owner))
|
sor->output.ddc = &sor->aux->ddc;
|
||||||
sor->output.ddc = &sor->aux->ddc;
|
|
||||||
else
|
|
||||||
put_device(&sor->aux->ddc.dev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sor->aux) {
|
if (!sor->aux) {
|
||||||
|
@ -3772,12 +3774,13 @@ static int tegra_sor_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
err = tegra_sor_parse_dt(sor);
|
err = tegra_sor_parse_dt(sor);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
goto put_aux;
|
||||||
|
|
||||||
err = tegra_output_probe(&sor->output);
|
err = tegra_output_probe(&sor->output);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
return dev_err_probe(&pdev->dev, err,
|
dev_err_probe(&pdev->dev, err, "failed to probe output\n");
|
||||||
"failed to probe output\n");
|
goto put_aux;
|
||||||
|
}
|
||||||
|
|
||||||
if (sor->ops && sor->ops->probe) {
|
if (sor->ops && sor->ops->probe) {
|
||||||
err = sor->ops->probe(sor);
|
err = sor->ops->probe(sor);
|
||||||
|
@ -3916,17 +3919,10 @@ static int tegra_sor_probe(struct platform_device *pdev)
|
||||||
platform_set_drvdata(pdev, sor);
|
platform_set_drvdata(pdev, sor);
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&sor->client.list);
|
host1x_client_init(&sor->client);
|
||||||
sor->client.ops = &sor_client_ops;
|
sor->client.ops = &sor_client_ops;
|
||||||
sor->client.dev = &pdev->dev;
|
sor->client.dev = &pdev->dev;
|
||||||
|
|
||||||
err = host1x_client_register(&sor->client);
|
|
||||||
if (err < 0) {
|
|
||||||
dev_err(&pdev->dev, "failed to register host1x client: %d\n",
|
|
||||||
err);
|
|
||||||
goto rpm_disable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On Tegra210 and earlier, provide our own implementation for the
|
* On Tegra210 and earlier, provide our own implementation for the
|
||||||
* pad output clock.
|
* pad output clock.
|
||||||
|
@ -3938,13 +3934,13 @@ static int tegra_sor_probe(struct platform_device *pdev)
|
||||||
sor->index);
|
sor->index);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto unregister;
|
goto uninit;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = host1x_client_resume(&sor->client);
|
err = host1x_client_resume(&sor->client);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(sor->dev, "failed to resume: %d\n", err);
|
dev_err(sor->dev, "failed to resume: %d\n", err);
|
||||||
goto unregister;
|
goto uninit;
|
||||||
}
|
}
|
||||||
|
|
||||||
sor->clk_pad = tegra_clk_sor_pad_register(sor, name);
|
sor->clk_pad = tegra_clk_sor_pad_register(sor, name);
|
||||||
|
@ -3955,17 +3951,30 @@ static int tegra_sor_probe(struct platform_device *pdev)
|
||||||
err = PTR_ERR(sor->clk_pad);
|
err = PTR_ERR(sor->clk_pad);
|
||||||
dev_err(sor->dev, "failed to register SOR pad clock: %d\n",
|
dev_err(sor->dev, "failed to register SOR pad clock: %d\n",
|
||||||
err);
|
err);
|
||||||
goto unregister;
|
goto uninit;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = __host1x_client_register(&sor->client);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(&pdev->dev, "failed to register host1x client: %d\n",
|
||||||
|
err);
|
||||||
|
goto uninit;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unregister:
|
uninit:
|
||||||
host1x_client_unregister(&sor->client);
|
host1x_client_exit(&sor->client);
|
||||||
rpm_disable:
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
remove:
|
remove:
|
||||||
|
if (sor->aux)
|
||||||
|
sor->output.ddc = NULL;
|
||||||
|
|
||||||
tegra_output_remove(&sor->output);
|
tegra_output_remove(&sor->output);
|
||||||
|
put_aux:
|
||||||
|
if (sor->aux)
|
||||||
|
put_device(sor->aux->dev);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3983,6 +3992,11 @@ static int tegra_sor_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
|
if (sor->aux) {
|
||||||
|
put_device(sor->aux->dev);
|
||||||
|
sor->output.ddc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
tegra_output_remove(&sor->output);
|
tegra_output_remove(&sor->output);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -735,6 +735,29 @@ void host1x_driver_unregister(struct host1x_driver *driver)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(host1x_driver_unregister);
|
EXPORT_SYMBOL(host1x_driver_unregister);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __host1x_client_init() - initialize a host1x client
|
||||||
|
* @client: host1x client
|
||||||
|
* @key: lock class key for the client-specific mutex
|
||||||
|
*/
|
||||||
|
void __host1x_client_init(struct host1x_client *client, struct lock_class_key *key)
|
||||||
|
{
|
||||||
|
INIT_LIST_HEAD(&client->list);
|
||||||
|
__mutex_init(&client->lock, "host1x client lock", key);
|
||||||
|
client->usecount = 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(__host1x_client_init);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* host1x_client_exit() - uninitialize a host1x client
|
||||||
|
* @client: host1x client
|
||||||
|
*/
|
||||||
|
void host1x_client_exit(struct host1x_client *client)
|
||||||
|
{
|
||||||
|
mutex_destroy(&client->lock);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(host1x_client_exit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __host1x_client_register() - register a host1x client
|
* __host1x_client_register() - register a host1x client
|
||||||
* @client: host1x client
|
* @client: host1x client
|
||||||
|
@ -747,16 +770,11 @@ EXPORT_SYMBOL(host1x_driver_unregister);
|
||||||
* device and call host1x_device_init(), which will in turn call each client's
|
* device and call host1x_device_init(), which will in turn call each client's
|
||||||
* &host1x_client_ops.init implementation.
|
* &host1x_client_ops.init implementation.
|
||||||
*/
|
*/
|
||||||
int __host1x_client_register(struct host1x_client *client,
|
int __host1x_client_register(struct host1x_client *client)
|
||||||
struct lock_class_key *key)
|
|
||||||
{
|
{
|
||||||
struct host1x *host1x;
|
struct host1x *host1x;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&client->list);
|
|
||||||
__mutex_init(&client->lock, "host1x client lock", key);
|
|
||||||
client->usecount = 0;
|
|
||||||
|
|
||||||
mutex_lock(&devices_lock);
|
mutex_lock(&devices_lock);
|
||||||
|
|
||||||
list_for_each_entry(host1x, &devices, list) {
|
list_for_each_entry(host1x, &devices, list) {
|
||||||
|
|
|
@ -332,12 +332,30 @@ static inline struct host1x_device *to_host1x_device(struct device *dev)
|
||||||
int host1x_device_init(struct host1x_device *device);
|
int host1x_device_init(struct host1x_device *device);
|
||||||
int host1x_device_exit(struct host1x_device *device);
|
int host1x_device_exit(struct host1x_device *device);
|
||||||
|
|
||||||
int __host1x_client_register(struct host1x_client *client,
|
void __host1x_client_init(struct host1x_client *client, struct lock_class_key *key);
|
||||||
struct lock_class_key *key);
|
void host1x_client_exit(struct host1x_client *client);
|
||||||
#define host1x_client_register(class) \
|
|
||||||
({ \
|
#define host1x_client_init(client) \
|
||||||
static struct lock_class_key __key; \
|
({ \
|
||||||
__host1x_client_register(class, &__key); \
|
static struct lock_class_key __key; \
|
||||||
|
__host1x_client_init(client, &__key); \
|
||||||
|
})
|
||||||
|
|
||||||
|
int __host1x_client_register(struct host1x_client *client);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that this wrapper calls __host1x_client_init() for compatibility
|
||||||
|
* with existing callers. Callers that want to separately initialize and
|
||||||
|
* register a host1x client must first initialize using either of the
|
||||||
|
* __host1x_client_init() or host1x_client_init() functions and then use
|
||||||
|
* the low-level __host1x_client_register() function to avoid the client
|
||||||
|
* getting reinitialized.
|
||||||
|
*/
|
||||||
|
#define host1x_client_register(client) \
|
||||||
|
({ \
|
||||||
|
static struct lock_class_key __key; \
|
||||||
|
__host1x_client_init(client, &__key); \
|
||||||
|
__host1x_client_register(client); \
|
||||||
})
|
})
|
||||||
|
|
||||||
int host1x_client_unregister(struct host1x_client *client);
|
int host1x_client_unregister(struct host1x_client *client);
|
||||||
|
|
Loading…
Reference in New Issue