Skip to content

Commit

Permalink
drm/virtio: 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.

Test Done:
- Android Boot
- display
- backlight

Tracked-On: OAM-117147
Signed-off-by: Xue, Bosheng <[email protected]>
  • Loading branch information
bosheng1 committed Aug 15, 2024
1 parent 4c19e9e commit d59fe10
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 d59fe10

Please sign in to comment.