Skip to content

Commit

Permalink
Support backlight device in virtio gpu
Browse files Browse the repository at this point in the history
Enable virtio backlight function, it will expose sysfs node
/sys/class/backlight/virtio-gpu-backlight0 for guest user.

Tracked-On: OAM-117147
Signed-off-by: Xue, Bosheng <[email protected]>
  • Loading branch information
bosheng1 committed Aug 15, 2024
1 parent 4c19e9e commit 03fbc52
Show file tree
Hide file tree
Showing 6 changed files with 281 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/virtio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ config DRM_VIRTIO_GPU
select DRM_KMS_HELPER
select DRM_GEM_SHMEM_HELPER
select VIRTIO_DMA_SHARED_BUFFER
select BACKLIGHT_CLASS_DEVICE
help
This is the virtual GPU driver for virtio. It can be used with
QEMU based VMMs (like KVM or Xen).
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/virtio/virtgpu_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ static unsigned int features[] = {
VIRTIO_GPU_F_MODIFIER,
VIRTIO_GPU_F_SCALING,
VIRTIO_GPU_F_VBLANK,
VIRTIO_GPU_F_BACKLIGHT,
};

#ifdef CONFIG_PM_SLEEP
Expand Down
26 changes: 26 additions & 0 deletions drivers/gpu/drm/virtio/virtgpu_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
#include <linux/virtio_gpu.h>
#include <linux/backlight.h>

#include <drm/drm_atomic.h>
#include <drm/drm_drv.h>
Expand Down Expand Up @@ -173,6 +174,7 @@ struct virtio_gpu_vbuffer {
struct list_head list;

uint32_t seqno;
struct completion notify;
};

struct virtio_gpu_output {
Expand Down Expand Up @@ -224,12 +226,26 @@ struct virtio_gpu_vblank {
uint32_t buf[4];
};

#define MAX_BACKLIGHT_NUM 4
struct virtio_gpu_backlight {
struct virtio_gpu_device *vgdev;
struct backlight_device *bd;
uint32_t backlight_id;
int32_t brightness;
int32_t max_brightness;
int32_t power;
enum backlight_type type;
enum backlight_scale scale;
};

struct virtio_gpu_device {
struct drm_device *ddev;

struct virtio_device *vdev;

struct virtio_gpu_output outputs[VIRTIO_GPU_MAX_SCANOUTS];
struct virtio_gpu_backlight backlight[MAX_BACKLIGHT_NUM];
uint32_t num_backlight;
uint32_t num_scanouts;
uint32_t num_vblankq;
struct virtio_gpu_queue ctrlq;
Expand All @@ -255,6 +271,7 @@ struct virtio_gpu_device {
bool has_modifier;
bool has_scaling;
bool has_vblank;
bool has_backlight;
bool has_indirect;
bool has_resource_assign_uuid;
bool has_resource_blob;
Expand Down Expand Up @@ -450,6 +467,15 @@ void virtio_gpu_cmd_set_scaling(struct virtio_gpu_device *vgdev,
uint32_t scanout_id,
struct drm_rect *rect_dst);

int virtio_gpu_cmd_backlight_update_status(struct virtio_gpu_device *vgdev,
uint32_t backlight_id);

int virtio_gpu_cmd_get_brightness(struct virtio_gpu_device *vgdev,
uint32_t backlight_id);

int virtio_gpu_cmd_backlight_query(struct virtio_gpu_device *vgdev,
uint32_t backlight_id);

/* virtgpu_display.c */
int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev);
void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev);
Expand Down
75 changes: 75 additions & 0 deletions drivers/gpu/drm/virtio/virtgpu_kms.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,65 @@ int virtio_gpu_find_vqs(struct virtio_gpu_device *vgdev)
return ret;
}

static int virtio_backlight_device_update_status(struct backlight_device *bd)
{
int ret = 0;
struct virtio_gpu_backlight *backlight = bl_get_data(bd);
backlight->power = bd->props.power;
backlight->brightness = bd->props.brightness;
ret = virtio_gpu_cmd_backlight_update_status(backlight->vgdev, backlight->backlight_id);
return ret;
}

static int virtio_backlight_device_get_brightness(struct backlight_device *bd)
{
int ret = 0;
struct virtio_gpu_backlight *backlight = bl_get_data(bd);
ret = virtio_gpu_cmd_get_brightness(backlight->vgdev, backlight->backlight_id);
return backlight->brightness;
}

static const struct backlight_ops virtio_backlight_device_ops = {
.update_status = virtio_backlight_device_update_status,
.get_brightness = virtio_backlight_device_get_brightness,
};

int virtio_backlight_device_register(struct virtio_gpu_device *vgdev, int index)
{
struct backlight_properties props;
char *name;
struct backlight_device *bd;
int ret = 0;
memset(&props, 0, sizeof(props));
if (index >= vgdev->num_backlight) {
return -EINVAL;
}
vgdev->backlight[index].vgdev = vgdev;
ret = virtio_gpu_cmd_backlight_query(vgdev, index);
if (ret) {
pr_err("fail to query backlight(%d) device config, ret:%d", index, ret);
return ret;
}

props.type = vgdev->backlight[index].type;
props.power = vgdev->backlight[index].power;
props.scale = vgdev->backlight[index].scale;
props.brightness = vgdev->backlight[index].brightness;
props.max_brightness = vgdev->backlight[index].max_brightness;
name = kasprintf(GFP_KERNEL, "virtio-gpu-backlight%d", index);
bd = devm_backlight_device_register(&vgdev->vdev->dev, name, &vgdev->vdev->dev,
&vgdev->backlight[index], &virtio_backlight_device_ops, &props);
if (IS_ERR(bd)) {
DRM_ERROR("failed to register backlight device\n");
kfree(name);
return PTR_ERR(bd);
}
vgdev->backlight[index].bd = bd;
DRM_INFO("backlight device:%s registered\n", name);
kfree(name);
return 0;
}

int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)
{
struct virtio_gpu_device *vgdev;
Expand Down Expand Up @@ -220,6 +279,9 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)
if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_VBLANK)) {
vgdev->has_vblank = true;
}
if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_BACKLIGHT)) {
vgdev->has_backlight = true;
}
if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_RESOURCE_BLOB)) {
vgdev->has_resource_blob = true;
if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_MODIFIER)) {
Expand Down Expand Up @@ -296,6 +358,15 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)
num_capsets, &num_capsets);
DRM_INFO("number of cap sets: %d\n", num_capsets);

vgdev->num_backlight = 0;
if (vgdev->has_backlight) {
virtio_cread_le(vgdev->vdev, struct virtio_gpu_config,
num_backlight, &vgdev->num_backlight);
if (vgdev->num_backlight > MAX_BACKLIGHT_NUM)
vgdev->num_backlight = MAX_BACKLIGHT_NUM;
}
DRM_INFO("number of virtio backlight: %d\n", vgdev->num_backlight);

ret = virtio_gpu_modeset_init(vgdev);
if (ret) {
DRM_ERROR("modeset init failed\n");
Expand All @@ -304,6 +375,10 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)

virtio_device_ready(vgdev->vdev);

for(i = 0; i < vgdev->num_backlight; i++) {
virtio_backlight_device_register(vgdev, i);
}

if (num_capsets)
virtio_gpu_get_capsets(vgdev, num_capsets);

Expand Down
129 changes: 129 additions & 0 deletions drivers/gpu/drm/virtio/virtgpu_vq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1416,3 +1416,132 @@ void virtio_gpu_cmd_set_scaling(struct virtio_gpu_device *vgdev,

virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
}

int virtio_gpu_cmd_backlight_update_status(struct virtio_gpu_device *vgdev,
uint32_t backlight_id)
{
struct virtio_gpu_backlight_update_status *cmd_p;
struct virtio_gpu_vbuffer *vbuf;

if (backlight_id >= vgdev->num_backlight) {
return -EINVAL;
}
cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p));
memset(cmd_p, 0, sizeof(*cmd_p));
cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_BACKLIGHT_UPDATE_STATUS);
cmd_p->backlight_id = cpu_to_le32(backlight_id);
cmd_p->brightness = cpu_to_le32(vgdev->backlight[backlight_id].brightness);
cmd_p->power = cpu_to_le32(vgdev->backlight[backlight_id].power);

virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
virtio_gpu_notify(vgdev);
return 0;
}

static void virtio_gpu_cmd_get_backlightness_cb(struct virtio_gpu_device *vgdev,
struct virtio_gpu_vbuffer *vbuf)
{
struct virtio_gpu_get_brightness *cmd_p =
(struct virtio_gpu_get_brightness *)vbuf->buf;
struct virtio_gpu_resp_brightness *resp =
(struct virtio_gpu_resp_brightness *)vbuf->resp_buf;
int32_t brightness = le32_to_cpu(resp->brightness);
uint32_t backlight_id = cmd_p->backlight_id;
if (backlight_id < vgdev->num_backlight) {
vgdev->backlight[backlight_id].brightness = brightness;
}
complete(&vbuf->notify);
}

int virtio_gpu_cmd_get_brightness(struct virtio_gpu_device *vgdev,
uint32_t backlight_id)
{
struct virtio_gpu_get_brightness *cmd_p;
struct virtio_gpu_vbuffer *vbuf;
void *resp_buf;
int ret = 0;

if (backlight_id >= vgdev->num_backlight)
return -EINVAL;
resp_buf = kzalloc(sizeof(struct virtio_gpu_resp_brightness),
GFP_KERNEL);
if (!resp_buf)
return -ENOMEM;

cmd_p = virtio_gpu_alloc_cmd_resp
(vgdev, &virtio_gpu_cmd_get_backlightness_cb, &vbuf,
sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_brightness),
resp_buf);
memset(cmd_p, 0, sizeof(*cmd_p));

init_completion(&vbuf->notify);
cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_BACKLIGHT_GET);
cmd_p->backlight_id = backlight_id;
virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
virtio_gpu_notify(vgdev);
ret = wait_for_completion_interruptible_timeout(&vbuf->notify, 100*HZ);
if (ret <= 0)
return -ETIME;
return 0;
}

static void virtio_gpu_cmd_get_backlight_info_cb(struct virtio_gpu_device *vgdev,
struct virtio_gpu_vbuffer *vbuf)
{
struct virtio_gpu_get_backlight_info *cmd_p =
(struct virtio_gpu_get_backlight_info *)vbuf->buf;
struct virtio_gpu_resp_backlight_info *resp =
(struct virtio_gpu_resp_backlight_info *)vbuf->resp_buf;
int32_t brightness = le32_to_cpu(resp->brightness);
int32_t max_brightness = le32_to_cpu(resp->max_brightness);
int32_t power = le32_to_cpu(resp->power);
int32_t type = le32_to_cpu(resp->type);
int32_t scale = le32_to_cpu(resp->scale);
uint32_t backlight_id = cmd_p->backlight_id;
if (backlight_id < vgdev->num_backlight) {
vgdev->backlight[backlight_id].brightness = brightness;
vgdev->backlight[backlight_id].max_brightness = max_brightness;
vgdev->backlight[backlight_id].power = power;
if (type > 0 && type < BACKLIGHT_TYPE_MAX)
vgdev->backlight[backlight_id].type = type;
else
vgdev->backlight[backlight_id].type = BACKLIGHT_RAW;
if (scale >= BACKLIGHT_SCALE_UNKNOWN && scale <= BACKLIGHT_SCALE_NON_LINEAR)
vgdev->backlight[backlight_id].scale = scale;
else
vgdev->backlight[backlight_id].scale = BACKLIGHT_SCALE_UNKNOWN;
}
complete(&vbuf->notify);
}

int virtio_gpu_cmd_backlight_query(struct virtio_gpu_device *vgdev,
uint32_t backlight_id)
{
struct virtio_gpu_get_backlight_info *cmd_p;
struct virtio_gpu_vbuffer *vbuf;
void *resp_buf;
int ret = 0;

if (backlight_id >= vgdev->num_backlight)
return -EINVAL;
resp_buf = kzalloc(sizeof(struct virtio_gpu_resp_backlight_info),
GFP_KERNEL);
if (!resp_buf)
return -ENOMEM;

cmd_p = virtio_gpu_alloc_cmd_resp
(vgdev, &virtio_gpu_cmd_get_backlight_info_cb, &vbuf,
sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_backlight_info),
resp_buf);
init_completion(&vbuf->notify);
memset(cmd_p, 0, sizeof(*cmd_p));

cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_BACKLIGHT_QUERY);
cmd_p->backlight_id = backlight_id;
virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
virtio_gpu_notify(vgdev);
ret = wait_for_completion_interruptible_timeout(&vbuf->notify, 100*HZ);
if (ret <= 0)
return -ETIME;
return 0;
}
Loading

0 comments on commit 03fbc52

Please sign in to comment.