Commit 45046af3 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-misc-fixes-2024-02-29' of...

Merge tag 'drm-misc-fixes-2024-02-29' of https://anongit.freedesktop.org/git/drm/drm-misc into drm-fixes

A reset fix for host1x, a resource leak fix and a probe fix for aux-hpd,
a use-after-free fix and a boot fix for a pmic_glink qcom driver in
drivers/soc, a fix for the simpledrm/tegra transition, a kunit fix for
the TTM tests, a font handling fix for fbcon, two allocation fixes and a
kunit test to cover them for drm/buddy
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Maxime Ripard <mripard@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240229-angelic-adorable-teal-fbfabb@houat
parents d206a76d c7070332
...@@ -199,7 +199,7 @@ config DRM_TTM ...@@ -199,7 +199,7 @@ config DRM_TTM
config DRM_TTM_KUNIT_TEST config DRM_TTM_KUNIT_TEST
tristate "KUnit tests for TTM" if !KUNIT_ALL_TESTS tristate "KUnit tests for TTM" if !KUNIT_ALL_TESTS
default n default n
depends on DRM && KUNIT && MMU depends on DRM && KUNIT && MMU && (UML || COMPILE_TEST)
select DRM_TTM select DRM_TTM
select DRM_EXPORT_FOR_TESTS if m select DRM_EXPORT_FOR_TESTS if m
select DRM_KUNIT_TEST_HELPERS select DRM_KUNIT_TEST_HELPERS
...@@ -207,7 +207,8 @@ config DRM_TTM_KUNIT_TEST ...@@ -207,7 +207,8 @@ config DRM_TTM_KUNIT_TEST
help help
Enables unit tests for TTM, a GPU memory manager subsystem used Enables unit tests for TTM, a GPU memory manager subsystem used
to manage memory buffers. This option is mostly useful for kernel to manage memory buffers. This option is mostly useful for kernel
developers. developers. It depends on (UML || COMPILE_TEST) since no other driver
which uses TTM can be loaded while running the tests.
If in doubt, say "N". If in doubt, say "N".
......
...@@ -25,20 +25,18 @@ static void drm_aux_hpd_bridge_release(struct device *dev) ...@@ -25,20 +25,18 @@ static void drm_aux_hpd_bridge_release(struct device *dev)
ida_free(&drm_aux_hpd_bridge_ida, adev->id); ida_free(&drm_aux_hpd_bridge_ida, adev->id);
of_node_put(adev->dev.platform_data); of_node_put(adev->dev.platform_data);
of_node_put(adev->dev.of_node);
kfree(adev); kfree(adev);
} }
static void drm_aux_hpd_bridge_unregister_adev(void *_adev) static void drm_aux_hpd_bridge_free_adev(void *_adev)
{ {
struct auxiliary_device *adev = _adev; auxiliary_device_uninit(_adev);
auxiliary_device_delete(adev);
auxiliary_device_uninit(adev);
} }
/** /**
* drm_dp_hpd_bridge_register - Create a simple HPD DisplayPort bridge * devm_drm_dp_hpd_bridge_alloc - allocate a HPD DisplayPort bridge
* @parent: device instance providing this bridge * @parent: device instance providing this bridge
* @np: device node pointer corresponding to this bridge instance * @np: device node pointer corresponding to this bridge instance
* *
...@@ -46,11 +44,9 @@ static void drm_aux_hpd_bridge_unregister_adev(void *_adev) ...@@ -46,11 +44,9 @@ static void drm_aux_hpd_bridge_unregister_adev(void *_adev)
* DRM_MODE_CONNECTOR_DisplayPort, which terminates the bridge chain and is * DRM_MODE_CONNECTOR_DisplayPort, which terminates the bridge chain and is
* able to send the HPD events. * able to send the HPD events.
* *
* Return: device instance that will handle created bridge or an error code * Return: bridge auxiliary device pointer or an error pointer
* encoded into the pointer.
*/ */
struct device *drm_dp_hpd_bridge_register(struct device *parent, struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent, struct device_node *np)
struct device_node *np)
{ {
struct auxiliary_device *adev; struct auxiliary_device *adev;
int ret; int ret;
...@@ -74,18 +70,62 @@ struct device *drm_dp_hpd_bridge_register(struct device *parent, ...@@ -74,18 +70,62 @@ struct device *drm_dp_hpd_bridge_register(struct device *parent,
ret = auxiliary_device_init(adev); ret = auxiliary_device_init(adev);
if (ret) { if (ret) {
of_node_put(adev->dev.platform_data);
of_node_put(adev->dev.of_node);
ida_free(&drm_aux_hpd_bridge_ida, adev->id); ida_free(&drm_aux_hpd_bridge_ida, adev->id);
kfree(adev); kfree(adev);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
ret = auxiliary_device_add(adev); ret = devm_add_action_or_reset(parent, drm_aux_hpd_bridge_free_adev, adev);
if (ret) { if (ret)
auxiliary_device_uninit(adev);
return ERR_PTR(ret); return ERR_PTR(ret);
}
ret = devm_add_action_or_reset(parent, drm_aux_hpd_bridge_unregister_adev, adev); return adev;
}
EXPORT_SYMBOL_GPL(devm_drm_dp_hpd_bridge_alloc);
static void drm_aux_hpd_bridge_del_adev(void *_adev)
{
auxiliary_device_delete(_adev);
}
/**
* devm_drm_dp_hpd_bridge_add - register a HDP DisplayPort bridge
* @dev: struct device to tie registration lifetime to
* @adev: bridge auxiliary device to be registered
*
* Returns: zero on success or a negative errno
*/
int devm_drm_dp_hpd_bridge_add(struct device *dev, struct auxiliary_device *adev)
{
int ret;
ret = auxiliary_device_add(adev);
if (ret)
return ret;
return devm_add_action_or_reset(dev, drm_aux_hpd_bridge_del_adev, adev);
}
EXPORT_SYMBOL_GPL(devm_drm_dp_hpd_bridge_add);
/**
* drm_dp_hpd_bridge_register - allocate and register a HDP DisplayPort bridge
* @parent: device instance providing this bridge
* @np: device node pointer corresponding to this bridge instance
*
* Return: device instance that will handle created bridge or an error pointer
*/
struct device *drm_dp_hpd_bridge_register(struct device *parent, struct device_node *np)
{
struct auxiliary_device *adev;
int ret;
adev = devm_drm_dp_hpd_bridge_alloc(parent, np);
if (IS_ERR(adev))
return ERR_CAST(adev);
ret = devm_drm_dp_hpd_bridge_add(parent, adev);
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
......
...@@ -332,6 +332,7 @@ alloc_range_bias(struct drm_buddy *mm, ...@@ -332,6 +332,7 @@ alloc_range_bias(struct drm_buddy *mm,
u64 start, u64 end, u64 start, u64 end,
unsigned int order) unsigned int order)
{ {
u64 req_size = mm->chunk_size << order;
struct drm_buddy_block *block; struct drm_buddy_block *block;
struct drm_buddy_block *buddy; struct drm_buddy_block *buddy;
LIST_HEAD(dfs); LIST_HEAD(dfs);
...@@ -367,6 +368,15 @@ alloc_range_bias(struct drm_buddy *mm, ...@@ -367,6 +368,15 @@ alloc_range_bias(struct drm_buddy *mm,
if (drm_buddy_block_is_allocated(block)) if (drm_buddy_block_is_allocated(block))
continue; continue;
if (block_start < start || block_end > end) {
u64 adjusted_start = max(block_start, start);
u64 adjusted_end = min(block_end, end);
if (round_down(adjusted_end + 1, req_size) <=
round_up(adjusted_start, req_size))
continue;
}
if (contains(start, end, block_start, block_end) && if (contains(start, end, block_start, block_end) &&
order == drm_buddy_block_order(block)) { order == drm_buddy_block_order(block)) {
/* /*
...@@ -761,8 +771,12 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, ...@@ -761,8 +771,12 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm,
return -EINVAL; return -EINVAL;
/* Actual range allocation */ /* Actual range allocation */
if (start + size == end) if (start + size == end) {
if (!IS_ALIGNED(start | end, min_block_size))
return -EINVAL;
return __drm_buddy_alloc_range(mm, start, size, NULL, blocks); return __drm_buddy_alloc_range(mm, start, size, NULL, blocks);
}
original_size = size; original_size = size;
original_min_size = min_block_size; original_min_size = min_block_size;
......
...@@ -1243,9 +1243,26 @@ static int host1x_drm_probe(struct host1x_device *dev) ...@@ -1243,9 +1243,26 @@ static int host1x_drm_probe(struct host1x_device *dev)
drm_mode_config_reset(drm); drm_mode_config_reset(drm);
err = drm_aperture_remove_framebuffers(&tegra_drm_driver); /*
if (err < 0) * Only take over from a potential firmware framebuffer if any CRTCs
goto hub; * 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) {
err = drm_aperture_remove_framebuffers(&tegra_drm_driver);
if (err < 0)
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);
if (err < 0) if (err < 0)
......
...@@ -14,11 +14,216 @@ ...@@ -14,11 +14,216 @@
#include "../lib/drm_random.h" #include "../lib/drm_random.h"
static unsigned int random_seed;
static inline u64 get_size(int order, u64 chunk_size) static inline u64 get_size(int order, u64 chunk_size)
{ {
return (1 << order) * chunk_size; return (1 << order) * chunk_size;
} }
static void drm_test_buddy_alloc_range_bias(struct kunit *test)
{
u32 mm_size, ps, bias_size, bias_start, bias_end, bias_rem;
DRM_RND_STATE(prng, random_seed);
unsigned int i, count, *order;
struct drm_buddy mm;
LIST_HEAD(allocated);
bias_size = SZ_1M;
ps = roundup_pow_of_two(prandom_u32_state(&prng) % bias_size);
ps = max(SZ_4K, ps);
mm_size = (SZ_8M-1) & ~(ps-1); /* Multiple roots */
kunit_info(test, "mm_size=%u, ps=%u\n", mm_size, ps);
KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, ps),
"buddy_init failed\n");
count = mm_size / bias_size;
order = drm_random_order(count, &prng);
KUNIT_EXPECT_TRUE(test, order);
/*
* Idea is to split the address space into uniform bias ranges, and then
* in some random order allocate within each bias, using various
* patterns within. This should detect if allocations leak out from a
* given bias, for example.
*/
for (i = 0; i < count; i++) {
LIST_HEAD(tmp);
u32 size;
bias_start = order[i] * bias_size;
bias_end = bias_start + bias_size;
bias_rem = bias_size;
/* internal round_up too big */
KUNIT_ASSERT_TRUE_MSG(test,
drm_buddy_alloc_blocks(&mm, bias_start,
bias_end, bias_size + ps, bias_size,
&allocated,
DRM_BUDDY_RANGE_ALLOCATION),
"buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
bias_start, bias_end, bias_size, bias_size);
/* size too big */
KUNIT_ASSERT_TRUE_MSG(test,
drm_buddy_alloc_blocks(&mm, bias_start,
bias_end, bias_size + ps, ps,
&allocated,
DRM_BUDDY_RANGE_ALLOCATION),
"buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
bias_start, bias_end, bias_size + ps, ps);
/* bias range too small for size */
KUNIT_ASSERT_TRUE_MSG(test,
drm_buddy_alloc_blocks(&mm, bias_start + ps,
bias_end, bias_size, ps,
&allocated,
DRM_BUDDY_RANGE_ALLOCATION),
"buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
bias_start + ps, bias_end, bias_size, ps);
/* bias misaligned */
KUNIT_ASSERT_TRUE_MSG(test,
drm_buddy_alloc_blocks(&mm, bias_start + ps,
bias_end - ps,
bias_size >> 1, bias_size >> 1,
&allocated,
DRM_BUDDY_RANGE_ALLOCATION),
"buddy_alloc h didn't fail with bias(%x-%x), size=%u, ps=%u\n",
bias_start + ps, bias_end - ps, bias_size >> 1, bias_size >> 1);
/* single big page */
KUNIT_ASSERT_FALSE_MSG(test,
drm_buddy_alloc_blocks(&mm, bias_start,
bias_end, bias_size, bias_size,
&tmp,
DRM_BUDDY_RANGE_ALLOCATION),
"buddy_alloc i failed with bias(%x-%x), size=%u, ps=%u\n",
bias_start, bias_end, bias_size, bias_size);
drm_buddy_free_list(&mm, &tmp);
/* single page with internal round_up */
KUNIT_ASSERT_FALSE_MSG(test,
drm_buddy_alloc_blocks(&mm, bias_start,
bias_end, ps, bias_size,
&tmp,
DRM_BUDDY_RANGE_ALLOCATION),
"buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
bias_start, bias_end, ps, bias_size);
drm_buddy_free_list(&mm, &tmp);
/* random size within */
size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
if (size)
KUNIT_ASSERT_FALSE_MSG(test,
drm_buddy_alloc_blocks(&mm, bias_start,
bias_end, size, ps,
&tmp,
DRM_BUDDY_RANGE_ALLOCATION),
"buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
bias_start, bias_end, size, ps);
bias_rem -= size;
/* too big for current avail */
KUNIT_ASSERT_TRUE_MSG(test,
drm_buddy_alloc_blocks(&mm, bias_start,
bias_end, bias_rem + ps, ps,
&allocated,
DRM_BUDDY_RANGE_ALLOCATION),
"buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
bias_start, bias_end, bias_rem + ps, ps);
if (bias_rem) {
/* random fill of the remainder */
size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
size = max(size, ps);
KUNIT_ASSERT_FALSE_MSG(test,
drm_buddy_alloc_blocks(&mm, bias_start,
bias_end, size, ps,
&allocated,
DRM_BUDDY_RANGE_ALLOCATION),
"buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
bias_start, bias_end, size, ps);
/*
* Intentionally allow some space to be left
* unallocated, and ideally not always on the bias
* boundaries.
*/
drm_buddy_free_list(&mm, &tmp);
} else {
list_splice_tail(&tmp, &allocated);
}
}
kfree(order);
drm_buddy_free_list(&mm, &allocated);
drm_buddy_fini(&mm);
/*
* Something more free-form. Idea is to pick a random starting bias
* range within the address space and then start filling it up. Also
* randomly grow the bias range in both directions as we go along. This
* should give us bias start/end which is not always uniform like above,
* and in some cases will require the allocator to jump over already
* allocated nodes in the middle of the address space.
*/
KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, ps),
"buddy_init failed\n");
bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps);
bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps);
bias_end = max(bias_end, bias_start + ps);
bias_rem = bias_end - bias_start;
do {
u32 size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
KUNIT_ASSERT_FALSE_MSG(test,
drm_buddy_alloc_blocks(&mm, bias_start,
bias_end, size, ps,
&allocated,
DRM_BUDDY_RANGE_ALLOCATION),
"buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
bias_start, bias_end, size);
bias_rem -= size;
/*
* Try to randomly grow the bias range in both directions, or
* only one, or perhaps don't grow at all.
*/
do {
u32 old_bias_start = bias_start;
u32 old_bias_end = bias_end;
if (bias_start)
bias_start -= round_up(prandom_u32_state(&prng) % bias_start, ps);
if (bias_end != mm_size)
bias_end += round_up(prandom_u32_state(&prng) % (mm_size - bias_end), ps);
bias_rem += old_bias_start - bias_start;
bias_rem += bias_end - old_bias_end;
} while (!bias_rem && (bias_start || bias_end != mm_size));
} while (bias_rem);
KUNIT_ASSERT_EQ(test, bias_start, 0);
KUNIT_ASSERT_EQ(test, bias_end, mm_size);
KUNIT_ASSERT_TRUE_MSG(test,
drm_buddy_alloc_blocks(&mm, bias_start, bias_end,
ps, ps,
&allocated,
DRM_BUDDY_RANGE_ALLOCATION),
"buddy_alloc passed with bias(%x-%x), size=%u\n",
bias_start, bias_end, ps);
drm_buddy_free_list(&mm, &allocated);
drm_buddy_fini(&mm);
}
static void drm_test_buddy_alloc_contiguous(struct kunit *test) static void drm_test_buddy_alloc_contiguous(struct kunit *test)
{ {
const unsigned long ps = SZ_4K, mm_size = 16 * 3 * SZ_4K; const unsigned long ps = SZ_4K, mm_size = 16 * 3 * SZ_4K;
...@@ -362,17 +567,30 @@ static void drm_test_buddy_alloc_limit(struct kunit *test) ...@@ -362,17 +567,30 @@ static void drm_test_buddy_alloc_limit(struct kunit *test)
drm_buddy_fini(&mm); drm_buddy_fini(&mm);
} }
static int drm_buddy_suite_init(struct kunit_suite *suite)
{
while (!random_seed)
random_seed = get_random_u32();
kunit_info(suite, "Testing DRM buddy manager, with random_seed=0x%x\n",
random_seed);
return 0;
}
static struct kunit_case drm_buddy_tests[] = { static struct kunit_case drm_buddy_tests[] = {
KUNIT_CASE(drm_test_buddy_alloc_limit), KUNIT_CASE(drm_test_buddy_alloc_limit),
KUNIT_CASE(drm_test_buddy_alloc_optimistic), KUNIT_CASE(drm_test_buddy_alloc_optimistic),
KUNIT_CASE(drm_test_buddy_alloc_pessimistic), KUNIT_CASE(drm_test_buddy_alloc_pessimistic),
KUNIT_CASE(drm_test_buddy_alloc_pathological), KUNIT_CASE(drm_test_buddy_alloc_pathological),
KUNIT_CASE(drm_test_buddy_alloc_contiguous), KUNIT_CASE(drm_test_buddy_alloc_contiguous),
KUNIT_CASE(drm_test_buddy_alloc_range_bias),
{} {}
}; };
static struct kunit_suite drm_buddy_test_suite = { static struct kunit_suite drm_buddy_test_suite = {
.name = "drm_buddy", .name = "drm_buddy",
.suite_init = drm_buddy_suite_init,
.test_cases = drm_buddy_tests, .test_cases = drm_buddy_tests,
}; };
......
...@@ -169,6 +169,7 @@ static const struct host1x_info host1x06_info = { ...@@ -169,6 +169,7 @@ static const struct host1x_info host1x06_info = {
.num_sid_entries = ARRAY_SIZE(tegra186_sid_table), .num_sid_entries = ARRAY_SIZE(tegra186_sid_table),
.sid_table = tegra186_sid_table, .sid_table = tegra186_sid_table,
.reserve_vblank_syncpts = false, .reserve_vblank_syncpts = false,
.skip_reset_assert = true,
}; };
static const struct host1x_sid_entry tegra194_sid_table[] = { static const struct host1x_sid_entry tegra194_sid_table[] = {
...@@ -680,13 +681,15 @@ static int __maybe_unused host1x_runtime_suspend(struct device *dev) ...@@ -680,13 +681,15 @@ static int __maybe_unused host1x_runtime_suspend(struct device *dev)
host1x_intr_stop(host); host1x_intr_stop(host);
host1x_syncpt_save(host); host1x_syncpt_save(host);
err = reset_control_bulk_assert(host->nresets, host->resets); if (!host->info->skip_reset_assert) {
if (err) { err = reset_control_bulk_assert(host->nresets, host->resets);
dev_err(dev, "failed to assert reset: %d\n", err); if (err) {
goto resume_host1x; dev_err(dev, "failed to assert reset: %d\n", err);
} goto resume_host1x;
}
usleep_range(1000, 2000); usleep_range(1000, 2000);
}
clk_disable_unprepare(host->clk); clk_disable_unprepare(host->clk);
reset_control_bulk_release(host->nresets, host->resets); reset_control_bulk_release(host->nresets, host->resets);
......
...@@ -116,6 +116,12 @@ struct host1x_info { ...@@ -116,6 +116,12 @@ struct host1x_info {
* the display driver disables VBLANK increments. * the display driver disables VBLANK increments.
*/ */
bool reserve_vblank_syncpts; bool reserve_vblank_syncpts;
/*
* On Tegra186, secure world applications may require access to
* host1x during suspend/resume. To allow this, we need to leave
* host1x not in reset.
*/
bool skip_reset_assert;
}; };
struct host1x { struct host1x {
......
...@@ -265,10 +265,17 @@ static int pmic_glink_probe(struct platform_device *pdev) ...@@ -265,10 +265,17 @@ static int pmic_glink_probe(struct platform_device *pdev)
pg->client_mask = *match_data; pg->client_mask = *match_data;
pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg);
if (IS_ERR(pg->pdr)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr),
"failed to initialize pdr\n");
return ret;
}
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) { if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) {
ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi"); ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi");
if (ret) if (ret)
return ret; goto out_release_pdr_handle;
} }
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) { if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) {
ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode"); ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode");
...@@ -281,17 +288,11 @@ static int pmic_glink_probe(struct platform_device *pdev) ...@@ -281,17 +288,11 @@ static int pmic_glink_probe(struct platform_device *pdev)
goto out_release_altmode_aux; goto out_release_altmode_aux;
} }
pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg);
if (IS_ERR(pg->pdr)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr), "failed to initialize pdr\n");
goto out_release_aux_devices;
}
service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd"); service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd");
if (IS_ERR(service)) { if (IS_ERR(service)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(service), ret = dev_err_probe(&pdev->dev, PTR_ERR(service),
"failed adding pdr lookup for charger_pd\n"); "failed adding pdr lookup for charger_pd\n");
goto out_release_pdr_handle; goto out_release_aux_devices;
} }
mutex_lock(&__pmic_glink_lock); mutex_lock(&__pmic_glink_lock);
...@@ -300,8 +301,6 @@ static int pmic_glink_probe(struct platform_device *pdev) ...@@ -300,8 +301,6 @@ static int pmic_glink_probe(struct platform_device *pdev)
return 0; return 0;
out_release_pdr_handle:
pdr_handle_release(pg->pdr);
out_release_aux_devices: out_release_aux_devices:
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
pmic_glink_del_aux_device(pg, &pg->ps_aux); pmic_glink_del_aux_device(pg, &pg->ps_aux);
...@@ -311,6 +310,8 @@ static int pmic_glink_probe(struct platform_device *pdev) ...@@ -311,6 +310,8 @@ static int pmic_glink_probe(struct platform_device *pdev)
out_release_ucsi_aux: out_release_ucsi_aux:
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
pmic_glink_del_aux_device(pg, &pg->ucsi_aux); pmic_glink_del_aux_device(pg, &pg->ucsi_aux);
out_release_pdr_handle:
pdr_handle_release(pg->pdr);
return ret; return ret;
} }
......
...@@ -76,7 +76,7 @@ struct pmic_glink_altmode_port { ...@@ -76,7 +76,7 @@ struct pmic_glink_altmode_port {
struct work_struct work; struct work_struct work;
struct device *bridge; struct auxiliary_device *bridge;
enum typec_orientation orientation; enum typec_orientation orientation;
u16 svid; u16 svid;
...@@ -230,7 +230,7 @@ static void pmic_glink_altmode_worker(struct work_struct *work) ...@@ -230,7 +230,7 @@ static void pmic_glink_altmode_worker(struct work_struct *work)
else else
pmic_glink_altmode_enable_usb(altmode, alt_port); pmic_glink_altmode_enable_usb(altmode, alt_port);
drm_aux_hpd_bridge_notify(alt_port->bridge, drm_aux_hpd_bridge_notify(&alt_port->bridge->dev,
alt_port->hpd_state ? alt_port->hpd_state ?
connector_status_connected : connector_status_connected :
connector_status_disconnected); connector_status_disconnected);
...@@ -454,7 +454,7 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev, ...@@ -454,7 +454,7 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
alt_port->index = port; alt_port->index = port;
INIT_WORK(&alt_port->work, pmic_glink_altmode_worker); INIT_WORK(&alt_port->work, pmic_glink_altmode_worker);
alt_port->bridge = drm_dp_hpd_bridge_register(dev, to_of_node(fwnode)); alt_port->bridge = devm_drm_dp_hpd_bridge_alloc(dev, to_of_node(fwnode));
if (IS_ERR(alt_port->bridge)) { if (IS_ERR(alt_port->bridge)) {
fwnode_handle_put(fwnode); fwnode_handle_put(fwnode);
return PTR_ERR(alt_port->bridge); return PTR_ERR(alt_port->bridge);
...@@ -510,6 +510,16 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev, ...@@ -510,6 +510,16 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
} }
} }
for (port = 0; port < ARRAY_SIZE(altmode->ports); port++) {
alt_port = &altmode->ports[port];
if (!alt_port->bridge)
continue;
ret = devm_drm_dp_hpd_bridge_add(dev, alt_port->bridge);
if (ret)
return ret;
}
altmode->client = devm_pmic_glink_register_client(dev, altmode->client = devm_pmic_glink_register_client(dev,
altmode->owner_id, altmode->owner_id,
pmic_glink_altmode_callback, pmic_glink_altmode_callback,
......
...@@ -2399,11 +2399,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount, ...@@ -2399,11 +2399,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
struct fbcon_display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
int resize, ret, old_userfont, old_width, old_height, old_charcount; int resize, ret, old_userfont, old_width, old_height, old_charcount;
char *old_data = NULL; u8 *old_data = vc->vc_font.data;
resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
if (p->userfont)
old_data = vc->vc_font.data;
vc->vc_font.data = (void *)(p->fontdata = data); vc->vc_font.data = (void *)(p->fontdata = data);
old_userfont = p->userfont; old_userfont = p->userfont;
if ((p->userfont = userfont)) if ((p->userfont = userfont))
...@@ -2437,13 +2435,13 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount, ...@@ -2437,13 +2435,13 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
update_screen(vc); update_screen(vc);
} }
if (old_data && (--REFCOUNT(old_data) == 0)) if (old_userfont && (--REFCOUNT(old_data) == 0))
kfree(old_data - FONT_EXTRA_WORDS * sizeof(int)); kfree(old_data - FONT_EXTRA_WORDS * sizeof(int));
return 0; return 0;
err_out: err_out:
p->fontdata = old_data; p->fontdata = old_data;
vc->vc_font.data = (void *)old_data; vc->vc_font.data = old_data;
if (userfont) { if (userfont) {
p->userfont = old_userfont; p->userfont = old_userfont;
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include <drm/drm_connector.h> #include <drm/drm_connector.h>
struct auxiliary_device;
#if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE) #if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE)
int drm_aux_bridge_register(struct device *parent); int drm_aux_bridge_register(struct device *parent);
#else #else
...@@ -19,10 +21,23 @@ static inline int drm_aux_bridge_register(struct device *parent) ...@@ -19,10 +21,23 @@ static inline int drm_aux_bridge_register(struct device *parent)
#endif #endif
#if IS_ENABLED(CONFIG_DRM_AUX_HPD_BRIDGE) #if IS_ENABLED(CONFIG_DRM_AUX_HPD_BRIDGE)
struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent, struct device_node *np);
int devm_drm_dp_hpd_bridge_add(struct device *dev, struct auxiliary_device *adev);
struct device *drm_dp_hpd_bridge_register(struct device *parent, struct device *drm_dp_hpd_bridge_register(struct device *parent,
struct device_node *np); struct device_node *np);
void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status); void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status);
#else #else
static inline struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent,
struct device_node *np)
{
return NULL;
}
static inline int devm_drm_dp_hpd_bridge_add(struct auxiliary_device *adev)
{
return 0;
}
static inline struct device *drm_dp_hpd_bridge_register(struct device *parent, static inline struct device *drm_dp_hpd_bridge_register(struct device *parent,
struct device_node *np) struct device_node *np)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment