mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
Merge d7067ecdbabb73f68a6c3410cbe11a545a9359eb on remote branch
Change-Id: Iea5f2b0cf8f85a62b8d8b486895e28a8b2372a91
This commit is contained in:
commit
d97685e68a
@ -477,16 +477,21 @@
|
||||
ccw_timeout_log [S390]
|
||||
See Documentation/s390/CommonIO for details.
|
||||
|
||||
cgroup_disable= [KNL] Disable a particular controller
|
||||
Format: {name of the controller(s) to disable}
|
||||
cgroup_disable= [KNL] Disable a particular controller or optional feature
|
||||
Format: {name of the controller(s) or feature(s) to disable}
|
||||
The effects of cgroup_disable=foo are:
|
||||
- foo isn't auto-mounted if you mount all cgroups in
|
||||
a single hierarchy
|
||||
- foo isn't visible as an individually mountable
|
||||
subsystem
|
||||
- if foo is an optional feature then the feature is
|
||||
disabled and corresponding cgroup files are not
|
||||
created
|
||||
{Currently only "memory" controller deal with this and
|
||||
cut the overhead, others just disable the usage. So
|
||||
only cgroup_disable=memory is actually worthy}
|
||||
Specifying "pressure" disables per-cgroup pressure
|
||||
stall information accounting feature
|
||||
|
||||
cgroup_no_v1= [KNL] Disable one, multiple, all cgroup controllers in v1
|
||||
Format: { controller[,controller...] | "all" }
|
||||
|
@ -68,6 +68,8 @@ CONFIG_ZSMALLOC=y
|
||||
CONFIG_BALANCE_ANON_FILE_RECLAIM=y
|
||||
CONFIG_SECCOMP=y
|
||||
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
|
||||
CONFIG_CMDLINE="cgroup_disable=pressure"
|
||||
CONFIG_CMDLINE_EXTEND=y
|
||||
CONFIG_CPU_FREQ_TIMES=y
|
||||
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
|
2
arch/arm/configs/vendor/trinket_defconfig
vendored
2
arch/arm/configs/vendor/trinket_defconfig
vendored
@ -72,6 +72,8 @@ CONFIG_ZSMALLOC=y
|
||||
CONFIG_BALANCE_ANON_FILE_RECLAIM=y
|
||||
CONFIG_SECCOMP=y
|
||||
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
|
||||
CONFIG_CMDLINE="cgroup_disable=pressure"
|
||||
CONFIG_CMDLINE_EXTEND=y
|
||||
CONFIG_CPU_FREQ_TIMES=y
|
||||
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
|
@ -21,6 +21,12 @@
|
||||
qcom,ion-heap-type = "SYSTEM";
|
||||
};
|
||||
|
||||
qcom,ion-heap@26 { /* USER CONTIG HEAP */
|
||||
reg = <26>;
|
||||
memory-region = <&user_contig_mem>;
|
||||
qcom,ion-heap-type = "DMA";
|
||||
};
|
||||
|
||||
qcom,ion-heap@27 { /* QSEECOM HEAP */
|
||||
reg = <27>;
|
||||
memory-region = <&qseecom_mem>;
|
||||
|
@ -507,7 +507,13 @@
|
||||
no-map;
|
||||
reg = <0 0x5e400000 0 0x1400000>;
|
||||
};
|
||||
|
||||
user_contig_mem: user_contig_region {
|
||||
compatible = "shared-dma-pool";
|
||||
alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>;
|
||||
reusable;
|
||||
alignment = <0x0 0x400000>;
|
||||
size = <0x0 0x1000000>;
|
||||
};
|
||||
qseecom_ta_mem: qseecom_ta_region {
|
||||
compatible = "shared-dma-pool";
|
||||
alloc-ranges = <0 0x00000000 0 0xffffffff>;
|
||||
|
@ -82,6 +82,8 @@ CONFIG_SETEND_EMULATION=y
|
||||
CONFIG_ARM64_SW_TTBR0_PAN=y
|
||||
# CONFIG_ARM64_VHE is not set
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_CMDLINE="cgroup_disable=pressure"
|
||||
CONFIG_CMDLINE_EXTEND=y
|
||||
# CONFIG_EFI is not set
|
||||
CONFIG_KRYO_PMU_WORKAROUND=y
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
|
2
arch/arm64/configs/vendor/atoll_defconfig
vendored
2
arch/arm64/configs/vendor/atoll_defconfig
vendored
@ -88,6 +88,8 @@ CONFIG_SETEND_EMULATION=y
|
||||
CONFIG_ARM64_SW_TTBR0_PAN=y
|
||||
# CONFIG_ARM64_VHE is not set
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_CMDLINE="cgroup_disable=pressure"
|
||||
CONFIG_CMDLINE_EXTEND=y
|
||||
CONFIG_KRYO_PMU_WORKAROUND=y
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
CONFIG_COMPAT=y
|
||||
|
@ -77,6 +77,8 @@ CONFIG_SETEND_EMULATION=y
|
||||
CONFIG_ARM64_SW_TTBR0_PAN=y
|
||||
# CONFIG_ARM64_VHE is not set
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_CMDLINE="cgroup_disable=pressure"
|
||||
CONFIG_CMDLINE_EXTEND=y
|
||||
# CONFIG_EFI is not set
|
||||
CONFIG_KRYO_PMU_WORKAROUND=y
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
|
@ -83,6 +83,8 @@ CONFIG_SETEND_EMULATION=y
|
||||
CONFIG_ARM64_SW_TTBR0_PAN=y
|
||||
# CONFIG_ARM64_VHE is not set
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_CMDLINE="cgroup_disable=pressure"
|
||||
CONFIG_CMDLINE_EXTEND=y
|
||||
CONFIG_KRYO_PMU_WORKAROUND=y
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
CONFIG_COMPAT=y
|
||||
|
@ -82,6 +82,8 @@ CONFIG_SETEND_EMULATION=y
|
||||
CONFIG_ARM64_SW_TTBR0_PAN=y
|
||||
# CONFIG_ARM64_VHE is not set
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_CMDLINE="cgroup_disable=pressure"
|
||||
CONFIG_CMDLINE_EXTEND=y
|
||||
# CONFIG_EFI is not set
|
||||
CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y
|
||||
CONFIG_KRYO_PMU_WORKAROUND=y
|
||||
|
2
arch/arm64/configs/vendor/sm8150_defconfig
vendored
2
arch/arm64/configs/vendor/sm8150_defconfig
vendored
@ -89,6 +89,8 @@ CONFIG_SETEND_EMULATION=y
|
||||
CONFIG_ARM64_SW_TTBR0_PAN=y
|
||||
# CONFIG_ARM64_VHE is not set
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_CMDLINE="cgroup_disable=pressure"
|
||||
CONFIG_CMDLINE_EXTEND=y
|
||||
CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y
|
||||
CONFIG_KRYO_PMU_WORKAROUND=y
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
|
@ -81,6 +81,8 @@ CONFIG_SETEND_EMULATION=y
|
||||
CONFIG_ARM64_SW_TTBR0_PAN=y
|
||||
# CONFIG_ARM64_VHE is not set
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_CMDLINE="cgroup_disable=pressure"
|
||||
CONFIG_CMDLINE_EXTEND=y
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
CONFIG_COMPAT=y
|
||||
CONFIG_PM_WAKELOCKS=y
|
||||
@ -438,6 +440,7 @@ CONFIG_DVB_MPQ=m
|
||||
CONFIG_DVB_MPQ_DEMUX=m
|
||||
CONFIG_DVB_MPQ_SW=y
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_CLIENT_BOOTSPLASH=y
|
||||
CONFIG_DRM_MSM_REGISTER_LOGGING=y
|
||||
CONFIG_DRM_SDE_EVTLOG_DEBUG=y
|
||||
CONFIG_DRM_SDE_RSC=y
|
||||
|
3
arch/arm64/configs/vendor/trinket_defconfig
vendored
3
arch/arm64/configs/vendor/trinket_defconfig
vendored
@ -87,6 +87,8 @@ CONFIG_SETEND_EMULATION=y
|
||||
CONFIG_ARM64_SW_TTBR0_PAN=y
|
||||
# CONFIG_ARM64_VHE is not set
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_CMDLINE="cgroup_disable=pressure"
|
||||
CONFIG_CMDLINE_EXTEND=y
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
CONFIG_COMPAT=y
|
||||
CONFIG_PM_WAKELOCKS=y
|
||||
@ -452,6 +454,7 @@ CONFIG_DVB_MPQ=m
|
||||
CONFIG_DVB_MPQ_DEMUX=m
|
||||
CONFIG_DVB_MPQ_SW=y
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_CLIENT_BOOTSPLASH=y
|
||||
CONFIG_DRM_MSM_REGISTER_LOGGING=y
|
||||
CONFIG_DRM_SDE_EVTLOG_DEBUG=y
|
||||
CONFIG_DRM_SDE_RSC=y
|
||||
|
@ -64,6 +64,13 @@ config DRM_DEBUG_MM_SELFTEST
|
||||
|
||||
If in doubt, say "N".
|
||||
|
||||
config DRM_CLIENT_BOOTSPLASH
|
||||
bool "DRM Bootsplash"
|
||||
help
|
||||
Choose this option to enable DRM bootsplash. This option needs to be
|
||||
selected only if UEFI bootsplash is disabled. Choosing this option
|
||||
will render splash logo in display panel during boot up.
|
||||
|
||||
config DRM_KMS_HELPER
|
||||
tristate
|
||||
depends on DRM
|
||||
|
@ -29,6 +29,7 @@ drm-$(CONFIG_DRM_PANEL) += drm_panel.o
|
||||
drm-$(CONFIG_OF) += drm_of.o
|
||||
drm-$(CONFIG_AGP) += drm_agpsupport.o
|
||||
drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
|
||||
drm-$(CONFIG_DRM_CLIENT_BOOTSPLASH) += drm_bootsplash.o
|
||||
|
||||
drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
|
||||
drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
|
||||
|
333
drivers/gpu/drm/drm_bootsplash.c
Normal file
333
drivers/gpu/drm/drm_bootsplash.c
Normal file
@ -0,0 +1,333 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/keyboard.h>
|
||||
#include <linux/completion.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_client.h>
|
||||
|
||||
#include "drm_internal.h"
|
||||
#include "drm_splash.h"
|
||||
|
||||
static bool drm_bootsplash_enabled;
|
||||
module_param_named(bootsplash_enabled, drm_bootsplash_enabled, bool, 0664);
|
||||
|
||||
static void drm_bootsplash_client_unregister(struct drm_client_dev *client);
|
||||
static int drm_bootsplash_client_hotplug(struct drm_client_dev *client);
|
||||
|
||||
struct drm_bootsplash {
|
||||
struct drm_client_dev client;
|
||||
struct mutex lock;
|
||||
struct drm_client_display *display;
|
||||
struct drm_client_buffer *buffer;
|
||||
struct work_struct worker;
|
||||
struct completion xref;
|
||||
bool started;
|
||||
bool stop;
|
||||
};
|
||||
|
||||
static void is_drm_bootsplash_enabled(struct device *dev)
|
||||
{
|
||||
drm_bootsplash_enabled = of_property_read_bool(dev->of_node,
|
||||
"qcom,sde-drm-fb-splash-logo-enabled");
|
||||
}
|
||||
|
||||
static void drm_bootsplash_buffer_delete(struct drm_bootsplash *splash)
|
||||
{
|
||||
if (!IS_ERR_OR_NULL(splash->buffer))
|
||||
drm_client_framebuffer_delete(splash->buffer);
|
||||
splash->buffer = NULL;
|
||||
}
|
||||
|
||||
static int drm_bootsplash_buffer_create(
|
||||
struct drm_bootsplash *splash, u32 width, u32 height)
|
||||
{
|
||||
splash->buffer =
|
||||
drm_client_framebuffer_create(&splash->client,
|
||||
width, height, SPLASH_IMAGE_FORMAT);
|
||||
if (IS_ERR(splash->buffer)) {
|
||||
drm_bootsplash_buffer_delete(splash);
|
||||
return PTR_ERR(splash->buffer);
|
||||
}
|
||||
|
||||
splash->buffer->vaddr =
|
||||
drm_client_buffer_vmap(splash->buffer);
|
||||
if (!splash->buffer->vaddr)
|
||||
DRM_ERROR("drm_client_buffer_vmap fail\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_bootsplash_display_probe(struct drm_bootsplash *splash)
|
||||
{
|
||||
struct drm_client_dev *client = &splash->client;
|
||||
unsigned int width = 0, height = 0;
|
||||
unsigned int num_non_tiled = 0, i;
|
||||
unsigned int modeset_mask = 0;
|
||||
struct drm_mode_set *modeset;
|
||||
bool tiled = false;
|
||||
int ret;
|
||||
|
||||
ret = drm_client_modeset_probe(client, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&client->modeset_mutex);
|
||||
|
||||
drm_client_for_each_modeset(modeset, client) {
|
||||
if (!modeset->mode)
|
||||
continue;
|
||||
|
||||
if (modeset->connectors[0]->has_tile)
|
||||
tiled = true;
|
||||
else
|
||||
num_non_tiled++;
|
||||
}
|
||||
|
||||
if (!tiled && !num_non_tiled) {
|
||||
drm_bootsplash_buffer_delete(splash);
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Assume only one tiled monitor is possible */
|
||||
if (tiled) {
|
||||
int hdisplay = 0, vdisplay = 0;
|
||||
|
||||
i = 0;
|
||||
drm_client_for_each_modeset(modeset, client) {
|
||||
i++;
|
||||
if (!modeset->connectors[0]->has_tile)
|
||||
continue;
|
||||
|
||||
if (!modeset->y)
|
||||
hdisplay += modeset->mode->hdisplay;
|
||||
if (!modeset->x)
|
||||
vdisplay += modeset->mode->vdisplay;
|
||||
modeset_mask |= BIT(i - 1);
|
||||
}
|
||||
|
||||
width = hdisplay;
|
||||
height = vdisplay;
|
||||
|
||||
goto trim;
|
||||
}
|
||||
|
||||
/* The rest have one display per modeset, pick the largest */
|
||||
i = 0;
|
||||
drm_client_for_each_modeset(modeset, client) {
|
||||
i++;
|
||||
if (!modeset->mode || modeset->connectors[0]->has_tile)
|
||||
continue;
|
||||
|
||||
if (modeset->mode->hdisplay *
|
||||
modeset->mode->vdisplay > width * height) {
|
||||
width = modeset->mode->hdisplay;
|
||||
height = modeset->mode->vdisplay;
|
||||
modeset_mask = BIT(i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
trim:
|
||||
i = 0;
|
||||
drm_client_for_each_modeset(modeset, client) {
|
||||
unsigned int j;
|
||||
|
||||
if (modeset_mask & BIT(i++))
|
||||
continue;
|
||||
drm_mode_destroy(client->dev, modeset->mode);
|
||||
modeset->mode = NULL;
|
||||
|
||||
for (j = 0; j < modeset->num_connectors; j++) {
|
||||
drm_connector_unreference(modeset->connectors[j]);
|
||||
modeset->connectors[j] = NULL;
|
||||
}
|
||||
modeset->num_connectors = 0;
|
||||
}
|
||||
|
||||
if (!splash->buffer ||
|
||||
splash->buffer->fb->width != width ||
|
||||
splash->buffer->fb->height != height) {
|
||||
drm_bootsplash_buffer_delete(splash);
|
||||
ret = drm_bootsplash_buffer_create(splash, width, height);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&client->modeset_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int drm_bootsplash_display_commit_buffer(
|
||||
struct drm_bootsplash *splash)
|
||||
{
|
||||
struct drm_client_dev *client = &splash->client;
|
||||
struct drm_mode_set *modeset;
|
||||
|
||||
mutex_lock(&client->modeset_mutex);
|
||||
drm_client_for_each_modeset(modeset, client) {
|
||||
if (modeset->mode)
|
||||
modeset->fb = splash->buffer->fb;
|
||||
}
|
||||
mutex_unlock(&client->modeset_mutex);
|
||||
|
||||
return drm_client_modeset_commit(client);
|
||||
}
|
||||
|
||||
/* Draw a box for copying the image */
|
||||
static void drm_bootsplash_draw_box(struct drm_client_buffer *buffer)
|
||||
{
|
||||
unsigned int width = buffer->fb->width;
|
||||
unsigned int height = buffer->fb->height;
|
||||
unsigned int x, y, z;
|
||||
u32 *pix;
|
||||
|
||||
pix = buffer->vaddr;
|
||||
pix += ((height / 2) - 50) * width;
|
||||
pix += (width / 2) - 50;
|
||||
|
||||
z = 0;
|
||||
for (y = 0; y < SPLASH_IMAGE_HEIGHT; y++) {
|
||||
for (x = 0; x < SPLASH_IMAGE_WIDTH; x++)
|
||||
*pix++ = splash_bgr888_image[z++];
|
||||
pix += width - SPLASH_IMAGE_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
static int drm_bootsplash_draw(struct drm_bootsplash *splash)
|
||||
{
|
||||
if (!splash->buffer)
|
||||
return -ENOENT;
|
||||
|
||||
drm_bootsplash_draw_box(splash->buffer);
|
||||
|
||||
return drm_bootsplash_display_commit_buffer(splash);
|
||||
}
|
||||
|
||||
static void drm_bootsplash_worker(struct work_struct *work)
|
||||
{
|
||||
struct drm_bootsplash *splash =
|
||||
container_of(work, struct drm_bootsplash, worker);
|
||||
struct drm_client_dev *client = &splash->client;
|
||||
struct drm_device *dev = client->dev;
|
||||
bool stop = false;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&splash->lock);
|
||||
stop = splash->stop;
|
||||
ret = drm_bootsplash_draw(splash);
|
||||
mutex_unlock(&splash->lock);
|
||||
|
||||
if (stop || ret == -ENOENT || ret == -EBUSY)
|
||||
goto skip;
|
||||
|
||||
msleep(5000);
|
||||
splash->stop = true;
|
||||
skip:
|
||||
drm_lastclose(dev);
|
||||
|
||||
drm_bootsplash_buffer_delete(splash);
|
||||
|
||||
DRM_DEBUG("Bootsplash has stopped (start=%u, stop=%u, ret=%d).\n",
|
||||
splash->started, splash->stop, ret);
|
||||
|
||||
complete(&splash->xref);
|
||||
}
|
||||
|
||||
static int drm_bootsplash_client_hotplug(struct drm_client_dev *client)
|
||||
{
|
||||
struct drm_bootsplash *splash =
|
||||
container_of(client, struct drm_bootsplash, client);
|
||||
int ret = 0, retval;
|
||||
|
||||
if (splash->stop)
|
||||
goto out_unlock;
|
||||
|
||||
ret = drm_bootsplash_display_probe(splash);
|
||||
if (ret < 0) {
|
||||
if (splash->started && ret == -ENOENT)
|
||||
splash->stop = true;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (!splash->started) {
|
||||
splash->started = true;
|
||||
reinit_completion(&splash->xref);
|
||||
schedule_work(&splash->worker);
|
||||
retval = wait_for_completion_interruptible(&splash->xref);
|
||||
if (retval < 0)
|
||||
DRM_ERROR("wait for bootsplash worker failed\n");
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_client_funcs drm_bootsplash_client_funcs = {
|
||||
.owner = THIS_MODULE,
|
||||
.unregister = drm_bootsplash_client_unregister,
|
||||
.hotplug = drm_bootsplash_client_hotplug,
|
||||
};
|
||||
|
||||
static void drm_bootsplash_client_unregister(struct drm_client_dev *client)
|
||||
{
|
||||
struct drm_bootsplash *splash =
|
||||
container_of(client, struct drm_bootsplash, client);
|
||||
|
||||
mutex_lock(&splash->lock);
|
||||
splash->stop = true;
|
||||
mutex_unlock(&splash->lock);
|
||||
|
||||
flush_work(&splash->worker);
|
||||
|
||||
drm_client_release(client);
|
||||
kfree(splash);
|
||||
}
|
||||
|
||||
void drm_bootsplash_client_register(struct drm_device *dev)
|
||||
{
|
||||
struct drm_bootsplash *splash;
|
||||
int ret;
|
||||
|
||||
is_drm_bootsplash_enabled(dev->dev);
|
||||
|
||||
if (!drm_bootsplash_enabled)
|
||||
return;
|
||||
|
||||
splash = kzalloc(sizeof(*splash), GFP_KERNEL);
|
||||
if (!splash)
|
||||
return;
|
||||
|
||||
ret = drm_client_init(dev, &splash->client, "bootsplash",
|
||||
&drm_bootsplash_client_funcs);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev->dev, "Fail to create client, ret=%d\n", ret);
|
||||
kfree(splash);
|
||||
return;
|
||||
}
|
||||
|
||||
/* For this simple example only allow the first */
|
||||
drm_bootsplash_enabled = false;
|
||||
|
||||
mutex_init(&splash->lock);
|
||||
|
||||
INIT_WORK(&splash->worker, drm_bootsplash_worker);
|
||||
init_completion(&splash->xref);
|
||||
|
||||
ret = drm_bootsplash_client_hotplug(&splash->client);
|
||||
if (ret)
|
||||
DRM_DEV_ERROR(dev->dev, "client hotplug ret=%d\n", ret);
|
||||
|
||||
drm_client_register(&splash->client);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("bootsplash");
|
@ -59,7 +59,6 @@ static void drm_client_close(struct drm_client_dev *client)
|
||||
|
||||
drm_file_free(client->file);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_client_close);
|
||||
|
||||
/**
|
||||
* drm_client_init - Initialise a DRM client
|
||||
@ -161,6 +160,13 @@ void drm_client_release(struct drm_client_dev *client)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_client_release);
|
||||
|
||||
void drm_client_dev_register(struct drm_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_DRM_CLIENT_BOOTSPLASH
|
||||
drm_bootsplash_client_register(dev);
|
||||
#endif
|
||||
}
|
||||
|
||||
void drm_client_dev_unregister(struct drm_device *dev)
|
||||
{
|
||||
struct drm_client_dev *client, *tmp;
|
||||
@ -180,6 +186,7 @@ void drm_client_dev_unregister(struct drm_device *dev)
|
||||
}
|
||||
mutex_unlock(&dev->clientlist_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_client_dev_unregister);
|
||||
|
||||
/**
|
||||
* drm_client_dev_hotplug - Send hotplug event to clients
|
||||
@ -253,7 +260,6 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
|
||||
struct drm_device *dev = client->dev;
|
||||
struct drm_client_buffer *buffer;
|
||||
struct drm_gem_object *obj;
|
||||
void *vaddr;
|
||||
int ret;
|
||||
|
||||
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
|
||||
@ -280,6 +286,40 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
|
||||
|
||||
buffer->gem = obj;
|
||||
|
||||
return buffer;
|
||||
|
||||
err_delete:
|
||||
drm_client_buffer_delete(buffer);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_client_buffer_vmap - Map DRM client buffer into address space
|
||||
* @buffer: DRM client buffer
|
||||
*
|
||||
* This function maps a client buffer into kernel address space. If the
|
||||
* buffer is already mapped, it returns the mapping's address.
|
||||
*
|
||||
* Client buffer mappings are not ref'counted. Each call to
|
||||
* drm_client_buffer_vmap() should be followed by a call to
|
||||
* drm_client_buffer_vunmap(); or the client buffer should be mapped
|
||||
* throughout its lifetime. The latter is the default.
|
||||
*
|
||||
* Returns:
|
||||
* The mapped memory's address
|
||||
*/
|
||||
void *drm_client_buffer_vmap(struct drm_client_buffer *buffer)
|
||||
{
|
||||
struct drm_device *dev = buffer->client->dev;
|
||||
void *vaddr;
|
||||
|
||||
if (buffer->vaddr)
|
||||
return buffer->vaddr;
|
||||
|
||||
if (!dev->driver->gem_prime_vmap)
|
||||
return ERR_PTR(-ENOTSUPP);
|
||||
|
||||
/*
|
||||
* FIXME: The dependency on GEM here isn't required, we could
|
||||
* convert the driver handle to a dma-buf instead and use the
|
||||
@ -288,21 +328,35 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
|
||||
* fd_install step out of the driver backend hooks, to make that
|
||||
* final step optional for internal users.
|
||||
*/
|
||||
vaddr = dev->driver->gem_prime_vmap(obj);
|
||||
if (!vaddr) {
|
||||
ret = -ENOMEM;
|
||||
goto err_delete;
|
||||
vaddr = dev->driver->gem_prime_vmap(buffer->gem);
|
||||
if (IS_ERR(vaddr)) {
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
buffer->vaddr = vaddr;
|
||||
|
||||
return buffer;
|
||||
|
||||
err_delete:
|
||||
drm_client_buffer_delete(buffer);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
return vaddr;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_client_buffer_vmap);
|
||||
|
||||
/**
|
||||
* drm_client_buffer_vunmap - Unmap DRM client buffer
|
||||
* @buffer: DRM client buffer
|
||||
*
|
||||
* This function removes a client buffer's memory mapping. This
|
||||
* function is only required by clients that manage their buffers
|
||||
* by themselves. By default, DRM client buffers are mapped throughout
|
||||
* their entire lifetime.
|
||||
*/
|
||||
void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
|
||||
{
|
||||
struct drm_device *dev = buffer->client->dev;
|
||||
|
||||
if (buffer->vaddr && dev->driver->gem_prime_vunmap)
|
||||
dev->driver->gem_prime_vunmap(buffer->gem, buffer->vaddr);
|
||||
buffer->vaddr = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_client_buffer_vunmap);
|
||||
|
||||
static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
|
||||
{
|
||||
|
@ -11,9 +11,23 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_client.h>
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "drm_crtc_internal.h"
|
||||
#include "drm_internal.h"
|
||||
|
||||
#define DRM_CLIENT_MAX_CLONED_CONNECTORS 8
|
||||
|
||||
struct drm_client_offset {
|
||||
int x, y;
|
||||
};
|
||||
|
||||
int drm_client_modeset_create(struct drm_client_dev *client)
|
||||
{
|
||||
@ -53,7 +67,7 @@ err_free:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void drm_client_modeset_release(struct drm_client_dev *client)
|
||||
static void drm_client_modeset_release(struct drm_client_dev *client)
|
||||
{
|
||||
struct drm_mode_set *modeset;
|
||||
unsigned int i;
|
||||
@ -70,8 +84,6 @@ void drm_client_modeset_release(struct drm_client_dev *client)
|
||||
modeset->num_connectors = 0;
|
||||
}
|
||||
}
|
||||
/* TODO: Remove export when modeset code has been moved over */
|
||||
EXPORT_SYMBOL(drm_client_modeset_release);
|
||||
|
||||
void drm_client_modeset_free(struct drm_client_dev *client)
|
||||
{
|
||||
@ -90,7 +102,8 @@ void drm_client_modeset_free(struct drm_client_dev *client)
|
||||
kfree(client->modesets);
|
||||
}
|
||||
|
||||
struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc)
|
||||
static struct drm_mode_set *
|
||||
drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_mode_set *modeset;
|
||||
|
||||
@ -100,5 +113,908 @@ struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, stru
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/* TODO: Remove export when modeset code has been moved over */
|
||||
EXPORT_SYMBOL(drm_client_find_modeset);
|
||||
|
||||
static struct drm_display_mode *
|
||||
drm_connector_has_preferred_mode(struct drm_connector *connector, int width, int height)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
list_for_each_entry(mode, &connector->modes, head) {
|
||||
if (mode->hdisplay > width ||
|
||||
mode->vdisplay > height)
|
||||
continue;
|
||||
if (mode->type & DRM_MODE_TYPE_PREFERRED)
|
||||
return mode;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct drm_display_mode *
|
||||
drm_connector_pick_cmdline_mode(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_cmdline_mode *cmdline_mode;
|
||||
struct drm_display_mode *mode;
|
||||
bool prefer_non_interlace;
|
||||
|
||||
cmdline_mode = &connector->cmdline_mode;
|
||||
if (cmdline_mode->specified == false)
|
||||
return NULL;
|
||||
|
||||
/* attempt to find a matching mode in the list of modes
|
||||
* we have gotten so far, if not add a CVT mode that conforms
|
||||
*/
|
||||
if (cmdline_mode->rb || cmdline_mode->margins)
|
||||
goto create_mode;
|
||||
|
||||
prefer_non_interlace = !cmdline_mode->interlace;
|
||||
again:
|
||||
list_for_each_entry(mode, &connector->modes, head) {
|
||||
/* Check (optional) mode name first */
|
||||
if (!strcmp(mode->name, cmdline_mode->name))
|
||||
return mode;
|
||||
|
||||
/* check width/height */
|
||||
if (mode->hdisplay != cmdline_mode->xres ||
|
||||
mode->vdisplay != cmdline_mode->yres)
|
||||
continue;
|
||||
|
||||
if (cmdline_mode->refresh_specified) {
|
||||
if (mode->vrefresh != cmdline_mode->refresh)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cmdline_mode->interlace) {
|
||||
if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
|
||||
continue;
|
||||
} else if (prefer_non_interlace) {
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
continue;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
if (prefer_non_interlace) {
|
||||
prefer_non_interlace = false;
|
||||
goto again;
|
||||
}
|
||||
|
||||
create_mode:
|
||||
mode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode);
|
||||
if (mode)
|
||||
list_add(&mode->head, &connector->modes);
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
|
||||
{
|
||||
bool enable;
|
||||
|
||||
if (strict)
|
||||
enable = connector->status == connector_status_connected;
|
||||
else
|
||||
enable = connector->status != connector_status_disconnected;
|
||||
|
||||
return enable;
|
||||
}
|
||||
|
||||
static void drm_client_connectors_enabled(struct drm_connector **connectors,
|
||||
unsigned int connector_count,
|
||||
bool *enabled)
|
||||
{
|
||||
bool any_enabled = false;
|
||||
struct drm_connector *connector;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < connector_count; i++) {
|
||||
connector = connectors[i];
|
||||
enabled[i] = drm_connector_enabled(connector, true);
|
||||
DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
|
||||
enabled[i] ? "yes" : "no");
|
||||
|
||||
any_enabled |= enabled[i];
|
||||
}
|
||||
|
||||
if (any_enabled)
|
||||
return;
|
||||
|
||||
for (i = 0; i < connector_count; i++)
|
||||
enabled[i] = drm_connector_enabled(connectors[i], false);
|
||||
}
|
||||
|
||||
static bool drm_client_target_cloned(struct drm_device *dev,
|
||||
struct drm_connector **connectors,
|
||||
unsigned int connector_count,
|
||||
struct drm_display_mode **modes,
|
||||
struct drm_client_offset *offsets,
|
||||
bool *enabled, int width, int height)
|
||||
{
|
||||
int count, i, j;
|
||||
bool can_clone = false;
|
||||
struct drm_display_mode *dmt_mode, *mode;
|
||||
|
||||
/* only contemplate cloning in the single crtc case */
|
||||
if (dev->mode_config.num_crtc > 1)
|
||||
return false;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < connector_count; i++) {
|
||||
if (enabled[i])
|
||||
count++;
|
||||
}
|
||||
|
||||
/* only contemplate cloning if more than one connector is enabled */
|
||||
if (count <= 1)
|
||||
return false;
|
||||
|
||||
/* check the command line or if nothing common pick 1024x768 */
|
||||
can_clone = true;
|
||||
for (i = 0; i < connector_count; i++) {
|
||||
if (!enabled[i])
|
||||
continue;
|
||||
modes[i] = drm_connector_pick_cmdline_mode(connectors[i]);
|
||||
if (!modes[i]) {
|
||||
can_clone = false;
|
||||
break;
|
||||
}
|
||||
for (j = 0; j < i; j++) {
|
||||
if (!enabled[j])
|
||||
continue;
|
||||
if (!drm_mode_match(modes[j], modes[i],
|
||||
DRM_MODE_MATCH_TIMINGS |
|
||||
DRM_MODE_MATCH_CLOCK |
|
||||
DRM_MODE_MATCH_FLAGS |
|
||||
DRM_MODE_MATCH_3D_FLAGS))
|
||||
can_clone = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (can_clone) {
|
||||
DRM_DEBUG_KMS("can clone using command line\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* try and find a 1024x768 mode on each connector */
|
||||
can_clone = true;
|
||||
dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
|
||||
|
||||
for (i = 0; i < connector_count; i++) {
|
||||
if (!enabled[i])
|
||||
continue;
|
||||
|
||||
list_for_each_entry(mode, &connectors[i]->modes, head) {
|
||||
if (drm_mode_match(mode, dmt_mode,
|
||||
DRM_MODE_MATCH_TIMINGS |
|
||||
DRM_MODE_MATCH_CLOCK |
|
||||
DRM_MODE_MATCH_FLAGS |
|
||||
DRM_MODE_MATCH_3D_FLAGS))
|
||||
modes[i] = mode;
|
||||
}
|
||||
if (!modes[i])
|
||||
can_clone = false;
|
||||
}
|
||||
|
||||
if (can_clone) {
|
||||
DRM_DEBUG_KMS("can clone using 1024x768\n");
|
||||
return true;
|
||||
}
|
||||
DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static int drm_client_get_tile_offsets(struct drm_connector **connectors,
|
||||
unsigned int connector_count,
|
||||
struct drm_display_mode **modes,
|
||||
struct drm_client_offset *offsets,
|
||||
int idx,
|
||||
int h_idx, int v_idx)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
int i;
|
||||
int hoffset = 0, voffset = 0;
|
||||
|
||||
for (i = 0; i < connector_count; i++) {
|
||||
connector = connectors[i];
|
||||
if (!connector->has_tile)
|
||||
continue;
|
||||
|
||||
if (!modes[i] && (h_idx || v_idx)) {
|
||||
DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
|
||||
connector->base.id);
|
||||
continue;
|
||||
}
|
||||
if (connector->tile_h_loc < h_idx)
|
||||
hoffset += modes[i]->hdisplay;
|
||||
|
||||
if (connector->tile_v_loc < v_idx)
|
||||
voffset += modes[i]->vdisplay;
|
||||
}
|
||||
offsets[idx].x = hoffset;
|
||||
offsets[idx].y = voffset;
|
||||
DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool drm_client_target_preferred(struct drm_connector **connectors,
|
||||
unsigned int connector_count,
|
||||
struct drm_display_mode **modes,
|
||||
struct drm_client_offset *offsets,
|
||||
bool *enabled, int width, int height)
|
||||
{
|
||||
const u64 mask = BIT_ULL(connector_count) - 1;
|
||||
struct drm_connector *connector;
|
||||
u64 conn_configured = 0;
|
||||
int tile_pass = 0;
|
||||
int i;
|
||||
|
||||
retry:
|
||||
for (i = 0; i < connector_count; i++) {
|
||||
connector = connectors[i];
|
||||
|
||||
if (conn_configured & BIT_ULL(i))
|
||||
continue;
|
||||
|
||||
if (enabled[i] == false) {
|
||||
conn_configured |= BIT_ULL(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* first pass over all the untiled connectors */
|
||||
if (tile_pass == 0 && connector->has_tile)
|
||||
continue;
|
||||
|
||||
if (tile_pass == 1) {
|
||||
if (connector->tile_h_loc != 0 ||
|
||||
connector->tile_v_loc != 0)
|
||||
continue;
|
||||
|
||||
} else {
|
||||
if (connector->tile_h_loc != tile_pass - 1 &&
|
||||
connector->tile_v_loc != tile_pass - 1)
|
||||
/* if this tile_pass doesn't cover any of the tiles - keep going */
|
||||
continue;
|
||||
|
||||
/*
|
||||
* find the tile offsets for this pass - need to find
|
||||
* all tiles left and above
|
||||
*/
|
||||
drm_client_get_tile_offsets(connectors, connector_count, modes, offsets, i,
|
||||
connector->tile_h_loc, connector->tile_v_loc);
|
||||
}
|
||||
DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
|
||||
connector->base.id);
|
||||
|
||||
/* got for command line mode first */
|
||||
modes[i] = drm_connector_pick_cmdline_mode(connector);
|
||||
if (!modes[i]) {
|
||||
DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
|
||||
connector->base.id, connector->tile_group ? connector->tile_group->id : 0);
|
||||
modes[i] = drm_connector_has_preferred_mode(connector, width, height);
|
||||
}
|
||||
/* No preferred modes, pick one off the list */
|
||||
if (!modes[i] && !list_empty(&connector->modes)) {
|
||||
list_for_each_entry(modes[i], &connector->modes, head)
|
||||
break;
|
||||
}
|
||||
DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
|
||||
"none");
|
||||
conn_configured |= BIT_ULL(i);
|
||||
}
|
||||
|
||||
if ((conn_configured & mask) != mask) {
|
||||
tile_pass++;
|
||||
goto retry;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool connector_has_possible_crtc(struct drm_connector *connector,
|
||||
struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_encoder *encoder;
|
||||
int i;
|
||||
|
||||
drm_connector_for_each_possible_encoder(connector, encoder, i) {
|
||||
if (encoder->possible_crtcs & drm_crtc_mask(crtc))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int drm_client_pick_crtcs(struct drm_client_dev *client,
|
||||
struct drm_connector **connectors,
|
||||
unsigned int connector_count,
|
||||
struct drm_crtc **best_crtcs,
|
||||
struct drm_display_mode **modes,
|
||||
int n, int width, int height)
|
||||
{
|
||||
struct drm_device *dev = client->dev;
|
||||
struct drm_connector *connector;
|
||||
int my_score, best_score, score;
|
||||
struct drm_crtc **crtcs, *crtc;
|
||||
struct drm_mode_set *modeset;
|
||||
int o;
|
||||
|
||||
if (n == connector_count)
|
||||
return 0;
|
||||
|
||||
connector = connectors[n];
|
||||
|
||||
best_crtcs[n] = NULL;
|
||||
best_score = drm_client_pick_crtcs(client, connectors, connector_count,
|
||||
best_crtcs, modes, n + 1, width, height);
|
||||
if (modes[n] == NULL)
|
||||
return best_score;
|
||||
|
||||
crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
|
||||
if (!crtcs)
|
||||
return best_score;
|
||||
|
||||
my_score = 1;
|
||||
if (connector->status == connector_status_connected)
|
||||
my_score++;
|
||||
if (connector->cmdline_mode.specified)
|
||||
my_score++;
|
||||
if (drm_connector_has_preferred_mode(connector, width, height))
|
||||
my_score++;
|
||||
|
||||
/*
|
||||
* select a crtc for this connector and then attempt to configure
|
||||
* remaining connectors
|
||||
*/
|
||||
drm_client_for_each_modeset(modeset, client) {
|
||||
crtc = modeset->crtc;
|
||||
|
||||
if (!connector_has_possible_crtc(connector, crtc))
|
||||
continue;
|
||||
|
||||
for (o = 0; o < n; o++)
|
||||
if (best_crtcs[o] == crtc)
|
||||
break;
|
||||
|
||||
if (o < n) {
|
||||
/* ignore cloning unless only a single crtc */
|
||||
if (dev->mode_config.num_crtc > 1)
|
||||
continue;
|
||||
|
||||
if (!drm_mode_equal(modes[o], modes[n]))
|
||||
continue;
|
||||
}
|
||||
|
||||
crtcs[n] = crtc;
|
||||
memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
|
||||
score = my_score + drm_client_pick_crtcs(client, connectors, connector_count,
|
||||
crtcs, modes, n + 1, width, height);
|
||||
if (score > best_score) {
|
||||
best_score = score;
|
||||
memcpy(best_crtcs, crtcs, connector_count * sizeof(*crtcs));
|
||||
}
|
||||
}
|
||||
|
||||
kfree(crtcs);
|
||||
return best_score;
|
||||
}
|
||||
|
||||
/* Try to read the BIOS display configuration and use it for the initial config */
|
||||
static bool drm_client_firmware_config(struct drm_client_dev *client,
|
||||
struct drm_connector **connectors,
|
||||
unsigned int connector_count,
|
||||
struct drm_crtc **crtcs,
|
||||
struct drm_display_mode **modes,
|
||||
struct drm_client_offset *offsets,
|
||||
bool *enabled, int width, int height)
|
||||
{
|
||||
unsigned int count = min_t(unsigned int, connector_count, BITS_PER_LONG);
|
||||
unsigned long conn_configured, conn_seq, mask;
|
||||
struct drm_device *dev = client->dev;
|
||||
int i, j;
|
||||
bool *save_enabled;
|
||||
bool fallback = true, ret = true;
|
||||
int num_connectors_enabled = 0;
|
||||
int num_connectors_detected = 0;
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
|
||||
if (!drm_drv_uses_atomic_modeset(dev))
|
||||
return false;
|
||||
|
||||
save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
|
||||
if (!save_enabled)
|
||||
return false;
|
||||
|
||||
drm_modeset_acquire_init(&ctx, 0);
|
||||
|
||||
while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
|
||||
drm_modeset_backoff(&ctx);
|
||||
|
||||
memcpy(save_enabled, enabled, count);
|
||||
mask = GENMASK(count - 1, 0);
|
||||
conn_configured = 0;
|
||||
retry:
|
||||
conn_seq = conn_configured;
|
||||
for (i = 0; i < count; i++) {
|
||||
struct drm_connector *connector;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_crtc *new_crtc;
|
||||
|
||||
connector = connectors[i];
|
||||
|
||||
if (conn_configured & BIT(i))
|
||||
continue;
|
||||
|
||||
if (conn_seq == 0 && !connector->has_tile)
|
||||
continue;
|
||||
|
||||
if (connector->status == connector_status_connected)
|
||||
num_connectors_detected++;
|
||||
|
||||
if (!enabled[i]) {
|
||||
DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
|
||||
connector->name);
|
||||
conn_configured |= BIT(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (connector->force == DRM_FORCE_OFF) {
|
||||
DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
|
||||
connector->name);
|
||||
enabled[i] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
encoder = connector->state->best_encoder;
|
||||
if (!encoder || WARN_ON(!connector->state->crtc)) {
|
||||
if (connector->force > DRM_FORCE_OFF)
|
||||
goto bail;
|
||||
|
||||
DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
|
||||
connector->name);
|
||||
enabled[i] = false;
|
||||
conn_configured |= BIT(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
num_connectors_enabled++;
|
||||
|
||||
new_crtc = connector->state->crtc;
|
||||
|
||||
/*
|
||||
* Make sure we're not trying to drive multiple connectors
|
||||
* with a single CRTC, since our cloning support may not
|
||||
* match the BIOS.
|
||||
*/
|
||||
for (j = 0; j < count; j++) {
|
||||
if (crtcs[j] == new_crtc) {
|
||||
DRM_DEBUG_KMS("fallback: cloned configuration\n");
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
|
||||
connector->name);
|
||||
|
||||
/* go for command line mode first */
|
||||
modes[i] = drm_connector_pick_cmdline_mode(connector);
|
||||
|
||||
/* try for preferred next */
|
||||
if (!modes[i]) {
|
||||
DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
|
||||
connector->name, connector->has_tile);
|
||||
modes[i] = drm_connector_has_preferred_mode(connector, width, height);
|
||||
}
|
||||
|
||||
/* No preferred mode marked by the EDID? Are there any modes? */
|
||||
if (!modes[i] && !list_empty(&connector->modes)) {
|
||||
DRM_DEBUG_KMS("using first mode listed on connector %s\n",
|
||||
connector->name);
|
||||
modes[i] = list_first_entry(&connector->modes,
|
||||
struct drm_display_mode,
|
||||
head);
|
||||
}
|
||||
|
||||
/* last resort: use current mode */
|
||||
if (!modes[i]) {
|
||||
/*
|
||||
* IMPORTANT: We want to use the adjusted mode (i.e.
|
||||
* after the panel fitter upscaling) as the initial
|
||||
* config, not the input mode, which is what crtc->mode
|
||||
* usually contains. But since our current
|
||||
* code puts a mode derived from the post-pfit timings
|
||||
* into crtc->mode this works out correctly.
|
||||
*
|
||||
* This is crtc->mode and not crtc->state->mode for the
|
||||
* fastboot check to work correctly.
|
||||
*/
|
||||
DRM_DEBUG_KMS("looking for current mode on connector %s\n",
|
||||
connector->name);
|
||||
modes[i] = &connector->state->crtc->mode;
|
||||
}
|
||||
crtcs[i] = new_crtc;
|
||||
|
||||
DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
|
||||
connector->name,
|
||||
connector->state->crtc->base.id,
|
||||
connector->state->crtc->name,
|
||||
modes[i]->hdisplay, modes[i]->vdisplay,
|
||||
modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
|
||||
|
||||
fallback = false;
|
||||
conn_configured |= BIT(i);
|
||||
}
|
||||
|
||||
if ((conn_configured & mask) != mask && conn_configured != conn_seq)
|
||||
goto retry;
|
||||
|
||||
/*
|
||||
* If the BIOS didn't enable everything it could, fall back to have the
|
||||
* same user experiencing of lighting up as much as possible like the
|
||||
* fbdev helper library.
|
||||
*/
|
||||
if (num_connectors_enabled != num_connectors_detected &&
|
||||
num_connectors_enabled < dev->mode_config.num_crtc) {
|
||||
DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
|
||||
DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
|
||||
num_connectors_detected);
|
||||
fallback = true;
|
||||
}
|
||||
|
||||
if (fallback) {
|
||||
bail:
|
||||
DRM_DEBUG_KMS("Not using firmware configuration\n");
|
||||
memcpy(enabled, save_enabled, count);
|
||||
ret = false;
|
||||
}
|
||||
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
|
||||
kfree(save_enabled);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_client_modeset_probe() - Probe for displays
|
||||
* @client: DRM client
|
||||
* @width: Maximum display mode width (optional)
|
||||
* @height: Maximum display mode height (optional)
|
||||
*
|
||||
* This function sets up display pipelines for enabled connectors and stores the
|
||||
* config in the client's modeset array.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success or negative error code on failure.
|
||||
*/
|
||||
int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height)
|
||||
{
|
||||
struct drm_connector *connector, **connectors = NULL;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
struct drm_device *dev = client->dev;
|
||||
unsigned int total_modes_count = 0;
|
||||
struct drm_client_offset *offsets;
|
||||
unsigned int connector_count = 0;
|
||||
struct drm_display_mode **modes;
|
||||
struct drm_crtc **crtcs;
|
||||
int i, ret = 0;
|
||||
bool *enabled;
|
||||
|
||||
DRM_DEBUG_KMS("\n");
|
||||
|
||||
if (!width)
|
||||
width = dev->mode_config.max_width;
|
||||
if (!height)
|
||||
height = dev->mode_config.max_height;
|
||||
|
||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
||||
struct drm_connector **tmp;
|
||||
|
||||
tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), GFP_KERNEL);
|
||||
if (!tmp) {
|
||||
ret = -ENOMEM;
|
||||
goto free_connectors;
|
||||
}
|
||||
|
||||
connectors = tmp;
|
||||
drm_connector_get(connector);
|
||||
connectors[connector_count++] = connector;
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
if (!connector_count)
|
||||
return 0;
|
||||
|
||||
crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
|
||||
modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
|
||||
offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);
|
||||
enabled = kcalloc(connector_count, sizeof(bool), GFP_KERNEL);
|
||||
if (!crtcs || !modes || !enabled || !offsets) {
|
||||
DRM_ERROR("Memory allocation failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&client->modeset_mutex);
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
for (i = 0; i < connector_count; i++)
|
||||
total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height);
|
||||
if (!total_modes_count)
|
||||
DRM_DEBUG_KMS("No connectors reported connected with modes\n");
|
||||
drm_client_connectors_enabled(connectors, connector_count, enabled);
|
||||
|
||||
if (!drm_client_firmware_config(client, connectors, connector_count, crtcs,
|
||||
modes, offsets, enabled, width, height)) {
|
||||
memset(modes, 0, connector_count * sizeof(*modes));
|
||||
memset(crtcs, 0, connector_count * sizeof(*crtcs));
|
||||
memset(offsets, 0, connector_count * sizeof(*offsets));
|
||||
|
||||
if (!drm_client_target_cloned(dev, connectors, connector_count, modes,
|
||||
offsets, enabled, width, height) &&
|
||||
!drm_client_target_preferred(connectors, connector_count, modes,
|
||||
offsets, enabled, width, height))
|
||||
DRM_ERROR("Unable to find initial modes\n");
|
||||
|
||||
DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
|
||||
width, height);
|
||||
|
||||
drm_client_pick_crtcs(client, connectors, connector_count,
|
||||
crtcs, modes, 0, width, height);
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
drm_client_modeset_release(client);
|
||||
|
||||
for (i = 0; i < connector_count; i++) {
|
||||
struct drm_display_mode *mode = modes[i];
|
||||
struct drm_crtc *crtc = crtcs[i];
|
||||
struct drm_client_offset *offset = &offsets[i];
|
||||
|
||||
if (mode && crtc) {
|
||||
struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc);
|
||||
struct drm_connector *connector = connectors[i];
|
||||
|
||||
DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
|
||||
mode->name, crtc->base.id, offset->x, offset->y);
|
||||
|
||||
if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||
|
||||
(dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1))) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
modeset->mode = drm_mode_duplicate(dev, mode);
|
||||
drm_connector_get(connector);
|
||||
modeset->connectors[modeset->num_connectors++] = connector;
|
||||
modeset->x = offset->x;
|
||||
modeset->y = offset->y;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&client->modeset_mutex);
|
||||
out:
|
||||
kfree(crtcs);
|
||||
kfree(modes);
|
||||
kfree(offsets);
|
||||
kfree(enabled);
|
||||
free_connectors:
|
||||
for (i = 0; i < connector_count; i++)
|
||||
drm_connector_put(connectors[i]);
|
||||
kfree(connectors);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_client_modeset_probe);
|
||||
|
||||
static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool active)
|
||||
{
|
||||
struct drm_device *dev = client->dev;
|
||||
struct drm_plane *plane;
|
||||
struct drm_atomic_state *state;
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
struct drm_mode_set *mode_set;
|
||||
int ret;
|
||||
|
||||
drm_modeset_acquire_init(&ctx, 0);
|
||||
|
||||
state = drm_atomic_state_alloc(dev);
|
||||
if (!state) {
|
||||
ret = -ENOMEM;
|
||||
goto out_ctx;
|
||||
}
|
||||
|
||||
state->acquire_ctx = &ctx;
|
||||
retry:
|
||||
drm_for_each_plane(plane, dev) {
|
||||
struct drm_plane_state *plane_state;
|
||||
|
||||
plane_state = drm_atomic_get_plane_state(state, plane);
|
||||
if (IS_ERR(plane_state)) {
|
||||
ret = PTR_ERR(plane_state);
|
||||
goto out_state;
|
||||
}
|
||||
|
||||
plane_state->rotation = DRM_MODE_ROTATE_0;
|
||||
|
||||
/* disable non-primary: */
|
||||
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
|
||||
continue;
|
||||
|
||||
ret = __drm_atomic_helper_disable_plane(plane, plane_state);
|
||||
if (ret != 0)
|
||||
goto out_state;
|
||||
}
|
||||
|
||||
drm_client_for_each_modeset(mode_set, client) {
|
||||
ret = __drm_atomic_helper_set_config(mode_set, state);
|
||||
if (ret != 0)
|
||||
goto out_state;
|
||||
|
||||
/*
|
||||
* __drm_atomic_helper_set_config() sets active when a
|
||||
* mode is set, unconditionally clear it if we force DPMS off
|
||||
*/
|
||||
if (!active) {
|
||||
struct drm_crtc *crtc = mode_set->crtc;
|
||||
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
|
||||
crtc_state->active = false;
|
||||
}
|
||||
}
|
||||
|
||||
ret = drm_atomic_commit(state);
|
||||
|
||||
out_state:
|
||||
if (ret == -EDEADLK)
|
||||
goto backoff;
|
||||
|
||||
out_ctx:
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
|
||||
return ret;
|
||||
|
||||
backoff:
|
||||
drm_atomic_state_clear(state);
|
||||
drm_modeset_backoff(&ctx);
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
static int drm_client_modeset_commit_legacy(struct drm_client_dev *client)
|
||||
{
|
||||
struct drm_device *dev = client->dev;
|
||||
struct drm_mode_set *mode_set;
|
||||
struct drm_plane *plane;
|
||||
int ret = 0;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
drm_for_each_plane(plane, dev) {
|
||||
if (plane->type != DRM_PLANE_TYPE_PRIMARY)
|
||||
drm_plane_force_disable(plane);
|
||||
}
|
||||
|
||||
drm_client_for_each_modeset(mode_set, client) {
|
||||
struct drm_crtc *crtc = mode_set->crtc;
|
||||
|
||||
if (crtc->funcs->cursor_set2) {
|
||||
ret = crtc->funcs->cursor_set2(crtc, NULL, 0, 0, 0, 0, 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
} else if (crtc->funcs->cursor_set) {
|
||||
ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = drm_mode_set_config_internal(mode_set);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_client_modeset_commit_force() - Force commit CRTC configuration
|
||||
* @client: DRM client
|
||||
*
|
||||
* Commit modeset configuration to crtcs without checking if there is a DRM master.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success or negative error code on failure.
|
||||
*/
|
||||
int drm_client_modeset_commit_force(struct drm_client_dev *client)
|
||||
{
|
||||
struct drm_device *dev = client->dev;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&client->modeset_mutex);
|
||||
if (drm_drv_uses_atomic_modeset(dev))
|
||||
ret = drm_client_modeset_commit_atomic(client, true);
|
||||
else
|
||||
ret = drm_client_modeset_commit_legacy(client);
|
||||
mutex_unlock(&client->modeset_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_client_modeset_commit_force);
|
||||
|
||||
/**
|
||||
* drm_client_modeset_commit() - Commit CRTC configuration
|
||||
* @client: DRM client
|
||||
*
|
||||
* Commit modeset configuration to crtcs.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success or negative error code on failure.
|
||||
*/
|
||||
int drm_client_modeset_commit(struct drm_client_dev *client)
|
||||
{
|
||||
struct drm_device *dev = client->dev;
|
||||
int ret;
|
||||
|
||||
if (!drm_master_internal_acquire(dev))
|
||||
return -EBUSY;
|
||||
|
||||
ret = drm_client_modeset_commit_force(client);
|
||||
|
||||
drm_master_internal_release(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_client_modeset_commit);
|
||||
|
||||
static void drm_client_modeset_dpms_legacy(struct drm_client_dev *client, int dpms_mode)
|
||||
{
|
||||
struct drm_device *dev = client->dev;
|
||||
struct drm_connector *connector;
|
||||
struct drm_mode_set *modeset;
|
||||
int j;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
drm_client_for_each_modeset(modeset, client) {
|
||||
if (!modeset->crtc->enabled)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < modeset->num_connectors; j++) {
|
||||
connector = modeset->connectors[j];
|
||||
connector->funcs->dpms(connector, dpms_mode);
|
||||
drm_object_property_set_value(&connector->base,
|
||||
dev->mode_config.dpms_property, dpms_mode);
|
||||
}
|
||||
}
|
||||
drm_modeset_unlock_all(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_client_modeset_dpms() - Set DPMS mode
|
||||
* @client: DRM client
|
||||
* @mode: DPMS mode
|
||||
*
|
||||
* Note: For atomic drivers @mode is reduced to on/off.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success or negative error code on failure.
|
||||
*/
|
||||
int drm_client_modeset_dpms(struct drm_client_dev *client, int mode)
|
||||
{
|
||||
struct drm_device *dev = client->dev;
|
||||
int ret = 0;
|
||||
|
||||
if (!drm_master_internal_acquire(dev))
|
||||
return -EBUSY;
|
||||
|
||||
mutex_lock(&client->modeset_mutex);
|
||||
if (drm_drv_uses_atomic_modeset(dev))
|
||||
ret = drm_client_modeset_commit_atomic(client, mode == DRM_MODE_DPMS_ON);
|
||||
else
|
||||
drm_client_modeset_dpms_legacy(client, mode);
|
||||
mutex_unlock(&client->modeset_mutex);
|
||||
|
||||
drm_master_internal_release(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_client_modeset_dpms);
|
||||
|
@ -133,8 +133,9 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
|
||||
connector->force = mode->force;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
|
||||
DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
|
||||
connector->name,
|
||||
mode->name,
|
||||
mode->xres, mode->yres,
|
||||
mode->refresh_specified ? mode->refresh : 60,
|
||||
mode->rb ? " reduced blanking" : "",
|
||||
@ -1309,7 +1310,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
|
||||
if (!connector)
|
||||
return -ENOENT;
|
||||
|
||||
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
|
||||
drm_connector_for_each_possible_encoder(connector, encoder, i)
|
||||
if (connector->encoder_ids[i] != 0)
|
||||
encoders_count++;
|
||||
|
||||
|
@ -839,6 +839,7 @@ err_minors:
|
||||
drm_minor_unregister(dev, DRM_MINOR_CONTROL);
|
||||
out_unlock:
|
||||
mutex_unlock(&drm_global_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dev_register);
|
||||
@ -866,8 +867,6 @@ void drm_dev_unregister(struct drm_device *dev)
|
||||
|
||||
dev->registered = false;
|
||||
|
||||
drm_client_dev_unregister(dev);
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
drm_modeset_unregister_all(dev);
|
||||
|
||||
|
@ -158,17 +158,8 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor)
|
||||
goto out_prime_destroy;
|
||||
}
|
||||
|
||||
if (drm_is_primary_client(file)) {
|
||||
ret = drm_master_open(file);
|
||||
if (ret)
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
return file;
|
||||
|
||||
out_close:
|
||||
if (dev->driver->postclose)
|
||||
dev->driver->postclose(dev, file);
|
||||
out_prime_destroy:
|
||||
if (drm_core_check_feature(dev, DRIVER_PRIME))
|
||||
drm_prime_destroy_file_private(&file->prime);
|
||||
@ -373,6 +364,7 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
|
||||
{
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_file *priv;
|
||||
int ret = 0;
|
||||
|
||||
if (filp->f_flags & O_EXCL)
|
||||
return -EBUSY; /* No exclusive opens */
|
||||
@ -387,6 +379,14 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
|
||||
if (IS_ERR(priv))
|
||||
return PTR_ERR(priv);
|
||||
|
||||
if (drm_is_primary_client(priv)) {
|
||||
ret = drm_master_open(priv);
|
||||
if (ret) {
|
||||
drm_file_free(priv);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
filp->private_data = priv;
|
||||
filp->f_mode |= FMODE_UNSIGNED_OFFSET;
|
||||
priv->filp = filp;
|
||||
|
@ -940,6 +940,100 @@ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_duplicate);
|
||||
|
||||
static bool drm_mode_match_timings(const struct drm_display_mode *mode1,
|
||||
const struct drm_display_mode *mode2)
|
||||
{
|
||||
return mode1->hdisplay == mode2->hdisplay &&
|
||||
mode1->hsync_start == mode2->hsync_start &&
|
||||
mode1->hsync_end == mode2->hsync_end &&
|
||||
mode1->htotal == mode2->htotal &&
|
||||
mode1->hskew == mode2->hskew &&
|
||||
mode1->vdisplay == mode2->vdisplay &&
|
||||
mode1->vsync_start == mode2->vsync_start &&
|
||||
mode1->vsync_end == mode2->vsync_end &&
|
||||
mode1->vtotal == mode2->vtotal &&
|
||||
mode1->vscan == mode2->vscan;
|
||||
}
|
||||
|
||||
static bool drm_mode_match_clock(const struct drm_display_mode *mode1,
|
||||
const struct drm_display_mode *mode2)
|
||||
{
|
||||
/*
|
||||
* do clock check convert to PICOS
|
||||
* so fb modes get matched the same
|
||||
*/
|
||||
if (mode1->clock && mode2->clock)
|
||||
return KHZ2PICOS(mode1->clock) == KHZ2PICOS(mode2->clock);
|
||||
else
|
||||
return mode1->clock == mode2->clock;
|
||||
}
|
||||
|
||||
static bool drm_mode_match_flags(const struct drm_display_mode *mode1,
|
||||
const struct drm_display_mode *mode2)
|
||||
{
|
||||
return (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
|
||||
(mode2->flags & ~DRM_MODE_FLAG_3D_MASK);
|
||||
}
|
||||
|
||||
static bool drm_mode_match_3d_flags(const struct drm_display_mode *mode1,
|
||||
const struct drm_display_mode *mode2)
|
||||
{
|
||||
return (mode1->flags & DRM_MODE_FLAG_3D_MASK) ==
|
||||
(mode2->flags & DRM_MODE_FLAG_3D_MASK);
|
||||
}
|
||||
|
||||
static bool drm_mode_match_aspect_ratio(const struct drm_display_mode *mode1,
|
||||
const struct drm_display_mode *mode2)
|
||||
{
|
||||
return mode1->picture_aspect_ratio == mode2->picture_aspect_ratio;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_mode_match - test modes for (partial) equality
|
||||
* @mode1: first mode
|
||||
* @mode2: second mode
|
||||
* @match_flags: which parts need to match (DRM_MODE_MATCH_*)
|
||||
*
|
||||
* Check to see if @mode1 and @mode2 are equivalent.
|
||||
*
|
||||
* Returns:
|
||||
* True if the modes are (partially) equal, false otherwise.
|
||||
*/
|
||||
bool drm_mode_match(const struct drm_display_mode *mode1,
|
||||
const struct drm_display_mode *mode2,
|
||||
unsigned int match_flags)
|
||||
|
||||
{
|
||||
if (!mode1 && !mode2)
|
||||
return true;
|
||||
|
||||
if (!mode1 || !mode2)
|
||||
return false;
|
||||
|
||||
if (match_flags & DRM_MODE_MATCH_TIMINGS &&
|
||||
!drm_mode_match_timings(mode1, mode2))
|
||||
return false;
|
||||
|
||||
if (match_flags & DRM_MODE_MATCH_CLOCK &&
|
||||
!drm_mode_match_clock(mode1, mode2))
|
||||
return false;
|
||||
|
||||
if (match_flags & DRM_MODE_MATCH_FLAGS &&
|
||||
!drm_mode_match_flags(mode1, mode2))
|
||||
return false;
|
||||
|
||||
if (match_flags & DRM_MODE_MATCH_3D_FLAGS &&
|
||||
!drm_mode_match_3d_flags(mode1, mode2))
|
||||
return false;
|
||||
|
||||
if (match_flags & DRM_MODE_MATCH_ASPECT_RATIO &&
|
||||
!drm_mode_match_aspect_ratio(mode1, mode2))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_match);
|
||||
|
||||
/**
|
||||
* drm_mode_equal - test modes for equality
|
||||
* @mode1: first mode
|
||||
@ -950,23 +1044,14 @@ EXPORT_SYMBOL(drm_mode_duplicate);
|
||||
* Returns:
|
||||
* True if the modes are equal, false otherwise.
|
||||
*/
|
||||
bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
|
||||
bool drm_mode_equal(const struct drm_display_mode *mode1,
|
||||
const struct drm_display_mode *mode2)
|
||||
{
|
||||
if (!mode1 && !mode2)
|
||||
return true;
|
||||
|
||||
if (!mode1 || !mode2)
|
||||
return false;
|
||||
|
||||
/* do clock check convert to PICOS so fb modes get matched
|
||||
* the same */
|
||||
if (mode1->clock && mode2->clock) {
|
||||
if (KHZ2PICOS(mode1->clock) != KHZ2PICOS(mode2->clock))
|
||||
return false;
|
||||
} else if (mode1->clock != mode2->clock)
|
||||
return false;
|
||||
|
||||
return drm_mode_equal_no_clocks(mode1, mode2);
|
||||
return drm_mode_match(mode1, mode2,
|
||||
DRM_MODE_MATCH_TIMINGS |
|
||||
DRM_MODE_MATCH_CLOCK |
|
||||
DRM_MODE_MATCH_FLAGS |
|
||||
DRM_MODE_MATCH_3D_FLAGS);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_equal);
|
||||
|
||||
@ -981,13 +1066,13 @@ EXPORT_SYMBOL(drm_mode_equal);
|
||||
* Returns:
|
||||
* True if the modes are equal, false otherwise.
|
||||
*/
|
||||
bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
|
||||
bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1,
|
||||
const struct drm_display_mode *mode2)
|
||||
{
|
||||
if ((mode1->flags & DRM_MODE_FLAG_3D_MASK) !=
|
||||
(mode2->flags & DRM_MODE_FLAG_3D_MASK))
|
||||
return false;
|
||||
|
||||
return drm_mode_equal_no_clocks_no_stereo(mode1, mode2);
|
||||
return drm_mode_match(mode1, mode2,
|
||||
DRM_MODE_MATCH_TIMINGS |
|
||||
DRM_MODE_MATCH_FLAGS |
|
||||
DRM_MODE_MATCH_3D_FLAGS);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_equal_no_clocks);
|
||||
|
||||
@ -1005,21 +1090,9 @@ EXPORT_SYMBOL(drm_mode_equal_no_clocks);
|
||||
bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
|
||||
const struct drm_display_mode *mode2)
|
||||
{
|
||||
if (mode1->hdisplay == mode2->hdisplay &&
|
||||
mode1->hsync_start == mode2->hsync_start &&
|
||||
mode1->hsync_end == mode2->hsync_end &&
|
||||
mode1->htotal == mode2->htotal &&
|
||||
mode1->hskew == mode2->hskew &&
|
||||
mode1->vdisplay == mode2->vdisplay &&
|
||||
mode1->vsync_start == mode2->vsync_start &&
|
||||
mode1->vsync_end == mode2->vsync_end &&
|
||||
mode1->vtotal == mode2->vtotal &&
|
||||
mode1->vscan == mode2->vscan &&
|
||||
(mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
|
||||
(mode2->flags & ~DRM_MODE_FLAG_3D_MASK))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return drm_mode_match(mode1, mode2,
|
||||
DRM_MODE_MATCH_TIMINGS |
|
||||
DRM_MODE_MATCH_FLAGS);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
|
||||
|
||||
|
3527
drivers/gpu/drm/drm_splash.h
Normal file
3527
drivers/gpu/drm/drm_splash.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,7 @@
|
||||
#include <linux/extcon.h>
|
||||
#include <linux/soc/qcom/fsa4480-i2c.h>
|
||||
|
||||
#include <drm/drm_client.h>
|
||||
#include "sde_connector.h"
|
||||
|
||||
#include "msm_drv.h"
|
||||
@ -126,6 +127,12 @@ static const struct of_device_id dp_dt_match[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static void dp_display_update_hdcp_info(struct dp_display_private *dp);
|
||||
static bool dp_display_framework_ready(struct dp_display_private *dp)
|
||||
{
|
||||
return dp->dp_display.post_open ? false : true;
|
||||
}
|
||||
|
||||
static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp)
|
||||
{
|
||||
return dp->link->hdcp_status.hdcp_version && dp->hdcp.ops;
|
||||
@ -342,6 +349,13 @@ static void dp_display_hdcp_cb_work(struct work_struct *work)
|
||||
|
||||
dp = container_of(dw, struct dp_display_private, hdcp_cb_work);
|
||||
|
||||
dp_display_update_hdcp_info(dp);
|
||||
|
||||
if (!dp_display_is_hdcp_enabled(dp))
|
||||
return;
|
||||
|
||||
dp->link->hdcp_status.hdcp_state = HDCP_STATE_AUTHENTICATING;
|
||||
|
||||
if (!dp->power_on || !dp->is_connected || atomic_read(&dp->aborted) ||
|
||||
dp->hdcp_abort)
|
||||
return;
|
||||
@ -627,6 +641,36 @@ static void dp_display_send_hpd_event(struct dp_display_private *dp)
|
||||
envp);
|
||||
}
|
||||
|
||||
static void dp_display_post_open(struct dp_display *dp_display)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct dp_display_private *dp;
|
||||
|
||||
if (!dp_display) {
|
||||
pr_err("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dp = container_of(dp_display, struct dp_display_private, dp_display);
|
||||
if (IS_ERR_OR_NULL(dp)) {
|
||||
pr_err("invalid params\n");
|
||||
return;
|
||||
}
|
||||
|
||||
connector = dp->dp_display.base_connector;
|
||||
|
||||
if (!connector) {
|
||||
pr_err("connector not set\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* if cable is already connected, send notification */
|
||||
if (dp->hpd->hpd_high)
|
||||
queue_work(dp->wq, &dp->connect_work);
|
||||
else
|
||||
dp_display->post_open = NULL;
|
||||
}
|
||||
|
||||
static int dp_display_send_hpd_notification(struct dp_display_private *dp)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -639,6 +683,15 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp)
|
||||
else
|
||||
dp->dp_display.is_sst_connected = false;
|
||||
|
||||
if (!dp_display_framework_ready(dp)) {
|
||||
pr_debug("%s: dp display framework not ready\n", __func__);
|
||||
if (!dp->dp_display.is_bootsplash_en) {
|
||||
dp->dp_display.is_bootsplash_en = true;
|
||||
drm_client_dev_register(dp->dp_display.drm_dev);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
reinit_completion(&dp->notification_comp);
|
||||
dp_display_send_hpd_event(dp);
|
||||
|
||||
@ -1205,6 +1258,11 @@ static void dp_display_connect_work(struct work_struct *work)
|
||||
struct dp_display_private *dp = container_of(work,
|
||||
struct dp_display_private, connect_work);
|
||||
|
||||
if (dp->dp_display.is_sst_connected && dp_display_framework_ready(dp)) {
|
||||
pr_debug("HPD already on\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (atomic_read(&dp->aborted)) {
|
||||
pr_warn("HPD off requested\n");
|
||||
return;
|
||||
@ -1453,6 +1511,7 @@ error_ctrl:
|
||||
error_panel:
|
||||
dp_link_put(dp->link);
|
||||
error_link:
|
||||
dp->aux->drm_aux_deregister(dp->aux);
|
||||
dp_aux_put(dp->aux);
|
||||
error_aux:
|
||||
dp_power_put(dp->power);
|
||||
@ -2782,7 +2841,7 @@ static int dp_display_probe(struct platform_device *pdev)
|
||||
g_dp_display->unprepare = dp_display_unprepare;
|
||||
g_dp_display->request_irq = dp_request_irq;
|
||||
g_dp_display->get_debug = dp_get_debug;
|
||||
g_dp_display->post_open = NULL;
|
||||
g_dp_display->post_open = dp_display_post_open;
|
||||
g_dp_display->post_init = dp_display_post_init;
|
||||
g_dp_display->config_hdr = dp_display_config_hdr;
|
||||
g_dp_display->mst_install = dp_display_mst_install;
|
||||
|
@ -72,6 +72,7 @@ struct dp_display {
|
||||
u32 max_vdisplay;
|
||||
u32 no_mst_encoder;
|
||||
void *dp_mst_prv_info;
|
||||
bool is_bootsplash_en;
|
||||
|
||||
int (*enable)(struct dp_display *dp_display, void *panel);
|
||||
int (*post_enable)(struct dp_display *dp_display, void *panel);
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "msm_kms.h"
|
||||
#include "sde_wb.h"
|
||||
#include "sde_dbg.h"
|
||||
#include <drm/drm_client.h>
|
||||
|
||||
/*
|
||||
* MSM driver version:
|
||||
@ -311,6 +312,7 @@ static int msm_drm_uninit(struct device *dev)
|
||||
drm_mode_config_cleanup(ddev);
|
||||
|
||||
if (priv->registered) {
|
||||
drm_client_dev_unregister(ddev);
|
||||
drm_dev_unregister(ddev);
|
||||
priv->registered = false;
|
||||
}
|
||||
|
@ -2944,7 +2944,8 @@ static void sde_crtc_vblank_cb(void *data)
|
||||
sde_crtc->vblank_cb_count++;
|
||||
|
||||
sde_crtc->vblank_last_cb_time = ktime_get();
|
||||
sysfs_notify_dirent(sde_crtc->vsync_event_sf);
|
||||
if (sde_crtc->vsync_event_sf)
|
||||
sysfs_notify_dirent(sde_crtc->vsync_event_sf);
|
||||
|
||||
drm_crtc_handle_vblank(crtc);
|
||||
DRM_DEBUG_VBL("crtc%d\n", crtc->base.id);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -243,35 +243,34 @@ int cam_cdm_stream_ops_internal(void *hw_priv,
|
||||
return -EINVAL;
|
||||
|
||||
core = (struct cam_cdm *)cdm_hw->core_info;
|
||||
mutex_lock(&cdm_hw->hw_mutex);
|
||||
client_idx = CAM_CDM_GET_CLIENT_IDX(*handle);
|
||||
client = core->clients[client_idx];
|
||||
if (!client) {
|
||||
CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, *handle);
|
||||
mutex_unlock(&cdm_hw->hw_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
cam_cdm_get_client_refcount(client);
|
||||
if (*handle != client->handle) {
|
||||
CAM_ERR(CAM_CDM, "client id given handle=%x invalid", *handle);
|
||||
cam_cdm_put_client_refcount(client);
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
if (operation == true) {
|
||||
if (true == client->stream_on) {
|
||||
CAM_ERR(CAM_CDM,
|
||||
"Invalid CDM client is already streamed ON");
|
||||
cam_cdm_put_client_refcount(client);
|
||||
return rc;
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
if (client->stream_on == false) {
|
||||
CAM_ERR(CAM_CDM,
|
||||
"Invalid CDM client is already streamed Off");
|
||||
cam_cdm_put_client_refcount(client);
|
||||
return rc;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&cdm_hw->hw_mutex);
|
||||
if (operation == true) {
|
||||
if (!cdm_hw->open_count) {
|
||||
struct cam_ahb_vote ahb_vote;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2017-2018, 2021 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -27,6 +27,7 @@
|
||||
#include <media/cam_req_mgr.h>
|
||||
#include <media/cam_defs.h>
|
||||
#include <media/cam_icp.h>
|
||||
#include "cam_mem_mgr.h"
|
||||
#include "cam_req_mgr_dev.h"
|
||||
#include "cam_subdev.h"
|
||||
#include "cam_node.h"
|
||||
@ -95,10 +96,17 @@ static int cam_icp_subdev_open(struct v4l2_subdev *sd,
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = cam_mem_mgr_init();
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CRM, "mem mgr init failed");
|
||||
goto end;
|
||||
}
|
||||
|
||||
hw_mgr_intf = &node->hw_mgr_intf;
|
||||
rc = hw_mgr_intf->hw_open(hw_mgr_intf->hw_mgr_priv, NULL);
|
||||
if (rc < 0) {
|
||||
CAM_ERR(CAM_ICP, "FW download failed");
|
||||
cam_mem_mgr_deinit();
|
||||
goto end;
|
||||
}
|
||||
g_icp_dev.open_cnt++;
|
||||
@ -140,6 +148,7 @@ static int cam_icp_subdev_close(struct v4l2_subdev *sd,
|
||||
goto end;
|
||||
}
|
||||
|
||||
cam_mem_mgr_deinit();
|
||||
end:
|
||||
mutex_unlock(&g_icp_dev.icp_lock);
|
||||
return 0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -24,8 +24,11 @@
|
||||
#include "cam_smmu_api.h"
|
||||
#include "cam_debug_util.h"
|
||||
|
||||
static struct cam_mem_table tbl;
|
||||
static atomic_t cam_mem_mgr_state = ATOMIC_INIT(CAM_MEM_MGR_UNINITIALIZED);
|
||||
static struct cam_mem_table tbl = {
|
||||
.m_lock = __MUTEX_INITIALIZER(tbl.m_lock),
|
||||
};
|
||||
|
||||
static atomic_t cam_mem_mgr_refcnt = ATOMIC_INIT(0);
|
||||
|
||||
static int cam_mem_util_get_dma_dir(uint32_t flags)
|
||||
{
|
||||
@ -129,12 +132,27 @@ int cam_mem_mgr_init(void)
|
||||
int i;
|
||||
int bitmap_size;
|
||||
|
||||
mutex_lock(&tbl.m_lock);
|
||||
|
||||
if (atomic_inc_return(&cam_mem_mgr_refcnt) > 1) {
|
||||
CAM_DBG(CAM_MEM,
|
||||
"Mem mgr refcnt: %d",
|
||||
atomic_read(&cam_mem_mgr_refcnt));
|
||||
mutex_unlock(&tbl.m_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(tbl.bufq, 0, sizeof(tbl.bufq));
|
||||
|
||||
bitmap_size = BITS_TO_LONGS(CAM_MEM_BUFQ_MAX) * sizeof(long);
|
||||
tbl.bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
||||
if (!tbl.bitmap)
|
||||
if (!tbl.bitmap) {
|
||||
atomic_dec(&cam_mem_mgr_refcnt);
|
||||
CAM_DBG(CAM_MEM, "Mem mgr refcnt: %d",
|
||||
atomic_read(&cam_mem_mgr_refcnt));
|
||||
mutex_unlock(&tbl.m_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tbl.bits = bitmap_size * BITS_PER_BYTE;
|
||||
bitmap_zero(tbl.bitmap, tbl.bits);
|
||||
@ -145,9 +163,8 @@ int cam_mem_mgr_init(void)
|
||||
tbl.bufq[i].fd = -1;
|
||||
tbl.bufq[i].buf_handle = -1;
|
||||
}
|
||||
mutex_init(&tbl.m_lock);
|
||||
|
||||
atomic_set(&cam_mem_mgr_state, CAM_MEM_MGR_INITIALIZED);
|
||||
mutex_unlock(&tbl.m_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -189,7 +206,7 @@ int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle,
|
||||
|
||||
*len_ptr = 0;
|
||||
|
||||
if (!atomic_read(&cam_mem_mgr_state)) {
|
||||
if (!atomic_read(&cam_mem_mgr_refcnt)) {
|
||||
CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -240,7 +257,7 @@ int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, size_t *len)
|
||||
int idx;
|
||||
struct dma_buf *dmabuf = NULL;
|
||||
|
||||
if (!atomic_read(&cam_mem_mgr_state)) {
|
||||
if (!atomic_read(&cam_mem_mgr_refcnt)) {
|
||||
CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -306,7 +323,7 @@ int cam_mem_put_cpu_buf(int32_t buf_handle)
|
||||
int idx;
|
||||
struct dma_buf *dmabuf = NULL;
|
||||
|
||||
if (!atomic_read(&cam_mem_mgr_state)) {
|
||||
if (!atomic_read(&cam_mem_mgr_refcnt)) {
|
||||
CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -360,7 +377,7 @@ int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd)
|
||||
uint32_t cache_dir;
|
||||
unsigned long dmabuf_flag = 0;
|
||||
|
||||
if (!atomic_read(&cam_mem_mgr_state)) {
|
||||
if (!atomic_read(&cam_mem_mgr_refcnt)) {
|
||||
CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -664,7 +681,7 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd)
|
||||
uintptr_t kvaddr = 0;
|
||||
size_t klen;
|
||||
|
||||
if (!atomic_read(&cam_mem_mgr_state)) {
|
||||
if (!atomic_read(&cam_mem_mgr_refcnt)) {
|
||||
CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -786,7 +803,7 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd)
|
||||
dma_addr_t hw_vaddr = 0;
|
||||
size_t len = 0;
|
||||
|
||||
if (!atomic_read(&cam_mem_mgr_state)) {
|
||||
if (!atomic_read(&cam_mem_mgr_refcnt)) {
|
||||
CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -957,7 +974,6 @@ static int cam_mem_mgr_cleanup_table(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&tbl.m_lock);
|
||||
for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) {
|
||||
if (!tbl.bufq[i].active) {
|
||||
CAM_DBG(CAM_MEM,
|
||||
@ -993,21 +1009,25 @@ static int cam_mem_mgr_cleanup_table(void)
|
||||
bitmap_zero(tbl.bitmap, tbl.bits);
|
||||
/* We need to reserve slot 0 because 0 is invalid */
|
||||
set_bit(0, tbl.bitmap);
|
||||
mutex_unlock(&tbl.m_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cam_mem_mgr_deinit(void)
|
||||
{
|
||||
atomic_set(&cam_mem_mgr_state, CAM_MEM_MGR_UNINITIALIZED);
|
||||
cam_mem_mgr_cleanup_table();
|
||||
mutex_lock(&tbl.m_lock);
|
||||
if (!atomic_dec_and_test(&cam_mem_mgr_refcnt)) {
|
||||
CAM_DBG(CAM_MEM, "Mem mgr refcnt: %d",
|
||||
atomic_read(&cam_mem_mgr_refcnt));
|
||||
mutex_unlock(&tbl.m_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
cam_mem_mgr_cleanup_table();
|
||||
bitmap_zero(tbl.bitmap, tbl.bits);
|
||||
kfree(tbl.bitmap);
|
||||
tbl.bitmap = NULL;
|
||||
mutex_unlock(&tbl.m_lock);
|
||||
mutex_destroy(&tbl.m_lock);
|
||||
}
|
||||
|
||||
static int cam_mem_util_unmap(int32_t idx,
|
||||
@ -1098,7 +1118,7 @@ int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd)
|
||||
int idx;
|
||||
int rc;
|
||||
|
||||
if (!atomic_read(&cam_mem_mgr_state)) {
|
||||
if (!atomic_read(&cam_mem_mgr_refcnt)) {
|
||||
CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1151,7 +1171,7 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp,
|
||||
|
||||
enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED;
|
||||
|
||||
if (!atomic_read(&cam_mem_mgr_state)) {
|
||||
if (!atomic_read(&cam_mem_mgr_refcnt)) {
|
||||
CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1276,7 +1296,7 @@ int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp)
|
||||
int32_t idx;
|
||||
int rc;
|
||||
|
||||
if (!atomic_read(&cam_mem_mgr_state)) {
|
||||
if (!atomic_read(&cam_mem_mgr_refcnt)) {
|
||||
CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1329,7 +1349,7 @@ int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp,
|
||||
int32_t smmu_hdl = 0;
|
||||
int32_t num_hdl = 0;
|
||||
|
||||
if (!atomic_read(&cam_mem_mgr_state)) {
|
||||
if (!atomic_read(&cam_mem_mgr_refcnt)) {
|
||||
CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1423,7 +1443,7 @@ int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp)
|
||||
int rc;
|
||||
int32_t smmu_hdl;
|
||||
|
||||
if (!atomic_read(&cam_mem_mgr_state)) {
|
||||
if (!atomic_read(&cam_mem_mgr_refcnt)) {
|
||||
CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2016-2019, 2021 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -20,12 +20,6 @@
|
||||
|
||||
#define CAM_MEM_BUFQ_MAX 1024
|
||||
|
||||
/* Enum for possible mem mgr states */
|
||||
enum cam_mem_mgr_state {
|
||||
CAM_MEM_MGR_UNINITIALIZED,
|
||||
CAM_MEM_MGR_INITIALIZED,
|
||||
};
|
||||
|
||||
/*Enum for possible SMMU operations */
|
||||
enum cam_smmu_mapping_client {
|
||||
CAM_SMMU_MAPPING_USER,
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -128,21 +128,6 @@ static int32_t cam_get_free_handle_index(void)
|
||||
return idx;
|
||||
}
|
||||
|
||||
static void cam_dump_tbl_info(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CAM_REQ_MGR_MAX_HANDLES; i++)
|
||||
CAM_INFO(CAM_CRM, "session_hdl=%x hdl_value=%x\n"
|
||||
"type=%d state=%d dev_id=%lld",
|
||||
hdl_tbl->hdl[i].session_hdl,
|
||||
hdl_tbl->hdl[i].hdl_value,
|
||||
hdl_tbl->hdl[i].type,
|
||||
hdl_tbl->hdl[i].state,
|
||||
hdl_tbl->hdl[i].dev_id);
|
||||
|
||||
}
|
||||
|
||||
int32_t cam_create_session_hdl(void *priv)
|
||||
{
|
||||
int idx;
|
||||
@ -159,7 +144,6 @@ int32_t cam_create_session_hdl(void *priv)
|
||||
idx = cam_get_free_handle_index();
|
||||
if (idx < 0) {
|
||||
CAM_ERR(CAM_CRM, "Unable to create session handle");
|
||||
cam_dump_tbl_info();
|
||||
spin_unlock_bh(&hdl_tbl_lock);
|
||||
return idx;
|
||||
}
|
||||
@ -193,7 +177,6 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data)
|
||||
idx = cam_get_free_handle_index();
|
||||
if (idx < 0) {
|
||||
CAM_ERR(CAM_CRM, "Unable to create device handle");
|
||||
cam_dump_tbl_info();
|
||||
spin_unlock_bh(&hdl_tbl_lock);
|
||||
return idx;
|
||||
}
|
||||
|
@ -485,6 +485,7 @@ static int ipa_uc_ntn_alloc_conn_smmu_info(struct ipa_ntn_setup_info *dest,
|
||||
source->buff_pool_base_sgt);
|
||||
if (result) {
|
||||
kfree(dest->data_buff_list);
|
||||
dest->data_buff_list = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -492,6 +493,7 @@ static int ipa_uc_ntn_alloc_conn_smmu_info(struct ipa_ntn_setup_info *dest,
|
||||
source->ring_base_sgt);
|
||||
if (result) {
|
||||
kfree(dest->data_buff_list);
|
||||
dest->data_buff_list = NULL;
|
||||
ipa_smmu_free_sgt(&dest->buff_pool_base_sgt);
|
||||
return result;
|
||||
}
|
||||
@ -502,6 +504,7 @@ static int ipa_uc_ntn_alloc_conn_smmu_info(struct ipa_ntn_setup_info *dest,
|
||||
static void ipa_uc_ntn_free_conn_smmu_info(struct ipa_ntn_setup_info *params)
|
||||
{
|
||||
kfree(params->data_buff_list);
|
||||
params->data_buff_list = NULL;
|
||||
ipa_smmu_free_sgt(¶ms->buff_pool_base_sgt);
|
||||
ipa_smmu_free_sgt(¶ms->ring_base_sgt);
|
||||
}
|
||||
|
@ -381,6 +381,7 @@ static void ipa3_active_clients_log_destroy(void)
|
||||
kfree(active_clients_table_buf);
|
||||
active_clients_table_buf = NULL;
|
||||
kfree(ipa3_ctx->ipa3_active_clients_logging.log_buffer[0]);
|
||||
ipa3_ctx->ipa3_active_clients_logging.log_buffer[0] = NULL;
|
||||
ipa3_ctx->ipa3_active_clients_logging.log_head = 0;
|
||||
ipa3_ctx->ipa3_active_clients_logging.log_tail =
|
||||
IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1;
|
||||
@ -7574,8 +7575,10 @@ fail_bus_reg:
|
||||
fail_init_mem_partition:
|
||||
fail_bind:
|
||||
kfree(ipa3_ctx->ctrl);
|
||||
ipa3_ctx->ctrl = NULL;
|
||||
fail_mem_ctrl:
|
||||
kfree(ipa3_ctx->ipa_tz_unlock_reg);
|
||||
ipa3_ctx->ipa_tz_unlock_reg = NULL;
|
||||
fail_tz_unlock_reg:
|
||||
if (ipa3_ctx->logbuf)
|
||||
ipc_log_context_destroy(ipa3_ctx->logbuf);
|
||||
@ -8015,6 +8018,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
|
||||
IPAERR("failed to read register addresses\n");
|
||||
kfree(ipa_tz_unlock_reg);
|
||||
kfree(ipa_drv_res->ipa_tz_unlock_reg);
|
||||
ipa_drv_res->ipa_tz_unlock_reg = NULL;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
|
@ -1264,10 +1264,12 @@ fail_repl:
|
||||
ep->sys->repl_hdlr = ipa3_replenish_rx_cache;
|
||||
ep->sys->repl->capacity = 0;
|
||||
kfree(ep->sys->repl);
|
||||
ep->sys->repl = NULL;
|
||||
fail_page_recycle_repl:
|
||||
if (ep->sys->page_recycle_repl) {
|
||||
ep->sys->page_recycle_repl->capacity = 0;
|
||||
kfree(ep->sys->page_recycle_repl);
|
||||
ep->sys->page_recycle_repl = NULL;
|
||||
}
|
||||
fail_gen2:
|
||||
if (ipa3_ctx->use_ipa_pm)
|
||||
@ -2654,6 +2656,7 @@ static void ipa3_cleanup_rx(struct ipa3_sys_context *sys)
|
||||
|
||||
kfree(sys->repl->cache);
|
||||
kfree(sys->repl);
|
||||
sys->repl = NULL;
|
||||
}
|
||||
if (sys->page_recycle_repl) {
|
||||
for (i = 0; i < sys->page_recycle_repl->capacity; i++) {
|
||||
@ -2672,6 +2675,7 @@ static void ipa3_cleanup_rx(struct ipa3_sys_context *sys)
|
||||
}
|
||||
kfree(sys->page_recycle_repl->cache);
|
||||
kfree(sys->page_recycle_repl);
|
||||
sys->page_recycle_repl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -777,6 +777,7 @@ alloc_chrdev0_region_fail:
|
||||
class_destroy(odl_cdev[0].class);
|
||||
create_char_dev0_fail:
|
||||
kfree(ipa3_odl_ctx);
|
||||
ipa3_odl_ctx = NULL;
|
||||
fail_mem_ctx:
|
||||
return result;
|
||||
}
|
||||
|
@ -637,6 +637,7 @@ int ipa_pm_init(struct ipa_pm_init_params *params)
|
||||
if (!ipa_pm_ctx->wq) {
|
||||
IPA_PM_ERR("create workqueue failed\n");
|
||||
kfree(ipa_pm_ctx);
|
||||
ipa_pm_ctx = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -759,6 +759,7 @@ static void ipa_release_ap_smmu_mappings(enum ipa_client_type client)
|
||||
ipa3_ctx->wdi_map_cnt--;
|
||||
}
|
||||
kfree(wdi_res[i].res);
|
||||
wdi_res[i].res = NULL;
|
||||
wdi_res[i].valid = false;
|
||||
}
|
||||
}
|
||||
@ -795,6 +796,7 @@ static void ipa_release_uc_smmu_mappings(enum ipa_client_type client)
|
||||
ipa3_ctx->wdi_map_cnt--;
|
||||
}
|
||||
kfree(wdi_res[i].res);
|
||||
wdi_res[i].res = NULL;
|
||||
wdi_res[i].valid = false;
|
||||
}
|
||||
}
|
||||
@ -946,6 +948,7 @@ void ipa3_release_wdi3_gsi_smmu_mappings(u8 dir)
|
||||
ipa3_ctx->wdi_map_cnt--;
|
||||
}
|
||||
kfree(wdi_res[i].res);
|
||||
wdi_res[i].res = NULL;
|
||||
wdi_res[i].valid = false;
|
||||
}
|
||||
}
|
||||
|
@ -175,6 +175,8 @@ int ion_hyp_assign_sg(struct sg_table *sgt, int *dest_vm_list,
|
||||
if (dest_vm_list[i] == VMID_CP_SEC_DISPLAY ||
|
||||
dest_vm_list[i] == VMID_CP_DSP_EXT)
|
||||
dest_perms[i] = PERM_READ;
|
||||
else if (dest_vm_list[i] == VMID_CP_CDSP)
|
||||
dest_perms[i] = PERM_READ | PERM_WRITE | PERM_EXEC;
|
||||
else if (dest_vm_list[i] == VMID_CP_CAMERA_ENCODE) {
|
||||
j = i;
|
||||
dest_perms[i] = PERM_READ | PERM_WRITE;
|
||||
@ -305,6 +307,8 @@ int ion_hyp_assign_from_flags(u64 base, u64 size, unsigned long flags)
|
||||
if (vmids[i] == VMID_CP_SEC_DISPLAY ||
|
||||
vmids[i] == VMID_CP_DSP_EXT)
|
||||
modes[i] = PERM_READ;
|
||||
else if (vmids[i] == VMID_CP_CDSP)
|
||||
modes[i] = PERM_READ | PERM_WRITE | PERM_EXEC;
|
||||
else
|
||||
modes[i] = PERM_READ | PERM_WRITE;
|
||||
|
||||
|
@ -136,7 +136,7 @@ static char sensor_clients[QMI_TS_MAX_NR][QMI_CLIENT_NAME_LENGTH] = {
|
||||
static int32_t encode_qmi(int32_t val)
|
||||
{
|
||||
uint32_t shift = 0, local_val = 0;
|
||||
int32_t temp_val = 0;
|
||||
unsigned long temp_val = 0;
|
||||
|
||||
if (val == INT_MAX || val == INT_MIN)
|
||||
return 0;
|
||||
@ -146,8 +146,7 @@ static int32_t encode_qmi(int32_t val)
|
||||
temp_val *= -1;
|
||||
local_val |= 1 << QMI_FL_SIGN_BIT;
|
||||
}
|
||||
shift = find_last_bit((const unsigned long *)&temp_val,
|
||||
sizeof(temp_val) * 8);
|
||||
shift = find_last_bit(&temp_val, sizeof(temp_val) * 8);
|
||||
local_val |= ((shift + 127) << QMI_MANTISSA_MSB);
|
||||
temp_val &= ~(1 << shift);
|
||||
|
||||
@ -291,6 +290,13 @@ static int qmi_ts_request(struct qmi_sensor *qmi_sens,
|
||||
qmi_sens->low_thresh != INT_MIN;
|
||||
req.temp_threshold_low =
|
||||
encode_qmi(qmi_sens->low_thresh);
|
||||
|
||||
pr_debug("Sensor:%s set high_trip:%d, low_trip:%d, high_valid:%d, low_valid:%d\n",
|
||||
qmi_sens->qmi_name,
|
||||
qmi_sens->high_thresh,
|
||||
qmi_sens->low_thresh,
|
||||
req.temp_threshold_high_valid,
|
||||
req.temp_threshold_low_valid);
|
||||
}
|
||||
|
||||
mutex_lock(&ts->mutex);
|
||||
|
@ -2097,9 +2097,6 @@ static void msm_hs_config_port(struct uart_port *uport, int cfg_flags)
|
||||
/* Handle CTS changes (Called from interrupt handler) */
|
||||
static void msm_hs_handle_delta_cts_locked(struct uart_port *uport)
|
||||
{
|
||||
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
|
||||
|
||||
msm_hs_resource_vote(msm_uport);
|
||||
/* clear interrupt */
|
||||
msm_hs_write(uport, UART_DM_CR, RESET_CTS);
|
||||
/* Calling CLOCK API. Hence mb() requires here. */
|
||||
@ -2108,7 +2105,6 @@ static void msm_hs_handle_delta_cts_locked(struct uart_port *uport)
|
||||
|
||||
/* clear the IOCTL TIOCMIWAIT if called */
|
||||
wake_up_interruptible(&uport->state->port.delta_msr_wait);
|
||||
msm_hs_resource_unvote(msm_uport);
|
||||
}
|
||||
|
||||
static irqreturn_t msm_hs_isr(int irq, void *dev)
|
||||
|
@ -36,6 +36,7 @@ struct drm_atomic_state;
|
||||
struct drm_private_obj;
|
||||
struct drm_private_state;
|
||||
|
||||
#ifdef CONFIG_DRM_KMS_HELPER
|
||||
int drm_atomic_helper_check_modeset(struct drm_device *dev,
|
||||
struct drm_atomic_state *state);
|
||||
int drm_atomic_helper_check_planes(struct drm_device *dev,
|
||||
@ -179,6 +180,29 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
|
||||
struct drm_modeset_acquire_ctx *ctx);
|
||||
void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
|
||||
struct drm_private_state *state);
|
||||
#else
|
||||
int drm_atomic_helper_disable_plane(struct drm_plane *plane,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_atomic_helper_set_config(struct drm_mode_set *set,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int __drm_atomic_helper_set_config(struct drm_mode_set *set,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
|
||||
|
@ -17,8 +17,6 @@ struct drm_gem_object;
|
||||
struct drm_minor;
|
||||
struct module;
|
||||
|
||||
#define DRM_CLIENT_MAX_CLONED_CONNECTORS 8
|
||||
|
||||
/**
|
||||
* struct drm_client_funcs - DRM client callbacks
|
||||
*/
|
||||
@ -106,7 +104,9 @@ struct drm_client_dev {
|
||||
int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
|
||||
const char *name, const struct drm_client_funcs *funcs);
|
||||
void drm_client_register(struct drm_client_dev *client);
|
||||
void drm_client_release(struct drm_client_dev *client);
|
||||
|
||||
void drm_client_dev_register(struct drm_device *dev);
|
||||
void drm_client_dev_unregister(struct drm_device *dev);
|
||||
void drm_client_dev_hotplug(struct drm_device *dev);
|
||||
void drm_client_dev_restore(struct drm_device *dev);
|
||||
@ -149,11 +149,19 @@ struct drm_client_buffer {
|
||||
struct drm_client_buffer *
|
||||
drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format);
|
||||
void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
|
||||
void *drm_client_buffer_vmap(struct drm_client_buffer *buffer);
|
||||
void drm_client_buffer_vunmap(struct drm_client_buffer *buffer);
|
||||
|
||||
int drm_client_modeset_create(struct drm_client_dev *client);
|
||||
void drm_client_modeset_free(struct drm_client_dev *client);
|
||||
void drm_client_modeset_release(struct drm_client_dev *client);
|
||||
struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc);
|
||||
int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height);
|
||||
int drm_client_modeset_commit_force(struct drm_client_dev *client);
|
||||
int drm_client_modeset_commit(struct drm_client_dev *client);
|
||||
int drm_client_modeset_dpms(struct drm_client_dev *client, int mode);
|
||||
|
||||
#ifdef CONFIG_DRM_CLIENT_BOOTSPLASH
|
||||
void drm_bootsplash_client_register(struct drm_device *dev);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* drm_client_for_each_modeset() - Iterate over client modesets
|
||||
@ -164,6 +172,21 @@ struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, stru
|
||||
for (({ lockdep_assert_held(&(client)->modeset_mutex); }), \
|
||||
modeset = (client)->modesets; modeset->crtc; modeset++)
|
||||
|
||||
/**
|
||||
* drm_client_for_each_connector_iter - connector_list iterator macro
|
||||
* @connector: &struct drm_connector pointer used as cursor
|
||||
* @iter: &struct drm_connector_list_iter
|
||||
*
|
||||
* This iterates the connectors that are useable for internal clients (excludes
|
||||
* writeback connectors).
|
||||
*
|
||||
* For more info see drm_for_each_connector_iter().
|
||||
*/
|
||||
#define drm_client_for_each_connector_iter(connector, iter) \
|
||||
drm_for_each_connector_iter(connector, iter) \
|
||||
if ((connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)\
|
||||
&& (connector->connector_type != DRM_MODE_CONNECTOR_VIRTUAL))
|
||||
|
||||
int drm_client_debugfs_init(struct drm_minor *minor);
|
||||
|
||||
#endif
|
||||
|
@ -657,6 +657,12 @@ struct drm_connector_funcs {
|
||||
|
||||
/* mode specified on the command line */
|
||||
struct drm_cmdline_mode {
|
||||
/**
|
||||
* @name:
|
||||
*
|
||||
* Name of the mode.
|
||||
*/
|
||||
char name[DRM_DISPLAY_MODE_LEN];
|
||||
bool specified;
|
||||
bool refresh_specified;
|
||||
bool bpp_specified;
|
||||
@ -1103,4 +1109,17 @@ void drm_connector_list_iter_end(struct drm_connector_list_iter *iter);
|
||||
#define drm_for_each_connector_iter(connector, iter) \
|
||||
while ((connector = drm_connector_list_iter_next(iter)))
|
||||
|
||||
/**
|
||||
* drm_connector_for_each_possible_encoder - iterate connector's possible encoders
|
||||
* @connector: &struct drm_connector pointer
|
||||
* @encoder: &struct drm_encoder pointer used as cursor
|
||||
* @__i: int iteration cursor, for macro-internal use
|
||||
*/
|
||||
#define drm_connector_for_each_possible_encoder(connector, encoder, __i) \
|
||||
for ((__i) = 0; (__i) < ARRAY_SIZE((connector)->encoder_ids) && \
|
||||
(connector)->encoder_ids[(__i)] != 0; (__i)++) \
|
||||
for_each_if((encoder) = \
|
||||
drm_encoder_find((connector)->dev, NULL, \
|
||||
(connector)->encoder_ids[(__i)])) \
|
||||
|
||||
#endif
|
||||
|
@ -150,6 +150,12 @@ enum drm_mode_status {
|
||||
|
||||
#define DRM_MODE_FLAG_3D_MAX DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF
|
||||
|
||||
#define DRM_MODE_MATCH_TIMINGS (1 << 0)
|
||||
#define DRM_MODE_MATCH_CLOCK (1 << 1)
|
||||
#define DRM_MODE_MATCH_FLAGS (1 << 2)
|
||||
#define DRM_MODE_MATCH_3D_FLAGS (1 << 3)
|
||||
#define DRM_MODE_MATCH_ASPECT_RATIO (1 << 4)
|
||||
|
||||
/**
|
||||
* struct drm_display_mode - DRM kernel-internal display mode structure
|
||||
* @hdisplay: horizontal display size
|
||||
@ -493,6 +499,9 @@ void drm_mode_copy(struct drm_display_mode *dst,
|
||||
const struct drm_display_mode *src);
|
||||
struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
|
||||
const struct drm_display_mode *mode);
|
||||
bool drm_mode_match(const struct drm_display_mode *mode1,
|
||||
const struct drm_display_mode *mode2,
|
||||
unsigned int match_flags);
|
||||
bool drm_mode_equal(const struct drm_display_mode *mode1,
|
||||
const struct drm_display_mode *mode2);
|
||||
bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1,
|
||||
|
@ -92,6 +92,7 @@ enum {
|
||||
|
||||
CFTYPE_NO_PREFIX = (1 << 3), /* (DON'T USE FOR NEW FILES) no subsys prefix */
|
||||
CFTYPE_WORLD_WRITABLE = (1 << 4), /* (DON'T USE FOR NEW FILES) S_IWUGO */
|
||||
CFTYPE_PRESSURE = (1 << 6), /* only if pressure feature is enabled */
|
||||
|
||||
/* internal flags, do not use outside cgroup core proper */
|
||||
__CFTYPE_ONLY_ON_DFL = (1 << 16), /* only on default hierarchy */
|
||||
|
@ -643,6 +643,8 @@ static inline struct psi_group *cgroup_psi(struct cgroup *cgrp)
|
||||
return &cgrp->psi;
|
||||
}
|
||||
|
||||
bool cgroup_psi_enabled(void);
|
||||
|
||||
static inline void cgroup_init_kthreadd(void)
|
||||
{
|
||||
/*
|
||||
@ -707,6 +709,11 @@ static inline struct psi_group *cgroup_psi(struct cgroup *cgrp)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool cgroup_psi_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool task_under_cgroup_hierarchy(struct task_struct *task,
|
||||
struct cgroup *ancestor)
|
||||
{
|
||||
|
@ -322,6 +322,7 @@ enum drm_mode_subconnector {
|
||||
#define DRM_MODE_CONNECTOR_VIRTUAL 15
|
||||
#define DRM_MODE_CONNECTOR_DSI 16
|
||||
#define DRM_MODE_CONNECTOR_DPI 17
|
||||
#define DRM_MODE_CONNECTOR_WRITEBACK 18
|
||||
|
||||
struct drm_mode_get_connector {
|
||||
|
||||
|
@ -203,6 +203,22 @@ struct cgroup_namespace init_cgroup_ns = {
|
||||
static struct file_system_type cgroup2_fs_type;
|
||||
static struct cftype cgroup_base_files[];
|
||||
|
||||
/* cgroup optional features */
|
||||
enum cgroup_opt_features {
|
||||
#ifdef CONFIG_PSI
|
||||
OPT_FEATURE_PRESSURE,
|
||||
#endif
|
||||
OPT_FEATURE_COUNT
|
||||
};
|
||||
|
||||
static const char *cgroup_opt_feature_names[OPT_FEATURE_COUNT] = {
|
||||
#ifdef CONFIG_PSI
|
||||
"pressure",
|
||||
#endif
|
||||
};
|
||||
|
||||
static u16 cgroup_feature_disable_mask __read_mostly;
|
||||
|
||||
static int cgroup_apply_control(struct cgroup *cgrp);
|
||||
static void cgroup_finalize_control(struct cgroup *cgrp, int ret);
|
||||
static void css_task_iter_skip(struct css_task_iter *it,
|
||||
@ -3413,6 +3429,18 @@ static void cgroup_pressure_release(struct kernfs_open_file *of)
|
||||
{
|
||||
psi_trigger_replace(&of->priv, NULL);
|
||||
}
|
||||
|
||||
bool cgroup_psi_enabled(void)
|
||||
{
|
||||
return (cgroup_feature_disable_mask & (1 << OPT_FEATURE_PRESSURE)) == 0;
|
||||
}
|
||||
|
||||
#else /* CONFIG_PSI */
|
||||
bool cgroup_psi_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PSI */
|
||||
|
||||
static int cgroup_file_open(struct kernfs_open_file *of)
|
||||
@ -3617,6 +3645,8 @@ static int cgroup_addrm_files(struct cgroup_subsys_state *css,
|
||||
restart:
|
||||
for (cft = cfts; cft != cft_end && cft->name[0] != '\0'; cft++) {
|
||||
/* does cft->flags tell us to skip this file on @cgrp? */
|
||||
if ((cft->flags & CFTYPE_PRESSURE) && !cgroup_psi_enabled())
|
||||
continue;
|
||||
if ((cft->flags & __CFTYPE_ONLY_ON_DFL) && !cgroup_on_dfl(cgrp))
|
||||
continue;
|
||||
if ((cft->flags & __CFTYPE_NOT_ON_DFL) && cgroup_on_dfl(cgrp))
|
||||
@ -3693,6 +3723,9 @@ static int cgroup_init_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
|
||||
|
||||
WARN_ON(cft->ss || cft->kf_ops);
|
||||
|
||||
if ((cft->flags & CFTYPE_PRESSURE) && !cgroup_psi_enabled())
|
||||
continue;
|
||||
|
||||
if (cft->seq_start)
|
||||
kf_ops = &cgroup_kf_ops;
|
||||
else
|
||||
@ -4587,7 +4620,7 @@ static struct cftype cgroup_base_files[] = {
|
||||
#ifdef CONFIG_PSI
|
||||
{
|
||||
.name = "io.pressure",
|
||||
.flags = CFTYPE_NOT_ON_ROOT,
|
||||
.flags = CFTYPE_NOT_ON_ROOT | CFTYPE_PRESSURE,
|
||||
.seq_show = cgroup_io_pressure_show,
|
||||
.write = cgroup_io_pressure_write,
|
||||
.poll = cgroup_pressure_poll,
|
||||
@ -4595,7 +4628,7 @@ static struct cftype cgroup_base_files[] = {
|
||||
},
|
||||
{
|
||||
.name = "memory.pressure",
|
||||
.flags = CFTYPE_NOT_ON_ROOT,
|
||||
.flags = CFTYPE_NOT_ON_ROOT | CFTYPE_PRESSURE,
|
||||
.seq_show = cgroup_memory_pressure_show,
|
||||
.write = cgroup_memory_pressure_write,
|
||||
.poll = cgroup_pressure_poll,
|
||||
@ -4603,7 +4636,7 @@ static struct cftype cgroup_base_files[] = {
|
||||
},
|
||||
{
|
||||
.name = "cpu.pressure",
|
||||
.flags = CFTYPE_NOT_ON_ROOT,
|
||||
.flags = CFTYPE_NOT_ON_ROOT | CFTYPE_PRESSURE,
|
||||
.seq_show = cgroup_cpu_pressure_show,
|
||||
.write = cgroup_cpu_pressure_write,
|
||||
.poll = cgroup_pressure_poll,
|
||||
@ -5770,6 +5803,15 @@ static int __init cgroup_disable(char *str)
|
||||
continue;
|
||||
cgroup_disable_mask |= 1 << i;
|
||||
}
|
||||
|
||||
for (i = 0; i < OPT_FEATURE_COUNT; i++) {
|
||||
if (strcmp(token, cgroup_opt_feature_names[i]))
|
||||
continue;
|
||||
cgroup_feature_disable_mask |= 1 << i;
|
||||
pr_info("Disabling %s control group feature\n",
|
||||
cgroup_opt_feature_names[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -146,6 +146,7 @@
|
||||
static int psi_bug __read_mostly;
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(psi_disabled);
|
||||
DEFINE_STATIC_KEY_TRUE(psi_cgroups_enabled);
|
||||
|
||||
#ifdef CONFIG_PSI_DEFAULT_DISABLED
|
||||
static bool psi_enable;
|
||||
@ -210,6 +211,9 @@ void __init psi_init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cgroup_psi_enabled())
|
||||
static_branch_disable(&psi_cgroups_enabled);
|
||||
|
||||
psi_period = jiffies_to_nsecs(PSI_FREQ);
|
||||
group_init(&psi_system);
|
||||
}
|
||||
@ -723,23 +727,23 @@ static u32 psi_group_change(struct psi_group *group, int cpu,
|
||||
|
||||
static struct psi_group *iterate_groups(struct task_struct *task, void **iter)
|
||||
{
|
||||
if (*iter == &psi_system)
|
||||
return NULL;
|
||||
|
||||
#ifdef CONFIG_CGROUPS
|
||||
struct cgroup *cgroup = NULL;
|
||||
if (static_branch_likely(&psi_cgroups_enabled)) {
|
||||
struct cgroup *cgroup = NULL;
|
||||
|
||||
if (!*iter)
|
||||
cgroup = task->cgroups->dfl_cgrp;
|
||||
else if (*iter == &psi_system)
|
||||
return NULL;
|
||||
else
|
||||
cgroup = cgroup_parent(*iter);
|
||||
if (!*iter)
|
||||
cgroup = task->cgroups->dfl_cgrp;
|
||||
else
|
||||
cgroup = cgroup_parent(*iter);
|
||||
|
||||
if (cgroup && cgroup_parent(cgroup)) {
|
||||
*iter = cgroup;
|
||||
return cgroup_psi(cgroup);
|
||||
if (cgroup && cgroup_parent(cgroup)) {
|
||||
*iter = cgroup;
|
||||
return cgroup_psi(cgroup);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (*iter)
|
||||
return NULL;
|
||||
#endif
|
||||
*iter = &psi_system;
|
||||
return &psi_system;
|
||||
|
@ -2654,7 +2654,7 @@ sub process {
|
||||
"email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr);
|
||||
}
|
||||
}
|
||||
if ($chk_author && $line =~ /^\s*signed-off-by:.*(quicinc|qualcomm)\.com/i) {
|
||||
if ($chk_author && $line =~ /^\s*signed-off-by:.*(qualcomm)\.com/i) {
|
||||
WARN("BAD_SIGN_OFF",
|
||||
"invalid Signed-off-by identity\n" . $line );
|
||||
}
|
||||
@ -2787,7 +2787,7 @@ sub process {
|
||||
}
|
||||
|
||||
#check the patch for invalid author credentials
|
||||
if ($chk_author && $line =~ /^From:.*(quicinc|qualcomm)\.com/) {
|
||||
if ($chk_author && $line =~ /^From:.*(qualcomm)\.com/) {
|
||||
WARN("BAD_AUTHOR", "invalid author identity\n" . $line );
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user