1a1d2a633SQiang Yu // SPDX-License-Identifier: GPL-2.0 OR MIT 2a1d2a633SQiang Yu /* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */ 3a1d2a633SQiang Yu 4a1d2a633SQiang Yu #include <linux/module.h> 5722d4f06SRob Herring #include <linux/of.h> 6722d4f06SRob Herring #include <linux/platform_device.h> 7a1d2a633SQiang Yu #include <linux/uaccess.h> 8a1d2a633SQiang Yu #include <linux/slab.h> 963945d51SQiang Yu #include <linux/pm_runtime.h> 10a1d2a633SQiang Yu #include <drm/drm_ioctl.h> 11a1d2a633SQiang Yu #include <drm/drm_drv.h> 12a1d2a633SQiang Yu #include <drm/drm_prime.h> 13a1d2a633SQiang Yu #include <drm/lima_drm.h> 14a1d2a633SQiang Yu 1519969707SMartin Blumenstingl #include "lima_device.h" 16a1d2a633SQiang Yu #include "lima_drv.h" 17a1d2a633SQiang Yu #include "lima_gem.h" 18a1d2a633SQiang Yu #include "lima_vm.h" 19a1d2a633SQiang Yu 20a1d2a633SQiang Yu int lima_sched_timeout_ms; 216aebc51dSQiang Yu uint lima_heap_init_nr_pages = 8; 22c67a3d4fSQiang Yu uint lima_max_error_tasks; 23de489844SAndrey Lebedev uint lima_job_hang_limit; 24a1d2a633SQiang Yu 2547ab1457SErico Nunes MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms"); 26a1d2a633SQiang Yu module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444); 27a1d2a633SQiang Yu 286aebc51dSQiang Yu MODULE_PARM_DESC(heap_init_nr_pages, "heap buffer init number of pages"); 296aebc51dSQiang Yu module_param_named(heap_init_nr_pages, lima_heap_init_nr_pages, uint, 0444); 306aebc51dSQiang Yu 31c67a3d4fSQiang Yu MODULE_PARM_DESC(max_error_tasks, "max number of error tasks to save"); 32c67a3d4fSQiang Yu module_param_named(max_error_tasks, lima_max_error_tasks, uint, 0644); 33c67a3d4fSQiang Yu 34de489844SAndrey Lebedev MODULE_PARM_DESC(job_hang_limit, "number of times to allow a job to hang before dropping it (default 0)"); 35de489844SAndrey Lebedev module_param_named(job_hang_limit, lima_job_hang_limit, uint, 0444); 36de489844SAndrey Lebedev 37a1d2a633SQiang Yu static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file) 38a1d2a633SQiang Yu { 39a1d2a633SQiang Yu struct drm_lima_get_param *args = data; 40a1d2a633SQiang Yu struct lima_device *ldev = to_lima_dev(dev); 41a1d2a633SQiang Yu 42a1d2a633SQiang Yu if (args->pad) 43a1d2a633SQiang Yu return -EINVAL; 44a1d2a633SQiang Yu 45a1d2a633SQiang Yu switch (args->param) { 46a1d2a633SQiang Yu case DRM_LIMA_PARAM_GPU_ID: 47a1d2a633SQiang Yu switch (ldev->id) { 48a1d2a633SQiang Yu case lima_gpu_mali400: 49a1d2a633SQiang Yu args->value = DRM_LIMA_PARAM_GPU_ID_MALI400; 50a1d2a633SQiang Yu break; 51a1d2a633SQiang Yu case lima_gpu_mali450: 52a1d2a633SQiang Yu args->value = DRM_LIMA_PARAM_GPU_ID_MALI450; 53a1d2a633SQiang Yu break; 54a1d2a633SQiang Yu default: 55a1d2a633SQiang Yu args->value = DRM_LIMA_PARAM_GPU_ID_UNKNOWN; 56a1d2a633SQiang Yu break; 57a1d2a633SQiang Yu } 58a1d2a633SQiang Yu break; 59a1d2a633SQiang Yu 60a1d2a633SQiang Yu case DRM_LIMA_PARAM_NUM_PP: 61a1d2a633SQiang Yu args->value = ldev->pipe[lima_pipe_pp].num_processor; 62a1d2a633SQiang Yu break; 63a1d2a633SQiang Yu 64a1d2a633SQiang Yu case DRM_LIMA_PARAM_GP_VERSION: 65a1d2a633SQiang Yu args->value = ldev->gp_version; 66a1d2a633SQiang Yu break; 67a1d2a633SQiang Yu 68a1d2a633SQiang Yu case DRM_LIMA_PARAM_PP_VERSION: 69a1d2a633SQiang Yu args->value = ldev->pp_version; 70a1d2a633SQiang Yu break; 71a1d2a633SQiang Yu 72a1d2a633SQiang Yu default: 73a1d2a633SQiang Yu return -EINVAL; 74a1d2a633SQiang Yu } 75a1d2a633SQiang Yu 76a1d2a633SQiang Yu return 0; 77a1d2a633SQiang Yu } 78a1d2a633SQiang Yu 79a1d2a633SQiang Yu static int lima_ioctl_gem_create(struct drm_device *dev, void *data, struct drm_file *file) 80a1d2a633SQiang Yu { 81a1d2a633SQiang Yu struct drm_lima_gem_create *args = data; 82a1d2a633SQiang Yu 83a1d2a633SQiang Yu if (args->pad) 84a1d2a633SQiang Yu return -EINVAL; 85a1d2a633SQiang Yu 866aebc51dSQiang Yu if (args->flags & ~(LIMA_BO_FLAG_HEAP)) 87a1d2a633SQiang Yu return -EINVAL; 88a1d2a633SQiang Yu 89a1d2a633SQiang Yu if (args->size == 0) 90a1d2a633SQiang Yu return -EINVAL; 91a1d2a633SQiang Yu 92a1d2a633SQiang Yu return lima_gem_create_handle(dev, file, args->size, args->flags, &args->handle); 93a1d2a633SQiang Yu } 94a1d2a633SQiang Yu 95a1d2a633SQiang Yu static int lima_ioctl_gem_info(struct drm_device *dev, void *data, struct drm_file *file) 96a1d2a633SQiang Yu { 97a1d2a633SQiang Yu struct drm_lima_gem_info *args = data; 98a1d2a633SQiang Yu 99a1d2a633SQiang Yu return lima_gem_get_info(file, args->handle, &args->va, &args->offset); 100a1d2a633SQiang Yu } 101a1d2a633SQiang Yu 102a1d2a633SQiang Yu static int lima_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file) 103a1d2a633SQiang Yu { 104a1d2a633SQiang Yu struct drm_lima_gem_submit *args = data; 105a1d2a633SQiang Yu struct lima_device *ldev = to_lima_dev(dev); 106a1d2a633SQiang Yu struct lima_drm_priv *priv = file->driver_priv; 107a1d2a633SQiang Yu struct drm_lima_gem_submit_bo *bos; 108a1d2a633SQiang Yu struct lima_sched_pipe *pipe; 109a1d2a633SQiang Yu struct lima_sched_task *task; 110a1d2a633SQiang Yu struct lima_ctx *ctx; 111a1d2a633SQiang Yu struct lima_submit submit = {0}; 112a1d2a633SQiang Yu size_t size; 113a1d2a633SQiang Yu int err = 0; 114a1d2a633SQiang Yu 115a1d2a633SQiang Yu if (args->pipe >= lima_pipe_num || args->nr_bos == 0) 116a1d2a633SQiang Yu return -EINVAL; 117a1d2a633SQiang Yu 118a1d2a633SQiang Yu if (args->flags & ~(LIMA_SUBMIT_FLAG_EXPLICIT_FENCE)) 119a1d2a633SQiang Yu return -EINVAL; 120a1d2a633SQiang Yu 121a1d2a633SQiang Yu pipe = ldev->pipe + args->pipe; 122a1d2a633SQiang Yu if (args->frame_size != pipe->frame_size) 123a1d2a633SQiang Yu return -EINVAL; 124a1d2a633SQiang Yu 125a1d2a633SQiang Yu bos = kvcalloc(args->nr_bos, sizeof(*submit.bos) + sizeof(*submit.lbos), GFP_KERNEL); 126a1d2a633SQiang Yu if (!bos) 127a1d2a633SQiang Yu return -ENOMEM; 128a1d2a633SQiang Yu 129a1d2a633SQiang Yu size = args->nr_bos * sizeof(*submit.bos); 130a1d2a633SQiang Yu if (copy_from_user(bos, u64_to_user_ptr(args->bos), size)) { 131a1d2a633SQiang Yu err = -EFAULT; 132a1d2a633SQiang Yu goto out0; 133a1d2a633SQiang Yu } 134a1d2a633SQiang Yu 135a1d2a633SQiang Yu task = kmem_cache_zalloc(pipe->task_slab, GFP_KERNEL); 136a1d2a633SQiang Yu if (!task) { 137a1d2a633SQiang Yu err = -ENOMEM; 138a1d2a633SQiang Yu goto out0; 139a1d2a633SQiang Yu } 140a1d2a633SQiang Yu 141a1d2a633SQiang Yu task->frame = task + 1; 142a1d2a633SQiang Yu if (copy_from_user(task->frame, u64_to_user_ptr(args->frame), args->frame_size)) { 143a1d2a633SQiang Yu err = -EFAULT; 144a1d2a633SQiang Yu goto out1; 145a1d2a633SQiang Yu } 146a1d2a633SQiang Yu 147a1d2a633SQiang Yu err = pipe->task_validate(pipe, task); 148a1d2a633SQiang Yu if (err) 149a1d2a633SQiang Yu goto out1; 150a1d2a633SQiang Yu 151a1d2a633SQiang Yu ctx = lima_ctx_get(&priv->ctx_mgr, args->ctx); 152a1d2a633SQiang Yu if (!ctx) { 153a1d2a633SQiang Yu err = -ENOENT; 154a1d2a633SQiang Yu goto out1; 155a1d2a633SQiang Yu } 156a1d2a633SQiang Yu 157a1d2a633SQiang Yu submit.pipe = args->pipe; 158a1d2a633SQiang Yu submit.bos = bos; 159a1d2a633SQiang Yu submit.lbos = (void *)bos + size; 160a1d2a633SQiang Yu submit.nr_bos = args->nr_bos; 161a1d2a633SQiang Yu submit.task = task; 162a1d2a633SQiang Yu submit.ctx = ctx; 163a1d2a633SQiang Yu submit.flags = args->flags; 164a1d2a633SQiang Yu submit.in_sync[0] = args->in_sync[0]; 165a1d2a633SQiang Yu submit.in_sync[1] = args->in_sync[1]; 166a1d2a633SQiang Yu submit.out_sync = args->out_sync; 167a1d2a633SQiang Yu 168a1d2a633SQiang Yu err = lima_gem_submit(file, &submit); 169a1d2a633SQiang Yu 170a1d2a633SQiang Yu lima_ctx_put(ctx); 171a1d2a633SQiang Yu out1: 172a1d2a633SQiang Yu if (err) 173a1d2a633SQiang Yu kmem_cache_free(pipe->task_slab, task); 174a1d2a633SQiang Yu out0: 175a1d2a633SQiang Yu kvfree(bos); 176a1d2a633SQiang Yu return err; 177a1d2a633SQiang Yu } 178a1d2a633SQiang Yu 179a1d2a633SQiang Yu static int lima_ioctl_gem_wait(struct drm_device *dev, void *data, struct drm_file *file) 180a1d2a633SQiang Yu { 181a1d2a633SQiang Yu struct drm_lima_gem_wait *args = data; 182a1d2a633SQiang Yu 183a1d2a633SQiang Yu if (args->op & ~(LIMA_GEM_WAIT_READ|LIMA_GEM_WAIT_WRITE)) 184a1d2a633SQiang Yu return -EINVAL; 185a1d2a633SQiang Yu 186a1d2a633SQiang Yu return lima_gem_wait(file, args->handle, args->op, args->timeout_ns); 187a1d2a633SQiang Yu } 188a1d2a633SQiang Yu 189a1d2a633SQiang Yu static int lima_ioctl_ctx_create(struct drm_device *dev, void *data, struct drm_file *file) 190a1d2a633SQiang Yu { 191a1d2a633SQiang Yu struct drm_lima_ctx_create *args = data; 192a1d2a633SQiang Yu struct lima_drm_priv *priv = file->driver_priv; 193a1d2a633SQiang Yu struct lima_device *ldev = to_lima_dev(dev); 194a1d2a633SQiang Yu 195a1d2a633SQiang Yu if (args->_pad) 196a1d2a633SQiang Yu return -EINVAL; 197a1d2a633SQiang Yu 198a1d2a633SQiang Yu return lima_ctx_create(ldev, &priv->ctx_mgr, &args->id); 199a1d2a633SQiang Yu } 200a1d2a633SQiang Yu 201a1d2a633SQiang Yu static int lima_ioctl_ctx_free(struct drm_device *dev, void *data, struct drm_file *file) 202a1d2a633SQiang Yu { 203a1d2a633SQiang Yu struct drm_lima_ctx_create *args = data; 204a1d2a633SQiang Yu struct lima_drm_priv *priv = file->driver_priv; 205a1d2a633SQiang Yu 206a1d2a633SQiang Yu if (args->_pad) 207a1d2a633SQiang Yu return -EINVAL; 208a1d2a633SQiang Yu 209a1d2a633SQiang Yu return lima_ctx_free(&priv->ctx_mgr, args->id); 210a1d2a633SQiang Yu } 211a1d2a633SQiang Yu 212a1d2a633SQiang Yu static int lima_drm_driver_open(struct drm_device *dev, struct drm_file *file) 213a1d2a633SQiang Yu { 214a1d2a633SQiang Yu int err; 215a1d2a633SQiang Yu struct lima_drm_priv *priv; 216a1d2a633SQiang Yu struct lima_device *ldev = to_lima_dev(dev); 217a1d2a633SQiang Yu 218a1d2a633SQiang Yu priv = kzalloc(sizeof(*priv), GFP_KERNEL); 219a1d2a633SQiang Yu if (!priv) 220a1d2a633SQiang Yu return -ENOMEM; 221a1d2a633SQiang Yu 222a1d2a633SQiang Yu priv->vm = lima_vm_create(ldev); 223a1d2a633SQiang Yu if (!priv->vm) { 224a1d2a633SQiang Yu err = -ENOMEM; 225a1d2a633SQiang Yu goto err_out0; 226a1d2a633SQiang Yu } 227a1d2a633SQiang Yu 228a1d2a633SQiang Yu lima_ctx_mgr_init(&priv->ctx_mgr); 229a1d2a633SQiang Yu 230a1d2a633SQiang Yu file->driver_priv = priv; 231a1d2a633SQiang Yu return 0; 232a1d2a633SQiang Yu 233a1d2a633SQiang Yu err_out0: 234a1d2a633SQiang Yu kfree(priv); 235a1d2a633SQiang Yu return err; 236a1d2a633SQiang Yu } 237a1d2a633SQiang Yu 238a1d2a633SQiang Yu static void lima_drm_driver_postclose(struct drm_device *dev, struct drm_file *file) 239a1d2a633SQiang Yu { 240a1d2a633SQiang Yu struct lima_drm_priv *priv = file->driver_priv; 241a1d2a633SQiang Yu 242a1d2a633SQiang Yu lima_ctx_mgr_fini(&priv->ctx_mgr); 243a1d2a633SQiang Yu lima_vm_put(priv->vm); 244a1d2a633SQiang Yu kfree(priv); 245a1d2a633SQiang Yu } 246a1d2a633SQiang Yu 247a1d2a633SQiang Yu static const struct drm_ioctl_desc lima_drm_driver_ioctls[] = { 248921d5732SEmil Velikov DRM_IOCTL_DEF_DRV(LIMA_GET_PARAM, lima_ioctl_get_param, DRM_RENDER_ALLOW), 249921d5732SEmil Velikov DRM_IOCTL_DEF_DRV(LIMA_GEM_CREATE, lima_ioctl_gem_create, DRM_RENDER_ALLOW), 250921d5732SEmil Velikov DRM_IOCTL_DEF_DRV(LIMA_GEM_INFO, lima_ioctl_gem_info, DRM_RENDER_ALLOW), 251921d5732SEmil Velikov DRM_IOCTL_DEF_DRV(LIMA_GEM_SUBMIT, lima_ioctl_gem_submit, DRM_RENDER_ALLOW), 252921d5732SEmil Velikov DRM_IOCTL_DEF_DRV(LIMA_GEM_WAIT, lima_ioctl_gem_wait, DRM_RENDER_ALLOW), 253921d5732SEmil Velikov DRM_IOCTL_DEF_DRV(LIMA_CTX_CREATE, lima_ioctl_ctx_create, DRM_RENDER_ALLOW), 254921d5732SEmil Velikov DRM_IOCTL_DEF_DRV(LIMA_CTX_FREE, lima_ioctl_ctx_free, DRM_RENDER_ALLOW), 255a1d2a633SQiang Yu }; 256a1d2a633SQiang Yu 2577e4d0b09SQiang Yu DEFINE_DRM_GEM_FOPS(lima_drm_driver_fops); 258a1d2a633SQiang Yu 25937d66109SLee Jones /* 260d20615f8SQiang Yu * Changelog: 261d20615f8SQiang Yu * 262d20615f8SQiang Yu * - 1.1.0 - add heap buffer support 263d20615f8SQiang Yu */ 264d20615f8SQiang Yu 26570a59dd8SDaniel Vetter static const struct drm_driver lima_drm_driver = { 2660424fdafSDaniel Vetter .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ, 267a1d2a633SQiang Yu .open = lima_drm_driver_open, 268a1d2a633SQiang Yu .postclose = lima_drm_driver_postclose, 269a1d2a633SQiang Yu .ioctls = lima_drm_driver_ioctls, 270a1d2a633SQiang Yu .num_ioctls = ARRAY_SIZE(lima_drm_driver_ioctls), 271a1d2a633SQiang Yu .fops = &lima_drm_driver_fops, 272a1d2a633SQiang Yu .name = "lima", 273a1d2a633SQiang Yu .desc = "lima DRM", 274d20615f8SQiang Yu .date = "20191231", 275a1d2a633SQiang Yu .major = 1, 276d20615f8SQiang Yu .minor = 1, 277a1d2a633SQiang Yu .patchlevel = 0, 278a1d2a633SQiang Yu 279d61dd248SQiang Yu .gem_create_object = lima_gem_create_object, 280d61dd248SQiang Yu .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, 281a1d2a633SQiang Yu }; 282a1d2a633SQiang Yu 28357b517ceSQiang Yu struct lima_block_reader { 28457b517ceSQiang Yu void *dst; 28557b517ceSQiang Yu size_t base; 28657b517ceSQiang Yu size_t count; 28757b517ceSQiang Yu size_t off; 28857b517ceSQiang Yu ssize_t read; 28957b517ceSQiang Yu }; 29057b517ceSQiang Yu 29157b517ceSQiang Yu static bool lima_read_block(struct lima_block_reader *reader, 29257b517ceSQiang Yu void *src, size_t src_size) 29357b517ceSQiang Yu { 29457b517ceSQiang Yu size_t max_off = reader->base + src_size; 29557b517ceSQiang Yu 29657b517ceSQiang Yu if (reader->off < max_off) { 29757b517ceSQiang Yu size_t size = min_t(size_t, max_off - reader->off, 29857b517ceSQiang Yu reader->count); 29957b517ceSQiang Yu 30057b517ceSQiang Yu memcpy(reader->dst, src + (reader->off - reader->base), size); 30157b517ceSQiang Yu 30257b517ceSQiang Yu reader->dst += size; 30357b517ceSQiang Yu reader->off += size; 30457b517ceSQiang Yu reader->read += size; 30557b517ceSQiang Yu reader->count -= size; 30657b517ceSQiang Yu } 30757b517ceSQiang Yu 30857b517ceSQiang Yu reader->base = max_off; 30957b517ceSQiang Yu 31057b517ceSQiang Yu return !!reader->count; 31157b517ceSQiang Yu } 31257b517ceSQiang Yu 31357b517ceSQiang Yu static ssize_t lima_error_state_read(struct file *filp, struct kobject *kobj, 31457b517ceSQiang Yu struct bin_attribute *attr, char *buf, 31557b517ceSQiang Yu loff_t off, size_t count) 31657b517ceSQiang Yu { 31757b517ceSQiang Yu struct device *dev = kobj_to_dev(kobj); 31857b517ceSQiang Yu struct lima_device *ldev = dev_get_drvdata(dev); 31957b517ceSQiang Yu struct lima_sched_error_task *et; 32057b517ceSQiang Yu struct lima_block_reader reader = { 32157b517ceSQiang Yu .dst = buf, 32257b517ceSQiang Yu .count = count, 32357b517ceSQiang Yu .off = off, 32457b517ceSQiang Yu }; 32557b517ceSQiang Yu 32657b517ceSQiang Yu mutex_lock(&ldev->error_task_list_lock); 32757b517ceSQiang Yu 32857b517ceSQiang Yu if (lima_read_block(&reader, &ldev->dump, sizeof(ldev->dump))) { 32957b517ceSQiang Yu list_for_each_entry(et, &ldev->error_task_list, list) { 33057b517ceSQiang Yu if (!lima_read_block(&reader, et->data, et->size)) 33157b517ceSQiang Yu break; 33257b517ceSQiang Yu } 33357b517ceSQiang Yu } 33457b517ceSQiang Yu 33557b517ceSQiang Yu mutex_unlock(&ldev->error_task_list_lock); 33657b517ceSQiang Yu return reader.read; 33757b517ceSQiang Yu } 33857b517ceSQiang Yu 33957b517ceSQiang Yu static ssize_t lima_error_state_write(struct file *file, struct kobject *kobj, 34057b517ceSQiang Yu struct bin_attribute *attr, char *buf, 34157b517ceSQiang Yu loff_t off, size_t count) 34257b517ceSQiang Yu { 34357b517ceSQiang Yu struct device *dev = kobj_to_dev(kobj); 34457b517ceSQiang Yu struct lima_device *ldev = dev_get_drvdata(dev); 34557b517ceSQiang Yu struct lima_sched_error_task *et, *tmp; 34657b517ceSQiang Yu 34757b517ceSQiang Yu mutex_lock(&ldev->error_task_list_lock); 34857b517ceSQiang Yu 34957b517ceSQiang Yu list_for_each_entry_safe(et, tmp, &ldev->error_task_list, list) { 35057b517ceSQiang Yu list_del(&et->list); 35157b517ceSQiang Yu kvfree(et); 35257b517ceSQiang Yu } 35357b517ceSQiang Yu 35457b517ceSQiang Yu ldev->dump.size = 0; 35557b517ceSQiang Yu ldev->dump.num_tasks = 0; 35657b517ceSQiang Yu 35757b517ceSQiang Yu mutex_unlock(&ldev->error_task_list_lock); 35857b517ceSQiang Yu 35957b517ceSQiang Yu return count; 36057b517ceSQiang Yu } 36157b517ceSQiang Yu 36257b517ceSQiang Yu static const struct bin_attribute lima_error_state_attr = { 36357b517ceSQiang Yu .attr.name = "error", 36457b517ceSQiang Yu .attr.mode = 0600, 36557b517ceSQiang Yu .size = 0, 36657b517ceSQiang Yu .read = lima_error_state_read, 36757b517ceSQiang Yu .write = lima_error_state_write, 36857b517ceSQiang Yu }; 36957b517ceSQiang Yu 370a1d2a633SQiang Yu static int lima_pdev_probe(struct platform_device *pdev) 371a1d2a633SQiang Yu { 372a1d2a633SQiang Yu struct lima_device *ldev; 373a1d2a633SQiang Yu struct drm_device *ddev; 374*b27a838fSErico Nunes const struct lima_compatible *comp; 375a1d2a633SQiang Yu int err; 376a1d2a633SQiang Yu 377a1d2a633SQiang Yu err = lima_sched_slab_init(); 378a1d2a633SQiang Yu if (err) 379a1d2a633SQiang Yu return err; 380a1d2a633SQiang Yu 381a1d2a633SQiang Yu ldev = devm_kzalloc(&pdev->dev, sizeof(*ldev), GFP_KERNEL); 382a1d2a633SQiang Yu if (!ldev) { 383a1d2a633SQiang Yu err = -ENOMEM; 384a1d2a633SQiang Yu goto err_out0; 385a1d2a633SQiang Yu } 386a1d2a633SQiang Yu 387a1d2a633SQiang Yu ldev->dev = &pdev->dev; 388*b27a838fSErico Nunes comp = of_device_get_match_data(&pdev->dev); 389*b27a838fSErico Nunes if (!comp) { 390*b27a838fSErico Nunes err = -ENODEV; 391*b27a838fSErico Nunes goto err_out0; 392*b27a838fSErico Nunes } 393*b27a838fSErico Nunes 394*b27a838fSErico Nunes ldev->id = comp->id; 395a1d2a633SQiang Yu 396a1d2a633SQiang Yu platform_set_drvdata(pdev, ldev); 397a1d2a633SQiang Yu 398a1d2a633SQiang Yu /* Allocate and initialize the DRM device. */ 399a1d2a633SQiang Yu ddev = drm_dev_alloc(&lima_drm_driver, &pdev->dev); 400c5647caeSHarshit Mogalapalli if (IS_ERR(ddev)) { 401c5647caeSHarshit Mogalapalli err = PTR_ERR(ddev); 402c5647caeSHarshit Mogalapalli goto err_out0; 403c5647caeSHarshit Mogalapalli } 404a1d2a633SQiang Yu 405a1d2a633SQiang Yu ddev->dev_private = ldev; 406a1d2a633SQiang Yu ldev->ddev = ddev; 407a1d2a633SQiang Yu 408a1d2a633SQiang Yu err = lima_device_init(ldev); 40934e88f9eSKrzysztof Kozlowski if (err) 410a1d2a633SQiang Yu goto err_out1; 411a1d2a633SQiang Yu 41219969707SMartin Blumenstingl err = lima_devfreq_init(ldev); 41319969707SMartin Blumenstingl if (err) { 41419969707SMartin Blumenstingl dev_err(&pdev->dev, "Fatal error during devfreq init\n"); 41519969707SMartin Blumenstingl goto err_out2; 41619969707SMartin Blumenstingl } 41719969707SMartin Blumenstingl 41850de2e9eSQiang Yu pm_runtime_set_active(ldev->dev); 41950de2e9eSQiang Yu pm_runtime_mark_last_busy(ldev->dev); 42050de2e9eSQiang Yu pm_runtime_set_autosuspend_delay(ldev->dev, 200); 42150de2e9eSQiang Yu pm_runtime_use_autosuspend(ldev->dev); 42250de2e9eSQiang Yu pm_runtime_enable(ldev->dev); 42350de2e9eSQiang Yu 424a1d2a633SQiang Yu /* 425a1d2a633SQiang Yu * Register the DRM device with the core and the connectors with 426a1d2a633SQiang Yu * sysfs. 427a1d2a633SQiang Yu */ 428a1d2a633SQiang Yu err = drm_dev_register(ddev, 0); 429a1d2a633SQiang Yu if (err < 0) 43019969707SMartin Blumenstingl goto err_out3; 431a1d2a633SQiang Yu 43257b517ceSQiang Yu if (sysfs_create_bin_file(&ldev->dev->kobj, &lima_error_state_attr)) 43357b517ceSQiang Yu dev_warn(ldev->dev, "fail to create error state sysfs\n"); 43457b517ceSQiang Yu 435a1d2a633SQiang Yu return 0; 436a1d2a633SQiang Yu 43719969707SMartin Blumenstingl err_out3: 43850de2e9eSQiang Yu pm_runtime_disable(ldev->dev); 43919969707SMartin Blumenstingl lima_devfreq_fini(ldev); 44050de2e9eSQiang Yu err_out2: 44150de2e9eSQiang Yu lima_device_fini(ldev); 442a1d2a633SQiang Yu err_out1: 443a1d2a633SQiang Yu drm_dev_put(ddev); 444a1d2a633SQiang Yu err_out0: 445a1d2a633SQiang Yu lima_sched_slab_fini(); 446a1d2a633SQiang Yu return err; 447a1d2a633SQiang Yu } 448a1d2a633SQiang Yu 449980ec644SUwe Kleine-König static void lima_pdev_remove(struct platform_device *pdev) 450a1d2a633SQiang Yu { 451a1d2a633SQiang Yu struct lima_device *ldev = platform_get_drvdata(pdev); 452a1d2a633SQiang Yu struct drm_device *ddev = ldev->ddev; 453a1d2a633SQiang Yu 45457b517ceSQiang Yu sysfs_remove_bin_file(&ldev->dev->kobj, &lima_error_state_attr); 45550de2e9eSQiang Yu 456a1d2a633SQiang Yu drm_dev_unregister(ddev); 45750de2e9eSQiang Yu 45850de2e9eSQiang Yu /* stop autosuspend to make sure device is in active state */ 45950de2e9eSQiang Yu pm_runtime_set_autosuspend_delay(ldev->dev, -1); 46050de2e9eSQiang Yu pm_runtime_disable(ldev->dev); 46150de2e9eSQiang Yu 46219969707SMartin Blumenstingl lima_devfreq_fini(ldev); 463a1d2a633SQiang Yu lima_device_fini(ldev); 46450de2e9eSQiang Yu 465a1d2a633SQiang Yu drm_dev_put(ddev); 466a1d2a633SQiang Yu lima_sched_slab_fini(); 467a1d2a633SQiang Yu } 468a1d2a633SQiang Yu 469*b27a838fSErico Nunes static const struct lima_compatible lima_mali400_data = { 470*b27a838fSErico Nunes .id = lima_gpu_mali400, 471*b27a838fSErico Nunes }; 472*b27a838fSErico Nunes 473*b27a838fSErico Nunes static const struct lima_compatible lima_mali450_data = { 474*b27a838fSErico Nunes .id = lima_gpu_mali450, 475*b27a838fSErico Nunes }; 476*b27a838fSErico Nunes 477a1d2a633SQiang Yu static const struct of_device_id dt_match[] = { 478*b27a838fSErico Nunes { .compatible = "arm,mali-400", .data = &lima_mali400_data }, 479*b27a838fSErico Nunes { .compatible = "arm,mali-450", .data = &lima_mali450_data }, 480a1d2a633SQiang Yu {} 481a1d2a633SQiang Yu }; 482a1d2a633SQiang Yu MODULE_DEVICE_TABLE(of, dt_match); 483a1d2a633SQiang Yu 48463945d51SQiang Yu static const struct dev_pm_ops lima_pm_ops = { 48563945d51SQiang Yu SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) 48663945d51SQiang Yu SET_RUNTIME_PM_OPS(lima_device_suspend, lima_device_resume, NULL) 48763945d51SQiang Yu }; 48863945d51SQiang Yu 489a1d2a633SQiang Yu static struct platform_driver lima_platform_driver = { 490a1d2a633SQiang Yu .probe = lima_pdev_probe, 491980ec644SUwe Kleine-König .remove_new = lima_pdev_remove, 492a1d2a633SQiang Yu .driver = { 493a1d2a633SQiang Yu .name = "lima", 49463945d51SQiang Yu .pm = &lima_pm_ops, 495a1d2a633SQiang Yu .of_match_table = dt_match, 496a1d2a633SQiang Yu }, 497a1d2a633SQiang Yu }; 498a1d2a633SQiang Yu 4994eda21d6SQiang Yu module_platform_driver(lima_platform_driver); 500a1d2a633SQiang Yu 501a1d2a633SQiang Yu MODULE_AUTHOR("Lima Project Developers"); 502a1d2a633SQiang Yu MODULE_DESCRIPTION("Lima DRM Driver"); 503a1d2a633SQiang Yu MODULE_LICENSE("GPL v2"); 504