diff options
Diffstat (limited to 'drivers/gpu')
238 files changed, 8795 insertions, 3473 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 1a0a8df2eed8..c4bf9a1cf4a6 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -264,3 +264,5 @@ source "drivers/gpu/drm/sti/Kconfig" source "drivers/gpu/drm/amd/amdkfd/Kconfig" source "drivers/gpu/drm/imx/Kconfig" + +source "drivers/gpu/drm/vc4/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 45e7719846b1..1e9ff4c3e3db 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -6,7 +6,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_context.o drm_dma.o \ drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \ drm_lock.o drm_memory.o drm_drv.o drm_vm.o \ - drm_agpsupport.o drm_scatter.o drm_pci.o \ + drm_scatter.o drm_pci.o \ drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \ drm_crtc.o drm_modes.o drm_edid.o \ drm_info.o drm_debugfs.o drm_encoder_slave.o \ @@ -19,6 +19,9 @@ drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o drm-$(CONFIG_PCI) += ati_pcigart.o drm-$(CONFIG_DRM_PANEL) += drm_panel.o drm-$(CONFIG_OF) += drm_of.o +drm-$(CONFIG_AGP) += drm_agpsupport.o + +drm-y += $(drm-m) 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 @@ -42,6 +45,7 @@ obj-$(CONFIG_DRM_MGA) += mga/ obj-$(CONFIG_DRM_I810) += i810/ obj-$(CONFIG_DRM_I915) += i915/ obj-$(CONFIG_DRM_MGAG200) += mgag200/ +obj-$(CONFIG_DRM_VC4) += vc4/ obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus/ obj-$(CONFIG_DRM_SIS) += sis/ obj-$(CONFIG_DRM_SAVAGE)+= savage/ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 6647fb26ef25..3fa1397fd7ae 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -79,6 +79,8 @@ extern int amdgpu_bapm; extern int amdgpu_deep_color; extern int amdgpu_vm_size; extern int amdgpu_vm_block_size; +extern int amdgpu_vm_fault_stop; +extern int amdgpu_vm_debug; extern int amdgpu_enable_scheduler; extern int amdgpu_sched_jobs; extern int amdgpu_sched_hw_submission; @@ -960,6 +962,11 @@ struct amdgpu_ring { #define AMDGPU_PTE_FRAG_64KB (4 << 7) #define AMDGPU_LOG2_PAGES_PER_FRAG 4 +/* How to programm VM fault handling */ +#define AMDGPU_VM_FAULT_STOP_NEVER 0 +#define AMDGPU_VM_FAULT_STOP_FIRST 1 +#define AMDGPU_VM_FAULT_STOP_ALWAYS 2 + struct amdgpu_vm_pt { struct amdgpu_bo *bo; uint64_t addr; @@ -1708,7 +1715,7 @@ struct amdgpu_vce { /* * SDMA */ -struct amdgpu_sdma { +struct amdgpu_sdma_instance { /* SDMA firmware */ const struct firmware *fw; uint32_t fw_version; @@ -1718,6 +1725,13 @@ struct amdgpu_sdma { bool burst_nop; }; +struct amdgpu_sdma { + struct amdgpu_sdma_instance instance[AMDGPU_MAX_SDMA_INSTANCES]; + struct amdgpu_irq_src trap_irq; + struct amdgpu_irq_src illegal_inst_irq; + int num_instances; +}; + /* * Firmware */ @@ -2064,9 +2078,7 @@ struct amdgpu_device { struct amdgpu_gfx gfx; /* sdma */ - struct amdgpu_sdma sdma[AMDGPU_MAX_SDMA_INSTANCES]; - struct amdgpu_irq_src sdma_trap_irq; - struct amdgpu_irq_src sdma_illegal_inst_irq; + struct amdgpu_sdma sdma; /* uvd */ bool has_uvd; @@ -2203,17 +2215,18 @@ static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v) ring->ring_free_dw--; } -static inline struct amdgpu_sdma * amdgpu_get_sdma_instance(struct amdgpu_ring *ring) +static inline struct amdgpu_sdma_instance * +amdgpu_get_sdma_instance(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; int i; - for (i = 0; i < AMDGPU_MAX_SDMA_INSTANCES; i++) - if (&adev->sdma[i].ring == ring) + for (i = 0; i < adev->sdma.num_instances; i++) + if (&adev->sdma.instance[i].ring == ring) break; if (i < AMDGPU_MAX_SDMA_INSTANCES) - return &adev->sdma[i]; + return &adev->sdma.instance[i]; else return NULL; } @@ -2349,10 +2362,10 @@ void amdgpu_driver_preclose_kms(struct drm_device *dev, struct drm_file *file_priv); int amdgpu_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon); int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon); -u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, int crtc); -int amdgpu_enable_vblank_kms(struct drm_device *dev, int crtc); -void amdgpu_disable_vblank_kms(struct drm_device *dev, int crtc); -int amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, +u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe); +int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe); +void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe); +int amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe, int *max_error, struct timeval *vblank_time, unsigned flags); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index aef4a7aac0f7..a142d5ae148d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -25,7 +25,6 @@ #include <linux/acpi.h> #include <linux/slab.h> #include <linux/power_supply.h> -#include <linux/vga_switcheroo.h> #include <acpi/video.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index dd2037bc0b4a..0e1376317683 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -649,12 +649,12 @@ static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) case KGD_ENGINE_SDMA1: hdr = (const union amdgpu_firmware_header *) - adev->sdma[0].fw->data; + adev->sdma.instance[0].fw->data; break; case KGD_ENGINE_SDMA2: hdr = (const union amdgpu_firmware_header *) - adev->sdma[1].fw->data; + adev->sdma.instance[1].fw->data; break; default: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c index dfd1d503bccf..79fa5c7de856 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -523,12 +523,12 @@ static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) case KGD_ENGINE_SDMA1: hdr = (const union amdgpu_firmware_header *) - adev->sdma[0].fw->data; + adev->sdma.instance[0].fw->data; break; case KGD_ENGINE_SDMA2: hdr = (const union amdgpu_firmware_header *) - adev->sdma[1].fw->data; + adev->sdma.instance[1].fw->data; break; default: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index 3f7aaa45bf8e..1a6b239baab9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -536,7 +536,7 @@ static bool amdgpu_atpx_detect(void) if (has_atpx && vga_count == 2) { acpi_get_name(amdgpu_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer); - printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n", + printk(KERN_INFO "vga_switcheroo: detected switching method %s handle\n", acpi_method_name); amdgpu_atpx_priv.atpx_detected = true; return true; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c index 02add0a508cb..c44c0c6afd1b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c @@ -29,7 +29,6 @@ #include "amdgpu.h" #include "atom.h" -#include <linux/vga_switcheroo.h> #include <linux/slab.h> #include <linux/acpi.h> /* diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index 1c3fc99c5465..8e995148f56e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -208,44 +208,6 @@ static int amdgpu_cgs_alloc_gpu_mem(void *cgs_device, return ret; } -static int amdgpu_cgs_import_gpu_mem(void *cgs_device, int dmabuf_fd, - cgs_handle_t *handle) -{ - CGS_FUNC_ADEV; - int r; - uint32_t dma_handle; - struct drm_gem_object *obj; - struct amdgpu_bo *bo; - struct drm_device *dev = adev->ddev; - struct drm_file *file_priv = NULL, *priv; - - mutex_lock(&dev->struct_mutex); - list_for_each_entry(priv, &dev->filelist, lhead) { - rcu_read_lock(); - if (priv->pid == get_pid(task_pid(current))) - file_priv = priv; - rcu_read_unlock(); - if (file_priv) - break; - } - mutex_unlock(&dev->struct_mutex); - r = dev->driver->prime_fd_to_handle(dev, - file_priv, dmabuf_fd, - &dma_handle); - spin_lock(&file_priv->table_lock); - - /* Check if we currently have a reference on the object */ - obj = idr_find(&file_priv->object_idr, dma_handle); - if (obj == NULL) { - spin_unlock(&file_priv->table_lock); - return -EINVAL; - } - spin_unlock(&file_priv->table_lock); - bo = gem_to_amdgpu_bo(obj); - *handle = (cgs_handle_t)bo; - return 0; -} - static int amdgpu_cgs_free_gpu_mem(void *cgs_device, cgs_handle_t handle) { struct amdgpu_bo *obj = (struct amdgpu_bo *)handle; @@ -810,7 +772,6 @@ static const struct cgs_ops amdgpu_cgs_ops = { }; static const struct cgs_os_ops amdgpu_cgs_os_ops = { - amdgpu_cgs_import_gpu_mem, amdgpu_cgs_add_irq_source, amdgpu_cgs_irq_get, amdgpu_cgs_irq_put diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 749420f1ea6f..baf00617fe90 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -104,10 +104,11 @@ int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type, } break; case AMDGPU_HW_IP_DMA: - if (ring < 2) { - *out_ring = &adev->sdma[ring].ring; + if (ring < adev->sdma.num_instances) { + *out_ring = &adev->sdma.instance[ring].ring; } else { - DRM_ERROR("only two SDMA rings are supported\n"); + DRM_ERROR("only %d SDMA rings are supported\n", + adev->sdma.num_instances); return -EINVAL; } break; @@ -156,7 +157,8 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) uint64_t *chunk_array_user; uint64_t *chunk_array; struct amdgpu_fpriv *fpriv = p->filp->driver_priv; - unsigned size, i; + unsigned size; + int i; int ret; if (cs->in.num_chunks == 0) @@ -176,7 +178,7 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) /* get chunks */ INIT_LIST_HEAD(&p->validated); - chunk_array_user = (uint64_t __user *)(cs->in.chunks); + chunk_array_user = (uint64_t __user *)(unsigned long)(cs->in.chunks); if (copy_from_user(chunk_array, chunk_array_user, sizeof(uint64_t)*cs->in.num_chunks)) { ret = -EFAULT; @@ -196,7 +198,7 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) struct drm_amdgpu_cs_chunk user_chunk; uint32_t __user *cdata; - chunk_ptr = (void __user *)chunk_array[i]; + chunk_ptr = (void __user *)(unsigned long)chunk_array[i]; if (copy_from_user(&user_chunk, chunk_ptr, sizeof(struct drm_amdgpu_cs_chunk))) { ret = -EFAULT; @@ -207,7 +209,7 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) p->chunks[i].length_dw = user_chunk.length_dw; size = p->chunks[i].length_dw; - cdata = (void __user *)user_chunk.chunk_data; + cdata = (void __user *)(unsigned long)user_chunk.chunk_data; p->chunks[i].user_ptr = cdata; p->chunks[i].kdata = drm_malloc_ab(size, sizeof(uint32_t)); @@ -566,9 +568,24 @@ static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p, if (r) return r; } + } - return amdgpu_vm_clear_invalids(adev, vm, &p->ibs[0].sync); + r = amdgpu_vm_clear_invalids(adev, vm, &p->ibs[0].sync); + + if (amdgpu_vm_debug && p->bo_list) { + /* Invalidate all BOs to test for userspace bugs */ + for (i = 0; i < p->bo_list->num_entries; i++) { + /* ignore duplicates */ + bo = p->bo_list->array[i].robj; + if (!bo) + continue; + + amdgpu_vm_bo_invalidate(adev, bo); + } + } + + return r; } static int amdgpu_cs_ib_vm_chunk(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 6068d8207d10..901a460b2c55 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1022,7 +1022,7 @@ static void amdgpu_check_arguments(struct amdgpu_device *adev) * amdgpu_switcheroo_set_state - set switcheroo state * * @pdev: pci dev pointer - * @state: vga switcheroo state + * @state: vga_switcheroo state * * Callback for the switcheroo driver. Suspends or resumes the * the asics before or after it is powered up using ACPI methods. @@ -1657,11 +1657,21 @@ int amdgpu_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) } drm_modeset_unlock_all(dev); - /* unpin the front buffers */ + /* unpin the front buffers and cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct amdgpu_framebuffer *rfb = to_amdgpu_framebuffer(crtc->primary->fb); struct amdgpu_bo *robj; + if (amdgpu_crtc->cursor_bo) { + struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); + r = amdgpu_bo_reserve(aobj, false); + if (r == 0) { + amdgpu_bo_unpin(aobj); + amdgpu_bo_unreserve(aobj); + } + } + if (rfb == NULL || rfb->obj == NULL) { continue; } @@ -1713,6 +1723,7 @@ int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon) { struct drm_connector *connector; struct amdgpu_device *adev = dev->dev_private; + struct drm_crtc *crtc; int r; if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) @@ -1746,6 +1757,24 @@ int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon) if (r) return r; + /* pin cursors */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); + + if (amdgpu_crtc->cursor_bo) { + struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); + r = amdgpu_bo_reserve(aobj, false); + if (r == 0) { + r = amdgpu_bo_pin(aobj, + AMDGPU_GEM_DOMAIN_VRAM, + &amdgpu_crtc->cursor_addr); + if (r != 0) + DRM_ERROR("Failed to pin cursor BO (%d)\n", r); + amdgpu_bo_unreserve(aobj); + } + } + } + /* blat the mode back in */ if (fbcon) { drm_helper_resume_force_mode(dev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 9b34a3410c32..de116398fa49 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -721,7 +721,7 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc, * an optional accurate timestamp of when query happened. * * \param dev Device to query. - * \param crtc Crtc to query. + * \param pipe Crtc to query. * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0). * \param *vpos Location where vertical scanout position should be stored. * \param *hpos Location where horizontal scanout position should go. @@ -744,8 +744,9 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc, * unknown small number of scanlines wrt. real scanout position. * */ -int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, - int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, +int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, + unsigned int flags, int *vpos, int *hpos, + ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode) { u32 vbl = 0, position = 0; @@ -760,7 +761,7 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl if (stime) *stime = ktime_get(); - if (amdgpu_display_page_flip_get_scanoutpos(adev, crtc, &vbl, &position) == 0) + if (amdgpu_display_page_flip_get_scanoutpos(adev, pipe, &vbl, &position) == 0) ret |= DRM_SCANOUTPOS_VALID; /* Get optional system timestamp after query. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index adb48353f2e1..ef58774b242c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -75,11 +75,13 @@ int amdgpu_bapm = -1; int amdgpu_deep_color = 0; int amdgpu_vm_size = 8; int amdgpu_vm_block_size = -1; +int amdgpu_vm_fault_stop = 0; +int amdgpu_vm_debug = 0; int amdgpu_exp_hw_support = 0; -int amdgpu_enable_scheduler = 0; +int amdgpu_enable_scheduler = 1; int amdgpu_sched_jobs = 16; int amdgpu_sched_hw_submission = 2; -int amdgpu_enable_semaphores = 1; +int amdgpu_enable_semaphores = 0; MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes"); module_param_named(vramlimit, amdgpu_vram_limit, int, 0600); @@ -141,10 +143,16 @@ module_param_named(vm_size, amdgpu_vm_size, int, 0444); MODULE_PARM_DESC(vm_block_size, "VM page table size in bits (default depending on vm_size)"); module_param_named(vm_block_size, amdgpu_vm_block_size, int, 0444); +MODULE_PARM_DESC(vm_fault_stop, "Stop on VM fault (0 = never (default), 1 = print first, 2 = always)"); +module_param_named(vm_fault_stop, amdgpu_vm_fault_stop, int, 0444); + +MODULE_PARM_DESC(vm_debug, "Debug VM handling (0 = disabled (default), 1 = enabled)"); +module_param_named(vm_debug, amdgpu_vm_debug, int, 0644); + MODULE_PARM_DESC(exp_hw_support, "experimental hw support (1 = enable, 0 = disable (default))"); module_param_named(exp_hw_support, amdgpu_exp_hw_support, int, 0444); -MODULE_PARM_DESC(enable_scheduler, "enable SW GPU scheduler (1 = enable, 0 = disable ((default))"); +MODULE_PARM_DESC(enable_scheduler, "enable SW GPU scheduler (1 = enable (default), 0 = disable)"); module_param_named(enable_scheduler, amdgpu_enable_scheduler, int, 0444); MODULE_PARM_DESC(sched_jobs, "the max number of jobs supported in the sw queue (default 16)"); @@ -153,7 +161,7 @@ module_param_named(sched_jobs, amdgpu_sched_jobs, int, 0444); MODULE_PARM_DESC(sched_hw_submission, "the max number of HW submissions (default 2)"); module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444); -MODULE_PARM_DESC(enable_semaphores, "Enable semaphores (1 = enable (default), 0 = disable)"); +MODULE_PARM_DESC(enable_semaphores, "Enable semaphores (1 = enable, 0 = disable (default))"); module_param_named(enable_semaphores, amdgpu_enable_semaphores, int, 0644); static struct pci_device_id pciidlist[] = { @@ -242,11 +250,11 @@ static struct pci_device_id pciidlist[] = { {0x1002, 0x985F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU}, #endif /* topaz */ - {0x1002, 0x6900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ}, - {0x1002, 0x6901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ}, - {0x1002, 0x6902, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ}, - {0x1002, 0x6903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ}, - {0x1002, 0x6907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ}, + {0x1002, 0x6900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT}, + {0x1002, 0x6901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT}, + {0x1002, 0x6902, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT}, + {0x1002, 0x6903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT}, + {0x1002, 0x6907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT}, /* tonga */ {0x1002, 0x6920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA}, {0x1002, 0x6921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA}, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index 8a122b1b7786..96290d9cddca 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -402,3 +402,19 @@ bool amdgpu_fbdev_robj_is_fb(struct amdgpu_device *adev, struct amdgpu_bo *robj) return true; return false; } + +void amdgpu_fbdev_restore_mode(struct amdgpu_device *adev) +{ + struct amdgpu_fbdev *afbdev = adev->mode_info.rfbdev; + struct drm_fb_helper *fb_helper; + int ret; + + if (!afbdev) + return; + + fb_helper = &afbdev->helper; + + ret = drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); + if (ret) + DRM_DEBUG("failed to restore crtc mode\n"); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index b3fc26c59787..fcad7e060938 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -628,8 +628,20 @@ int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring) init_waitqueue_head(&ring->fence_drv.fence_queue); if (amdgpu_enable_scheduler) { + long timeout = msecs_to_jiffies(amdgpu_lockup_timeout); + if (timeout == 0) { + /* + * FIXME: + * Delayed workqueue cannot use it directly, + * so the scheduler will not use delayed workqueue if + * MAX_SCHEDULE_TIMEOUT is set. + * Currently keep it simple and silly. + */ + timeout = MAX_SCHEDULE_TIMEOUT; + } r = amd_sched_init(&ring->sched, &amdgpu_sched_ops, - amdgpu_sched_hw_submission, ring->name); + amdgpu_sched_hw_submission, + timeout, ring->name); if (r) { DRM_ERROR("Failed to create scheduler on ring %s.\n", ring->name); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 275f1c3dbba0..1618e2294a16 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -218,8 +218,8 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file break; case AMDGPU_HW_IP_DMA: type = AMD_IP_BLOCK_TYPE_SDMA; - ring_mask = adev->sdma[0].ring.ready ? 1 : 0; - ring_mask |= ((adev->sdma[1].ring.ready ? 1 : 0) << 1); + for (i = 0; i < adev->sdma.num_instances; i++) + ring_mask |= ((adev->sdma.instance[i].ring.ready ? 1 : 0) << i); ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; ib_size_alignment = 1; break; @@ -341,10 +341,10 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file fw_info.feature = 0; break; case AMDGPU_INFO_FW_SDMA: - if (info->query_fw.index >= 2) + if (info->query_fw.index >= adev->sdma.num_instances) return -EINVAL; - fw_info.ver = adev->sdma[info->query_fw.index].fw_version; - fw_info.feature = adev->sdma[info->query_fw.index].feature_version; + fw_info.ver = adev->sdma.instance[info->query_fw.index].fw_version; + fw_info.feature = adev->sdma.instance[info->query_fw.index].feature_version; break; default: return -EINVAL; @@ -485,14 +485,17 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file * Outdated mess for old drm with Xorg being in charge (void function now). */ /** - * amdgpu_driver_firstopen_kms - drm callback for last close + * amdgpu_driver_lastclose_kms - drm callback for last close * * @dev: drm dev pointer * - * Switch vga switcheroo state after last close (all asics). + * Switch vga_switcheroo state after last close (all asics). */ void amdgpu_driver_lastclose_kms(struct drm_device *dev) { + struct amdgpu_device *adev = dev->dev_private; + + amdgpu_fbdev_restore_mode(adev); vga_switcheroo_process_delayed_switch(); } @@ -600,36 +603,36 @@ void amdgpu_driver_preclose_kms(struct drm_device *dev, * amdgpu_get_vblank_counter_kms - get frame count * * @dev: drm dev pointer - * @crtc: crtc to get the frame count from + * @pipe: crtc to get the frame count from * * Gets the frame count on the requested crtc (all asics). * Returns frame count on success, -EINVAL on failure. */ -u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, int crtc) +u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe) { struct amdgpu_device *adev = dev->dev_private; - if (crtc < 0 || crtc >= adev->mode_info.num_crtc) { - DRM_ERROR("Invalid crtc %d\n", crtc); + if (pipe >= adev->mode_info.num_crtc) { + DRM_ERROR("Invalid crtc %u\n", pipe); return -EINVAL; } - return amdgpu_display_vblank_get_counter(adev, crtc); + return amdgpu_display_vblank_get_counter(adev, pipe); } /** * amdgpu_enable_vblank_kms - enable vblank interrupt * * @dev: drm dev pointer - * @crtc: crtc to enable vblank interrupt for + * @pipe: crtc to enable vblank interrupt for * * Enable the interrupt on the requested crtc (all asics). * Returns 0 on success, -EINVAL on failure. */ -int amdgpu_enable_vblank_kms(struct drm_device *dev, int crtc) +int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe) { struct amdgpu_device *adev = dev->dev_private; - int idx = amdgpu_crtc_idx_to_irq_type(adev, crtc); + int idx = amdgpu_crtc_idx_to_irq_type(adev, pipe); return amdgpu_irq_get(adev, &adev->crtc_irq, idx); } @@ -638,14 +641,14 @@ int amdgpu_enable_vblank_kms(struct drm_device *dev, int crtc) * amdgpu_disable_vblank_kms - disable vblank interrupt * * @dev: drm dev pointer - * @crtc: crtc to disable vblank interrupt for + * @pipe: crtc to disable vblank interrupt for * * Disable the interrupt on the requested crtc (all asics). */ -void amdgpu_disable_vblank_kms(struct drm_device *dev, int crtc) +void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe) { struct amdgpu_device *adev = dev->dev_private; - int idx = amdgpu_crtc_idx_to_irq_type(adev, crtc); + int idx = amdgpu_crtc_idx_to_irq_type(adev, pipe); amdgpu_irq_put(adev, &adev->crtc_irq, idx); } @@ -663,41 +666,41 @@ void amdgpu_disable_vblank_kms(struct drm_device *dev, int crtc) * scanout position. (all asics). * Returns postive status flags on success, negative error on failure. */ -int amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, +int amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe, int *max_error, struct timeval *vblank_time, unsigned flags) { - struct drm_crtc *drmcrtc; + struct drm_crtc *crtc; struct amdgpu_device *adev = dev->dev_private; - if (crtc < 0 || crtc >= dev->num_crtcs) { - DRM_ERROR("Invalid crtc %d\n", crtc); + if (pipe >= dev->num_crtcs) { + DRM_ERROR("Invalid crtc %u\n", pipe); return -EINVAL; } /* Get associated drm_crtc: */ - drmcrtc = &adev->mode_info.crtcs[crtc]->base; + crtc = &adev->mode_info.crtcs[pipe]->base; /* Helper routine in DRM core does all the work: */ - return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, + return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, vblank_time, flags, - &drmcrtc->hwmode); + &crtc->hwmode); } const struct drm_ioctl_desc amdgpu_ioctls_kms[] = { - DRM_IOCTL_DEF_DRV(AMDGPU_GEM_CREATE, amdgpu_gem_create_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(AMDGPU_CTX, amdgpu_ctx_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(AMDGPU_BO_LIST, amdgpu_bo_list_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_GEM_CREATE, amdgpu_gem_create_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_CTX, amdgpu_ctx_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_BO_LIST, amdgpu_bo_list_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), /* KMS */ - DRM_IOCTL_DEF_DRV(AMDGPU_GEM_MMAP, amdgpu_gem_mmap_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(AMDGPU_GEM_WAIT_IDLE, amdgpu_gem_wait_idle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(AMDGPU_CS, amdgpu_cs_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(AMDGPU_INFO, amdgpu_info_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(AMDGPU_WAIT_CS, amdgpu_cs_wait_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(AMDGPU_GEM_METADATA, amdgpu_gem_metadata_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(AMDGPU_GEM_VA, amdgpu_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(AMDGPU_GEM_OP, amdgpu_gem_op_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(AMDGPU_GEM_USERPTR, amdgpu_gem_userptr_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_GEM_MMAP, amdgpu_gem_mmap_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_GEM_WAIT_IDLE, amdgpu_gem_wait_idle_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_CS, amdgpu_cs_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_INFO, amdgpu_info_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_WAIT_CS, amdgpu_cs_wait_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_GEM_METADATA, amdgpu_gem_metadata_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_GEM_VA, amdgpu_gem_va_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_GEM_OP, amdgpu_gem_op_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_GEM_USERPTR, amdgpu_gem_userptr_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), }; int amdgpu_max_kms_ioctl = ARRAY_SIZE(amdgpu_ioctls_kms); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 2b03425f9740..b62c1710cab6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -373,6 +373,10 @@ struct amdgpu_crtc { uint32_t crtc_offset; struct drm_gem_object *cursor_bo; uint64_t cursor_addr; + int cursor_x; + int cursor_y; + int cursor_hot_x; + int cursor_hot_y; int cursor_width; int cursor_height; int max_cursor_width; @@ -540,11 +544,10 @@ bool amdgpu_ddc_probe(struct amdgpu_connector *amdgpu_connector, bool use_aux); void amdgpu_encoder_set_active_device(struct drm_encoder *encoder); -int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, - unsigned int flags, - int *vpos, int *hpos, ktime_t *stime, - ktime_t *etime, - const struct drm_display_mode *mode); +int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, + unsigned int flags, int *vpos, int *hpos, + ktime_t *stime, ktime_t *etime, + const struct drm_display_mode *mode); int amdgpu_framebuffer_init(struct drm_device *dev, struct amdgpu_framebuffer *rfb, @@ -568,6 +571,7 @@ void amdgpu_fbdev_fini(struct amdgpu_device *adev); void amdgpu_fbdev_set_suspend(struct amdgpu_device *adev, int state); int amdgpu_fbdev_total_size(struct amdgpu_device *adev); bool amdgpu_fbdev_robj_is_fb(struct amdgpu_device *adev, struct amdgpu_bo *robj); +void amdgpu_fbdev_restore_mode(struct amdgpu_device *adev); void amdgpu_fb_output_poll_changed(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 1a7708f365f3..0d524384ff79 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -132,6 +132,8 @@ static void amdgpu_ttm_placement_init(struct amdgpu_device *adev, placements[c].fpfn = 0; placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; + if (!(flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)) + placements[c - 1].flags |= TTM_PL_FLAG_TOPDOWN; } if (domain & AMDGPU_GEM_DOMAIN_GTT) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 30dce235ddeb..b13a74b273a6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -540,8 +540,8 @@ static int amdgpu_debugfs_ring_info(struct seq_file *m, void *data) static int amdgpu_gfx_index = offsetof(struct amdgpu_device, gfx.gfx_ring[0]); static int cayman_cp1_index = offsetof(struct amdgpu_device, gfx.compute_ring[0]); static int cayman_cp2_index = offsetof(struct amdgpu_device, gfx.compute_ring[1]); -static int amdgpu_dma1_index = offsetof(struct amdgpu_device, sdma[0].ring); -static int amdgpu_dma2_index = offsetof(struct amdgpu_device, sdma[1].ring); +static int amdgpu_dma1_index = offsetof(struct amdgpu_device, sdma.instance[0].ring); +static int amdgpu_dma2_index = offsetof(struct amdgpu_device, sdma.instance[1].ring); static int r600_uvd_index = offsetof(struct amdgpu_device, uvd.ring); static int si_vce1_index = offsetof(struct amdgpu_device, vce.ring[0]); static int si_vce2_index = offsetof(struct amdgpu_device, vce.ring[1]); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index 961d7265c286..76ecbaf72a2e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -111,7 +111,7 @@ TRACE_EVENT(amdgpu_vm_bo_unmap, __entry->offset, __entry->flags) ); -TRACE_EVENT(amdgpu_vm_bo_update, +DECLARE_EVENT_CLASS(amdgpu_vm_mapping, TP_PROTO(struct amdgpu_bo_va_mapping *mapping), TP_ARGS(mapping), TP_STRUCT__entry( @@ -129,6 +129,16 @@ TRACE_EVENT(amdgpu_vm_bo_update, __entry->soffset, __entry->eoffset, __entry->flags) ); +DEFINE_EVENT(amdgpu_vm_mapping, amdgpu_vm_bo_update, + TP_PROTO(struct amdgpu_bo_va_mapping *mapping), + TP_ARGS(mapping) +); + +DEFINE_EVENT(amdgpu_vm_mapping, amdgpu_vm_bo_mapping, + TP_PROTO(struct amdgpu_bo_va_mapping *mapping), + TP_ARGS(mapping) +); + TRACE_EVENT(amdgpu_vm_set_page, TP_PROTO(uint64_t pe, uint64_t addr, unsigned count, uint32_t incr, uint32_t flags), diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 364cbe975332..a089e69e9927 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1072,6 +1072,11 @@ static int amdgpu_mm_dump_table(struct seq_file *m, void *data) spin_lock(&glob->lru_lock); ret = drm_mm_dump_table(m, mm); spin_unlock(&glob->lru_lock); + if (ttm_pl == TTM_PL_VRAM) + seq_printf(m, "man size:%llu pages, ram usage:%luMB, vis usage:%luMB\n", + adev->mman.bdev.man[ttm_pl].size, + atomic64_read(&adev->vram_usage) >> 20, + atomic64_read(&adev->vram_vis_usage) >> 20); return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 1e14531353e0..644fd9b8591f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -147,8 +147,10 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring, /* check if the id is still valid */ if (vm_id->id && vm_id->last_id_use && - vm_id->last_id_use == adev->vm_manager.active[vm_id->id]) + vm_id->last_id_use == adev->vm_manager.active[vm_id->id]) { + trace_amdgpu_vm_grab_id(vm_id->id, ring->idx); return 0; + } /* we definately need to flush */ vm_id->pd_gpu_addr = ~0ll; @@ -455,8 +457,10 @@ int amdgpu_vm_update_page_directory(struct amdgpu_device *adev, return -ENOMEM; r = amdgpu_ib_get(ring, NULL, ndw * 4, ib); - if (r) + if (r) { + kfree(ib); return r; + } ib->length_dw = 0; /* walk over the address space and update the page directory */ @@ -850,6 +854,14 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, return r; } + if (trace_amdgpu_vm_bo_mapping_enabled()) { + list_for_each_entry(mapping, &bo_va->valids, list) + trace_amdgpu_vm_bo_mapping(mapping); + + list_for_each_entry(mapping, &bo_va->invalids, list) + trace_amdgpu_vm_bo_mapping(mapping); + } + spin_lock(&vm->status_lock); list_splice_init(&bo_va->invalids, &bo_va->valids); list_del_init(&bo_va->vm_status); diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c index a0346a90d805..1b50e6c13fb3 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.c +++ b/drivers/gpu/drm/amd/amdgpu/atom.c @@ -685,6 +685,27 @@ static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg) } } +static void atom_op_div32(atom_exec_context *ctx, int *ptr, int arg) +{ + uint64_t val64; + uint8_t attr = U8((*ptr)++); + uint32_t dst, src; + SDEBUG(" src1: "); + dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); + SDEBUG(" src2: "); + src = atom_get_src(ctx, attr, ptr); + if (src != 0) { + val64 = dst; + val64 |= ((uint64_t)ctx->ctx->divmul[1]) << 32; + do_div(val64, src); + ctx->ctx->divmul[0] = lower_32_bits(val64); + ctx->ctx->divmul[1] = upper_32_bits(val64); + } else { + ctx->ctx->divmul[0] = 0; + ctx->ctx->divmul[1] = 0; + } +} + static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg) { /* functionally, a nop */ @@ -788,6 +809,20 @@ static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg) ctx->ctx->divmul[0] = dst * src; } +static void atom_op_mul32(atom_exec_context *ctx, int *ptr, int arg) +{ + uint64_t val64; + uint8_t attr = U8((*ptr)++); + uint32_t dst, src; + SDEBUG(" src1: "); + dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); + SDEBUG(" src2: "); + src = atom_get_src(ctx, attr, ptr); + val64 = (uint64_t)dst * (uint64_t)src; + ctx->ctx->divmul[0] = lower_32_bits(val64); + ctx->ctx->divmul[1] = upper_32_bits(val64); +} + static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg) { /* nothing */ @@ -1022,7 +1057,15 @@ static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg) static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg) { - printk(KERN_INFO "unimplemented!\n"); + uint8_t val = U8((*ptr)++); + SDEBUG("DEBUG output: 0x%02X\n", val); +} + +static void atom_op_processds(atom_exec_context *ctx, int *ptr, int arg) +{ + uint16_t val = U16(*ptr); + (*ptr) += val + 2; + SDEBUG("PROCESSDS output: 0x%02X\n", val); } static struct { @@ -1151,7 +1194,13 @@ static struct { atom_op_shr, ATOM_ARG_FB}, { atom_op_shr, ATOM_ARG_PLL}, { atom_op_shr, ATOM_ARG_MC}, { -atom_op_debug, 0},}; + atom_op_debug, 0}, { + atom_op_processds, 0}, { + atom_op_mul32, ATOM_ARG_PS}, { + atom_op_mul32, ATOM_ARG_WS}, { + atom_op_div32, ATOM_ARG_PS}, { + atom_op_div32, ATOM_ARG_WS}, +}; static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params) { diff --git a/drivers/gpu/drm/amd/amdgpu/atom.h b/drivers/gpu/drm/amd/amdgpu/atom.h index 09d0f8230708..fece8f45dc7a 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.h +++ b/drivers/gpu/drm/amd/amdgpu/atom.h @@ -60,7 +60,7 @@ #define ATOM_CT_PS_MASK 0x7F #define ATOM_CT_CODE_PTR 6 -#define ATOM_OP_CNT 123 +#define ATOM_OP_CNT 127 #define ATOM_OP_EOT 91 #define ATOM_CASE_MAGIC 0x63 diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c index cd6edc40c9cd..1e0bba29e167 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c @@ -1279,8 +1279,7 @@ amdgpu_atombios_encoder_setup_dig(struct drm_encoder *encoder, int action) amdgpu_atombios_encoder_setup_dig_encoder(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); } if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - amdgpu_atombios_encoder_setup_dig_transmitter(encoder, - ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); + amdgpu_atombios_encoder_set_backlight_level(amdgpu_encoder, dig->backlight_level); if (ext_encoder) amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder, ATOM_ENABLE); } else { diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index 82e8d0730517..a1a35a5df8e7 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -6185,6 +6185,11 @@ static int ci_dpm_late_init(void *handle) if (!amdgpu_dpm) return 0; + /* init the sysfs and debugfs files late */ + ret = amdgpu_pm_sysfs_init(adev); + if (ret) + return ret; + ret = ci_set_temperature_range(adev); if (ret) return ret; @@ -6232,9 +6237,6 @@ static int ci_dpm_sw_init(void *handle) adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps; if (amdgpu_dpm == 1) amdgpu_pm_print_power_states(adev); - ret = amdgpu_pm_sysfs_init(adev); - if (ret) - goto dpm_failed; mutex_unlock(&adev->pm.mutex); DRM_INFO("amdgpu: dpm initialized\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 4b6ce74753cd..484710cfdf82 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -1567,6 +1567,9 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev) int ret, i; u16 tmp16; + if (pci_is_root_bus(adev->pdev->bus)) + return; + if (amdgpu_pcie_gen2 == 0) return; diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index 9ea9de457da3..814598e76c98 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -96,7 +96,7 @@ static int cik_sdma_init_microcode(struct amdgpu_device *adev) { const char *chip_name; char fw_name[30]; - int err, i; + int err = 0, i; DRM_DEBUG("\n"); @@ -119,24 +119,24 @@ static int cik_sdma_init_microcode(struct amdgpu_device *adev) default: BUG(); } - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { if (i == 0) snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name); else snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma1.bin", chip_name); - err = request_firmware(&adev->sdma[i].fw, fw_name, adev->dev); + err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev); if (err) goto out; - err = amdgpu_ucode_validate(adev->sdma[i].fw); + err = amdgpu_ucode_validate(adev->sdma.instance[i].fw); } out: if (err) { printk(KERN_ERR "cik_sdma: Failed to load firmware \"%s\"\n", fw_name); - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { - release_firmware(adev->sdma[i].fw); - adev->sdma[i].fw = NULL; + for (i = 0; i < adev->sdma.num_instances; i++) { + release_firmware(adev->sdma.instance[i].fw); + adev->sdma.instance[i].fw = NULL; } } return err; @@ -168,7 +168,7 @@ static uint32_t cik_sdma_ring_get_rptr(struct amdgpu_ring *ring) static uint32_t cik_sdma_ring_get_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - u32 me = (ring == &adev->sdma[0].ring) ? 0 : 1; + u32 me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; return (RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me]) & 0x3fffc) >> 2; } @@ -183,14 +183,14 @@ static uint32_t cik_sdma_ring_get_wptr(struct amdgpu_ring *ring) static void cik_sdma_ring_set_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - u32 me = (ring == &adev->sdma[0].ring) ? 0 : 1; + u32 me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], (ring->wptr << 2) & 0x3fffc); } static void cik_sdma_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) { - struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ring); + struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring); int i; for (i = 0; i < count; i++) @@ -248,7 +248,7 @@ static void cik_sdma_ring_emit_hdp_flush(struct amdgpu_ring *ring) SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */ u32 ref_and_mask; - if (ring == &ring->adev->sdma[0].ring) + if (ring == &ring->adev->sdma.instance[0].ring) ref_and_mask = GPU_HDP_FLUSH_DONE__SDMA0_MASK; else ref_and_mask = GPU_HDP_FLUSH_DONE__SDMA1_MASK; @@ -327,8 +327,8 @@ static bool cik_sdma_ring_emit_semaphore(struct amdgpu_ring *ring, */ static void cik_sdma_gfx_stop(struct amdgpu_device *adev) { - struct amdgpu_ring *sdma0 = &adev->sdma[0].ring; - struct amdgpu_ring *sdma1 = &adev->sdma[1].ring; + struct amdgpu_ring *sdma0 = &adev->sdma.instance[0].ring; + struct amdgpu_ring *sdma1 = &adev->sdma.instance[1].ring; u32 rb_cntl; int i; @@ -336,7 +336,7 @@ static void cik_sdma_gfx_stop(struct amdgpu_device *adev) (adev->mman.buffer_funcs_ring == sdma1)) amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size); - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { rb_cntl = RREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i]); rb_cntl &= ~SDMA0_GFX_RB_CNTL__RB_ENABLE_MASK; WREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i], rb_cntl); @@ -376,7 +376,7 @@ static void cik_sdma_enable(struct amdgpu_device *adev, bool enable) cik_sdma_rlc_stop(adev); } - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { me_cntl = RREG32(mmSDMA0_F32_CNTL + sdma_offsets[i]); if (enable) me_cntl &= ~SDMA0_F32_CNTL__HALT_MASK; @@ -402,8 +402,8 @@ static int cik_sdma_gfx_resume(struct amdgpu_device *adev) u32 wb_offset; int i, j, r; - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { - ring = &adev->sdma[i].ring; + for (i = 0; i < adev->sdma.num_instances; i++) { + ring = &adev->sdma.instance[i].ring; wb_offset = (ring->rptr_offs * 4); mutex_lock(&adev->srbm_mutex); @@ -502,26 +502,25 @@ static int cik_sdma_load_microcode(struct amdgpu_device *adev) u32 fw_size; int i, j; - if (!adev->sdma[0].fw || !adev->sdma[1].fw) - return -EINVAL; - /* halt the MEs */ cik_sdma_enable(adev, false); - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { - hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data; + for (i = 0; i < adev->sdma.num_instances; i++) { + if (!adev->sdma.instance[i].fw) + return -EINVAL; + hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma.instance[i].fw->data; amdgpu_ucode_print_sdma_hdr(&hdr->header); fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; - adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); - adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); - if (adev->sdma[i].feature_version >= 20) - adev->sdma[i].burst_nop = true; + adev->sdma.instance[i].fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->sdma.instance[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); + if (adev->sdma.instance[i].feature_version >= 20) + adev->sdma.instance[i].burst_nop = true; fw_data = (const __le32 *) - (adev->sdma[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + (adev->sdma.instance[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], 0); for (j = 0; j < fw_size; j++) WREG32(mmSDMA0_UCODE_DATA + sdma_offsets[i], le32_to_cpup(fw_data++)); - WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], adev->sdma[i].fw_version); + WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], adev->sdma.instance[i].fw_version); } return 0; @@ -830,7 +829,7 @@ static void cik_sdma_vm_set_pte_pde(struct amdgpu_ib *ib, */ static void cik_sdma_vm_pad_ib(struct amdgpu_ib *ib) { - struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ib->ring); + struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ib->ring); u32 pad_count; int i; @@ -934,6 +933,8 @@ static int cik_sdma_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + adev->sdma.num_instances = SDMA_MAX_INSTANCE; + cik_sdma_set_ring_funcs(adev); cik_sdma_set_irq_funcs(adev); cik_sdma_set_buffer_funcs(adev); @@ -946,7 +947,7 @@ static int cik_sdma_sw_init(void *handle) { struct amdgpu_ring *ring; struct amdgpu_device *adev = (struct amdgpu_device *)handle; - int r; + int r, i; r = cik_sdma_init_microcode(adev); if (r) { @@ -955,43 +956,33 @@ static int cik_sdma_sw_init(void *handle) } /* SDMA trap event */ - r = amdgpu_irq_add_id(adev, 224, &adev->sdma_trap_irq); + r = amdgpu_irq_add_id(adev, 224, &adev->sdma.trap_irq); if (r) return r; /* SDMA Privileged inst */ - r = amdgpu_irq_add_id(adev, 241, &adev->sdma_illegal_inst_irq); + r = amdgpu_irq_add_id(adev, 241, &adev->sdma.illegal_inst_irq); if (r) return r; /* SDMA Privileged inst */ - r = amdgpu_irq_add_id(adev, 247, &adev->sdma_illegal_inst_irq); - if (r) - return r; - - ring = &adev->sdma[0].ring; - ring->ring_obj = NULL; - - ring = &adev->sdma[1].ring; - ring->ring_obj = NULL; - - ring = &adev->sdma[0].ring; - sprintf(ring->name, "sdma0"); - r = amdgpu_ring_init(adev, ring, 256 * 1024, - SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0), 0xf, - &adev->sdma_trap_irq, AMDGPU_SDMA_IRQ_TRAP0, - AMDGPU_RING_TYPE_SDMA); + r = amdgpu_irq_add_id(adev, 247, &adev->sdma.illegal_inst_irq); if (r) return r; - ring = &adev->sdma[1].ring; - sprintf(ring->name, "sdma1"); - r = amdgpu_ring_init(adev, ring, 256 * 1024, - SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0), 0xf, - &adev->sdma_trap_irq, AMDGPU_SDMA_IRQ_TRAP1, - AMDGPU_RING_TYPE_SDMA); - if (r) - return r; + for (i = 0; i < adev->sdma.num_instances; i++) { + ring = &adev->sdma.instance[i].ring; + ring->ring_obj = NULL; + sprintf(ring->name, "sdma%d", i); + r = amdgpu_ring_init(adev, ring, 256 * 1024, + SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0), 0xf, + &adev->sdma.trap_irq, + (i == 0) ? + AMDGPU_SDMA_IRQ_TRAP0 : AMDGPU_SDMA_IRQ_TRAP1, + AMDGPU_RING_TYPE_SDMA); + if (r) + return r; + } return r; } @@ -999,9 +990,10 @@ static int cik_sdma_sw_init(void *handle) static int cik_sdma_sw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int i; - amdgpu_ring_fini(&adev->sdma[0].ring); - amdgpu_ring_fini(&adev->sdma[1].ring); + for (i = 0; i < adev->sdma.num_instances; i++) + amdgpu_ring_fini(&adev->sdma.instance[i].ring); return 0; } @@ -1078,7 +1070,7 @@ static void cik_sdma_print_status(void *handle) dev_info(adev->dev, "CIK SDMA registers\n"); dev_info(adev->dev, " SRBM_STATUS2=0x%08X\n", RREG32(mmSRBM_STATUS2)); - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { dev_info(adev->dev, " SDMA%d_STATUS_REG=0x%08X\n", i, RREG32(mmSDMA0_STATUS_REG + sdma_offsets[i])); dev_info(adev->dev, " SDMA%d_ME_CNTL=0x%08X\n", @@ -1223,7 +1215,7 @@ static int cik_sdma_process_trap_irq(struct amdgpu_device *adev, case 0: switch (queue_id) { case 0: - amdgpu_fence_process(&adev->sdma[0].ring); + amdgpu_fence_process(&adev->sdma.instance[0].ring); break; case 1: /* XXX compute */ @@ -1236,7 +1228,7 @@ static int cik_sdma_process_trap_irq(struct amdgpu_device *adev, case 1: switch (queue_id) { case 0: - amdgpu_fence_process(&adev->sdma[1].ring); + amdgpu_fence_process(&adev->sdma.instance[1].ring); break; case 1: /* XXX compute */ @@ -1334,8 +1326,10 @@ static const struct amdgpu_ring_funcs cik_sdma_ring_funcs = { static void cik_sdma_set_ring_funcs(struct amdgpu_device *adev) { - adev->sdma[0].ring.funcs = &cik_sdma_ring_funcs; - adev->sdma[1].ring.funcs = &cik_sdma_ring_funcs; + int i; + + for (i = 0; i < adev->sdma.num_instances; i++) + adev->sdma.instance[i].ring.funcs = &cik_sdma_ring_funcs; } static const struct amdgpu_irq_src_funcs cik_sdma_trap_irq_funcs = { @@ -1349,9 +1343,9 @@ static const struct amdgpu_irq_src_funcs cik_sdma_illegal_inst_irq_funcs = { static void cik_sdma_set_irq_funcs(struct amdgpu_device *adev) { - adev->sdma_trap_irq.num_types = AMDGPU_SDMA_IRQ_LAST; - adev->sdma_trap_irq.funcs = &cik_sdma_trap_irq_funcs; - adev->sdma_illegal_inst_irq.funcs = &cik_sdma_illegal_inst_irq_funcs; + adev->sdma.trap_irq.num_types = AMDGPU_SDMA_IRQ_LAST; + adev->sdma.trap_irq.funcs = &cik_sdma_trap_irq_funcs; + adev->sdma.illegal_inst_irq.funcs = &cik_sdma_illegal_inst_irq_funcs; } /** @@ -1416,7 +1410,7 @@ static void cik_sdma_set_buffer_funcs(struct amdgpu_device *adev) { if (adev->mman.buffer_funcs == NULL) { adev->mman.buffer_funcs = &cik_sdma_buffer_funcs; - adev->mman.buffer_funcs_ring = &adev->sdma[0].ring; + adev->mman.buffer_funcs_ring = &adev->sdma.instance[0].ring; } } @@ -1431,7 +1425,7 @@ static void cik_sdma_set_vm_pte_funcs(struct amdgpu_device *adev) { if (adev->vm_manager.vm_pte_funcs == NULL) { adev->vm_manager.vm_pte_funcs = &cik_sdma_vm_pte_funcs; - adev->vm_manager.vm_pte_funcs_ring = &adev->sdma[0].ring; + adev->vm_manager.vm_pte_funcs_ring = &adev->sdma.instance[0].ring; adev->vm_manager.vm_pte_funcs_ring->is_pte_ring = true; } } diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c index 44fa96ad4709..2e3373ed4c94 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c @@ -596,6 +596,12 @@ static int cz_dpm_late_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; if (amdgpu_dpm) { + int ret; + /* init the sysfs and debugfs files late */ + ret = amdgpu_pm_sysfs_init(adev); + if (ret) + return ret; + /* powerdown unused blocks for now */ cz_dpm_powergate_uvd(adev, true); cz_dpm_powergate_vce(adev, true); @@ -632,10 +638,6 @@ static int cz_dpm_sw_init(void *handle) if (amdgpu_dpm == 1) amdgpu_pm_print_power_states(adev); - ret = amdgpu_pm_sysfs_init(adev); - if (ret) - goto dpm_init_failed; - mutex_unlock(&adev->pm.mutex); DRM_INFO("amdgpu: dpm initialized\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index e4d101b1252a..37073930e2c9 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -2499,26 +2499,19 @@ static void dce_v10_0_show_cursor(struct drm_crtc *crtc) struct amdgpu_device *adev = crtc->dev->dev_private; u32 tmp; + WREG32(mmCUR_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, + upper_32_bits(amdgpu_crtc->cursor_addr)); + WREG32(mmCUR_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset, + lower_32_bits(amdgpu_crtc->cursor_addr)); + tmp = RREG32_IDX(mmCUR_CONTROL + amdgpu_crtc->crtc_offset); tmp = REG_SET_FIELD(tmp, CUR_CONTROL, CURSOR_EN, 1); tmp = REG_SET_FIELD(tmp, CUR_CONTROL, CURSOR_MODE, 2); WREG32_IDX(mmCUR_CONTROL + amdgpu_crtc->crtc_offset, tmp); } -static void dce_v10_0_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, - uint64_t gpu_addr) -{ - struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; - - WREG32(mmCUR_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, - upper_32_bits(gpu_addr)); - WREG32(mmCUR_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset, - lower_32_bits(gpu_addr)); -} - -static int dce_v10_0_crtc_cursor_move(struct drm_crtc *crtc, - int x, int y) +static int dce_v10_0_cursor_move_locked(struct drm_crtc *crtc, + int x, int y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct amdgpu_device *adev = crtc->dev->dev_private; @@ -2538,26 +2531,40 @@ static int dce_v10_0_crtc_cursor_move(struct drm_crtc *crtc, y = 0; } - dce_v10_0_lock_cursor(crtc, true); WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y); WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin); WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1)); - dce_v10_0_lock_cursor(crtc, false); + + amdgpu_crtc->cursor_x = x; + amdgpu_crtc->cursor_y = y; return 0; } -static int dce_v10_0_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, - uint32_t handle, - uint32_t width, - uint32_t height) +static int dce_v10_0_crtc_cursor_move(struct drm_crtc *crtc, + int x, int y) +{ + int ret; + + dce_v10_0_lock_cursor(crtc, true); + ret = dce_v10_0_cursor_move_locked(crtc, x, y); + dce_v10_0_lock_cursor(crtc, false); + + return ret; +} + +static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height, + int32_t hot_x, + int32_t hot_y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_gem_object *obj; - struct amdgpu_bo *robj; - uint64_t gpu_addr; + struct amdgpu_bo *aobj; int ret; if (!handle) { @@ -2579,41 +2586,71 @@ static int dce_v10_0_crtc_cursor_set(struct drm_crtc *crtc, return -ENOENT; } - robj = gem_to_amdgpu_bo(obj); - ret = amdgpu_bo_reserve(robj, false); - if (unlikely(ret != 0)) - goto fail; - ret = amdgpu_bo_pin_restricted(robj, AMDGPU_GEM_DOMAIN_VRAM, - 0, 0, &gpu_addr); - amdgpu_bo_unreserve(robj); - if (ret) - goto fail; + aobj = gem_to_amdgpu_bo(obj); + ret = amdgpu_bo_reserve(aobj, false); + if (ret != 0) { + drm_gem_object_unreference_unlocked(obj); + return ret; + } + + ret = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM, &amdgpu_crtc->cursor_addr); + amdgpu_bo_unreserve(aobj); + if (ret) { + DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret); + drm_gem_object_unreference_unlocked(obj); + return ret; + } amdgpu_crtc->cursor_width = width; amdgpu_crtc->cursor_height = height; dce_v10_0_lock_cursor(crtc, true); - dce_v10_0_set_cursor(crtc, obj, gpu_addr); + + if (hot_x != amdgpu_crtc->cursor_hot_x || + hot_y != amdgpu_crtc->cursor_hot_y) { + int x, y; + + x = amdgpu_crtc->cursor_x + amdgpu_crtc->cursor_hot_x - hot_x; + y = amdgpu_crtc->cursor_y + amdgpu_crtc->cursor_hot_y - hot_y; + + dce_v10_0_cursor_move_locked(crtc, x, y); + + amdgpu_crtc->cursor_hot_x = hot_x; + amdgpu_crtc->cursor_hot_y = hot_y; + } + dce_v10_0_show_cursor(crtc); dce_v10_0_lock_cursor(crtc, false); unpin: if (amdgpu_crtc->cursor_bo) { - robj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); - ret = amdgpu_bo_reserve(robj, false); + struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); + ret = amdgpu_bo_reserve(aobj, false); if (likely(ret == 0)) { - amdgpu_bo_unpin(robj); - amdgpu_bo_unreserve(robj); + amdgpu_bo_unpin(aobj); + amdgpu_bo_unreserve(aobj); } drm_gem_object_unreference_unlocked(amdgpu_crtc->cursor_bo); } amdgpu_crtc->cursor_bo = obj; return 0; -fail: - drm_gem_object_unreference_unlocked(obj); +} - return ret; +static void dce_v10_0_cursor_reset(struct drm_crtc *crtc) +{ + struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); + + if (amdgpu_crtc->cursor_bo) { + dce_v10_0_lock_cursor(crtc, true); + + dce_v10_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x, + amdgpu_crtc->cursor_y); + + dce_v10_0_show_cursor(crtc); + + dce_v10_0_lock_cursor(crtc, false); + } } static void dce_v10_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, @@ -2641,7 +2678,7 @@ static void dce_v10_0_crtc_destroy(struct drm_crtc *crtc) } static const struct drm_crtc_funcs dce_v10_0_crtc_funcs = { - .cursor_set = dce_v10_0_crtc_cursor_set, + .cursor_set2 = dce_v10_0_crtc_cursor_set2, .cursor_move = dce_v10_0_crtc_cursor_move, .gamma_set = dce_v10_0_crtc_gamma_set, .set_config = amdgpu_crtc_set_config, @@ -2774,6 +2811,7 @@ static int dce_v10_0_crtc_mode_set(struct drm_crtc *crtc, dce_v10_0_crtc_do_set_base(crtc, old_fb, x, y, 0); amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode); amdgpu_atombios_crtc_scaler_setup(crtc); + dce_v10_0_cursor_reset(crtc); /* update the hw version fpr dpm */ amdgpu_crtc->hw_mode = *adjusted_mode; @@ -3267,37 +3305,20 @@ static int dce_v10_0_set_pageflip_irq_state(struct amdgpu_device *adev, unsigned type, enum amdgpu_interrupt_state state) { - u32 reg, reg_block; - /* now deal with page flip IRQ */ - switch (type) { - case AMDGPU_PAGEFLIP_IRQ_D1: - reg_block = CRTC0_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D2: - reg_block = CRTC1_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D3: - reg_block = CRTC2_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D4: - reg_block = CRTC3_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D5: - reg_block = CRTC4_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D6: - reg_block = CRTC5_REGISTER_OFFSET; - break; - default: - DRM_ERROR("invalid pageflip crtc %d\n", type); - return -EINVAL; + u32 reg; + + if (type >= adev->mode_info.num_crtc) { + DRM_ERROR("invalid pageflip crtc %d\n", type); + return -EINVAL; } - reg = RREG32(mmGRPH_INTERRUPT_CONTROL + reg_block); + reg = RREG32(mmGRPH_INTERRUPT_CONTROL + crtc_offsets[type]); if (state == AMDGPU_IRQ_STATE_DISABLE) - WREG32(mmGRPH_INTERRUPT_CONTROL + reg_block, reg & ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK); + WREG32(mmGRPH_INTERRUPT_CONTROL + crtc_offsets[type], + reg & ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK); else - WREG32(mmGRPH_INTERRUPT_CONTROL + reg_block, reg | GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK); + WREG32(mmGRPH_INTERRUPT_CONTROL + crtc_offsets[type], + reg | GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK); return 0; } @@ -3306,7 +3327,6 @@ static int dce_v10_0_pageflip_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) { - int reg_block; unsigned long flags; unsigned crtc_id; struct amdgpu_crtc *amdgpu_crtc; @@ -3315,33 +3335,15 @@ static int dce_v10_0_pageflip_irq(struct amdgpu_device *adev, crtc_id = (entry->src_id - 8) >> 1; amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; - /* ack the interrupt */ - switch(crtc_id){ - case AMDGPU_PAGEFLIP_IRQ_D1: - reg_block = CRTC0_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D2: - reg_block = CRTC1_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D3: - reg_block = CRTC2_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D4: - reg_block = CRTC3_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D5: - reg_block = CRTC4_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D6: - reg_block = CRTC5_REGISTER_OFFSET; - break; - default: - DRM_ERROR("invalid pageflip crtc %d\n", crtc_id); - return -EINVAL; + if (crtc_id >= adev->mode_info.num_crtc) { + DRM_ERROR("invalid pageflip crtc %d\n", crtc_id); + return -EINVAL; } - if (RREG32(mmGRPH_INTERRUPT_STATUS + reg_block) & GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_OCCURRED_MASK) - WREG32(mmGRPH_INTERRUPT_STATUS + reg_block, GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK); + if (RREG32(mmGRPH_INTERRUPT_STATUS + crtc_offsets[crtc_id]) & + GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_OCCURRED_MASK) + WREG32(mmGRPH_INTERRUPT_STATUS + crtc_offsets[crtc_id], + GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK); /* IRQ could occur when in initial stage */ if (amdgpu_crtc == NULL) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 6411e8244671..5be83a3f0192 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -2476,26 +2476,19 @@ static void dce_v11_0_show_cursor(struct drm_crtc *crtc) struct amdgpu_device *adev = crtc->dev->dev_private; u32 tmp; + WREG32(mmCUR_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, + upper_32_bits(amdgpu_crtc->cursor_addr)); + WREG32(mmCUR_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset, + lower_32_bits(amdgpu_crtc->cursor_addr)); + tmp = RREG32_IDX(mmCUR_CONTROL + amdgpu_crtc->crtc_offset); tmp = REG_SET_FIELD(tmp, CUR_CONTROL, CURSOR_EN, 1); tmp = REG_SET_FIELD(tmp, CUR_CONTROL, CURSOR_MODE, 2); WREG32_IDX(mmCUR_CONTROL + amdgpu_crtc->crtc_offset, tmp); } -static void dce_v11_0_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, - uint64_t gpu_addr) -{ - struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; - - WREG32(mmCUR_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, - upper_32_bits(gpu_addr)); - WREG32(mmCUR_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset, - lower_32_bits(gpu_addr)); -} - -static int dce_v11_0_crtc_cursor_move(struct drm_crtc *crtc, - int x, int y) +static int dce_v11_0_cursor_move_locked(struct drm_crtc *crtc, + int x, int y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct amdgpu_device *adev = crtc->dev->dev_private; @@ -2515,26 +2508,40 @@ static int dce_v11_0_crtc_cursor_move(struct drm_crtc *crtc, y = 0; } - dce_v11_0_lock_cursor(crtc, true); WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y); WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin); WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1)); - dce_v11_0_lock_cursor(crtc, false); + + amdgpu_crtc->cursor_x = x; + amdgpu_crtc->cursor_y = y; return 0; } -static int dce_v11_0_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, - uint32_t handle, - uint32_t width, - uint32_t height) +static int dce_v11_0_crtc_cursor_move(struct drm_crtc *crtc, + int x, int y) +{ + int ret; + + dce_v11_0_lock_cursor(crtc, true); + ret = dce_v11_0_cursor_move_locked(crtc, x, y); + dce_v11_0_lock_cursor(crtc, false); + + return ret; +} + +static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height, + int32_t hot_x, + int32_t hot_y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_gem_object *obj; - struct amdgpu_bo *robj; - uint64_t gpu_addr; + struct amdgpu_bo *aobj; int ret; if (!handle) { @@ -2556,41 +2563,71 @@ static int dce_v11_0_crtc_cursor_set(struct drm_crtc *crtc, return -ENOENT; } - robj = gem_to_amdgpu_bo(obj); - ret = amdgpu_bo_reserve(robj, false); - if (unlikely(ret != 0)) - goto fail; - ret = amdgpu_bo_pin_restricted(robj, AMDGPU_GEM_DOMAIN_VRAM, - 0, 0, &gpu_addr); - amdgpu_bo_unreserve(robj); - if (ret) - goto fail; + aobj = gem_to_amdgpu_bo(obj); + ret = amdgpu_bo_reserve(aobj, false); + if (ret != 0) { + drm_gem_object_unreference_unlocked(obj); + return ret; + } + + ret = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM, &amdgpu_crtc->cursor_addr); + amdgpu_bo_unreserve(aobj); + if (ret) { + DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret); + drm_gem_object_unreference_unlocked(obj); + return ret; + } amdgpu_crtc->cursor_width = width; amdgpu_crtc->cursor_height = height; dce_v11_0_lock_cursor(crtc, true); - dce_v11_0_set_cursor(crtc, obj, gpu_addr); + + if (hot_x != amdgpu_crtc->cursor_hot_x || + hot_y != amdgpu_crtc->cursor_hot_y) { + int x, y; + + x = amdgpu_crtc->cursor_x + amdgpu_crtc->cursor_hot_x - hot_x; + y = amdgpu_crtc->cursor_y + amdgpu_crtc->cursor_hot_y - hot_y; + + dce_v11_0_cursor_move_locked(crtc, x, y); + + amdgpu_crtc->cursor_hot_x = hot_x; + amdgpu_crtc->cursor_hot_y = hot_y; + } + dce_v11_0_show_cursor(crtc); dce_v11_0_lock_cursor(crtc, false); unpin: if (amdgpu_crtc->cursor_bo) { - robj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); - ret = amdgpu_bo_reserve(robj, false); + struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); + ret = amdgpu_bo_reserve(aobj, false); if (likely(ret == 0)) { - amdgpu_bo_unpin(robj); - amdgpu_bo_unreserve(robj); + amdgpu_bo_unpin(aobj); + amdgpu_bo_unreserve(aobj); } drm_gem_object_unreference_unlocked(amdgpu_crtc->cursor_bo); } amdgpu_crtc->cursor_bo = obj; return 0; -fail: - drm_gem_object_unreference_unlocked(obj); +} - return ret; +static void dce_v11_0_cursor_reset(struct drm_crtc *crtc) +{ + struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); + + if (amdgpu_crtc->cursor_bo) { + dce_v11_0_lock_cursor(crtc, true); + + dce_v11_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x, + amdgpu_crtc->cursor_y); + + dce_v11_0_show_cursor(crtc); + + dce_v11_0_lock_cursor(crtc, false); + } } static void dce_v11_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, @@ -2618,7 +2655,7 @@ static void dce_v11_0_crtc_destroy(struct drm_crtc *crtc) } static const struct drm_crtc_funcs dce_v11_0_crtc_funcs = { - .cursor_set = dce_v11_0_crtc_cursor_set, + .cursor_set2 = dce_v11_0_crtc_cursor_set2, .cursor_move = dce_v11_0_crtc_cursor_move, .gamma_set = dce_v11_0_crtc_gamma_set, .set_config = amdgpu_crtc_set_config, @@ -2751,6 +2788,7 @@ static int dce_v11_0_crtc_mode_set(struct drm_crtc *crtc, dce_v11_0_crtc_do_set_base(crtc, old_fb, x, y, 0); amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode); amdgpu_atombios_crtc_scaler_setup(crtc); + dce_v11_0_cursor_reset(crtc); /* update the hw version fpr dpm */ amdgpu_crtc->hw_mode = *adjusted_mode; @@ -2888,7 +2926,7 @@ static int dce_v11_0_early_init(void *handle) switch (adev->asic_type) { case CHIP_CARRIZO: - adev->mode_info.num_crtc = 4; + adev->mode_info.num_crtc = 3; adev->mode_info.num_hpd = 6; adev->mode_info.num_dig = 9; break; @@ -3243,37 +3281,20 @@ static int dce_v11_0_set_pageflip_irq_state(struct amdgpu_device *adev, unsigned type, enum amdgpu_interrupt_state state) { - u32 reg, reg_block; - /* now deal with page flip IRQ */ - switch (type) { - case AMDGPU_PAGEFLIP_IRQ_D1: - reg_block = CRTC0_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D2: - reg_block = CRTC1_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D3: - reg_block = CRTC2_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D4: - reg_block = CRTC3_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D5: - reg_block = CRTC4_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D6: - reg_block = CRTC5_REGISTER_OFFSET; - break; - default: - DRM_ERROR("invalid pageflip crtc %d\n", type); - return -EINVAL; + u32 reg; + + if (type >= adev->mode_info.num_crtc) { + DRM_ERROR("invalid pageflip crtc %d\n", type); + return -EINVAL; } - reg = RREG32(mmGRPH_INTERRUPT_CONTROL + reg_block); + reg = RREG32(mmGRPH_INTERRUPT_CONTROL + crtc_offsets[type]); if (state == AMDGPU_IRQ_STATE_DISABLE) - WREG32(mmGRPH_INTERRUPT_CONTROL + reg_block, reg & ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK); + WREG32(mmGRPH_INTERRUPT_CONTROL + crtc_offsets[type], + reg & ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK); else - WREG32(mmGRPH_INTERRUPT_CONTROL + reg_block, reg | GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK); + WREG32(mmGRPH_INTERRUPT_CONTROL + crtc_offsets[type], + reg | GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK); return 0; } @@ -3282,7 +3303,6 @@ static int dce_v11_0_pageflip_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) { - int reg_block; unsigned long flags; unsigned crtc_id; struct amdgpu_crtc *amdgpu_crtc; @@ -3291,33 +3311,15 @@ static int dce_v11_0_pageflip_irq(struct amdgpu_device *adev, crtc_id = (entry->src_id - 8) >> 1; amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; - /* ack the interrupt */ - switch(crtc_id){ - case AMDGPU_PAGEFLIP_IRQ_D1: - reg_block = CRTC0_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D2: - reg_block = CRTC1_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D3: - reg_block = CRTC2_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D4: - reg_block = CRTC3_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D5: - reg_block = CRTC4_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D6: - reg_block = CRTC5_REGISTER_OFFSET; - break; - default: - DRM_ERROR("invalid pageflip crtc %d\n", crtc_id); - return -EINVAL; + if (crtc_id >= adev->mode_info.num_crtc) { + DRM_ERROR("invalid pageflip crtc %d\n", crtc_id); + return -EINVAL; } - if (RREG32(mmGRPH_INTERRUPT_STATUS + reg_block) & GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_OCCURRED_MASK) - WREG32(mmGRPH_INTERRUPT_STATUS + reg_block, GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK); + if (RREG32(mmGRPH_INTERRUPT_STATUS + crtc_offsets[crtc_id]) & + GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_OCCURRED_MASK) + WREG32(mmGRPH_INTERRUPT_STATUS + crtc_offsets[crtc_id], + GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK); /* IRQ could occur when in initial stage */ if(amdgpu_crtc == NULL) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index c86911c2ea2a..d784fb43efc2 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -2411,26 +2411,19 @@ static void dce_v8_0_show_cursor(struct drm_crtc *crtc) struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct amdgpu_device *adev = crtc->dev->dev_private; + WREG32(mmCUR_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, + upper_32_bits(amdgpu_crtc->cursor_addr)); + WREG32(mmCUR_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset, + lower_32_bits(amdgpu_crtc->cursor_addr)); + WREG32_IDX(mmCUR_CONTROL + amdgpu_crtc->crtc_offset, CUR_CONTROL__CURSOR_EN_MASK | (CURSOR_24_8_PRE_MULT << CUR_CONTROL__CURSOR_MODE__SHIFT) | (CURSOR_URGENT_1_2 << CUR_CONTROL__CURSOR_URGENT_CONTROL__SHIFT)); } -static void dce_v8_0_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, - uint64_t gpu_addr) -{ - struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; - - WREG32(mmCUR_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, - upper_32_bits(gpu_addr)); - WREG32(mmCUR_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset, - gpu_addr & 0xffffffff); -} - -static int dce_v8_0_crtc_cursor_move(struct drm_crtc *crtc, - int x, int y) +static int dce_v8_0_cursor_move_locked(struct drm_crtc *crtc, + int x, int y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct amdgpu_device *adev = crtc->dev->dev_private; @@ -2450,26 +2443,40 @@ static int dce_v8_0_crtc_cursor_move(struct drm_crtc *crtc, y = 0; } - dce_v8_0_lock_cursor(crtc, true); WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y); WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin); WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1)); - dce_v8_0_lock_cursor(crtc, false); + + amdgpu_crtc->cursor_x = x; + amdgpu_crtc->cursor_y = y; return 0; } -static int dce_v8_0_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, - uint32_t handle, - uint32_t width, - uint32_t height) +static int dce_v8_0_crtc_cursor_move(struct drm_crtc *crtc, + int x, int y) +{ + int ret; + + dce_v8_0_lock_cursor(crtc, true); + ret = dce_v8_0_cursor_move_locked(crtc, x, y); + dce_v8_0_lock_cursor(crtc, false); + + return ret; +} + +static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height, + int32_t hot_x, + int32_t hot_y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_gem_object *obj; - struct amdgpu_bo *robj; - uint64_t gpu_addr; + struct amdgpu_bo *aobj; int ret; if (!handle) { @@ -2491,41 +2498,71 @@ static int dce_v8_0_crtc_cursor_set(struct drm_crtc *crtc, return -ENOENT; } - robj = gem_to_amdgpu_bo(obj); - ret = amdgpu_bo_reserve(robj, false); - if (unlikely(ret != 0)) - goto fail; - ret = amdgpu_bo_pin_restricted(robj, AMDGPU_GEM_DOMAIN_VRAM, - 0, 0, &gpu_addr); - amdgpu_bo_unreserve(robj); - if (ret) - goto fail; + aobj = gem_to_amdgpu_bo(obj); + ret = amdgpu_bo_reserve(aobj, false); + if (ret != 0) { + drm_gem_object_unreference_unlocked(obj); + return ret; + } + + ret = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM, &amdgpu_crtc->cursor_addr); + amdgpu_bo_unreserve(aobj); + if (ret) { + DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret); + drm_gem_object_unreference_unlocked(obj); + return ret; + } amdgpu_crtc->cursor_width = width; amdgpu_crtc->cursor_height = height; dce_v8_0_lock_cursor(crtc, true); - dce_v8_0_set_cursor(crtc, obj, gpu_addr); + + if (hot_x != amdgpu_crtc->cursor_hot_x || + hot_y != amdgpu_crtc->cursor_hot_y) { + int x, y; + + x = amdgpu_crtc->cursor_x + amdgpu_crtc->cursor_hot_x - hot_x; + y = amdgpu_crtc->cursor_y + amdgpu_crtc->cursor_hot_y - hot_y; + + dce_v8_0_cursor_move_locked(crtc, x, y); + + amdgpu_crtc->cursor_hot_x = hot_x; + amdgpu_crtc->cursor_hot_y = hot_y; + } + dce_v8_0_show_cursor(crtc); dce_v8_0_lock_cursor(crtc, false); unpin: if (amdgpu_crtc->cursor_bo) { - robj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); - ret = amdgpu_bo_reserve(robj, false); + struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); + ret = amdgpu_bo_reserve(aobj, false); if (likely(ret == 0)) { - amdgpu_bo_unpin(robj); - amdgpu_bo_unreserve(robj); + amdgpu_bo_unpin(aobj); + amdgpu_bo_unreserve(aobj); } drm_gem_object_unreference_unlocked(amdgpu_crtc->cursor_bo); } amdgpu_crtc->cursor_bo = obj; return 0; -fail: - drm_gem_object_unreference_unlocked(obj); +} - return ret; +static void dce_v8_0_cursor_reset(struct drm_crtc *crtc) +{ + struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); + + if (amdgpu_crtc->cursor_bo) { + dce_v8_0_lock_cursor(crtc, true); + + dce_v8_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x, + amdgpu_crtc->cursor_y); + + dce_v8_0_show_cursor(crtc); + + dce_v8_0_lock_cursor(crtc, false); + } } static void dce_v8_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, @@ -2553,7 +2590,7 @@ static void dce_v8_0_crtc_destroy(struct drm_crtc *crtc) } static const struct drm_crtc_funcs dce_v8_0_crtc_funcs = { - .cursor_set = dce_v8_0_crtc_cursor_set, + .cursor_set2 = dce_v8_0_crtc_cursor_set2, .cursor_move = dce_v8_0_crtc_cursor_move, .gamma_set = dce_v8_0_crtc_gamma_set, .set_config = amdgpu_crtc_set_config, @@ -2693,6 +2730,7 @@ static int dce_v8_0_crtc_mode_set(struct drm_crtc *crtc, dce_v8_0_crtc_do_set_base(crtc, old_fb, x, y, 0); amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode); amdgpu_atombios_crtc_scaler_setup(crtc); + dce_v8_0_cursor_reset(crtc); /* update the hw version fpr dpm */ amdgpu_crtc->hw_mode = *adjusted_mode; @@ -3274,37 +3312,20 @@ static int dce_v8_0_set_pageflip_interrupt_state(struct amdgpu_device *adev, unsigned type, enum amdgpu_interrupt_state state) { - u32 reg, reg_block; - /* now deal with page flip IRQ */ - switch (type) { - case AMDGPU_PAGEFLIP_IRQ_D1: - reg_block = CRTC0_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D2: - reg_block = CRTC1_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D3: - reg_block = CRTC2_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D4: - reg_block = CRTC3_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D5: - reg_block = CRTC4_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D6: - reg_block = CRTC5_REGISTER_OFFSET; - break; - default: - DRM_ERROR("invalid pageflip crtc %d\n", type); - return -EINVAL; + u32 reg; + + if (type >= adev->mode_info.num_crtc) { + DRM_ERROR("invalid pageflip crtc %d\n", type); + return -EINVAL; } - reg = RREG32(mmGRPH_INTERRUPT_CONTROL + reg_block); + reg = RREG32(mmGRPH_INTERRUPT_CONTROL + crtc_offsets[type]); if (state == AMDGPU_IRQ_STATE_DISABLE) - WREG32(mmGRPH_INTERRUPT_CONTROL + reg_block, reg & ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK); + WREG32(mmGRPH_INTERRUPT_CONTROL + crtc_offsets[type], + reg & ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK); else - WREG32(mmGRPH_INTERRUPT_CONTROL + reg_block, reg | GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK); + WREG32(mmGRPH_INTERRUPT_CONTROL + crtc_offsets[type], + reg | GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK); return 0; } @@ -3313,7 +3334,6 @@ static int dce_v8_0_pageflip_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) { - int reg_block; unsigned long flags; unsigned crtc_id; struct amdgpu_crtc *amdgpu_crtc; @@ -3322,33 +3342,15 @@ static int dce_v8_0_pageflip_irq(struct amdgpu_device *adev, crtc_id = (entry->src_id - 8) >> 1; amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; - /* ack the interrupt */ - switch(crtc_id){ - case AMDGPU_PAGEFLIP_IRQ_D1: - reg_block = CRTC0_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D2: - reg_block = CRTC1_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D3: - reg_block = CRTC2_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D4: - reg_block = CRTC3_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D5: - reg_block = CRTC4_REGISTER_OFFSET; - break; - case AMDGPU_PAGEFLIP_IRQ_D6: - reg_block = CRTC5_REGISTER_OFFSET; - break; - default: - DRM_ERROR("invalid pageflip crtc %d\n", crtc_id); - return -EINVAL; + if (crtc_id >= adev->mode_info.num_crtc) { + DRM_ERROR("invalid pageflip crtc %d\n", crtc_id); + return -EINVAL; } - if (RREG32(mmGRPH_INTERRUPT_STATUS + reg_block) & GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_OCCURRED_MASK) - WREG32(mmGRPH_INTERRUPT_STATUS + reg_block, GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK); + if (RREG32(mmGRPH_INTERRUPT_STATUS + crtc_offsets[crtc_id]) & + GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_OCCURRED_MASK) + WREG32(mmGRPH_INTERRUPT_STATUS + crtc_offsets[crtc_id], + GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK); /* IRQ could occur when in initial stage */ if (amdgpu_crtc == NULL) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index cb4f68f53f24..718250ae9856 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -903,6 +903,191 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev) return 0; } +static void gfx_v8_0_gpu_early_init(struct amdgpu_device *adev) +{ + u32 gb_addr_config; + u32 mc_shared_chmap, mc_arb_ramcfg; + u32 dimm00_addr_map, dimm01_addr_map, dimm10_addr_map, dimm11_addr_map; + u32 tmp; + + switch (adev->asic_type) { + case CHIP_TOPAZ: + adev->gfx.config.max_shader_engines = 1; + adev->gfx.config.max_tile_pipes = 2; + adev->gfx.config.max_cu_per_sh = 6; + adev->gfx.config.max_sh_per_se = 1; + adev->gfx.config.max_backends_per_se = 2; + adev->gfx.config.max_texture_channel_caches = 2; + adev->gfx.config.max_gprs = 256; + adev->gfx.config.max_gs_threads = 32; + adev->gfx.config.max_hw_contexts = 8; + + adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; + adev->gfx.config.sc_prim_fifo_size_backend = 0x100; + adev->gfx.config.sc_hiz_tile_fifo_size = 0x30; + adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130; + gb_addr_config = TOPAZ_GB_ADDR_CONFIG_GOLDEN; + break; + case CHIP_FIJI: + adev->gfx.config.max_shader_engines = 4; + adev->gfx.config.max_tile_pipes = 16; + adev->gfx.config.max_cu_per_sh = 16; + adev->gfx.config.max_sh_per_se = 1; + adev->gfx.config.max_backends_per_se = 4; + adev->gfx.config.max_texture_channel_caches = 8; + adev->gfx.config.max_gprs = 256; + adev->gfx.config.max_gs_threads = 32; + adev->gfx.config.max_hw_contexts = 8; + + adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; + adev->gfx.config.sc_prim_fifo_size_backend = 0x100; + adev->gfx.config.sc_hiz_tile_fifo_size = 0x30; + adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130; + gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN; + break; + case CHIP_TONGA: + adev->gfx.config.max_shader_engines = 4; + adev->gfx.config.max_tile_pipes = 8; + adev->gfx.config.max_cu_per_sh = 8; + adev->gfx.config.max_sh_per_se = 1; + adev->gfx.config.max_backends_per_se = 2; + adev->gfx.config.max_texture_channel_caches = 8; + adev->gfx.config.max_gprs = 256; + adev->gfx.config.max_gs_threads = 32; + adev->gfx.config.max_hw_contexts = 8; + + adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; + adev->gfx.config.sc_prim_fifo_size_backend = 0x100; + adev->gfx.config.sc_hiz_tile_fifo_size = 0x30; + adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130; + gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN; + break; + case CHIP_CARRIZO: + adev->gfx.config.max_shader_engines = 1; + adev->gfx.config.max_tile_pipes = 2; + adev->gfx.config.max_sh_per_se = 1; + adev->gfx.config.max_backends_per_se = 2; + + switch (adev->pdev->revision) { + case 0xc4: + case 0x84: + case 0xc8: + case 0xcc: + /* B10 */ + adev->gfx.config.max_cu_per_sh = 8; + break; + case 0xc5: + case 0x81: + case 0x85: + case 0xc9: + case 0xcd: + /* B8 */ + adev->gfx.config.max_cu_per_sh = 6; + break; + case 0xc6: + case 0xca: + case 0xce: + /* B6 */ + adev->gfx.config.max_cu_per_sh = 6; + break; + case 0xc7: + case 0x87: + case 0xcb: + default: + /* B4 */ + adev->gfx.config.max_cu_per_sh = 4; + break; + } + + adev->gfx.config.max_texture_channel_caches = 2; + adev->gfx.config.max_gprs = 256; + adev->gfx.config.max_gs_threads = 32; + adev->gfx.config.max_hw_contexts = 8; + + adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; + adev->gfx.config.sc_prim_fifo_size_backend = 0x100; + adev->gfx.config.sc_hiz_tile_fifo_size = 0x30; + adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130; + gb_addr_config = CARRIZO_GB_ADDR_CONFIG_GOLDEN; + break; + default: + adev->gfx.config.max_shader_engines = 2; + adev->gfx.config.max_tile_pipes = 4; + adev->gfx.config.max_cu_per_sh = 2; + adev->gfx.config.max_sh_per_se = 1; + adev->gfx.config.max_backends_per_se = 2; + adev->gfx.config.max_texture_channel_caches = 4; + adev->gfx.config.max_gprs = 256; + adev->gfx.config.max_gs_threads = 32; + adev->gfx.config.max_hw_contexts = 8; + + adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; + adev->gfx.config.sc_prim_fifo_size_backend = 0x100; + adev->gfx.config.sc_hiz_tile_fifo_size = 0x30; + adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130; + gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN; + break; + } + + mc_shared_chmap = RREG32(mmMC_SHARED_CHMAP); + adev->gfx.config.mc_arb_ramcfg = RREG32(mmMC_ARB_RAMCFG); + mc_arb_ramcfg = adev->gfx.config.mc_arb_ramcfg; + + adev->gfx.config.num_tile_pipes = adev->gfx.config.max_tile_pipes; + adev->gfx.config.mem_max_burst_length_bytes = 256; + if (adev->flags & AMD_IS_APU) { + /* Get memory bank mapping mode. */ + tmp = RREG32(mmMC_FUS_DRAM0_BANK_ADDR_MAPPING); + dimm00_addr_map = REG_GET_FIELD(tmp, MC_FUS_DRAM0_BANK_ADDR_MAPPING, DIMM0ADDRMAP); + dimm01_addr_map = REG_GET_FIELD(tmp, MC_FUS_DRAM0_BANK_ADDR_MAPPING, DIMM1ADDRMAP); + + tmp = RREG32(mmMC_FUS_DRAM1_BANK_ADDR_MAPPING); + dimm10_addr_map = REG_GET_FIELD(tmp, MC_FUS_DRAM1_BANK_ADDR_MAPPING, DIMM0ADDRMAP); + dimm11_addr_map = REG_GET_FIELD(tmp, MC_FUS_DRAM1_BANK_ADDR_MAPPING, DIMM1ADDRMAP); + + /* Validate settings in case only one DIMM installed. */ + if ((dimm00_addr_map == 0) || (dimm00_addr_map == 3) || (dimm00_addr_map == 4) || (dimm00_addr_map > 12)) + dimm00_addr_map = 0; + if ((dimm01_addr_map == 0) || (dimm01_addr_map == 3) || (dimm01_addr_map == 4) || (dimm01_addr_map > 12)) + dimm01_addr_map = 0; + if ((dimm10_addr_map == 0) || (dimm10_addr_map == 3) || (dimm10_addr_map == 4) || (dimm10_addr_map > 12)) + dimm10_addr_map = 0; + if ((dimm11_addr_map == 0) || (dimm11_addr_map == 3) || (dimm11_addr_map == 4) || (dimm11_addr_map > 12)) + dimm11_addr_map = 0; + + /* If DIMM Addr map is 8GB, ROW size should be 2KB. Otherwise 1KB. */ + /* If ROW size(DIMM1) != ROW size(DMIMM0), ROW size should be larger one. */ + if ((dimm00_addr_map == 11) || (dimm01_addr_map == 11) || (dimm10_addr_map == 11) || (dimm11_addr_map == 11)) + adev->gfx.config.mem_row_size_in_kb = 2; + else + adev->gfx.config.mem_row_size_in_kb = 1; + } else { + tmp = REG_GET_FIELD(mc_arb_ramcfg, MC_ARB_RAMCFG, NOOFCOLS); + adev->gfx.config.mem_row_size_in_kb = (4 * (1 << (8 + tmp))) / 1024; + if (adev->gfx.config.mem_row_size_in_kb > 4) + adev->gfx.config.mem_row_size_in_kb = 4; + } + + adev->gfx.config.shader_engine_tile_size = 32; + adev->gfx.config.num_gpus = 1; + adev->gfx.config.multi_gpu_tile_size = 64; + + /* fix up row size */ + switch (adev->gfx.config.mem_row_size_in_kb) { + case 1: + default: + gb_addr_config = REG_SET_FIELD(gb_addr_config, GB_ADDR_CONFIG, ROW_SIZE, 0); + break; + case 2: + gb_addr_config = REG_SET_FIELD(gb_addr_config, GB_ADDR_CONFIG, ROW_SIZE, 1); + break; + case 4: + gb_addr_config = REG_SET_FIELD(gb_addr_config, GB_ADDR_CONFIG, ROW_SIZE, 2); + break; + } + adev->gfx.config.gb_addr_config = gb_addr_config; +} + static int gfx_v8_0_sw_init(void *handle) { int i, r; @@ -1010,6 +1195,8 @@ static int gfx_v8_0_sw_init(void *handle) adev->gfx.ce_ram_size = 0x8000; + gfx_v8_0_gpu_early_init(adev); + return 0; } @@ -2043,203 +2230,23 @@ static void gfx_v8_0_init_compute_vmid(struct amdgpu_device *adev) static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) { - u32 gb_addr_config; - u32 mc_shared_chmap, mc_arb_ramcfg; - u32 dimm00_addr_map, dimm01_addr_map, dimm10_addr_map, dimm11_addr_map; u32 tmp; int i; - switch (adev->asic_type) { - case CHIP_TOPAZ: - adev->gfx.config.max_shader_engines = 1; - adev->gfx.config.max_tile_pipes = 2; - adev->gfx.config.max_cu_per_sh = 6; - adev->gfx.config.max_sh_per_se = 1; - adev->gfx.config.max_backends_per_se = 2; - adev->gfx.config.max_texture_channel_caches = 2; - adev->gfx.config.max_gprs = 256; - adev->gfx.config.max_gs_threads = 32; - adev->gfx.config.max_hw_contexts = 8; - - adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; - adev->gfx.config.sc_prim_fifo_size_backend = 0x100; - adev->gfx.config.sc_hiz_tile_fifo_size = 0x30; - adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = TOPAZ_GB_ADDR_CONFIG_GOLDEN; - break; - case CHIP_FIJI: - adev->gfx.config.max_shader_engines = 4; - adev->gfx.config.max_tile_pipes = 16; - adev->gfx.config.max_cu_per_sh = 16; - adev->gfx.config.max_sh_per_se = 1; - adev->gfx.config.max_backends_per_se = 4; - adev->gfx.config.max_texture_channel_caches = 8; - adev->gfx.config.max_gprs = 256; - adev->gfx.config.max_gs_threads = 32; - adev->gfx.config.max_hw_contexts = 8; - - adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; - adev->gfx.config.sc_prim_fifo_size_backend = 0x100; - adev->gfx.config.sc_hiz_tile_fifo_size = 0x30; - adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN; - break; - case CHIP_TONGA: - adev->gfx.config.max_shader_engines = 4; - adev->gfx.config.max_tile_pipes = 8; - adev->gfx.config.max_cu_per_sh = 8; - adev->gfx.config.max_sh_per_se = 1; - adev->gfx.config.max_backends_per_se = 2; - adev->gfx.config.max_texture_channel_caches = 8; - adev->gfx.config.max_gprs = 256; - adev->gfx.config.max_gs_threads = 32; - adev->gfx.config.max_hw_contexts = 8; - - adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; - adev->gfx.config.sc_prim_fifo_size_backend = 0x100; - adev->gfx.config.sc_hiz_tile_fifo_size = 0x30; - adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN; - break; - case CHIP_CARRIZO: - adev->gfx.config.max_shader_engines = 1; - adev->gfx.config.max_tile_pipes = 2; - adev->gfx.config.max_sh_per_se = 1; - adev->gfx.config.max_backends_per_se = 2; - - switch (adev->pdev->revision) { - case 0xc4: - case 0x84: - case 0xc8: - case 0xcc: - /* B10 */ - adev->gfx.config.max_cu_per_sh = 8; - break; - case 0xc5: - case 0x81: - case 0x85: - case 0xc9: - case 0xcd: - /* B8 */ - adev->gfx.config.max_cu_per_sh = 6; - break; - case 0xc6: - case 0xca: - case 0xce: - /* B6 */ - adev->gfx.config.max_cu_per_sh = 6; - break; - case 0xc7: - case 0x87: - case 0xcb: - default: - /* B4 */ - adev->gfx.config.max_cu_per_sh = 4; - break; - } - - adev->gfx.config.max_texture_channel_caches = 2; - adev->gfx.config.max_gprs = 256; - adev->gfx.config.max_gs_threads = 32; - adev->gfx.config.max_hw_contexts = 8; - - adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; - adev->gfx.config.sc_prim_fifo_size_backend = 0x100; - adev->gfx.config.sc_hiz_tile_fifo_size = 0x30; - adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = CARRIZO_GB_ADDR_CONFIG_GOLDEN; - break; - default: - adev->gfx.config.max_shader_engines = 2; - adev->gfx.config.max_tile_pipes = 4; - adev->gfx.config.max_cu_per_sh = 2; - adev->gfx.config.max_sh_per_se = 1; - adev->gfx.config.max_backends_per_se = 2; - adev->gfx.config.max_texture_channel_caches = 4; - adev->gfx.config.max_gprs = 256; - adev->gfx.config.max_gs_threads = 32; - adev->gfx.config.max_hw_contexts = 8; - - adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; - adev->gfx.config.sc_prim_fifo_size_backend = 0x100; - adev->gfx.config.sc_hiz_tile_fifo_size = 0x30; - adev->gfx.config.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN; - break; - } - tmp = RREG32(mmGRBM_CNTL); tmp = REG_SET_FIELD(tmp, GRBM_CNTL, READ_TIMEOUT, 0xff); WREG32(mmGRBM_CNTL, tmp); - mc_shared_chmap = RREG32(mmMC_SHARED_CHMAP); - adev->gfx.config.mc_arb_ramcfg = RREG32(mmMC_ARB_RAMCFG); - mc_arb_ramcfg = adev->gfx.config.mc_arb_ramcfg; - - adev->gfx.config.num_tile_pipes = adev->gfx.config.max_tile_pipes; - adev->gfx.config.mem_max_burst_length_bytes = 256; - if (adev->flags & AMD_IS_APU) { - /* Get memory bank mapping mode. */ - tmp = RREG32(mmMC_FUS_DRAM0_BANK_ADDR_MAPPING); - dimm00_addr_map = REG_GET_FIELD(tmp, MC_FUS_DRAM0_BANK_ADDR_MAPPING, DIMM0ADDRMAP); - dimm01_addr_map = REG_GET_FIELD(tmp, MC_FUS_DRAM0_BANK_ADDR_MAPPING, DIMM1ADDRMAP); - - tmp = RREG32(mmMC_FUS_DRAM1_BANK_ADDR_MAPPING); - dimm10_addr_map = REG_GET_FIELD(tmp, MC_FUS_DRAM1_BANK_ADDR_MAPPING, DIMM0ADDRMAP); - dimm11_addr_map = REG_GET_FIELD(tmp, MC_FUS_DRAM1_BANK_ADDR_MAPPING, DIMM1ADDRMAP); - - /* Validate settings in case only one DIMM installed. */ - if ((dimm00_addr_map == 0) || (dimm00_addr_map == 3) || (dimm00_addr_map == 4) || (dimm00_addr_map > 12)) - dimm00_addr_map = 0; - if ((dimm01_addr_map == 0) || (dimm01_addr_map == 3) || (dimm01_addr_map == 4) || (dimm01_addr_map > 12)) - dimm01_addr_map = 0; - if ((dimm10_addr_map == 0) || (dimm10_addr_map == 3) || (dimm10_addr_map == 4) || (dimm10_addr_map > 12)) - dimm10_addr_map = 0; - if ((dimm11_addr_map == 0) || (dimm11_addr_map == 3) || (dimm11_addr_map == 4) || (dimm11_addr_map > 12)) - dimm11_addr_map = 0; - - /* If DIMM Addr map is 8GB, ROW size should be 2KB. Otherwise 1KB. */ - /* If ROW size(DIMM1) != ROW size(DMIMM0), ROW size should be larger one. */ - if ((dimm00_addr_map == 11) || (dimm01_addr_map == 11) || (dimm10_addr_map == 11) || (dimm11_addr_map == 11)) - adev->gfx.config.mem_row_size_in_kb = 2; - else - adev->gfx.config.mem_row_size_in_kb = 1; - } else { - tmp = REG_GET_FIELD(mc_arb_ramcfg, MC_ARB_RAMCFG, NOOFCOLS); - adev->gfx.config.mem_row_size_in_kb = (4 * (1 << (8 + tmp))) / 1024; - if (adev->gfx.config.mem_row_size_in_kb > 4) - adev->gfx.config.mem_row_size_in_kb = 4; - } - - adev->gfx.config.shader_engine_tile_size = 32; - adev->gfx.config.num_gpus = 1; - adev->gfx.config.multi_gpu_tile_size = 64; - - /* fix up row size */ - switch (adev->gfx.config.mem_row_size_in_kb) { - case 1: - default: - gb_addr_config = REG_SET_FIELD(gb_addr_config, GB_ADDR_CONFIG, ROW_SIZE, 0); - break; - case 2: - gb_addr_config = REG_SET_FIELD(gb_addr_config, GB_ADDR_CONFIG, ROW_SIZE, 1); - break; - case 4: - gb_addr_config = REG_SET_FIELD(gb_addr_config, GB_ADDR_CONFIG, ROW_SIZE, 2); - break; - } - adev->gfx.config.gb_addr_config = gb_addr_config; - - WREG32(mmGB_ADDR_CONFIG, gb_addr_config); - WREG32(mmHDP_ADDR_CONFIG, gb_addr_config); - WREG32(mmDMIF_ADDR_CALC, gb_addr_config); + WREG32(mmGB_ADDR_CONFIG, adev->gfx.config.gb_addr_config); + WREG32(mmHDP_ADDR_CONFIG, adev->gfx.config.gb_addr_config); + WREG32(mmDMIF_ADDR_CALC, adev->gfx.config.gb_addr_config); WREG32(mmSDMA0_TILING_CONFIG + SDMA0_REGISTER_OFFSET, - gb_addr_config & 0x70); + adev->gfx.config.gb_addr_config & 0x70); WREG32(mmSDMA0_TILING_CONFIG + SDMA1_REGISTER_OFFSET, - gb_addr_config & 0x70); - WREG32(mmUVD_UDEC_ADDR_CONFIG, gb_addr_config); - WREG32(mmUVD_UDEC_DB_ADDR_CONFIG, gb_addr_config); - WREG32(mmUVD_UDEC_DBW_ADDR_CONFIG, gb_addr_config); + adev->gfx.config.gb_addr_config & 0x70); + WREG32(mmUVD_UDEC_ADDR_CONFIG, adev->gfx.config.gb_addr_config); + WREG32(mmUVD_UDEC_DB_ADDR_CONFIG, adev->gfx.config.gb_addr_config); + WREG32(mmUVD_UDEC_DBW_ADDR_CONFIG, adev->gfx.config.gb_addr_config); gfx_v8_0_tiling_mode_table_init(adev); @@ -2256,13 +2263,13 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) if (i == 0) { tmp = REG_SET_FIELD(0, SH_MEM_CONFIG, DEFAULT_MTYPE, MTYPE_UC); tmp = REG_SET_FIELD(tmp, SH_MEM_CONFIG, APE1_MTYPE, MTYPE_UC); - tmp = REG_SET_FIELD(tmp, SH_MEM_CONFIG, ALIGNMENT_MODE, + tmp = REG_SET_FIELD(tmp, SH_MEM_CONFIG, ALIGNMENT_MODE, SH_MEM_ALIGNMENT_MODE_UNALIGNED); WREG32(mmSH_MEM_CONFIG, tmp); } else { tmp = REG_SET_FIELD(0, SH_MEM_CONFIG, DEFAULT_MTYPE, MTYPE_NC); tmp = REG_SET_FIELD(tmp, SH_MEM_CONFIG, APE1_MTYPE, MTYPE_NC); - tmp = REG_SET_FIELD(tmp, SH_MEM_CONFIG, ALIGNMENT_MODE, + tmp = REG_SET_FIELD(tmp, SH_MEM_CONFIG, ALIGNMENT_MODE, SH_MEM_ALIGNMENT_MODE_UNALIGNED); WREG32(mmSH_MEM_CONFIG, tmp); } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 774528ab8704..488348272c4d 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -436,6 +436,33 @@ static int gmc_v7_0_gart_set_pte_pde(struct amdgpu_device *adev, } /** + * gmc_v8_0_set_fault_enable_default - update VM fault handling + * + * @adev: amdgpu_device pointer + * @value: true redirects VM faults to the default page + */ +static void gmc_v7_0_set_fault_enable_default(struct amdgpu_device *adev, + bool value) +{ + u32 tmp; + + tmp = RREG32(mmVM_CONTEXT1_CNTL); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + RANGE_PROTECTION_FAULT_ENABLE_DEFAULT, value); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT, value); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + PDE0_PROTECTION_FAULT_ENABLE_DEFAULT, value); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + VALID_PROTECTION_FAULT_ENABLE_DEFAULT, value); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + READ_PROTECTION_FAULT_ENABLE_DEFAULT, value); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value); + WREG32(mmVM_CONTEXT1_CNTL, tmp); +} + +/** * gmc_v7_0_gart_enable - gart enable * * @adev: amdgpu_device pointer @@ -523,15 +550,13 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev) tmp = RREG32(mmVM_CONTEXT1_CNTL); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, ENABLE_CONTEXT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PAGE_TABLE_DEPTH, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, RANGE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PDE0_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, VALID_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, READ_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PAGE_TABLE_BLOCK_SIZE, amdgpu_vm_block_size - 9); WREG32(mmVM_CONTEXT1_CNTL, tmp); + if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_ALWAYS) + gmc_v7_0_set_fault_enable_default(adev, false); + else + gmc_v7_0_set_fault_enable_default(adev, true); if (adev->asic_type == CHIP_KAVERI) { tmp = RREG32(mmCHUB_CONTROL); @@ -1262,6 +1287,15 @@ static int gmc_v7_0_process_interrupt(struct amdgpu_device *adev, addr = RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_ADDR); status = RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_STATUS); mc_client = RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_MCCLIENT); + /* reset addr and status */ + WREG32_P(mmVM_CONTEXT1_CNTL2, 1, ~1); + + if (!addr && !status) + return 0; + + if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_FIRST) + gmc_v7_0_set_fault_enable_default(adev, false); + dev_err(adev->dev, "GPU fault detected: %d 0x%08x\n", entry->src_id, entry->src_data); dev_err(adev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", @@ -1269,8 +1303,6 @@ static int gmc_v7_0_process_interrupt(struct amdgpu_device *adev, dev_err(adev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", status); gmc_v7_0_vm_decode_fault(adev, status, addr, mc_client); - /* reset addr and status */ - WREG32_P(mmVM_CONTEXT1_CNTL2, 1, ~1); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 9a07742620d0..42b5ff827055 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -550,6 +550,35 @@ static int gmc_v8_0_gart_set_pte_pde(struct amdgpu_device *adev, } /** + * gmc_v8_0_set_fault_enable_default - update VM fault handling + * + * @adev: amdgpu_device pointer + * @value: true redirects VM faults to the default page + */ +static void gmc_v8_0_set_fault_enable_default(struct amdgpu_device *adev, + bool value) +{ + u32 tmp; + + tmp = RREG32(mmVM_CONTEXT1_CNTL); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + RANGE_PROTECTION_FAULT_ENABLE_DEFAULT, value); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT, value); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + PDE0_PROTECTION_FAULT_ENABLE_DEFAULT, value); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + VALID_PROTECTION_FAULT_ENABLE_DEFAULT, value); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + READ_PROTECTION_FAULT_ENABLE_DEFAULT, value); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, value); + tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, + EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, value); + WREG32(mmVM_CONTEXT1_CNTL, tmp); +} + +/** * gmc_v8_0_gart_enable - gart enable * * @adev: amdgpu_device pointer @@ -663,6 +692,10 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev) tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PAGE_TABLE_BLOCK_SIZE, amdgpu_vm_block_size - 9); WREG32(mmVM_CONTEXT1_CNTL, tmp); + if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_ALWAYS) + gmc_v8_0_set_fault_enable_default(adev, false); + else + gmc_v8_0_set_fault_enable_default(adev, true); gmc_v8_0_gart_flush_gpu_tlb(adev, 0); DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", @@ -1262,6 +1295,15 @@ static int gmc_v8_0_process_interrupt(struct amdgpu_device *adev, addr = RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_ADDR); status = RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_STATUS); mc_client = RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_MCCLIENT); + /* reset addr and status */ + WREG32_P(mmVM_CONTEXT1_CNTL2, 1, ~1); + + if (!addr && !status) + return 0; + + if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_FIRST) + gmc_v8_0_set_fault_enable_default(adev, false); + dev_err(adev->dev, "GPU fault detected: %d 0x%08x\n", entry->src_id, entry->src_data); dev_err(adev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", @@ -1269,8 +1311,6 @@ static int gmc_v8_0_process_interrupt(struct amdgpu_device *adev, dev_err(adev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", status); gmc_v8_0_vm_decode_fault(adev, status, addr, mc_client); - /* reset addr and status */ - WREG32_P(mmVM_CONTEXT1_CNTL2, 1, ~1); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c index 94ec04a9c4d5..9745ed3a9aef 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c @@ -2995,6 +2995,12 @@ static int kv_dpm_late_init(void *handle) { /* powerdown unused blocks for now */ struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int ret; + + /* init the sysfs and debugfs files late */ + ret = amdgpu_pm_sysfs_init(adev); + if (ret) + return ret; kv_dpm_powergate_acp(adev, true); kv_dpm_powergate_samu(adev, true); @@ -3038,9 +3044,6 @@ static int kv_dpm_sw_init(void *handle) adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps; if (amdgpu_dpm == 1) amdgpu_pm_print_power_states(adev); - ret = amdgpu_pm_sysfs_init(adev); - if (ret) - goto dpm_failed; mutex_unlock(&adev->pm.mutex); DRM_INFO("amdgpu: dpm initialized\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index 14e87234171a..f8b868c7c496 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -118,7 +118,7 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev) { const char *chip_name; char fw_name[30]; - int err, i; + int err = 0, i; struct amdgpu_firmware_info *info = NULL; const struct common_firmware_header *header = NULL; const struct sdma_firmware_header_v1_0 *hdr; @@ -132,27 +132,27 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev) default: BUG(); } - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { if (i == 0) snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name); else snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name); - err = request_firmware(&adev->sdma[i].fw, fw_name, adev->dev); + err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev); if (err) goto out; - err = amdgpu_ucode_validate(adev->sdma[i].fw); + err = amdgpu_ucode_validate(adev->sdma.instance[i].fw); if (err) goto out; - hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data; - adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); - adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); - if (adev->sdma[i].feature_version >= 20) - adev->sdma[i].burst_nop = true; + hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma.instance[i].fw->data; + adev->sdma.instance[i].fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->sdma.instance[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); + if (adev->sdma.instance[i].feature_version >= 20) + adev->sdma.instance[i].burst_nop = true; if (adev->firmware.smu_load) { info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i]; info->ucode_id = AMDGPU_UCODE_ID_SDMA0 + i; - info->fw = adev->sdma[i].fw; + info->fw = adev->sdma.instance[i].fw; header = (const struct common_firmware_header *)info->fw->data; adev->firmware.fw_size += ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); @@ -164,9 +164,9 @@ out: printk(KERN_ERR "sdma_v2_4: Failed to load firmware \"%s\"\n", fw_name); - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { - release_firmware(adev->sdma[i].fw); - adev->sdma[i].fw = NULL; + for (i = 0; i < adev->sdma.num_instances; i++) { + release_firmware(adev->sdma.instance[i].fw); + adev->sdma.instance[i].fw = NULL; } } return err; @@ -199,7 +199,7 @@ static uint32_t sdma_v2_4_ring_get_rptr(struct amdgpu_ring *ring) static uint32_t sdma_v2_4_ring_get_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - int me = (ring == &ring->adev->sdma[0].ring) ? 0 : 1; + int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; u32 wptr = RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me]) >> 2; return wptr; @@ -215,14 +215,14 @@ static uint32_t sdma_v2_4_ring_get_wptr(struct amdgpu_ring *ring) static void sdma_v2_4_ring_set_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - int me = (ring == &ring->adev->sdma[0].ring) ? 0 : 1; + int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], ring->wptr << 2); } static void sdma_v2_4_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) { - struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ring); + struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring); int i; for (i = 0; i < count; i++) @@ -284,7 +284,7 @@ static void sdma_v2_4_ring_emit_hdp_flush(struct amdgpu_ring *ring) { u32 ref_and_mask = 0; - if (ring == &ring->adev->sdma[0].ring) + if (ring == &ring->adev->sdma.instance[0].ring) ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA0, 1); else ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA1, 1); @@ -368,8 +368,8 @@ static bool sdma_v2_4_ring_emit_semaphore(struct amdgpu_ring *ring, */ static void sdma_v2_4_gfx_stop(struct amdgpu_device *adev) { - struct amdgpu_ring *sdma0 = &adev->sdma[0].ring; - struct amdgpu_ring *sdma1 = &adev->sdma[1].ring; + struct amdgpu_ring *sdma0 = &adev->sdma.instance[0].ring; + struct amdgpu_ring *sdma1 = &adev->sdma.instance[1].ring; u32 rb_cntl, ib_cntl; int i; @@ -377,7 +377,7 @@ static void sdma_v2_4_gfx_stop(struct amdgpu_device *adev) (adev->mman.buffer_funcs_ring == sdma1)) amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size); - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { rb_cntl = RREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i]); rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 0); WREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i], rb_cntl); @@ -419,7 +419,7 @@ static void sdma_v2_4_enable(struct amdgpu_device *adev, bool enable) sdma_v2_4_rlc_stop(adev); } - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { f32_cntl = RREG32(mmSDMA0_F32_CNTL + sdma_offsets[i]); if (enable) f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_F32_CNTL, HALT, 0); @@ -445,8 +445,8 @@ static int sdma_v2_4_gfx_resume(struct amdgpu_device *adev) u32 wb_offset; int i, j, r; - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { - ring = &adev->sdma[i].ring; + for (i = 0; i < adev->sdma.num_instances; i++) { + ring = &adev->sdma.instance[i].ring; wb_offset = (ring->rptr_offs * 4); mutex_lock(&adev->srbm_mutex); @@ -545,29 +545,23 @@ static int sdma_v2_4_load_microcode(struct amdgpu_device *adev) const __le32 *fw_data; u32 fw_size; int i, j; - bool smc_loads_fw = false; /* XXX fix me */ - - if (!adev->sdma[0].fw || !adev->sdma[1].fw) - return -EINVAL; /* halt the MEs */ sdma_v2_4_enable(adev, false); - if (smc_loads_fw) { - /* XXX query SMC for fw load complete */ - } else { - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { - hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data; - amdgpu_ucode_print_sdma_hdr(&hdr->header); - fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; - fw_data = (const __le32 *) - (adev->sdma[i].fw->data + - le32_to_cpu(hdr->header.ucode_array_offset_bytes)); - WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], 0); - for (j = 0; j < fw_size; j++) - WREG32(mmSDMA0_UCODE_DATA + sdma_offsets[i], le32_to_cpup(fw_data++)); - WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], adev->sdma[i].fw_version); - } + for (i = 0; i < adev->sdma.num_instances; i++) { + if (!adev->sdma.instance[i].fw) + return -EINVAL; + hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma.instance[i].fw->data; + amdgpu_ucode_print_sdma_hdr(&hdr->header); + fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; + fw_data = (const __le32 *) + (adev->sdma.instance[i].fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], 0); + for (j = 0; j < fw_size; j++) + WREG32(mmSDMA0_UCODE_DATA + sdma_offsets[i], le32_to_cpup(fw_data++)); + WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], adev->sdma.instance[i].fw_version); } return 0; @@ -894,7 +888,7 @@ static void sdma_v2_4_vm_set_pte_pde(struct amdgpu_ib *ib, */ static void sdma_v2_4_vm_pad_ib(struct amdgpu_ib *ib) { - struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ib->ring); + struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ib->ring); u32 pad_count; int i; @@ -952,6 +946,8 @@ static int sdma_v2_4_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + adev->sdma.num_instances = SDMA_MAX_INSTANCE; + sdma_v2_4_set_ring_funcs(adev); sdma_v2_4_set_buffer_funcs(adev); sdma_v2_4_set_vm_pte_funcs(adev); @@ -963,21 +959,21 @@ static int sdma_v2_4_early_init(void *handle) static int sdma_v2_4_sw_init(void *handle) { struct amdgpu_ring *ring; - int r; + int r, i; struct amdgpu_device *adev = (struct amdgpu_device *)handle; /* SDMA trap event */ - r = amdgpu_irq_add_id(adev, 224, &adev->sdma_trap_irq); + r = amdgpu_irq_add_id(adev, 224, &adev->sdma.trap_irq); if (r) return r; /* SDMA Privileged inst */ - r = amdgpu_irq_add_id(adev, 241, &adev->sdma_illegal_inst_irq); + r = amdgpu_irq_add_id(adev, 241, &adev->sdma.illegal_inst_irq); if (r) return r; /* SDMA Privileged inst */ - r = amdgpu_irq_add_id(adev, 247, &adev->sdma_illegal_inst_irq); + r = amdgpu_irq_add_id(adev, 247, &adev->sdma.illegal_inst_irq); if (r) return r; @@ -987,31 +983,20 @@ static int sdma_v2_4_sw_init(void *handle) return r; } - ring = &adev->sdma[0].ring; - ring->ring_obj = NULL; - ring->use_doorbell = false; - - ring = &adev->sdma[1].ring; - ring->ring_obj = NULL; - ring->use_doorbell = false; - - ring = &adev->sdma[0].ring; - sprintf(ring->name, "sdma0"); - r = amdgpu_ring_init(adev, ring, 256 * 1024, - SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), 0xf, - &adev->sdma_trap_irq, AMDGPU_SDMA_IRQ_TRAP0, - AMDGPU_RING_TYPE_SDMA); - if (r) - return r; - - ring = &adev->sdma[1].ring; - sprintf(ring->name, "sdma1"); - r = amdgpu_ring_init(adev, ring, 256 * 1024, - SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), 0xf, - &adev->sdma_trap_irq, AMDGPU_SDMA_IRQ_TRAP1, - AMDGPU_RING_TYPE_SDMA); - if (r) - return r; + for (i = 0; i < adev->sdma.num_instances; i++) { + ring = &adev->sdma.instance[i].ring; + ring->ring_obj = NULL; + ring->use_doorbell = false; + sprintf(ring->name, "sdma%d", i); + r = amdgpu_ring_init(adev, ring, 256 * 1024, + SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), 0xf, + &adev->sdma.trap_irq, + (i == 0) ? + AMDGPU_SDMA_IRQ_TRAP0 : AMDGPU_SDMA_IRQ_TRAP1, + AMDGPU_RING_TYPE_SDMA); + if (r) + return r; + } return r; } @@ -1019,9 +1004,10 @@ static int sdma_v2_4_sw_init(void *handle) static int sdma_v2_4_sw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int i; - amdgpu_ring_fini(&adev->sdma[0].ring); - amdgpu_ring_fini(&adev->sdma[1].ring); + for (i = 0; i < adev->sdma.num_instances; i++) + amdgpu_ring_fini(&adev->sdma.instance[i].ring); return 0; } @@ -1100,7 +1086,7 @@ static void sdma_v2_4_print_status(void *handle) dev_info(adev->dev, "VI SDMA registers\n"); dev_info(adev->dev, " SRBM_STATUS2=0x%08X\n", RREG32(mmSRBM_STATUS2)); - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { dev_info(adev->dev, " SDMA%d_STATUS_REG=0x%08X\n", i, RREG32(mmSDMA0_STATUS_REG + sdma_offsets[i])); dev_info(adev->dev, " SDMA%d_F32_CNTL=0x%08X\n", @@ -1243,7 +1229,7 @@ static int sdma_v2_4_process_trap_irq(struct amdgpu_device *adev, case 0: switch (queue_id) { case 0: - amdgpu_fence_process(&adev->sdma[0].ring); + amdgpu_fence_process(&adev->sdma.instance[0].ring); break; case 1: /* XXX compute */ @@ -1256,7 +1242,7 @@ static int sdma_v2_4_process_trap_irq(struct amdgpu_device *adev, case 1: switch (queue_id) { case 0: - amdgpu_fence_process(&adev->sdma[1].ring); + amdgpu_fence_process(&adev->sdma.instance[1].ring); break; case 1: /* XXX compute */ @@ -1345,8 +1331,10 @@ static const struct amdgpu_ring_funcs sdma_v2_4_ring_funcs = { static void sdma_v2_4_set_ring_funcs(struct amdgpu_device *adev) { - adev->sdma[0].ring.funcs = &sdma_v2_4_ring_funcs; - adev->sdma[1].ring.funcs = &sdma_v2_4_ring_funcs; + int i; + + for (i = 0; i < adev->sdma.num_instances; i++) + adev->sdma.instance[i].ring.funcs = &sdma_v2_4_ring_funcs; } static const struct amdgpu_irq_src_funcs sdma_v2_4_trap_irq_funcs = { @@ -1360,9 +1348,9 @@ static const struct amdgpu_irq_src_funcs sdma_v2_4_illegal_inst_irq_funcs = { static void sdma_v2_4_set_irq_funcs(struct amdgpu_device *adev) { - adev->sdma_trap_irq.num_types = AMDGPU_SDMA_IRQ_LAST; - adev->sdma_trap_irq.funcs = &sdma_v2_4_trap_irq_funcs; - adev->sdma_illegal_inst_irq.funcs = &sdma_v2_4_illegal_inst_irq_funcs; + adev->sdma.trap_irq.num_types = AMDGPU_SDMA_IRQ_LAST; + adev->sdma.trap_irq.funcs = &sdma_v2_4_trap_irq_funcs; + adev->sdma.illegal_inst_irq.funcs = &sdma_v2_4_illegal_inst_irq_funcs; } /** @@ -1428,7 +1416,7 @@ static void sdma_v2_4_set_buffer_funcs(struct amdgpu_device *adev) { if (adev->mman.buffer_funcs == NULL) { adev->mman.buffer_funcs = &sdma_v2_4_buffer_funcs; - adev->mman.buffer_funcs_ring = &adev->sdma[0].ring; + adev->mman.buffer_funcs_ring = &adev->sdma.instance[0].ring; } } @@ -1443,7 +1431,7 @@ static void sdma_v2_4_set_vm_pte_funcs(struct amdgpu_device *adev) { if (adev->vm_manager.vm_pte_funcs == NULL) { adev->vm_manager.vm_pte_funcs = &sdma_v2_4_vm_pte_funcs; - adev->vm_manager.vm_pte_funcs_ring = &adev->sdma[0].ring; + adev->vm_manager.vm_pte_funcs_ring = &adev->sdma.instance[0].ring; adev->vm_manager.vm_pte_funcs_ring->is_pte_ring = true; } } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 9bfe92df15f7..670555a45da9 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -184,7 +184,7 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev) { const char *chip_name; char fw_name[30]; - int err, i; + int err = 0, i; struct amdgpu_firmware_info *info = NULL; const struct common_firmware_header *header = NULL; const struct sdma_firmware_header_v1_0 *hdr; @@ -204,27 +204,27 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev) default: BUG(); } - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { if (i == 0) snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name); else snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name); - err = request_firmware(&adev->sdma[i].fw, fw_name, adev->dev); + err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev); if (err) goto out; - err = amdgpu_ucode_validate(adev->sdma[i].fw); + err = amdgpu_ucode_validate(adev->sdma.instance[i].fw); if (err) goto out; - hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data; - adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); - adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); - if (adev->sdma[i].feature_version >= 20) - adev->sdma[i].burst_nop = true; + hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma.instance[i].fw->data; + adev->sdma.instance[i].fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->sdma.instance[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); + if (adev->sdma.instance[i].feature_version >= 20) + adev->sdma.instance[i].burst_nop = true; if (adev->firmware.smu_load) { info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i]; info->ucode_id = AMDGPU_UCODE_ID_SDMA0 + i; - info->fw = adev->sdma[i].fw; + info->fw = adev->sdma.instance[i].fw; header = (const struct common_firmware_header *)info->fw->data; adev->firmware.fw_size += ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); @@ -235,9 +235,9 @@ out: printk(KERN_ERR "sdma_v3_0: Failed to load firmware \"%s\"\n", fw_name); - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { - release_firmware(adev->sdma[i].fw); - adev->sdma[i].fw = NULL; + for (i = 0; i < adev->sdma.num_instances; i++) { + release_firmware(adev->sdma.instance[i].fw); + adev->sdma.instance[i].fw = NULL; } } return err; @@ -276,7 +276,7 @@ static uint32_t sdma_v3_0_ring_get_wptr(struct amdgpu_ring *ring) /* XXX check if swapping is necessary on BE */ wptr = ring->adev->wb.wb[ring->wptr_offs] >> 2; } else { - int me = (ring == &ring->adev->sdma[0].ring) ? 0 : 1; + int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; wptr = RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me]) >> 2; } @@ -300,7 +300,7 @@ static void sdma_v3_0_ring_set_wptr(struct amdgpu_ring *ring) adev->wb.wb[ring->wptr_offs] = ring->wptr << 2; WDOORBELL32(ring->doorbell_index, ring->wptr << 2); } else { - int me = (ring == &ring->adev->sdma[0].ring) ? 0 : 1; + int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], ring->wptr << 2); } @@ -308,7 +308,7 @@ static void sdma_v3_0_ring_set_wptr(struct amdgpu_ring *ring) static void sdma_v3_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) { - struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ring); + struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring); int i; for (i = 0; i < count; i++) @@ -369,7 +369,7 @@ static void sdma_v3_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) { u32 ref_and_mask = 0; - if (ring == &ring->adev->sdma[0].ring) + if (ring == &ring->adev->sdma.instance[0].ring) ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA0, 1); else ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA1, 1); @@ -454,8 +454,8 @@ static bool sdma_v3_0_ring_emit_semaphore(struct amdgpu_ring *ring, */ static void sdma_v3_0_gfx_stop(struct amdgpu_device *adev) { - struct amdgpu_ring *sdma0 = &adev->sdma[0].ring; - struct amdgpu_ring *sdma1 = &adev->sdma[1].ring; + struct amdgpu_ring *sdma0 = &adev->sdma.instance[0].ring; + struct amdgpu_ring *sdma1 = &adev->sdma.instance[1].ring; u32 rb_cntl, ib_cntl; int i; @@ -463,7 +463,7 @@ static void sdma_v3_0_gfx_stop(struct amdgpu_device *adev) (adev->mman.buffer_funcs_ring == sdma1)) amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size); - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { rb_cntl = RREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i]); rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 0); WREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i], rb_cntl); @@ -500,7 +500,7 @@ static void sdma_v3_0_ctx_switch_enable(struct amdgpu_device *adev, bool enable) u32 f32_cntl; int i; - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { f32_cntl = RREG32(mmSDMA0_CNTL + sdma_offsets[i]); if (enable) f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_CNTL, @@ -530,7 +530,7 @@ static void sdma_v3_0_enable(struct amdgpu_device *adev, bool enable) sdma_v3_0_rlc_stop(adev); } - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { f32_cntl = RREG32(mmSDMA0_F32_CNTL + sdma_offsets[i]); if (enable) f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_F32_CNTL, HALT, 0); @@ -557,8 +557,8 @@ static int sdma_v3_0_gfx_resume(struct amdgpu_device *adev) u32 doorbell; int i, j, r; - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { - ring = &adev->sdma[i].ring; + for (i = 0; i < adev->sdma.num_instances; i++) { + ring = &adev->sdma.instance[i].ring; wb_offset = (ring->rptr_offs * 4); mutex_lock(&adev->srbm_mutex); @@ -669,23 +669,22 @@ static int sdma_v3_0_load_microcode(struct amdgpu_device *adev) u32 fw_size; int i, j; - if (!adev->sdma[0].fw || !adev->sdma[1].fw) - return -EINVAL; - /* halt the MEs */ sdma_v3_0_enable(adev, false); - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { - hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data; + for (i = 0; i < adev->sdma.num_instances; i++) { + if (!adev->sdma.instance[i].fw) + return -EINVAL; + hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma.instance[i].fw->data; amdgpu_ucode_print_sdma_hdr(&hdr->header); fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; fw_data = (const __le32 *) - (adev->sdma[i].fw->data + + (adev->sdma.instance[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], 0); for (j = 0; j < fw_size; j++) WREG32(mmSDMA0_UCODE_DATA + sdma_offsets[i], le32_to_cpup(fw_data++)); - WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], adev->sdma[i].fw_version); + WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], adev->sdma.instance[i].fw_version); } return 0; @@ -701,21 +700,21 @@ static int sdma_v3_0_load_microcode(struct amdgpu_device *adev) */ static int sdma_v3_0_start(struct amdgpu_device *adev) { - int r; + int r, i; if (!adev->firmware.smu_load) { r = sdma_v3_0_load_microcode(adev); if (r) return r; } else { - r = adev->smu.smumgr_funcs->check_fw_load_finish(adev, - AMDGPU_UCODE_ID_SDMA0); - if (r) - return -EINVAL; - r = adev->smu.smumgr_funcs->check_fw_load_finish(adev, - AMDGPU_UCODE_ID_SDMA1); - if (r) - return -EINVAL; + for (i = 0; i < adev->sdma.num_instances; i++) { + r = adev->smu.smumgr_funcs->check_fw_load_finish(adev, + (i == 0) ? + AMDGPU_UCODE_ID_SDMA0 : + AMDGPU_UCODE_ID_SDMA1); + if (r) + return -EINVAL; + } } /* unhalt the MEs */ @@ -1013,7 +1012,7 @@ static void sdma_v3_0_vm_set_pte_pde(struct amdgpu_ib *ib, */ static void sdma_v3_0_vm_pad_ib(struct amdgpu_ib *ib) { - struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ib->ring); + struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ib->ring); u32 pad_count; int i; @@ -1071,6 +1070,12 @@ static int sdma_v3_0_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + switch (adev->asic_type) { + default: + adev->sdma.num_instances = SDMA_MAX_INSTANCE; + break; + } + sdma_v3_0_set_ring_funcs(adev); sdma_v3_0_set_buffer_funcs(adev); sdma_v3_0_set_vm_pte_funcs(adev); @@ -1082,21 +1087,21 @@ static int sdma_v3_0_early_init(void *handle) static int sdma_v3_0_sw_init(void *handle) { struct amdgpu_ring *ring; - int r; + int r, i; struct amdgpu_device *adev = (struct amdgpu_device *)handle; /* SDMA trap event */ - r = amdgpu_irq_add_id(adev, 224, &adev->sdma_trap_irq); + r = amdgpu_irq_add_id(adev, 224, &adev->sdma.trap_irq); if (r) return r; /* SDMA Privileged inst */ - r = amdgpu_irq_add_id(adev, 241, &adev->sdma_illegal_inst_irq); + r = amdgpu_irq_add_id(adev, 241, &adev->sdma.illegal_inst_irq); if (r) return r; /* SDMA Privileged inst */ - r = amdgpu_irq_add_id(adev, 247, &adev->sdma_illegal_inst_irq); + r = amdgpu_irq_add_id(adev, 247, &adev->sdma.illegal_inst_irq); if (r) return r; @@ -1106,33 +1111,23 @@ static int sdma_v3_0_sw_init(void *handle) return r; } - ring = &adev->sdma[0].ring; - ring->ring_obj = NULL; - ring->use_doorbell = true; - ring->doorbell_index = AMDGPU_DOORBELL_sDMA_ENGINE0; - - ring = &adev->sdma[1].ring; - ring->ring_obj = NULL; - ring->use_doorbell = true; - ring->doorbell_index = AMDGPU_DOORBELL_sDMA_ENGINE1; - - ring = &adev->sdma[0].ring; - sprintf(ring->name, "sdma0"); - r = amdgpu_ring_init(adev, ring, 256 * 1024, - SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), 0xf, - &adev->sdma_trap_irq, AMDGPU_SDMA_IRQ_TRAP0, - AMDGPU_RING_TYPE_SDMA); - if (r) - return r; - - ring = &adev->sdma[1].ring; - sprintf(ring->name, "sdma1"); - r = amdgpu_ring_init(adev, ring, 256 * 1024, - SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), 0xf, - &adev->sdma_trap_irq, AMDGPU_SDMA_IRQ_TRAP1, - AMDGPU_RING_TYPE_SDMA); - if (r) - return r; + for (i = 0; i < adev->sdma.num_instances; i++) { + ring = &adev->sdma.instance[i].ring; + ring->ring_obj = NULL; + ring->use_doorbell = true; + ring->doorbell_index = (i == 0) ? + AMDGPU_DOORBELL_sDMA_ENGINE0 : AMDGPU_DOORBELL_sDMA_ENGINE1; + + sprintf(ring->name, "sdma%d", i); + r = amdgpu_ring_init(adev, ring, 256 * 1024, + SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), 0xf, + &adev->sdma.trap_irq, + (i == 0) ? + AMDGPU_SDMA_IRQ_TRAP0 : AMDGPU_SDMA_IRQ_TRAP1, + AMDGPU_RING_TYPE_SDMA); + if (r) + return r; + } return r; } @@ -1140,9 +1135,10 @@ static int sdma_v3_0_sw_init(void *handle) static int sdma_v3_0_sw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int i; - amdgpu_ring_fini(&adev->sdma[0].ring); - amdgpu_ring_fini(&adev->sdma[1].ring); + for (i = 0; i < adev->sdma.num_instances; i++) + amdgpu_ring_fini(&adev->sdma.instance[i].ring); return 0; } @@ -1222,7 +1218,7 @@ static void sdma_v3_0_print_status(void *handle) dev_info(adev->dev, "VI SDMA registers\n"); dev_info(adev->dev, " SRBM_STATUS2=0x%08X\n", RREG32(mmSRBM_STATUS2)); - for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + for (i = 0; i < adev->sdma.num_instances; i++) { dev_info(adev->dev, " SDMA%d_STATUS_REG=0x%08X\n", i, RREG32(mmSDMA0_STATUS_REG + sdma_offsets[i])); dev_info(adev->dev, " SDMA%d_F32_CNTL=0x%08X\n", @@ -1367,7 +1363,7 @@ static int sdma_v3_0_process_trap_irq(struct amdgpu_device *adev, case 0: switch (queue_id) { case 0: - amdgpu_fence_process(&adev->sdma[0].ring); + amdgpu_fence_process(&adev->sdma.instance[0].ring); break; case 1: /* XXX compute */ @@ -1380,7 +1376,7 @@ static int sdma_v3_0_process_trap_irq(struct amdgpu_device *adev, case 1: switch (queue_id) { case 0: - amdgpu_fence_process(&adev->sdma[1].ring); + amdgpu_fence_process(&adev->sdma.instance[1].ring); break; case 1: /* XXX compute */ @@ -1468,8 +1464,10 @@ static const struct amdgpu_ring_funcs sdma_v3_0_ring_funcs = { static void sdma_v3_0_set_ring_funcs(struct amdgpu_device *adev) { - adev->sdma[0].ring.funcs = &sdma_v3_0_ring_funcs; - adev->sdma[1].ring.funcs = &sdma_v3_0_ring_funcs; + int i; + + for (i = 0; i < adev->sdma.num_instances; i++) + adev->sdma.instance[i].ring.funcs = &sdma_v3_0_ring_funcs; } static const struct amdgpu_irq_src_funcs sdma_v3_0_trap_irq_funcs = { @@ -1483,9 +1481,9 @@ static const struct amdgpu_irq_src_funcs sdma_v3_0_illegal_inst_irq_funcs = { static void sdma_v3_0_set_irq_funcs(struct amdgpu_device *adev) { - adev->sdma_trap_irq.num_types = AMDGPU_SDMA_IRQ_LAST; - adev->sdma_trap_irq.funcs = &sdma_v3_0_trap_irq_funcs; - adev->sdma_illegal_inst_irq.funcs = &sdma_v3_0_illegal_inst_irq_funcs; + adev->sdma.trap_irq.num_types = AMDGPU_SDMA_IRQ_LAST; + adev->sdma.trap_irq.funcs = &sdma_v3_0_trap_irq_funcs; + adev->sdma.illegal_inst_irq.funcs = &sdma_v3_0_illegal_inst_irq_funcs; } /** @@ -1551,7 +1549,7 @@ static void sdma_v3_0_set_buffer_funcs(struct amdgpu_device *adev) { if (adev->mman.buffer_funcs == NULL) { adev->mman.buffer_funcs = &sdma_v3_0_buffer_funcs; - adev->mman.buffer_funcs_ring = &adev->sdma[0].ring; + adev->mman.buffer_funcs_ring = &adev->sdma.instance[0].ring; } } @@ -1566,7 +1564,7 @@ static void sdma_v3_0_set_vm_pte_funcs(struct amdgpu_device *adev) { if (adev->vm_manager.vm_pte_funcs == NULL) { adev->vm_manager.vm_pte_funcs = &sdma_v3_0_vm_pte_funcs; - adev->vm_manager.vm_pte_funcs_ring = &adev->sdma[0].ring; + adev->vm_manager.vm_pte_funcs_ring = &adev->sdma.instance[0].ring; adev->vm_manager.vm_pte_funcs_ring->is_pte_ring = true; } } diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index b55ceb14fdcd..0bac8702e934 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -1005,6 +1005,9 @@ static void vi_pcie_gen3_enable(struct amdgpu_device *adev) u32 mask; int ret; + if (pci_is_root_bus(adev->pdev->bus)) + return; + if (amdgpu_pcie_gen2 == 0) return; diff --git a/drivers/gpu/drm/amd/include/cgs_linux.h b/drivers/gpu/drm/amd/include/cgs_linux.h index 488642f08267..3b47ae313e36 100644 --- a/drivers/gpu/drm/amd/include/cgs_linux.h +++ b/drivers/gpu/drm/amd/include/cgs_linux.h @@ -27,19 +27,6 @@ #include "cgs_common.h" /** - * cgs_import_gpu_mem() - Import dmabuf handle - * @cgs_device: opaque device handle - * @dmabuf_fd: DMABuf file descriptor - * @handle: memory handle (output) - * - * Must be called in the process context that dmabuf_fd belongs to. - * - * Return: 0 on success, -errno otherwise - */ -typedef int (*cgs_import_gpu_mem_t)(void *cgs_device, int dmabuf_fd, - cgs_handle_t *handle); - -/** * cgs_irq_source_set_func() - Callback for enabling/disabling interrupt sources * @private_data: private data provided to cgs_add_irq_source * @src_id: interrupt source ID @@ -114,16 +101,12 @@ typedef int (*cgs_irq_get_t)(void *cgs_device, unsigned src_id, unsigned type); typedef int (*cgs_irq_put_t)(void *cgs_device, unsigned src_id, unsigned type); struct cgs_os_ops { - cgs_import_gpu_mem_t import_gpu_mem; - /* IRQ handling */ cgs_add_irq_source_t add_irq_source; cgs_irq_get_t irq_get; cgs_irq_put_t irq_put; }; -#define cgs_import_gpu_mem(dev,dmabuf_fd,handle) \ - CGS_OS_CALL(import_gpu_mem,dev,dmabuf_fd,handle) #define cgs_add_irq_source(dev,src_id,num_types,set,handler,private_data) \ CGS_OS_CALL(add_irq_source,dev,src_id,num_types,set,handler, \ private_data) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 3697eeeecf82..7fa1d7a438e9 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -327,19 +327,49 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) struct amd_sched_fence *s_fence = container_of(cb, struct amd_sched_fence, cb); struct amd_gpu_scheduler *sched = s_fence->sched; + unsigned long flags; atomic_dec(&sched->hw_rq_count); amd_sched_fence_signal(s_fence); + if (sched->timeout != MAX_SCHEDULE_TIMEOUT) { + cancel_delayed_work_sync(&s_fence->dwork); + spin_lock_irqsave(&sched->fence_list_lock, flags); + list_del_init(&s_fence->list); + spin_unlock_irqrestore(&sched->fence_list_lock, flags); + } fence_put(&s_fence->base); wake_up_interruptible(&sched->wake_up_worker); } +static void amd_sched_fence_work_func(struct work_struct *work) +{ + struct amd_sched_fence *s_fence = + container_of(work, struct amd_sched_fence, dwork.work); + struct amd_gpu_scheduler *sched = s_fence->sched; + struct amd_sched_fence *entity, *tmp; + unsigned long flags; + + DRM_ERROR("[%s] scheduler is timeout!\n", sched->name); + + /* Clean all pending fences */ + spin_lock_irqsave(&sched->fence_list_lock, flags); + list_for_each_entry_safe(entity, tmp, &sched->fence_list, list) { + DRM_ERROR(" fence no %d\n", entity->base.seqno); + cancel_delayed_work(&entity->dwork); + list_del_init(&entity->list); + fence_put(&entity->base); + } + spin_unlock_irqrestore(&sched->fence_list_lock, flags); +} + static int amd_sched_main(void *param) { struct sched_param sparam = {.sched_priority = 1}; struct amd_gpu_scheduler *sched = (struct amd_gpu_scheduler *)param; int r, count; + spin_lock_init(&sched->fence_list_lock); + INIT_LIST_HEAD(&sched->fence_list); sched_setscheduler(current, SCHED_FIFO, &sparam); while (!kthread_should_stop()) { @@ -347,6 +377,7 @@ static int amd_sched_main(void *param) struct amd_sched_fence *s_fence; struct amd_sched_job *sched_job; struct fence *fence; + unsigned long flags; wait_event_interruptible(sched->wake_up_worker, kthread_should_stop() || @@ -357,6 +388,15 @@ static int amd_sched_main(void *param) entity = sched_job->s_entity; s_fence = sched_job->s_fence; + + if (sched->timeout != MAX_SCHEDULE_TIMEOUT) { + INIT_DELAYED_WORK(&s_fence->dwork, amd_sched_fence_work_func); + schedule_delayed_work(&s_fence->dwork, sched->timeout); + spin_lock_irqsave(&sched->fence_list_lock, flags); + list_add_tail(&s_fence->list, &sched->fence_list); + spin_unlock_irqrestore(&sched->fence_list_lock, flags); + } + atomic_inc(&sched->hw_rq_count); fence = sched->ops->run_job(sched_job); if (fence) { @@ -392,11 +432,12 @@ static int amd_sched_main(void *param) */ int amd_sched_init(struct amd_gpu_scheduler *sched, struct amd_sched_backend_ops *ops, - unsigned hw_submission, const char *name) + unsigned hw_submission, long timeout, const char *name) { sched->ops = ops; sched->hw_submission_limit = hw_submission; sched->name = name; + sched->timeout = timeout; amd_sched_rq_init(&sched->sched_rq); amd_sched_rq_init(&sched->kernel_rq); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 80b64dc22214..929e9aced041 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -68,6 +68,8 @@ struct amd_sched_fence { struct amd_gpu_scheduler *sched; spinlock_t lock; void *owner; + struct delayed_work dwork; + struct list_head list; }; struct amd_sched_job { @@ -103,18 +105,21 @@ struct amd_sched_backend_ops { struct amd_gpu_scheduler { struct amd_sched_backend_ops *ops; uint32_t hw_submission_limit; + long timeout; const char *name; struct amd_sched_rq sched_rq; struct amd_sched_rq kernel_rq; wait_queue_head_t wake_up_worker; wait_queue_head_t job_scheduled; atomic_t hw_rq_count; + struct list_head fence_list; + spinlock_t fence_list_lock; struct task_struct *thread; }; int amd_sched_init(struct amd_gpu_scheduler *sched, struct amd_sched_backend_ops *ops, - uint32_t hw_submission, const char *name); + uint32_t hw_submission, long timeout, const char *name); void amd_sched_fini(struct amd_gpu_scheduler *sched); int amd_sched_entity_init(struct amd_gpu_scheduler *sched, diff --git a/drivers/gpu/drm/armada/Kconfig b/drivers/gpu/drm/armada/Kconfig index 50ae88ad4d76..eb773e9af313 100644 --- a/drivers/gpu/drm/armada/Kconfig +++ b/drivers/gpu/drm/armada/Kconfig @@ -14,12 +14,3 @@ config DRM_ARMADA This driver provides no built-in acceleration; acceleration is performed by other IP found on the SoC. This driver provides kernel mode setting and buffer management to userspace. - -config DRM_ARMADA_TDA1998X - bool "Support TDA1998X HDMI output" - depends on DRM_ARMADA != n - depends on I2C && DRM_I2C_NXP_TDA998X = y - default y - help - Support the TDA1998x HDMI output device found on the Solid-Run - CuBox. diff --git a/drivers/gpu/drm/armada/Makefile b/drivers/gpu/drm/armada/Makefile index d6f43e06150a..ffd673615772 100644 --- a/drivers/gpu/drm/armada/Makefile +++ b/drivers/gpu/drm/armada/Makefile @@ -1,6 +1,5 @@ armada-y := armada_crtc.o armada_drv.o armada_fb.o armada_fbdev.o \ - armada_gem.o armada_output.o armada_overlay.o \ - armada_slave.o + armada_gem.o armada_overlay.o armada-y += armada_510.o armada-$(CONFIG_DEBUG_FS) += armada_debugfs.o diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 01ffe9bffe38..cebcab560626 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -20,6 +20,7 @@ #include "armada_hw.h" struct armada_frame_work { + struct armada_plane_work work; struct drm_pending_vblank_event *event; struct armada_regs regs[4]; struct drm_framebuffer *old_fb; @@ -33,6 +34,23 @@ enum csc_mode { CSC_RGB_STUDIO = 2, }; +static const uint32_t armada_primary_formats[] = { + DRM_FORMAT_UYVY, + DRM_FORMAT_YUYV, + DRM_FORMAT_VYUY, + DRM_FORMAT_YVYU, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_RGB565, + DRM_FORMAT_BGR565, +}; + /* * A note about interlacing. Let's consider HDMI 1920x1080i. * The timing parameters we have from X are: @@ -173,49 +191,82 @@ static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb, return i; } -static int armada_drm_crtc_queue_frame_work(struct armada_crtc *dcrtc, - struct armada_frame_work *work) +static void armada_drm_plane_work_run(struct armada_crtc *dcrtc, + struct armada_plane *plane) +{ + struct armada_plane_work *work = xchg(&plane->work, NULL); + + /* Handle any pending frame work. */ + if (work) { + work->fn(dcrtc, plane, work); + drm_vblank_put(dcrtc->crtc.dev, dcrtc->num); + } + + wake_up(&plane->frame_wait); +} + +int armada_drm_plane_work_queue(struct armada_crtc *dcrtc, + struct armada_plane *plane, struct armada_plane_work *work) { - struct drm_device *dev = dcrtc->crtc.dev; - unsigned long flags; int ret; - ret = drm_vblank_get(dev, dcrtc->num); + ret = drm_vblank_get(dcrtc->crtc.dev, dcrtc->num); if (ret) { DRM_ERROR("failed to acquire vblank counter\n"); return ret; } - spin_lock_irqsave(&dev->event_lock, flags); - if (!dcrtc->frame_work) - dcrtc->frame_work = work; - else - ret = -EBUSY; - spin_unlock_irqrestore(&dev->event_lock, flags); - + ret = cmpxchg(&plane->work, NULL, work) ? -EBUSY : 0; if (ret) - drm_vblank_put(dev, dcrtc->num); + drm_vblank_put(dcrtc->crtc.dev, dcrtc->num); return ret; } -static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc) +int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout) { - struct drm_device *dev = dcrtc->crtc.dev; - struct armada_frame_work *work = dcrtc->frame_work; + return wait_event_timeout(plane->frame_wait, !plane->work, timeout); +} - dcrtc->frame_work = NULL; +struct armada_plane_work *armada_drm_plane_work_cancel( + struct armada_crtc *dcrtc, struct armada_plane *plane) +{ + struct armada_plane_work *work = xchg(&plane->work, NULL); - armada_drm_crtc_update_regs(dcrtc, work->regs); + if (work) + drm_vblank_put(dcrtc->crtc.dev, dcrtc->num); - if (work->event) - drm_send_vblank_event(dev, dcrtc->num, work->event); + return work; +} - drm_vblank_put(dev, dcrtc->num); +static int armada_drm_crtc_queue_frame_work(struct armada_crtc *dcrtc, + struct armada_frame_work *work) +{ + struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary); + + return armada_drm_plane_work_queue(dcrtc, plane, &work->work); +} + +static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc, + struct armada_plane *plane, struct armada_plane_work *work) +{ + struct armada_frame_work *fwork = container_of(work, struct armada_frame_work, work); + struct drm_device *dev = dcrtc->crtc.dev; + unsigned long flags; + + spin_lock_irqsave(&dcrtc->irq_lock, flags); + armada_drm_crtc_update_regs(dcrtc, fwork->regs); + spin_unlock_irqrestore(&dcrtc->irq_lock, flags); + + if (fwork->event) { + spin_lock_irqsave(&dev->event_lock, flags); + drm_send_vblank_event(dev, dcrtc->num, fwork->event); + spin_unlock_irqrestore(&dev->event_lock, flags); + } /* Finally, queue the process-half of the cleanup. */ - __armada_drm_queue_unref_work(dcrtc->crtc.dev, work->old_fb); - kfree(work); + __armada_drm_queue_unref_work(dcrtc->crtc.dev, fwork->old_fb); + kfree(fwork); } static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, @@ -235,6 +286,7 @@ static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, work = kmalloc(sizeof(*work), GFP_KERNEL); if (work) { int i = 0; + work->work.fn = armada_drm_crtc_complete_frame_work; work->event = NULL; work->old_fb = fb; armada_reg_queue_end(work->regs, i); @@ -255,19 +307,14 @@ static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, static void armada_drm_vblank_off(struct armada_crtc *dcrtc) { - struct drm_device *dev = dcrtc->crtc.dev; + struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary); /* * Tell the DRM core that vblank IRQs aren't going to happen for * a while. This cleans up any pending vblank events for us. */ drm_crtc_vblank_off(&dcrtc->crtc); - - /* Handle any pending flip event. */ - spin_lock_irq(&dev->event_lock); - if (dcrtc->frame_work) - armada_drm_crtc_complete_frame_work(dcrtc); - spin_unlock_irq(&dev->event_lock); + armada_drm_plane_work_run(dcrtc, plane); } void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b, @@ -287,7 +334,11 @@ static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) if (dcrtc->dpms != dpms) { dcrtc->dpms = dpms; + if (!IS_ERR(dcrtc->clk) && !dpms_blanked(dpms)) + WARN_ON(clk_prepare_enable(dcrtc->clk)); armada_drm_crtc_update(dcrtc); + if (!IS_ERR(dcrtc->clk) && dpms_blanked(dpms)) + clk_disable_unprepare(dcrtc->clk); if (dpms_blanked(dpms)) armada_drm_vblank_off(dcrtc); else @@ -310,17 +361,11 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc) /* * If we have an overlay plane associated with this CRTC, disable * it before the modeset to avoid its coordinates being outside - * the new mode parameters. DRM doesn't provide help with this. + * the new mode parameters. */ plane = dcrtc->plane; - if (plane) { - struct drm_framebuffer *fb = plane->fb; - - plane->funcs->disable_plane(plane); - plane->fb = NULL; - plane->crtc = NULL; - drm_framebuffer_unreference(fb); - } + if (plane) + drm_plane_force_disable(plane); } /* The mode_config.mutex will be held for this call */ @@ -356,8 +401,8 @@ static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) { - struct armada_vbl_event *e, *n; void __iomem *base = dcrtc->base; + struct drm_plane *ovl_plane; if (stat & DMA_FF_UNDERFLOW) DRM_ERROR("video underflow on crtc %u\n", dcrtc->num); @@ -368,11 +413,10 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) drm_handle_vblank(dcrtc->crtc.dev, dcrtc->num); spin_lock(&dcrtc->irq_lock); - - list_for_each_entry_safe(e, n, &dcrtc->vbl_list, node) { - list_del_init(&e->node); - drm_vblank_put(dcrtc->crtc.dev, dcrtc->num); - e->fn(dcrtc, e->data); + ovl_plane = dcrtc->plane; + if (ovl_plane) { + struct armada_plane *plane = drm_to_armada_plane(ovl_plane); + armada_drm_plane_work_run(dcrtc, plane); } if (stat & GRA_FRAME_IRQ && dcrtc->interlaced) { @@ -404,14 +448,8 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) spin_unlock(&dcrtc->irq_lock); if (stat & GRA_FRAME_IRQ) { - struct drm_device *dev = dcrtc->crtc.dev; - - spin_lock(&dev->event_lock); - if (dcrtc->frame_work) - armada_drm_crtc_complete_frame_work(dcrtc); - spin_unlock(&dev->event_lock); - - wake_up(&dcrtc->frame_wait); + struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary); + armada_drm_plane_work_run(dcrtc, plane); } } @@ -527,7 +565,8 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, adj->crtc_vtotal, tm, bm); /* Wait for pending flips to complete */ - wait_event(dcrtc->frame_wait, !dcrtc->frame_work); + armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), + MAX_SCHEDULE_TIMEOUT); drm_crtc_vblank_off(crtc); @@ -537,6 +576,13 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL); } + /* + * If we are blanked, we would have disabled the clock. Re-enable + * it so that compute_clock() does the right thing. + */ + if (!IS_ERR(dcrtc->clk) && dpms_blanked(dcrtc->dpms)) + WARN_ON(clk_prepare_enable(dcrtc->clk)); + /* Now compute the divider for real */ dcrtc->variant->compute_clock(dcrtc, adj, &sclk); @@ -637,7 +683,8 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, armada_reg_queue_end(regs, i); /* Wait for pending flips to complete */ - wait_event(dcrtc->frame_wait, !dcrtc->frame_work); + armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), + MAX_SCHEDULE_TIMEOUT); /* Take a reference to the new fb as we're using it */ drm_framebuffer_reference(crtc->primary->fb); @@ -651,18 +698,47 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, return 0; } +void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc, + struct drm_plane *plane) +{ + u32 sram_para1, dma_ctrl0_mask; + + /* + * Drop our reference on any framebuffer attached to this plane. + * We don't need to NULL this out as drm_plane_force_disable(), + * and __setplane_internal() will do so for an overlay plane, and + * __drm_helper_disable_unused_functions() will do so for the + * primary plane. + */ + if (plane->fb) + drm_framebuffer_unreference(plane->fb); + + /* Power down the Y/U/V FIFOs */ + sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66; + + /* Power down most RAMs and FIFOs if this is the primary plane */ + if (plane->type == DRM_PLANE_TYPE_PRIMARY) { + sram_para1 |= CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | + CFG_PDWN32x32 | CFG_PDWN64x66; + dma_ctrl0_mask = CFG_GRA_ENA; + } else { + dma_ctrl0_mask = CFG_DMA_ENA; + } + + spin_lock_irq(&dcrtc->irq_lock); + armada_updatel(0, dma_ctrl0_mask, dcrtc->base + LCD_SPU_DMA_CTRL0); + spin_unlock_irq(&dcrtc->irq_lock); + + armada_updatel(sram_para1, 0, dcrtc->base + LCD_SPU_SRAM_PARA1); +} + /* The mode_config.mutex will be held for this call */ static void armada_drm_crtc_disable(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); - armada_drm_crtc_finish_fb(dcrtc, crtc->primary->fb, true); - - /* Power down most RAMs and FIFOs */ - writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | - CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 | - CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1); + armada_drm_crtc_plane_disable(dcrtc, crtc->primary); } static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { @@ -920,8 +996,6 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct armada_frame_work *work; - struct drm_device *dev = crtc->dev; - unsigned long flags; unsigned i; int ret; @@ -933,6 +1007,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, if (!work) return -ENOMEM; + work->work.fn = armada_drm_crtc_complete_frame_work; work->event = event; work->old_fb = dcrtc->crtc.primary->fb; @@ -966,12 +1041,8 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, * Finally, if the display is blanked, we won't receive an * interrupt, so complete it now. */ - if (dpms_blanked(dcrtc->dpms)) { - spin_lock_irqsave(&dev->event_lock, flags); - if (dcrtc->frame_work) - armada_drm_crtc_complete_frame_work(dcrtc); - spin_unlock_irqrestore(&dev->event_lock, flags); - } + if (dpms_blanked(dcrtc->dpms)) + armada_drm_plane_work_run(dcrtc, drm_to_armada_plane(dcrtc->crtc.primary)); return 0; } @@ -1012,6 +1083,19 @@ static struct drm_crtc_funcs armada_crtc_funcs = { .set_property = armada_drm_crtc_set_property, }; +static const struct drm_plane_funcs armada_primary_plane_funcs = { + .update_plane = drm_primary_helper_update, + .disable_plane = drm_primary_helper_disable, + .destroy = drm_primary_helper_destroy, +}; + +int armada_drm_plane_init(struct armada_plane *plane) +{ + init_waitqueue_head(&plane->frame_wait); + + return 0; +} + static struct drm_prop_enum_list armada_drm_csc_yuv_enum_list[] = { { CSC_AUTO, "Auto" }, { CSC_YUV_CCIR601, "CCIR601" }, @@ -1044,12 +1128,13 @@ static int armada_drm_crtc_create_properties(struct drm_device *dev) return 0; } -int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, +static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, struct resource *res, int irq, const struct armada_variant *variant, struct device_node *port) { struct armada_private *priv = drm->dev_private; struct armada_crtc *dcrtc; + struct armada_plane *primary; void __iomem *base; int ret; @@ -1080,8 +1165,6 @@ int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24; spin_lock_init(&dcrtc->irq_lock); dcrtc->irq_ena = CLEAN_SPU_IRQ_ISR; - INIT_LIST_HEAD(&dcrtc->vbl_list); - init_waitqueue_head(&dcrtc->frame_wait); /* Initialize some registers which we don't otherwise set */ writel_relaxed(0x00000001, dcrtc->base + LCD_CFG_SCLK_DIV); @@ -1118,7 +1201,32 @@ int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, priv->dcrtc[dcrtc->num] = dcrtc; dcrtc->crtc.port = port; - drm_crtc_init(drm, &dcrtc->crtc, &armada_crtc_funcs); + + primary = kzalloc(sizeof(*primary), GFP_KERNEL); + if (!primary) + return -ENOMEM; + + ret = armada_drm_plane_init(primary); + if (ret) { + kfree(primary); + return ret; + } + + ret = drm_universal_plane_init(drm, &primary->base, 0, + &armada_primary_plane_funcs, + armada_primary_formats, + ARRAY_SIZE(armada_primary_formats), + DRM_PLANE_TYPE_PRIMARY); + if (ret) { + kfree(primary); + return ret; + } + + ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, &primary->base, NULL, + &armada_crtc_funcs); + if (ret) + goto err_crtc_init; + drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs); drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop, @@ -1127,6 +1235,10 @@ int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, dcrtc->csc_rgb_mode); return armada_overlay_plane_create(drm, 1 << dcrtc->num); + +err_crtc_init: + primary->base.funcs->destroy(&primary->base); + return ret; } static int diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 98102a5a9af5..04fdd22d483b 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -31,9 +31,30 @@ struct armada_regs { #define armada_reg_queue_end(_r, _i) \ armada_reg_queue_mod(_r, _i, 0, 0, ~0) -struct armada_frame_work; +struct armada_crtc; +struct armada_plane; struct armada_variant; +struct armada_plane_work { + void (*fn)(struct armada_crtc *, + struct armada_plane *, + struct armada_plane_work *); +}; + +struct armada_plane { + struct drm_plane base; + wait_queue_head_t frame_wait; + struct armada_plane_work *work; +}; +#define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) + +int armada_drm_plane_init(struct armada_plane *plane); +int armada_drm_plane_work_queue(struct armada_crtc *dcrtc, + struct armada_plane *plane, struct armada_plane_work *work); +int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout); +struct armada_plane_work *armada_drm_plane_work_cancel( + struct armada_crtc *dcrtc, struct armada_plane *plane); + struct armada_crtc { struct drm_crtc crtc; const struct armada_variant *variant; @@ -66,25 +87,20 @@ struct armada_crtc { uint32_t dumb_ctrl; uint32_t spu_iopad_ctrl; - wait_queue_head_t frame_wait; - struct armada_frame_work *frame_work; - spinlock_t irq_lock; uint32_t irq_ena; - struct list_head vbl_list; }; #define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc) -struct device_node; -int armada_drm_crtc_create(struct drm_device *, struct device *, - struct resource *, int, const struct armada_variant *, - struct device_node *); void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int); void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int); void armada_drm_crtc_disable_irq(struct armada_crtc *, u32); void armada_drm_crtc_enable_irq(struct armada_crtc *, u32); void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); +void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc, + struct drm_plane *plane); + extern struct platform_driver armada_lcd_platform_driver; #endif diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index 5f6aef0dca59..4df6f2af2b21 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -37,22 +37,6 @@ static inline uint32_t armada_pitch(uint32_t width, uint32_t bpp) return ALIGN(pitch, 128); } -struct armada_vbl_event { - struct list_head node; - void *data; - void (*fn)(struct armada_crtc *, void *); -}; -void armada_drm_vbl_event_add(struct armada_crtc *, - struct armada_vbl_event *); -void armada_drm_vbl_event_remove(struct armada_crtc *, - struct armada_vbl_event *); -#define armada_drm_vbl_event_init(_e, _f, _d) do { \ - struct armada_vbl_event *__e = _e; \ - INIT_LIST_HEAD(&__e->node); \ - __e->data = _d; \ - __e->fn = _f; \ -} while (0) - struct armada_private; diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 225034b74cda..1cbb080f0c4a 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -18,47 +18,6 @@ #include <drm/armada_drm.h> #include "armada_ioctlP.h" -#ifdef CONFIG_DRM_ARMADA_TDA1998X -#include <drm/i2c/tda998x.h> -#include "armada_slave.h" - -static struct tda998x_encoder_params params = { - /* With 0x24, there is no translation between vp_out and int_vp - FB LCD out Pins VIP Int Vp - R:23:16 R:7:0 VPC7:0 7:0 7:0[R] - G:15:8 G:15:8 VPB7:0 23:16 23:16[G] - B:7:0 B:23:16 VPA7:0 15:8 15:8[B] - */ - .swap_a = 2, - .swap_b = 3, - .swap_c = 4, - .swap_d = 5, - .swap_e = 0, - .swap_f = 1, - .audio_cfg = BIT(2), - .audio_frame[1] = 1, - .audio_format = AFMT_SPDIF, - .audio_sample_rate = 44100, -}; - -static const struct armada_drm_slave_config tda19988_config = { - .i2c_adapter_id = 0, - .crtcs = 1 << 0, /* Only LCD0 at the moment */ - .polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT, - .interlace_allowed = true, - .info = { - .type = "tda998x", - .addr = 0x70, - .platform_data = ¶ms, - }, -}; -#endif - -static bool is_componentized(struct device *dev) -{ - return dev->of_node || dev->platform_data; -} - static void armada_drm_unref_work(struct work_struct *work) { struct armada_private *priv = @@ -91,16 +50,11 @@ void armada_drm_queue_unref_work(struct drm_device *dev, static int armada_drm_load(struct drm_device *dev, unsigned long flags) { - const struct platform_device_id *id; - const struct armada_variant *variant; struct armada_private *priv; - struct resource *res[ARRAY_SIZE(priv->dcrtc)]; struct resource *mem = NULL; - int ret, n, i; - - memset(res, 0, sizeof(res)); + int ret, n; - for (n = i = 0; ; n++) { + for (n = 0; ; n++) { struct resource *r = platform_get_resource(dev->platformdev, IORESOURCE_MEM, n); if (!r) @@ -109,8 +63,6 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags) /* Resources above 64K are graphics memory */ if (resource_size(r) > SZ_64K) mem = r; - else if (i < ARRAY_SIZE(priv->dcrtc)) - res[i++] = r; else return -EINVAL; } @@ -131,13 +83,6 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags) platform_set_drvdata(dev->platformdev, dev); dev->dev_private = priv; - /* Get the implementation specific driver data. */ - id = platform_get_device_id(dev->platformdev); - if (!id) - return -ENXIO; - - variant = (const struct armada_variant *)id->driver_data; - INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work); INIT_KFIFO(priv->fb_unref); @@ -157,34 +102,9 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags) dev->mode_config.funcs = &armada_drm_mode_config_funcs; drm_mm_init(&priv->linear, mem->start, resource_size(mem)); - /* Create all LCD controllers */ - for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) { - int irq; - - if (!res[n]) - break; - - irq = platform_get_irq(dev->platformdev, n); - if (irq < 0) - goto err_kms; - - ret = armada_drm_crtc_create(dev, dev->dev, res[n], irq, - variant, NULL); - if (ret) - goto err_kms; - } - - if (is_componentized(dev->dev)) { - ret = component_bind_all(dev->dev, dev); - if (ret) - goto err_kms; - } else { -#ifdef CONFIG_DRM_ARMADA_TDA1998X - ret = armada_drm_connector_slave_create(dev, &tda19988_config); - if (ret) - goto err_kms; -#endif - } + ret = component_bind_all(dev->dev, dev); + if (ret) + goto err_kms; ret = drm_vblank_init(dev, dev->mode_config.num_crtc); if (ret) @@ -202,8 +122,7 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags) return 0; err_comp: - if (is_componentized(dev->dev)) - component_unbind_all(dev->dev, dev); + component_unbind_all(dev->dev, dev); err_kms: drm_mode_config_cleanup(dev); drm_mm_takedown(&priv->linear); @@ -219,8 +138,7 @@ static int armada_drm_unload(struct drm_device *dev) drm_kms_helper_poll_fini(dev); armada_fbdev_fini(dev); - if (is_componentized(dev->dev)) - component_unbind_all(dev->dev, dev); + component_unbind_all(dev->dev, dev); drm_mode_config_cleanup(dev); drm_mm_takedown(&priv->linear); @@ -230,50 +148,24 @@ static int armada_drm_unload(struct drm_device *dev) return 0; } -void armada_drm_vbl_event_add(struct armada_crtc *dcrtc, - struct armada_vbl_event *evt) -{ - unsigned long flags; - - spin_lock_irqsave(&dcrtc->irq_lock, flags); - if (list_empty(&evt->node)) { - list_add_tail(&evt->node, &dcrtc->vbl_list); - - drm_vblank_get(dcrtc->crtc.dev, dcrtc->num); - } - spin_unlock_irqrestore(&dcrtc->irq_lock, flags); -} - -void armada_drm_vbl_event_remove(struct armada_crtc *dcrtc, - struct armada_vbl_event *evt) -{ - if (!list_empty(&evt->node)) { - list_del_init(&evt->node); - drm_vblank_put(dcrtc->crtc.dev, dcrtc->num); - } -} - /* These are called under the vbl_lock. */ -static int armada_drm_enable_vblank(struct drm_device *dev, int crtc) +static int armada_drm_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct armada_private *priv = dev->dev_private; - armada_drm_crtc_enable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA); + armada_drm_crtc_enable_irq(priv->dcrtc[pipe], VSYNC_IRQ_ENA); return 0; } -static void armada_drm_disable_vblank(struct drm_device *dev, int crtc) +static void armada_drm_disable_vblank(struct drm_device *dev, unsigned int pipe) { struct armada_private *priv = dev->dev_private; - armada_drm_crtc_disable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA); + armada_drm_crtc_disable_irq(priv->dcrtc[pipe], VSYNC_IRQ_ENA); } static struct drm_ioctl_desc armada_ioctls[] = { - DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl, - DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl, - DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(ARMADA_GEM_PWRITE, armada_gem_pwrite_ioctl, - DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,0), + DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl, 0), + DRM_IOCTL_DEF_DRV(ARMADA_GEM_PWRITE, armada_gem_pwrite_ioctl, 0), }; static void armada_drm_lastclose(struct drm_device *dev) @@ -300,7 +192,7 @@ static struct drm_driver armada_drm_driver = { .lastclose = armada_drm_lastclose, .unload = armada_drm_unload, .set_busid = drm_platform_set_busid, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = armada_drm_enable_vblank, .disable_vblank = armada_drm_disable_vblank, #ifdef CONFIG_DEBUG_FS @@ -435,37 +327,28 @@ static const struct component_master_ops armada_master_ops = { static int armada_drm_probe(struct platform_device *pdev) { - if (is_componentized(&pdev->dev)) { - struct component_match *match = NULL; - int ret; - - ret = armada_drm_find_components(&pdev->dev, &match); - if (ret < 0) - return ret; - - return component_master_add_with_match(&pdev->dev, - &armada_master_ops, match); - } else { - return drm_platform_init(&armada_drm_driver, pdev); - } + struct component_match *match = NULL; + int ret; + + ret = armada_drm_find_components(&pdev->dev, &match); + if (ret < 0) + return ret; + + return component_master_add_with_match(&pdev->dev, &armada_master_ops, + match); } static int armada_drm_remove(struct platform_device *pdev) { - if (is_componentized(&pdev->dev)) - component_master_del(&pdev->dev, &armada_master_ops); - else - drm_put_dev(platform_get_drvdata(pdev)); + component_master_del(&pdev->dev, &armada_master_ops); return 0; } static const struct platform_device_id armada_drm_platform_ids[] = { { .name = "armada-drm", - .driver_data = (unsigned long)&armada510_ops, }, { .name = "armada-510-drm", - .driver_data = (unsigned long)&armada510_ops, }, { }, }; diff --git a/drivers/gpu/drm/armada/armada_output.c b/drivers/gpu/drm/armada/armada_output.c deleted file mode 100644 index 5a9823178291..000000000000 --- a/drivers/gpu/drm/armada/armada_output.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <drm/drmP.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_edid.h> -#include <drm/drm_encoder_slave.h> -#include "armada_output.h" -#include "armada_drm.h" - -struct armada_connector { - struct drm_connector conn; - const struct armada_output_type *type; -}; - -#define drm_to_armada_conn(c) container_of(c, struct armada_connector, conn) - -struct drm_encoder *armada_drm_connector_encoder(struct drm_connector *conn) -{ - struct drm_encoder *enc = conn->encoder; - - return enc ? enc : drm_encoder_find(conn->dev, conn->encoder_ids[0]); -} - -static enum drm_connector_status armada_drm_connector_detect( - struct drm_connector *conn, bool force) -{ - struct armada_connector *dconn = drm_to_armada_conn(conn); - enum drm_connector_status status = connector_status_disconnected; - - if (dconn->type->detect) { - status = dconn->type->detect(conn, force); - } else { - struct drm_encoder *enc = armada_drm_connector_encoder(conn); - - if (enc) - status = encoder_helper_funcs(enc)->detect(enc, conn); - } - - return status; -} - -static void armada_drm_connector_destroy(struct drm_connector *conn) -{ - struct armada_connector *dconn = drm_to_armada_conn(conn); - - drm_connector_unregister(conn); - drm_connector_cleanup(conn); - kfree(dconn); -} - -static int armada_drm_connector_set_property(struct drm_connector *conn, - struct drm_property *property, uint64_t value) -{ - struct armada_connector *dconn = drm_to_armada_conn(conn); - - if (!dconn->type->set_property) - return -EINVAL; - - return dconn->type->set_property(conn, property, value); -} - -static const struct drm_connector_funcs armada_drm_conn_funcs = { - .dpms = drm_helper_connector_dpms, - .fill_modes = drm_helper_probe_single_connector_modes, - .detect = armada_drm_connector_detect, - .destroy = armada_drm_connector_destroy, - .set_property = armada_drm_connector_set_property, -}; - -/* Shouldn't this be a generic helper function? */ -int armada_drm_slave_encoder_mode_valid(struct drm_connector *conn, - struct drm_display_mode *mode) -{ - struct drm_encoder *encoder = armada_drm_connector_encoder(conn); - int valid = MODE_BAD; - - if (encoder) { - struct drm_encoder_slave *slave = to_encoder_slave(encoder); - - valid = slave->slave_funcs->mode_valid(encoder, mode); - } - return valid; -} - -int armada_drm_slave_encoder_set_property(struct drm_connector *conn, - struct drm_property *property, uint64_t value) -{ - struct drm_encoder *encoder = armada_drm_connector_encoder(conn); - int rc = -EINVAL; - - if (encoder) { - struct drm_encoder_slave *slave = to_encoder_slave(encoder); - - rc = slave->slave_funcs->set_property(encoder, conn, property, - value); - } - return rc; -} - -int armada_output_create(struct drm_device *dev, - const struct armada_output_type *type, const void *data) -{ - struct armada_connector *dconn; - int ret; - - dconn = kzalloc(sizeof(*dconn), GFP_KERNEL); - if (!dconn) - return -ENOMEM; - - dconn->type = type; - - ret = drm_connector_init(dev, &dconn->conn, &armada_drm_conn_funcs, - type->connector_type); - if (ret) { - DRM_ERROR("unable to init connector\n"); - goto err_destroy_dconn; - } - - ret = type->create(&dconn->conn, data); - if (ret) - goto err_conn; - - ret = drm_connector_register(&dconn->conn); - if (ret) - goto err_sysfs; - - return 0; - - err_sysfs: - if (dconn->conn.encoder) - dconn->conn.encoder->funcs->destroy(dconn->conn.encoder); - err_conn: - drm_connector_cleanup(&dconn->conn); - err_destroy_dconn: - kfree(dconn); - return ret; -} diff --git a/drivers/gpu/drm/armada/armada_output.h b/drivers/gpu/drm/armada/armada_output.h deleted file mode 100644 index f448785753e8..000000000000 --- a/drivers/gpu/drm/armada/armada_output.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef ARMADA_CONNETOR_H -#define ARMADA_CONNETOR_H - -#define encoder_helper_funcs(encoder) \ - ((const struct drm_encoder_helper_funcs *)encoder->helper_private) - -struct armada_output_type { - int connector_type; - enum drm_connector_status (*detect)(struct drm_connector *, bool); - int (*create)(struct drm_connector *, const void *); - int (*set_property)(struct drm_connector *, struct drm_property *, - uint64_t); -}; - -struct drm_encoder *armada_drm_connector_encoder(struct drm_connector *conn); - -int armada_drm_slave_encoder_mode_valid(struct drm_connector *conn, - struct drm_display_mode *mode); - -int armada_drm_slave_encoder_set_property(struct drm_connector *conn, - struct drm_property *property, uint64_t value); - -int armada_output_create(struct drm_device *dev, - const struct armada_output_type *type, const void *data); - -#endif diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index e939faba7fcc..5c22b380f8f3 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -16,7 +16,7 @@ #include <drm/armada_drm.h> #include "armada_ioctlP.h" -struct armada_plane_properties { +struct armada_ovl_plane_properties { uint32_t colorkey_yr; uint32_t colorkey_ug; uint32_t colorkey_vb; @@ -29,26 +29,25 @@ struct armada_plane_properties { uint32_t colorkey_mode; }; -struct armada_plane { - struct drm_plane base; - spinlock_t lock; +struct armada_ovl_plane { + struct armada_plane base; struct drm_framebuffer *old_fb; uint32_t src_hw; uint32_t dst_hw; uint32_t dst_yx; uint32_t ctrl0; struct { - struct armada_vbl_event update; + struct armada_plane_work work; struct armada_regs regs[13]; - wait_queue_head_t wait; } vbl; - struct armada_plane_properties prop; + struct armada_ovl_plane_properties prop; }; -#define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) +#define drm_to_armada_ovl_plane(p) \ + container_of(p, struct armada_ovl_plane, base.base) static void -armada_ovl_update_attr(struct armada_plane_properties *prop, +armada_ovl_update_attr(struct armada_ovl_plane_properties *prop, struct armada_crtc *dcrtc) { writel_relaxed(prop->colorkey_yr, dcrtc->base + LCD_SPU_COLORKEY_Y); @@ -71,32 +70,34 @@ armada_ovl_update_attr(struct armada_plane_properties *prop, spin_unlock_irq(&dcrtc->irq_lock); } -/* === Plane support === */ -static void armada_plane_vbl(struct armada_crtc *dcrtc, void *data) +static void armada_ovl_retire_fb(struct armada_ovl_plane *dplane, + struct drm_framebuffer *fb) { - struct armada_plane *dplane = data; - struct drm_framebuffer *fb; + struct drm_framebuffer *old_fb; - armada_drm_crtc_update_regs(dcrtc, dplane->vbl.regs); + old_fb = xchg(&dplane->old_fb, fb); - spin_lock(&dplane->lock); - fb = dplane->old_fb; - dplane->old_fb = NULL; - spin_unlock(&dplane->lock); + if (old_fb) + armada_drm_queue_unref_work(dplane->base.base.dev, old_fb); +} - if (fb) - armada_drm_queue_unref_work(dcrtc->crtc.dev, fb); +/* === Plane support === */ +static void armada_ovl_plane_work(struct armada_crtc *dcrtc, + struct armada_plane *plane, struct armada_plane_work *work) +{ + struct armada_ovl_plane *dplane = container_of(plane, struct armada_ovl_plane, base); - wake_up(&dplane->vbl.wait); + armada_drm_crtc_update_regs(dcrtc, dplane->vbl.regs); + armada_ovl_retire_fb(dplane, NULL); } static int -armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, +armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { - struct armada_plane *dplane = drm_to_armada_plane(plane); + struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct drm_rect src = { .x1 = src_x, @@ -160,9 +161,8 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, dcrtc->base + LCD_SPU_SRAM_PARA1); } - wait_event_timeout(dplane->vbl.wait, - list_empty(&dplane->vbl.update.node), - HZ/25); + if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0) + armada_drm_plane_work_cancel(dcrtc, &dplane->base); if (plane->fb != fb) { struct armada_gem_object *obj = drm_fb_obj(fb); @@ -175,17 +175,8 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, */ drm_framebuffer_reference(fb); - if (plane->fb) { - struct drm_framebuffer *older_fb; - - spin_lock_irq(&dplane->lock); - older_fb = dplane->old_fb; - dplane->old_fb = plane->fb; - spin_unlock_irq(&dplane->lock); - if (older_fb) - armada_drm_queue_unref_work(dcrtc->crtc.dev, - older_fb); - } + if (plane->fb) + armada_ovl_retire_fb(dplane, plane->fb); src_y = src.y1 >> 16; src_x = src.x1 >> 16; @@ -262,60 +253,50 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, } if (idx) { armada_reg_queue_end(dplane->vbl.regs, idx); - armada_drm_vbl_event_add(dcrtc, &dplane->vbl.update); + armada_drm_plane_work_queue(dcrtc, &dplane->base, + &dplane->vbl.work); } return 0; } -static int armada_plane_disable(struct drm_plane *plane) +static int armada_ovl_plane_disable(struct drm_plane *plane) { - struct armada_plane *dplane = drm_to_armada_plane(plane); + struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); struct drm_framebuffer *fb; struct armada_crtc *dcrtc; - if (!dplane->base.crtc) + if (!dplane->base.base.crtc) return 0; - dcrtc = drm_to_armada_crtc(dplane->base.crtc); - dcrtc->plane = NULL; - - spin_lock_irq(&dcrtc->irq_lock); - armada_drm_vbl_event_remove(dcrtc, &dplane->vbl.update); - armada_updatel(0, CFG_DMA_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0); - dplane->ctrl0 = 0; - spin_unlock_irq(&dcrtc->irq_lock); + dcrtc = drm_to_armada_crtc(dplane->base.base.crtc); - /* Power down the Y/U/V FIFOs */ - armada_updatel(CFG_PDWN16x66 | CFG_PDWN32x66, 0, - dcrtc->base + LCD_SPU_SRAM_PARA1); + armada_drm_plane_work_cancel(dcrtc, &dplane->base); + armada_drm_crtc_plane_disable(dcrtc, plane); - if (plane->fb) - drm_framebuffer_unreference(plane->fb); + dcrtc->plane = NULL; + dplane->ctrl0 = 0; - spin_lock_irq(&dplane->lock); - fb = dplane->old_fb; - dplane->old_fb = NULL; - spin_unlock_irq(&dplane->lock); + fb = xchg(&dplane->old_fb, NULL); if (fb) drm_framebuffer_unreference(fb); return 0; } -static void armada_plane_destroy(struct drm_plane *plane) +static void armada_ovl_plane_destroy(struct drm_plane *plane) { - struct armada_plane *dplane = drm_to_armada_plane(plane); + struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); drm_plane_cleanup(plane); kfree(dplane); } -static int armada_plane_set_property(struct drm_plane *plane, +static int armada_ovl_plane_set_property(struct drm_plane *plane, struct drm_property *property, uint64_t val) { struct armada_private *priv = plane->dev->dev_private; - struct armada_plane *dplane = drm_to_armada_plane(plane); + struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); bool update_attr = false; if (property == priv->colorkey_prop) { @@ -372,21 +353,21 @@ static int armada_plane_set_property(struct drm_plane *plane, update_attr = true; } - if (update_attr && dplane->base.crtc) + if (update_attr && dplane->base.base.crtc) armada_ovl_update_attr(&dplane->prop, - drm_to_armada_crtc(dplane->base.crtc)); + drm_to_armada_crtc(dplane->base.base.crtc)); return 0; } -static const struct drm_plane_funcs armada_plane_funcs = { - .update_plane = armada_plane_update, - .disable_plane = armada_plane_disable, - .destroy = armada_plane_destroy, - .set_property = armada_plane_set_property, +static const struct drm_plane_funcs armada_ovl_plane_funcs = { + .update_plane = armada_ovl_plane_update, + .disable_plane = armada_ovl_plane_disable, + .destroy = armada_ovl_plane_destroy, + .set_property = armada_ovl_plane_set_property, }; -static const uint32_t armada_formats[] = { +static const uint32_t armada_ovl_formats[] = { DRM_FORMAT_UYVY, DRM_FORMAT_YUYV, DRM_FORMAT_YUV420, @@ -456,7 +437,7 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) { struct armada_private *priv = dev->dev_private; struct drm_mode_object *mobj; - struct armada_plane *dplane; + struct armada_ovl_plane *dplane; int ret; ret = armada_overlay_create_properties(dev); @@ -467,13 +448,23 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) if (!dplane) return -ENOMEM; - spin_lock_init(&dplane->lock); - init_waitqueue_head(&dplane->vbl.wait); - armada_drm_vbl_event_init(&dplane->vbl.update, armada_plane_vbl, - dplane); + ret = armada_drm_plane_init(&dplane->base); + if (ret) { + kfree(dplane); + return ret; + } + + dplane->vbl.work.fn = armada_ovl_plane_work; - drm_plane_init(dev, &dplane->base, crtcs, &armada_plane_funcs, - armada_formats, ARRAY_SIZE(armada_formats), false); + ret = drm_universal_plane_init(dev, &dplane->base.base, crtcs, + &armada_ovl_plane_funcs, + armada_ovl_formats, + ARRAY_SIZE(armada_ovl_formats), + DRM_PLANE_TYPE_OVERLAY); + if (ret) { + kfree(dplane); + return ret; + } dplane->prop.colorkey_yr = 0xfefefe00; dplane->prop.colorkey_ug = 0x01010100; @@ -483,7 +474,7 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) dplane->prop.contrast = 0x4000; dplane->prop.saturation = 0x4000; - mobj = &dplane->base.base; + mobj = &dplane->base.base.base; drm_object_attach_property(mobj, priv->colorkey_prop, 0x0101fe); drm_object_attach_property(mobj, priv->colorkey_min_prop, diff --git a/drivers/gpu/drm/armada/armada_slave.c b/drivers/gpu/drm/armada/armada_slave.c deleted file mode 100644 index 00d0facb42f3..000000000000 --- a/drivers/gpu/drm/armada/armada_slave.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2012 Russell King - * Rewritten from the dovefb driver, and Armada510 manuals. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <drm/drmP.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_edid.h> -#include <drm/drm_encoder_slave.h> -#include "armada_drm.h" -#include "armada_output.h" -#include "armada_slave.h" - -static int armada_drm_slave_get_modes(struct drm_connector *conn) -{ - struct drm_encoder *enc = armada_drm_connector_encoder(conn); - int count = 0; - - if (enc) { - struct drm_encoder_slave *slave = to_encoder_slave(enc); - - count = slave->slave_funcs->get_modes(enc, conn); - } - - return count; -} - -static void armada_drm_slave_destroy(struct drm_encoder *enc) -{ - struct drm_encoder_slave *slave = to_encoder_slave(enc); - struct i2c_client *client = drm_i2c_encoder_get_client(enc); - - if (slave->slave_funcs) - slave->slave_funcs->destroy(enc); - if (client) - i2c_put_adapter(client->adapter); - - drm_encoder_cleanup(&slave->base); - kfree(slave); -} - -static const struct drm_encoder_funcs armada_drm_slave_encoder_funcs = { - .destroy = armada_drm_slave_destroy, -}; - -static const struct drm_connector_helper_funcs armada_drm_slave_helper_funcs = { - .get_modes = armada_drm_slave_get_modes, - .mode_valid = armada_drm_slave_encoder_mode_valid, - .best_encoder = armada_drm_connector_encoder, -}; - -static const struct drm_encoder_helper_funcs drm_slave_encoder_helpers = { - .dpms = drm_i2c_encoder_dpms, - .save = drm_i2c_encoder_save, - .restore = drm_i2c_encoder_restore, - .mode_fixup = drm_i2c_encoder_mode_fixup, - .prepare = drm_i2c_encoder_prepare, - .commit = drm_i2c_encoder_commit, - .mode_set = drm_i2c_encoder_mode_set, - .detect = drm_i2c_encoder_detect, -}; - -static int -armada_drm_conn_slave_create(struct drm_connector *conn, const void *data) -{ - const struct armada_drm_slave_config *config = data; - struct drm_encoder_slave *slave; - struct i2c_adapter *adap; - int ret; - - conn->interlace_allowed = config->interlace_allowed; - conn->doublescan_allowed = config->doublescan_allowed; - conn->polled = config->polled; - - drm_connector_helper_add(conn, &armada_drm_slave_helper_funcs); - - slave = kzalloc(sizeof(*slave), GFP_KERNEL); - if (!slave) - return -ENOMEM; - - slave->base.possible_crtcs = config->crtcs; - - adap = i2c_get_adapter(config->i2c_adapter_id); - if (!adap) { - kfree(slave); - return -EPROBE_DEFER; - } - - ret = drm_encoder_init(conn->dev, &slave->base, - &armada_drm_slave_encoder_funcs, - DRM_MODE_ENCODER_TMDS); - if (ret) { - DRM_ERROR("unable to init encoder\n"); - i2c_put_adapter(adap); - kfree(slave); - return ret; - } - - ret = drm_i2c_encoder_init(conn->dev, slave, adap, &config->info); - i2c_put_adapter(adap); - if (ret) { - DRM_ERROR("unable to init encoder slave\n"); - armada_drm_slave_destroy(&slave->base); - return ret; - } - - drm_encoder_helper_add(&slave->base, &drm_slave_encoder_helpers); - - ret = slave->slave_funcs->create_resources(&slave->base, conn); - if (ret) { - armada_drm_slave_destroy(&slave->base); - return ret; - } - - ret = drm_mode_connector_attach_encoder(conn, &slave->base); - if (ret) { - armada_drm_slave_destroy(&slave->base); - return ret; - } - - conn->encoder = &slave->base; - - return ret; -} - -static const struct armada_output_type armada_drm_conn_slave = { - .connector_type = DRM_MODE_CONNECTOR_HDMIA, - .create = armada_drm_conn_slave_create, - .set_property = armada_drm_slave_encoder_set_property, -}; - -int armada_drm_connector_slave_create(struct drm_device *dev, - const struct armada_drm_slave_config *config) -{ - return armada_output_create(dev, &armada_drm_conn_slave, config); -} diff --git a/drivers/gpu/drm/armada/armada_slave.h b/drivers/gpu/drm/armada/armada_slave.h deleted file mode 100644 index bf2374c96fc1..000000000000 --- a/drivers/gpu/drm/armada/armada_slave.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef ARMADA_SLAVE_H -#define ARMADA_SLAVE_H - -#include <linux/i2c.h> -#include <drm/drmP.h> - -struct armada_drm_slave_config { - int i2c_adapter_id; - uint32_t crtcs; - uint8_t polled; - bool interlace_allowed; - bool doublescan_allowed; - struct i2c_board_info info; -}; - -int armada_drm_connector_slave_create(struct drm_device *dev, - const struct armada_drm_slave_config *); - -#endif diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 8bc62ec407f9..244df0a440b7 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -656,7 +656,8 @@ static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev) regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr); } -static int atmel_hlcdc_dc_enable_vblank(struct drm_device *dev, int crtc) +static int atmel_hlcdc_dc_enable_vblank(struct drm_device *dev, + unsigned int pipe) { struct atmel_hlcdc_dc *dc = dev->dev_private; @@ -666,7 +667,8 @@ static int atmel_hlcdc_dc_enable_vblank(struct drm_device *dev, int crtc) return 0; } -static void atmel_hlcdc_dc_disable_vblank(struct drm_device *dev, int crtc) +static void atmel_hlcdc_dc_disable_vblank(struct drm_device *dev, + unsigned int pipe) { struct atmel_hlcdc_dc *dc = dev->dev_private; @@ -697,7 +699,7 @@ static struct drm_driver atmel_hlcdc_dc_driver = { .irq_preinstall = atmel_hlcdc_dc_irq_uninstall, .irq_postinstall = atmel_hlcdc_dc_irq_postinstall, .irq_uninstall = atmel_hlcdc_dc_irq_uninstall, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = atmel_hlcdc_dc_enable_vblank, .disable_vblank = atmel_hlcdc_dc_disable_vblank, .gem_free_object = drm_gem_cma_free_object, diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 36fda86b3518..d0299aed517e 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -633,7 +633,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, if (!state->bpp[i]) return -EINVAL; - switch (state->base.rotation & 0xf) { + switch (state->base.rotation & DRM_ROTATE_MASK) { case BIT(DRM_ROTATE_90): offset = ((y_offset + state->src_y + patched_src_w - 1) / ydiv) * fb->pitches[i]; diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 2de52a53a803..6dddd392aa42 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -11,6 +11,18 @@ config DRM_DW_HDMI tristate select DRM_KMS_HELPER +config DRM_DW_HDMI_AHB_AUDIO + tristate "Synopsis Designware AHB Audio interface" + depends on DRM_DW_HDMI && SND + select SND_PCM + select SND_PCM_ELD + select SND_PCM_IEC958 + help + Support the AHB Audio interface which is part of the Synopsis + Designware HDMI block. This is used in conjunction with + the i.MX6 HDMI driver. + + config DRM_NXP_PTN3460 tristate "NXP PTN3460 DP/LVDS bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index e2eef1c2f4c3..d4e28beec30e 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -1,5 +1,6 @@ ccflags-y := -Iinclude/drm obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o +obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw_hdmi-ahb-audio.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o diff --git a/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c new file mode 100644 index 000000000000..59f630f1c61a --- /dev/null +++ b/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.c @@ -0,0 +1,653 @@ +/* + * DesignWare HDMI audio driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Written and tested against the Designware HDMI Tx found in iMX6. + */ +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <drm/bridge/dw_hdmi.h> +#include <drm/drm_edid.h> + +#include <sound/asoundef.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_drm_eld.h> +#include <sound/pcm_iec958.h> + +#include "dw_hdmi-audio.h" + +#define DRIVER_NAME "dw-hdmi-ahb-audio" + +/* Provide some bits rather than bit offsets */ +enum { + HDMI_AHB_DMA_CONF0_SW_FIFO_RST = BIT(7), + HDMI_AHB_DMA_CONF0_EN_HLOCK = BIT(3), + HDMI_AHB_DMA_START_START = BIT(0), + HDMI_AHB_DMA_STOP_STOP = BIT(0), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = BIT(5), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = BIT(4), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = BIT(3), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = BIT(2), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = BIT(1), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL = + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR | + HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST | + HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY | + HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE | + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL | + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY, + HDMI_IH_AHBDMAAUD_STAT0_ERROR = BIT(5), + HDMI_IH_AHBDMAAUD_STAT0_LOST = BIT(4), + HDMI_IH_AHBDMAAUD_STAT0_RETRY = BIT(3), + HDMI_IH_AHBDMAAUD_STAT0_DONE = BIT(2), + HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = BIT(1), + HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0), + HDMI_IH_AHBDMAAUD_STAT0_ALL = + HDMI_IH_AHBDMAAUD_STAT0_ERROR | + HDMI_IH_AHBDMAAUD_STAT0_LOST | + HDMI_IH_AHBDMAAUD_STAT0_RETRY | + HDMI_IH_AHBDMAAUD_STAT0_DONE | + HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL | + HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY, + HDMI_AHB_DMA_CONF0_INCR16 = 2 << 1, + HDMI_AHB_DMA_CONF0_INCR8 = 1 << 1, + HDMI_AHB_DMA_CONF0_INCR4 = 0, + HDMI_AHB_DMA_CONF0_BURST_MODE = BIT(0), + HDMI_AHB_DMA_MASK_DONE = BIT(7), + + HDMI_REVISION_ID = 0x0001, + HDMI_IH_AHBDMAAUD_STAT0 = 0x0109, + HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189, + HDMI_FC_AUDICONF2 = 0x1027, + HDMI_FC_AUDSCONF = 0x1063, + HDMI_FC_AUDSCONF_LAYOUT1 = 1 << 0, + HDMI_FC_AUDSCONF_LAYOUT0 = 0 << 0, + HDMI_AHB_DMA_CONF0 = 0x3600, + HDMI_AHB_DMA_START = 0x3601, + HDMI_AHB_DMA_STOP = 0x3602, + HDMI_AHB_DMA_THRSLD = 0x3603, + HDMI_AHB_DMA_STRADDR0 = 0x3604, + HDMI_AHB_DMA_STPADDR0 = 0x3608, + HDMI_AHB_DMA_MASK = 0x3614, + HDMI_AHB_DMA_POL = 0x3615, + HDMI_AHB_DMA_CONF1 = 0x3616, + HDMI_AHB_DMA_BUFFPOL = 0x361a, +}; + +struct dw_hdmi_channel_conf { + u8 conf1; + u8 ca; +}; + +/* + * The default mapping of ALSA channels to HDMI channels and speaker + * allocation bits. Note that we can't do channel remapping here - + * channels must be in the same order. + * + * Mappings for alsa-lib pcm/surround*.conf files: + * + * Front Sur4.0 Sur4.1 Sur5.0 Sur5.1 Sur7.1 + * Channels 2 4 6 6 6 8 + * + * Our mapping from ALSA channel to CEA686D speaker name and HDMI channel: + * + * Number of ALSA channels + * ALSA Channel 2 3 4 5 6 7 8 + * 0 FL:0 = = = = = = + * 1 FR:1 = = = = = = + * 2 FC:3 RL:4 LFE:2 = = = + * 3 RR:5 RL:4 FC:3 = = + * 4 RR:5 RL:4 = = + * 5 RR:5 = = + * 6 RC:6 = + * 7 RLC/FRC RLC/FRC + */ +static struct dw_hdmi_channel_conf default_hdmi_channel_config[7] = { + { 0x03, 0x00 }, /* FL,FR */ + { 0x0b, 0x02 }, /* FL,FR,FC */ + { 0x33, 0x08 }, /* FL,FR,RL,RR */ + { 0x37, 0x09 }, /* FL,FR,LFE,RL,RR */ + { 0x3f, 0x0b }, /* FL,FR,LFE,FC,RL,RR */ + { 0x7f, 0x0f }, /* FL,FR,LFE,FC,RL,RR,RC */ + { 0xff, 0x13 }, /* FL,FR,LFE,FC,RL,RR,[FR]RC,[FR]LC */ +}; + +struct snd_dw_hdmi { + struct snd_card *card; + struct snd_pcm *pcm; + spinlock_t lock; + struct dw_hdmi_audio_data data; + struct snd_pcm_substream *substream; + void (*reformat)(struct snd_dw_hdmi *, size_t, size_t); + void *buf_src; + void *buf_dst; + dma_addr_t buf_addr; + unsigned buf_offset; + unsigned buf_period; + unsigned buf_size; + unsigned channels; + u8 revision; + u8 iec_offset; + u8 cs[192][8]; +}; + +static void dw_hdmi_writel(u32 val, void __iomem *ptr) +{ + writeb_relaxed(val, ptr); + writeb_relaxed(val >> 8, ptr + 1); + writeb_relaxed(val >> 16, ptr + 2); + writeb_relaxed(val >> 24, ptr + 3); +} + +/* + * Convert to hardware format: The userspace buffer contains IEC958 samples, + * with the PCUV bits in bits 31..28 and audio samples in bits 27..4. We + * need these to be in bits 27..24, with the IEC B bit in bit 28, and audio + * samples in 23..0. + * + * Default preamble in bits 3..0: 8 = block start, 4 = even 2 = odd + * + * Ideally, we could do with having the data properly formatted in userspace. + */ +static void dw_hdmi_reformat_iec958(struct snd_dw_hdmi *dw, + size_t offset, size_t bytes) +{ + u32 *src = dw->buf_src + offset; + u32 *dst = dw->buf_dst + offset; + u32 *end = dw->buf_src + offset + bytes; + + do { + u32 b, sample = *src++; + + b = (sample & 8) << (28 - 3); + + sample >>= 4; + + *dst++ = sample | b; + } while (src < end); +} + +static u32 parity(u32 sample) +{ + sample ^= sample >> 16; + sample ^= sample >> 8; + sample ^= sample >> 4; + sample ^= sample >> 2; + sample ^= sample >> 1; + return (sample & 1) << 27; +} + +static void dw_hdmi_reformat_s24(struct snd_dw_hdmi *dw, + size_t offset, size_t bytes) +{ + u32 *src = dw->buf_src + offset; + u32 *dst = dw->buf_dst + offset; + u32 *end = dw->buf_src + offset + bytes; + + do { + unsigned i; + u8 *cs; + + cs = dw->cs[dw->iec_offset++]; + if (dw->iec_offset >= 192) + dw->iec_offset = 0; + + i = dw->channels; + do { + u32 sample = *src++; + + sample &= ~0xff000000; + sample |= *cs++ << 24; + sample |= parity(sample & ~0xf8000000); + + *dst++ = sample; + } while (--i); + } while (src < end); +} + +static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw, + struct snd_pcm_runtime *runtime) +{ + u8 cs[4]; + unsigned ch, i, j; + + snd_pcm_create_iec958_consumer(runtime, cs, sizeof(cs)); + + memset(dw->cs, 0, sizeof(dw->cs)); + + for (ch = 0; ch < 8; ch++) { + cs[2] &= ~IEC958_AES2_CON_CHANNEL; + cs[2] |= (ch + 1) << 4; + + for (i = 0; i < ARRAY_SIZE(cs); i++) { + unsigned c = cs[i]; + + for (j = 0; j < 8; j++, c >>= 1) + dw->cs[i * 8 + j][ch] = (c & 1) << 2; + } + } + dw->cs[0][0] |= BIT(4); +} + +static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw) +{ + void __iomem *base = dw->data.base; + unsigned offset = dw->buf_offset; + unsigned period = dw->buf_period; + u32 start, stop; + + dw->reformat(dw, offset, period); + + /* Clear all irqs before enabling irqs and starting DMA */ + writeb_relaxed(HDMI_IH_AHBDMAAUD_STAT0_ALL, + base + HDMI_IH_AHBDMAAUD_STAT0); + + start = dw->buf_addr + offset; + stop = start + period - 1; + + /* Setup the hardware start/stop addresses */ + dw_hdmi_writel(start, base + HDMI_AHB_DMA_STRADDR0); + dw_hdmi_writel(stop, base + HDMI_AHB_DMA_STPADDR0); + + writeb_relaxed((u8)~HDMI_AHB_DMA_MASK_DONE, base + HDMI_AHB_DMA_MASK); + writeb(HDMI_AHB_DMA_START_START, base + HDMI_AHB_DMA_START); + + offset += period; + if (offset >= dw->buf_size) + offset = 0; + dw->buf_offset = offset; +} + +static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw) +{ + /* Disable interrupts before disabling DMA */ + writeb_relaxed(~0, dw->data.base + HDMI_AHB_DMA_MASK); + writeb_relaxed(HDMI_AHB_DMA_STOP_STOP, dw->data.base + HDMI_AHB_DMA_STOP); +} + +static irqreturn_t snd_dw_hdmi_irq(int irq, void *data) +{ + struct snd_dw_hdmi *dw = data; + struct snd_pcm_substream *substream; + unsigned stat; + + stat = readb_relaxed(dw->data.base + HDMI_IH_AHBDMAAUD_STAT0); + if (!stat) + return IRQ_NONE; + + writeb_relaxed(stat, dw->data.base + HDMI_IH_AHBDMAAUD_STAT0); + + substream = dw->substream; + if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) { + snd_pcm_period_elapsed(substream); + + spin_lock(&dw->lock); + if (dw->substream) + dw_hdmi_start_dma(dw); + spin_unlock(&dw->lock); + } + + return IRQ_HANDLED; +} + +static struct snd_pcm_hardware dw_hdmi_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .channels_min = 2, + .channels_max = 8, + .buffer_bytes_max = 1024 * 1024, + .period_bytes_min = 256, + .period_bytes_max = 8192, /* ERR004323: must limit to 8k */ + .periods_min = 2, + .periods_max = 16, + .fifo_size = 0, +}; + +static int dw_hdmi_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dw_hdmi *dw = substream->private_data; + void __iomem *base = dw->data.base; + int ret; + + runtime->hw = dw_hdmi_hw; + + ret = snd_pcm_hw_constraint_eld(runtime, dw->data.eld); + if (ret < 0) + return ret; + + ret = snd_pcm_limit_hw_rates(runtime); + if (ret < 0) + return ret; + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + + /* Limit the buffer size to the size of the preallocated buffer */ + ret = snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + 0, substream->dma_buffer.bytes); + if (ret < 0) + return ret; + + /* Clear FIFO */ + writeb_relaxed(HDMI_AHB_DMA_CONF0_SW_FIFO_RST, + base + HDMI_AHB_DMA_CONF0); + + /* Configure interrupt polarities */ + writeb_relaxed(~0, base + HDMI_AHB_DMA_POL); + writeb_relaxed(~0, base + HDMI_AHB_DMA_BUFFPOL); + + /* Keep interrupts masked, and clear any pending */ + writeb_relaxed(~0, base + HDMI_AHB_DMA_MASK); + writeb_relaxed(~0, base + HDMI_IH_AHBDMAAUD_STAT0); + + ret = request_irq(dw->data.irq, snd_dw_hdmi_irq, IRQF_SHARED, + "dw-hdmi-audio", dw); + if (ret) + return ret; + + /* Un-mute done interrupt */ + writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL & + ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE, + base + HDMI_IH_MUTE_AHBDMAAUD_STAT0); + + return 0; +} + +static int dw_hdmi_close(struct snd_pcm_substream *substream) +{ + struct snd_dw_hdmi *dw = substream->private_data; + + /* Mute all interrupts */ + writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL, + dw->data.base + HDMI_IH_MUTE_AHBDMAAUD_STAT0); + + free_irq(dw->data.irq, dw); + + return 0; +} + +static int dw_hdmi_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +static int dw_hdmi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + /* Allocate the PCM runtime buffer, which is exposed to userspace. */ + return snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(params)); +} + +static int dw_hdmi_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dw_hdmi *dw = substream->private_data; + u8 threshold, conf0, conf1, layout, ca; + + /* Setup as per 3.0.5 FSL 4.1.0 BSP */ + switch (dw->revision) { + case 0x0a: + conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE | + HDMI_AHB_DMA_CONF0_INCR4; + if (runtime->channels == 2) + threshold = 126; + else + threshold = 124; + break; + case 0x1a: + conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE | + HDMI_AHB_DMA_CONF0_INCR8; + threshold = 128; + break; + default: + /* NOTREACHED */ + return -EINVAL; + } + + dw_hdmi_set_sample_rate(dw->data.hdmi, runtime->rate); + + /* Minimum number of bytes in the fifo. */ + runtime->hw.fifo_size = threshold * 32; + + conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK; + conf1 = default_hdmi_channel_config[runtime->channels - 2].conf1; + ca = default_hdmi_channel_config[runtime->channels - 2].ca; + + /* + * For >2 channel PCM audio, we need to select layout 1 + * and set an appropriate channel map. + */ + if (runtime->channels > 2) + layout = HDMI_FC_AUDSCONF_LAYOUT1; + else + layout = HDMI_FC_AUDSCONF_LAYOUT0; + + writeb_relaxed(threshold, dw->data.base + HDMI_AHB_DMA_THRSLD); + writeb_relaxed(conf0, dw->data.base + HDMI_AHB_DMA_CONF0); + writeb_relaxed(conf1, dw->data.base + HDMI_AHB_DMA_CONF1); + writeb_relaxed(layout, dw->data.base + HDMI_FC_AUDSCONF); + writeb_relaxed(ca, dw->data.base + HDMI_FC_AUDICONF2); + + switch (runtime->format) { + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + dw->reformat = dw_hdmi_reformat_iec958; + break; + case SNDRV_PCM_FORMAT_S24_LE: + dw_hdmi_create_cs(dw, runtime); + dw->reformat = dw_hdmi_reformat_s24; + break; + } + dw->iec_offset = 0; + dw->channels = runtime->channels; + dw->buf_src = runtime->dma_area; + dw->buf_dst = substream->dma_buffer.area; + dw->buf_addr = substream->dma_buffer.addr; + dw->buf_period = snd_pcm_lib_period_bytes(substream); + dw->buf_size = snd_pcm_lib_buffer_bytes(substream); + + return 0; +} + +static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_dw_hdmi *dw = substream->private_data; + unsigned long flags; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + spin_lock_irqsave(&dw->lock, flags); + dw->buf_offset = 0; + dw->substream = substream; + dw_hdmi_start_dma(dw); + dw_hdmi_audio_enable(dw->data.hdmi); + spin_unlock_irqrestore(&dw->lock, flags); + substream->runtime->delay = substream->runtime->period_size; + break; + + case SNDRV_PCM_TRIGGER_STOP: + spin_lock_irqsave(&dw->lock, flags); + dw->substream = NULL; + dw_hdmi_stop_dma(dw); + dw_hdmi_audio_disable(dw->data.hdmi); + spin_unlock_irqrestore(&dw->lock, flags); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static snd_pcm_uframes_t dw_hdmi_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dw_hdmi *dw = substream->private_data; + + /* + * We are unable to report the exact hardware position as + * reading the 32-bit DMA position using 8-bit reads is racy. + */ + return bytes_to_frames(runtime, dw->buf_offset); +} + +static struct snd_pcm_ops snd_dw_hdmi_ops = { + .open = dw_hdmi_open, + .close = dw_hdmi_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = dw_hdmi_hw_params, + .hw_free = dw_hdmi_hw_free, + .prepare = dw_hdmi_prepare, + .trigger = dw_hdmi_trigger, + .pointer = dw_hdmi_pointer, + .page = snd_pcm_lib_get_vmalloc_page, +}; + +static int snd_dw_hdmi_probe(struct platform_device *pdev) +{ + const struct dw_hdmi_audio_data *data = pdev->dev.platform_data; + struct device *dev = pdev->dev.parent; + struct snd_dw_hdmi *dw; + struct snd_card *card; + struct snd_pcm *pcm; + unsigned revision; + int ret; + + writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL, + data->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0); + revision = readb_relaxed(data->base + HDMI_REVISION_ID); + if (revision != 0x0a && revision != 0x1a) { + dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n", + revision); + return -ENXIO; + } + + ret = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, sizeof(struct snd_dw_hdmi), &card); + if (ret < 0) + return ret; + + strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver)); + strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "%s rev 0x%02x, irq %d", card->shortname, revision, + data->irq); + + dw = card->private_data; + dw->card = card; + dw->data = *data; + dw->revision = revision; + + spin_lock_init(&dw->lock); + + ret = snd_pcm_new(card, "DW HDMI", 0, 1, 0, &pcm); + if (ret < 0) + goto err; + + dw->pcm = pcm; + pcm->private_data = dw; + strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops); + + /* + * To support 8-channel 96kHz audio reliably, we need 512k + * to satisfy alsa with our restricted period (ERR004323). + */ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + dev, 128 * 1024, 1024 * 1024); + + ret = snd_card_register(card); + if (ret < 0) + goto err; + + platform_set_drvdata(pdev, dw); + + return 0; + +err: + snd_card_free(card); + return ret; +} + +static int snd_dw_hdmi_remove(struct platform_device *pdev) +{ + struct snd_dw_hdmi *dw = platform_get_drvdata(pdev); + + snd_card_free(dw->card); + + return 0; +} + +#if defined(CONFIG_PM_SLEEP) && defined(IS_NOT_BROKEN) +/* + * This code is fine, but requires implementation in the dw_hdmi_trigger() + * method which is currently missing as I have no way to test this. + */ +static int snd_dw_hdmi_suspend(struct device *dev) +{ + struct snd_dw_hdmi *dw = dev_get_drvdata(dev); + + snd_power_change_state(dw->card, SNDRV_CTL_POWER_D3cold); + snd_pcm_suspend_all(dw->pcm); + + return 0; +} + +static int snd_dw_hdmi_resume(struct device *dev) +{ + struct snd_dw_hdmi *dw = dev_get_drvdata(dev); + + snd_power_change_state(dw->card, SNDRV_CTL_POWER_D0); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(snd_dw_hdmi_pm, snd_dw_hdmi_suspend, + snd_dw_hdmi_resume); +#define PM_OPS &snd_dw_hdmi_pm +#else +#define PM_OPS NULL +#endif + +static struct platform_driver snd_dw_hdmi_driver = { + .probe = snd_dw_hdmi_probe, + .remove = snd_dw_hdmi_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .pm = PM_OPS, + }, +}; + +module_platform_driver(snd_dw_hdmi_driver); + +MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); +MODULE_DESCRIPTION("Synopsis Designware HDMI AHB ALSA interface"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/gpu/drm/bridge/dw_hdmi-audio.h b/drivers/gpu/drm/bridge/dw_hdmi-audio.h new file mode 100644 index 000000000000..91f631beecc7 --- /dev/null +++ b/drivers/gpu/drm/bridge/dw_hdmi-audio.h @@ -0,0 +1,14 @@ +#ifndef DW_HDMI_AUDIO_H +#define DW_HDMI_AUDIO_H + +struct dw_hdmi; + +struct dw_hdmi_audio_data { + phys_addr_t phys; + void __iomem *base; + int irq; + struct dw_hdmi *hdmi; + u8 *eld; +}; + +#endif diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index 0083d4e7e7e2..56de9f1c95fc 100644 --- a/drivers/gpu/drm/bridge/dw_hdmi.c +++ b/drivers/gpu/drm/bridge/dw_hdmi.c @@ -28,6 +28,7 @@ #include <drm/bridge/dw_hdmi.h> #include "dw_hdmi.h" +#include "dw_hdmi-audio.h" #define HDMI_EDID_LEN 512 @@ -104,6 +105,7 @@ struct dw_hdmi { struct drm_encoder *encoder; struct drm_bridge *bridge; + struct platform_device *audio; enum dw_hdmi_devtype dev_type; struct device *dev; struct clk *isfr_clk; @@ -126,7 +128,11 @@ struct dw_hdmi { bool sink_has_audio; struct mutex mutex; /* for state below and previous_mode */ + enum drm_connector_force force; /* mutex-protected force state */ bool disabled; /* DRM has disabled our bridge */ + bool bridge_is_on; /* indicates the bridge is on */ + bool rxsense; /* rxsense state */ + u8 phy_mask; /* desired phy int mask settings */ spinlock_t audio_lock; struct mutex audio_mutex; @@ -134,12 +140,19 @@ struct dw_hdmi { unsigned int audio_cts; unsigned int audio_n; bool audio_enable; - int ratio; void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); u8 (*read)(struct dw_hdmi *hdmi, int offset); }; +#define HDMI_IH_PHY_STAT0_RX_SENSE \ + (HDMI_IH_PHY_STAT0_RX_SENSE0 | HDMI_IH_PHY_STAT0_RX_SENSE1 | \ + HDMI_IH_PHY_STAT0_RX_SENSE2 | HDMI_IH_PHY_STAT0_RX_SENSE3) + +#define HDMI_PHY_RX_SENSE \ + (HDMI_PHY_RX_SENSE0 | HDMI_PHY_RX_SENSE1 | \ + HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3) + static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset) { writel(val, hdmi->regs + (offset << 2)); @@ -203,61 +216,53 @@ static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts, hdmi_writeb(hdmi, n & 0xff, HDMI_AUD_N1); } -static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk, - unsigned int ratio) +static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk) { unsigned int n = (128 * freq) / 1000; + unsigned int mult = 1; + + while (freq > 48000) { + mult *= 2; + freq /= 2; + } switch (freq) { case 32000: - if (pixel_clk == 25170000) - n = (ratio == 150) ? 9152 : 4576; - else if (pixel_clk == 27020000) - n = (ratio == 150) ? 8192 : 4096; - else if (pixel_clk == 74170000 || pixel_clk == 148350000) + if (pixel_clk == 25175000) + n = 4576; + else if (pixel_clk == 27027000) + n = 4096; + else if (pixel_clk == 74176000 || pixel_clk == 148352000) n = 11648; else n = 4096; + n *= mult; break; case 44100: - if (pixel_clk == 25170000) + if (pixel_clk == 25175000) n = 7007; - else if (pixel_clk == 74170000) + else if (pixel_clk == 74176000) n = 17836; - else if (pixel_clk == 148350000) - n = (ratio == 150) ? 17836 : 8918; + else if (pixel_clk == 148352000) + n = 8918; else n = 6272; + n *= mult; break; case 48000: - if (pixel_clk == 25170000) - n = (ratio == 150) ? 9152 : 6864; - else if (pixel_clk == 27020000) - n = (ratio == 150) ? 8192 : 6144; - else if (pixel_clk == 74170000) + if (pixel_clk == 25175000) + n = 6864; + else if (pixel_clk == 27027000) + n = 6144; + else if (pixel_clk == 74176000) n = 11648; - else if (pixel_clk == 148350000) - n = (ratio == 150) ? 11648 : 5824; + else if (pixel_clk == 148352000) + n = 5824; else n = 6144; - break; - - case 88200: - n = hdmi_compute_n(44100, pixel_clk, ratio) * 2; - break; - - case 96000: - n = hdmi_compute_n(48000, pixel_clk, ratio) * 2; - break; - - case 176400: - n = hdmi_compute_n(44100, pixel_clk, ratio) * 4; - break; - - case 192000: - n = hdmi_compute_n(48000, pixel_clk, ratio) * 4; + n *= mult; break; default: @@ -267,93 +272,29 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk, return n; } -static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk, - unsigned int ratio) -{ - unsigned int cts = 0; - - pr_debug("%s: freq: %d pixel_clk: %ld ratio: %d\n", __func__, freq, - pixel_clk, ratio); - - switch (freq) { - case 32000: - if (pixel_clk == 297000000) { - cts = 222750; - break; - } - case 48000: - case 96000: - case 192000: - switch (pixel_clk) { - case 25200000: - case 27000000: - case 54000000: - case 74250000: - case 148500000: - cts = pixel_clk / 1000; - break; - case 297000000: - cts = 247500; - break; - /* - * All other TMDS clocks are not supported by - * DWC_hdmi_tx. The TMDS clocks divided or - * multiplied by 1,001 coefficients are not - * supported. - */ - default: - break; - } - break; - case 44100: - case 88200: - case 176400: - switch (pixel_clk) { - case 25200000: - cts = 28000; - break; - case 27000000: - cts = 30000; - break; - case 54000000: - cts = 60000; - break; - case 74250000: - cts = 82500; - break; - case 148500000: - cts = 165000; - break; - case 297000000: - cts = 247500; - break; - default: - break; - } - break; - default: - break; - } - if (ratio == 100) - return cts; - return (cts * ratio) / 100; -} - static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi, - unsigned long pixel_clk, unsigned int sample_rate, unsigned int ratio) + unsigned long pixel_clk, unsigned int sample_rate) { + unsigned long ftdms = pixel_clk; unsigned int n, cts; + u64 tmp; - n = hdmi_compute_n(sample_rate, pixel_clk, ratio); - cts = hdmi_compute_cts(sample_rate, pixel_clk, ratio); - if (!cts) { - dev_err(hdmi->dev, - "%s: pixel clock/sample rate not supported: %luMHz / %ukHz\n", - __func__, pixel_clk, sample_rate); - } + n = hdmi_compute_n(sample_rate, pixel_clk); + + /* + * Compute the CTS value from the N value. Note that CTS and N + * can be up to 20 bits in total, so we need 64-bit math. Also + * note that our TDMS clock is not fully accurate; it is accurate + * to kHz. This can introduce an unnecessary remainder in the + * calculation below, so we don't try to warn about that. + */ + tmp = (u64)ftdms * n; + do_div(tmp, 128 * sample_rate); + cts = tmp; - dev_dbg(hdmi->dev, "%s: samplerate=%ukHz ratio=%d pixelclk=%luMHz N=%d cts=%d\n", - __func__, sample_rate, ratio, pixel_clk, n, cts); + dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n", + __func__, sample_rate, ftdms / 1000000, (ftdms / 1000) % 1000, + n, cts); spin_lock_irq(&hdmi->audio_lock); hdmi->audio_n = n; @@ -365,8 +306,7 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi, static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi) { mutex_lock(&hdmi->audio_mutex); - hdmi_set_clk_regenerator(hdmi, 74250000, hdmi->sample_rate, - hdmi->ratio); + hdmi_set_clk_regenerator(hdmi, 74250000, hdmi->sample_rate); mutex_unlock(&hdmi->audio_mutex); } @@ -374,7 +314,7 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi) { mutex_lock(&hdmi->audio_mutex); hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock, - hdmi->sample_rate, hdmi->ratio); + hdmi->sample_rate); mutex_unlock(&hdmi->audio_mutex); } @@ -383,7 +323,7 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate) mutex_lock(&hdmi->audio_mutex); hdmi->sample_rate = rate; hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock, - hdmi->sample_rate, hdmi->ratio); + hdmi->sample_rate); mutex_unlock(&hdmi->audio_mutex); } EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_rate); @@ -1063,6 +1003,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, u8 inv_val; struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode; int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; + unsigned int vdisplay; vmode->mpixelclock = mode->clock * 1000; @@ -1102,13 +1043,29 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF); + vdisplay = mode->vdisplay; + vblank = mode->vtotal - mode->vdisplay; + v_de_vs = mode->vsync_start - mode->vdisplay; + vsync_len = mode->vsync_end - mode->vsync_start; + + /* + * When we're setting an interlaced mode, we need + * to adjust the vertical timing to suit. + */ + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { + vdisplay /= 2; + vblank /= 2; + v_de_vs /= 2; + vsync_len /= 2; + } + /* Set up horizontal active pixel width */ hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1); hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0); /* Set up vertical active lines */ - hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1); - hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0); + hdmi_writeb(hdmi, vdisplay >> 8, HDMI_FC_INVACTV1); + hdmi_writeb(hdmi, vdisplay, HDMI_FC_INVACTV0); /* Set up horizontal blanking pixel region width */ hblank = mode->htotal - mode->hdisplay; @@ -1116,7 +1073,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0); /* Set up vertical blanking pixel region width */ - vblank = mode->vtotal - mode->vdisplay; hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK); /* Set up HSYNC active edge delay width (in pixel clks) */ @@ -1125,7 +1081,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0); /* Set up VSYNC active edge delay (in lines) */ - v_de_vs = mode->vsync_start - mode->vdisplay; hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY); /* Set up HSYNC active pulse width (in pixel clks) */ @@ -1134,7 +1089,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0); /* Set up VSYNC active edge delay (in lines) */ - vsync_len = mode->vsync_end - mode->vsync_start; hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH); } @@ -1302,10 +1256,11 @@ static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi) HDMI_PHY_I2CM_CTLINT_ADDR); /* enable cable hot plug irq */ - hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0); + hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); /* Clear Hotplug interrupts */ - hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, + HDMI_IH_PHY_STAT0); return 0; } @@ -1364,12 +1319,61 @@ static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi) static void dw_hdmi_poweron(struct dw_hdmi *hdmi) { + hdmi->bridge_is_on = true; dw_hdmi_setup(hdmi, &hdmi->previous_mode); } static void dw_hdmi_poweroff(struct dw_hdmi *hdmi) { dw_hdmi_phy_disable(hdmi); + hdmi->bridge_is_on = false; +} + +static void dw_hdmi_update_power(struct dw_hdmi *hdmi) +{ + int force = hdmi->force; + + if (hdmi->disabled) { + force = DRM_FORCE_OFF; + } else if (force == DRM_FORCE_UNSPECIFIED) { + if (hdmi->rxsense) + force = DRM_FORCE_ON; + else + force = DRM_FORCE_OFF; + } + + if (force == DRM_FORCE_OFF) { + if (hdmi->bridge_is_on) + dw_hdmi_poweroff(hdmi); + } else { + if (!hdmi->bridge_is_on) + dw_hdmi_poweron(hdmi); + } +} + +/* + * Adjust the detection of RXSENSE according to whether we have a forced + * connection mode enabled, or whether we have been disabled. There is + * no point processing RXSENSE interrupts if we have a forced connection + * state, or DRM has us disabled. + * + * We also disable rxsense interrupts when we think we're disconnected + * to avoid floating TDMS signals giving false rxsense interrupts. + * + * Note: we still need to listen for HPD interrupts even when DRM has us + * disabled so that we can detect a connect event. + */ +static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) +{ + u8 old_mask = hdmi->phy_mask; + + if (hdmi->force || hdmi->disabled || !hdmi->rxsense) + hdmi->phy_mask |= HDMI_PHY_RX_SENSE; + else + hdmi->phy_mask &= ~HDMI_PHY_RX_SENSE; + + if (old_mask != hdmi->phy_mask) + hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); } static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, @@ -1399,7 +1403,8 @@ static void dw_hdmi_bridge_disable(struct drm_bridge *bridge) mutex_lock(&hdmi->mutex); hdmi->disabled = true; - dw_hdmi_poweroff(hdmi); + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); mutex_unlock(&hdmi->mutex); } @@ -1408,8 +1413,9 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge) struct dw_hdmi *hdmi = bridge->driver_private; mutex_lock(&hdmi->mutex); - dw_hdmi_poweron(hdmi); hdmi->disabled = false; + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); mutex_unlock(&hdmi->mutex); } @@ -1424,6 +1430,12 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, connector); + mutex_lock(&hdmi->mutex); + hdmi->force = DRM_FORCE_UNSPECIFIED; + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); + mutex_unlock(&hdmi->mutex); + return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ? connector_status_connected : connector_status_disconnected; } @@ -1447,6 +1459,8 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) hdmi->sink_has_audio = drm_detect_monitor_audio(edid); drm_mode_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); + /* Store the ELD */ + drm_edid_to_eld(connector, edid); kfree(edid); } else { dev_dbg(hdmi->dev, "failed to get edid\n"); @@ -1488,11 +1502,24 @@ static void dw_hdmi_connector_destroy(struct drm_connector *connector) drm_connector_cleanup(connector); } +static void dw_hdmi_connector_force(struct drm_connector *connector) +{ + struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, + connector); + + mutex_lock(&hdmi->mutex); + hdmi->force = connector->force; + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); + mutex_unlock(&hdmi->mutex); +} + static struct drm_connector_funcs dw_hdmi_connector_funcs = { .dpms = drm_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = dw_hdmi_connector_detect, .destroy = dw_hdmi_connector_destroy, + .force = dw_hdmi_connector_force, }; static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = { @@ -1525,33 +1552,69 @@ static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id) static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) { struct dw_hdmi *hdmi = dev_id; - u8 intr_stat; - u8 phy_int_pol; + u8 intr_stat, phy_int_pol, phy_pol_mask, phy_stat; intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0); - phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0); + phy_stat = hdmi_readb(hdmi, HDMI_PHY_STAT0); + + phy_pol_mask = 0; + if (intr_stat & HDMI_IH_PHY_STAT0_HPD) + phy_pol_mask |= HDMI_PHY_HPD; + if (intr_stat & HDMI_IH_PHY_STAT0_RX_SENSE0) + phy_pol_mask |= HDMI_PHY_RX_SENSE0; + if (intr_stat & HDMI_IH_PHY_STAT0_RX_SENSE1) + phy_pol_mask |= HDMI_PHY_RX_SENSE1; + if (intr_stat & HDMI_IH_PHY_STAT0_RX_SENSE2) + phy_pol_mask |= HDMI_PHY_RX_SENSE2; + if (intr_stat & HDMI_IH_PHY_STAT0_RX_SENSE3) + phy_pol_mask |= HDMI_PHY_RX_SENSE3; + + if (phy_pol_mask) + hdmi_modb(hdmi, ~phy_int_pol, phy_pol_mask, HDMI_PHY_POL0); - if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { - hdmi_modb(hdmi, ~phy_int_pol, HDMI_PHY_HPD, HDMI_PHY_POL0); + /* + * RX sense tells us whether the TDMS transmitters are detecting + * load - in other words, there's something listening on the + * other end of the link. Use this to decide whether we should + * power on the phy as HPD may be toggled by the sink to merely + * ask the source to re-read the EDID. + */ + if (intr_stat & + (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) { mutex_lock(&hdmi->mutex); - if (phy_int_pol & HDMI_PHY_HPD) { - dev_dbg(hdmi->dev, "EVENT=plugin\n"); - - if (!hdmi->disabled) - dw_hdmi_poweron(hdmi); - } else { - dev_dbg(hdmi->dev, "EVENT=plugout\n"); - - if (!hdmi->disabled) - dw_hdmi_poweroff(hdmi); + if (!hdmi->disabled && !hdmi->force) { + /* + * If the RX sense status indicates we're disconnected, + * clear the software rxsense status. + */ + if (!(phy_stat & HDMI_PHY_RX_SENSE)) + hdmi->rxsense = false; + + /* + * Only set the software rxsense status when both + * rxsense and hpd indicates we're connected. + * This avoids what seems to be bad behaviour in + * at least iMX6S versions of the phy. + */ + if (phy_stat & HDMI_PHY_HPD) + hdmi->rxsense = true; + + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); } mutex_unlock(&hdmi->mutex); + } + + if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { + dev_dbg(hdmi->dev, "EVENT=%s\n", + phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout"); drm_helper_hpd_irq_event(hdmi->bridge->dev); } hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); - hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); + hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), + HDMI_IH_MUTE_PHY_STAT0); return IRQ_HANDLED; } @@ -1599,7 +1662,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master, { struct drm_device *drm = data; struct device_node *np = dev->of_node; + struct platform_device_info pdevinfo; struct device_node *ddc_node; + struct dw_hdmi_audio_data audio; struct dw_hdmi *hdmi; int ret; u32 val = 1; @@ -1608,13 +1673,16 @@ int dw_hdmi_bind(struct device *dev, struct device *master, if (!hdmi) return -ENOMEM; + hdmi->connector.interlace_allowed = 1; + hdmi->plat_data = plat_data; hdmi->dev = dev; hdmi->dev_type = plat_data->dev_type; hdmi->sample_rate = 48000; - hdmi->ratio = 100; hdmi->encoder = encoder; hdmi->disabled = true; + hdmi->rxsense = true; + hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE); mutex_init(&hdmi->mutex); mutex_init(&hdmi->audio_mutex); @@ -1705,10 +1773,11 @@ int dw_hdmi_bind(struct device *dev, struct device *master, * Configure registers related to HDMI interrupt * generation before registering IRQ. */ - hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0); + hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0); /* Clear Hotplug interrupts */ - hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, + HDMI_IH_PHY_STAT0); ret = dw_hdmi_fb_registered(hdmi); if (ret) @@ -1719,7 +1788,26 @@ int dw_hdmi_bind(struct device *dev, struct device *master, goto err_iahb; /* Unmute interrupts */ - hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); + hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), + HDMI_IH_MUTE_PHY_STAT0); + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo.parent = dev; + pdevinfo.id = PLATFORM_DEVID_AUTO; + + if (hdmi_readb(hdmi, HDMI_CONFIG1_ID) & HDMI_CONFIG1_AHB) { + audio.phys = iores->start; + audio.base = hdmi->regs; + audio.irq = irq; + audio.hdmi = hdmi; + audio.eld = hdmi->connector.eld; + + pdevinfo.name = "dw-hdmi-ahb-audio"; + pdevinfo.data = &audio; + pdevinfo.size_data = sizeof(audio); + pdevinfo.dma_mask = DMA_BIT_MASK(32); + hdmi->audio = platform_device_register_full(&pdevinfo); + } dev_set_drvdata(dev, hdmi); @@ -1738,6 +1826,9 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data) { struct dw_hdmi *hdmi = dev_get_drvdata(dev); + if (hdmi->audio && !IS_ERR(hdmi->audio)) + platform_device_unregister(hdmi->audio); + /* Disable all interrupts */ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h index ee7f7ed2ab12..fc9a560429d6 100644 --- a/drivers/gpu/drm/bridge/dw_hdmi.h +++ b/drivers/gpu/drm/bridge/dw_hdmi.h @@ -545,6 +545,9 @@ #define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12 enum { +/* CONFIG1_ID field values */ + HDMI_CONFIG1_AHB = 0x01, + /* IH_FC_INT2 field values */ HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03, HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02, diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c index 4b2b4aa5033b..a10ea6aec629 100644 --- a/drivers/gpu/drm/drm_agpsupport.c +++ b/drivers/gpu/drm/drm_agpsupport.c @@ -36,8 +36,6 @@ #include <linux/slab.h> #include "drm_legacy.h" -#if __OS_HAS_AGP - #include <asm/agp.h> /** @@ -502,5 +500,3 @@ drm_agp_bind_pages(struct drm_device *dev, return mem; } EXPORT_SYMBOL(drm_agp_bind_pages); - -#endif /* __OS_HAS_AGP */ diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 87a2a446d2b7..0c6f62168776 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1790,8 +1790,13 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, primary_state->crtc_w = set->mode->hdisplay; primary_state->src_x = set->x << 16; primary_state->src_y = set->y << 16; - primary_state->src_h = set->mode->vdisplay << 16; - primary_state->src_w = set->mode->hdisplay << 16; + if (primary_state->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) { + primary_state->src_h = set->mode->hdisplay << 16; + primary_state->src_w = set->mode->vdisplay << 16; + } else { + primary_state->src_h = set->mode->vdisplay << 16; + primary_state->src_w = set->mode->hdisplay << 16; + } commit: ret = update_output_state(state, set); diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 569064a00693..f1a204d253cc 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -582,7 +582,7 @@ static void drm_cleanup_buf_error(struct drm_device * dev, } } -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) /** * Add AGP buffers for DMA transfers. * @@ -756,7 +756,7 @@ int drm_legacy_addbufs_agp(struct drm_device *dev, return 0; } EXPORT_SYMBOL(drm_legacy_addbufs_agp); -#endif /* __OS_HAS_AGP */ +#endif /* CONFIG_AGP */ int drm_legacy_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) @@ -1145,7 +1145,7 @@ int drm_legacy_addbufs(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) return -EINVAL; -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (request->flags & _DRM_AGP_BUFFER) ret = drm_legacy_addbufs_agp(dev, request); else diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e600a5fb2b60..e54660a858e1 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -306,8 +306,7 @@ static int drm_mode_object_get_reg(struct drm_device *dev, * reference counted modeset objects like framebuffers. * * Returns: - * New unique (relative to other objects in @dev) integer identifier for the - * object. + * Zero on success, error code on failure. */ int drm_mode_object_get(struct drm_device *dev, struct drm_mode_object *obj, uint32_t obj_type) @@ -423,7 +422,7 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, out: mutex_unlock(&dev->mode_config.fb_lock); - return 0; + return ret; } EXPORT_SYMBOL(drm_framebuffer_init); @@ -677,7 +676,6 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, crtc->dev = dev; crtc->funcs = funcs; - crtc->invert_dimensions = false; drm_modeset_lock_init(&crtc->mutex); ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); @@ -2286,6 +2284,32 @@ int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) return -EINVAL; } +static int check_src_coords(uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h, + const struct drm_framebuffer *fb) +{ + unsigned int fb_width, fb_height; + + fb_width = fb->width << 16; + fb_height = fb->height << 16; + + /* Make sure source coordinates are inside the fb. */ + if (src_w > fb_width || + src_x > fb_width - src_w || + src_h > fb_height || + src_y > fb_height - src_h) { + DRM_DEBUG_KMS("Invalid source coordinates " + "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", + src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, + src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, + src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, + src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); + return -ENOSPC; + } + + return 0; +} + /* * setplane_internal - setplane handler for internal callers * @@ -2305,7 +2329,6 @@ static int __setplane_internal(struct drm_plane *plane, uint32_t src_w, uint32_t src_h) { int ret = 0; - unsigned int fb_width, fb_height; /* No fb means shut it down */ if (!fb) { @@ -2342,27 +2365,13 @@ static int __setplane_internal(struct drm_plane *plane, crtc_y > INT_MAX - (int32_t) crtc_h) { DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", crtc_w, crtc_h, crtc_x, crtc_y); - return -ERANGE; + ret = -ERANGE; + goto out; } - - fb_width = fb->width << 16; - fb_height = fb->height << 16; - - /* Make sure source coordinates are inside the fb. */ - if (src_w > fb_width || - src_x > fb_width - src_w || - src_h > fb_height || - src_y > fb_height - src_h) { - DRM_DEBUG_KMS("Invalid source coordinates " - "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", - src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, - src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, - src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, - src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); - ret = -ENOSPC; + ret = check_src_coords(src_x, src_y, src_w, src_h, fb); + if (ret) goto out; - } plane->old_fb = plane->fb; ret = plane->funcs->update_plane(plane, crtc, fb, @@ -2553,20 +2562,13 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); - if (crtc->invert_dimensions) + if (crtc->state && + crtc->primary->state->rotation & (BIT(DRM_ROTATE_90) | + BIT(DRM_ROTATE_270))) swap(hdisplay, vdisplay); - if (hdisplay > fb->width || - vdisplay > fb->height || - x > fb->width - hdisplay || - y > fb->height - vdisplay) { - DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", - fb->width, fb->height, hdisplay, vdisplay, x, y, - crtc->invert_dimensions ? " (inverted)" : ""); - return -ENOSPC; - } - - return 0; + return check_src_coords(x << 16, y << 16, + hdisplay << 16, vdisplay << 16, fb); } EXPORT_SYMBOL(drm_crtc_check_viewport); @@ -5181,7 +5183,14 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, goto out; } - ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); + if (crtc->state) { + const struct drm_plane_state *state = crtc->primary->state; + + ret = check_src_coords(state->src_x, state->src_y, + state->src_w, state->src_h, fb); + } else { + ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); + } if (ret) goto out; @@ -5629,7 +5638,8 @@ unsigned int drm_rotation_simplify(unsigned int rotation, { if (rotation & ~supported_rotations) { rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y); - rotation = (rotation & ~0xf) | BIT((ffs(rotation & 0xf) + 1) % 4); + rotation = (rotation & DRM_REFLECT_MASK) | + BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4); } return rotation; diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index e23df5fd3836..2d46fc6230c2 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -53,8 +53,8 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int offset, int size, u8 *bytes); -static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_branch *mstb); +static void drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_branch *mstb); static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_branch *mstb, struct drm_dp_mst_port *port); @@ -804,8 +804,6 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref) struct drm_dp_mst_port *port, *tmp; bool wake_tx = false; - cancel_work_sync(&mstb->mgr->work); - /* * destroy all ports - don't need lock * as there are no more references to the mst branch @@ -863,29 +861,33 @@ static void drm_dp_destroy_port(struct kref *kref) { struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref); struct drm_dp_mst_topology_mgr *mgr = port->mgr; + if (!port->input) { port->vcpi.num_slots = 0; kfree(port->cached_edid); - /* we can't destroy the connector here, as - we might be holding the mode_config.mutex - from an EDID retrieval */ + /* + * The only time we don't have a connector + * on an output port is if the connector init + * fails. + */ if (port->connector) { + /* we can't destroy the connector here, as + * we might be holding the mode_config.mutex + * from an EDID retrieval */ + mutex_lock(&mgr->destroy_connector_lock); list_add(&port->next, &mgr->destroy_connector_list); mutex_unlock(&mgr->destroy_connector_lock); schedule_work(&mgr->destroy_connector_work); return; } + /* no need to clean up vcpi + * as if we have no connector we never setup a vcpi */ drm_dp_port_teardown_pdt(port, port->pdt); - - if (!port->input && port->vcpi.vcpi > 0) - drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); } kfree(port); - - (*mgr->cbs->hotplug)(mgr); } static void drm_dp_put_port(struct drm_dp_mst_port *port) @@ -1027,8 +1029,8 @@ static void drm_dp_check_port_guid(struct drm_dp_mst_branch *mstb, } } -static void build_mst_prop_path(struct drm_dp_mst_port *port, - struct drm_dp_mst_branch *mstb, +static void build_mst_prop_path(const struct drm_dp_mst_branch *mstb, + int pnum, char *proppath, size_t proppath_size) { @@ -1041,7 +1043,7 @@ static void build_mst_prop_path(struct drm_dp_mst_port *port, snprintf(temp, sizeof(temp), "-%d", port_num); strlcat(proppath, temp, proppath_size); } - snprintf(temp, sizeof(temp), "-%d", port->port_num); + snprintf(temp, sizeof(temp), "-%d", pnum); strlcat(proppath, temp, proppath_size); } @@ -1105,22 +1107,32 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, drm_dp_port_teardown_pdt(port, old_pdt); ret = drm_dp_port_setup_pdt(port); - if (ret == true) { + if (ret == true) drm_dp_send_link_address(mstb->mgr, port->mstb); - port->mstb->link_address_sent = true; - } } if (created && !port->input) { char proppath[255]; - build_mst_prop_path(port, mstb, proppath, sizeof(proppath)); - port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath); - if (port->port_num >= 8) { + build_mst_prop_path(mstb, port->port_num, proppath, sizeof(proppath)); + port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath); + if (!port->connector) { + /* remove it from the port list */ + mutex_lock(&mstb->mgr->lock); + list_del(&port->next); + mutex_unlock(&mstb->mgr->lock); + /* drop port list reference */ + drm_dp_put_port(port); + goto out; + } + if (port->port_num >= DP_MST_LOGICAL_PORT_0) { port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); + drm_mode_connector_set_tile_property(port->connector); } + (*mstb->mgr->cbs->register_connector)(port->connector); } +out: /* put reference to this port */ drm_dp_put_port(port); } @@ -1182,17 +1194,18 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_ list_for_each_entry(port, &mstb->ports, next) { if (port->port_num == port_num) { - if (!port->mstb) { + mstb = port->mstb; + if (!mstb) { DRM_ERROR("failed to lookup MSTB with lct %d, rad %02x\n", lct, rad[0]); - return NULL; + goto out; } - mstb = port->mstb; break; } } } kref_get(&mstb->kref); +out: mutex_unlock(&mgr->lock); return mstb; } @@ -1202,10 +1215,9 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m { struct drm_dp_mst_port *port; struct drm_dp_mst_branch *mstb_child; - if (!mstb->link_address_sent) { + if (!mstb->link_address_sent) drm_dp_send_link_address(mgr, mstb); - mstb->link_address_sent = true; - } + list_for_each_entry(port, &mstb->ports, next) { if (port->input) continue; @@ -1458,8 +1470,8 @@ static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr, mutex_unlock(&mgr->qlock); } -static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_branch *mstb) +static void drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_branch *mstb) { int len; struct drm_dp_sideband_msg_tx *txmsg; @@ -1467,11 +1479,12 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); if (!txmsg) - return -ENOMEM; + return; txmsg->dst = mstb; len = build_link_address(txmsg); + mstb->link_address_sent = true; drm_dp_queue_down_tx(mgr, txmsg); ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); @@ -1499,11 +1512,12 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, } (*mgr->cbs->hotplug)(mgr); } - } else + } else { + mstb->link_address_sent = false; DRM_DEBUG_KMS("link address failed %d\n", ret); + } kfree(txmsg); - return 0; } static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, @@ -1978,6 +1992,8 @@ void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr) drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, DP_MST_EN | DP_UPSTREAM_IS_SRC); mutex_unlock(&mgr->lock); + flush_work(&mgr->work); + flush_work(&mgr->destroy_connector_work); } EXPORT_SYMBOL(drm_dp_mst_topology_mgr_suspend); @@ -2263,10 +2279,10 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ if (port->cached_edid) edid = drm_edid_duplicate(port->cached_edid); - else + else { edid = drm_get_edid(connector, &port->aux.ddc); - - drm_mode_connector_set_tile_property(connector); + drm_mode_connector_set_tile_property(connector); + } drm_dp_put_port(port); return edid; } @@ -2671,7 +2687,7 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) { struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); struct drm_dp_mst_port *port; - + bool send_hotplug = false; /* * Not a regular list traverse as we have to drop the destroy * connector lock before destroying the connector, to avoid AB->BA @@ -2694,7 +2710,10 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) if (!port->input && port->vcpi.vcpi > 0) drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); kfree(port); + send_hotplug = true; } + if (send_hotplug) + (*mgr->cbs->hotplug)(mgr); } /** @@ -2747,6 +2766,7 @@ EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init); */ void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr) { + flush_work(&mgr->work); flush_work(&mgr->destroy_connector_work); mutex_lock(&mgr->payload_lock); kfree(mgr->payloads); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 9ad823fcde87..9362609df38a 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -37,11 +37,9 @@ #include "drm_legacy.h" #include "drm_internal.h" -unsigned int drm_debug = 0; /* 1 to enable debug output */ +unsigned int drm_debug = 0; /* bitmask of DRM_UT_x */ EXPORT_SYMBOL(drm_debug); -bool drm_atomic = 0; - MODULE_AUTHOR(CORE_AUTHOR); MODULE_DESCRIPTION(CORE_DESC); MODULE_LICENSE("GPL and additional rights"); @@ -397,15 +395,51 @@ void drm_minor_release(struct drm_minor *minor) } /** + * DOC: driver instance overview + * + * A device instance for a drm driver is represented by struct &drm_device. This + * is allocated with drm_dev_alloc(), usually from bus-specific ->probe() + * callbacks implemented by the driver. The driver then needs to initialize all + * the various subsystems for the drm device like memory management, vblank + * handling, modesetting support and intial output configuration plus obviously + * initialize all the corresponding hardware bits. An important part of this is + * also calling drm_dev_set_unique() to set the userspace-visible unique name of + * this device instance. Finally when everything is up and running and ready for + * userspace the device instance can be published using drm_dev_register(). + * + * There is also deprecated support for initalizing device instances using + * bus-specific helpers and the ->load() callback. But due to + * backwards-compatibility needs the device instance have to be published too + * early, which requires unpretty global locking to make safe and is therefore + * only support for existing drivers not yet converted to the new scheme. + * + * When cleaning up a device instance everything needs to be done in reverse: + * First unpublish the device instance with drm_dev_unregister(). Then clean up + * any other resources allocated at device initialization and drop the driver's + * reference to &drm_device using drm_dev_unref(). + * + * Note that the lifetime rules for &drm_device instance has still a lot of + * historical baggage. Hence use the reference counting provided by + * drm_dev_ref() and drm_dev_unref() only carefully. + * + * Also note that embedding of &drm_device is currently not (yet) supported (but + * it would be easy to add). Drivers can store driver-private data in the + * dev_priv field of &drm_device. + */ + +/** * drm_put_dev - Unregister and release a DRM device * @dev: DRM device * * Called at module unload time or when a PCI device is unplugged. * - * Use of this function is discouraged. It will eventually go away completely. - * Please use drm_dev_unregister() and drm_dev_unref() explicitly instead. - * * Cleans up all DRM device, calling drm_lastclose(). + * + * Note: Use of this function is deprecated. It will eventually go away + * completely. Please use drm_dev_unregister() and drm_dev_unref() explicitly + * instead to make sure that the device isn't userspace accessible any more + * while teardown is in progress, ensuring that userspace can't access an + * inconsistent state. */ void drm_put_dev(struct drm_device *dev) { @@ -518,7 +552,9 @@ static void drm_fs_inode_free(struct inode *inode) * * Allocate and initialize a new DRM device. No device registration is done. * Call drm_dev_register() to advertice the device to user space and register it - * with other core subsystems. + * with other core subsystems. This should be done last in the device + * initialization sequence to make sure userspace can't access an inconsistent + * state. * * The initial ref-count of the object is 1. Use drm_dev_ref() and * drm_dev_unref() to take and drop further ref-counts. @@ -673,6 +709,12 @@ EXPORT_SYMBOL(drm_dev_unref); * * Never call this twice on any device! * + * NOTE: To ensure backward compatibility with existing drivers method this + * function calls the ->load() method after registering the device nodes, + * creating race conditions. Usage of the ->load() methods is therefore + * deprecated, drivers must perform all initialization before calling + * drm_dev_register(). + * * RETURNS: * 0 on success, negative error code on failure. */ @@ -720,6 +762,9 @@ EXPORT_SYMBOL(drm_dev_register); * Unregister the DRM device from the system. This does the reverse of * drm_dev_register() but does not deallocate the device. The caller must call * drm_dev_unref() to drop their final reference. + * + * This should be called first in the device teardown code to make sure + * userspace can't access the device instance any more. */ void drm_dev_unregister(struct drm_device *dev) { diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index abe9793d548d..e673c13c7391 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -360,11 +360,7 @@ retry: goto fail; } - ret = drm_atomic_plane_set_property(plane, plane_state, - dev->mode_config.rotation_property, - BIT(DRM_ROTATE_0)); - if (ret != 0) - goto fail; + plane_state->rotation = BIT(DRM_ROTATE_0); /* disable non-primary: */ if (plane->type == DRM_PLANE_TYPE_PRIMARY) @@ -442,7 +438,11 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) struct drm_crtc *crtc = mode_set->crtc; int ret; - if (crtc->funcs->cursor_set) { + if (crtc->funcs->cursor_set2) { + ret = crtc->funcs->cursor_set2(crtc, NULL, 0, 0, 0, 0, 0); + if (ret) + return ret; + } else if (crtc->funcs->cursor_set) { ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0); if (ret) return ret; @@ -1231,7 +1231,7 @@ int drm_fb_helper_set_par(struct fb_info *info) EXPORT_SYMBOL(drm_fb_helper_set_par); static int pan_display_atomic(struct fb_var_screeninfo *var, - struct fb_info *info) + struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; struct drm_device *dev = fb_helper->dev; @@ -1249,6 +1249,8 @@ retry: mode_set = &fb_helper->crtc_info[i].mode_set; + mode_set->crtc->primary->old_fb = mode_set->crtc->primary->fb; + mode_set->x = var->xoffset; mode_set->y = var->yoffset; @@ -1264,13 +1266,34 @@ retry: info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; - return 0; fail: + for(i = 0; i < fb_helper->crtc_count; i++) { + struct drm_mode_set *mode_set; + struct drm_plane *plane; + + mode_set = &fb_helper->crtc_info[i].mode_set; + plane = mode_set->crtc->primary; + + if (ret == 0) { + struct drm_framebuffer *new_fb = plane->state->fb; + + if (new_fb) + drm_framebuffer_reference(new_fb); + plane->fb = new_fb; + plane->crtc = plane->state->crtc; + + if (plane->old_fb) + drm_framebuffer_unreference(plane->old_fb); + } + plane->old_fb = NULL; + } + if (ret == -EDEADLK) goto backoff; - drm_atomic_state_free(state); + if (ret != 0) + drm_atomic_state_free(state); return ret; diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 3c2d4abd71c5..64353d40db53 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -763,7 +763,8 @@ EXPORT_SYMBOL(drm_gem_object_release); void drm_gem_object_free(struct kref *kref) { - struct drm_gem_object *obj = (struct drm_gem_object *) kref; + struct drm_gem_object *obj = + container_of(kref, struct drm_gem_object, refcount); struct drm_device *dev = obj->dev; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -810,8 +811,6 @@ EXPORT_SYMBOL(drm_gem_vm_close); * drm_gem_mmap() prevents unprivileged users from mapping random objects. So * callers must verify access restrictions before calling this helper. * - * NOTE: This function has to be protected with dev->struct_mutex - * * Return 0 or success or -EINVAL if the object size is smaller than the VMA * size, or if no gem_vm_ops are provided. */ @@ -820,8 +819,6 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, { struct drm_device *dev = obj->dev; - lockdep_assert_held(&dev->struct_mutex); - /* Check for valid size. */ if (obj_size < vma->vm_end - vma->vm_start) return -EINVAL; @@ -865,30 +862,46 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) { struct drm_file *priv = filp->private_data; struct drm_device *dev = priv->minor->dev; - struct drm_gem_object *obj; + struct drm_gem_object *obj = NULL; struct drm_vma_offset_node *node; int ret; if (drm_device_is_unplugged(dev)) return -ENODEV; - mutex_lock(&dev->struct_mutex); + drm_vma_offset_lock_lookup(dev->vma_offset_manager); + node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager, + vma->vm_pgoff, + vma_pages(vma)); + if (likely(node)) { + obj = container_of(node, struct drm_gem_object, vma_node); + /* + * When the object is being freed, after it hits 0-refcnt it + * proceeds to tear down the object. In the process it will + * attempt to remove the VMA offset and so acquire this + * mgr->vm_lock. Therefore if we find an object with a 0-refcnt + * that matches our range, we know it is in the process of being + * destroyed and will be freed as soon as we release the lock - + * so we have to check for the 0-refcnted object and treat it as + * invalid. + */ + if (!kref_get_unless_zero(&obj->refcount)) + obj = NULL; + } + drm_vma_offset_unlock_lookup(dev->vma_offset_manager); - node = drm_vma_offset_exact_lookup(dev->vma_offset_manager, - vma->vm_pgoff, - vma_pages(vma)); - if (!node) { - mutex_unlock(&dev->struct_mutex); + if (!obj) return -EINVAL; - } else if (!drm_vma_node_is_allowed(node, filp)) { - mutex_unlock(&dev->struct_mutex); + + if (!drm_vma_node_is_allowed(node, filp)) { + drm_gem_object_unreference_unlocked(obj); return -EACCES; } - obj = container_of(node, struct drm_gem_object, vma_node); - ret = drm_gem_mmap_obj(obj, drm_vma_node_size(node) << PAGE_SHIFT, vma); + ret = drm_gem_mmap_obj(obj, drm_vma_node_size(node) << PAGE_SHIFT, + vma); - mutex_unlock(&dev->struct_mutex); + drm_gem_object_unreference_unlocked(obj); return ret; } diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index 86cc793cdf79..4fb4c45d039f 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -484,9 +484,7 @@ int drm_gem_cma_prime_mmap(struct drm_gem_object *obj, struct drm_device *dev = obj->dev; int ret; - mutex_lock(&dev->struct_mutex); ret = drm_gem_mmap_obj(obj, obj->size, vma); - mutex_unlock(&dev->struct_mutex); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index ddfa6014c2c2..57676f8d7ecf 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -720,7 +720,7 @@ static int compat_drm_dma(struct file *file, unsigned int cmd, return 0; } -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) typedef struct drm_agp_mode32 { u32 mode; /**< AGP mode */ } drm_agp_mode32_t; @@ -882,7 +882,7 @@ static int compat_drm_agp_unbind(struct file *file, unsigned int cmd, return drm_ioctl(file, DRM_IOCTL_AGP_UNBIND, (unsigned long)request); } -#endif /* __OS_HAS_AGP */ +#endif /* CONFIG_AGP */ typedef struct drm_scatter_gather32 { u32 size; /**< In bytes -- will round to page boundary */ @@ -1090,7 +1090,7 @@ static drm_ioctl_compat_t *drm_compat_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX32)] = compat_drm_getsareactx, [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX32)] = compat_drm_resctx, [DRM_IOCTL_NR(DRM_IOCTL_DMA32)] = compat_drm_dma, -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE32)] = compat_drm_agp_enable, [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO32)] = compat_drm_agp_info, [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC32)] = compat_drm_agp_alloc, diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index d93e7378c077..8ce2a0c59116 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -40,7 +40,7 @@ static int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv); -/** +/* * Get the bus id. * * \param inode device inode. @@ -75,7 +75,7 @@ drm_unset_busid(struct drm_device *dev, master->unique_len = 0; } -/** +/* * Set the bus id. * * \param inode device inode. @@ -149,7 +149,7 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) return 0; } -/** +/* * Get a mapping information. * * \param inode device inode. @@ -201,7 +201,7 @@ static int drm_getmap(struct drm_device *dev, void *data, return 0; } -/** +/* * Get client information. * * \param inode device inode. @@ -244,7 +244,7 @@ static int drm_getclient(struct drm_device *dev, void *data, } } -/** +/* * Get statistics information. * * \param inode device inode. @@ -265,7 +265,7 @@ static int drm_getstats(struct drm_device *dev, void *data, return 0; } -/** +/* * Get device/driver capabilities */ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -318,7 +318,7 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_ return 0; } -/** +/* * Set device/driver capabilities */ static int @@ -352,7 +352,7 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) return 0; } -/** +/* * Setversion ioctl. * * \param inode device inode. @@ -406,7 +406,18 @@ done: return retcode; } -/** No-op ioctl. */ +/** + * drm_noop - DRM no-op ioctl implemntation + * @dev: DRM device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: DRM file for the ioctl call + * + * This no-op implementation for drm ioctls is useful for deprecated + * functionality where we can't return a failure code because existing userspace + * checks the result of the ioctl, but doesn't care about the action. + * + * Always returns successfully with 0. + */ int drm_noop(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -416,6 +427,28 @@ int drm_noop(struct drm_device *dev, void *data, EXPORT_SYMBOL(drm_noop); /** + * drm_invalid_op - DRM invalid ioctl implemntation + * @dev: DRM device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: DRM file for the ioctl call + * + * This no-op implementation for drm ioctls is useful for deprecated + * functionality where we really don't want to allow userspace to call the ioctl + * any more. This is the case for old ums interfaces for drivers that + * transitioned to kms gradually and so kept the old legacy tables around. This + * only applies to radeon and i915 kms drivers, other drivers shouldn't need to + * use this function. + * + * Always fails with a return value of -EINVAL. + */ +int drm_invalid_op(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return -EINVAL; +} +EXPORT_SYMBOL(drm_invalid_op); + +/* * Copy and IOCTL return string to user space */ static int drm_copy_field(char __user *buf, size_t *buf_len, const char *value) @@ -438,7 +471,7 @@ static int drm_copy_field(char __user *buf, size_t *buf_len, const char *value) return 0; } -/** +/* * Get version information * * \param inode device inode. @@ -470,7 +503,7 @@ static int drm_version(struct drm_device *dev, void *data, return err; } -/** +/* * drm_ioctl_permit - Check ioctl permissions against caller * * @flags: ioctl permission flags. @@ -518,7 +551,7 @@ EXPORT_SYMBOL(drm_ioctl_permit); .name = #ioctl \ } -/** Ioctl table */ +/* Ioctl table */ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED|DRM_RENDER_ALLOW|DRM_CONTROL_ALLOW), @@ -571,7 +604,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -635,16 +668,16 @@ static const struct drm_ioctl_desc drm_ioctls[] = { #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) /** - * Called whenever a process performs an ioctl on /dev/drm. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument. - * \return zero on success or negative number on failure. + * drm_ioctl - ioctl callback implementation for DRM drivers + * @filp: file this ioctl is called on + * @cmd: ioctl cmd number + * @arg: user argument * * Looks up the ioctl function in the ::ioctls table, checking for root * previleges if so required, and dispatches to the respective function. + * + * Returns: + * Zero on success, negative error code on failure. */ long drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) @@ -658,13 +691,16 @@ long drm_ioctl(struct file *filp, char stack_kdata[128]; char *kdata = NULL; unsigned int usize, asize, drv_size; + bool is_driver_ioctl; dev = file_priv->minor->dev; if (drm_device_is_unplugged(dev)) return -ENODEV; - if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END) { + is_driver_ioctl = nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END; + + if (is_driver_ioctl) { /* driver ioctl */ if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls) goto err_i1; @@ -723,7 +759,10 @@ long drm_ioctl(struct file *filp, memset(kdata, 0, usize); } - if (ioctl->flags & DRM_UNLOCKED) + /* Enforce sane locking for kms driver ioctls. Core ioctls are + * too messy still. */ + if ((drm_core_check_feature(dev, DRIVER_MODESET) && is_driver_ioctl) || + (ioctl->flags & DRM_UNLOCKED)) retcode = func(dev, kdata, file_priv); else { mutex_lock(&drm_global_mutex); @@ -754,9 +793,15 @@ EXPORT_SYMBOL(drm_ioctl); /** * drm_ioctl_flags - Check for core ioctl and return ioctl permission flags + * @nr: ioctl number + * @flags: where to return the ioctl permission flags + * + * This ioctl is only used by the vmwgfx driver to augment the access checks + * done by the drm core and insofar a pretty decent layering violation. This + * shouldn't be used by any drivers. * - * @nr: Ioctl number. - * @flags: Where to return the ioctl permission flags + * Returns: + * True if the @nr corresponds to a DRM core ioctl numer, false otherwise. */ bool drm_ioctl_flags(unsigned int nr, unsigned int *flags) { diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index ed2394e1720b..eba6337f5860 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -213,17 +213,17 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); if (diff == 0 && flags & DRM_CALLED_FROM_VBLIRQ) - DRM_DEBUG("crtc %u: Redundant vblirq ignored." - " diff_ns = %lld, framedur_ns = %d)\n", - pipe, (long long) diff_ns, framedur_ns); + DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored." + " diff_ns = %lld, framedur_ns = %d)\n", + pipe, (long long) diff_ns, framedur_ns); } else { /* some kind of default for drivers w/o accurate vbl timestamping */ diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0; } - DRM_DEBUG("updating vblank count on crtc %u:" - " current=%u, diff=%u, hw=%u hw_last=%u\n", - pipe, vblank->count, diff, cur_vblank, vblank->last); + DRM_DEBUG_VBL("updating vblank count on crtc %u:" + " current=%u, diff=%u, hw=%u hw_last=%u\n", + pipe, vblank->count, diff, cur_vblank, vblank->last); if (diff == 0) { WARN_ON_ONCE(cur_vblank != vblank->last); @@ -232,10 +232,11 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, /* * Only reinitialize corresponding vblank timestamp if high-precision query - * available and didn't fail. Otherwise reinitialize delayed at next vblank - * interrupt and assign 0 for now, to mark the vblanktimestamp as invalid. + * available and didn't fail, or we were called from the vblank interrupt. + * Otherwise reinitialize delayed at next vblank interrupt and assign 0 + * for now, to mark the vblanktimestamp as invalid. */ - if (!rc) + if (!rc && (flags & DRM_CALLED_FROM_VBLIRQ) == 0) t_vblank = (struct timeval) {0, 0}; store_vblank(dev, pipe, diff, &t_vblank, cur_vblank); @@ -799,11 +800,11 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, etime = ktime_sub_ns(etime, delta_ns); *vblank_time = ktime_to_timeval(etime); - DRM_DEBUG("crtc %u : v 0x%x p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n", - pipe, vbl_status, hpos, vpos, - (long)tv_etime.tv_sec, (long)tv_etime.tv_usec, - (long)vblank_time->tv_sec, (long)vblank_time->tv_usec, - duration_ns/1000, i); + DRM_DEBUG_VBL("crtc %u : v 0x%x p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n", + pipe, vbl_status, hpos, vpos, + (long)tv_etime.tv_sec, (long)tv_etime.tv_usec, + (long)vblank_time->tv_sec, (long)vblank_time->tv_usec, + duration_ns/1000, i); return ret; } @@ -876,7 +877,7 @@ drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, * Returns: * The software vblank counter. */ -u32 drm_vblank_count(struct drm_device *dev, int pipe) +u32 drm_vblank_count(struct drm_device *dev, unsigned int pipe) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; @@ -1271,8 +1272,8 @@ void drm_vblank_off(struct drm_device *dev, unsigned int pipe) list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { if (e->pipe != pipe) continue; - DRM_DEBUG("Sending premature vblank event on disable: \ - wanted %d, current %d\n", + DRM_DEBUG("Sending premature vblank event on disable: " + "wanted %d, current %d\n", e->event.sequence, seq); list_del(&e->base.link); drm_vblank_put(dev, pipe); @@ -1797,3 +1798,20 @@ bool drm_crtc_handle_vblank(struct drm_crtc *crtc) return drm_handle_vblank(crtc->dev, drm_crtc_index(crtc)); } EXPORT_SYMBOL(drm_crtc_handle_vblank); + +/** + * drm_vblank_no_hw_counter - "No hw counter" implementation of .get_vblank_counter() + * @dev: DRM device + * @pipe: CRTC for which to read the counter + * + * Drivers can plug this into the .get_vblank_counter() function if + * there is no useable hardware frame counter available. + * + * Returns: + * 0 + */ +u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe) +{ + return 0; +} +EXPORT_SYMBOL(drm_vblank_no_hw_counter); diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c index a521ef6ff807..87a8cb73366f 100644 --- a/drivers/gpu/drm/drm_memory.c +++ b/drivers/gpu/drm/drm_memory.c @@ -38,7 +38,7 @@ #include <drm/drmP.h> #include "drm_legacy.h" -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) #ifdef HAVE_PAGE_AGP # include <asm/agp.h> @@ -111,14 +111,14 @@ int drm_unbind_agp(struct agp_memory * handle) return agp_unbind_memory(handle); } -#else /* __OS_HAS_AGP */ +#else /* CONFIG_AGP */ static inline void *agp_remap(unsigned long offset, unsigned long size, struct drm_device * dev) { return NULL; } -#endif /* agp */ +#endif /* CONFIG_AGP */ void drm_legacy_ioremap(struct drm_local_map *map, struct drm_device *dev) { diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 1b1bd42b0368..fcd2a86acd2c 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -266,6 +266,9 @@ void drm_pci_agp_destroy(struct drm_device *dev) * then register the character device and inter module information. * Try and register, if we fail to register, backout previous work. * + * NOTE: This function is deprecated, please use drm_dev_alloc() and + * drm_dev_register() instead and remove your ->load() callback. + * * Return: 0 on success or a negative error code on failure. */ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, @@ -326,6 +329,10 @@ EXPORT_SYMBOL(drm_get_pci_dev); * Initializes a drm_device structures, registering the stubs and initializing * the AGP device. * + * NOTE: This function is deprecated. Modern modesetting drm drivers should use + * pci_register_driver() directly, this function only provides shadow-binding + * support for old legacy drivers on top of that core pci function. + * * Return: 0 on success or a negative error code on failure. */ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver) @@ -435,6 +442,10 @@ EXPORT_SYMBOL(drm_pci_init); * * Unregisters one or more devices matched by a PCI driver from the DRM * subsystem. + * + * NOTE: This function is deprecated. Modern modesetting drm drivers should use + * pci_unregister_driver() directly, this function only provides shadow-binding + * support for old legacy drivers on top of that core pci function. */ void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver) { diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 5314c9d5fef4..644169e1a029 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -95,6 +95,9 @@ EXPORT_SYMBOL(drm_platform_set_busid); * subsystem, initializing a drm_device structure and calling the driver's * .load() function. * + * NOTE: This function is deprecated, please use drm_dev_alloc() and + * drm_dev_register() instead and remove your ->load() callback. + * * Return: 0 on success or a negative error code on failure. */ int drm_platform_init(struct drm_driver *driver, struct platform_device *platform_device) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index d734780b31c0..a18164f2f6d2 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -94,7 +94,18 @@ static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector) } #define DRM_OUTPUT_POLL_PERIOD (10*HZ) -static void __drm_kms_helper_poll_enable(struct drm_device *dev) +/** + * drm_kms_helper_poll_enable_locked - re-enable output polling. + * @dev: drm_device + * + * This function re-enables the output polling work without + * locking the mode_config mutex. + * + * This is like drm_kms_helper_poll_enable() however it is to be + * called from a context where the mode_config mutex is locked + * already. + */ +void drm_kms_helper_poll_enable_locked(struct drm_device *dev) { bool poll = false; struct drm_connector *connector; @@ -113,6 +124,8 @@ static void __drm_kms_helper_poll_enable(struct drm_device *dev) if (poll) schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); } +EXPORT_SYMBOL(drm_kms_helper_poll_enable_locked); + static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector, uint32_t maxX, uint32_t maxY, bool merge_type_bits) @@ -174,7 +187,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect /* Re-enable polling in case the global poll config changed. */ if (drm_kms_helper_poll != dev->mode_config.poll_running) - __drm_kms_helper_poll_enable(dev); + drm_kms_helper_poll_enable_locked(dev); dev->mode_config.poll_running = drm_kms_helper_poll; @@ -428,7 +441,7 @@ EXPORT_SYMBOL(drm_kms_helper_poll_disable); void drm_kms_helper_poll_enable(struct drm_device *dev) { mutex_lock(&dev->mode_config.mutex); - __drm_kms_helper_poll_enable(dev); + drm_kms_helper_poll_enable_locked(dev); mutex_unlock(&dev->mode_config.mutex); } EXPORT_SYMBOL(drm_kms_helper_poll_enable); diff --git a/drivers/gpu/drm/drm_rect.c b/drivers/gpu/drm/drm_rect.c index 631f5afd451c..531ac4cc9756 100644 --- a/drivers/gpu/drm/drm_rect.c +++ b/drivers/gpu/drm/drm_rect.c @@ -330,7 +330,7 @@ void drm_rect_rotate(struct drm_rect *r, } } - switch (rotation & 0xf) { + switch (rotation & DRM_ROTATE_MASK) { case BIT(DRM_ROTATE_0): break; case BIT(DRM_ROTATE_90): @@ -390,7 +390,7 @@ void drm_rect_rotate_inv(struct drm_rect *r, { struct drm_rect tmp; - switch (rotation & 0xf) { + switch (rotation & DRM_ROTATE_MASK) { case BIT(DRM_ROTATE_0): break; case BIT(DRM_ROTATE_90): diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index f08873f6489c..615b7e667320 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -230,18 +230,12 @@ static ssize_t dpms_show(struct device *device, char *buf) { struct drm_connector *connector = to_drm_connector(device); - struct drm_device *dev = connector->dev; - uint64_t dpms_status; - int ret; + int dpms; - ret = drm_object_property_get_value(&connector->base, - dev->mode_config.dpms_property, - &dpms_status); - if (ret) - return 0; + dpms = READ_ONCE(connector->dpms); return snprintf(buf, PAGE_SIZE, "%s\n", - drm_get_dpms_name((int)dpms_status)); + drm_get_dpms_name(dpms)); } static ssize_t enabled_show(struct device *device, diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index aab49ee4ed40..f90bd5fe35ba 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -95,7 +95,7 @@ static pgprot_t drm_dma_prot(uint32_t map_type, struct vm_area_struct *vma) * Find the right map and if it's AGP memory find the real physical page to * map, get the page, increment the use count and return it. */ -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct drm_file *priv = vma->vm_file->private_data; @@ -168,12 +168,12 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) vm_fault_error: return VM_FAULT_SIGBUS; /* Disallow mremap */ } -#else /* __OS_HAS_AGP */ +#else static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { return VM_FAULT_SIGBUS; } -#endif /* __OS_HAS_AGP */ +#endif /** * \c nopage method for shared virtual memory. @@ -556,7 +556,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) * --BenH. */ if (!vma->vm_pgoff -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) && (!dev->agp || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) #endif diff --git a/drivers/gpu/drm/drm_vma_manager.c b/drivers/gpu/drm/drm_vma_manager.c index 68c1f32fb086..2f2ecde8285b 100644 --- a/drivers/gpu/drm/drm_vma_manager.c +++ b/drivers/gpu/drm/drm_vma_manager.c @@ -112,7 +112,7 @@ void drm_vma_offset_manager_destroy(struct drm_vma_offset_manager *mgr) EXPORT_SYMBOL(drm_vma_offset_manager_destroy); /** - * drm_vma_offset_lookup() - Find node in offset space + * drm_vma_offset_lookup_locked() - Find node in offset space * @mgr: Manager object * @start: Start address for object (page-based) * @pages: Size of object (page-based) @@ -122,37 +122,21 @@ EXPORT_SYMBOL(drm_vma_offset_manager_destroy); * region and the given node will be returned, as long as the node spans the * whole requested area (given the size in number of pages as @pages). * - * RETURNS: - * Returns NULL if no suitable node can be found. Otherwise, the best match - * is returned. It's the caller's responsibility to make sure the node doesn't - * get destroyed before the caller can access it. - */ -struct drm_vma_offset_node *drm_vma_offset_lookup(struct drm_vma_offset_manager *mgr, - unsigned long start, - unsigned long pages) -{ - struct drm_vma_offset_node *node; - - read_lock(&mgr->vm_lock); - node = drm_vma_offset_lookup_locked(mgr, start, pages); - read_unlock(&mgr->vm_lock); - - return node; -} -EXPORT_SYMBOL(drm_vma_offset_lookup); - -/** - * drm_vma_offset_lookup_locked() - Find node in offset space - * @mgr: Manager object - * @start: Start address for object (page-based) - * @pages: Size of object (page-based) + * Note that before lookup the vma offset manager lookup lock must be acquired + * with drm_vma_offset_lock_lookup(). See there for an example. This can then be + * used to implement weakly referenced lookups using kref_get_unless_zero(). * - * Same as drm_vma_offset_lookup() but requires the caller to lock offset lookup - * manually. See drm_vma_offset_lock_lookup() for an example. + * Example: + * drm_vma_offset_lock_lookup(mgr); + * node = drm_vma_offset_lookup_locked(mgr); + * if (node) + * kref_get_unless_zero(container_of(node, sth, entr)); + * drm_vma_offset_unlock_lookup(mgr); * * RETURNS: * Returns NULL if no suitable node can be found. Otherwise, the best match - * is returned. + * is returned. It's the caller's responsibility to make sure the node doesn't + * get destroyed before the caller can access it. */ struct drm_vma_offset_node *drm_vma_offset_lookup_locked(struct drm_vma_offset_manager *mgr, unsigned long start, diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index cbdb78ef3bac..e6cbaca821a4 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -37,7 +37,6 @@ * DECON stands for Display and Enhancement controller. */ -#define DECON_DEFAULT_FRAMERATE 60 #define MIN_FB_WIDTH_FOR_16WORD_BURST 128 #define WINDOWS_NR 2 @@ -165,16 +164,6 @@ static u32 decon_calc_clkdiv(struct decon_context *ctx, return (clkdiv < 0x100) ? clkdiv : 0xff; } -static bool decon_mode_fixup(struct exynos_drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - if (adjusted_mode->vrefresh == 0) - adjusted_mode->vrefresh = DECON_DEFAULT_FRAMERATE; - - return true; -} - static void decon_commit(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; @@ -637,7 +626,6 @@ static void decon_disable(struct exynos_drm_crtc *crtc) static const struct exynos_drm_crtc_ops decon_crtc_ops = { .enable = decon_enable, .disable = decon_disable, - .mode_fixup = decon_mode_fixup, .commit = decon_commit, .enable_vblank = decon_enable_vblank, .disable_vblank = decon_disable_vblank, diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index d66ade0efac8..124fb9a56f02 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1383,28 +1383,6 @@ static int exynos_dp_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int exynos_dp_suspend(struct device *dev) -{ - struct exynos_dp_device *dp = dev_get_drvdata(dev); - - exynos_dp_disable(&dp->encoder); - return 0; -} - -static int exynos_dp_resume(struct device *dev) -{ - struct exynos_dp_device *dp = dev_get_drvdata(dev); - - exynos_dp_enable(&dp->encoder); - return 0; -} -#endif - -static const struct dev_pm_ops exynos_dp_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume) -}; - static const struct of_device_id exynos_dp_match[] = { { .compatible = "samsung,exynos5-dp" }, {}, @@ -1417,7 +1395,6 @@ struct platform_driver dp_driver = { .driver = { .name = "exynos-dp", .owner = THIS_MODULE, - .pm = &exynos_dp_pm_ops, .of_match_table = exynos_dp_match, }, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index c68a6a2a9b57..7f55ba6771c6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -28,7 +28,6 @@ int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) return 0; } -EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register); int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv) { @@ -39,7 +38,6 @@ int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv) return 0; } -EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister); int exynos_drm_device_subdrv_probe(struct drm_device *dev) { @@ -69,7 +67,6 @@ int exynos_drm_device_subdrv_probe(struct drm_device *dev) return 0; } -EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_probe); int exynos_drm_device_subdrv_remove(struct drm_device *dev) { @@ -87,7 +84,6 @@ int exynos_drm_device_subdrv_remove(struct drm_device *dev) return 0; } -EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_remove); int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) { @@ -111,7 +107,6 @@ err: } return ret; } -EXPORT_SYMBOL_GPL(exynos_drm_subdrv_open); void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file) { @@ -122,4 +117,3 @@ void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file) subdrv->close(dev, subdrv->dev, file); } } -EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close); diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 0872aa2f450f..50dec0df160f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -41,20 +41,6 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc) exynos_crtc->ops->disable(exynos_crtc); } -static bool -exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - - if (exynos_crtc->ops->mode_fixup) - return exynos_crtc->ops->mode_fixup(exynos_crtc, mode, - adjusted_mode); - - return true; -} - static void exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) { @@ -99,7 +85,6 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { .enable = exynos_drm_crtc_enable, .disable = exynos_drm_crtc_disable, - .mode_fixup = exynos_drm_crtc_mode_fixup, .mode_set_nofb = exynos_drm_crtc_mode_set_nofb, .atomic_begin = exynos_crtc_atomic_begin, .atomic_flush = exynos_crtc_atomic_flush, @@ -167,7 +152,7 @@ err_crtc: return ERR_PTR(ret); } -int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) +int exynos_drm_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct exynos_drm_private *private = dev->dev_private; struct exynos_drm_crtc *exynos_crtc = @@ -179,7 +164,7 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) return 0; } -void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) +void exynos_drm_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe) { struct exynos_drm_private *private = dev->dev_private; struct exynos_drm_crtc *exynos_crtc = diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index f87d4abda6f7..f9f365bd0257 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -23,8 +23,8 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, enum exynos_drm_output_type type, const struct exynos_drm_crtc_ops *ops, void *context); -int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); -void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe); +int exynos_drm_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe); +void exynos_drm_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe); void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc); void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, struct exynos_drm_plane *exynos_plane); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index f0a5839bd226..09c4c6af8cd1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -304,6 +304,7 @@ int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, return 0; } +#ifdef CONFIG_PM_SLEEP static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state) { struct drm_connector *connector; @@ -340,6 +341,7 @@ static int exynos_drm_resume(struct drm_device *dev) return 0; } +#endif static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) { @@ -403,25 +405,25 @@ static const struct vm_operations_struct exynos_drm_gem_vm_ops = { static const struct drm_ioctl_desc exynos_ioctls[] = { DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl, - DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET, exynos_drm_gem_get_ioctl, - DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION, vidi_connection_ioctl, - DRM_UNLOCKED | DRM_AUTH), + DRM_AUTH), DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER, exynos_g2d_get_ver_ioctl, - DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST, exynos_g2d_set_cmdlist_ioctl, - DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, exynos_g2d_exec_ioctl, - DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY, exynos_drm_ipp_get_property, - DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY, exynos_drm_ipp_set_property, - DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF, exynos_drm_ipp_queue_buf, - DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL, exynos_drm_ipp_cmd_ctrl, - DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), }; static const struct file_operations exynos_drm_driver_fops = { @@ -447,7 +449,7 @@ static struct drm_driver exynos_drm_driver = { .lastclose = exynos_drm_lastclose, .postclose = exynos_drm_postclose, .set_busid = drm_platform_set_busid, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = exynos_drm_crtc_enable_vblank, .disable_vblank = exynos_drm_crtc_disable_vblank, .gem_free_object = exynos_drm_gem_free_object, diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index b7ba21dfb696..6c717ba672db 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -82,7 +82,6 @@ struct exynos_drm_plane { * * @enable: enable the device * @disable: disable the device - * @mode_fixup: fix mode data before applying it * @commit: set current hw specific display mode to hw. * @enable_vblank: specific driver callback for enabling vblank interrupt. * @disable_vblank: specific driver callback for disabling vblank interrupt. @@ -103,9 +102,6 @@ struct exynos_drm_crtc; struct exynos_drm_crtc_ops { void (*enable)(struct exynos_drm_crtc *crtc); void (*disable)(struct exynos_drm_crtc *crtc); - bool (*mode_fixup)(struct exynos_drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); void (*commit)(struct exynos_drm_crtc *crtc); int (*enable_vblank)(struct exynos_drm_crtc *crtc); void (*disable_vblank)(struct exynos_drm_crtc *crtc); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 2a652359af64..dd3a5e6d58c8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -1206,23 +1206,6 @@ static struct exynos_drm_ipp_ops fimc_dst_ops = { .set_addr = fimc_dst_set_addr, }; -static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable) -{ - DRM_DEBUG_KMS("enable[%d]\n", enable); - - if (enable) { - clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]); - clk_prepare_enable(ctx->clocks[FIMC_CLK_WB_A]); - ctx->suspended = false; - } else { - clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]); - clk_disable_unprepare(ctx->clocks[FIMC_CLK_WB_A]); - ctx->suspended = true; - } - - return 0; -} - static irqreturn_t fimc_irq_handler(int irq, void *dev_id) { struct fimc_context *ctx = dev_id; @@ -1780,6 +1763,24 @@ static int fimc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable) +{ + DRM_DEBUG_KMS("enable[%d]\n", enable); + + if (enable) { + clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]); + clk_prepare_enable(ctx->clocks[FIMC_CLK_WB_A]); + ctx->suspended = false; + } else { + clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]); + clk_disable_unprepare(ctx->clocks[FIMC_CLK_WB_A]); + ctx->suspended = true; + } + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int fimc_suspend(struct device *dev) { @@ -1806,7 +1807,6 @@ static int fimc_resume(struct device *dev) } #endif -#ifdef CONFIG_PM static int fimc_runtime_suspend(struct device *dev) { struct fimc_context *ctx = get_fimc_context(dev); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 750a9e6b9e8d..3d1aba67758b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -41,7 +41,6 @@ * CPU Interface. */ -#define FIMD_DEFAULT_FRAMERATE 60 #define MIN_FB_WIDTH_FOR_16WORD_BURST 128 /* position control register for hardware window 0, 2 ~ 4.*/ @@ -377,16 +376,6 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx, return (clkdiv < 0x100) ? clkdiv : 0xff; } -static bool fimd_mode_fixup(struct exynos_drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - if (adjusted_mode->vrefresh == 0) - adjusted_mode->vrefresh = FIMD_DEFAULT_FRAMERATE; - - return true; -} - static void fimd_commit(struct exynos_drm_crtc *crtc) { struct fimd_context *ctx = crtc->ctx; @@ -882,13 +871,12 @@ static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable) return; val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE; - writel(DP_MIE_CLK_DP_ENABLE, ctx->regs + DP_MIE_CLKCON); + writel(val, ctx->regs + DP_MIE_CLKCON); } static const struct exynos_drm_crtc_ops fimd_crtc_ops = { .enable = fimd_enable, .disable = fimd_disable, - .mode_fixup = fimd_mode_fixup, .commit = fimd_commit, .enable_vblank = fimd_enable_vblank, .disable_vblank = fimd_disable_vblank, diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 3734c34aed16..c17efdb238a6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -1059,7 +1059,6 @@ int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data, return 0; } -EXPORT_SYMBOL_GPL(exynos_g2d_get_ver_ioctl); int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, struct drm_file *file) @@ -1230,7 +1229,6 @@ err: g2d_put_cmdlist(g2d, node); return ret; } -EXPORT_SYMBOL_GPL(exynos_g2d_set_cmdlist_ioctl); int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, struct drm_file *file) @@ -1293,7 +1291,6 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, out: return 0; } -EXPORT_SYMBOL_GPL(exynos_g2d_exec_ioctl); static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index f12fbc36b120..407afedb6003 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -56,39 +56,35 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem_obj *obj) nr_pages = obj->size >> PAGE_SHIFT; if (!is_drm_iommu_supported(dev)) { - dma_addr_t start_addr; - unsigned int i = 0; - obj->pages = drm_calloc_large(nr_pages, sizeof(struct page *)); if (!obj->pages) { DRM_ERROR("failed to allocate pages.\n"); return -ENOMEM; } + } - obj->cookie = dma_alloc_attrs(dev->dev, - obj->size, - &obj->dma_addr, GFP_KERNEL, - &obj->dma_attrs); - if (!obj->cookie) { - DRM_ERROR("failed to allocate buffer.\n"); + obj->cookie = dma_alloc_attrs(dev->dev, obj->size, &obj->dma_addr, + GFP_KERNEL, &obj->dma_attrs); + if (!obj->cookie) { + DRM_ERROR("failed to allocate buffer.\n"); + if (obj->pages) drm_free_large(obj->pages); - return -ENOMEM; - } + return -ENOMEM; + } + + if (obj->pages) { + dma_addr_t start_addr; + unsigned int i = 0; start_addr = obj->dma_addr; while (i < nr_pages) { - obj->pages[i] = phys_to_page(start_addr); + obj->pages[i] = pfn_to_page(dma_to_pfn(dev->dev, + start_addr)); start_addr += PAGE_SIZE; i++; } } else { - obj->pages = dma_alloc_attrs(dev->dev, obj->size, - &obj->dma_addr, GFP_KERNEL, - &obj->dma_attrs); - if (!obj->pages) { - DRM_ERROR("failed to allocate buffer.\n"); - return -ENOMEM; - } + obj->pages = obj->cookie; } DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", @@ -110,15 +106,11 @@ static void exynos_drm_free_buf(struct exynos_drm_gem_obj *obj) DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", (unsigned long)obj->dma_addr, obj->size); - if (!is_drm_iommu_supported(dev)) { - dma_free_attrs(dev->dev, obj->size, obj->cookie, - (dma_addr_t)obj->dma_addr, &obj->dma_attrs); - drm_free_large(obj->pages); - } else - dma_free_attrs(dev->dev, obj->size, obj->pages, - (dma_addr_t)obj->dma_addr, &obj->dma_attrs); + dma_free_attrs(dev->dev, obj->size, obj->cookie, + (dma_addr_t)obj->dma_addr, &obj->dma_attrs); - obj->dma_addr = (dma_addr_t)NULL; + if (!is_drm_iommu_supported(dev)) + drm_free_large(obj->pages); } static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, @@ -156,18 +148,14 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj) * once dmabuf's refcount becomes 0. */ if (obj->import_attach) - goto out; - - exynos_drm_free_buf(exynos_gem_obj); - -out: - drm_gem_free_mmap_offset(obj); + drm_prime_gem_destroy(obj, exynos_gem_obj->sgt); + else + exynos_drm_free_buf(exynos_gem_obj); /* release file pointer to gem object. */ drm_gem_object_release(obj); kfree(exynos_gem_obj); - exynos_gem_obj = NULL; } unsigned long exynos_drm_gem_get_size(struct drm_device *dev, @@ -190,8 +178,7 @@ unsigned long exynos_drm_gem_get_size(struct drm_device *dev, return exynos_gem_obj->size; } - -struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, +static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, unsigned long size) { struct exynos_drm_gem_obj *exynos_gem_obj; @@ -212,6 +199,13 @@ struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, return ERR_PTR(ret); } + ret = drm_gem_create_mmap_offset(obj); + if (ret < 0) { + drm_gem_object_release(obj); + kfree(exynos_gem_obj); + return ERR_PTR(ret); + } + DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); return exynos_gem_obj; @@ -313,7 +307,7 @@ void exynos_drm_gem_put_dma_addr(struct drm_device *dev, drm_gem_object_unreference_unlocked(obj); } -int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, +static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, struct vm_area_struct *vma) { struct drm_device *drm_dev = exynos_gem_obj->base.dev; @@ -342,7 +336,8 @@ int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ struct exynos_drm_gem_obj *exynos_gem_obj; +{ + struct exynos_drm_gem_obj *exynos_gem_obj; struct drm_exynos_gem_info *args = data; struct drm_gem_object *obj; @@ -402,6 +397,7 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_mode_create_dumb *args) { struct exynos_drm_gem_obj *exynos_gem_obj; + unsigned int flags; int ret; /* @@ -413,16 +409,12 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, args->pitch = args->width * ((args->bpp + 7) / 8); args->size = args->pitch * args->height; - if (is_drm_iommu_supported(dev)) { - exynos_gem_obj = exynos_drm_gem_create(dev, - EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC, - args->size); - } else { - exynos_gem_obj = exynos_drm_gem_create(dev, - EXYNOS_BO_CONTIG | EXYNOS_BO_WC, - args->size); - } + if (is_drm_iommu_supported(dev)) + flags = EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC; + else + flags = EXYNOS_BO_CONTIG | EXYNOS_BO_WC; + exynos_gem_obj = exynos_drm_gem_create(dev, flags, args->size); if (IS_ERR(exynos_gem_obj)) { dev_warn(dev->dev, "FB allocation failed.\n"); return PTR_ERR(exynos_gem_obj); @@ -460,14 +452,9 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, goto unlock; } - ret = drm_gem_create_mmap_offset(obj); - if (ret) - goto out; - *offset = drm_vma_node_offset_addr(&obj->vma_node); DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset); -out: drm_gem_object_unreference(obj); unlock: mutex_unlock(&dev->struct_mutex); @@ -543,7 +530,6 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) err_close_vm: drm_gem_vm_close(vma); - drm_gem_free_mmap_offset(obj); return ret; } @@ -588,6 +574,8 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, if (ret < 0) goto err_free_large; + exynos_gem_obj->sgt = sgt; + if (sgt->nents == 1) { /* always physically continuous memory if sgt->nents is 1. */ exynos_gem_obj->flags |= EXYNOS_BO_CONTIG; diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index cd62f8410d1e..b62d1007c0e0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -39,6 +39,7 @@ * - this address could be physical address without IOMMU and * device address with IOMMU. * @pages: Array of backing pages. + * @sgt: Imported sg_table. * * P.S. this object would be transferred to user as kms_bo.handle so * user can access the buffer through kms_bo.handle. @@ -52,6 +53,7 @@ struct exynos_drm_gem_obj { dma_addr_t dma_addr; struct dma_attrs dma_attrs; struct page **pages; + struct sg_table *sgt; }; struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); @@ -59,10 +61,6 @@ struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); /* destroy a buffer with gem object */ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj); -/* create a private gem object and initialize it. */ -struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, - unsigned long size); - /* create a new buffer with gem object */ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, unsigned int flags, diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c index 425e70625388..2f5c118f4c8e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c @@ -786,6 +786,7 @@ static int rotator_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM static int rotator_clk_crtl(struct rot_context *rot, bool enable) { if (enable) { @@ -822,7 +823,6 @@ static int rotator_resume(struct device *dev) } #endif -#ifdef CONFIG_PM static int rotator_runtime_suspend(struct device *dev) { struct rot_context *rot = dev_get_drvdata(dev); diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index 9a8e2da47158..1930234ba5f1 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c @@ -140,7 +140,7 @@ static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg) return IRQ_HANDLED; } -static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, int crtc) +static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; unsigned int value; @@ -156,7 +156,8 @@ static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, int crtc) return 0; } -static void fsl_dcu_drm_disable_vblank(struct drm_device *dev, int crtc) +static void fsl_dcu_drm_disable_vblank(struct drm_device *dev, + unsigned int pipe) { struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; unsigned int value; @@ -192,7 +193,7 @@ static struct drm_driver fsl_dcu_drm_driver = { .unload = fsl_dcu_unload, .preclose = fsl_dcu_drm_preclose, .irq_handler = fsl_dcu_drm_irq, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = fsl_dcu_drm_enable_vblank, .disable_vblank = fsl_dcu_drm_disable_vblank, .gem_free_object = drm_gem_cma_free_object, diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index e38057b91865..e21726ecac32 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -687,15 +687,15 @@ extern void psb_irq_turn_off_dpst(struct drm_device *dev); extern void psb_irq_uninstall_islands(struct drm_device *dev, int hw_islands); extern int psb_vblank_wait2(struct drm_device *dev, unsigned int *sequence); extern int psb_vblank_wait(struct drm_device *dev, unsigned int *sequence); -extern int psb_enable_vblank(struct drm_device *dev, int crtc); -extern void psb_disable_vblank(struct drm_device *dev, int crtc); +extern int psb_enable_vblank(struct drm_device *dev, unsigned int pipe); +extern void psb_disable_vblank(struct drm_device *dev, unsigned int pipe); void psb_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask); void psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask); -extern u32 psb_get_vblank_counter(struct drm_device *dev, int crtc); +extern u32 psb_get_vblank_counter(struct drm_device *dev, unsigned int pipe); /* framebuffer.c */ extern int psbfb_probed(struct drm_device *dev); diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c index 624eb36511c5..78eb10902809 100644 --- a/drivers/gpu/drm/gma500/psb_irq.c +++ b/drivers/gpu/drm/gma500/psb_irq.c @@ -510,7 +510,7 @@ int psb_irq_disable_dpst(struct drm_device *dev) /* * It is used to enable VBLANK interrupt */ -int psb_enable_vblank(struct drm_device *dev, int pipe) +int psb_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct drm_psb_private *dev_priv = dev->dev_private; unsigned long irqflags; @@ -549,7 +549,7 @@ int psb_enable_vblank(struct drm_device *dev, int pipe) /* * It is used to disable VBLANK interrupt */ -void psb_disable_vblank(struct drm_device *dev, int pipe) +void psb_disable_vblank(struct drm_device *dev, unsigned int pipe) { struct drm_psb_private *dev_priv = dev->dev_private; unsigned long irqflags; @@ -622,7 +622,7 @@ void mdfld_disable_te(struct drm_device *dev, int pipe) /* Called from drm generic code, passed a 'crtc', which * we use as a pipe index */ -u32 psb_get_vblank_counter(struct drm_device *dev, int pipe) +u32 psb_get_vblank_counter(struct drm_device *dev, unsigned int pipe) { uint32_t high_frame = PIPEAFRAMEHIGH; uint32_t low_frame = PIPEAFRAMEPIXEL; @@ -654,7 +654,7 @@ u32 psb_get_vblank_counter(struct drm_device *dev, int pipe) reg_val = REG_READ(pipeconf_reg); if (!(reg_val & PIPEACONF_ENABLE)) { - dev_err(dev->dev, "trying to get vblank count for disabled pipe %d\n", + dev_err(dev->dev, "trying to get vblank count for disabled pipe %u\n", pipe); goto psb_get_vblank_counter_exit; } diff --git a/drivers/gpu/drm/gma500/psb_irq.h b/drivers/gpu/drm/gma500/psb_irq.h index d0b45ffa1126..e6a81a8c9f35 100644 --- a/drivers/gpu/drm/gma500/psb_irq.h +++ b/drivers/gpu/drm/gma500/psb_irq.h @@ -38,9 +38,9 @@ int psb_irq_enable_dpst(struct drm_device *dev); int psb_irq_disable_dpst(struct drm_device *dev); void psb_irq_turn_on_dpst(struct drm_device *dev); void psb_irq_turn_off_dpst(struct drm_device *dev); -int psb_enable_vblank(struct drm_device *dev, int pipe); -void psb_disable_vblank(struct drm_device *dev, int pipe); -u32 psb_get_vblank_counter(struct drm_device *dev, int pipe); +int psb_enable_vblank(struct drm_device *dev, unsigned int pipe); +void psb_disable_vblank(struct drm_device *dev, unsigned int pipe); +u32 psb_get_vblank_counter(struct drm_device *dev, unsigned int pipe); int mdfld_enable_te(struct drm_device *dev, int pipe); void mdfld_disable_te(struct drm_device *dev, int pipe); diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 424228be79ae..896b6aaf8c4d 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -23,7 +23,6 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> -#include <drm/drm_encoder_slave.h> #include <drm/drm_edid.h> #include <drm/drm_of.h> #include <drm/i2c/tda998x.h> @@ -34,9 +33,8 @@ struct tda998x_priv { struct i2c_client *cec; struct i2c_client *hdmi; struct mutex mutex; - struct delayed_work dwork; - uint16_t rev; - uint8_t current_page; + u16 rev; + u8 current_page; int dpms; bool is_hdmi_sink; u8 vip_cntrl_0; @@ -46,10 +44,21 @@ struct tda998x_priv { wait_queue_head_t wq_edid; volatile int wq_edid_wait; - struct drm_encoder *encoder; + + struct work_struct detect_work; + struct timer_list edid_delay_timer; + wait_queue_head_t edid_delay_waitq; + bool edid_delay_active; + + struct drm_encoder encoder; + struct drm_connector connector; }; -#define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv) +#define conn_to_tda998x_priv(x) \ + container_of(x, struct tda998x_priv, connector) + +#define enc_to_tda998x_priv(x) \ + container_of(x, struct tda998x_priv, encoder) /* The TDA9988 series of devices use a paged register scheme.. to simplify * things we encode the page # in upper bits of the register #. To read/ @@ -326,6 +335,8 @@ struct tda998x_priv { # define CEC_FRO_IM_CLK_CTRL_FRO_DIV (1 << 0) #define REG_CEC_RXSHPDINTENA 0xfc /* read/write */ #define REG_CEC_RXSHPDINT 0xfd /* read */ +# define CEC_RXSHPDINT_RXSENS BIT(0) +# define CEC_RXSHPDINT_HPD BIT(1) #define REG_CEC_RXSHPDLEV 0xfe /* read */ # define CEC_RXSHPDLEV_RXSENS (1 << 0) # define CEC_RXSHPDLEV_HPD (1 << 1) @@ -345,10 +356,10 @@ struct tda998x_priv { #define TDA19988 0x0301 static void -cec_write(struct tda998x_priv *priv, uint16_t addr, uint8_t val) +cec_write(struct tda998x_priv *priv, u16 addr, u8 val) { struct i2c_client *client = priv->cec; - uint8_t buf[] = {addr, val}; + u8 buf[] = {addr, val}; int ret; ret = i2c_master_send(client, buf, sizeof(buf)); @@ -356,11 +367,11 @@ cec_write(struct tda998x_priv *priv, uint16_t addr, uint8_t val) dev_err(&client->dev, "Error %d writing to cec:0x%x\n", ret, addr); } -static uint8_t -cec_read(struct tda998x_priv *priv, uint8_t addr) +static u8 +cec_read(struct tda998x_priv *priv, u8 addr) { struct i2c_client *client = priv->cec; - uint8_t val; + u8 val; int ret; ret = i2c_master_send(client, &addr, sizeof(addr)); @@ -379,11 +390,11 @@ fail: } static int -set_page(struct tda998x_priv *priv, uint16_t reg) +set_page(struct tda998x_priv *priv, u16 reg) { if (REG2PAGE(reg) != priv->current_page) { struct i2c_client *client = priv->hdmi; - uint8_t buf[] = { + u8 buf[] = { REG_CURPAGE, REG2PAGE(reg) }; int ret = i2c_master_send(client, buf, sizeof(buf)); @@ -399,10 +410,10 @@ set_page(struct tda998x_priv *priv, uint16_t reg) } static int -reg_read_range(struct tda998x_priv *priv, uint16_t reg, char *buf, int cnt) +reg_read_range(struct tda998x_priv *priv, u16 reg, char *buf, int cnt) { struct i2c_client *client = priv->hdmi; - uint8_t addr = REG2ADDR(reg); + u8 addr = REG2ADDR(reg); int ret; mutex_lock(&priv->mutex); @@ -428,10 +439,10 @@ out: } static void -reg_write_range(struct tda998x_priv *priv, uint16_t reg, uint8_t *p, int cnt) +reg_write_range(struct tda998x_priv *priv, u16 reg, u8 *p, int cnt) { struct i2c_client *client = priv->hdmi; - uint8_t buf[cnt+1]; + u8 buf[cnt+1]; int ret; buf[0] = REG2ADDR(reg); @@ -450,9 +461,9 @@ out: } static int -reg_read(struct tda998x_priv *priv, uint16_t reg) +reg_read(struct tda998x_priv *priv, u16 reg) { - uint8_t val = 0; + u8 val = 0; int ret; ret = reg_read_range(priv, reg, &val, sizeof(val)); @@ -462,10 +473,10 @@ reg_read(struct tda998x_priv *priv, uint16_t reg) } static void -reg_write(struct tda998x_priv *priv, uint16_t reg, uint8_t val) +reg_write(struct tda998x_priv *priv, u16 reg, u8 val) { struct i2c_client *client = priv->hdmi; - uint8_t buf[] = {REG2ADDR(reg), val}; + u8 buf[] = {REG2ADDR(reg), val}; int ret; mutex_lock(&priv->mutex); @@ -481,10 +492,10 @@ out: } static void -reg_write16(struct tda998x_priv *priv, uint16_t reg, uint16_t val) +reg_write16(struct tda998x_priv *priv, u16 reg, u16 val) { struct i2c_client *client = priv->hdmi; - uint8_t buf[] = {REG2ADDR(reg), val >> 8, val}; + u8 buf[] = {REG2ADDR(reg), val >> 8, val}; int ret; mutex_lock(&priv->mutex); @@ -500,7 +511,7 @@ out: } static void -reg_set(struct tda998x_priv *priv, uint16_t reg, uint8_t val) +reg_set(struct tda998x_priv *priv, u16 reg, u8 val) { int old_val; @@ -510,7 +521,7 @@ reg_set(struct tda998x_priv *priv, uint16_t reg, uint8_t val) } static void -reg_clear(struct tda998x_priv *priv, uint16_t reg, uint8_t val) +reg_clear(struct tda998x_priv *priv, u16 reg, u8 val) { int old_val; @@ -551,15 +562,50 @@ tda998x_reset(struct tda998x_priv *priv) reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24); } -/* handle HDMI connect/disconnect */ -static void tda998x_hpd(struct work_struct *work) +/* + * The TDA998x has a problem when trying to read the EDID close to a + * HPD assertion: it needs a delay of 100ms to avoid timing out while + * trying to read EDID data. + * + * However, tda998x_encoder_get_modes() may be called at any moment + * after tda998x_connector_detect() indicates that we are connected, so + * we need to delay probing modes in tda998x_encoder_get_modes() after + * we have seen a HPD inactive->active transition. This code implements + * that delay. + */ +static void tda998x_edid_delay_done(unsigned long data) +{ + struct tda998x_priv *priv = (struct tda998x_priv *)data; + + priv->edid_delay_active = false; + wake_up(&priv->edid_delay_waitq); + schedule_work(&priv->detect_work); +} + +static void tda998x_edid_delay_start(struct tda998x_priv *priv) +{ + priv->edid_delay_active = true; + mod_timer(&priv->edid_delay_timer, jiffies + HZ/10); +} + +static int tda998x_edid_delay_wait(struct tda998x_priv *priv) +{ + return wait_event_killable(priv->edid_delay_waitq, !priv->edid_delay_active); +} + +/* + * We need to run the KMS hotplug event helper outside of our threaded + * interrupt routine as this can call back into our get_modes method, + * which will want to make use of interrupts. + */ +static void tda998x_detect_work(struct work_struct *work) { - struct delayed_work *dwork = to_delayed_work(work); struct tda998x_priv *priv = - container_of(dwork, struct tda998x_priv, dwork); + container_of(work, struct tda998x_priv, detect_work); + struct drm_device *dev = priv->encoder.dev; - if (priv->encoder && priv->encoder->dev) - drm_kms_helper_hotplug_event(priv->encoder->dev); + if (dev) + drm_kms_helper_hotplug_event(dev); } /* @@ -569,9 +615,8 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data) { struct tda998x_priv *priv = data; u8 sta, cec, lvl, flag0, flag1, flag2; + bool handled = false; - if (!priv) - return IRQ_HANDLED; sta = cec_read(priv, REG_CEC_INTSTATUS); cec = cec_read(priv, REG_CEC_RXSHPDINT); lvl = cec_read(priv, REG_CEC_RXSHPDLEV); @@ -581,75 +626,76 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data) DRM_DEBUG_DRIVER( "tda irq sta %02x cec %02x lvl %02x f0 %02x f1 %02x f2 %02x\n", sta, cec, lvl, flag0, flag1, flag2); + + if (cec & CEC_RXSHPDINT_HPD) { + if (lvl & CEC_RXSHPDLEV_HPD) + tda998x_edid_delay_start(priv); + else + schedule_work(&priv->detect_work); + + handled = true; + } + if ((flag2 & INT_FLAGS_2_EDID_BLK_RD) && priv->wq_edid_wait) { priv->wq_edid_wait = 0; wake_up(&priv->wq_edid); - } else if (cec != 0) { /* HPD change */ - schedule_delayed_work(&priv->dwork, HZ/10); + handled = true; } - return IRQ_HANDLED; -} -static uint8_t tda998x_cksum(uint8_t *buf, size_t bytes) -{ - int sum = 0; - - while (bytes--) - sum -= *buf++; - return sum; + return IRQ_RETVAL(handled); } -#define HB(x) (x) -#define PB(x) (HB(2) + 1 + (x)) - static void -tda998x_write_if(struct tda998x_priv *priv, uint8_t bit, uint16_t addr, - uint8_t *buf, size_t size) +tda998x_write_if(struct tda998x_priv *priv, u8 bit, u16 addr, + union hdmi_infoframe *frame) { + u8 buf[32]; + ssize_t len; + + len = hdmi_infoframe_pack(frame, buf, sizeof(buf)); + if (len < 0) { + dev_err(&priv->hdmi->dev, + "hdmi_infoframe_pack() type=0x%02x failed: %zd\n", + frame->any.type, len); + return; + } + reg_clear(priv, REG_DIP_IF_FLAGS, bit); - reg_write_range(priv, addr, buf, size); + reg_write_range(priv, addr, buf, len); reg_set(priv, REG_DIP_IF_FLAGS, bit); } static void tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p) { - u8 buf[PB(HDMI_AUDIO_INFOFRAME_SIZE) + 1]; + union hdmi_infoframe frame; + + hdmi_audio_infoframe_init(&frame.audio); - memset(buf, 0, sizeof(buf)); - buf[HB(0)] = HDMI_INFOFRAME_TYPE_AUDIO; - buf[HB(1)] = 0x01; - buf[HB(2)] = HDMI_AUDIO_INFOFRAME_SIZE; - buf[PB(1)] = p->audio_frame[1] & 0x07; /* CC */ - buf[PB(2)] = p->audio_frame[2] & 0x1c; /* SF */ - buf[PB(4)] = p->audio_frame[4]; - buf[PB(5)] = p->audio_frame[5] & 0xf8; /* DM_INH + LSV */ + frame.audio.channels = p->audio_frame[1] & 0x07; + frame.audio.channel_allocation = p->audio_frame[4]; + frame.audio.level_shift_value = (p->audio_frame[5] & 0x78) >> 3; + frame.audio.downmix_inhibit = (p->audio_frame[5] & 0x80) >> 7; - buf[PB(0)] = tda998x_cksum(buf, sizeof(buf)); + /* + * L-PCM and IEC61937 compressed audio shall always set sample + * frequency to "refer to stream". For others, see the HDMI + * specification. + */ + frame.audio.sample_frequency = (p->audio_frame[2] & 0x1c) >> 2; - tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf, - sizeof(buf)); + tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, &frame); } static void tda998x_write_avi(struct tda998x_priv *priv, struct drm_display_mode *mode) { - struct hdmi_avi_infoframe frame; - u8 buf[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; - ssize_t len; + union hdmi_infoframe frame; - drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); + drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode); + frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; - frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; - - len = hdmi_avi_infoframe_pack(&frame, buf, sizeof(buf)); - if (len < 0) { - dev_err(&priv->hdmi->dev, - "hdmi_avi_infoframe_pack() failed: %zd\n", len); - return; - } - - tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, buf, len); + tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, &frame); } static void tda998x_audio_mute(struct tda998x_priv *priv, bool on) @@ -667,8 +713,8 @@ static void tda998x_configure_audio(struct tda998x_priv *priv, struct drm_display_mode *mode, struct tda998x_encoder_params *p) { - uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv; - uint32_t n; + u8 buf[6], clksel_aip, clksel_fs, cts_n, adiv; + u32 n; /* Enable audio ports */ reg_write(priv, REG_ENA_AP, p->audio_cfg); @@ -776,8 +822,10 @@ static void tda998x_encoder_set_config(struct tda998x_priv *priv, priv->params = *p; } -static void tda998x_encoder_dpms(struct tda998x_priv *priv, int mode) +static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode) { + struct tda998x_priv *priv = enc_to_tda998x_priv(encoder); + /* we only care about on or off: */ if (mode != DRM_MODE_DPMS_ON) mode = DRM_MODE_DPMS_OFF; @@ -827,8 +875,8 @@ tda998x_encoder_mode_fixup(struct drm_encoder *encoder, return true; } -static int tda998x_encoder_mode_valid(struct tda998x_priv *priv, - struct drm_display_mode *mode) +static int tda998x_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { if (mode->clock > 150000) return MODE_CLOCK_HIGH; @@ -840,18 +888,19 @@ static int tda998x_encoder_mode_valid(struct tda998x_priv *priv, } static void -tda998x_encoder_mode_set(struct tda998x_priv *priv, +tda998x_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - uint16_t ref_pix, ref_line, n_pix, n_line; - uint16_t hs_pix_s, hs_pix_e; - uint16_t vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e; - uint16_t vs2_pix_s, vs2_pix_e, vs2_line_s, vs2_line_e; - uint16_t vwin1_line_s, vwin1_line_e; - uint16_t vwin2_line_s, vwin2_line_e; - uint16_t de_pix_s, de_pix_e; - uint8_t reg, div, rep; + struct tda998x_priv *priv = enc_to_tda998x_priv(encoder); + u16 ref_pix, ref_line, n_pix, n_line; + u16 hs_pix_s, hs_pix_e; + u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e; + u16 vs2_pix_s, vs2_pix_e, vs2_line_s, vs2_line_e; + u16 vwin1_line_s, vwin1_line_e; + u16 vwin2_line_s, vwin2_line_e; + u16 de_pix_s, de_pix_e; + u8 reg, div, rep; /* * Internally TDA998x is using ITU-R BT.656 style sync but @@ -1031,9 +1080,10 @@ tda998x_encoder_mode_set(struct tda998x_priv *priv, } static enum drm_connector_status -tda998x_encoder_detect(struct tda998x_priv *priv) +tda998x_connector_detect(struct drm_connector *connector, bool force) { - uint8_t val = cec_read(priv, REG_CEC_RXSHPDLEV); + struct tda998x_priv *priv = conn_to_tda998x_priv(connector); + u8 val = cec_read(priv, REG_CEC_RXSHPDLEV); return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected : connector_status_disconnected; @@ -1042,7 +1092,7 @@ tda998x_encoder_detect(struct tda998x_priv *priv) static int read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length) { struct tda998x_priv *priv = data; - uint8_t offset, segptr; + u8 offset, segptr; int ret, i; offset = (blk & 1) ? 128 : 0; @@ -1095,13 +1145,20 @@ static int read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length) return 0; } -static int -tda998x_encoder_get_modes(struct tda998x_priv *priv, - struct drm_connector *connector) +static int tda998x_connector_get_modes(struct drm_connector *connector) { + struct tda998x_priv *priv = conn_to_tda998x_priv(connector); struct edid *edid; int n; + /* + * If we get killed while waiting for the HPD timeout, return + * no modes found: we are not in a restartable path, so we + * can't handle signals gracefully. + */ + if (tda998x_edid_delay_wait(priv)) + return 0; + if (priv->rev == TDA19988) reg_clear(priv, REG_TX4, TX4_PD_RAM); @@ -1133,101 +1190,21 @@ static void tda998x_encoder_set_polling(struct tda998x_priv *priv, DRM_CONNECTOR_POLL_DISCONNECT; } -static int -tda998x_encoder_set_property(struct drm_encoder *encoder, - struct drm_connector *connector, - struct drm_property *property, - uint64_t val) -{ - DBG(""); - return 0; -} - static void tda998x_destroy(struct tda998x_priv *priv) { /* disable all IRQs and free the IRQ handler */ cec_write(priv, REG_CEC_RXSHPDINTENA, 0); reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); - if (priv->hdmi->irq) { - free_irq(priv->hdmi->irq, priv); - cancel_delayed_work_sync(&priv->dwork); - } - - i2c_unregister_device(priv->cec); -} - -/* Slave encoder support */ - -static void -tda998x_encoder_slave_set_config(struct drm_encoder *encoder, void *params) -{ - tda998x_encoder_set_config(to_tda998x_priv(encoder), params); -} -static void tda998x_encoder_slave_destroy(struct drm_encoder *encoder) -{ - struct tda998x_priv *priv = to_tda998x_priv(encoder); - - tda998x_destroy(priv); - drm_i2c_encoder_destroy(encoder); - kfree(priv); -} - -static void tda998x_encoder_slave_dpms(struct drm_encoder *encoder, int mode) -{ - tda998x_encoder_dpms(to_tda998x_priv(encoder), mode); -} - -static int tda998x_encoder_slave_mode_valid(struct drm_encoder *encoder, - struct drm_display_mode *mode) -{ - return tda998x_encoder_mode_valid(to_tda998x_priv(encoder), mode); -} + if (priv->hdmi->irq) + free_irq(priv->hdmi->irq, priv); -static void -tda998x_encoder_slave_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - tda998x_encoder_mode_set(to_tda998x_priv(encoder), mode, adjusted_mode); -} + del_timer_sync(&priv->edid_delay_timer); + cancel_work_sync(&priv->detect_work); -static enum drm_connector_status -tda998x_encoder_slave_detect(struct drm_encoder *encoder, - struct drm_connector *connector) -{ - return tda998x_encoder_detect(to_tda998x_priv(encoder)); -} - -static int tda998x_encoder_slave_get_modes(struct drm_encoder *encoder, - struct drm_connector *connector) -{ - return tda998x_encoder_get_modes(to_tda998x_priv(encoder), connector); -} - -static int -tda998x_encoder_slave_create_resources(struct drm_encoder *encoder, - struct drm_connector *connector) -{ - tda998x_encoder_set_polling(to_tda998x_priv(encoder), connector); - return 0; + i2c_unregister_device(priv->cec); } -static struct drm_encoder_slave_funcs tda998x_encoder_slave_funcs = { - .set_config = tda998x_encoder_slave_set_config, - .destroy = tda998x_encoder_slave_destroy, - .dpms = tda998x_encoder_slave_dpms, - .save = tda998x_encoder_save, - .restore = tda998x_encoder_restore, - .mode_fixup = tda998x_encoder_mode_fixup, - .mode_valid = tda998x_encoder_slave_mode_valid, - .mode_set = tda998x_encoder_slave_mode_set, - .detect = tda998x_encoder_slave_detect, - .get_modes = tda998x_encoder_slave_get_modes, - .create_resources = tda998x_encoder_slave_create_resources, - .set_property = tda998x_encoder_set_property, -}; - /* I2C driver functions */ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) @@ -1252,6 +1229,10 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) priv->dpms = DRM_MODE_DPMS_OFF; mutex_init(&priv->mutex); /* protect the page access */ + init_waitqueue_head(&priv->edid_delay_waitq); + setup_timer(&priv->edid_delay_timer, tda998x_edid_delay_done, + (unsigned long)priv); + INIT_WORK(&priv->detect_work, tda998x_detect_work); /* wake up the device: */ cec_write(priv, REG_CEC_ENAMODS, @@ -1310,7 +1291,6 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) /* init read EDID waitqueue and HDP work */ init_waitqueue_head(&priv->wq_edid); - INIT_DELAYED_WORK(&priv->dwork, tda998x_hpd); /* clear pending interrupts */ reg_read(priv, REG_INT_FLAGS_0); @@ -1359,84 +1339,31 @@ fail: return -ENXIO; } -static int tda998x_encoder_init(struct i2c_client *client, - struct drm_device *dev, - struct drm_encoder_slave *encoder_slave) -{ - struct tda998x_priv *priv; - int ret; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->encoder = &encoder_slave->base; - - ret = tda998x_create(client, priv); - if (ret) { - kfree(priv); - return ret; - } - - encoder_slave->slave_priv = priv; - encoder_slave->slave_funcs = &tda998x_encoder_slave_funcs; - - return 0; -} - -struct tda998x_priv2 { - struct tda998x_priv base; - struct drm_encoder encoder; - struct drm_connector connector; -}; - -#define conn_to_tda998x_priv2(x) \ - container_of(x, struct tda998x_priv2, connector); - -#define enc_to_tda998x_priv2(x) \ - container_of(x, struct tda998x_priv2, encoder); - -static void tda998x_encoder2_dpms(struct drm_encoder *encoder, int mode) -{ - struct tda998x_priv2 *priv = enc_to_tda998x_priv2(encoder); - - tda998x_encoder_dpms(&priv->base, mode); -} - static void tda998x_encoder_prepare(struct drm_encoder *encoder) { - tda998x_encoder2_dpms(encoder, DRM_MODE_DPMS_OFF); + tda998x_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); } static void tda998x_encoder_commit(struct drm_encoder *encoder) { - tda998x_encoder2_dpms(encoder, DRM_MODE_DPMS_ON); -} - -static void tda998x_encoder2_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct tda998x_priv2 *priv = enc_to_tda998x_priv2(encoder); - - tda998x_encoder_mode_set(&priv->base, mode, adjusted_mode); + tda998x_encoder_dpms(encoder, DRM_MODE_DPMS_ON); } static const struct drm_encoder_helper_funcs tda998x_encoder_helper_funcs = { - .dpms = tda998x_encoder2_dpms, + .dpms = tda998x_encoder_dpms, .save = tda998x_encoder_save, .restore = tda998x_encoder_restore, .mode_fixup = tda998x_encoder_mode_fixup, .prepare = tda998x_encoder_prepare, .commit = tda998x_encoder_commit, - .mode_set = tda998x_encoder2_mode_set, + .mode_set = tda998x_encoder_mode_set, }; static void tda998x_encoder_destroy(struct drm_encoder *encoder) { - struct tda998x_priv2 *priv = enc_to_tda998x_priv2(encoder); + struct tda998x_priv *priv = enc_to_tda998x_priv(encoder); - tda998x_destroy(&priv->base); + tda998x_destroy(priv); drm_encoder_cleanup(encoder); } @@ -1444,25 +1371,10 @@ static const struct drm_encoder_funcs tda998x_encoder_funcs = { .destroy = tda998x_encoder_destroy, }; -static int tda998x_connector_get_modes(struct drm_connector *connector) -{ - struct tda998x_priv2 *priv = conn_to_tda998x_priv2(connector); - - return tda998x_encoder_get_modes(&priv->base, connector); -} - -static int tda998x_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - struct tda998x_priv2 *priv = conn_to_tda998x_priv2(connector); - - return tda998x_encoder_mode_valid(&priv->base, mode); -} - static struct drm_encoder * tda998x_connector_best_encoder(struct drm_connector *connector) { - struct tda998x_priv2 *priv = conn_to_tda998x_priv2(connector); + struct tda998x_priv *priv = conn_to_tda998x_priv(connector); return &priv->encoder; } @@ -1474,14 +1386,6 @@ const struct drm_connector_helper_funcs tda998x_connector_helper_funcs = { .best_encoder = tda998x_connector_best_encoder, }; -static enum drm_connector_status -tda998x_connector_detect(struct drm_connector *connector, bool force) -{ - struct tda998x_priv2 *priv = conn_to_tda998x_priv2(connector); - - return tda998x_encoder_detect(&priv->base); -} - static void tda998x_connector_destroy(struct drm_connector *connector) { drm_connector_unregister(connector); @@ -1500,8 +1404,8 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data) struct tda998x_encoder_params *params = dev->platform_data; struct i2c_client *client = to_i2c_client(dev); struct drm_device *drm = data; - struct tda998x_priv2 *priv; - uint32_t crtcs = 0; + struct tda998x_priv *priv; + u32 crtcs = 0; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -1519,18 +1423,17 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data) crtcs = 1 << 0; } - priv->base.encoder = &priv->encoder; priv->connector.interlace_allowed = 1; priv->encoder.possible_crtcs = crtcs; - ret = tda998x_create(client, &priv->base); + ret = tda998x_create(client, priv); if (ret) return ret; if (!dev->of_node && params) - tda998x_encoder_set_config(&priv->base, params); + tda998x_encoder_set_config(priv, params); - tda998x_encoder_set_polling(&priv->base, &priv->connector); + tda998x_encoder_set_polling(priv, &priv->connector); drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs); ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs, @@ -1560,18 +1463,18 @@ err_sysfs: err_connector: drm_encoder_cleanup(&priv->encoder); err_encoder: - tda998x_destroy(&priv->base); + tda998x_destroy(priv); return ret; } static void tda998x_unbind(struct device *dev, struct device *master, void *data) { - struct tda998x_priv2 *priv = dev_get_drvdata(dev); + struct tda998x_priv *priv = dev_get_drvdata(dev); drm_connector_cleanup(&priv->connector); drm_encoder_cleanup(&priv->encoder); - tda998x_destroy(&priv->base); + tda998x_destroy(priv); } static const struct component_ops tda998x_ops = { @@ -1605,38 +1508,18 @@ static struct i2c_device_id tda998x_ids[] = { }; MODULE_DEVICE_TABLE(i2c, tda998x_ids); -static struct drm_i2c_encoder_driver tda998x_driver = { - .i2c_driver = { - .probe = tda998x_probe, - .remove = tda998x_remove, - .driver = { - .name = "tda998x", - .of_match_table = of_match_ptr(tda998x_dt_ids), - }, - .id_table = tda998x_ids, +static struct i2c_driver tda998x_driver = { + .probe = tda998x_probe, + .remove = tda998x_remove, + .driver = { + .name = "tda998x", + .of_match_table = of_match_ptr(tda998x_dt_ids), }, - .encoder_init = tda998x_encoder_init, + .id_table = tda998x_ids, }; -/* Module initialization */ - -static int __init -tda998x_init(void) -{ - DBG(""); - return drm_i2c_encoder_register(THIS_MODULE, &tda998x_driver); -} - -static void __exit -tda998x_exit(void) -{ - DBG(""); - drm_i2c_encoder_unregister(&tda998x_driver); -} +module_i2c_driver(tda998x_driver); MODULE_AUTHOR("Rob Clark <robdclark@gmail.com"); MODULE_DESCRIPTION("NXP Semiconductors TDA998X HDMI Encoder"); MODULE_LICENSE("GPL"); - -module_init(tda998x_init); -module_exit(tda998x_exit); diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 1676388a62df..a3b22bdacd44 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -956,7 +956,6 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data) if (ret) return ret; - seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start); seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs); for (i = 0; i < dev_priv->num_fence_regs; i++) { struct drm_i915_gem_object *obj = dev_priv->fence_regs[i].obj; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 499060a08d25..2336af92d94b 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -75,7 +75,7 @@ static int i915_getparam(struct drm_device *dev, void *data, value = 1; break; case I915_PARAM_NUM_FENCES_AVAIL: - value = dev_priv->num_fence_regs - dev_priv->fence_reg_start; + value = dev_priv->num_fence_regs; break; case I915_PARAM_HAS_OVERLAY: value = dev_priv->overlay ? 1 : 0; @@ -183,35 +183,6 @@ static int i915_getparam(struct drm_device *dev, void *data, return 0; } -static int i915_setparam(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - drm_i915_setparam_t *param = data; - - switch (param->param) { - case I915_SETPARAM_USE_MI_BATCHBUFFER_START: - case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY: - case I915_SETPARAM_ALLOW_BATCHBUFFER: - /* Reject all old ums/dri params. */ - return -ENODEV; - - case I915_SETPARAM_NUM_USED_FENCES: - if (param->value > dev_priv->num_fence_regs || - param->value < 0) - return -EINVAL; - /* Userspace can use first N regs */ - dev_priv->fence_reg_start = param->value; - break; - default: - DRM_DEBUG_DRIVER("unknown parameter %d\n", - param->param); - return -EINVAL; - } - - return 0; -} - static int i915_get_bridge_dev(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1318,7 +1289,7 @@ const struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_IRQ_EMIT, drm_noop, DRM_AUTH), DRM_IOCTL_DEF_DRV(I915_IRQ_WAIT, drm_noop, DRM_AUTH), DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam, DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_SETPARAM, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF_DRV(I915_ALLOC, drm_noop, DRM_AUTH), DRM_IOCTL_DEF_DRV(I915_FREE, drm_noop, DRM_AUTH), DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -1328,41 +1299,41 @@ const struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_GET_VBLANK_PIPE, drm_noop, DRM_AUTH), DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, drm_noop, DRM_AUTH), DRM_IOCTL_DEF_DRV(I915_HWS_ADDR, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(I915_GEM_CREATE, i915_gem_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_GEM_CREATE, i915_gem_create_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0), + DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_RENDER_ALLOW), }; int i915_max_ioctl = ARRAY_SIZE(i915_ioctls); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index dd0429c612a4..8afda459a26e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1786,7 +1786,6 @@ struct drm_i915_private { struct mutex pps_mutex; struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */ - int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ int num_fence_regs; /* 8 on pre-965, 16 otherwise */ unsigned int fsb_freq, mem_freq, is_ddr3; diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c index 1cbfd5b83135..40a10b25956c 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence.c +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -317,7 +317,7 @@ i915_find_fence_reg(struct drm_device *dev) /* First try to find a free reg */ avail = NULL; - for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { + for (i = 0; i < dev_priv->num_fence_regs; i++) { reg = &dev_priv->fence_regs[i]; if (!reg->obj) return reg; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e24378ee7eda..d68328fa175b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -653,7 +653,7 @@ static void i915_enable_asle_pipestat(struct drm_device *dev) * of horizontal active on the first line of vertical active */ -static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe) +static u32 i8xx_get_vblank_counter(struct drm_device *dev, unsigned int pipe) { /* Gen2 doesn't have a hardware frame counter */ return 0; @@ -662,7 +662,7 @@ static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe) /* Called from drm generic code, passed a 'crtc', which * we use as a pipe index */ -static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) +static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long high_frame; @@ -710,7 +710,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff; } -static u32 g4x_get_vblank_counter(struct drm_device *dev, int pipe) +static u32 g4x_get_vblank_counter(struct drm_device *dev, unsigned int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -770,7 +770,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) return (position + crtc->scanline_offset) % vtotal; } -static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, +static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, unsigned int flags, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode) @@ -907,27 +907,27 @@ int intel_get_crtc_scanline(struct intel_crtc *crtc) return position; } -static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, +static int i915_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe, int *max_error, struct timeval *vblank_time, unsigned flags) { struct drm_crtc *crtc; - if (pipe < 0 || pipe >= INTEL_INFO(dev)->num_pipes) { - DRM_ERROR("Invalid crtc %d\n", pipe); + if (pipe >= INTEL_INFO(dev)->num_pipes) { + DRM_ERROR("Invalid crtc %u\n", pipe); return -EINVAL; } /* Get drm_crtc to timestamp: */ crtc = intel_get_crtc_for_pipe(dev, pipe); if (crtc == NULL) { - DRM_ERROR("Invalid crtc %d\n", pipe); + DRM_ERROR("Invalid crtc %u\n", pipe); return -EINVAL; } if (!crtc->hwmode.crtc_clock) { - DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); + DRM_DEBUG_KMS("crtc %u is disabled\n", pipe); return -EBUSY; } @@ -2619,7 +2619,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged, /* Called from drm generic code, passed 'crtc' which * we use as a pipe index */ -static int i915_enable_vblank(struct drm_device *dev, int pipe) +static int i915_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; @@ -2636,7 +2636,7 @@ static int i915_enable_vblank(struct drm_device *dev, int pipe) return 0; } -static int ironlake_enable_vblank(struct drm_device *dev, int pipe) +static int ironlake_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; @@ -2650,7 +2650,7 @@ static int ironlake_enable_vblank(struct drm_device *dev, int pipe) return 0; } -static int valleyview_enable_vblank(struct drm_device *dev, int pipe) +static int valleyview_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; @@ -2663,7 +2663,7 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe) return 0; } -static int gen8_enable_vblank(struct drm_device *dev, int pipe) +static int gen8_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; @@ -2679,7 +2679,7 @@ static int gen8_enable_vblank(struct drm_device *dev, int pipe) /* Called from drm generic code, passed 'crtc' which * we use as a pipe index */ -static void i915_disable_vblank(struct drm_device *dev, int pipe) +static void i915_disable_vblank(struct drm_device *dev, unsigned int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; @@ -2691,7 +2691,7 @@ static void i915_disable_vblank(struct drm_device *dev, int pipe) spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } -static void ironlake_disable_vblank(struct drm_device *dev, int pipe) +static void ironlake_disable_vblank(struct drm_device *dev, unsigned int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; @@ -2703,7 +2703,7 @@ static void ironlake_disable_vblank(struct drm_device *dev, int pipe) spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } -static void valleyview_disable_vblank(struct drm_device *dev, int pipe) +static void valleyview_disable_vblank(struct drm_device *dev, unsigned int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; @@ -2714,7 +2714,7 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe) spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } -static void gen8_disable_vblank(struct drm_device *dev, int pipe) +static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 15372598b2c3..0639275fc471 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -458,11 +458,17 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); drm_mode_connector_set_path_property(connector, pathprop); + return connector; +} + +static void intel_dp_register_mst_connector(struct drm_connector *connector) +{ + struct intel_connector *intel_connector = to_intel_connector(connector); + struct drm_device *dev = connector->dev; drm_modeset_lock_all(dev); intel_connector_add_to_fbdev(intel_connector); drm_modeset_unlock_all(dev); drm_connector_register(&intel_connector->base); - return connector; } static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, @@ -508,6 +514,7 @@ static void intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) static struct drm_dp_mst_topology_cbs mst_cbs = { .add_connector = intel_dp_add_mst_connector, + .register_connector = intel_dp_register_mst_connector, .destroy_connector = intel_dp_destroy_mst_connector, .hotplug = intel_dp_mst_hotplug, }; diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 53c0173a39fe..b17785719598 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -180,7 +180,7 @@ static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv) /* Enable polling and queue hotplug re-enabling. */ if (hpd_disabled) { - drm_kms_helper_poll_enable(dev); + drm_kms_helper_poll_enable_locked(dev); mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work, msecs_to_jiffies(HPD_STORM_REENABLE_DELAY)); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 1bb1c9c8126e..efb704ba248b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -511,16 +511,16 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring) status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring)); read_pointer = ring->next_context_status_buffer; - write_pointer = status_pointer & 0x07; + write_pointer = status_pointer & GEN8_CSB_PTR_MASK; if (read_pointer > write_pointer) - write_pointer += 6; + write_pointer += GEN8_CSB_ENTRIES; spin_lock(&ring->execlist_lock); while (read_pointer < write_pointer) { read_pointer++; - status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % 6)); - status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % 6)); + status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % GEN8_CSB_ENTRIES)); + status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % GEN8_CSB_ENTRIES)); if (status & GEN8_CTX_STATUS_IDLE_ACTIVE) continue; @@ -552,10 +552,12 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring) spin_unlock(&ring->execlist_lock); WARN(submit_contexts > 2, "More than two context complete events?\n"); - ring->next_context_status_buffer = write_pointer % 6; + ring->next_context_status_buffer = write_pointer % GEN8_CSB_ENTRIES; I915_WRITE(RING_CONTEXT_STATUS_PTR(ring), - _MASKED_FIELD(0x07 << 8, ((u32)ring->next_context_status_buffer & 0x07) << 8)); + _MASKED_FIELD(GEN8_CSB_PTR_MASK << 8, + ((u32)ring->next_context_status_buffer & + GEN8_CSB_PTR_MASK) << 8)); } static int execlists_context_queue(struct drm_i915_gem_request *request) @@ -1462,6 +1464,7 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) { struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; + u8 next_context_status_buffer_hw; lrc_setup_hardware_status_page(ring, ring->default_context->engine[ring->id].state); @@ -1479,7 +1482,29 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) | _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); POSTING_READ(RING_MODE_GEN7(ring)); - ring->next_context_status_buffer = 0; + + /* + * Instead of resetting the Context Status Buffer (CSB) read pointer to + * zero, we need to read the write pointer from hardware and use its + * value because "this register is power context save restored". + * Effectively, these states have been observed: + * + * | Suspend-to-idle (freeze) | Suspend-to-RAM (mem) | + * BDW | CSB regs not reset | CSB regs reset | + * CHT | CSB regs not reset | CSB regs not reset | + */ + next_context_status_buffer_hw = (I915_READ(RING_CONTEXT_STATUS_PTR(ring)) + & GEN8_CSB_PTR_MASK); + + /* + * When the CSB registers are reset (also after power-up / gpu reset), + * CSB write pointer is set to all 1's, which is not valid, use '5' in + * this special case, so the first element read is CSB[0]. + */ + if (next_context_status_buffer_hw == GEN8_CSB_PTR_MASK) + next_context_status_buffer_hw = (GEN8_CSB_ENTRIES - 1); + + ring->next_context_status_buffer = next_context_status_buffer_hw; DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name); memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 8a08a2780321..4e60d54ba66d 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -25,6 +25,8 @@ #define _INTEL_LRC_H_ #define GEN8_LR_CONTEXT_ALIGN 4096 +#define GEN8_CSB_ENTRIES 6 +#define GEN8_CSB_PTR_MASK 0x07 /* Execlists regs */ #define RING_ELSP(ring) ((ring)->mmio_base+0x230) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 0cfe4c14866a..ec010ee74050 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -246,7 +246,8 @@ static void skl_power_well_post_enable(struct drm_i915_private *dev_priv, } if (power_well->data == SKL_DISP_PW_1) { - intel_prepare_ddi(dev); + if (!dev_priv->power_domains.initializing) + intel_prepare_ddi(dev); gen8_irq_power_well_post_enable(dev_priv, 1 << PIPE_A); } } diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 74f505b0dd02..de00a6c31ab6 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -145,10 +145,10 @@ void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc) } EXPORT_SYMBOL_GPL(imx_drm_handle_vblank); -static int imx_drm_enable_vblank(struct drm_device *drm, int crtc) +static int imx_drm_enable_vblank(struct drm_device *drm, unsigned int pipe) { struct imx_drm_device *imxdrm = drm->dev_private; - struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc]; + struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe]; int ret; if (!imx_drm_crtc) @@ -163,10 +163,10 @@ static int imx_drm_enable_vblank(struct drm_device *drm, int crtc) return ret; } -static void imx_drm_disable_vblank(struct drm_device *drm, int crtc) +static void imx_drm_disable_vblank(struct drm_device *drm, unsigned int pipe) { struct imx_drm_device *imxdrm = drm->dev_private; - struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc]; + struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe]; if (!imx_drm_crtc) return; @@ -487,7 +487,7 @@ static struct drm_driver imx_drm_driver = { .gem_prime_vmap = drm_gem_cma_prime_vmap, .gem_prime_vunmap = drm_gem_cma_prime_vunmap, .gem_prime_mmap = drm_gem_cma_prime_mmap, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = imx_drm_enable_vblank, .disable_vblank = imx_drm_disable_vblank, .ioctls = imx_drm_ioctls, diff --git a/drivers/gpu/drm/mga/mga_dma.c b/drivers/gpu/drm/mga/mga_dma.c index 8cfa9cb74c86..1f2f9ca25901 100644 --- a/drivers/gpu/drm/mga/mga_dma.c +++ b/drivers/gpu/drm/mga/mga_dma.c @@ -416,7 +416,7 @@ int mga_driver_load(struct drm_device *dev, unsigned long flags) return 0; } -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) /** * Bootstrap the driver for AGP DMA. * @@ -947,7 +947,7 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup) drm_legacy_ioremapfree(dev->agp_buffer_map, dev); if (dev_priv->used_new_dma_init) { -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->agp_handle != 0) { struct drm_agp_binding unbind_req; struct drm_agp_buffer free_req; diff --git a/drivers/gpu/drm/mga/mga_drv.h b/drivers/gpu/drm/mga/mga_drv.h index b4a2014917e5..bb312339e0b0 100644 --- a/drivers/gpu/drm/mga/mga_drv.h +++ b/drivers/gpu/drm/mga/mga_drv.h @@ -183,9 +183,9 @@ extern int mga_warp_install_microcode(drm_mga_private_t *dev_priv); extern int mga_warp_init(drm_mga_private_t *dev_priv); /* mga_irq.c */ -extern int mga_enable_vblank(struct drm_device *dev, int crtc); -extern void mga_disable_vblank(struct drm_device *dev, int crtc); -extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc); +extern int mga_enable_vblank(struct drm_device *dev, unsigned int pipe); +extern void mga_disable_vblank(struct drm_device *dev, unsigned int pipe); +extern u32 mga_get_vblank_counter(struct drm_device *dev, unsigned int pipe); extern int mga_driver_fence_wait(struct drm_device *dev, unsigned int *sequence); extern int mga_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence); extern irqreturn_t mga_driver_irq_handler(int irq, void *arg); diff --git a/drivers/gpu/drm/mga/mga_irq.c b/drivers/gpu/drm/mga/mga_irq.c index 1b071b8ff9dc..693ba708cfed 100644 --- a/drivers/gpu/drm/mga/mga_irq.c +++ b/drivers/gpu/drm/mga/mga_irq.c @@ -35,12 +35,12 @@ #include <drm/mga_drm.h> #include "mga_drv.h" -u32 mga_get_vblank_counter(struct drm_device *dev, int crtc) +u32 mga_get_vblank_counter(struct drm_device *dev, unsigned int pipe) { const drm_mga_private_t *const dev_priv = (drm_mga_private_t *) dev->dev_private; - if (crtc != 0) + if (pipe != 0) return 0; return atomic_read(&dev_priv->vbl_received); @@ -88,13 +88,13 @@ irqreturn_t mga_driver_irq_handler(int irq, void *arg) return IRQ_NONE; } -int mga_enable_vblank(struct drm_device *dev, int crtc) +int mga_enable_vblank(struct drm_device *dev, unsigned int pipe) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - if (crtc != 0) { - DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", - crtc); + if (pipe != 0) { + DRM_ERROR("tried to enable vblank on non-existent crtc %u\n", + pipe); return 0; } @@ -103,11 +103,11 @@ int mga_enable_vblank(struct drm_device *dev, int crtc) } -void mga_disable_vblank(struct drm_device *dev, int crtc) +void mga_disable_vblank(struct drm_device *dev, unsigned int pipe) { - if (crtc != 0) { - DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", - crtc); + if (pipe != 0) { + DRM_ERROR("tried to disable vblank on non-existent crtc %u\n", + pipe); } /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 8e6c7c638e24..84d3ec98e6b9 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -14,20 +14,6 @@ config DRM_MSM help DRM/KMS driver for MSM/snapdragon. -config DRM_MSM_FBDEV - bool "Enable legacy fbdev support for MSM modesetting driver" - depends on DRM_MSM - select DRM_KMS_FB_HELPER - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - default y - help - Choose this option if you have a need for the legacy fbdev - support. Note that this support also provide the linux console - support on top of the MSM modesetting driver. - config DRM_MSM_REGISTER_LOGGING bool "MSM DRM register logging" depends on DRM_MSM diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 0a543eb5e5d7..1c90290be716 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -50,7 +50,7 @@ msm-y := \ msm_rd.o \ msm_ringbuffer.o -msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o +msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \ diff --git a/drivers/gpu/drm/msm/adreno/a2xx.xml.h b/drivers/gpu/drm/msm/adreno/a2xx.xml.h index 0261f0d31612..9e2aceb4ffe6 100644 --- a/drivers/gpu/drm/msm/adreno/a2xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a2xx.xml.h @@ -8,13 +8,14 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 398 bytes, from 2015-09-24 17:25:31) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10755 bytes, from 2015-09-14 20:46:55) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63785 bytes, from 2015-08-14 18:27:06) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67771 bytes, from 2015-09-14 20:46:55) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63970 bytes, from 2015-09-14 20:50:12) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2015-09-24 17:30:00) Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) diff --git a/drivers/gpu/drm/msm/adreno/a3xx.xml.h b/drivers/gpu/drm/msm/adreno/a3xx.xml.h index 48d133711487..97dc1c6ec107 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a3xx.xml.h @@ -8,13 +8,14 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 398 bytes, from 2015-09-24 17:25:31) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10755 bytes, from 2015-09-14 20:46:55) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63785 bytes, from 2015-08-14 18:27:06) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67771 bytes, from 2015-09-14 20:46:55) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63970 bytes, from 2015-09-14 20:50:12) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2015-09-24 17:30:00) Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) @@ -280,6 +281,8 @@ enum a3xx_rb_blend_opcode { enum a3xx_intp_mode { SMOOTH = 0, FLAT = 1, + ZERO = 2, + ONE = 3, }; enum a3xx_repl_mode { @@ -680,9 +683,16 @@ static inline uint32_t REG_A3XX_CP_PROTECT_REG(uint32_t i0) { return 0x00000460 #define A3XX_GRAS_CL_CLIP_CNTL_VP_CLIP_CODE_IGNORE 0x00080000 #define A3XX_GRAS_CL_CLIP_CNTL_VP_XFORM_DISABLE 0x00100000 #define A3XX_GRAS_CL_CLIP_CNTL_PERSP_DIVISION_DISABLE 0x00200000 +#define A3XX_GRAS_CL_CLIP_CNTL_ZERO_GB_SCALE_Z 0x00400000 #define A3XX_GRAS_CL_CLIP_CNTL_ZCOORD 0x00800000 #define A3XX_GRAS_CL_CLIP_CNTL_WCOORD 0x01000000 #define A3XX_GRAS_CL_CLIP_CNTL_ZCLIP_DISABLE 0x02000000 +#define A3XX_GRAS_CL_CLIP_CNTL_NUM_USER_CLIP_PLANES__MASK 0x1c000000 +#define A3XX_GRAS_CL_CLIP_CNTL_NUM_USER_CLIP_PLANES__SHIFT 26 +static inline uint32_t A3XX_GRAS_CL_CLIP_CNTL_NUM_USER_CLIP_PLANES(uint32_t val) +{ + return ((val) << A3XX_GRAS_CL_CLIP_CNTL_NUM_USER_CLIP_PLANES__SHIFT) & A3XX_GRAS_CL_CLIP_CNTL_NUM_USER_CLIP_PLANES__MASK; +} #define REG_A3XX_GRAS_CL_GB_CLIP_ADJ 0x00002044 #define A3XX_GRAS_CL_GB_CLIP_ADJ_HORZ__MASK 0x000003ff @@ -773,7 +783,7 @@ static inline uint32_t A3XX_GRAS_SU_POINT_SIZE(float val) #define A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT 0 static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL(float val) { - return ((((int32_t)(val * 16384.0))) << A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__MASK; + return ((((int32_t)(val * 1048576.0))) << A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__MASK; } #define REG_A3XX_GRAS_SU_POLY_OFFSET_OFFSET 0x0000206d @@ -894,6 +904,9 @@ static inline uint32_t A3XX_RB_MODE_CONTROL_MRT(uint32_t val) #define A3XX_RB_MODE_CONTROL_PACKER_TIMER_ENABLE 0x00010000 #define REG_A3XX_RB_RENDER_CONTROL 0x000020c1 +#define A3XX_RB_RENDER_CONTROL_DUAL_COLOR_IN_ENABLE 0x00000001 +#define A3XX_RB_RENDER_CONTROL_YUV_IN_ENABLE 0x00000002 +#define A3XX_RB_RENDER_CONTROL_COV_VALUE_INPUT_ENABLE 0x00000004 #define A3XX_RB_RENDER_CONTROL_FACENESS 0x00000008 #define A3XX_RB_RENDER_CONTROL_BIN_WIDTH__MASK 0x00000ff0 #define A3XX_RB_RENDER_CONTROL_BIN_WIDTH__SHIFT 4 @@ -907,6 +920,8 @@ static inline uint32_t A3XX_RB_RENDER_CONTROL_BIN_WIDTH(uint32_t val) #define A3XX_RB_RENDER_CONTROL_YCOORD 0x00008000 #define A3XX_RB_RENDER_CONTROL_ZCOORD 0x00010000 #define A3XX_RB_RENDER_CONTROL_WCOORD 0x00020000 +#define A3XX_RB_RENDER_CONTROL_I_CLAMP_ENABLE 0x00080000 +#define A3XX_RB_RENDER_CONTROL_COV_VALUE_OUTPUT_ENABLE 0x00100000 #define A3XX_RB_RENDER_CONTROL_ALPHA_TEST 0x00400000 #define A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC__MASK 0x07000000 #define A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC__SHIFT 24 @@ -914,6 +929,8 @@ static inline uint32_t A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC(enum adreno_compar { return ((val) << A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC__SHIFT) & A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC__MASK; } +#define A3XX_RB_RENDER_CONTROL_ALPHA_TO_COVERAGE 0x40000000 +#define A3XX_RB_RENDER_CONTROL_ALPHA_TO_ONE 0x80000000 #define REG_A3XX_RB_MSAA_CONTROL 0x000020c2 #define A3XX_RB_MSAA_CONTROL_DISABLE 0x00000400 diff --git a/drivers/gpu/drm/msm/adreno/a4xx.xml.h b/drivers/gpu/drm/msm/adreno/a4xx.xml.h index ac55066db3b0..99de8271dba8 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a4xx.xml.h @@ -8,13 +8,14 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 398 bytes, from 2015-09-24 17:25:31) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10755 bytes, from 2015-09-14 20:46:55) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63785 bytes, from 2015-08-14 18:27:06) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67771 bytes, from 2015-09-14 20:46:55) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63970 bytes, from 2015-09-14 20:50:12) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2015-09-24 17:30:00) Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) @@ -162,10 +163,13 @@ enum a4xx_tex_fmt { TFMT4_8_UNORM = 4, TFMT4_8_8_UNORM = 14, TFMT4_8_8_8_8_UNORM = 28, + TFMT4_8_SNORM = 5, TFMT4_8_8_SNORM = 15, TFMT4_8_8_8_8_SNORM = 29, + TFMT4_8_UINT = 6, TFMT4_8_8_UINT = 16, TFMT4_8_8_8_8_UINT = 30, + TFMT4_8_SINT = 7, TFMT4_8_8_SINT = 17, TFMT4_8_8_8_8_SINT = 31, TFMT4_16_UINT = 21, @@ -246,7 +250,8 @@ enum a4xx_tex_clamp { A4XX_TEX_REPEAT = 0, A4XX_TEX_CLAMP_TO_EDGE = 1, A4XX_TEX_MIRROR_REPEAT = 2, - A4XX_TEX_CLAMP_NONE = 3, + A4XX_TEX_CLAMP_TO_BORDER = 3, + A4XX_TEX_MIRROR_CLAMP = 4, }; enum a4xx_tex_aniso { diff --git a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h index 399a9e528139..c304468cf2bd 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h +++ b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h @@ -8,13 +8,14 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 398 bytes, from 2015-09-24 17:25:31) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10755 bytes, from 2015-09-14 20:46:55) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63785 bytes, from 2015-08-14 18:27:06) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67771 bytes, from 2015-09-14 20:46:55) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63970 bytes, from 2015-09-14 20:50:12) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2015-09-24 17:30:00) Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) @@ -85,6 +86,10 @@ enum adreno_rb_blend_factor { FACTOR_CONSTANT_ALPHA = 14, FACTOR_ONE_MINUS_CONSTANT_ALPHA = 15, FACTOR_SRC_ALPHA_SATURATE = 16, + FACTOR_SRC1_COLOR = 20, + FACTOR_ONE_MINUS_SRC1_COLOR = 21, + FACTOR_SRC1_ALPHA = 22, + FACTOR_ONE_MINUS_SRC1_ALPHA = 23, }; enum adreno_rb_surface_endian { diff --git a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h index 41904fed1350..a22fef569499 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h +++ b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h @@ -8,13 +8,14 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 398 bytes, from 2015-09-24 17:25:31) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10755 bytes, from 2015-09-14 20:46:55) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63785 bytes, from 2015-08-14 18:27:06) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67771 bytes, from 2015-09-14 20:46:55) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63970 bytes, from 2015-09-14 20:50:12) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2015-09-24 17:30:00) Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h b/drivers/gpu/drm/msm/dsi/dsi.xml.h index 1d2e32f0817b..b2b5f3dd1b4c 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.xml.h +++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h @@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 37194 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 27887 bytes, from 2015-10-22 16:34:52) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2015-10-22 16:35:02) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43) @@ -567,114 +567,234 @@ static inline uint32_t DSI_VERSION_MAJOR(uint32_t val) #define REG_DSI_8x60_PHY_CAL_STATUS 0x000000fc #define DSI_8x60_PHY_CAL_STATUS_CAL_BUSY 0x10000000 -static inline uint32_t REG_DSI_8960_LN(uint32_t i0) { return 0x00000300 + 0x40*i0; } +static inline uint32_t REG_DSI_28nm_8960_PHY_LN(uint32_t i0) { return 0x00000000 + 0x40*i0; } -static inline uint32_t REG_DSI_8960_LN_CFG_0(uint32_t i0) { return 0x00000300 + 0x40*i0; } +static inline uint32_t REG_DSI_28nm_8960_PHY_LN_CFG_0(uint32_t i0) { return 0x00000000 + 0x40*i0; } -static inline uint32_t REG_DSI_8960_LN_CFG_1(uint32_t i0) { return 0x00000304 + 0x40*i0; } +static inline uint32_t REG_DSI_28nm_8960_PHY_LN_CFG_1(uint32_t i0) { return 0x00000004 + 0x40*i0; } -static inline uint32_t REG_DSI_8960_LN_CFG_2(uint32_t i0) { return 0x00000308 + 0x40*i0; } +static inline uint32_t REG_DSI_28nm_8960_PHY_LN_CFG_2(uint32_t i0) { return 0x00000008 + 0x40*i0; } -static inline uint32_t REG_DSI_8960_LN_TEST_DATAPATH(uint32_t i0) { return 0x0000030c + 0x40*i0; } +static inline uint32_t REG_DSI_28nm_8960_PHY_LN_TEST_DATAPATH(uint32_t i0) { return 0x0000000c + 0x40*i0; } -static inline uint32_t REG_DSI_8960_LN_TEST_STR_0(uint32_t i0) { return 0x00000314 + 0x40*i0; } +static inline uint32_t REG_DSI_28nm_8960_PHY_LN_TEST_STR_0(uint32_t i0) { return 0x00000014 + 0x40*i0; } -static inline uint32_t REG_DSI_8960_LN_TEST_STR_1(uint32_t i0) { return 0x00000318 + 0x40*i0; } +static inline uint32_t REG_DSI_28nm_8960_PHY_LN_TEST_STR_1(uint32_t i0) { return 0x00000018 + 0x40*i0; } -#define REG_DSI_8960_PHY_LNCK_CFG_0 0x00000400 +#define REG_DSI_28nm_8960_PHY_LNCK_CFG_0 0x00000100 -#define REG_DSI_8960_PHY_LNCK_CFG_1 0x00000404 +#define REG_DSI_28nm_8960_PHY_LNCK_CFG_1 0x00000104 -#define REG_DSI_8960_PHY_LNCK_CFG_2 0x00000408 +#define REG_DSI_28nm_8960_PHY_LNCK_CFG_2 0x00000108 -#define REG_DSI_8960_PHY_LNCK_TEST_DATAPATH 0x0000040c +#define REG_DSI_28nm_8960_PHY_LNCK_TEST_DATAPATH 0x0000010c -#define REG_DSI_8960_PHY_LNCK_TEST_STR0 0x00000414 +#define REG_DSI_28nm_8960_PHY_LNCK_TEST_STR0 0x00000114 -#define REG_DSI_8960_PHY_LNCK_TEST_STR1 0x00000418 +#define REG_DSI_28nm_8960_PHY_LNCK_TEST_STR1 0x00000118 -#define REG_DSI_8960_PHY_TIMING_CTRL_0 0x00000440 +#define REG_DSI_28nm_8960_PHY_TIMING_CTRL_0 0x00000140 +#define DSI_28nm_8960_PHY_TIMING_CTRL_0_CLK_ZERO__MASK 0x000000ff +#define DSI_28nm_8960_PHY_TIMING_CTRL_0_CLK_ZERO__SHIFT 0 +static inline uint32_t DSI_28nm_8960_PHY_TIMING_CTRL_0_CLK_ZERO(uint32_t val) +{ + return ((val) << DSI_28nm_8960_PHY_TIMING_CTRL_0_CLK_ZERO__SHIFT) & DSI_28nm_8960_PHY_TIMING_CTRL_0_CLK_ZERO__MASK; +} + +#define REG_DSI_28nm_8960_PHY_TIMING_CTRL_1 0x00000144 +#define DSI_28nm_8960_PHY_TIMING_CTRL_1_CLK_TRAIL__MASK 0x000000ff +#define DSI_28nm_8960_PHY_TIMING_CTRL_1_CLK_TRAIL__SHIFT 0 +static inline uint32_t DSI_28nm_8960_PHY_TIMING_CTRL_1_CLK_TRAIL(uint32_t val) +{ + return ((val) << DSI_28nm_8960_PHY_TIMING_CTRL_1_CLK_TRAIL__SHIFT) & DSI_28nm_8960_PHY_TIMING_CTRL_1_CLK_TRAIL__MASK; +} + +#define REG_DSI_28nm_8960_PHY_TIMING_CTRL_2 0x00000148 +#define DSI_28nm_8960_PHY_TIMING_CTRL_2_CLK_PREPARE__MASK 0x000000ff +#define DSI_28nm_8960_PHY_TIMING_CTRL_2_CLK_PREPARE__SHIFT 0 +static inline uint32_t DSI_28nm_8960_PHY_TIMING_CTRL_2_CLK_PREPARE(uint32_t val) +{ + return ((val) << DSI_28nm_8960_PHY_TIMING_CTRL_2_CLK_PREPARE__SHIFT) & DSI_28nm_8960_PHY_TIMING_CTRL_2_CLK_PREPARE__MASK; +} + +#define REG_DSI_28nm_8960_PHY_TIMING_CTRL_3 0x0000014c + +#define REG_DSI_28nm_8960_PHY_TIMING_CTRL_4 0x00000150 +#define DSI_28nm_8960_PHY_TIMING_CTRL_4_HS_EXIT__MASK 0x000000ff +#define DSI_28nm_8960_PHY_TIMING_CTRL_4_HS_EXIT__SHIFT 0 +static inline uint32_t DSI_28nm_8960_PHY_TIMING_CTRL_4_HS_EXIT(uint32_t val) +{ + return ((val) << DSI_28nm_8960_PHY_TIMING_CTRL_4_HS_EXIT__SHIFT) & DSI_28nm_8960_PHY_TIMING_CTRL_4_HS_EXIT__MASK; +} + +#define REG_DSI_28nm_8960_PHY_TIMING_CTRL_5 0x00000154 +#define DSI_28nm_8960_PHY_TIMING_CTRL_5_HS_ZERO__MASK 0x000000ff +#define DSI_28nm_8960_PHY_TIMING_CTRL_5_HS_ZERO__SHIFT 0 +static inline uint32_t DSI_28nm_8960_PHY_TIMING_CTRL_5_HS_ZERO(uint32_t val) +{ + return ((val) << DSI_28nm_8960_PHY_TIMING_CTRL_5_HS_ZERO__SHIFT) & DSI_28nm_8960_PHY_TIMING_CTRL_5_HS_ZERO__MASK; +} + +#define REG_DSI_28nm_8960_PHY_TIMING_CTRL_6 0x00000158 +#define DSI_28nm_8960_PHY_TIMING_CTRL_6_HS_PREPARE__MASK 0x000000ff +#define DSI_28nm_8960_PHY_TIMING_CTRL_6_HS_PREPARE__SHIFT 0 +static inline uint32_t DSI_28nm_8960_PHY_TIMING_CTRL_6_HS_PREPARE(uint32_t val) +{ + return ((val) << DSI_28nm_8960_PHY_TIMING_CTRL_6_HS_PREPARE__SHIFT) & DSI_28nm_8960_PHY_TIMING_CTRL_6_HS_PREPARE__MASK; +} + +#define REG_DSI_28nm_8960_PHY_TIMING_CTRL_7 0x0000015c +#define DSI_28nm_8960_PHY_TIMING_CTRL_7_HS_TRAIL__MASK 0x000000ff +#define DSI_28nm_8960_PHY_TIMING_CTRL_7_HS_TRAIL__SHIFT 0 +static inline uint32_t DSI_28nm_8960_PHY_TIMING_CTRL_7_HS_TRAIL(uint32_t val) +{ + return ((val) << DSI_28nm_8960_PHY_TIMING_CTRL_7_HS_TRAIL__SHIFT) & DSI_28nm_8960_PHY_TIMING_CTRL_7_HS_TRAIL__MASK; +} + +#define REG_DSI_28nm_8960_PHY_TIMING_CTRL_8 0x00000160 +#define DSI_28nm_8960_PHY_TIMING_CTRL_8_HS_RQST__MASK 0x000000ff +#define DSI_28nm_8960_PHY_TIMING_CTRL_8_HS_RQST__SHIFT 0 +static inline uint32_t DSI_28nm_8960_PHY_TIMING_CTRL_8_HS_RQST(uint32_t val) +{ + return ((val) << DSI_28nm_8960_PHY_TIMING_CTRL_8_HS_RQST__SHIFT) & DSI_28nm_8960_PHY_TIMING_CTRL_8_HS_RQST__MASK; +} + +#define REG_DSI_28nm_8960_PHY_TIMING_CTRL_9 0x00000164 +#define DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_GO__MASK 0x00000007 +#define DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_GO__SHIFT 0 +static inline uint32_t DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_GO(uint32_t val) +{ + return ((val) << DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_GO__SHIFT) & DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_GO__MASK; +} +#define DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_SURE__MASK 0x00000070 +#define DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_SURE__SHIFT 4 +static inline uint32_t DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_SURE(uint32_t val) +{ + return ((val) << DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_SURE__SHIFT) & DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_SURE__MASK; +} + +#define REG_DSI_28nm_8960_PHY_TIMING_CTRL_10 0x00000168 +#define DSI_28nm_8960_PHY_TIMING_CTRL_10_TA_GET__MASK 0x00000007 +#define DSI_28nm_8960_PHY_TIMING_CTRL_10_TA_GET__SHIFT 0 +static inline uint32_t DSI_28nm_8960_PHY_TIMING_CTRL_10_TA_GET(uint32_t val) +{ + return ((val) << DSI_28nm_8960_PHY_TIMING_CTRL_10_TA_GET__SHIFT) & DSI_28nm_8960_PHY_TIMING_CTRL_10_TA_GET__MASK; +} + +#define REG_DSI_28nm_8960_PHY_TIMING_CTRL_11 0x0000016c +#define DSI_28nm_8960_PHY_TIMING_CTRL_11_TRIG3_CMD__MASK 0x000000ff +#define DSI_28nm_8960_PHY_TIMING_CTRL_11_TRIG3_CMD__SHIFT 0 +static inline uint32_t DSI_28nm_8960_PHY_TIMING_CTRL_11_TRIG3_CMD(uint32_t val) +{ + return ((val) << DSI_28nm_8960_PHY_TIMING_CTRL_11_TRIG3_CMD__SHIFT) & DSI_28nm_8960_PHY_TIMING_CTRL_11_TRIG3_CMD__MASK; +} + +#define REG_DSI_28nm_8960_PHY_CTRL_0 0x00000170 + +#define REG_DSI_28nm_8960_PHY_CTRL_1 0x00000174 + +#define REG_DSI_28nm_8960_PHY_CTRL_2 0x00000178 + +#define REG_DSI_28nm_8960_PHY_CTRL_3 0x0000017c + +#define REG_DSI_28nm_8960_PHY_STRENGTH_0 0x00000180 + +#define REG_DSI_28nm_8960_PHY_STRENGTH_1 0x00000184 + +#define REG_DSI_28nm_8960_PHY_STRENGTH_2 0x00000188 + +#define REG_DSI_28nm_8960_PHY_BIST_CTRL_0 0x0000018c + +#define REG_DSI_28nm_8960_PHY_BIST_CTRL_1 0x00000190 + +#define REG_DSI_28nm_8960_PHY_BIST_CTRL_2 0x00000194 + +#define REG_DSI_28nm_8960_PHY_BIST_CTRL_3 0x00000198 + +#define REG_DSI_28nm_8960_PHY_BIST_CTRL_4 0x0000019c -#define REG_DSI_8960_PHY_TIMING_CTRL_1 0x00000444 +#define REG_DSI_28nm_8960_PHY_LDO_CTRL 0x000001b0 -#define REG_DSI_8960_PHY_TIMING_CTRL_2 0x00000448 +#define REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_0 0x00000000 -#define REG_DSI_8960_PHY_TIMING_CTRL_3 0x0000044c +#define REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_1 0x00000004 -#define REG_DSI_8960_PHY_TIMING_CTRL_4 0x00000450 +#define REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_2 0x00000008 -#define REG_DSI_8960_PHY_TIMING_CTRL_5 0x00000454 +#define REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_3 0x0000000c -#define REG_DSI_8960_PHY_TIMING_CTRL_6 0x00000458 +#define REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_4 0x00000010 -#define REG_DSI_8960_PHY_TIMING_CTRL_7 0x0000045c +#define REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_5 0x00000014 -#define REG_DSI_8960_PHY_TIMING_CTRL_8 0x00000460 +#define REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CAL_PWR_CFG 0x00000018 -#define REG_DSI_8960_PHY_TIMING_CTRL_9 0x00000464 +#define REG_DSI_28nm_8960_PHY_MISC_CAL_HW_TRIGGER 0x00000028 -#define REG_DSI_8960_PHY_TIMING_CTRL_10 0x00000468 +#define REG_DSI_28nm_8960_PHY_MISC_CAL_SW_CFG_0 0x0000002c -#define REG_DSI_8960_PHY_TIMING_CTRL_11 0x0000046c +#define REG_DSI_28nm_8960_PHY_MISC_CAL_SW_CFG_1 0x00000030 -#define REG_DSI_8960_PHY_CTRL_0 0x00000470 +#define REG_DSI_28nm_8960_PHY_MISC_CAL_SW_CFG_2 0x00000034 -#define REG_DSI_8960_PHY_CTRL_1 0x00000474 +#define REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_0 0x00000038 -#define REG_DSI_8960_PHY_CTRL_2 0x00000478 +#define REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_1 0x0000003c -#define REG_DSI_8960_PHY_CTRL_3 0x0000047c +#define REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_2 0x00000040 -#define REG_DSI_8960_PHY_STRENGTH_0 0x00000480 +#define REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_3 0x00000044 -#define REG_DSI_8960_PHY_STRENGTH_1 0x00000484 +#define REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_4 0x00000048 -#define REG_DSI_8960_PHY_STRENGTH_2 0x00000488 +#define REG_DSI_28nm_8960_PHY_MISC_CAL_STATUS 0x00000050 +#define DSI_28nm_8960_PHY_MISC_CAL_STATUS_CAL_BUSY 0x00000010 -#define REG_DSI_8960_PHY_BIST_CTRL_0 0x0000048c +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_0 0x00000000 +#define DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE 0x00000001 -#define REG_DSI_8960_PHY_BIST_CTRL_1 0x00000490 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_1 0x00000004 -#define REG_DSI_8960_PHY_BIST_CTRL_2 0x00000494 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_2 0x00000008 -#define REG_DSI_8960_PHY_BIST_CTRL_3 0x00000498 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_3 0x0000000c -#define REG_DSI_8960_PHY_BIST_CTRL_4 0x0000049c +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_4 0x00000010 -#define REG_DSI_8960_PHY_LDO_CTRL 0x000004b0 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_5 0x00000014 -#define REG_DSI_8960_PHY_REGULATOR_CTRL_0 0x00000500 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_6 0x00000018 -#define REG_DSI_8960_PHY_REGULATOR_CTRL_1 0x00000504 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_7 0x0000001c -#define REG_DSI_8960_PHY_REGULATOR_CTRL_2 0x00000508 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_8 0x00000020 -#define REG_DSI_8960_PHY_REGULATOR_CTRL_3 0x0000050c +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_9 0x00000024 -#define REG_DSI_8960_PHY_REGULATOR_CTRL_4 0x00000510 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_10 0x00000028 -#define REG_DSI_8960_PHY_REGULATOR_CAL_PWR_CFG 0x00000518 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_11 0x0000002c -#define REG_DSI_8960_PHY_CAL_HW_TRIGGER 0x00000528 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_12 0x00000030 -#define REG_DSI_8960_PHY_CAL_SW_CFG_0 0x0000052c +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_13 0x00000034 -#define REG_DSI_8960_PHY_CAL_SW_CFG_1 0x00000530 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_14 0x00000038 -#define REG_DSI_8960_PHY_CAL_SW_CFG_2 0x00000534 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_15 0x0000003c -#define REG_DSI_8960_PHY_CAL_HW_CFG_0 0x00000538 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_16 0x00000040 -#define REG_DSI_8960_PHY_CAL_HW_CFG_1 0x0000053c +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_17 0x00000044 -#define REG_DSI_8960_PHY_CAL_HW_CFG_2 0x00000540 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_18 0x00000048 -#define REG_DSI_8960_PHY_CAL_HW_CFG_3 0x00000544 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_19 0x0000004c -#define REG_DSI_8960_PHY_CAL_HW_CFG_4 0x00000548 +#define REG_DSI_28nm_8960_PHY_PLL_CTRL_20 0x00000050 -#define REG_DSI_8960_PHY_CAL_STATUS 0x00000550 -#define DSI_8960_PHY_CAL_STATUS_CAL_BUSY 0x00000010 +#define REG_DSI_28nm_8960_PHY_PLL_RDY 0x00000080 +#define DSI_28nm_8960_PHY_PLL_RDY_PLL_RDY 0x00000001 static inline uint32_t REG_DSI_28nm_PHY_LN(uint32_t i0) { return 0x00000000 + 0x40*i0; } diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 8d82973fe9db..4c49868efcda 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -278,7 +278,7 @@ static int dsi_regulator_init(struct msm_dsi_host *msm_host) } for (i = 0; i < num; i++) { - if ((regs[i].min_voltage >= 0) && (regs[i].max_voltage >= 0)) { + if (regulator_can_change_voltage(s[i].consumer)) { ret = regulator_set_voltage(s[i].consumer, regs[i].min_voltage, regs[i].max_voltage); if (ret < 0) { diff --git a/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h b/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h index 5de505e627be..80ec65e47468 100644 --- a/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h +++ b/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h @@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 37194 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 27887 bytes, from 2015-10-22 16:34:52) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2015-10-22 16:35:02) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43) diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 401ff58d6893..f1f955f571fa 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -178,7 +178,7 @@ static int dsi_phy_regulator_init(struct msm_dsi_phy *phy) } for (i = 0; i < num; i++) { - if ((regs[i].min_voltage >= 0) && (regs[i].max_voltage >= 0)) { + if (regulator_can_change_voltage(s[i].consumer)) { ret = regulator_set_voltage(s[i].consumer, regs[i].min_voltage, regs[i].max_voltage); if (ret < 0) { diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c index f1a7c7b46420..edf74110ced7 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c @@ -99,16 +99,14 @@ static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_1(i), 0); dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_2(i), 0); dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_3(i), 0); + dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(i), 0); dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_DATAPATH(i), 0); dsi_phy_write(base + REG_DSI_28nm_PHY_LN_DEBUG_SEL(i), 0); dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_0(i), 0x1); dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_1(i), 0x97); } - dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(0), 0); - dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(1), 0x5); - dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(2), 0xa); - dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(3), 0xf); + dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_4, 0); dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_1, 0xc0); dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR0, 0x1); dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR1, 0xbb); diff --git a/drivers/gpu/drm/msm/dsi/sfpb.xml.h b/drivers/gpu/drm/msm/dsi/sfpb.xml.h index 06cbddfc914f..7d7662e69e11 100644 --- a/drivers/gpu/drm/msm/dsi/sfpb.xml.h +++ b/drivers/gpu/drm/msm/dsi/sfpb.xml.h @@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 37194 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 27887 bytes, from 2015-10-22 16:34:52) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2015-10-22 16:35:02) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43) @@ -45,7 +45,18 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#define REG_SFPB_CFG 0x00000058 +enum sfpb_ahb_arb_master_port_en { + SFPB_MASTER_PORT_ENABLE = 3, + SFPB_MASTER_PORT_DISABLE = 0, +}; + +#define REG_SFPB_GPREG 0x00000058 +#define SFPB_GPREG_MASTER_PORT_EN__MASK 0x00001800 +#define SFPB_GPREG_MASTER_PORT_EN__SHIFT 11 +static inline uint32_t SFPB_GPREG_MASTER_PORT_EN(enum sfpb_ahb_arb_master_port_en val) +{ + return ((val) << SFPB_GPREG_MASTER_PORT_EN__SHIFT) & SFPB_GPREG_MASTER_PORT_EN__MASK; +} #endif /* SFPB_XML */ diff --git a/drivers/gpu/drm/msm/edp/edp.xml.h b/drivers/gpu/drm/msm/edp/edp.xml.h index bef1d65fe28c..90bf5ed46746 100644 --- a/drivers/gpu/drm/msm/edp/edp.xml.h +++ b/drivers/gpu/drm/msm/edp/edp.xml.h @@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 37194 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 27887 bytes, from 2015-10-22 16:34:52) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2015-10-22 16:35:02) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 101b324cdeef..1f4a95eeb348 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -328,6 +328,9 @@ fail: .item ## _names = item ##_names_ ## entry, \ .item ## _cnt = ARRAY_SIZE(item ## _names_ ## entry) +static const char *pwr_reg_names_none[] = {}; +static const char *hpd_reg_names_none[] = {}; + static struct hdmi_platform_config hdmi_tx_8660_config = { .phy_init = hdmi_phy_8x60_init, }; @@ -367,18 +370,26 @@ static struct hdmi_platform_config hdmi_tx_8084_config = { .hpd_freq = hpd_clk_freq_8x74, }; -static const char *hpd_reg_names_8x94[] = {}; - static struct hdmi_platform_config hdmi_tx_8994_config = { .phy_init = NULL, /* nothing to do for this HDMI PHY 20nm */ HDMI_CFG(pwr_reg, 8x74), - HDMI_CFG(hpd_reg, 8x94), + HDMI_CFG(hpd_reg, none), + HDMI_CFG(pwr_clk, 8x74), + HDMI_CFG(hpd_clk, 8x74), + .hpd_freq = hpd_clk_freq_8x74, +}; + +static struct hdmi_platform_config hdmi_tx_8996_config = { + .phy_init = NULL, + HDMI_CFG(pwr_reg, none), + HDMI_CFG(hpd_reg, none), HDMI_CFG(pwr_clk, 8x74), HDMI_CFG(hpd_clk, 8x74), .hpd_freq = hpd_clk_freq_8x74, }; static const struct of_device_id dt_match[] = { + { .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8996_config }, { .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8994_config }, { .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config }, { .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config }, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h index 0b1b5586ff35..10c45700aefe 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h @@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 37194 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 27887 bytes, from 2015-10-22 16:34:52) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2015-10-22 16:35:02) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43) diff --git a/drivers/gpu/drm/msm/hdmi/qfprom.xml.h b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h index 2aa23b98f8aa..dbd9cc4daf2e 100644 --- a/drivers/gpu/drm/msm/hdmi/qfprom.xml.h +++ b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h @@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 37194 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 27887 bytes, from 2015-10-22 16:34:52) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2015-10-22 16:35:02) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h index 74b86734fef5..d5d94575fa1b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h @@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 37194 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 27887 bytes, from 2015-10-22 16:34:52) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2015-10-22 16:35:02) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h index 3469f50d5590..c37da9c61e29 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h @@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 37194 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 27887 bytes, from 2015-10-22 16:34:52) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2015-10-22 16:35:02) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43) @@ -895,6 +895,7 @@ static inline uint32_t MDP5_PIPE_SRC_OP_MODE_BWC(enum mdp5_pipe_bwc val) #define MDP5_PIPE_SRC_OP_MODE_IGC_ROM_1 0x00040000 #define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE 0x00400000 #define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE_ODD 0x00800000 +#define MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE 0x80000000 static inline uint32_t REG_MDP5_PIPE_SRC_CONSTANT_COLOR(enum mdp5_pipe i0) { return 0x0000003c + __offset_PIPE(i0); } @@ -932,6 +933,83 @@ static inline uint32_t MDP5_PIPE_DECIMATION_HORZ(uint32_t val) return ((val) << MDP5_PIPE_DECIMATION_HORZ__SHIFT) & MDP5_PIPE_DECIMATION_HORZ__MASK; } +static inline uint32_t __offset_SW_PIX_EXT(enum mdp_component_type idx) +{ + switch (idx) { + case COMP_0: return 0x00000100; + case COMP_1_2: return 0x00000110; + case COMP_3: return 0x00000120; + default: return INVALID_IDX(idx); + } +} +static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000000 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); } + +static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT_LR(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000000 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); } +#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__MASK 0x000000ff +#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__SHIFT 0 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__MASK 0x0000ff00 +#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__SHIFT 8 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(int32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__MASK 0x00ff0000 +#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__SHIFT 16 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__MASK 0xff000000 +#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__SHIFT 24 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(int32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT_TB(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000004 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); } +#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__MASK 0x000000ff +#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__SHIFT 0 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__MASK 0x0000ff00 +#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__SHIFT 8 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(int32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__MASK 0x00ff0000 +#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__SHIFT 16 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__MASK 0xff000000 +#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__SHIFT 24 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(int32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000008 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); } +#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__MASK 0x0000ffff +#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__SHIFT 0 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__MASK 0xffff0000 +#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__SHIFT 16 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(uint32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__SHIFT) & MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__MASK; +} + static inline uint32_t REG_MDP5_PIPE_SCALE_CONFIG(enum mdp5_pipe i0) { return 0x00000204 + __offset_PIPE(i0); } #define MDP5_PIPE_SCALE_CONFIG_SCALEX_EN 0x00000001 #define MDP5_PIPE_SCALE_CONFIG_SCALEY_EN 0x00000002 diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c index a1e26f23c7cc..bb1225aa2f75 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c @@ -27,6 +27,8 @@ const struct mdp5_cfg_hw msm8x74v1_config = { .mdp = { .count = 1, .base = { 0x00100 }, + .caps = MDP_CAP_SMP | + 0, }, .smp = { .mmb_count = 22, @@ -96,6 +98,8 @@ const struct mdp5_cfg_hw msm8x74v2_config = { .mdp = { .count = 1, .base = { 0x00100 }, + .caps = MDP_CAP_SMP | + 0, }, .smp = { .mmb_count = 22, @@ -165,6 +169,8 @@ const struct mdp5_cfg_hw apq8084_config = { .mdp = { .count = 1, .base = { 0x00100 }, + .caps = MDP_CAP_SMP | + 0, }, .smp = { .mmb_count = 44, @@ -242,6 +248,8 @@ const struct mdp5_cfg_hw msm8x16_config = { .mdp = { .count = 1, .base = { 0x01000 }, + .caps = MDP_CAP_SMP | + 0, }, .smp = { .mmb_count = 8, @@ -301,6 +309,8 @@ const struct mdp5_cfg_hw msm8x94_config = { .mdp = { .count = 1, .base = { 0x01000 }, + .caps = MDP_CAP_SMP | + 0, }, .smp = { .mmb_count = 44, @@ -370,7 +380,89 @@ const struct mdp5_cfg_hw msm8x94_config = { [3] = INTF_HDMI, }, }, - .max_clk = 320000000, + .max_clk = 400000000, +}; + +const struct mdp5_cfg_hw msm8x96_config = { + .name = "msm8x96", + .mdp = { + .count = 1, + .base = { 0x01000 }, + .caps = MDP_CAP_DSC | + MDP_CAP_CDM | + 0, + }, + .ctl = { + .count = 5, + .base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 }, + .flush_hw_mask = 0xf4ffffff, + }, + .pipe_vig = { + .count = 4, + .base = { 0x05000, 0x07000, 0x09000, 0x0b000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SCALE | + MDP_PIPE_CAP_CSC | + MDP_PIPE_CAP_DECIMATION | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_rgb = { + .count = 4, + .base = { 0x15000, 0x17000, 0x19000, 0x1b000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SCALE | + MDP_PIPE_CAP_DECIMATION | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_dma = { + .count = 2, + .base = { 0x25000, 0x27000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .lm = { + .count = 6, + .base = { 0x45000, 0x46000, 0x47000, 0x48000, 0x49000, 0x4a000 }, + .nb_stages = 8, + .max_width = 2560, + .max_height = 0xFFFF, + }, + .dspp = { + .count = 2, + .base = { 0x55000, 0x57000 }, + }, + .ad = { + .count = 3, + .base = { 0x79000, 0x79800, 0x7a000 }, + }, + .pp = { + .count = 4, + .base = { 0x71000, 0x71800, 0x72000, 0x72800 }, + }, + .cdm = { + .count = 1, + .base = { 0x7a200 }, + }, + .dsc = { + .count = 2, + .base = { 0x81000, 0x81400 }, + }, + .intf = { + .base = { 0x6b000, 0x6b800, 0x6c000, 0x6c800, 0x6d000 }, + .connect = { + [0] = INTF_DISABLED, + [1] = INTF_DSI, + [2] = INTF_DSI, + [3] = INTF_HDMI, + }, + }, + .max_clk = 412500000, }; static const struct mdp5_cfg_handler cfg_handlers[] = { @@ -379,6 +471,7 @@ static const struct mdp5_cfg_handler cfg_handlers[] = { { .revision = 3, .config = { .hw = &apq8084_config } }, { .revision = 6, .config = { .hw = &msm8x16_config } }, { .revision = 9, .config = { .hw = &msm8x94_config } }, + { .revision = 7, .config = { .hw = &msm8x96_config } }, }; static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h index efb918d9f68b..050e1618c836 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h @@ -61,7 +61,12 @@ struct mdp5_smp_block { int mmb_size; /* MMB: size in bytes */ uint32_t clients[MAX_CLIENTS]; /* SMP port allocation /pipe */ mdp5_smp_state_t reserved_state;/* SMP MMBs statically allocated */ - int reserved[MAX_CLIENTS]; /* # of MMBs allocated per client */ + uint8_t reserved[MAX_CLIENTS]; /* # of MMBs allocated per client */ +}; + +struct mdp5_mdp_block { + MDP5_SUB_BLOCK_DEFINITION; + uint32_t caps; /* MDP capabilities: MDP_CAP_xxx bits */ }; #define MDP5_INTF_NUM_MAX 5 @@ -74,7 +79,7 @@ struct mdp5_intf_block { struct mdp5_cfg_hw { char *name; - struct mdp5_sub_block mdp; + struct mdp5_mdp_block mdp; struct mdp5_smp_block smp; struct mdp5_ctl_block ctl; struct mdp5_pipe_block pipe_vig; @@ -84,6 +89,8 @@ struct mdp5_cfg_hw { struct mdp5_sub_block dspp; struct mdp5_sub_block ad; struct mdp5_sub_block pp; + struct mdp5_sub_block dsc; + struct mdp5_sub_block cdm; struct mdp5_intf_block intf; uint32_t max_clk; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 047cb0433ccb..b532faa8026d 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -452,15 +452,19 @@ static void read_hw_revision(struct mdp5_kms *mdp5_kms, } static int get_clk(struct platform_device *pdev, struct clk **clkp, - const char *name) + const char *name, bool mandatory) { struct device *dev = &pdev->dev; struct clk *clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { + if (IS_ERR(clk) && mandatory) { dev_err(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk)); return PTR_ERR(clk); } - *clkp = clk; + if (IS_ERR(clk)) + DBG("skipping %s", name); + else + *clkp = clk; + return 0; } @@ -514,25 +518,26 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) goto fail; } - ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk"); + /* mandatory clocks: */ + ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk", true); if (ret) goto fail; - ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface_clk"); + ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface_clk", true); if (ret) goto fail; - ret = get_clk(pdev, &mdp5_kms->src_clk, "core_clk_src"); + ret = get_clk(pdev, &mdp5_kms->src_clk, "core_clk_src", true); if (ret) goto fail; - ret = get_clk(pdev, &mdp5_kms->core_clk, "core_clk"); + ret = get_clk(pdev, &mdp5_kms->core_clk, "core_clk", true); if (ret) goto fail; - ret = get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk"); - if (ret) - DBG("failed to get (optional) lut_clk clock"); - ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk"); + ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk", true); if (ret) goto fail; + /* optional clocks: */ + get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk", false); + /* we need to set a default rate before enabling. Set a safe * rate first, then figure out hw revision, and then set a * more optimal rate: @@ -549,15 +554,23 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) } config = mdp5_cfg_get_config(mdp5_kms->cfg); + mdp5_kms->caps = config->hw->mdp.caps; /* TODO: compute core clock rate at runtime */ clk_set_rate(mdp5_kms->src_clk, config->hw->max_clk); - mdp5_kms->smp = mdp5_smp_init(mdp5_kms->dev, &config->hw->smp); - if (IS_ERR(mdp5_kms->smp)) { - ret = PTR_ERR(mdp5_kms->smp); - mdp5_kms->smp = NULL; - goto fail; + /* + * Some chipsets have a Shared Memory Pool (SMP), while others + * have dedicated latency buffering per source pipe instead; + * this section initializes the SMP: + */ + if (mdp5_kms->caps & MDP_CAP_SMP) { + mdp5_kms->smp = mdp5_smp_init(mdp5_kms->dev, &config->hw->smp); + if (IS_ERR(mdp5_kms->smp)) { + ret = PTR_ERR(mdp5_kms->smp); + mdp5_kms->smp = NULL; + goto fail; + } } mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, mdp5_kms->cfg); @@ -586,6 +599,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) if (IS_ERR(mmu)) { ret = PTR_ERR(mmu); dev_err(dev->dev, "failed to init iommu: %d\n", ret); + iommu_domain_free(config->platform.iommu); goto fail; } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 0bb62423586e..84f65d415598 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -32,6 +32,8 @@ struct mdp5_kms { struct drm_device *dev; struct mdp5_cfg_handler *cfg; + uint32_t caps; /* MDP capabilities (MDP_CAP_XXX bits) */ + /* mapper-id used to request GEM buffer mapped for scanout: */ int id; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index a0f5ff0ce8dc..81cd49045ffc 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -500,7 +500,7 @@ static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase) static int calc_scalex_steps(struct drm_plane *plane, uint32_t pixel_format, uint32_t src, uint32_t dest, - uint32_t phasex_steps[2]) + uint32_t phasex_steps[COMP_MAX]) { struct mdp5_kms *mdp5_kms = get_kms(plane); struct device *dev = mdp5_kms->dev->dev; @@ -516,15 +516,16 @@ static int calc_scalex_steps(struct drm_plane *plane, hsub = drm_format_horz_chroma_subsampling(pixel_format); - phasex_steps[0] = phasex_step; - phasex_steps[1] = phasex_step / hsub; + phasex_steps[COMP_0] = phasex_step; + phasex_steps[COMP_3] = phasex_step; + phasex_steps[COMP_1_2] = phasex_step / hsub; return 0; } static int calc_scaley_steps(struct drm_plane *plane, uint32_t pixel_format, uint32_t src, uint32_t dest, - uint32_t phasey_steps[2]) + uint32_t phasey_steps[COMP_MAX]) { struct mdp5_kms *mdp5_kms = get_kms(plane); struct device *dev = mdp5_kms->dev->dev; @@ -540,46 +541,127 @@ static int calc_scaley_steps(struct drm_plane *plane, vsub = drm_format_vert_chroma_subsampling(pixel_format); - phasey_steps[0] = phasey_step; - phasey_steps[1] = phasey_step / vsub; + phasey_steps[COMP_0] = phasey_step; + phasey_steps[COMP_3] = phasey_step; + phasey_steps[COMP_1_2] = phasey_step / vsub; return 0; } -static uint32_t get_scale_config(enum mdp_chroma_samp_type chroma_sample, - uint32_t src, uint32_t dest, bool hor) +static uint32_t get_scale_config(const struct mdp_format *format, + uint32_t src, uint32_t dst, bool horz) { - uint32_t y_filter = (src <= dest) ? SCALE_FILTER_CA : SCALE_FILTER_PCMN; - uint32_t y_a_filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN; - uint32_t uv_filter = ((src / 2) <= dest) ? /* 2x upsample */ - SCALE_FILTER_BIL : SCALE_FILTER_PCMN; - uint32_t value = 0; - - if (chroma_sample == CHROMA_420 || chroma_sample == CHROMA_H2V1) { - if (hor) - value = MDP5_PIPE_SCALE_CONFIG_SCALEX_EN | - MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(y_filter) | - MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(y_a_filter) | - MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter); - else - value = MDP5_PIPE_SCALE_CONFIG_SCALEY_EN | - MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(y_filter) | - MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(y_a_filter) | - MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter); - } else if (src != dest) { - if (hor) - value = MDP5_PIPE_SCALE_CONFIG_SCALEX_EN | - MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(y_a_filter) | - MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(y_a_filter); - else - value = MDP5_PIPE_SCALE_CONFIG_SCALEY_EN | - MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(y_a_filter) | - MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(y_a_filter); + bool scaling = format->is_yuv ? true : (src != dst); + uint32_t sub, pix_fmt = format->base.pixel_format; + uint32_t ya_filter, uv_filter; + bool yuv = format->is_yuv; + + if (!scaling) + return 0; + + if (yuv) { + sub = horz ? drm_format_horz_chroma_subsampling(pix_fmt) : + drm_format_vert_chroma_subsampling(pix_fmt); + uv_filter = ((src / sub) <= dst) ? + SCALE_FILTER_BIL : SCALE_FILTER_PCMN; } + ya_filter = (src <= dst) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN; - return value; + if (horz) + return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN | + MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(ya_filter) | + MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(ya_filter) | + COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter)); + else + return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN | + MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(ya_filter) | + MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(ya_filter) | + COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter)); } +static void calc_pixel_ext(const struct mdp_format *format, + uint32_t src, uint32_t dst, uint32_t phase_step[2], + int pix_ext_edge1[COMP_MAX], int pix_ext_edge2[COMP_MAX], + bool horz) +{ + bool scaling = format->is_yuv ? true : (src != dst); + int i; + + /* + * Note: + * We assume here that: + * 1. PCMN filter is used for downscale + * 2. bilinear filter is used for upscale + * 3. we are in a single pipe configuration + */ + + for (i = 0; i < COMP_MAX; i++) { + pix_ext_edge1[i] = 0; + pix_ext_edge2[i] = scaling ? 1 : 0; + } +} + +static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe, + const struct mdp_format *format, + uint32_t src_w, int pe_left[COMP_MAX], int pe_right[COMP_MAX], + uint32_t src_h, int pe_top[COMP_MAX], int pe_bottom[COMP_MAX]) +{ + uint32_t pix_fmt = format->base.pixel_format; + uint32_t lr, tb, req; + int i; + + for (i = 0; i < COMP_MAX; i++) { + uint32_t roi_w = src_w; + uint32_t roi_h = src_h; + + if (format->is_yuv && i == COMP_1_2) { + roi_w /= drm_format_horz_chroma_subsampling(pix_fmt); + roi_h /= drm_format_vert_chroma_subsampling(pix_fmt); + } + + lr = (pe_left[i] >= 0) ? + MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(pe_left[i]) : + MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(pe_left[i]); + + lr |= (pe_right[i] >= 0) ? + MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(pe_right[i]) : + MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(pe_right[i]); + + tb = (pe_top[i] >= 0) ? + MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(pe_top[i]) : + MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(pe_top[i]); + + tb |= (pe_bottom[i] >= 0) ? + MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(pe_bottom[i]) : + MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(pe_bottom[i]); + + req = MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(roi_w + + pe_left[i] + pe_right[i]); + + req |= MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(roi_h + + pe_top[i] + pe_bottom[i]); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_LR(pipe, i), lr); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_TB(pipe, i), tb); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(pipe, i), req); + + DBG("comp-%d (L/R): rpt=%d/%d, ovf=%d/%d, req=%d", i, + FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT), + FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT), + FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF), + FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF), + FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT)); + + DBG("comp-%d (T/B): rpt=%d/%d, ovf=%d/%d, req=%d", i, + FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT), + FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT), + FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF), + FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF), + FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM)); + } +} + + static int mdp5_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, @@ -593,8 +675,10 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, enum mdp5_pipe pipe = mdp5_plane->pipe; const struct mdp_format *format; uint32_t nplanes, config = 0; - /* below array -> index 0: comp 0/3 ; index 1: comp 1/2 */ - uint32_t phasex_step[2] = {0,}, phasey_step[2] = {0,}; + uint32_t phasex_step[COMP_MAX] = {0,}, phasey_step[COMP_MAX] = {0,}; + bool pe = mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT; + int pe_left[COMP_MAX], pe_right[COMP_MAX]; + int pe_top[COMP_MAX], pe_bottom[COMP_MAX]; uint32_t hdecm = 0, vdecm = 0; uint32_t pix_format; bool vflip, hflip; @@ -621,10 +705,12 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); /* Request some memory from the SMP: */ - ret = mdp5_smp_request(mdp5_kms->smp, - mdp5_plane->pipe, format, src_w, false); - if (ret) - return ret; + if (mdp5_kms->smp) { + ret = mdp5_smp_request(mdp5_kms->smp, + mdp5_plane->pipe, format, src_w, false); + if (ret) + return ret; + } /* * Currently we update the hw for allocations/requests immediately, @@ -632,7 +718,8 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, * would move into atomic->check_plane_state(), while updating the * hw would remain here: */ - mdp5_smp_configure(mdp5_kms->smp, pipe); + if (mdp5_kms->smp) + mdp5_smp_configure(mdp5_kms->smp, pipe); ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, phasex_step); if (ret) @@ -642,11 +729,18 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, if (ret) return ret; + if (mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT) { + calc_pixel_ext(format, src_w, crtc_w, phasex_step, + pe_left, pe_right, true); + calc_pixel_ext(format, src_h, crtc_h, phasey_step, + pe_top, pe_bottom, false); + } + /* TODO calc hdecm, vdecm */ /* SCALE is used to both scale and up-sample chroma components */ - config |= get_scale_config(format->chroma_sample, src_w, crtc_w, true); - config |= get_scale_config(format->chroma_sample, src_h, crtc_h, false); + config |= get_scale_config(format, src_w, crtc_w, true); + config |= get_scale_config(format, src_h, crtc_h, false); DBG("scale config = %x", config); hflip = !!(pstate->rotation & BIT(DRM_REFLECT_X)); @@ -695,20 +789,26 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe), (hflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_LR : 0) | (vflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_UD : 0) | + COND(pe, MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE) | MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS)); /* not using secure mode: */ mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0); + if (mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT) + mdp5_write_pixel_ext(mdp5_kms, pipe, format, + src_w, pe_left, pe_right, + src_h, pe_top, pe_bottom); + if (mdp5_plane->caps & MDP_PIPE_CAP_SCALE) { mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), - phasex_step[0]); + phasex_step[COMP_0]); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), - phasey_step[0]); + phasey_step[COMP_0]); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe), - phasex_step[1]); + phasex_step[COMP_1_2]); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe), - phasey_step[1]); + phasey_step[COMP_1_2]); mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe), MDP5_PIPE_DECIMATION_VERT(vdecm) | MDP5_PIPE_DECIMATION_HORZ(hdecm)); @@ -738,7 +838,8 @@ void mdp5_plane_complete_flip(struct drm_plane *plane) DBG("%s: complete flip", mdp5_plane->name); - mdp5_smp_commit(mdp5_kms->smp, pipe); + if (mdp5_kms->smp) + mdp5_smp_commit(mdp5_kms->smp, pipe); to_mdp5_plane_state(plane->state)->pending = false; } @@ -764,7 +865,7 @@ void mdp5_plane_complete_commit(struct drm_plane *plane, struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); enum mdp5_pipe pipe = mdp5_plane->pipe; - if (!plane_enabled(plane->state)) { + if (!plane_enabled(plane->state) && mdp5_kms->smp) { DBG("%s: free SMP", mdp5_plane->name); mdp5_smp_release(mdp5_kms->smp, pipe); } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c index 563cca972dcb..6f425c25d9fe 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c @@ -90,7 +90,7 @@ struct mdp5_smp { struct drm_device *dev; - const struct mdp5_smp_block *cfg; + uint8_t reserved[MAX_CLIENTS]; /* fixed MMBs allocation per client */ int blk_cnt; int blk_size; @@ -141,10 +141,10 @@ static int smp_request_block(struct mdp5_smp *smp, struct mdp5_kms *mdp5_kms = get_kms(smp); struct mdp5_client_smp_state *ps = &smp->client_state[cid]; int i, ret, avail, cur_nblks, cnt = smp->blk_cnt; - int reserved; + uint8_t reserved; unsigned long flags; - reserved = smp->cfg->reserved[cid]; + reserved = smp->reserved[cid]; spin_lock_irqsave(&smp->state_lock, flags); @@ -405,12 +405,12 @@ struct mdp5_smp *mdp5_smp_init(struct drm_device *dev, const struct mdp5_smp_blo } smp->dev = dev; - smp->cfg = cfg; smp->blk_cnt = cfg->mmb_count; smp->blk_size = cfg->mmb_size; /* statically tied MMBs cannot be re-allocated: */ bitmap_copy(smp->state, cfg->reserved_state, smp->blk_cnt); + memcpy(smp->reserved, cfg->reserved, sizeof(smp->reserved)); spin_lock_init(&smp->state_lock); return smp; diff --git a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h index 4f792c4e40f4..0aec1ac1f6d0 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h @@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-09 22:10:24) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 26057 bytes, from 2015-08-14 21:47:57) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2015-05-20 20:03:07) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 37194 bytes, from 2015-09-18 12:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 27887 bytes, from 2015-10-22 16:34:52) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2015-10-22 16:35:02) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29154 bytes, from 2015-08-10 21:25:43) @@ -78,6 +78,13 @@ enum mdp_alpha_type { BG_PIXEL = 3, }; +enum mdp_component_type { + COMP_0 = 0, + COMP_1_2 = 1, + COMP_3 = 2, + COMP_MAX = 3, +}; + enum mdp_bpc { BPC1 = 0, BPC5 = 1, diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h index 46a94e7d50e2..303130320748 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.h @@ -100,12 +100,18 @@ struct mdp_format { uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats, bool rgb_only); const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format); +/* MDP capabilities */ +#define MDP_CAP_SMP BIT(0) /* Shared Memory Pool */ +#define MDP_CAP_DSC BIT(1) /* VESA Display Stream Compression */ +#define MDP_CAP_CDM BIT(2) /* Chroma Down Module (HDMI 2.0 YUV) */ + /* MDP pipe capabilities */ #define MDP_PIPE_CAP_HFLIP BIT(0) #define MDP_PIPE_CAP_VFLIP BIT(1) #define MDP_PIPE_CAP_SCALE BIT(2) #define MDP_PIPE_CAP_CSC BIT(3) #define MDP_PIPE_CAP_DECIMATION BIT(4) +#define MDP_PIPE_CAP_SW_PIX_EXT BIT(5) static inline bool pipe_supports_yuv(uint32_t pipe_caps) { diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 0339c5d82d37..b88ce514eb8e 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -21,11 +21,9 @@ static void msm_fb_output_poll_changed(struct drm_device *dev) { -#ifdef CONFIG_DRM_MSM_FBDEV struct msm_drm_private *priv = dev->dev_private; if (priv->fbdev) drm_fb_helper_hotplug_event(priv->fbdev); -#endif } static const struct drm_mode_config_funcs mode_config_funcs = { @@ -56,7 +54,7 @@ module_param(reglog, bool, 0600); #define reglog 0 #endif -#ifdef CONFIG_DRM_MSM_FBDEV +#ifdef CONFIG_DRM_FBDEV_EMULATION static bool fbdev = true; MODULE_PARM_DESC(fbdev, "Enable fbdev compat layer"); module_param(fbdev, bool, 0600); @@ -423,7 +421,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) drm_mode_config_reset(dev); -#ifdef CONFIG_DRM_MSM_FBDEV +#ifdef CONFIG_DRM_FBDEV_EMULATION if (fbdev) priv->fbdev = msm_fbdev_init(dev); #endif @@ -491,11 +489,9 @@ static void msm_preclose(struct drm_device *dev, struct drm_file *file) static void msm_lastclose(struct drm_device *dev) { -#ifdef CONFIG_DRM_MSM_FBDEV struct msm_drm_private *priv = dev->dev_private; if (priv->fbdev) drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev); -#endif } static irqreturn_t msm_irq(int irq, void *arg) @@ -531,24 +527,24 @@ static void msm_irq_uninstall(struct drm_device *dev) kms->funcs->irq_uninstall(kms); } -static int msm_enable_vblank(struct drm_device *dev, int crtc_id) +static int msm_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; if (!kms) return -ENXIO; - DBG("dev=%p, crtc=%d", dev, crtc_id); - return vblank_ctrl_queue_work(priv, crtc_id, true); + DBG("dev=%p, crtc=%u", dev, pipe); + return vblank_ctrl_queue_work(priv, pipe, true); } -static void msm_disable_vblank(struct drm_device *dev, int crtc_id) +static void msm_disable_vblank(struct drm_device *dev, unsigned int pipe) { struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; if (!kms) return; - DBG("dev=%p, crtc=%d", dev, crtc_id); - vblank_ctrl_queue_work(priv, crtc_id, false); + DBG("dev=%p, crtc=%u", dev, pipe); + vblank_ctrl_queue_work(priv, pipe, false); } /* @@ -932,13 +928,13 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data, } static const struct drm_ioctl_desc msm_ioctls[] = { - DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_GEM_INFO, msm_ioctl_gem_info, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_FINI, msm_ioctl_gem_cpu_fini, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_GEM_SUBMIT, msm_ioctl_gem_submit, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE, msm_ioctl_wait_fence, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_INFO, msm_ioctl_gem_info, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_FINI, msm_ioctl_gem_cpu_fini, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_SUBMIT, msm_ioctl_gem_submit, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE, msm_ioctl_wait_fence, DRM_AUTH|DRM_RENDER_ALLOW), }; static const struct vm_operations_struct vm_ops = { @@ -978,7 +974,7 @@ static struct drm_driver msm_driver = { .irq_preinstall = msm_irq_preinstall, .irq_postinstall = msm_irq_postinstall, .irq_uninstall = msm_irq_uninstall, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = msm_enable_vblank, .disable_vblank = msm_disable_vblank, .gem_free_object = msm_gem_free_object, diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index f97a1964ef39..3f6ec077b51d 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -68,12 +68,7 @@ static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma) if (drm_device_is_unplugged(dev)) return -ENODEV; - mutex_lock(&dev->struct_mutex); - ret = drm_gem_mmap_obj(drm_obj, drm_obj->size, vma); - - mutex_unlock(&dev->struct_mutex); - if (ret) { pr_err("%s:drm_gem_mmap_obj fail\n", __func__); return ret; diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c index 831461bc98a5..121975b07cd4 100644 --- a/drivers/gpu/drm/msm/msm_gem_prime.c +++ b/drivers/gpu/drm/msm/msm_gem_prime.c @@ -45,9 +45,7 @@ int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) { int ret; - mutex_lock(&obj->dev->struct_mutex); ret = drm_gem_mmap_obj(obj, obj->size, vma); - mutex_unlock(&obj->dev->struct_mutex); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 8f70d9248ac5..6b02ada6579a 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -651,6 +651,14 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, if (iommu) { dev_info(drm->dev, "%s: using IOMMU\n", name); gpu->mmu = msm_iommu_new(&pdev->dev, iommu); + if (IS_ERR(gpu->mmu)) { + ret = PTR_ERR(gpu->mmu); + dev_err(drm->dev, "failed to init iommu: %d\n", ret); + gpu->mmu = NULL; + iommu_domain_free(iommu); + goto fail; + } + } else { dev_info(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name); } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 15057b39491c..78f520d05de9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -574,7 +574,7 @@ static struct ttm_tt * nouveau_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, uint32_t page_flags, struct page *dummy_read) { -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) struct nouveau_drm *drm = nouveau_bdev(bdev); if (drm->agp.bridge) { @@ -1366,7 +1366,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) /* System memory */ return 0; case TTM_PL_TT: -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (drm->agp.bridge) { mem->bus.offset = mem->start << PAGE_SHIFT; mem->bus.base = drm->agp.base; @@ -1496,7 +1496,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) ttm->caching_state == tt_uncached) return ttm_dma_populate(ttm_dma, dev->dev); -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (drm->agp.bridge) { return ttm_agp_tt_populate(ttm); } @@ -1563,7 +1563,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) return; } -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (drm->agp.bridge) { ttm_agp_tt_unpopulate(ttm); return; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index a82c3cbe3127..614b32e6381c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -51,12 +51,12 @@ nouveau_display_vblank_handler(struct nvif_notify *notify) } int -nouveau_display_vblank_enable(struct drm_device *dev, int head) +nouveau_display_vblank_enable(struct drm_device *dev, unsigned int pipe) { struct drm_crtc *crtc; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - if (nv_crtc->index == head) { + if (nv_crtc->index == pipe) { nvif_notify_get(&nv_crtc->vblank); return 0; } @@ -65,12 +65,12 @@ nouveau_display_vblank_enable(struct drm_device *dev, int head) } void -nouveau_display_vblank_disable(struct drm_device *dev, int head) +nouveau_display_vblank_disable(struct drm_device *dev, unsigned int pipe) { struct drm_crtc *crtc; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - if (nv_crtc->index == head) { + if (nv_crtc->index == pipe) { nvif_notify_put(&nv_crtc->vblank); return; } @@ -132,14 +132,15 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, } int -nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags, - int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, +nouveau_display_scanoutpos(struct drm_device *dev, unsigned int pipe, + unsigned int flags, int *vpos, int *hpos, + ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode) { struct drm_crtc *crtc; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (nouveau_crtc(crtc)->index == head) { + if (nouveau_crtc(crtc)->index == pipe) { return nouveau_display_scanoutpos_head(crtc, vpos, hpos, stime, etime); } @@ -149,15 +150,15 @@ nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags, } int -nouveau_display_vblstamp(struct drm_device *dev, int head, int *max_error, - struct timeval *time, unsigned flags) +nouveau_display_vblstamp(struct drm_device *dev, unsigned int pipe, + int *max_error, struct timeval *time, unsigned flags) { struct drm_crtc *crtc; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (nouveau_crtc(crtc)->index == head) { + if (nouveau_crtc(crtc)->index == pipe) { return drm_calc_vbltimestamp_from_scanoutpos(dev, - head, max_error, time, flags, + pipe, max_error, time, flags, &crtc->hwmode); } } @@ -471,9 +472,13 @@ nouveau_display_create(struct drm_device *dev) if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { dev->mode_config.max_width = 4096; dev->mode_config.max_height = 4096; - } else { + } else + if (drm->device.info.family < NV_DEVICE_INFO_V0_FERMI) { dev->mode_config.max_width = 8192; dev->mode_config.max_height = 8192; + } else { + dev->mode_config.max_width = 16384; + dev->mode_config.max_height = 16384; } dev->mode_config.preferred_depth = 24; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 4182d21538c5..856abe0f070d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -65,12 +65,12 @@ int nouveau_display_init(struct drm_device *dev); void nouveau_display_fini(struct drm_device *dev); int nouveau_display_suspend(struct drm_device *dev, bool runtime); void nouveau_display_resume(struct drm_device *dev, bool runtime); -int nouveau_display_vblank_enable(struct drm_device *, int); -void nouveau_display_vblank_disable(struct drm_device *, int); -int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int, - int *, int *, ktime_t *, ktime_t *, - const struct drm_display_mode *); -int nouveau_display_vblstamp(struct drm_device *, int, int *, +int nouveau_display_vblank_enable(struct drm_device *, unsigned int); +void nouveau_display_vblank_disable(struct drm_device *, unsigned int); +int nouveau_display_scanoutpos(struct drm_device *, unsigned int, + unsigned int, int *, int *, ktime_t *, + ktime_t *, const struct drm_display_mode *); +int nouveau_display_vblstamp(struct drm_device *, unsigned int, int *, struct timeval *, unsigned); int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index ccefb645fd55..45ba67819199 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -862,18 +862,18 @@ nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv) static const struct drm_ioctl_desc nouveau_ioctls[] = { - DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_abi16_ioctl_getparam, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_abi16_ioctl_setparam, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_abi16_ioctl_channel_alloc, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_abi16_ioctl_channel_free, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_abi16_ioctl_grobj_alloc, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_abi16_ioctl_notifierobj_alloc, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_abi16_ioctl_gpuobj_free, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_abi16_ioctl_getparam, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_abi16_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_abi16_ioctl_channel_alloc, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_abi16_ioctl_channel_free, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_abi16_ioctl_grobj_alloc, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_abi16_ioctl_notifierobj_alloc, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_abi16_ioctl_gpuobj_free, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH|DRM_RENDER_ALLOW), }; long @@ -934,7 +934,7 @@ driver_stub = { .debugfs_cleanup = nouveau_debugfs_takedown, #endif - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = nouveau_display_vblank_enable, .disable_vblank = nouveau_display_vblank_disable, .get_scanout_position = nouveau_display_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 2791701685dc..59f27e774acb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -178,8 +178,30 @@ nouveau_fbcon_sync(struct fb_info *info) return 0; } +static int +nouveau_fbcon_open(struct fb_info *info, int user) +{ + struct nouveau_fbdev *fbcon = info->par; + struct nouveau_drm *drm = nouveau_drm(fbcon->dev); + int ret = pm_runtime_get_sync(drm->dev->dev); + if (ret < 0 && ret != -EACCES) + return ret; + return 0; +} + +static int +nouveau_fbcon_release(struct fb_info *info, int user) +{ + struct nouveau_fbdev *fbcon = info->par; + struct nouveau_drm *drm = nouveau_drm(fbcon->dev); + pm_runtime_put(drm->dev->dev); + return 0; +} + static struct fb_ops nouveau_fbcon_ops = { .owner = THIS_MODULE, + .fb_open = nouveau_fbcon_open, + .fb_release = nouveau_fbcon_release, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, .fb_fillrect = nouveau_fbcon_fillrect, @@ -195,6 +217,8 @@ static struct fb_ops nouveau_fbcon_ops = { static struct fb_ops nouveau_fbcon_sw_ops = { .owner = THIS_MODULE, + .fb_open = nouveau_fbcon_open, + .fb_release = nouveau_fbcon_release, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, .fb_fillrect = drm_fb_helper_cfb_fillrect, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 65af31441e9c..a7d69ce7abc1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -267,6 +267,12 @@ init_i2c(struct nvbios_init *init, int index) index = NVKM_I2C_BUS_PRI; if (init->outp && init->outp->i2c_upper_default) index = NVKM_I2C_BUS_SEC; + } else + if (index == 0x80) { + index = NVKM_I2C_BUS_PRI; + } else + if (index == 0x81) { + index = NVKM_I2C_BUS_SEC; } bus = nvkm_i2c_bus_find(i2c, index); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h index e0ec2a6b7b79..212800ecdce9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h @@ -8,7 +8,10 @@ struct nvbios_source { void *(*init)(struct nvkm_bios *, const char *); void (*fini)(void *); u32 (*read)(void *, u32 offset, u32 length, struct nvkm_bios *); + u32 (*size)(void *); bool rw; + bool ignore_checksum; + bool no_pcir; }; int nvbios_extend(struct nvkm_bios *, u32 length); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c index 792f017525f6..b2557e87afdd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c @@ -45,7 +45,7 @@ shadow_fetch(struct nvkm_bios *bios, struct shadow *mthd, u32 upto) u32 read = mthd->func->read(data, start, limit - start, bios); bios->size = start + read; } - return bios->size >= limit; + return bios->size >= upto; } static int @@ -55,14 +55,22 @@ shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd) struct nvbios_image image; int score = 1; - if (!shadow_fetch(bios, mthd, offset + 0x1000)) { - nvkm_debug(subdev, "%08x: header fetch failed\n", offset); - return 0; - } + if (mthd->func->no_pcir) { + image.base = 0; + image.type = 0; + image.size = mthd->func->size(mthd->data); + image.last = 1; + } else { + if (!shadow_fetch(bios, mthd, offset + 0x1000)) { + nvkm_debug(subdev, "%08x: header fetch failed\n", + offset); + return 0; + } - if (!nvbios_image(bios, idx, &image)) { - nvkm_debug(subdev, "image %d invalid\n", idx); - return 0; + if (!nvbios_image(bios, idx, &image)) { + nvkm_debug(subdev, "image %d invalid\n", idx); + return 0; + } } nvkm_debug(subdev, "%08x: type %02x, %d bytes\n", image.base, image.type, image.size); @@ -74,7 +82,8 @@ shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd) switch (image.type) { case 0x00: - if (nvbios_checksum(&bios->data[image.base], image.size)) { + if (!mthd->func->ignore_checksum && + nvbios_checksum(&bios->data[image.base], image.size)) { nvkm_debug(subdev, "%08x: checksum failed\n", image.base); if (mthd->func->rw) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c index bd60d7dd09f5..4bf486b57101 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c @@ -21,6 +21,7 @@ * */ #include "priv.h" + #include <core/pci.h> #if defined(__powerpc__) @@ -33,17 +34,26 @@ static u32 of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) { struct priv *priv = data; - if (offset + length <= priv->size) { + if (offset < priv->size) { + length = min_t(u32, length, priv->size - offset); memcpy_fromio(bios->data + offset, priv->data + offset, length); return length; } return 0; } +static u32 +of_size(void *data) +{ + struct priv *priv = data; + return priv->size; +} + static void * of_init(struct nvkm_bios *bios, const char *name) { - struct pci_dev *pdev = bios->subdev.device->func->pci(bios->subdev.device)->pdev; + struct nvkm_device *device = bios->subdev.device; + struct pci_dev *pdev = device->func->pci(device)->pdev; struct device_node *dn; struct priv *priv; if (!(dn = pci_device_to_OF_node(pdev))) @@ -62,7 +72,10 @@ nvbios_of = { .init = of_init, .fini = (void(*)(void *))kfree, .read = of_read, + .size = of_size, .rw = false, + .ignore_checksum = true, + .no_pcir = true, }; #else const struct nvbios_source diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c index 814cb51cc873..385a90f91ed6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c @@ -35,6 +35,8 @@ static const struct nvkm_device_agp_quirk nvkm_device_agp_quirks[] = { /* VIA Apollo PRO133x / GeForce FX 5600 Ultra - fdo#20341 */ { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_NVIDIA, 0x0311, 2 }, + /* SiS 761 does not support AGP cards, use PCI mode */ + { PCI_VENDOR_ID_SI, 0x0761, PCI_ANY_ID, PCI_ANY_ID, 0 }, {}, }; @@ -137,8 +139,10 @@ nvkm_agp_ctor(struct nvkm_pci *pci) while (quirk->hostbridge_vendor) { if (info.device->vendor == quirk->hostbridge_vendor && info.device->device == quirk->hostbridge_device && - pci->pdev->vendor == quirk->chip_vendor && - pci->pdev->device == quirk->chip_device) { + (quirk->chip_vendor == (u16)PCI_ANY_ID || + pci->pdev->vendor == quirk->chip_vendor) && + (quirk->chip_device == (u16)PCI_ANY_ID || + pci->pdev->device == quirk->chip_device)) { nvkm_info(subdev, "forcing default agp mode to %dX, " "use NvAGP=<mode> to override\n", quirk->mode); diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 9a4ba4f03567..ad09590e8a46 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -412,9 +412,6 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, dispc_mgr_go(omap_crtc->channel); omap_irq_register(crtc->dev, &omap_crtc->vblank_irq); } - - crtc->invert_dimensions = !!(crtc->primary->state->rotation & - (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))); } static int omap_crtc_atomic_set_property(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index d685e23449ce..5c6609cbb6a2 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -626,12 +626,12 @@ static int ioctl_gem_info(struct drm_device *dev, void *data, } static const struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = { - DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param, DRM_UNLOCKED|DRM_AUTH), - DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new, DRM_UNLOCKED|DRM_AUTH), - DRM_IOCTL_DEF_DRV(OMAP_GEM_CPU_PREP, ioctl_gem_cpu_prep, DRM_UNLOCKED|DRM_AUTH), - DRM_IOCTL_DEF_DRV(OMAP_GEM_CPU_FINI, ioctl_gem_cpu_fini, DRM_UNLOCKED|DRM_AUTH), - DRM_IOCTL_DEF_DRV(OMAP_GEM_INFO, ioctl_gem_info, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param, DRM_AUTH), + DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new, DRM_AUTH), + DRM_IOCTL_DEF_DRV(OMAP_GEM_CPU_PREP, ioctl_gem_cpu_prep, DRM_AUTH), + DRM_IOCTL_DEF_DRV(OMAP_GEM_CPU_FINI, ioctl_gem_cpu_fini, DRM_AUTH), + DRM_IOCTL_DEF_DRV(OMAP_GEM_INFO, ioctl_gem_info, DRM_AUTH), }; /* @@ -839,7 +839,7 @@ static struct drm_driver omap_drm_driver = { .preclose = dev_preclose, .postclose = dev_postclose, .set_busid = drm_platform_set_busid, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = omap_irq_enable_vblank, .disable_vblank = omap_irq_disable_vblank, #ifdef CONFIG_DEBUG_FS diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 12081e61d45a..5c367aad8a6e 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -129,8 +129,8 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); int omap_gem_resume(struct device *dev); #endif -int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id); -void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id); +int omap_irq_enable_vblank(struct drm_device *dev, unsigned int pipe); +void omap_irq_disable_vblank(struct drm_device *dev, unsigned int pipe); void __omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq); void __omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq); void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq); diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 51b1219af87f..636a1f921569 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -171,7 +171,7 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, uint32_t w = win->src_w; uint32_t h = win->src_h; - switch (win->rotation & 0xf) { + switch (win->rotation & DRM_ROTATE_MASK) { default: dev_err(fb->dev->dev, "invalid rotation: %02x", (uint32_t)win->rotation); @@ -209,7 +209,7 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, info->rotation_type = OMAP_DSS_ROT_TILER; info->screen_width = omap_gem_tiled_stride(plane->bo, orient); } else { - switch (win->rotation & 0xf) { + switch (win->rotation & DRM_ROTATE_MASK) { case 0: case BIT(DRM_ROTATE_0): /* OK */ diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index 0cc71c9d08d5..27c297672076 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -140,15 +140,12 @@ static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, struct vm_area_struct *vma) { struct drm_gem_object *obj = buffer->priv; - struct drm_device *dev = obj->dev; int ret = 0; if (WARN_ON(!obj->filp)) return -EINVAL; - mutex_lock(&dev->struct_mutex); ret = drm_gem_mmap_obj(obj, omap_gem_mmap_size(obj), vma); - mutex_unlock(&dev->struct_mutex); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c index 249c0330d6ce..60e1e8016708 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/drivers/gpu/drm/omapdrm/omap_irq.c @@ -134,7 +134,7 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, /** * enable_vblank - enable vblank interrupt events * @dev: DRM device - * @crtc: which irq to enable + * @pipe: which irq to enable * * Enable vblank interrupts for @crtc. If the device doesn't have * a hardware vblank counter, this routine should be a no-op, since @@ -144,13 +144,13 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, * Zero on success, appropriate errno if the given @crtc's vblank * interrupt cannot be enabled. */ -int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id) +int omap_irq_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct omap_drm_private *priv = dev->dev_private; - struct drm_crtc *crtc = priv->crtcs[crtc_id]; + struct drm_crtc *crtc = priv->crtcs[pipe]; unsigned long flags; - DBG("dev=%p, crtc=%d", dev, crtc_id); + DBG("dev=%p, crtc=%u", dev, pipe); spin_lock_irqsave(&list_lock, flags); priv->vblank_mask |= pipe2vbl(crtc); @@ -163,19 +163,19 @@ int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id) /** * disable_vblank - disable vblank interrupt events * @dev: DRM device - * @crtc: which irq to enable + * @pipe: which irq to enable * * Disable vblank interrupts for @crtc. If the device doesn't have * a hardware vblank counter, this routine should be a no-op, since * interrupts will have to stay on to keep the count accurate. */ -void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id) +void omap_irq_disable_vblank(struct drm_device *dev, unsigned int pipe) { struct omap_drm_private *priv = dev->dev_private; - struct drm_crtc *crtc = priv->crtcs[crtc_id]; + struct drm_crtc *crtc = priv->crtcs[pipe]; unsigned long flags; - DBG("dev=%p, crtc=%d", dev, crtc_id); + DBG("dev=%p, crtc=%u", dev, pipe); spin_lock_irqsave(&list_lock, flags); priv->vblank_mask &= ~pipe2vbl(crtc); diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 09e363bb55f2..3054bda72688 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -108,7 +108,7 @@ static void omap_plane_atomic_update(struct drm_plane *plane, win.src_x = state->src_x >> 16; win.src_y = state->src_y >> 16; - switch (state->rotation & 0xf) { + switch (state->rotation & DRM_ROTATE_MASK) { case BIT(DRM_ROTATE_90): case BIT(DRM_ROTATE_270): win.src_w = state->src_h >> 16; diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index dd845f82cc24..183aea1abebc 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -244,6 +244,10 @@ static int qxl_crtc_page_flip(struct drm_crtc *crtc, ret = qxl_bo_reserve(bo, false); if (ret) return ret; + ret = qxl_bo_pin(bo, bo->type, NULL); + qxl_bo_unreserve(bo); + if (ret) + return ret; qxl_draw_dirty_fb(qdev, qfb_src, bo, 0, 0, &norect, one_clip_rect, inc); @@ -257,7 +261,11 @@ static int qxl_crtc_page_flip(struct drm_crtc *crtc, } drm_vblank_put(dev, qcrtc->index); - qxl_bo_unreserve(bo); + ret = qxl_bo_reserve(bo, false); + if (!ret) { + qxl_bo_unpin(bo); + qxl_bo_unreserve(bo); + } return 0; } @@ -618,7 +626,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, adjusted_mode->hdisplay, adjusted_mode->vdisplay); - if (qcrtc->index == 0) + if (bo->is_primary == false) recreate_primary = true; if (bo->surf.stride * bo->surf.height > qdev->vram_size) { diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index 83f6f0b5e9ef..7307b07fe06b 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -196,17 +196,18 @@ static int qxl_pm_restore(struct device *dev) return qxl_drm_resume(drm_dev, false); } -static u32 qxl_noop_get_vblank_counter(struct drm_device *dev, int crtc) +static u32 qxl_noop_get_vblank_counter(struct drm_device *dev, + unsigned int pipe) { return 0; } -static int qxl_noop_enable_vblank(struct drm_device *dev, int crtc) +static int qxl_noop_enable_vblank(struct drm_device *dev, unsigned int pipe) { return 0; } -static void qxl_noop_disable_vblank(struct drm_device *dev, int crtc) +static void qxl_noop_disable_vblank(struct drm_device *dev, unsigned int pipe) { } diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index 41c422fee31a..c4a552637c93 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -144,14 +144,17 @@ static void qxl_dirty_update(struct qxl_fbdev *qfbdev, spin_lock_irqsave(&qfbdev->dirty.lock, flags); - if (qfbdev->dirty.y1 < y) - y = qfbdev->dirty.y1; - if (qfbdev->dirty.y2 > y2) - y2 = qfbdev->dirty.y2; - if (qfbdev->dirty.x1 < x) - x = qfbdev->dirty.x1; - if (qfbdev->dirty.x2 > x2) - x2 = qfbdev->dirty.x2; + if ((qfbdev->dirty.y2 - qfbdev->dirty.y1) && + (qfbdev->dirty.x2 - qfbdev->dirty.x1)) { + if (qfbdev->dirty.y1 < y) + y = qfbdev->dirty.y1; + if (qfbdev->dirty.y2 > y2) + y2 = qfbdev->dirty.y2; + if (qfbdev->dirty.x1 < x) + x = qfbdev->dirty.x1; + if (qfbdev->dirty.x2 > x2) + x2 = qfbdev->dirty.x2; + } qfbdev->dirty.x1 = x; qfbdev->dirty.x2 = x2; diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index bda5c5f80c24..2ae8577497ca 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -422,21 +422,21 @@ static int qxl_alloc_surf_ioctl(struct drm_device *dev, void *data, } const struct drm_ioctl_desc qxl_ioctls[] = { - DRM_IOCTL_DEF_DRV(QXL_ALLOC, qxl_alloc_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(QXL_ALLOC, qxl_alloc_ioctl, DRM_AUTH), - DRM_IOCTL_DEF_DRV(QXL_MAP, qxl_map_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(QXL_MAP, qxl_map_ioctl, DRM_AUTH), DRM_IOCTL_DEF_DRV(QXL_EXECBUFFER, qxl_execbuffer_ioctl, - DRM_AUTH|DRM_UNLOCKED), + DRM_AUTH), DRM_IOCTL_DEF_DRV(QXL_UPDATE_AREA, qxl_update_area_ioctl, - DRM_AUTH|DRM_UNLOCKED), + DRM_AUTH), DRM_IOCTL_DEF_DRV(QXL_GETPARAM, qxl_getparam_ioctl, - DRM_AUTH|DRM_UNLOCKED), + DRM_AUTH), DRM_IOCTL_DEF_DRV(QXL_CLIENTCAP, qxl_clientcap_ioctl, - DRM_AUTH|DRM_UNLOCKED), + DRM_AUTH), DRM_IOCTL_DEF_DRV(QXL_ALLOC_SURF, qxl_alloc_surf_ioctl, - DRM_AUTH|DRM_UNLOCKED), + DRM_AUTH), }; int qxl_max_ioctls = ARRAY_SIZE(qxl_ioctls); diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c index b66ec331c17c..4efa8e261baf 100644 --- a/drivers/gpu/drm/qxl/qxl_release.c +++ b/drivers/gpu/drm/qxl/qxl_release.c @@ -307,7 +307,7 @@ int qxl_alloc_surface_release_reserved(struct qxl_device *qdev, idr_ret = qxl_release_alloc(qdev, QXL_RELEASE_SURFACE_CMD, release); if (idr_ret < 0) return idr_ret; - bo = qxl_bo_ref(to_qxl_bo(entry->tv.bo)); + bo = to_qxl_bo(entry->tv.bo); (*release)->release_offset = create_rel->release_offset + 64; @@ -316,8 +316,6 @@ int qxl_alloc_surface_release_reserved(struct qxl_device *qdev, info = qxl_release_map(qdev, *release); info->id = idr_ret; qxl_release_unmap(qdev, *release, info); - - qxl_bo_unref(&bo); return 0; } diff --git a/drivers/gpu/drm/r128/r128_cce.c b/drivers/gpu/drm/r128/r128_cce.c index 2c45ac9c1dc3..14fd83b5f497 100644 --- a/drivers/gpu/drm/r128/r128_cce.c +++ b/drivers/gpu/drm/r128/r128_cce.c @@ -311,7 +311,7 @@ static void r128_cce_init_ring_buffer(struct drm_device *dev, /* The manual (p. 2) says this address is in "VM space". This * means it's an offset from the start of AGP space. */ -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (!dev_priv->is_pci) ring_start = dev_priv->cce_ring->offset - dev->agp->base; else @@ -505,7 +505,7 @@ static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init) (drm_r128_sarea_t *) ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (!dev_priv->is_pci) { drm_legacy_ioremap_wc(dev_priv->cce_ring, dev); drm_legacy_ioremap_wc(dev_priv->ring_rptr, dev); @@ -529,7 +529,7 @@ static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init) (void *)(unsigned long)dev->agp_buffer_map->offset; } -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (!dev_priv->is_pci) dev_priv->cce_buffers_offset = dev->agp->base; else @@ -552,7 +552,7 @@ static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init) dev_priv->sarea_priv->last_dispatch = 0; R128_WRITE(R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch); -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->is_pci) { #endif dev_priv->gart_info.table_mask = DMA_BIT_MASK(32); @@ -568,7 +568,7 @@ static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init) return -ENOMEM; } R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr); -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) } #endif @@ -600,7 +600,7 @@ int r128_do_cleanup_cce(struct drm_device *dev) if (dev->dev_private) { drm_r128_private_t *dev_priv = dev->dev_private; -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (!dev_priv->is_pci) { if (dev_priv->cce_ring != NULL) drm_legacy_ioremapfree(dev_priv->cce_ring, dev); diff --git a/drivers/gpu/drm/r128/r128_drv.h b/drivers/gpu/drm/r128/r128_drv.h index 723e5d6f10a4..09143b840482 100644 --- a/drivers/gpu/drm/r128/r128_drv.h +++ b/drivers/gpu/drm/r128/r128_drv.h @@ -154,9 +154,9 @@ extern int r128_wait_ring(drm_r128_private_t *dev_priv, int n); extern int r128_do_cce_idle(drm_r128_private_t *dev_priv); extern int r128_do_cleanup_cce(struct drm_device *dev); -extern int r128_enable_vblank(struct drm_device *dev, int crtc); -extern void r128_disable_vblank(struct drm_device *dev, int crtc); -extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc); +extern int r128_enable_vblank(struct drm_device *dev, unsigned int pipe); +extern void r128_disable_vblank(struct drm_device *dev, unsigned int pipe); +extern u32 r128_get_vblank_counter(struct drm_device *dev, unsigned int pipe); extern irqreturn_t r128_driver_irq_handler(int irq, void *arg); extern void r128_driver_irq_preinstall(struct drm_device *dev); extern int r128_driver_irq_postinstall(struct drm_device *dev); diff --git a/drivers/gpu/drm/r128/r128_irq.c b/drivers/gpu/drm/r128/r128_irq.c index c2ae496babb7..9730f4918944 100644 --- a/drivers/gpu/drm/r128/r128_irq.c +++ b/drivers/gpu/drm/r128/r128_irq.c @@ -34,11 +34,11 @@ #include <drm/r128_drm.h> #include "r128_drv.h" -u32 r128_get_vblank_counter(struct drm_device *dev, int crtc) +u32 r128_get_vblank_counter(struct drm_device *dev, unsigned int pipe) { const drm_r128_private_t *dev_priv = dev->dev_private; - if (crtc != 0) + if (pipe != 0) return 0; return atomic_read(&dev_priv->vbl_received); @@ -62,12 +62,12 @@ irqreturn_t r128_driver_irq_handler(int irq, void *arg) return IRQ_NONE; } -int r128_enable_vblank(struct drm_device *dev, int crtc) +int r128_enable_vblank(struct drm_device *dev, unsigned int pipe) { drm_r128_private_t *dev_priv = dev->dev_private; - if (crtc != 0) { - DRM_ERROR("%s: bad crtc %d\n", __func__, crtc); + if (pipe != 0) { + DRM_ERROR("%s: bad crtc %u\n", __func__, pipe); return -EINVAL; } @@ -75,10 +75,10 @@ int r128_enable_vblank(struct drm_device *dev, int crtc) return 0; } -void r128_disable_vblank(struct drm_device *dev, int crtc) +void r128_disable_vblank(struct drm_device *dev, unsigned int pipe) { - if (crtc != 0) - DRM_ERROR("%s: bad crtc %d\n", __func__, crtc); + if (pipe != 0) + DRM_ERROR("%s: bad crtc %u\n", __func__, pipe); /* * FIXME: implement proper interrupt disable by using the vblank diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index c3872598b85a..65adb9c72377 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -1624,8 +1624,9 @@ radeon_atom_encoder_dpms_avivo(struct drm_encoder *encoder, int mode) } else atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - args.ucAction = ATOM_LCD_BLON; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + atombios_set_backlight_level(radeon_encoder, dig->backlight_level); } break; case DRM_MODE_DPMS_STANDBY: @@ -1706,8 +1707,7 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); } if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - atombios_dig_transmitter_setup(encoder, - ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); + atombios_set_backlight_level(radeon_encoder, dig->backlight_level); if (ext_encoder) atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); break; diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index c9e0fbbf76a3..46f87d4aaf31 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -34,6 +34,8 @@ #define MAX(a,b) (((a)>(b))?(a):(b)) #define MIN(a,b) (((a)<(b))?(a):(b)) +#define REG_SAFE_BM_SIZE ARRAY_SIZE(evergreen_reg_safe_bm) + int r600_dma_cs_next_reloc(struct radeon_cs_parser *p, struct radeon_bo_list **cs_reloc); struct evergreen_cs_track { @@ -84,6 +86,7 @@ struct evergreen_cs_track { u32 htile_surface; struct radeon_bo *htile_bo; unsigned long indirect_draw_buffer_size; + const unsigned *reg_safe_bm; }; static u32 evergreen_cs_get_aray_mode(u32 tiling_flags) @@ -444,7 +447,7 @@ static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned i * command stream. */ if (!surf.mode) { - volatile u32 *ib = p->ib.ptr; + uint32_t *ib = p->ib.ptr; unsigned long tmp, nby, bsize, size, min = 0; /* find the height the ddx wants */ @@ -1083,41 +1086,18 @@ static int evergreen_cs_parse_packet0(struct radeon_cs_parser *p, } /** - * evergreen_cs_check_reg() - check if register is authorized or not + * evergreen_cs_handle_reg() - process registers that need special handling. * @parser: parser structure holding parsing context * @reg: register we are testing * @idx: index into the cs buffer - * - * This function will test against evergreen_reg_safe_bm and return 0 - * if register is safe. If register is not flag as safe this function - * will test it against a list of register needind special handling. */ -static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) +static int evergreen_cs_handle_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) { struct evergreen_cs_track *track = (struct evergreen_cs_track *)p->track; struct radeon_bo_list *reloc; - u32 last_reg; - u32 m, i, tmp, *ib; + u32 tmp, *ib; int r; - if (p->rdev->family >= CHIP_CAYMAN) - last_reg = ARRAY_SIZE(cayman_reg_safe_bm); - else - last_reg = ARRAY_SIZE(evergreen_reg_safe_bm); - - i = (reg >> 7); - if (i >= last_reg) { - dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); - return -EINVAL; - } - m = 1 << ((reg >> 2) & 31); - if (p->rdev->family >= CHIP_CAYMAN) { - if (!(cayman_reg_safe_bm[i] & m)) - return 0; - } else { - if (!(evergreen_reg_safe_bm[i] & m)) - return 0; - } ib = p->ib.ptr; switch (reg) { /* force following reg to 0 in an attempt to disable out buffer @@ -1764,29 +1744,27 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) return 0; } -static bool evergreen_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) +/** + * evergreen_is_safe_reg() - check if register is authorized or not + * @parser: parser structure holding parsing context + * @reg: register we are testing + * + * This function will test against reg_safe_bm and return true + * if register is safe or false otherwise. + */ +static inline bool evergreen_is_safe_reg(struct radeon_cs_parser *p, u32 reg) { - u32 last_reg, m, i; - - if (p->rdev->family >= CHIP_CAYMAN) - last_reg = ARRAY_SIZE(cayman_reg_safe_bm); - else - last_reg = ARRAY_SIZE(evergreen_reg_safe_bm); + struct evergreen_cs_track *track = p->track; + u32 m, i; i = (reg >> 7); - if (i >= last_reg) { - dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); + if (unlikely(i >= REG_SAFE_BM_SIZE)) { return false; } m = 1 << ((reg >> 2) & 31); - if (p->rdev->family >= CHIP_CAYMAN) { - if (!(cayman_reg_safe_bm[i] & m)) - return true; - } else { - if (!(evergreen_reg_safe_bm[i] & m)) - return true; - } - dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); + if (!(track->reg_safe_bm[i] & m)) + return true; + return false; } @@ -1795,7 +1773,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, { struct radeon_bo_list *reloc; struct evergreen_cs_track *track; - volatile u32 *ib; + uint32_t *ib; unsigned idx; unsigned i; unsigned start_reg, end_reg, reg; @@ -2321,9 +2299,10 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n"); return -EINVAL; } - for (i = 0; i < pkt->count; i++) { - reg = start_reg + (4 * i); - r = evergreen_cs_check_reg(p, reg, idx+1+i); + for (reg = start_reg, idx++; reg <= end_reg; reg += 4, idx++) { + if (evergreen_is_safe_reg(p, reg)) + continue; + r = evergreen_cs_handle_reg(p, reg, idx); if (r) return r; } @@ -2337,9 +2316,10 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, DRM_ERROR("bad PACKET3_SET_CONTEXT_REG\n"); return -EINVAL; } - for (i = 0; i < pkt->count; i++) { - reg = start_reg + (4 * i); - r = evergreen_cs_check_reg(p, reg, idx+1+i); + for (reg = start_reg, idx++; reg <= end_reg; reg += 4, idx++) { + if (evergreen_is_safe_reg(p, reg)) + continue; + r = evergreen_cs_handle_reg(p, reg, idx); if (r) return r; } @@ -2594,8 +2574,11 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, } else { /* SRC is a reg. */ reg = radeon_get_ib_value(p, idx+1) << 2; - if (!evergreen_is_safe_reg(p, reg, idx+1)) + if (!evergreen_is_safe_reg(p, reg)) { + dev_warn(p->dev, "forbidden register 0x%08x at %d\n", + reg, idx + 1); return -EINVAL; + } } if (idx_value & 0x2) { u64 offset; @@ -2618,8 +2601,11 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, } else { /* DST is a reg. */ reg = radeon_get_ib_value(p, idx+3) << 2; - if (!evergreen_is_safe_reg(p, reg, idx+3)) + if (!evergreen_is_safe_reg(p, reg)) { + dev_warn(p->dev, "forbidden register 0x%08x at %d\n", + reg, idx + 3); return -EINVAL; + } } break; case PACKET3_NOP: @@ -2644,11 +2630,15 @@ int evergreen_cs_parse(struct radeon_cs_parser *p) if (track == NULL) return -ENOMEM; evergreen_cs_track_init(track); - if (p->rdev->family >= CHIP_CAYMAN) + if (p->rdev->family >= CHIP_CAYMAN) { tmp = p->rdev->config.cayman.tile_config; - else + track->reg_safe_bm = cayman_reg_safe_bm; + } else { tmp = p->rdev->config.evergreen.tile_config; - + track->reg_safe_bm = evergreen_reg_safe_bm; + } + BUILD_BUG_ON(ARRAY_SIZE(cayman_reg_safe_bm) != REG_SAFE_BM_SIZE); + BUILD_BUG_ON(ARRAY_SIZE(evergreen_reg_safe_bm) != REG_SAFE_BM_SIZE); switch (tmp & 0xf) { case 0: track->npipes = 1; @@ -2757,7 +2747,7 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) struct radeon_cs_chunk *ib_chunk = p->chunk_ib; struct radeon_bo_list *src_reloc, *dst_reloc, *dst2_reloc; u32 header, cmd, count, sub_cmd; - volatile u32 *ib = p->ib.ptr; + uint32_t *ib = p->ib.ptr; u32 idx; u64 src_offset, dst_offset, dst2_offset; int r; diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index 98f9adaccc3d..e231eeafef23 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -1837,7 +1837,7 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev, SET_RING_HEAD(dev_priv, 0); dev_priv->ring.tail = 0; -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->flags & RADEON_IS_AGP) { rptr_addr = dev_priv->ring_rptr->offset - dev->agp->base + @@ -1863,7 +1863,7 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev, dev_priv->ring.size_l2qw); #endif -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->flags & RADEON_IS_AGP) { /* XXX */ radeon_write_agp_base(dev_priv, dev->agp->base); @@ -1946,7 +1946,7 @@ int r600_do_cleanup_cp(struct drm_device *dev) if (dev->irq_enabled) drm_irq_uninstall(dev); -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->flags & RADEON_IS_AGP) { if (dev_priv->cp_ring != NULL) { drm_legacy_ioremapfree(dev_priv->cp_ring, dev); @@ -2089,7 +2089,7 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, } } -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) /* XXX */ if (dev_priv->flags & RADEON_IS_AGP) { drm_legacy_ioremap_wc(dev_priv->cp_ring, dev); @@ -2148,7 +2148,7 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, * location in the card and on the bus, though we have to * align it down. */ -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) /* XXX */ if (dev_priv->flags & RADEON_IS_AGP) { base = dev->agp->base; @@ -2175,7 +2175,7 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, base, dev_priv->gart_vm_start); } -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) /* XXX */ if (dev_priv->flags & RADEON_IS_AGP) dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset @@ -2212,7 +2212,7 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->flags & RADEON_IS_AGP) { /* XXX turn off pcie gart */ } else diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 77e9d07c55b6..59acd0e5c2c6 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -25,7 +25,6 @@ #include <linux/acpi.h> #include <linux/slab.h> #include <linux/power_supply.h> -#include <linux/vga_switcheroo.h> #include <acpi/video.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index a9297b2c3524..fe994aac3b04 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -28,7 +28,7 @@ #include "radeon.h" #include <drm/radeon_drm.h> -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) struct radeon_agpmode_quirk { u32 hostbridge_vendor; @@ -123,7 +123,7 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = { int radeon_agp_init(struct radeon_device *rdev) { -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) struct radeon_agpmode_quirk *p = radeon_agpmode_quirk_list; struct drm_agp_mode mode; struct drm_agp_info info; @@ -257,7 +257,7 @@ int radeon_agp_init(struct radeon_device *rdev) void radeon_agp_resume(struct radeon_device *rdev) { -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) int r; if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); @@ -269,7 +269,7 @@ void radeon_agp_resume(struct radeon_device *rdev) void radeon_agp_fini(struct radeon_device *rdev) { -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (rdev->ddev->agp && rdev->ddev->agp->acquired) { drm_agp_release(rdev->ddev); } diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index f2421bc3e901..1d4d4520a0ac 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -31,7 +31,6 @@ #include <drm/drm_crtc_helper.h> #include <drm/radeon_drm.h> #include <linux/vgaarb.h> -#include <linux/vga_switcheroo.h> #include "radeon_reg.h" #include "radeon.h" #include "radeon_asic.h" diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 8bc7d0bbd3c8..a771b9f0bf98 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -535,7 +535,7 @@ static bool radeon_atpx_detect(void) if (has_atpx && vga_count == 2) { acpi_get_name(radeon_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer); - printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n", + printk(KERN_INFO "vga_switcheroo: detected switching method %s handle\n", acpi_method_name); radeon_atpx_priv.atpx_detected = true; return true; diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index d27e4ccb848c..21b6732425c5 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -30,7 +30,6 @@ #include "radeon.h" #include "atom.h" -#include <linux/vga_switcheroo.h> #include <linux/slab.h> #include <linux/acpi.h> /* diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index ea134a7d51a5..500287eff55d 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -762,7 +762,7 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, ((dev_priv->gart_vm_start - 1) & 0xffff0000) | (dev_priv->fb_location >> 16)); -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->flags & RADEON_IS_AGP) { radeon_write_agp_base(dev_priv, dev->agp->base); @@ -791,7 +791,7 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, SET_RING_HEAD(dev_priv, cur_read_ptr); dev_priv->ring.tail = cur_read_ptr; -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->flags & RADEON_IS_AGP) { RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, dev_priv->ring_rptr->offset @@ -1335,7 +1335,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, } } -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->flags & RADEON_IS_AGP) { drm_legacy_ioremap_wc(dev_priv->cp_ring, dev); drm_legacy_ioremap_wc(dev_priv->ring_rptr, dev); @@ -1394,7 +1394,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, * location in the card and on the bus, though we have to * align it down. */ -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->flags & RADEON_IS_AGP) { base = dev->agp->base; /* Check if valid */ @@ -1424,7 +1424,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, RADEON_READ(RADEON_CONFIG_APER_SIZE); } -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->flags & RADEON_IS_AGP) dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset - dev->agp->base @@ -1455,7 +1455,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->flags & RADEON_IS_AGP) { /* Turn off PCI GART */ radeon_set_pcigart(dev_priv, 0); @@ -1566,7 +1566,7 @@ static int radeon_do_cleanup_cp(struct drm_device * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->flags & RADEON_IS_AGP) { if (dev_priv->cp_ring != NULL) { drm_legacy_ioremapfree(dev_priv->cp_ring, dev); @@ -1625,7 +1625,7 @@ static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_pri DRM_DEBUG("Starting radeon_do_resume_cp()\n"); -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (dev_priv->flags & RADEON_IS_AGP) { /* Turn off PCI GART */ radeon_set_pcigart(dev_priv, 0); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index f3f562f6d848..c566993a2ec3 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1197,7 +1197,7 @@ static void radeon_check_arguments(struct radeon_device *rdev) * radeon_switcheroo_set_state - set switcheroo state * * @pdev: pci dev pointer - * @state: vga switcheroo state + * @state: vga_switcheroo state * * Callback for the switcheroo driver. Suspends or resumes the * the asics before or after it is powered up using ACPI methods. diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 0503af748d99..a8d9927ed9eb 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1634,18 +1634,8 @@ int radeon_modeset_init(struct radeon_device *rdev) radeon_fbdev_init(rdev); drm_kms_helper_poll_init(rdev->ddev); - if (rdev->pm.dpm_enabled) { - /* do dpm late init */ - ret = radeon_pm_late_init(rdev); - if (ret) { - rdev->pm.dpm_enabled = false; - DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); - } - /* set the dpm state for PX since there won't be - * a modeset to call this. - */ - radeon_pm_compute_clocks(rdev); - } + /* do pm late init */ + ret = radeon_pm_late_init(rdev); return 0; } @@ -1799,8 +1789,9 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, * unknown small number of scanlines wrt. real scanout position. * */ -int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, - int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, +int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, + unsigned int flags, int *vpos, int *hpos, + ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode) { u32 stat_crtc = 0, vbl = 0, position = 0; @@ -1816,42 +1807,42 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl *stime = ktime_get(); if (ASIC_IS_DCE4(rdev)) { - if (crtc == 0) { + if (pipe == 0) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC0_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC0_REGISTER_OFFSET); ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 1) { + if (pipe == 1) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC1_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC1_REGISTER_OFFSET); ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 2) { + if (pipe == 2) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC2_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC2_REGISTER_OFFSET); ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 3) { + if (pipe == 3) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC3_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC3_REGISTER_OFFSET); ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 4) { + if (pipe == 4) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC4_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC4_REGISTER_OFFSET); ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 5) { + if (pipe == 5) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC5_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + @@ -1859,19 +1850,19 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl ret |= DRM_SCANOUTPOS_VALID; } } else if (ASIC_IS_AVIVO(rdev)) { - if (crtc == 0) { + if (pipe == 0) { vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END); position = RREG32(AVIVO_D1CRTC_STATUS_POSITION); ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 1) { + if (pipe == 1) { vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END); position = RREG32(AVIVO_D2CRTC_STATUS_POSITION); ret |= DRM_SCANOUTPOS_VALID; } } else { /* Pre-AVIVO: Different encoding of scanout pos and vblank interval. */ - if (crtc == 0) { + if (pipe == 0) { /* Assume vbl_end == 0, get vbl_start from * upper 16 bits. */ @@ -1885,7 +1876,7 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 1) { + if (pipe == 1) { vbl = (RREG32(RADEON_CRTC2_V_TOTAL_DISP) & RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT; position = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index 5e09c061847f..6cddae44fa6e 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -265,7 +265,6 @@ static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topol { struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr); struct drm_device *dev = master->base.dev; - struct radeon_device *rdev = dev->dev_private; struct radeon_connector *radeon_connector; struct drm_connector *connector; @@ -286,12 +285,19 @@ static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topol drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); drm_mode_connector_set_path_property(connector, pathprop); + return connector; +} + +static void radeon_dp_register_mst_connector(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; + drm_modeset_lock_all(dev); radeon_fb_add_connector(rdev, connector); drm_modeset_unlock_all(dev); drm_connector_register(connector); - return connector; } static void radeon_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, @@ -324,6 +330,7 @@ static void radeon_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) struct drm_dp_mst_topology_cbs mst_cbs = { .add_connector = radeon_dp_add_mst_connector, + .register_connector = radeon_dp_register_mst_connector, .destroy_connector = radeon_dp_destroy_mst_connector, .hotplug = radeon_dp_mst_hotplug, }; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index e30c1d73b4ca..5b6a6f5b3619 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -105,10 +105,10 @@ void radeon_driver_preclose_kms(struct drm_device *dev, struct drm_file *file_priv); int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon); int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon); -u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc); -int radeon_enable_vblank_kms(struct drm_device *dev, int crtc); -void radeon_disable_vblank_kms(struct drm_device *dev, int crtc); -int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, +u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe); +int radeon_enable_vblank_kms(struct drm_device *dev, unsigned int pipe); +void radeon_disable_vblank_kms(struct drm_device *dev, unsigned int pipe); +int radeon_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe, int *max_error, struct timeval *vblank_time, unsigned flags); @@ -124,9 +124,8 @@ void radeon_gem_object_close(struct drm_gem_object *obj, struct dma_buf *radeon_gem_prime_export(struct drm_device *dev, struct drm_gem_object *gobj, int flags); -extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, - unsigned int flags, - int *vpos, int *hpos, +extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int crtc, + unsigned int flags, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode); extern bool radeon_is_px(struct drm_device *dev); diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 46bd3938282c..0caafc7a6e17 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -404,9 +404,9 @@ extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file * extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void radeon_do_release(struct drm_device * dev); -extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc); -extern int radeon_enable_vblank(struct drm_device *dev, int crtc); -extern void radeon_disable_vblank(struct drm_device *dev, int crtc); +extern u32 radeon_get_vblank_counter(struct drm_device *dev, unsigned int pipe); +extern int radeon_enable_vblank(struct drm_device *dev, unsigned int pipe); +extern void radeon_disable_vblank(struct drm_device *dev, unsigned int pipe); extern irqreturn_t radeon_driver_irq_handler(int irq, void *arg); extern void radeon_driver_irq_preinstall(struct drm_device * dev); extern int radeon_driver_irq_postinstall(struct drm_device *dev); diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 7214858ffcea..26da2f4d7b4f 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -48,40 +48,10 @@ struct radeon_fbdev { struct radeon_device *rdev; }; -/** - * radeon_fb_helper_set_par - Hide cursor on CRTCs used by fbdev. - * - * @info: fbdev info - * - * This function hides the cursor on all CRTCs used by fbdev. - */ -static int radeon_fb_helper_set_par(struct fb_info *info) -{ - int ret; - - ret = drm_fb_helper_set_par(info); - - /* XXX: with universal plane support fbdev will automatically disable - * all non-primary planes (including the cursor) - */ - if (ret == 0) { - struct drm_fb_helper *fb_helper = info->par; - int i; - - for (i = 0; i < fb_helper->crtc_count; i++) { - struct drm_crtc *crtc = fb_helper->crtc_info[i].mode_set.crtc; - - radeon_crtc_cursor_set2(crtc, NULL, 0, 0, 0, 0, 0); - } - } - - return ret; -} - static struct fb_ops radeonfb_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = radeon_fb_helper_set_par, + .fb_set_par = drm_fb_helper_set_par, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, @@ -427,3 +397,19 @@ void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector { drm_fb_helper_remove_one_connector(&rdev->mode_info.rfbdev->helper, connector); } + +void radeon_fbdev_restore_mode(struct radeon_device *rdev) +{ + struct radeon_fbdev *rfbdev = rdev->mode_info.rfbdev; + struct drm_fb_helper *fb_helper; + int ret; + + if (!rfbdev) + return; + + fb_helper = &rfbdev->helper; + + ret = drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); + if (ret) + DRM_DEBUG("failed to restore crtc mode\n"); +} diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c index 244b19bab2e7..688afb62f7c4 100644 --- a/drivers/gpu/drm/radeon/radeon_irq.c +++ b/drivers/gpu/drm/radeon/radeon_irq.c @@ -62,12 +62,12 @@ static void r500_vbl_irq_set_state(struct drm_device *dev, u32 mask, int state) RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); } -int radeon_enable_vblank(struct drm_device *dev, int crtc) +int radeon_enable_vblank(struct drm_device *dev, unsigned int pipe) { drm_radeon_private_t *dev_priv = dev->dev_private; if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) { - switch (crtc) { + switch (pipe) { case 0: r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 1); break; @@ -75,12 +75,12 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc) r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 1); break; default: - DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", - crtc); + DRM_ERROR("tried to enable vblank on non-existent crtc %u\n", + pipe); return -EINVAL; } } else { - switch (crtc) { + switch (pipe) { case 0: radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1); break; @@ -88,8 +88,8 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc) radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1); break; default: - DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", - crtc); + DRM_ERROR("tried to enable vblank on non-existent crtc %u\n", + pipe); return -EINVAL; } } @@ -97,12 +97,12 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc) return 0; } -void radeon_disable_vblank(struct drm_device *dev, int crtc) +void radeon_disable_vblank(struct drm_device *dev, unsigned int pipe) { drm_radeon_private_t *dev_priv = dev->dev_private; if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) { - switch (crtc) { + switch (pipe) { case 0: r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 0); break; @@ -110,12 +110,12 @@ void radeon_disable_vblank(struct drm_device *dev, int crtc) r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 0); break; default: - DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", - crtc); + DRM_ERROR("tried to enable vblank on non-existent crtc %u\n", + pipe); break; } } else { - switch (crtc) { + switch (pipe) { case 0: radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0); break; @@ -123,8 +123,8 @@ void radeon_disable_vblank(struct drm_device *dev, int crtc) radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0); break; default: - DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", - crtc); + DRM_ERROR("tried to enable vblank on non-existent crtc %u\n", + pipe); break; } } @@ -255,7 +255,7 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr) return ret; } -u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc) +u32 radeon_get_vblank_counter(struct drm_device *dev, unsigned int pipe) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -264,18 +264,18 @@ u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc) return -EINVAL; } - if (crtc < 0 || crtc > 1) { - DRM_ERROR("Invalid crtc %d\n", crtc); + if (pipe > 1) { + DRM_ERROR("Invalid crtc %u\n", pipe); return -EINVAL; } if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) { - if (crtc == 0) + if (pipe == 0) return RADEON_READ(R500_D1CRTC_FRAME_COUNT); else return RADEON_READ(R500_D2CRTC_FRAME_COUNT); } else { - if (crtc == 0) + if (pipe == 0) return RADEON_READ(RADEON_CRTC_CRNT_FRAME); else return RADEON_READ(RADEON_CRTC2_CRNT_FRAME); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index fd9da282b29c..5f687c95a1e1 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -598,14 +598,17 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file * Outdated mess for old drm with Xorg being in charge (void function now). */ /** - * radeon_driver_firstopen_kms - drm callback for last close + * radeon_driver_lastclose_kms - drm callback for last close * * @dev: drm dev pointer * - * Switch vga switcheroo state after last close (all asics). + * Switch vga_switcheroo state after last close (all asics). */ void radeon_driver_lastclose_kms(struct drm_device *dev) { + struct radeon_device *rdev = dev->dev_private; + + radeon_fbdev_restore_mode(rdev); vga_switcheroo_process_delayed_switch(); } @@ -844,89 +847,49 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, &drmcrtc->hwmode); } -#define KMS_INVALID_IOCTL(name) \ -static int name(struct drm_device *dev, void *data, struct drm_file \ - *file_priv) \ -{ \ - DRM_ERROR("invalid ioctl with kms %s\n", __func__); \ - return -EINVAL; \ -} - -/* - * All these ioctls are invalid in kms world. - */ -KMS_INVALID_IOCTL(radeon_cp_init_kms) -KMS_INVALID_IOCTL(radeon_cp_start_kms) -KMS_INVALID_IOCTL(radeon_cp_stop_kms) -KMS_INVALID_IOCTL(radeon_cp_reset_kms) -KMS_INVALID_IOCTL(radeon_cp_idle_kms) -KMS_INVALID_IOCTL(radeon_cp_resume_kms) -KMS_INVALID_IOCTL(radeon_engine_reset_kms) -KMS_INVALID_IOCTL(radeon_fullscreen_kms) -KMS_INVALID_IOCTL(radeon_cp_swap_kms) -KMS_INVALID_IOCTL(radeon_cp_clear_kms) -KMS_INVALID_IOCTL(radeon_cp_vertex_kms) -KMS_INVALID_IOCTL(radeon_cp_indices_kms) -KMS_INVALID_IOCTL(radeon_cp_texture_kms) -KMS_INVALID_IOCTL(radeon_cp_stipple_kms) -KMS_INVALID_IOCTL(radeon_cp_indirect_kms) -KMS_INVALID_IOCTL(radeon_cp_vertex2_kms) -KMS_INVALID_IOCTL(radeon_cp_cmdbuf_kms) -KMS_INVALID_IOCTL(radeon_cp_getparam_kms) -KMS_INVALID_IOCTL(radeon_cp_flip_kms) -KMS_INVALID_IOCTL(radeon_mem_alloc_kms) -KMS_INVALID_IOCTL(radeon_mem_free_kms) -KMS_INVALID_IOCTL(radeon_mem_init_heap_kms) -KMS_INVALID_IOCTL(radeon_irq_emit_kms) -KMS_INVALID_IOCTL(radeon_irq_wait_kms) -KMS_INVALID_IOCTL(radeon_cp_setparam_kms) -KMS_INVALID_IOCTL(radeon_surface_alloc_kms) -KMS_INVALID_IOCTL(radeon_surface_free_kms) - - const struct drm_ioctl_desc radeon_ioctls_kms[] = { - DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, radeon_cp_init_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(RADEON_CP_START, radeon_cp_start_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(RADEON_CP_STOP, radeon_cp_stop_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(RADEON_CP_RESET, radeon_cp_reset_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(RADEON_CP_IDLE, radeon_cp_idle_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_CP_RESUME, radeon_cp_resume_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_RESET, radeon_engine_reset_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_FULLSCREEN, radeon_fullscreen_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_SWAP, radeon_cp_swap_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_CLEAR, radeon_cp_clear_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_VERTEX, radeon_cp_vertex_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_INDICES, radeon_cp_indices_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_TEXTURE, radeon_cp_texture_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_STIPPLE, radeon_cp_stipple_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_INDIRECT, radeon_cp_indirect_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(RADEON_VERTEX2, radeon_cp_vertex2_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_CMDBUF, radeon_cp_cmdbuf_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_GETPARAM, radeon_cp_getparam_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_FLIP, radeon_cp_flip_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_ALLOC, radeon_mem_alloc_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_FREE, radeon_mem_free_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_INIT_HEAP, radeon_mem_init_heap_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(RADEON_IRQ_EMIT, radeon_irq_emit_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_IRQ_WAIT, radeon_irq_wait_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_SETPARAM, radeon_cp_setparam_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_SURF_ALLOC, radeon_surface_alloc_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_SURF_FREE, radeon_surface_free_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_START, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_STOP, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_RESET, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_IDLE, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CP_RESUME, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_RESET, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FULLSCREEN, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SWAP, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CLEAR, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_VERTEX, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INDICES, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_TEXTURE, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_STIPPLE, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INDIRECT, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_VERTEX2, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CMDBUF, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_GETPARAM, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FLIP, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_ALLOC, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FREE, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INIT_HEAP, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_IRQ_EMIT, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_IRQ_WAIT, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SETPARAM, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SURF_ALLOC, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SURF_FREE, drm_invalid_op, DRM_AUTH), /* KMS */ - DRM_IOCTL_DEF_DRV(RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_CS, radeon_cs_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_INFO, radeon_info_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_OP, radeon_gem_op_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_USERPTR, radeon_gem_userptr_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_CS, radeon_cs_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_INFO, radeon_info_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_OP, radeon_gem_op_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_USERPTR, radeon_gem_userptr_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), }; int radeon_max_kms_ioctl = ARRAY_SIZE(radeon_ioctls_kms); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 2317d04f8a09..830e171c3a9e 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -874,9 +874,8 @@ extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); extern void radeon_cursor_reset(struct drm_crtc *crtc); -extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, - unsigned int flags, - int *vpos, int *hpos, +extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, + unsigned int flags, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode); @@ -981,6 +980,7 @@ int radeon_fbdev_init(struct radeon_device *rdev); void radeon_fbdev_fini(struct radeon_device *rdev); void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state); bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj); +void radeon_fbdev_restore_mode(struct radeon_device *rdev); void radeon_fb_output_poll_changed(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 10f4c12e439e..bcdc508127f1 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -1326,14 +1326,6 @@ static int radeon_pm_init_old(struct radeon_device *rdev) INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler); if (rdev->pm.num_power_states > 1) { - /* where's the best place to put these? */ - ret = device_create_file(rdev->dev, &dev_attr_power_profile); - if (ret) - DRM_ERROR("failed to create device file for power profile\n"); - ret = device_create_file(rdev->dev, &dev_attr_power_method); - if (ret) - DRM_ERROR("failed to create device file for power method\n"); - if (radeon_debugfs_pm_init(rdev)) { DRM_ERROR("Failed to register debugfs file for PM!\n"); } @@ -1391,20 +1383,6 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev) goto dpm_failed; rdev->pm.dpm_enabled = true; - ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); - if (ret) - DRM_ERROR("failed to create device file for dpm state\n"); - ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); - if (ret) - DRM_ERROR("failed to create device file for dpm state\n"); - /* XXX: these are noops for dpm but are here for backwards compat */ - ret = device_create_file(rdev->dev, &dev_attr_power_profile); - if (ret) - DRM_ERROR("failed to create device file for power profile\n"); - ret = device_create_file(rdev->dev, &dev_attr_power_method); - if (ret) - DRM_ERROR("failed to create device file for power method\n"); - if (radeon_debugfs_pm_init(rdev)) { DRM_ERROR("Failed to register debugfs file for dpm!\n"); } @@ -1545,9 +1523,44 @@ int radeon_pm_late_init(struct radeon_device *rdev) int ret = 0; if (rdev->pm.pm_method == PM_METHOD_DPM) { - mutex_lock(&rdev->pm.mutex); - ret = radeon_dpm_late_enable(rdev); - mutex_unlock(&rdev->pm.mutex); + if (rdev->pm.dpm_enabled) { + ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); + if (ret) + DRM_ERROR("failed to create device file for dpm state\n"); + ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); + if (ret) + DRM_ERROR("failed to create device file for dpm state\n"); + /* XXX: these are noops for dpm but are here for backwards compat */ + ret = device_create_file(rdev->dev, &dev_attr_power_profile); + if (ret) + DRM_ERROR("failed to create device file for power profile\n"); + ret = device_create_file(rdev->dev, &dev_attr_power_method); + if (ret) + DRM_ERROR("failed to create device file for power method\n"); + + mutex_lock(&rdev->pm.mutex); + ret = radeon_dpm_late_enable(rdev); + mutex_unlock(&rdev->pm.mutex); + if (ret) { + rdev->pm.dpm_enabled = false; + DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); + } else { + /* set the dpm state for PX since there won't be + * a modeset to call this. + */ + radeon_pm_compute_clocks(rdev); + } + } + } else { + if (rdev->pm.num_power_states > 1) { + /* where's the best place to put these? */ + ret = device_create_file(rdev->dev, &dev_attr_power_profile); + if (ret) + DRM_ERROR("failed to create device file for power profile\n"); + ret = device_create_file(rdev->dev, &dev_attr_power_method); + if (ret) + DRM_ERROR("failed to create device file for power method\n"); + } } return ret; } diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 06ac59fe332a..e34307459e50 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -144,7 +144,7 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->available_caching = TTM_PL_MASK_CACHING; man->default_caching = TTM_PL_FLAG_CACHED; man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | TTM_MEMTYPE_FLAG_CMA; -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (rdev->flags & RADEON_IS_AGP) { if (!rdev->ddev->agp) { DRM_ERROR("AGP is not enabled for memory type %u\n", @@ -461,7 +461,7 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_ /* system memory */ return 0; case TTM_PL_TT: -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (rdev->flags & RADEON_IS_AGP) { /* RADEON_IS_AGP is set only if AGP is active */ mem->bus.offset = mem->start << PAGE_SHIFT; @@ -680,7 +680,7 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev, struct radeon_ttm_tt *gtt; rdev = radeon_get_rdev(bdev); -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (rdev->flags & RADEON_IS_AGP) { return ttm_agp_tt_create(bdev, rdev->ddev->agp->bridge, size, page_flags, dummy_read_page); @@ -736,7 +736,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) } rdev = radeon_get_rdev(ttm->bdev); -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (rdev->flags & RADEON_IS_AGP) { return ttm_agp_tt_populate(ttm); } @@ -787,7 +787,7 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm) return; rdev = radeon_get_rdev(ttm->bdev); -#if __OS_HAS_AGP +#if IS_ENABLED(CONFIG_AGP) if (rdev->flags & RADEON_IS_AGP) { ttm_agp_tt_unpopulate(ttm); return; diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index e9115d3f67b0..e72bf46042e0 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -2928,6 +2928,7 @@ static struct si_dpm_quirk si_dpm_quirk_list[] = { { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 }, { PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 }, { PCI_VENDOR_ID_ATI, 0x6811, 0x1762, 0x2015, 0, 120000 }, + { PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 }, { 0, 0, 0, 0 }, }; diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 11485a4a16ae..d4e0a39568f6 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -1,6 +1,6 @@ config DRM_RCAR_DU tristate "DRM Support for R-Car Display Unit" - depends on DRM && ARM && HAVE_DMA_ATTRS + depends on DRM && ARM && HAVE_DMA_ATTRS && OF depends on ARCH_SHMOBILE || COMPILE_TEST select DRM_KMS_HELPER select DRM_KMS_CMA_HELPER diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 780ca11512ba..40422f6b645e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -84,16 +84,17 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = { .num_lvds = 2, }; +/* M2-W (r8a7791) and M2-N (r8a7793) are identical */ static const struct rcar_du_device_info rcar_du_r8a7791_info = { .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_EXT_CTRL_REGS, .num_crtcs = 2, .routes = { - /* R8A7791 has one RGB output, one LVDS output and one + /* R8A779[13] has one RGB output, one LVDS output and one * (currently unsupported) TCON output. */ [RCAR_DU_OUTPUT_DPAD0] = { - .possible_crtcs = BIT(1), + .possible_crtcs = BIT(1) | BIT(0), .encoder_type = DRM_MODE_ENCODER_NONE, .port = 0, }, @@ -106,19 +107,34 @@ static const struct rcar_du_device_info rcar_du_r8a7791_info = { .num_lvds = 1, }; -static const struct platform_device_id rcar_du_id_table[] = { - { "rcar-du-r8a7779", (kernel_ulong_t)&rcar_du_r8a7779_info }, - { "rcar-du-r8a7790", (kernel_ulong_t)&rcar_du_r8a7790_info }, - { "rcar-du-r8a7791", (kernel_ulong_t)&rcar_du_r8a7791_info }, - { } +static const struct rcar_du_device_info rcar_du_r8a7794_info = { + .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK + | RCAR_DU_FEATURE_EXT_CTRL_REGS, + .num_crtcs = 2, + .routes = { + /* R8A7794 has two RGB outputs and one (currently unsupported) + * TCON output. + */ + [RCAR_DU_OUTPUT_DPAD0] = { + .possible_crtcs = BIT(0), + .encoder_type = DRM_MODE_ENCODER_NONE, + .port = 0, + }, + [RCAR_DU_OUTPUT_DPAD1] = { + .possible_crtcs = BIT(1), + .encoder_type = DRM_MODE_ENCODER_NONE, + .port = 1, + }, + }, + .num_lvds = 0, }; -MODULE_DEVICE_TABLE(platform, rcar_du_id_table); - static const struct of_device_id rcar_du_of_table[] = { { .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info }, { .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info }, { .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info }, + { .compatible = "renesas,du-r8a7793", .data = &rcar_du_r8a7791_info }, + { .compatible = "renesas,du-r8a7794", .data = &rcar_du_r8a7794_info }, { } }; @@ -167,8 +183,7 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags) init_waitqueue_head(&rcdu->commit.wait); rcdu->dev = &pdev->dev; - rcdu->info = np ? of_match_device(rcar_du_of_table, rcdu->dev)->data - : (void *)platform_get_device_id(pdev)->driver_data; + rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data; rcdu->ddev = dev; dev->dev_private = rcdu; @@ -221,20 +236,20 @@ static void rcar_du_lastclose(struct drm_device *dev) drm_fbdev_cma_restore_mode(rcdu->fbdev); } -static int rcar_du_enable_vblank(struct drm_device *dev, int crtc) +static int rcar_du_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct rcar_du_device *rcdu = dev->dev_private; - rcar_du_crtc_enable_vblank(&rcdu->crtcs[crtc], true); + rcar_du_crtc_enable_vblank(&rcdu->crtcs[pipe], true); return 0; } -static void rcar_du_disable_vblank(struct drm_device *dev, int crtc) +static void rcar_du_disable_vblank(struct drm_device *dev, unsigned int pipe) { struct rcar_du_device *rcdu = dev->dev_private; - rcar_du_crtc_enable_vblank(&rcdu->crtcs[crtc], false); + rcar_du_crtc_enable_vblank(&rcdu->crtcs[pipe], false); } static const struct file_operations rcar_du_fops = { @@ -259,7 +274,7 @@ static struct drm_driver rcar_du_driver = { .preclose = rcar_du_preclose, .lastclose = rcar_du_lastclose, .set_busid = drm_platform_set_busid, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = rcar_du_enable_vblank, .disable_vblank = rcar_du_disable_vblank, .gem_free_object = drm_gem_cma_free_object, @@ -340,7 +355,6 @@ static struct platform_driver rcar_du_platform_driver = { .pm = &rcar_du_pm_ops, .of_match_table = rcar_du_of_table, }, - .id_table = rcar_du_id_table, }; module_platform_driver(rcar_du_platform_driver); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index 7fd39a7d91c8..8e2ffe025153 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c @@ -49,9 +49,10 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp) u32 defr8 = DEFR8_CODE | DEFR8_DEFE8; /* The DEFR8 register for the first group also controls RGB output - * routing to DPAD0 + * routing to DPAD0 for DU instances that support it. */ - if (rgrp->index == 0) + if (rgrp->dev->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs > 1 && + rgrp->index == 0) defr8 |= DEFR8_DRGBS_DU(rgrp->dev->dpad0_source); rcar_du_group_write(rgrp, DEFR8, defr8); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index c66986414bb4..ffa583712cd9 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -273,29 +273,6 @@ static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs = { .atomic_update = rcar_du_plane_atomic_update, }; -static void rcar_du_plane_reset(struct drm_plane *plane) -{ - struct rcar_du_plane_state *state; - - if (plane->state && plane->state->fb) - drm_framebuffer_unreference(plane->state->fb); - - kfree(plane->state); - plane->state = NULL; - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) - return; - - state->hwindex = -1; - state->alpha = 255; - state->colorkey = RCAR_DU_COLORKEY_NONE; - state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1; - - plane->state = &state->state; - plane->state->plane = plane; -} - static struct drm_plane_state * rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane) { @@ -322,6 +299,28 @@ static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane, kfree(to_rcar_plane_state(state)); } +static void rcar_du_plane_reset(struct drm_plane *plane) +{ + struct rcar_du_plane_state *state; + + if (plane->state) { + rcar_du_plane_atomic_destroy_state(plane, plane->state); + plane->state = NULL; + } + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) + return; + + state->hwindex = -1; + state->alpha = 255; + state->colorkey = RCAR_DU_COLORKEY_NONE; + state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1; + + plane->state = &state->state; + plane->state->plane = plane; +} + static int rcar_du_plane_atomic_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 9a0c2911272a..f22e1e1ee64a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -103,7 +103,8 @@ static struct drm_crtc *rockchip_crtc_from_pipe(struct drm_device *drm, return NULL; } -static int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) +static int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, + unsigned int pipe) { struct rockchip_drm_private *priv = dev->dev_private; struct drm_crtc *crtc = rockchip_crtc_from_pipe(dev, pipe); @@ -115,7 +116,8 @@ static int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) return 0; } -static void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) +static void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, + unsigned int pipe) { struct rockchip_drm_private *priv = dev->dev_private; struct drm_crtc *crtc = rockchip_crtc_from_pipe(dev, pipe); @@ -277,7 +279,7 @@ static struct drm_driver rockchip_drm_driver = { .load = rockchip_drm_load, .unload = rockchip_drm_unload, .lastclose = rockchip_drm_lastclose, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = rockchip_drm_crtc_enable_vblank, .disable_vblank = rockchip_drm_crtc_disable_vblank, .gem_vm_ops = &rockchip_drm_vm_ops, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index a6d9104f7f15..8caea0a33dd8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -79,12 +79,9 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj, int rockchip_gem_mmap_buf(struct drm_gem_object *obj, struct vm_area_struct *vma) { - struct drm_device *drm = obj->dev; int ret; - mutex_lock(&drm->struct_mutex); ret = drm_gem_mmap_obj(obj, obj->size, vma); - mutex_unlock(&drm->struct_mutex); if (ret) return ret; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index 666321de7b99..04e66e3751b4 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -231,7 +231,7 @@ static irqreturn_t shmob_drm_irq(int irq, void *arg) return IRQ_HANDLED; } -static int shmob_drm_enable_vblank(struct drm_device *dev, int crtc) +static int shmob_drm_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct shmob_drm_device *sdev = dev->dev_private; @@ -240,7 +240,7 @@ static int shmob_drm_enable_vblank(struct drm_device *dev, int crtc) return 0; } -static void shmob_drm_disable_vblank(struct drm_device *dev, int crtc) +static void shmob_drm_disable_vblank(struct drm_device *dev, unsigned int pipe) { struct shmob_drm_device *sdev = dev->dev_private; @@ -269,7 +269,7 @@ static struct drm_driver shmob_drm_driver = { .preclose = shmob_drm_preclose, .set_busid = drm_platform_set_busid, .irq_handler = shmob_drm_irq, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = shmob_drm_enable_vblank, .disable_vblank = shmob_drm_disable_vblank, .gem_free_object = drm_gem_cma_free_object, diff --git a/drivers/gpu/drm/sis/sis_drv.h b/drivers/gpu/drm/sis/sis_drv.h index 16f972b2a76a..328f8a750976 100644 --- a/drivers/gpu/drm/sis/sis_drv.h +++ b/drivers/gpu/drm/sis/sis_drv.h @@ -67,6 +67,10 @@ typedef struct drm_sis_private { struct idr object_idr; } drm_sis_private_t; +struct sis_file_private { + struct list_head obj_list; +}; + extern int sis_idle(struct drm_device *dev); extern void sis_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv); diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index 018ffc970e96..493c4a3006ad 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c @@ -299,7 +299,7 @@ int sti_crtc_vblank_cb(struct notifier_block *nb, return 0; } -int sti_crtc_enable_vblank(struct drm_device *dev, int crtc) +int sti_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe) { struct sti_private *dev_priv = dev->dev_private; struct sti_compositor *compo = dev_priv->compo; @@ -307,9 +307,9 @@ int sti_crtc_enable_vblank(struct drm_device *dev, int crtc) DRM_DEBUG_DRIVER("\n"); - if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ? + if (sti_vtg_register_client(pipe == STI_MIXER_MAIN ? compo->vtg_main : compo->vtg_aux, - vtg_vblank_nb, crtc)) { + vtg_vblank_nb, pipe)) { DRM_ERROR("Cannot register VTG notifier\n"); return -EINVAL; } @@ -318,7 +318,7 @@ int sti_crtc_enable_vblank(struct drm_device *dev, int crtc) } EXPORT_SYMBOL(sti_crtc_enable_vblank); -void sti_crtc_disable_vblank(struct drm_device *drm_dev, int crtc) +void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe) { struct sti_private *priv = drm_dev->dev_private; struct sti_compositor *compo = priv->compo; @@ -326,14 +326,14 @@ void sti_crtc_disable_vblank(struct drm_device *drm_dev, int crtc) DRM_DEBUG_DRIVER("\n"); - if (sti_vtg_unregister_client(crtc == STI_MIXER_MAIN ? + if (sti_vtg_unregister_client(pipe == STI_MIXER_MAIN ? compo->vtg_main : compo->vtg_aux, vtg_vblank_nb)) DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); /* free the resources of the pending requests */ - if (compo->mixer[crtc]->pending_event) { - drm_vblank_put(drm_dev, crtc); - compo->mixer[crtc]->pending_event = NULL; + if (compo->mixer[pipe]->pending_event) { + drm_vblank_put(drm_dev, pipe); + compo->mixer[pipe]->pending_event = NULL; } } EXPORT_SYMBOL(sti_crtc_disable_vblank); diff --git a/drivers/gpu/drm/sti/sti_crtc.h b/drivers/gpu/drm/sti/sti_crtc.h index 51963e6ddbe7..3f2d89a3634d 100644 --- a/drivers/gpu/drm/sti/sti_crtc.h +++ b/drivers/gpu/drm/sti/sti_crtc.h @@ -13,8 +13,8 @@ struct sti_mixer; int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, struct drm_plane *primary, struct drm_plane *cursor); -int sti_crtc_enable_vblank(struct drm_device *dev, int crtc); -void sti_crtc_disable_vblank(struct drm_device *dev, int crtc); +int sti_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe); +void sti_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe); int sti_crtc_vblank_cb(struct notifier_block *nb, unsigned long event, void *data); bool sti_crtc_is_main(struct drm_crtc *drm_crtc); diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 9f85988a43ce..f8469967a0bf 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -201,7 +201,7 @@ static struct drm_driver sti_driver = { .dumb_destroy = drm_gem_dumb_destroy, .fops = &sti_driver_fops, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = sti_crtc_enable_vblank, .disable_vblank = sti_crtc_disable_vblank, diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 2486bc24bff6..159ef515cab1 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -778,20 +778,20 @@ static int tegra_gem_get_flags(struct drm_device *drm, void *data, static const struct drm_ioctl_desc tegra_drm_ioctls[] = { #ifdef CONFIG_DRM_TEGRA_STAGING - DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_TILING, tegra_gem_set_tiling, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_TILING, tegra_gem_get_tiling, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_FLAGS, tegra_gem_set_flags, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_FLAGS, tegra_gem_get_flags, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, 0), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, 0), + DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, 0), + DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, 0), + DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, 0), + DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, 0), + DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, 0), + DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, 0), + DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, 0), + DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base, 0), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_TILING, tegra_gem_set_tiling, 0), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_TILING, tegra_gem_get_tiling, 0), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_FLAGS, tegra_gem_set_flags, 0), + DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_FLAGS, tegra_gem_get_flags, 0), #endif }; @@ -822,7 +822,8 @@ static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, return NULL; } -static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe) +static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, + unsigned int pipe) { struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); struct tegra_dc *dc = to_tegra_dc(crtc); @@ -833,7 +834,7 @@ static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe) return tegra_dc_get_vblank_counter(dc); } -static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe) +static int tegra_drm_enable_vblank(struct drm_device *drm, unsigned int pipe) { struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); struct tegra_dc *dc = to_tegra_dc(crtc); @@ -846,7 +847,7 @@ static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe) return 0; } -static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe) +static void tegra_drm_disable_vblank(struct drm_device *drm, unsigned int pipe) { struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); struct tegra_dc *dc = to_tegra_dc(crtc); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 0f283a3b932c..876cad58b1f9 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -425,13 +425,13 @@ static void enable_vblank(struct drm_device *dev, bool enable) tilcdc_clear(dev, reg, mask); } -static int tilcdc_enable_vblank(struct drm_device *dev, int crtc) +static int tilcdc_enable_vblank(struct drm_device *dev, unsigned int pipe) { enable_vblank(dev, true); return 0; } -static void tilcdc_disable_vblank(struct drm_device *dev, int crtc) +static void tilcdc_disable_vblank(struct drm_device *dev, unsigned int pipe) { enable_vblank(dev, false); } @@ -563,7 +563,7 @@ static struct drm_driver tilcdc_driver = { .irq_preinstall = tilcdc_irq_preinstall, .irq_postinstall = tilcdc_irq_postinstall, .irq_uninstall = tilcdc_irq_uninstall, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = tilcdc_enable_vblank, .disable_vblank = tilcdc_disable_vblank, .gem_free_object = drm_gem_cma_free_object, diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig new file mode 100644 index 000000000000..e502802d74b6 --- /dev/null +++ b/drivers/gpu/drm/vc4/Kconfig @@ -0,0 +1,13 @@ +config DRM_VC4 + tristate "Broadcom VC4 Graphics" + depends on ARCH_BCM2835 || COMPILE_TEST + depends on DRM + select DRM_KMS_HELPER + select DRM_KMS_CMA_HELPER + help + Choose this option if you have a system that has a Broadcom + VC4 GPU, such as the Raspberry Pi or other BCM2708/BCM2835. + + This driver requires that "avoid_warnings=2" be present in + the config.txt for the firmware, to keep it from smashing + our display setup. diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile new file mode 100644 index 000000000000..32b4f9cd8f52 --- /dev/null +++ b/drivers/gpu/drm/vc4/Makefile @@ -0,0 +1,17 @@ +ccflags-y := -Iinclude/drm + +# Please keep these build lists sorted! + +# core driver code +vc4-y := \ + vc4_bo.o \ + vc4_crtc.o \ + vc4_drv.o \ + vc4_kms.o \ + vc4_hdmi.o \ + vc4_hvs.o \ + vc4_plane.o + +vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o + +obj-$(CONFIG_DRM_VC4) += vc4.o diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c new file mode 100644 index 000000000000..ab9f5108ae1a --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -0,0 +1,52 @@ +/* + * Copyright © 2015 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* DOC: VC4 GEM BO management support. + * + * The VC4 GPU architecture (both scanout and rendering) has direct + * access to system memory with no MMU in between. To support it, we + * use the GEM CMA helper functions to allocate contiguous ranges of + * physical memory for our BOs. + */ + +#include "vc4_drv.h" + +struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size) +{ + struct drm_gem_cma_object *cma_obj; + + cma_obj = drm_gem_cma_create(dev, size); + if (IS_ERR(cma_obj)) + return NULL; + else + return to_vc4_bo(&cma_obj->base); +} + +int vc4_dumb_create(struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + struct vc4_bo *bo = NULL; + int ret; + + if (args->pitch < min_pitch) + args->pitch = min_pitch; + + if (args->size < args->pitch * args->height) + args->size = args->pitch * args->height; + + bo = vc4_bo_create(dev, roundup(args->size, PAGE_SIZE)); + if (!bo) + return -ENOMEM; + + ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); + drm_gem_object_unreference_unlocked(&bo->base.base); + + return ret; +} diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c new file mode 100644 index 000000000000..7a9f4768591e --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -0,0 +1,672 @@ +/* + * Copyright (C) 2015 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/** + * DOC: VC4 CRTC module + * + * In VC4, the Pixel Valve is what most closely corresponds to the + * DRM's concept of a CRTC. The PV generates video timings from the + * output's clock plus its configuration. It pulls scaled pixels from + * the HVS at that timing, and feeds it to the encoder. + * + * However, the DRM CRTC also collects the configuration of all the + * DRM planes attached to it. As a result, this file also manages + * setup of the VC4 HVS's display elements on the CRTC. + * + * The 2835 has 3 different pixel valves. pv0 in the audio power + * domain feeds DSI0 or DPI, while pv1 feeds DS1 or SMI. pv2 in the + * image domain can feed either HDMI or the SDTV controller. The + * pixel valve chooses from the CPRMAN clocks (HSM for HDMI, VEC for + * SDTV, etc.) according to which output type is chosen in the mux. + * + * For power management, the pixel valve's registers are all clocked + * by the AXI clock, while the timings and FIFOs make use of the + * output-specific clock. Since the encoders also directly consume + * the CPRMAN clocks, and know what timings they need, they are the + * ones that set the clock. + */ + +#include "drm_atomic.h" +#include "drm_atomic_helper.h" +#include "drm_crtc_helper.h" +#include "linux/clk.h" +#include "linux/component.h" +#include "linux/of_device.h" +#include "vc4_drv.h" +#include "vc4_regs.h" + +struct vc4_crtc { + struct drm_crtc base; + const struct vc4_crtc_data *data; + void __iomem *regs; + + /* Which HVS channel we're using for our CRTC. */ + int channel; + + /* Pointer to the actual hardware display list memory for the + * crtc. + */ + u32 __iomem *dlist; + + u32 dlist_size; /* in dwords */ + + struct drm_pending_vblank_event *event; +}; + +static inline struct vc4_crtc * +to_vc4_crtc(struct drm_crtc *crtc) +{ + return (struct vc4_crtc *)crtc; +} + +struct vc4_crtc_data { + /* Which channel of the HVS this pixelvalve sources from. */ + int hvs_channel; + + enum vc4_encoder_type encoder0_type; + enum vc4_encoder_type encoder1_type; +}; + +#define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset)) +#define CRTC_READ(offset) readl(vc4_crtc->regs + (offset)) + +#define CRTC_REG(reg) { reg, #reg } +static const struct { + u32 reg; + const char *name; +} crtc_regs[] = { + CRTC_REG(PV_CONTROL), + CRTC_REG(PV_V_CONTROL), + CRTC_REG(PV_VSYNCD), + CRTC_REG(PV_HORZA), + CRTC_REG(PV_HORZB), + CRTC_REG(PV_VERTA), + CRTC_REG(PV_VERTB), + CRTC_REG(PV_VERTA_EVEN), + CRTC_REG(PV_VERTB_EVEN), + CRTC_REG(PV_INTEN), + CRTC_REG(PV_INTSTAT), + CRTC_REG(PV_STAT), + CRTC_REG(PV_HACT_ACT), +}; + +static void vc4_crtc_dump_regs(struct vc4_crtc *vc4_crtc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(crtc_regs); i++) { + DRM_INFO("0x%04x (%s): 0x%08x\n", + crtc_regs[i].reg, crtc_regs[i].name, + CRTC_READ(crtc_regs[i].reg)); + } +} + +#ifdef CONFIG_DEBUG_FS +int vc4_crtc_debugfs_regs(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *)m->private; + struct drm_device *dev = node->minor->dev; + int crtc_index = (uintptr_t)node->info_ent->data; + struct drm_crtc *crtc; + struct vc4_crtc *vc4_crtc; + int i; + + i = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (i == crtc_index) + break; + i++; + } + if (!crtc) + return 0; + vc4_crtc = to_vc4_crtc(crtc); + + for (i = 0; i < ARRAY_SIZE(crtc_regs); i++) { + seq_printf(m, "%s (0x%04x): 0x%08x\n", + crtc_regs[i].name, crtc_regs[i].reg, + CRTC_READ(crtc_regs[i].reg)); + } + + return 0; +} +#endif + +static void vc4_crtc_destroy(struct drm_crtc *crtc) +{ + drm_crtc_cleanup(crtc); +} + +static u32 vc4_get_fifo_full_level(u32 format) +{ + static const u32 fifo_len_bytes = 64; + static const u32 hvs_latency_pix = 6; + + switch (format) { + case PV_CONTROL_FORMAT_DSIV_16: + case PV_CONTROL_FORMAT_DSIC_16: + return fifo_len_bytes - 2 * hvs_latency_pix; + case PV_CONTROL_FORMAT_DSIV_18: + return fifo_len_bytes - 14; + case PV_CONTROL_FORMAT_24: + case PV_CONTROL_FORMAT_DSIV_24: + default: + return fifo_len_bytes - 3 * hvs_latency_pix; + } +} + +/* + * Returns the clock select bit for the connector attached to the + * CRTC. + */ +static int vc4_get_clock_select(struct drm_crtc *crtc) +{ + struct drm_connector *connector; + + drm_for_each_connector(connector, crtc->dev) { + if (connector && connector->state->crtc == crtc) { + struct drm_encoder *encoder = connector->encoder; + struct vc4_encoder *vc4_encoder = + to_vc4_encoder(encoder); + + return vc4_encoder->clock_select; + } + } + + return -1; +} + +static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) +{ + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct drm_crtc_state *state = crtc->state; + struct drm_display_mode *mode = &state->adjusted_mode; + bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; + u32 vactive = (mode->vdisplay >> (interlace ? 1 : 0)); + u32 format = PV_CONTROL_FORMAT_24; + bool debug_dump_regs = false; + int clock_select = vc4_get_clock_select(crtc); + + if (debug_dump_regs) { + DRM_INFO("CRTC %d regs before:\n", drm_crtc_index(crtc)); + vc4_crtc_dump_regs(vc4_crtc); + } + + /* Reset the PV fifo. */ + CRTC_WRITE(PV_CONTROL, 0); + CRTC_WRITE(PV_CONTROL, PV_CONTROL_FIFO_CLR | PV_CONTROL_EN); + CRTC_WRITE(PV_CONTROL, 0); + + CRTC_WRITE(PV_HORZA, + VC4_SET_FIELD(mode->htotal - mode->hsync_end, + PV_HORZA_HBP) | + VC4_SET_FIELD(mode->hsync_end - mode->hsync_start, + PV_HORZA_HSYNC)); + CRTC_WRITE(PV_HORZB, + VC4_SET_FIELD(mode->hsync_start - mode->hdisplay, + PV_HORZB_HFP) | + VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE)); + + if (interlace) { + CRTC_WRITE(PV_VERTA_EVEN, + VC4_SET_FIELD(mode->vtotal - mode->vsync_end - 1, + PV_VERTA_VBP) | + VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, + PV_VERTA_VSYNC)); + CRTC_WRITE(PV_VERTB_EVEN, + VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, + PV_VERTB_VFP) | + VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE)); + } + + CRTC_WRITE(PV_HACT_ACT, mode->hdisplay); + + CRTC_WRITE(PV_V_CONTROL, + PV_VCONTROL_CONTINUOUS | + (interlace ? PV_VCONTROL_INTERLACE : 0)); + + CRTC_WRITE(PV_CONTROL, + VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | + VC4_SET_FIELD(vc4_get_fifo_full_level(format), + PV_CONTROL_FIFO_LEVEL) | + PV_CONTROL_CLR_AT_START | + PV_CONTROL_TRIGGER_UNDERFLOW | + PV_CONTROL_WAIT_HSTART | + VC4_SET_FIELD(clock_select, PV_CONTROL_CLK_SELECT) | + PV_CONTROL_FIFO_CLR | + PV_CONTROL_EN); + + if (debug_dump_regs) { + DRM_INFO("CRTC %d regs after:\n", drm_crtc_index(crtc)); + vc4_crtc_dump_regs(vc4_crtc); + } +} + +static void require_hvs_enabled(struct drm_device *dev) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + + WARN_ON_ONCE((HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE) != + SCALER_DISPCTRL_ENABLE); +} + +static void vc4_crtc_disable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + u32 chan = vc4_crtc->channel; + int ret; + require_hvs_enabled(dev); + + CRTC_WRITE(PV_V_CONTROL, + CRTC_READ(PV_V_CONTROL) & ~PV_VCONTROL_VIDEN); + ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1); + WARN_ONCE(ret, "Timeout waiting for !PV_VCONTROL_VIDEN\n"); + + if (HVS_READ(SCALER_DISPCTRLX(chan)) & + SCALER_DISPCTRLX_ENABLE) { + HVS_WRITE(SCALER_DISPCTRLX(chan), + SCALER_DISPCTRLX_RESET); + + /* While the docs say that reset is self-clearing, it + * seems it doesn't actually. + */ + HVS_WRITE(SCALER_DISPCTRLX(chan), 0); + } + + /* Once we leave, the scaler should be disabled and its fifo empty. */ + + WARN_ON_ONCE(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_RESET); + + WARN_ON_ONCE(VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)), + SCALER_DISPSTATX_MODE) != + SCALER_DISPSTATX_MODE_DISABLED); + + WARN_ON_ONCE((HVS_READ(SCALER_DISPSTATX(chan)) & + (SCALER_DISPSTATX_FULL | SCALER_DISPSTATX_EMPTY)) != + SCALER_DISPSTATX_EMPTY); +} + +static void vc4_crtc_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct drm_crtc_state *state = crtc->state; + struct drm_display_mode *mode = &state->adjusted_mode; + + require_hvs_enabled(dev); + + /* Turn on the scaler, which will wait for vstart to start + * compositing. + */ + HVS_WRITE(SCALER_DISPCTRLX(vc4_crtc->channel), + VC4_SET_FIELD(mode->hdisplay, SCALER_DISPCTRLX_WIDTH) | + VC4_SET_FIELD(mode->vdisplay, SCALER_DISPCTRLX_HEIGHT) | + SCALER_DISPCTRLX_ENABLE); + + /* Turn on the pixel valve, which will emit the vstart signal. */ + CRTC_WRITE(PV_V_CONTROL, + CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); +} + +static int vc4_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_plane *plane; + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + u32 dlist_count = 0; + + /* The pixelvalve can only feed one encoder (and encoders are + * 1:1 with connectors.) + */ + if (drm_atomic_connectors_for_crtc(state->state, crtc) > 1) + return -EINVAL; + + drm_atomic_crtc_state_for_each_plane(plane, state) { + struct drm_plane_state *plane_state = + state->state->plane_states[drm_plane_index(plane)]; + + /* plane might not have changed, in which case take + * current state: + */ + if (!plane_state) + plane_state = plane->state; + + dlist_count += vc4_plane_dlist_size(plane_state); + } + + dlist_count++; /* Account for SCALER_CTL0_END. */ + + if (!vc4_crtc->dlist || dlist_count > vc4_crtc->dlist_size) { + vc4_crtc->dlist = ((u32 __iomem *)vc4->hvs->dlist + + HVS_BOOTLOADER_DLIST_END); + vc4_crtc->dlist_size = ((SCALER_DLIST_SIZE >> 2) - + HVS_BOOTLOADER_DLIST_END); + + if (dlist_count > vc4_crtc->dlist_size) { + DRM_DEBUG_KMS("dlist too large for CRTC (%d > %d).\n", + dlist_count, vc4_crtc->dlist_size); + return -EINVAL; + } + } + + return 0; +} + +static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct drm_plane *plane; + bool debug_dump_regs = false; + u32 __iomem *dlist_next = vc4_crtc->dlist; + + if (debug_dump_regs) { + DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc)); + vc4_hvs_dump_state(dev); + } + + /* Copy all the active planes' dlist contents to the hardware dlist. + * + * XXX: If the new display list was large enough that it + * overlapped a currently-read display list, we need to do + * something like disable scanout before putting in the new + * list. For now, we're safe because we only have the two + * planes. + */ + drm_atomic_crtc_for_each_plane(plane, crtc) { + dlist_next += vc4_plane_write_dlist(plane, dlist_next); + } + + if (dlist_next == vc4_crtc->dlist) { + /* If no planes were enabled, use the SCALER_CTL0_END + * at the start of the display list memory (in the + * bootloader section). We'll rewrite that + * SCALER_CTL0_END, just in case, though. + */ + writel(SCALER_CTL0_END, vc4->hvs->dlist); + HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), 0); + } else { + writel(SCALER_CTL0_END, dlist_next); + dlist_next++; + + HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), + (u32 *)vc4_crtc->dlist - (u32 *)vc4->hvs->dlist); + + /* Make the next display list start after ours. */ + vc4_crtc->dlist_size -= (dlist_next - vc4_crtc->dlist); + vc4_crtc->dlist = dlist_next; + } + + if (debug_dump_regs) { + DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc)); + vc4_hvs_dump_state(dev); + } + + if (crtc->state->event) { + unsigned long flags; + + crtc->state->event->pipe = drm_crtc_index(crtc); + + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + spin_lock_irqsave(&dev->event_lock, flags); + vc4_crtc->event = crtc->state->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + crtc->state->event = NULL; + } +} + +int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id]; + + CRTC_WRITE(PV_INTEN, PV_INT_VFP_START); + + return 0; +} + +void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id]; + + CRTC_WRITE(PV_INTEN, 0); +} + +static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) +{ + struct drm_crtc *crtc = &vc4_crtc->base; + struct drm_device *dev = crtc->dev; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + if (vc4_crtc->event) { + drm_crtc_send_vblank_event(crtc, vc4_crtc->event); + vc4_crtc->event = NULL; + } + spin_unlock_irqrestore(&dev->event_lock, flags); +} + +static irqreturn_t vc4_crtc_irq_handler(int irq, void *data) +{ + struct vc4_crtc *vc4_crtc = data; + u32 stat = CRTC_READ(PV_INTSTAT); + irqreturn_t ret = IRQ_NONE; + + if (stat & PV_INT_VFP_START) { + CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START); + drm_crtc_handle_vblank(&vc4_crtc->base); + vc4_crtc_handle_page_flip(vc4_crtc); + ret = IRQ_HANDLED; + } + + return ret; +} + +static const struct drm_crtc_funcs vc4_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .destroy = vc4_crtc_destroy, + .page_flip = drm_atomic_helper_page_flip, + .set_property = NULL, + .cursor_set = NULL, /* handled by drm_mode_cursor_universal */ + .cursor_move = NULL, /* handled by drm_mode_cursor_universal */ + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { + .mode_set_nofb = vc4_crtc_mode_set_nofb, + .disable = vc4_crtc_disable, + .enable = vc4_crtc_enable, + .atomic_check = vc4_crtc_atomic_check, + .atomic_flush = vc4_crtc_atomic_flush, +}; + +/* Frees the page flip event when the DRM device is closed with the + * event still outstanding. + */ +void vc4_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) +{ + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct drm_device *dev = crtc->dev; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + + if (vc4_crtc->event && vc4_crtc->event->base.file_priv == file) { + vc4_crtc->event->base.destroy(&vc4_crtc->event->base); + drm_crtc_vblank_put(crtc); + vc4_crtc->event = NULL; + } + + spin_unlock_irqrestore(&dev->event_lock, flags); +} + +static const struct vc4_crtc_data pv0_data = { + .hvs_channel = 0, + .encoder0_type = VC4_ENCODER_TYPE_DSI0, + .encoder1_type = VC4_ENCODER_TYPE_DPI, +}; + +static const struct vc4_crtc_data pv1_data = { + .hvs_channel = 2, + .encoder0_type = VC4_ENCODER_TYPE_DSI1, + .encoder1_type = VC4_ENCODER_TYPE_SMI, +}; + +static const struct vc4_crtc_data pv2_data = { + .hvs_channel = 1, + .encoder0_type = VC4_ENCODER_TYPE_VEC, + .encoder1_type = VC4_ENCODER_TYPE_HDMI, +}; + +static const struct of_device_id vc4_crtc_dt_match[] = { + { .compatible = "brcm,bcm2835-pixelvalve0", .data = &pv0_data }, + { .compatible = "brcm,bcm2835-pixelvalve1", .data = &pv1_data }, + { .compatible = "brcm,bcm2835-pixelvalve2", .data = &pv2_data }, + {} +}; + +static void vc4_set_crtc_possible_masks(struct drm_device *drm, + struct drm_crtc *crtc) +{ + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct drm_encoder *encoder; + + drm_for_each_encoder(encoder, drm) { + struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); + + if (vc4_encoder->type == vc4_crtc->data->encoder0_type) { + vc4_encoder->clock_select = 0; + encoder->possible_crtcs |= drm_crtc_mask(crtc); + } else if (vc4_encoder->type == vc4_crtc->data->encoder1_type) { + vc4_encoder->clock_select = 1; + encoder->possible_crtcs |= drm_crtc_mask(crtc); + } + } +} + +static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_crtc *vc4_crtc; + struct drm_crtc *crtc; + struct drm_plane *primary_plane, *cursor_plane; + const struct of_device_id *match; + int ret; + + vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); + if (!vc4_crtc) + return -ENOMEM; + crtc = &vc4_crtc->base; + + match = of_match_device(vc4_crtc_dt_match, dev); + if (!match) + return -ENODEV; + vc4_crtc->data = match->data; + + vc4_crtc->regs = vc4_ioremap_regs(pdev, 0); + if (IS_ERR(vc4_crtc->regs)) + return PTR_ERR(vc4_crtc->regs); + + /* For now, we create just the primary and the legacy cursor + * planes. We should be able to stack more planes on easily, + * but to do that we would need to compute the bandwidth + * requirement of the plane configuration, and reject ones + * that will take too much. + */ + primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY); + if (!primary_plane) { + dev_err(dev, "failed to construct primary plane\n"); + ret = PTR_ERR(primary_plane); + goto err; + } + + cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); + if (!cursor_plane) { + dev_err(dev, "failed to construct cursor plane\n"); + ret = PTR_ERR(cursor_plane); + goto err_primary; + } + + drm_crtc_init_with_planes(drm, crtc, primary_plane, cursor_plane, + &vc4_crtc_funcs); + drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs); + primary_plane->crtc = crtc; + cursor_plane->crtc = crtc; + vc4->crtc[drm_crtc_index(crtc)] = vc4_crtc; + vc4_crtc->channel = vc4_crtc->data->hvs_channel; + + CRTC_WRITE(PV_INTEN, 0); + CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START); + ret = devm_request_irq(dev, platform_get_irq(pdev, 0), + vc4_crtc_irq_handler, 0, "vc4 crtc", vc4_crtc); + if (ret) + goto err_cursor; + + vc4_set_crtc_possible_masks(drm, crtc); + + platform_set_drvdata(pdev, vc4_crtc); + + return 0; + +err_cursor: + cursor_plane->funcs->destroy(cursor_plane); +err_primary: + primary_plane->funcs->destroy(primary_plane); +err: + return ret; +} + +static void vc4_crtc_unbind(struct device *dev, struct device *master, + void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev); + + vc4_crtc_destroy(&vc4_crtc->base); + + CRTC_WRITE(PV_INTEN, 0); + + platform_set_drvdata(pdev, NULL); +} + +static const struct component_ops vc4_crtc_ops = { + .bind = vc4_crtc_bind, + .unbind = vc4_crtc_unbind, +}; + +static int vc4_crtc_dev_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &vc4_crtc_ops); +} + +static int vc4_crtc_dev_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &vc4_crtc_ops); + return 0; +} + +struct platform_driver vc4_crtc_driver = { + .probe = vc4_crtc_dev_probe, + .remove = vc4_crtc_dev_remove, + .driver = { + .name = "vc4_crtc", + .of_match_table = vc4_crtc_dt_match, + }, +}; diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c new file mode 100644 index 000000000000..4297b0a5b74e --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_debugfs.c @@ -0,0 +1,39 @@ +/* + * Copyright © 2014 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/seq_file.h> +#include <linux/circ_buf.h> +#include <linux/ctype.h> +#include <linux/debugfs.h> +#include <drm/drmP.h> + +#include "vc4_drv.h" +#include "vc4_regs.h" + +static const struct drm_info_list vc4_debugfs_list[] = { + {"hdmi_regs", vc4_hdmi_debugfs_regs, 0}, + {"hvs_regs", vc4_hvs_debugfs_regs, 0}, + {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0}, + {"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1}, + {"crtc2_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)2}, +}; + +#define VC4_DEBUGFS_ENTRIES ARRAY_SIZE(vc4_debugfs_list) + +int +vc4_debugfs_init(struct drm_minor *minor) +{ + return drm_debugfs_create_files(vc4_debugfs_list, VC4_DEBUGFS_ENTRIES, + minor->debugfs_root, minor); +} + +void +vc4_debugfs_cleanup(struct drm_minor *minor) +{ + drm_debugfs_remove_files(vc4_debugfs_list, VC4_DEBUGFS_ENTRIES, minor); +} diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c new file mode 100644 index 000000000000..6e730605edcc --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2014-2015 Broadcom + * Copyright (C) 2013 Red Hat + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/component.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include "drm_fb_cma_helper.h" + +#include "vc4_drv.h" +#include "vc4_regs.h" + +#define DRIVER_NAME "vc4" +#define DRIVER_DESC "Broadcom VC4 graphics" +#define DRIVER_DATE "20140616" +#define DRIVER_MAJOR 0 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 + +/* Helper function for mapping the regs on a platform device. */ +void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index) +{ + struct resource *res; + void __iomem *map; + + res = platform_get_resource(dev, IORESOURCE_MEM, index); + map = devm_ioremap_resource(&dev->dev, res); + if (IS_ERR(map)) { + DRM_ERROR("Failed to map registers: %ld\n", PTR_ERR(map)); + return map; + } + + return map; +} + +static void vc4_drm_preclose(struct drm_device *dev, struct drm_file *file) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + vc4_cancel_page_flip(crtc, file); +} + +static void vc4_lastclose(struct drm_device *dev) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + + if (vc4->fbdev) + drm_fbdev_cma_restore_mode(vc4->fbdev); +} + +static const struct file_operations vc4_drm_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, + .mmap = drm_gem_cma_mmap, + .poll = drm_poll, + .read = drm_read, +#ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, +#endif + .llseek = noop_llseek, +}; + +static const struct drm_ioctl_desc vc4_drm_ioctls[] = { +}; + +static struct drm_driver vc4_drm_driver = { + .driver_features = (DRIVER_MODESET | + DRIVER_ATOMIC | + DRIVER_GEM | + DRIVER_PRIME), + .lastclose = vc4_lastclose, + .preclose = vc4_drm_preclose, + + .enable_vblank = vc4_enable_vblank, + .disable_vblank = vc4_disable_vblank, + .get_vblank_counter = drm_vblank_count, + +#if defined(CONFIG_DEBUG_FS) + .debugfs_init = vc4_debugfs_init, + .debugfs_cleanup = vc4_debugfs_cleanup, +#endif + + .gem_free_object = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, + + .dumb_create = vc4_dumb_create, + .dumb_map_offset = drm_gem_cma_dumb_map_offset, + .dumb_destroy = drm_gem_dumb_destroy, + + .ioctls = vc4_drm_ioctls, + .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls), + .fops = &vc4_drm_fops, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, +}; + +static int compare_dev(struct device *dev, void *data) +{ + return dev == data; +} + +static void vc4_match_add_drivers(struct device *dev, + struct component_match **match, + struct platform_driver *const *drivers, + int count) +{ + int i; + + for (i = 0; i < count; i++) { + struct device_driver *drv = &drivers[i]->driver; + struct device *p = NULL, *d; + + while ((d = bus_find_device(&platform_bus_type, p, drv, + (void *)platform_bus_type.match))) { + put_device(p); + component_match_add(dev, match, compare_dev, d); + p = d; + } + put_device(p); + } +} + +static int vc4_drm_bind(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm; + struct drm_connector *connector; + struct vc4_dev *vc4; + int ret = 0; + + dev->coherent_dma_mask = DMA_BIT_MASK(32); + + vc4 = devm_kzalloc(dev, sizeof(*vc4), GFP_KERNEL); + if (!vc4) + return -ENOMEM; + + drm = drm_dev_alloc(&vc4_drm_driver, dev); + if (!drm) + return -ENOMEM; + platform_set_drvdata(pdev, drm); + vc4->dev = drm; + drm->dev_private = vc4; + + drm_dev_set_unique(drm, dev_name(dev)); + + drm_mode_config_init(drm); + if (ret) + goto unref; + + ret = component_bind_all(dev, drm); + if (ret) + goto unref; + + ret = drm_dev_register(drm, 0); + if (ret < 0) + goto unbind_all; + + /* Connector registration has to occur after DRM device + * registration, because it creates sysfs entries based on the + * DRM device. + */ + list_for_each_entry(connector, &drm->mode_config.connector_list, head) { + ret = drm_connector_register(connector); + if (ret) + goto unregister; + } + + vc4_kms_load(drm); + + return 0; + +unregister: + drm_dev_unregister(drm); +unbind_all: + component_unbind_all(dev, drm); +unref: + drm_dev_unref(drm); + return ret; +} + +static void vc4_drm_unbind(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = platform_get_drvdata(pdev); + struct vc4_dev *vc4 = to_vc4_dev(drm); + + if (vc4->fbdev) + drm_fbdev_cma_fini(vc4->fbdev); + + drm_mode_config_cleanup(drm); + + drm_put_dev(drm); +} + +static const struct component_master_ops vc4_drm_ops = { + .bind = vc4_drm_bind, + .unbind = vc4_drm_unbind, +}; + +static struct platform_driver *const component_drivers[] = { + &vc4_hdmi_driver, + &vc4_crtc_driver, + &vc4_hvs_driver, +}; + +static int vc4_platform_drm_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + struct device *dev = &pdev->dev; + + vc4_match_add_drivers(dev, &match, + component_drivers, ARRAY_SIZE(component_drivers)); + + return component_master_add_with_match(dev, &vc4_drm_ops, match); +} + +static int vc4_platform_drm_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &vc4_drm_ops); + + return 0; +} + +static const struct of_device_id vc4_of_match[] = { + { .compatible = "brcm,bcm2835-vc4", }, + {}, +}; +MODULE_DEVICE_TABLE(of, vc4_of_match); + +static struct platform_driver vc4_platform_driver = { + .probe = vc4_platform_drm_probe, + .remove = vc4_platform_drm_remove, + .driver = { + .name = "vc4-drm", + .owner = THIS_MODULE, + .of_match_table = vc4_of_match, + }, +}; + +static int __init vc4_drm_register(void) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(component_drivers); i++) { + ret = platform_driver_register(component_drivers[i]); + if (ret) { + while (--i >= 0) + platform_driver_unregister(component_drivers[i]); + return ret; + } + } + return platform_driver_register(&vc4_platform_driver); +} + +static void __exit vc4_drm_unregister(void) +{ + int i; + + for (i = ARRAY_SIZE(component_drivers) - 1; i >= 0; i--) + platform_driver_unregister(component_drivers[i]); + + platform_driver_unregister(&vc4_platform_driver); +} + +module_init(vc4_drm_register); +module_exit(vc4_drm_unregister); + +MODULE_ALIAS("platform:vc4-drm"); +MODULE_DESCRIPTION("Broadcom VC4 DRM Driver"); +MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h new file mode 100644 index 000000000000..fd8319fa682e --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2015 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "drmP.h" +#include "drm_gem_cma_helper.h" + +struct vc4_dev { + struct drm_device *dev; + + struct vc4_hdmi *hdmi; + struct vc4_hvs *hvs; + struct vc4_crtc *crtc[3]; + + struct drm_fbdev_cma *fbdev; +}; + +static inline struct vc4_dev * +to_vc4_dev(struct drm_device *dev) +{ + return (struct vc4_dev *)dev->dev_private; +} + +struct vc4_bo { + struct drm_gem_cma_object base; +}; + +static inline struct vc4_bo * +to_vc4_bo(struct drm_gem_object *bo) +{ + return (struct vc4_bo *)bo; +} + +struct vc4_hvs { + struct platform_device *pdev; + void __iomem *regs; + void __iomem *dlist; +}; + +struct vc4_plane { + struct drm_plane base; +}; + +static inline struct vc4_plane * +to_vc4_plane(struct drm_plane *plane) +{ + return (struct vc4_plane *)plane; +} + +enum vc4_encoder_type { + VC4_ENCODER_TYPE_HDMI, + VC4_ENCODER_TYPE_VEC, + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_DSI1, + VC4_ENCODER_TYPE_SMI, + VC4_ENCODER_TYPE_DPI, +}; + +struct vc4_encoder { + struct drm_encoder base; + enum vc4_encoder_type type; + u32 clock_select; +}; + +static inline struct vc4_encoder * +to_vc4_encoder(struct drm_encoder *encoder) +{ + return container_of(encoder, struct vc4_encoder, base); +} + +#define HVS_READ(offset) readl(vc4->hvs->regs + offset) +#define HVS_WRITE(offset, val) writel(val, vc4->hvs->regs + offset) + +/** + * _wait_for - magic (register) wait macro + * + * Does the right thing for modeset paths when run under kdgb or similar atomic + * contexts. Note that it's important that we check the condition again after + * having timed out, since the timeout could be due to preemption or similar and + * we've never had a chance to check the condition before the timeout. + */ +#define _wait_for(COND, MS, W) ({ \ + unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1; \ + int ret__ = 0; \ + while (!(COND)) { \ + if (time_after(jiffies, timeout__)) { \ + if (!(COND)) \ + ret__ = -ETIMEDOUT; \ + break; \ + } \ + if (W && drm_can_sleep()) { \ + msleep(W); \ + } else { \ + cpu_relax(); \ + } \ + } \ + ret__; \ +}) + +#define wait_for(COND, MS) _wait_for(COND, MS, 1) + +/* vc4_bo.c */ +void vc4_free_object(struct drm_gem_object *gem_obj); +struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size); +int vc4_dumb_create(struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args); +struct dma_buf *vc4_prime_export(struct drm_device *dev, + struct drm_gem_object *obj, int flags); + +/* vc4_crtc.c */ +extern struct platform_driver vc4_crtc_driver; +int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id); +void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id); +void vc4_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); +int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg); + +/* vc4_debugfs.c */ +int vc4_debugfs_init(struct drm_minor *minor); +void vc4_debugfs_cleanup(struct drm_minor *minor); + +/* vc4_drv.c */ +void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index); + +/* vc4_hdmi.c */ +extern struct platform_driver vc4_hdmi_driver; +int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused); + +/* vc4_hvs.c */ +extern struct platform_driver vc4_hvs_driver; +void vc4_hvs_dump_state(struct drm_device *dev); +int vc4_hvs_debugfs_regs(struct seq_file *m, void *unused); + +/* vc4_kms.c */ +int vc4_kms_load(struct drm_device *dev); + +/* vc4_plane.c */ +struct drm_plane *vc4_plane_init(struct drm_device *dev, + enum drm_plane_type type); +u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist); +u32 vc4_plane_dlist_size(struct drm_plane_state *state); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c new file mode 100644 index 000000000000..da9a36d6e1d1 --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -0,0 +1,590 @@ +/* + * Copyright (C) 2015 Broadcom + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * DOC: VC4 Falcon HDMI module + * + * The HDMI core has a state machine and a PHY. Most of the unit + * operates off of the HSM clock from CPRMAN. It also internally uses + * the PLLH_PIX clock for the PHY. + */ + +#include "drm_atomic_helper.h" +#include "drm_crtc_helper.h" +#include "drm_edid.h" +#include "linux/clk.h" +#include "linux/component.h" +#include "linux/i2c.h" +#include "linux/of_gpio.h" +#include "linux/of_platform.h" +#include "vc4_drv.h" +#include "vc4_regs.h" + +/* General HDMI hardware state. */ +struct vc4_hdmi { + struct platform_device *pdev; + + struct drm_encoder *encoder; + struct drm_connector *connector; + + struct i2c_adapter *ddc; + void __iomem *hdmicore_regs; + void __iomem *hd_regs; + int hpd_gpio; + + struct clk *pixel_clock; + struct clk *hsm_clock; +}; + +#define HDMI_READ(offset) readl(vc4->hdmi->hdmicore_regs + offset) +#define HDMI_WRITE(offset, val) writel(val, vc4->hdmi->hdmicore_regs + offset) +#define HD_READ(offset) readl(vc4->hdmi->hd_regs + offset) +#define HD_WRITE(offset, val) writel(val, vc4->hdmi->hd_regs + offset) + +/* VC4 HDMI encoder KMS struct */ +struct vc4_hdmi_encoder { + struct vc4_encoder base; + bool hdmi_monitor; +}; + +static inline struct vc4_hdmi_encoder * +to_vc4_hdmi_encoder(struct drm_encoder *encoder) +{ + return container_of(encoder, struct vc4_hdmi_encoder, base.base); +} + +/* VC4 HDMI connector KMS struct */ +struct vc4_hdmi_connector { + struct drm_connector base; + + /* Since the connector is attached to just the one encoder, + * this is the reference to it so we can do the best_encoder() + * hook. + */ + struct drm_encoder *encoder; +}; + +static inline struct vc4_hdmi_connector * +to_vc4_hdmi_connector(struct drm_connector *connector) +{ + return container_of(connector, struct vc4_hdmi_connector, base); +} + +#define HDMI_REG(reg) { reg, #reg } +static const struct { + u32 reg; + const char *name; +} hdmi_regs[] = { + HDMI_REG(VC4_HDMI_CORE_REV), + HDMI_REG(VC4_HDMI_SW_RESET_CONTROL), + HDMI_REG(VC4_HDMI_HOTPLUG_INT), + HDMI_REG(VC4_HDMI_HOTPLUG), + HDMI_REG(VC4_HDMI_HORZA), + HDMI_REG(VC4_HDMI_HORZB), + HDMI_REG(VC4_HDMI_FIFO_CTL), + HDMI_REG(VC4_HDMI_SCHEDULER_CONTROL), + HDMI_REG(VC4_HDMI_VERTA0), + HDMI_REG(VC4_HDMI_VERTA1), + HDMI_REG(VC4_HDMI_VERTB0), + HDMI_REG(VC4_HDMI_VERTB1), + HDMI_REG(VC4_HDMI_TX_PHY_RESET_CTL), +}; + +static const struct { + u32 reg; + const char *name; +} hd_regs[] = { + HDMI_REG(VC4_HD_M_CTL), + HDMI_REG(VC4_HD_MAI_CTL), + HDMI_REG(VC4_HD_VID_CTL), + HDMI_REG(VC4_HD_CSC_CTL), + HDMI_REG(VC4_HD_FRAME_COUNT), +}; + +#ifdef CONFIG_DEBUG_FS +int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *)m->private; + struct drm_device *dev = node->minor->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(hdmi_regs); i++) { + seq_printf(m, "%s (0x%04x): 0x%08x\n", + hdmi_regs[i].name, hdmi_regs[i].reg, + HDMI_READ(hdmi_regs[i].reg)); + } + + for (i = 0; i < ARRAY_SIZE(hd_regs); i++) { + seq_printf(m, "%s (0x%04x): 0x%08x\n", + hd_regs[i].name, hd_regs[i].reg, + HD_READ(hd_regs[i].reg)); + } + + return 0; +} +#endif /* CONFIG_DEBUG_FS */ + +static void vc4_hdmi_dump_regs(struct drm_device *dev) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(hdmi_regs); i++) { + DRM_INFO("0x%04x (%s): 0x%08x\n", + hdmi_regs[i].reg, hdmi_regs[i].name, + HDMI_READ(hdmi_regs[i].reg)); + } + for (i = 0; i < ARRAY_SIZE(hd_regs); i++) { + DRM_INFO("0x%04x (%s): 0x%08x\n", + hd_regs[i].reg, hd_regs[i].name, + HD_READ(hd_regs[i].reg)); + } +} + +static enum drm_connector_status +vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) +{ + struct drm_device *dev = connector->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + + if (vc4->hdmi->hpd_gpio) { + if (gpio_get_value(vc4->hdmi->hpd_gpio)) + return connector_status_connected; + else + return connector_status_disconnected; + } + + if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) + return connector_status_connected; + else + return connector_status_disconnected; +} + +static void vc4_hdmi_connector_destroy(struct drm_connector *connector) +{ + drm_connector_unregister(connector); + drm_connector_cleanup(connector); +} + +static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) +{ + struct vc4_hdmi_connector *vc4_connector = + to_vc4_hdmi_connector(connector); + struct drm_encoder *encoder = vc4_connector->encoder; + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); + struct drm_device *dev = connector->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + int ret = 0; + struct edid *edid; + + edid = drm_get_edid(connector, vc4->hdmi->ddc); + if (!edid) + return -ENODEV; + + vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); + drm_mode_connector_update_edid_property(connector, edid); + ret = drm_add_edid_modes(connector, edid); + + return ret; +} + +static struct drm_encoder * +vc4_hdmi_connector_best_encoder(struct drm_connector *connector) +{ + struct vc4_hdmi_connector *hdmi_connector = + to_vc4_hdmi_connector(connector); + return hdmi_connector->encoder; +} + +static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { + .dpms = drm_atomic_helper_connector_dpms, + .detect = vc4_hdmi_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = vc4_hdmi_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = { + .get_modes = vc4_hdmi_connector_get_modes, + .best_encoder = vc4_hdmi_connector_best_encoder, +}; + +static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, + struct drm_encoder *encoder) +{ + struct drm_connector *connector = NULL; + struct vc4_hdmi_connector *hdmi_connector; + int ret = 0; + + hdmi_connector = devm_kzalloc(dev->dev, sizeof(*hdmi_connector), + GFP_KERNEL); + if (!hdmi_connector) { + ret = -ENOMEM; + goto fail; + } + connector = &hdmi_connector->base; + + hdmi_connector->encoder = encoder; + + drm_connector_init(dev, connector, &vc4_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); + drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs); + + connector->polled = (DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT); + + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + + drm_mode_connector_attach_encoder(connector, encoder); + + return connector; + + fail: + if (connector) + vc4_hdmi_connector_destroy(connector); + + return ERR_PTR(ret); +} + +static void vc4_hdmi_encoder_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +static const struct drm_encoder_funcs vc4_hdmi_encoder_funcs = { + .destroy = vc4_hdmi_encoder_destroy, +}; + +static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *unadjusted_mode, + struct drm_display_mode *mode) +{ + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + bool debug_dump_regs = false; + bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; + bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; + u32 vactive = (mode->vdisplay >> + ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0)); + u32 verta = (VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, + VC4_HDMI_VERTA_VSP) | + VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, + VC4_HDMI_VERTA_VFP) | + VC4_SET_FIELD(vactive, VC4_HDMI_VERTA_VAL)); + u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) | + VC4_SET_FIELD(mode->vtotal - mode->vsync_end, + VC4_HDMI_VERTB_VBP)); + + if (debug_dump_regs) { + DRM_INFO("HDMI regs before:\n"); + vc4_hdmi_dump_regs(dev); + } + + HD_WRITE(VC4_HD_VID_CTL, 0); + + clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000); + + HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, + HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | + VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT | + VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS); + + HDMI_WRITE(VC4_HDMI_HORZA, + (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) | + (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) | + VC4_SET_FIELD(mode->hdisplay, VC4_HDMI_HORZA_HAP)); + + HDMI_WRITE(VC4_HDMI_HORZB, + VC4_SET_FIELD(mode->htotal - mode->hsync_end, + VC4_HDMI_HORZB_HBP) | + VC4_SET_FIELD(mode->hsync_end - mode->hsync_start, + VC4_HDMI_HORZB_HSP) | + VC4_SET_FIELD(mode->hsync_start - mode->hdisplay, + VC4_HDMI_HORZB_HFP)); + + HDMI_WRITE(VC4_HDMI_VERTA0, verta); + HDMI_WRITE(VC4_HDMI_VERTA1, verta); + + HDMI_WRITE(VC4_HDMI_VERTB0, vertb); + HDMI_WRITE(VC4_HDMI_VERTB1, vertb); + + HD_WRITE(VC4_HD_VID_CTL, + (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | + (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); + + /* The RGB order applies even when CSC is disabled. */ + HD_WRITE(VC4_HD_CSC_CTL, VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, + VC4_HD_CSC_CTL_ORDER)); + + HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); + + if (debug_dump_regs) { + DRM_INFO("HDMI regs after:\n"); + vc4_hdmi_dump_regs(dev); + } +} + +static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + + HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); + HD_WRITE(VC4_HD_VID_CTL, + HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); +} + +static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) +{ + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + int ret; + + HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0); + + HD_WRITE(VC4_HD_VID_CTL, + HD_READ(VC4_HD_VID_CTL) | + VC4_HD_VID_CTL_ENABLE | + VC4_HD_VID_CTL_UNDERFLOW_ENABLE | + VC4_HD_VID_CTL_FRAME_COUNTER_RESET); + + if (vc4_encoder->hdmi_monitor) { + HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, + HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | + VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); + + ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & + VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1); + WARN_ONCE(ret, "Timeout waiting for " + "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); + } else { + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, + HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & + ~(VC4_HDMI_RAM_PACKET_ENABLE)); + HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, + HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & + ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); + + ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & + VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1); + WARN_ONCE(ret, "Timeout waiting for " + "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); + } + + if (vc4_encoder->hdmi_monitor) { + u32 drift; + + WARN_ON(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & + VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE)); + HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, + HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | + VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT); + + /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set + * up the infoframe. + */ + + drift = HDMI_READ(VC4_HDMI_FIFO_CTL); + drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK; + + HDMI_WRITE(VC4_HDMI_FIFO_CTL, + drift & ~VC4_HDMI_FIFO_CTL_RECENTER); + HDMI_WRITE(VC4_HDMI_FIFO_CTL, + drift | VC4_HDMI_FIFO_CTL_RECENTER); + udelay(1000); + HDMI_WRITE(VC4_HDMI_FIFO_CTL, + drift & ~VC4_HDMI_FIFO_CTL_RECENTER); + HDMI_WRITE(VC4_HDMI_FIFO_CTL, + drift | VC4_HDMI_FIFO_CTL_RECENTER); + + ret = wait_for(HDMI_READ(VC4_HDMI_FIFO_CTL) & + VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1); + WARN_ONCE(ret, "Timeout waiting for " + "VC4_HDMI_FIFO_CTL_RECENTER_DONE"); + } +} + +static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { + .mode_set = vc4_hdmi_encoder_mode_set, + .disable = vc4_hdmi_encoder_disable, + .enable = vc4_hdmi_encoder_enable, +}; + +static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = drm->dev_private; + struct vc4_hdmi *hdmi; + struct vc4_hdmi_encoder *vc4_hdmi_encoder; + struct device_node *ddc_node; + u32 value; + int ret; + + hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + vc4_hdmi_encoder = devm_kzalloc(dev, sizeof(*vc4_hdmi_encoder), + GFP_KERNEL); + if (!vc4_hdmi_encoder) + return -ENOMEM; + vc4_hdmi_encoder->base.type = VC4_ENCODER_TYPE_HDMI; + hdmi->encoder = &vc4_hdmi_encoder->base.base; + + hdmi->pdev = pdev; + hdmi->hdmicore_regs = vc4_ioremap_regs(pdev, 0); + if (IS_ERR(hdmi->hdmicore_regs)) + return PTR_ERR(hdmi->hdmicore_regs); + + hdmi->hd_regs = vc4_ioremap_regs(pdev, 1); + if (IS_ERR(hdmi->hd_regs)) + return PTR_ERR(hdmi->hd_regs); + + ddc_node = of_parse_phandle(dev->of_node, "ddc", 0); + if (!ddc_node) { + DRM_ERROR("Failed to find ddc node in device tree\n"); + return -ENODEV; + } + + hdmi->pixel_clock = devm_clk_get(dev, "pixel"); + if (IS_ERR(hdmi->pixel_clock)) { + DRM_ERROR("Failed to get pixel clock\n"); + return PTR_ERR(hdmi->pixel_clock); + } + hdmi->hsm_clock = devm_clk_get(dev, "hdmi"); + if (IS_ERR(hdmi->hsm_clock)) { + DRM_ERROR("Failed to get HDMI state machine clock\n"); + return PTR_ERR(hdmi->hsm_clock); + } + + hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); + if (!hdmi->ddc) { + DRM_DEBUG("Failed to get ddc i2c adapter by node\n"); + return -EPROBE_DEFER; + } + + /* Enable the clocks at startup. We can't quite recover from + * turning off the pixel clock during disable/enables yet, so + * it's always running. + */ + ret = clk_prepare_enable(hdmi->pixel_clock); + if (ret) { + DRM_ERROR("Failed to turn on pixel clock: %d\n", ret); + goto err_put_i2c; + } + + ret = clk_prepare_enable(hdmi->hsm_clock); + if (ret) { + DRM_ERROR("Failed to turn on HDMI state machine clock: %d\n", + ret); + goto err_unprepare_pix; + } + + /* Only use the GPIO HPD pin if present in the DT, otherwise + * we'll use the HDMI core's register. + */ + if (of_find_property(dev->of_node, "hpd-gpios", &value)) { + hdmi->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpios", 0); + if (hdmi->hpd_gpio < 0) { + ret = hdmi->hpd_gpio; + goto err_unprepare_hsm; + } + } + + vc4->hdmi = hdmi; + + /* HDMI core must be enabled. */ + WARN_ON_ONCE((HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE) == 0); + + drm_encoder_init(drm, hdmi->encoder, &vc4_hdmi_encoder_funcs, + DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(hdmi->encoder, &vc4_hdmi_encoder_helper_funcs); + + hdmi->connector = vc4_hdmi_connector_init(drm, hdmi->encoder); + if (IS_ERR(hdmi->connector)) { + ret = PTR_ERR(hdmi->connector); + goto err_destroy_encoder; + } + + return 0; + +err_destroy_encoder: + vc4_hdmi_encoder_destroy(hdmi->encoder); +err_unprepare_hsm: + clk_disable_unprepare(hdmi->hsm_clock); +err_unprepare_pix: + clk_disable_unprepare(hdmi->pixel_clock); +err_put_i2c: + put_device(&vc4->hdmi->ddc->dev); + + return ret; +} + +static void vc4_hdmi_unbind(struct device *dev, struct device *master, + void *data) +{ + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = drm->dev_private; + struct vc4_hdmi *hdmi = vc4->hdmi; + + vc4_hdmi_connector_destroy(hdmi->connector); + vc4_hdmi_encoder_destroy(hdmi->encoder); + + clk_disable_unprepare(hdmi->pixel_clock); + clk_disable_unprepare(hdmi->hsm_clock); + put_device(&hdmi->ddc->dev); + + vc4->hdmi = NULL; +} + +static const struct component_ops vc4_hdmi_ops = { + .bind = vc4_hdmi_bind, + .unbind = vc4_hdmi_unbind, +}; + +static int vc4_hdmi_dev_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &vc4_hdmi_ops); +} + +static int vc4_hdmi_dev_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &vc4_hdmi_ops); + return 0; +} + +static const struct of_device_id vc4_hdmi_dt_match[] = { + { .compatible = "brcm,bcm2835-hdmi" }, + {} +}; + +struct platform_driver vc4_hdmi_driver = { + .probe = vc4_hdmi_dev_probe, + .remove = vc4_hdmi_dev_remove, + .driver = { + .name = "vc4_hdmi", + .of_match_table = vc4_hdmi_dt_match, + }, +}; diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c new file mode 100644 index 000000000000..ab1673f672a4 --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2015 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/** + * DOC: VC4 HVS module. + * + * The HVS is the piece of hardware that does translation, scaling, + * colorspace conversion, and compositing of pixels stored in + * framebuffers into a FIFO of pixels going out to the Pixel Valve + * (CRTC). It operates at the system clock rate (the system audio + * clock gate, specifically), which is much higher than the pixel + * clock rate. + * + * There is a single global HVS, with multiple output FIFOs that can + * be consumed by the PVs. This file just manages the resources for + * the HVS, while the vc4_crtc.c code actually drives HVS setup for + * each CRTC. + */ + +#include "linux/component.h" +#include "vc4_drv.h" +#include "vc4_regs.h" + +#define HVS_REG(reg) { reg, #reg } +static const struct { + u32 reg; + const char *name; +} hvs_regs[] = { + HVS_REG(SCALER_DISPCTRL), + HVS_REG(SCALER_DISPSTAT), + HVS_REG(SCALER_DISPID), + HVS_REG(SCALER_DISPECTRL), + HVS_REG(SCALER_DISPPROF), + HVS_REG(SCALER_DISPDITHER), + HVS_REG(SCALER_DISPEOLN), + HVS_REG(SCALER_DISPLIST0), + HVS_REG(SCALER_DISPLIST1), + HVS_REG(SCALER_DISPLIST2), + HVS_REG(SCALER_DISPLSTAT), + HVS_REG(SCALER_DISPLACT0), + HVS_REG(SCALER_DISPLACT1), + HVS_REG(SCALER_DISPLACT2), + HVS_REG(SCALER_DISPCTRL0), + HVS_REG(SCALER_DISPBKGND0), + HVS_REG(SCALER_DISPSTAT0), + HVS_REG(SCALER_DISPBASE0), + HVS_REG(SCALER_DISPCTRL1), + HVS_REG(SCALER_DISPBKGND1), + HVS_REG(SCALER_DISPSTAT1), + HVS_REG(SCALER_DISPBASE1), + HVS_REG(SCALER_DISPCTRL2), + HVS_REG(SCALER_DISPBKGND2), + HVS_REG(SCALER_DISPSTAT2), + HVS_REG(SCALER_DISPBASE2), + HVS_REG(SCALER_DISPALPHA2), +}; + +void vc4_hvs_dump_state(struct drm_device *dev) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) { + DRM_INFO("0x%04x (%s): 0x%08x\n", + hvs_regs[i].reg, hvs_regs[i].name, + HVS_READ(hvs_regs[i].reg)); + } + + DRM_INFO("HVS ctx:\n"); + for (i = 0; i < 64; i += 4) { + DRM_INFO("0x%08x (%s): 0x%08x 0x%08x 0x%08x 0x%08x\n", + i * 4, i < HVS_BOOTLOADER_DLIST_END ? "B" : "D", + ((uint32_t *)vc4->hvs->dlist)[i + 0], + ((uint32_t *)vc4->hvs->dlist)[i + 1], + ((uint32_t *)vc4->hvs->dlist)[i + 2], + ((uint32_t *)vc4->hvs->dlist)[i + 3]); + } +} + +#ifdef CONFIG_DEBUG_FS +int vc4_hvs_debugfs_regs(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *)m->private; + struct drm_device *dev = node->minor->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) { + seq_printf(m, "%s (0x%04x): 0x%08x\n", + hvs_regs[i].name, hvs_regs[i].reg, + HVS_READ(hvs_regs[i].reg)); + } + + return 0; +} +#endif + +static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = drm->dev_private; + struct vc4_hvs *hvs = NULL; + + hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL); + if (!hvs) + return -ENOMEM; + + hvs->pdev = pdev; + + hvs->regs = vc4_ioremap_regs(pdev, 0); + if (IS_ERR(hvs->regs)) + return PTR_ERR(hvs->regs); + + hvs->dlist = hvs->regs + SCALER_DLIST_START; + + vc4->hvs = hvs; + return 0; +} + +static void vc4_hvs_unbind(struct device *dev, struct device *master, + void *data) +{ + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = drm->dev_private; + + vc4->hvs = NULL; +} + +static const struct component_ops vc4_hvs_ops = { + .bind = vc4_hvs_bind, + .unbind = vc4_hvs_unbind, +}; + +static int vc4_hvs_dev_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &vc4_hvs_ops); +} + +static int vc4_hvs_dev_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &vc4_hvs_ops); + return 0; +} + +static const struct of_device_id vc4_hvs_dt_match[] = { + { .compatible = "brcm,bcm2835-hvs" }, + {} +}; + +struct platform_driver vc4_hvs_driver = { + .probe = vc4_hvs_dev_probe, + .remove = vc4_hvs_dev_remove, + .driver = { + .name = "vc4_hvs", + .of_match_table = vc4_hvs_dt_match, + }, +}; diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c new file mode 100644 index 000000000000..2e5597d10cc6 --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/** + * DOC: VC4 KMS + * + * This is the general code for implementing KMS mode setting that + * doesn't clearly associate with any of the other objects (plane, + * crtc, HDMI encoder). + */ + +#include "drm_crtc.h" +#include "drm_atomic_helper.h" +#include "drm_crtc_helper.h" +#include "drm_plane_helper.h" +#include "drm_fb_cma_helper.h" +#include "vc4_drv.h" + +static void vc4_output_poll_changed(struct drm_device *dev) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + + if (vc4->fbdev) + drm_fbdev_cma_hotplug_event(vc4->fbdev); +} + +static const struct drm_mode_config_funcs vc4_mode_funcs = { + .output_poll_changed = vc4_output_poll_changed, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, + .fb_create = drm_fb_cma_create, +}; + +int vc4_kms_load(struct drm_device *dev) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + int ret; + + ret = drm_vblank_init(dev, dev->mode_config.num_crtc); + if (ret < 0) { + dev_err(dev->dev, "failed to initialize vblank\n"); + return ret; + } + + dev->mode_config.max_width = 2048; + dev->mode_config.max_height = 2048; + dev->mode_config.funcs = &vc4_mode_funcs; + dev->mode_config.preferred_depth = 24; + dev->vblank_disable_allowed = true; + + drm_mode_config_reset(dev); + + vc4->fbdev = drm_fbdev_cma_init(dev, 32, + dev->mode_config.num_crtc, + dev->mode_config.num_connector); + if (IS_ERR(vc4->fbdev)) + vc4->fbdev = NULL; + + drm_kms_helper_poll_init(dev); + + return 0; +} diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c new file mode 100644 index 000000000000..cdd8b10c0147 --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2015 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/** + * DOC: VC4 plane module + * + * Each DRM plane is a layer of pixels being scanned out by the HVS. + * + * At atomic modeset check time, we compute the HVS display element + * state that would be necessary for displaying the plane (giving us a + * chance to figure out if a plane configuration is invalid), then at + * atomic flush time the CRTC will ask us to write our element state + * into the region of the HVS that it has allocated for us. + */ + +#include "vc4_drv.h" +#include "vc4_regs.h" +#include "drm_atomic_helper.h" +#include "drm_fb_cma_helper.h" +#include "drm_plane_helper.h" + +struct vc4_plane_state { + struct drm_plane_state base; + u32 *dlist; + u32 dlist_size; /* Number of dwords in allocated for the display list */ + u32 dlist_count; /* Number of used dwords in the display list. */ +}; + +static inline struct vc4_plane_state * +to_vc4_plane_state(struct drm_plane_state *state) +{ + return (struct vc4_plane_state *)state; +} + +static const struct hvs_format { + u32 drm; /* DRM_FORMAT_* */ + u32 hvs; /* HVS_FORMAT_* */ + u32 pixel_order; + bool has_alpha; +} hvs_formats[] = { + { + .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, + .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false, + }, + { + .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, + .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true, + }, +}; + +static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { + if (hvs_formats[i].drm == drm_format) + return &hvs_formats[i]; + } + + return NULL; +} + +static bool plane_enabled(struct drm_plane_state *state) +{ + return state->fb && state->crtc; +} + +struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) +{ + struct vc4_plane_state *vc4_state; + + if (WARN_ON(!plane->state)) + return NULL; + + vc4_state = kmemdup(plane->state, sizeof(*vc4_state), GFP_KERNEL); + if (!vc4_state) + return NULL; + + __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); + + if (vc4_state->dlist) { + vc4_state->dlist = kmemdup(vc4_state->dlist, + vc4_state->dlist_count * 4, + GFP_KERNEL); + if (!vc4_state->dlist) { + kfree(vc4_state); + return NULL; + } + vc4_state->dlist_size = vc4_state->dlist_count; + } + + return &vc4_state->base; +} + +void vc4_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + + kfree(vc4_state->dlist); + __drm_atomic_helper_plane_destroy_state(plane, &vc4_state->base); + kfree(state); +} + +/* Called during init to allocate the plane's atomic state. */ +void vc4_plane_reset(struct drm_plane *plane) +{ + struct vc4_plane_state *vc4_state; + + WARN_ON(plane->state); + + vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); + if (!vc4_state) + return; + + plane->state = &vc4_state->base; + vc4_state->base.plane = plane; +} + +static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val) +{ + if (vc4_state->dlist_count == vc4_state->dlist_size) { + u32 new_size = max(4u, vc4_state->dlist_count * 2); + u32 *new_dlist = kmalloc(new_size * 4, GFP_KERNEL); + + if (!new_dlist) + return; + memcpy(new_dlist, vc4_state->dlist, vc4_state->dlist_count * 4); + + kfree(vc4_state->dlist); + vc4_state->dlist = new_dlist; + vc4_state->dlist_size = new_size; + } + + vc4_state->dlist[vc4_state->dlist_count++] = val; +} + +/* Writes out a full display list for an active plane to the plane's + * private dlist state. + */ +static int vc4_plane_mode_set(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + struct drm_framebuffer *fb = state->fb; + struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); + u32 ctl0_offset = vc4_state->dlist_count; + const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format); + uint32_t offset = fb->offsets[0]; + int crtc_x = state->crtc_x; + int crtc_y = state->crtc_y; + int crtc_w = state->crtc_w; + int crtc_h = state->crtc_h; + + if (crtc_x < 0) { + offset += drm_format_plane_cpp(fb->pixel_format, 0) * -crtc_x; + crtc_w += crtc_x; + crtc_x = 0; + } + + if (crtc_y < 0) { + offset += fb->pitches[0] * -crtc_y; + crtc_h += crtc_y; + crtc_y = 0; + } + + vc4_dlist_write(vc4_state, + SCALER_CTL0_VALID | + (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | + (format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | + SCALER_CTL0_UNITY); + + /* Position Word 0: Image Positions and Alpha Value */ + vc4_dlist_write(vc4_state, + VC4_SET_FIELD(0xff, SCALER_POS0_FIXED_ALPHA) | + VC4_SET_FIELD(crtc_x, SCALER_POS0_START_X) | + VC4_SET_FIELD(crtc_y, SCALER_POS0_START_Y)); + + /* Position Word 1: Scaled Image Dimensions. + * Skipped due to SCALER_CTL0_UNITY scaling. + */ + + /* Position Word 2: Source Image Size, Alpha Mode */ + vc4_dlist_write(vc4_state, + VC4_SET_FIELD(format->has_alpha ? + SCALER_POS2_ALPHA_MODE_PIPELINE : + SCALER_POS2_ALPHA_MODE_FIXED, + SCALER_POS2_ALPHA_MODE) | + VC4_SET_FIELD(crtc_w, SCALER_POS2_WIDTH) | + VC4_SET_FIELD(crtc_h, SCALER_POS2_HEIGHT)); + + /* Position Word 3: Context. Written by the HVS. */ + vc4_dlist_write(vc4_state, 0xc0c0c0c0); + + /* Pointer Word 0: RGB / Y Pointer */ + vc4_dlist_write(vc4_state, bo->paddr + offset); + + /* Pointer Context Word 0: Written by the HVS */ + vc4_dlist_write(vc4_state, 0xc0c0c0c0); + + /* Pitch word 0: Pointer 0 Pitch */ + vc4_dlist_write(vc4_state, + VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH)); + + vc4_state->dlist[ctl0_offset] |= + VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE); + + return 0; +} + +/* If a modeset involves changing the setup of a plane, the atomic + * infrastructure will call this to validate a proposed plane setup. + * However, if a plane isn't getting updated, this (and the + * corresponding vc4_plane_atomic_update) won't get called. Thus, we + * compute the dlist here and have all active plane dlists get updated + * in the CRTC's flush. + */ +static int vc4_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + + vc4_state->dlist_count = 0; + + if (plane_enabled(state)) + return vc4_plane_mode_set(plane, state); + else + return 0; +} + +static void vc4_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + /* No contents here. Since we don't know where in the CRTC's + * dlist we should be stored, our dlist is uploaded to the + * hardware with vc4_plane_write_dlist() at CRTC atomic_flush + * time. + */ +} + +u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist) +{ + struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); + int i; + + /* Can't memcpy_toio() because it needs to be 32-bit writes. */ + for (i = 0; i < vc4_state->dlist_count; i++) + writel(vc4_state->dlist[i], &dlist[i]); + + return vc4_state->dlist_count; +} + +u32 vc4_plane_dlist_size(struct drm_plane_state *state) +{ + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + + return vc4_state->dlist_count; +} + +static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { + .prepare_fb = NULL, + .cleanup_fb = NULL, + .atomic_check = vc4_plane_atomic_check, + .atomic_update = vc4_plane_atomic_update, +}; + +static void vc4_plane_destroy(struct drm_plane *plane) +{ + drm_plane_helper_disable(plane); + drm_plane_cleanup(plane); +} + +static const struct drm_plane_funcs vc4_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = vc4_plane_destroy, + .set_property = NULL, + .reset = vc4_plane_reset, + .atomic_duplicate_state = vc4_plane_duplicate_state, + .atomic_destroy_state = vc4_plane_destroy_state, +}; + +struct drm_plane *vc4_plane_init(struct drm_device *dev, + enum drm_plane_type type) +{ + struct drm_plane *plane = NULL; + struct vc4_plane *vc4_plane; + u32 formats[ARRAY_SIZE(hvs_formats)]; + int ret = 0; + unsigned i; + + vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), + GFP_KERNEL); + if (!vc4_plane) { + ret = -ENOMEM; + goto fail; + } + + for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) + formats[i] = hvs_formats[i].drm; + plane = &vc4_plane->base; + ret = drm_universal_plane_init(dev, plane, 0xff, + &vc4_plane_funcs, + formats, ARRAY_SIZE(formats), + type); + + drm_plane_helper_add(plane, &vc4_plane_helper_funcs); + + return plane; +fail: + if (plane) + vc4_plane_destroy(plane); + + return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h new file mode 100644 index 000000000000..9e4e904c668e --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_regs.h @@ -0,0 +1,570 @@ +/* + * Copyright © 2014-2015 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef VC4_REGS_H +#define VC4_REGS_H + +#include <linux/bitops.h> + +#define VC4_MASK(high, low) ((u32)GENMASK(high, low)) +/* Using the GNU statement expression extension */ +#define VC4_SET_FIELD(value, field) \ + ({ \ + uint32_t fieldval = (value) << field##_SHIFT; \ + WARN_ON((fieldval & ~field##_MASK) != 0); \ + fieldval & field##_MASK; \ + }) + +#define VC4_GET_FIELD(word, field) (((word) & field##_MASK) >> \ + field##_SHIFT) + +#define V3D_IDENT0 0x00000 +# define V3D_EXPECTED_IDENT0 \ + ((2 << 24) | \ + ('V' << 0) | \ + ('3' << 8) | \ + ('D' << 16)) + +#define V3D_IDENT1 0x00004 +/* Multiples of 1kb */ +# define V3D_IDENT1_VPM_SIZE_MASK VC4_MASK(31, 28) +# define V3D_IDENT1_VPM_SIZE_SHIFT 28 +# define V3D_IDENT1_NSEM_MASK VC4_MASK(23, 16) +# define V3D_IDENT1_NSEM_SHIFT 16 +# define V3D_IDENT1_TUPS_MASK VC4_MASK(15, 12) +# define V3D_IDENT1_TUPS_SHIFT 12 +# define V3D_IDENT1_QUPS_MASK VC4_MASK(11, 8) +# define V3D_IDENT1_QUPS_SHIFT 8 +# define V3D_IDENT1_NSLC_MASK VC4_MASK(7, 4) +# define V3D_IDENT1_NSLC_SHIFT 4 +# define V3D_IDENT1_REV_MASK VC4_MASK(3, 0) +# define V3D_IDENT1_REV_SHIFT 0 + +#define V3D_IDENT2 0x00008 +#define V3D_SCRATCH 0x00010 +#define V3D_L2CACTL 0x00020 +# define V3D_L2CACTL_L2CCLR BIT(2) +# define V3D_L2CACTL_L2CDIS BIT(1) +# define V3D_L2CACTL_L2CENA BIT(0) + +#define V3D_SLCACTL 0x00024 +# define V3D_SLCACTL_T1CC_MASK VC4_MASK(27, 24) +# define V3D_SLCACTL_T1CC_SHIFT 24 +# define V3D_SLCACTL_T0CC_MASK VC4_MASK(19, 16) +# define V3D_SLCACTL_T0CC_SHIFT 16 +# define V3D_SLCACTL_UCC_MASK VC4_MASK(11, 8) +# define V3D_SLCACTL_UCC_SHIFT 8 +# define V3D_SLCACTL_ICC_MASK VC4_MASK(3, 0) +# define V3D_SLCACTL_ICC_SHIFT 0 + +#define V3D_INTCTL 0x00030 +#define V3D_INTENA 0x00034 +#define V3D_INTDIS 0x00038 +# define V3D_INT_SPILLUSE BIT(3) +# define V3D_INT_OUTOMEM BIT(2) +# define V3D_INT_FLDONE BIT(1) +# define V3D_INT_FRDONE BIT(0) + +#define V3D_CT0CS 0x00100 +#define V3D_CT1CS 0x00104 +#define V3D_CTNCS(n) (V3D_CT0CS + 4 * n) +# define V3D_CTRSTA BIT(15) +# define V3D_CTSEMA BIT(12) +# define V3D_CTRTSD BIT(8) +# define V3D_CTRUN BIT(5) +# define V3D_CTSUBS BIT(4) +# define V3D_CTERR BIT(3) +# define V3D_CTMODE BIT(0) + +#define V3D_CT0EA 0x00108 +#define V3D_CT1EA 0x0010c +#define V3D_CTNEA(n) (V3D_CT0EA + 4 * (n)) +#define V3D_CT0CA 0x00110 +#define V3D_CT1CA 0x00114 +#define V3D_CTNCA(n) (V3D_CT0CA + 4 * (n)) +#define V3D_CT00RA0 0x00118 +#define V3D_CT01RA0 0x0011c +#define V3D_CTNRA0(n) (V3D_CT00RA0 + 4 * (n)) +#define V3D_CT0LC 0x00120 +#define V3D_CT1LC 0x00124 +#define V3D_CTNLC(n) (V3D_CT0LC + 4 * (n)) +#define V3D_CT0PC 0x00128 +#define V3D_CT1PC 0x0012c +#define V3D_CTNPC(n) (V3D_CT0PC + 4 * (n)) + +#define V3D_PCS 0x00130 +# define V3D_BMOOM BIT(8) +# define V3D_RMBUSY BIT(3) +# define V3D_RMACTIVE BIT(2) +# define V3D_BMBUSY BIT(1) +# define V3D_BMACTIVE BIT(0) + +#define V3D_BFC 0x00134 +#define V3D_RFC 0x00138 +#define V3D_BPCA 0x00300 +#define V3D_BPCS 0x00304 +#define V3D_BPOA 0x00308 +#define V3D_BPOS 0x0030c +#define V3D_BXCF 0x00310 +#define V3D_SQRSV0 0x00410 +#define V3D_SQRSV1 0x00414 +#define V3D_SQCNTL 0x00418 +#define V3D_SRQPC 0x00430 +#define V3D_SRQUA 0x00434 +#define V3D_SRQUL 0x00438 +#define V3D_SRQCS 0x0043c +#define V3D_VPACNTL 0x00500 +#define V3D_VPMBASE 0x00504 +#define V3D_PCTRC 0x00670 +#define V3D_PCTRE 0x00674 +#define V3D_PCTR0 0x00680 +#define V3D_PCTRS0 0x00684 +#define V3D_PCTR1 0x00688 +#define V3D_PCTRS1 0x0068c +#define V3D_PCTR2 0x00690 +#define V3D_PCTRS2 0x00694 +#define V3D_PCTR3 0x00698 +#define V3D_PCTRS3 0x0069c +#define V3D_PCTR4 0x006a0 +#define V3D_PCTRS4 0x006a4 +#define V3D_PCTR5 0x006a8 +#define V3D_PCTRS5 0x006ac +#define V3D_PCTR6 0x006b0 +#define V3D_PCTRS6 0x006b4 +#define V3D_PCTR7 0x006b8 +#define V3D_PCTRS7 0x006bc +#define V3D_PCTR8 0x006c0 +#define V3D_PCTRS8 0x006c4 +#define V3D_PCTR9 0x006c8 +#define V3D_PCTRS9 0x006cc +#define V3D_PCTR10 0x006d0 +#define V3D_PCTRS10 0x006d4 +#define V3D_PCTR11 0x006d8 +#define V3D_PCTRS11 0x006dc +#define V3D_PCTR12 0x006e0 +#define V3D_PCTRS12 0x006e4 +#define V3D_PCTR13 0x006e8 +#define V3D_PCTRS13 0x006ec +#define V3D_PCTR14 0x006f0 +#define V3D_PCTRS14 0x006f4 +#define V3D_PCTR15 0x006f8 +#define V3D_PCTRS15 0x006fc +#define V3D_BGE 0x00f00 +#define V3D_FDBGO 0x00f04 +#define V3D_FDBGB 0x00f08 +#define V3D_FDBGR 0x00f0c +#define V3D_FDBGS 0x00f10 +#define V3D_ERRSTAT 0x00f20 + +#define PV_CONTROL 0x00 +# define PV_CONTROL_FORMAT_MASK VC4_MASK(23, 21) +# define PV_CONTROL_FORMAT_SHIFT 21 +# define PV_CONTROL_FORMAT_24 0 +# define PV_CONTROL_FORMAT_DSIV_16 1 +# define PV_CONTROL_FORMAT_DSIC_16 2 +# define PV_CONTROL_FORMAT_DSIV_18 3 +# define PV_CONTROL_FORMAT_DSIV_24 4 + +# define PV_CONTROL_FIFO_LEVEL_MASK VC4_MASK(20, 15) +# define PV_CONTROL_FIFO_LEVEL_SHIFT 15 +# define PV_CONTROL_CLR_AT_START BIT(14) +# define PV_CONTROL_TRIGGER_UNDERFLOW BIT(13) +# define PV_CONTROL_WAIT_HSTART BIT(12) +# define PV_CONTROL_CLK_SELECT_DSI_VEC 0 +# define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI 1 +# define PV_CONTROL_CLK_SELECT_MASK VC4_MASK(3, 2) +# define PV_CONTROL_CLK_SELECT_SHIFT 2 +# define PV_CONTROL_FIFO_CLR BIT(1) +# define PV_CONTROL_EN BIT(0) + +#define PV_V_CONTROL 0x04 +# define PV_VCONTROL_INTERLACE BIT(4) +# define PV_VCONTROL_CONTINUOUS BIT(1) +# define PV_VCONTROL_VIDEN BIT(0) + +#define PV_VSYNCD 0x08 + +#define PV_HORZA 0x0c +# define PV_HORZA_HBP_MASK VC4_MASK(31, 16) +# define PV_HORZA_HBP_SHIFT 16 +# define PV_HORZA_HSYNC_MASK VC4_MASK(15, 0) +# define PV_HORZA_HSYNC_SHIFT 0 + +#define PV_HORZB 0x10 +# define PV_HORZB_HFP_MASK VC4_MASK(31, 16) +# define PV_HORZB_HFP_SHIFT 16 +# define PV_HORZB_HACTIVE_MASK VC4_MASK(15, 0) +# define PV_HORZB_HACTIVE_SHIFT 0 + +#define PV_VERTA 0x14 +# define PV_VERTA_VBP_MASK VC4_MASK(31, 16) +# define PV_VERTA_VBP_SHIFT 16 +# define PV_VERTA_VSYNC_MASK VC4_MASK(15, 0) +# define PV_VERTA_VSYNC_SHIFT 0 + +#define PV_VERTB 0x18 +# define PV_VERTB_VFP_MASK VC4_MASK(31, 16) +# define PV_VERTB_VFP_SHIFT 16 +# define PV_VERTB_VACTIVE_MASK VC4_MASK(15, 0) +# define PV_VERTB_VACTIVE_SHIFT 0 + +#define PV_VERTA_EVEN 0x1c +#define PV_VERTB_EVEN 0x20 + +#define PV_INTEN 0x24 +#define PV_INTSTAT 0x28 +# define PV_INT_VID_IDLE BIT(9) +# define PV_INT_VFP_END BIT(8) +# define PV_INT_VFP_START BIT(7) +# define PV_INT_VACT_START BIT(6) +# define PV_INT_VBP_START BIT(5) +# define PV_INT_VSYNC_START BIT(4) +# define PV_INT_HFP_START BIT(3) +# define PV_INT_HACT_START BIT(2) +# define PV_INT_HBP_START BIT(1) +# define PV_INT_HSYNC_START BIT(0) + +#define PV_STAT 0x2c + +#define PV_HACT_ACT 0x30 + +#define SCALER_DISPCTRL 0x00000000 +/* Global register for clock gating the HVS */ +# define SCALER_DISPCTRL_ENABLE BIT(31) +# define SCALER_DISPCTRL_DSP2EISLUR BIT(15) +# define SCALER_DISPCTRL_DSP1EISLUR BIT(14) +/* Enables Display 0 short line and underrun contribution to + * SCALER_DISPSTAT_IRQDISP0. Note that short frame contributions are + * always enabled. + */ +# define SCALER_DISPCTRL_DSP0EISLUR BIT(13) +# define SCALER_DISPCTRL_DSP2EIEOLN BIT(12) +# define SCALER_DISPCTRL_DSP2EIEOF BIT(11) +# define SCALER_DISPCTRL_DSP1EIEOLN BIT(10) +# define SCALER_DISPCTRL_DSP1EIEOF BIT(9) +/* Enables Display 0 end-of-line-N contribution to + * SCALER_DISPSTAT_IRQDISP0 + */ +# define SCALER_DISPCTRL_DSP0EIEOLN BIT(8) +/* Enables Display 0 EOF contribution to SCALER_DISPSTAT_IRQDISP0 */ +# define SCALER_DISPCTRL_DSP0EIEOF BIT(7) + +# define SCALER_DISPCTRL_SLVRDEIRQ BIT(6) +# define SCALER_DISPCTRL_SLVWREIRQ BIT(5) +# define SCALER_DISPCTRL_DMAEIRQ BIT(4) +# define SCALER_DISPCTRL_DISP2EIRQ BIT(3) +# define SCALER_DISPCTRL_DISP1EIRQ BIT(2) +/* Enables interrupt generation on the enabled EOF/EOLN/EISLUR + * bits and short frames.. + */ +# define SCALER_DISPCTRL_DISP0EIRQ BIT(1) +/* Enables interrupt generation on scaler profiler interrupt. */ +# define SCALER_DISPCTRL_SCLEIRQ BIT(0) + +#define SCALER_DISPSTAT 0x00000004 +# define SCALER_DISPSTAT_COBLOW2 BIT(29) +# define SCALER_DISPSTAT_EOLN2 BIT(28) +# define SCALER_DISPSTAT_ESFRAME2 BIT(27) +# define SCALER_DISPSTAT_ESLINE2 BIT(26) +# define SCALER_DISPSTAT_EUFLOW2 BIT(25) +# define SCALER_DISPSTAT_EOF2 BIT(24) + +# define SCALER_DISPSTAT_COBLOW1 BIT(21) +# define SCALER_DISPSTAT_EOLN1 BIT(20) +# define SCALER_DISPSTAT_ESFRAME1 BIT(19) +# define SCALER_DISPSTAT_ESLINE1 BIT(18) +# define SCALER_DISPSTAT_EUFLOW1 BIT(17) +# define SCALER_DISPSTAT_EOF1 BIT(16) + +# define SCALER_DISPSTAT_RESP_MASK VC4_MASK(15, 14) +# define SCALER_DISPSTAT_RESP_SHIFT 14 +# define SCALER_DISPSTAT_RESP_OKAY 0 +# define SCALER_DISPSTAT_RESP_EXOKAY 1 +# define SCALER_DISPSTAT_RESP_SLVERR 2 +# define SCALER_DISPSTAT_RESP_DECERR 3 + +# define SCALER_DISPSTAT_COBLOW0 BIT(13) +/* Set when the DISPEOLN line is done compositing. */ +# define SCALER_DISPSTAT_EOLN0 BIT(12) +/* Set when VSTART is seen but there are still pixels in the current + * output line. + */ +# define SCALER_DISPSTAT_ESFRAME0 BIT(11) +/* Set when HSTART is seen but there are still pixels in the current + * output line. + */ +# define SCALER_DISPSTAT_ESLINE0 BIT(10) +/* Set when the the downstream tries to read from the display FIFO + * while it's empty. + */ +# define SCALER_DISPSTAT_EUFLOW0 BIT(9) +/* Set when the display mode changes from RUN to EOF */ +# define SCALER_DISPSTAT_EOF0 BIT(8) + +/* Set on AXI invalid DMA ID error. */ +# define SCALER_DISPSTAT_DMA_ERROR BIT(7) +/* Set on AXI slave read decode error */ +# define SCALER_DISPSTAT_IRQSLVRD BIT(6) +/* Set on AXI slave write decode error */ +# define SCALER_DISPSTAT_IRQSLVWR BIT(5) +/* Set when SCALER_DISPSTAT_DMA_ERROR is set, or + * SCALER_DISPSTAT_RESP_ERROR is not SCALER_DISPSTAT_RESP_OKAY. + */ +# define SCALER_DISPSTAT_IRQDMA BIT(4) +# define SCALER_DISPSTAT_IRQDISP2 BIT(3) +# define SCALER_DISPSTAT_IRQDISP1 BIT(2) +/* Set when any of the EOF/EOLN/ESFRAME/ESLINE bits are set and their + * corresponding interrupt bit is enabled in DISPCTRL. + */ +# define SCALER_DISPSTAT_IRQDISP0 BIT(1) +/* On read, the profiler interrupt. On write, clear *all* interrupt bits. */ +# define SCALER_DISPSTAT_IRQSCL BIT(0) + +#define SCALER_DISPID 0x00000008 +#define SCALER_DISPECTRL 0x0000000c +#define SCALER_DISPPROF 0x00000010 +#define SCALER_DISPDITHER 0x00000014 +#define SCALER_DISPEOLN 0x00000018 +#define SCALER_DISPLIST0 0x00000020 +#define SCALER_DISPLIST1 0x00000024 +#define SCALER_DISPLIST2 0x00000028 +#define SCALER_DISPLSTAT 0x0000002c +#define SCALER_DISPLISTX(x) (SCALER_DISPLIST0 + \ + (x) * (SCALER_DISPLIST1 - \ + SCALER_DISPLIST0)) + +#define SCALER_DISPLACT0 0x00000030 +#define SCALER_DISPLACT1 0x00000034 +#define SCALER_DISPLACT2 0x00000038 +#define SCALER_DISPCTRL0 0x00000040 +# define SCALER_DISPCTRLX_ENABLE BIT(31) +# define SCALER_DISPCTRLX_RESET BIT(30) +# define SCALER_DISPCTRLX_WIDTH_MASK VC4_MASK(23, 12) +# define SCALER_DISPCTRLX_WIDTH_SHIFT 12 +# define SCALER_DISPCTRLX_HEIGHT_MASK VC4_MASK(11, 0) +# define SCALER_DISPCTRLX_HEIGHT_SHIFT 0 + +#define SCALER_DISPBKGND0 0x00000044 +#define SCALER_DISPSTAT0 0x00000048 +#define SCALER_DISPBASE0 0x0000004c +# define SCALER_DISPSTATX_MODE_MASK VC4_MASK(31, 30) +# define SCALER_DISPSTATX_MODE_SHIFT 30 +# define SCALER_DISPSTATX_MODE_DISABLED 0 +# define SCALER_DISPSTATX_MODE_INIT 1 +# define SCALER_DISPSTATX_MODE_RUN 2 +# define SCALER_DISPSTATX_MODE_EOF 3 +# define SCALER_DISPSTATX_FULL BIT(29) +# define SCALER_DISPSTATX_EMPTY BIT(28) +#define SCALER_DISPCTRL1 0x00000050 +#define SCALER_DISPBKGND1 0x00000054 +#define SCALER_DISPSTAT1 0x00000058 +#define SCALER_DISPSTATX(x) (SCALER_DISPSTAT0 + \ + (x) * (SCALER_DISPSTAT1 - \ + SCALER_DISPSTAT0)) +#define SCALER_DISPBASE1 0x0000005c +#define SCALER_DISPCTRL2 0x00000060 +#define SCALER_DISPCTRLX(x) (SCALER_DISPCTRL0 + \ + (x) * (SCALER_DISPCTRL1 - \ + SCALER_DISPCTRL0)) +#define SCALER_DISPBKGND2 0x00000064 +#define SCALER_DISPSTAT2 0x00000068 +#define SCALER_DISPBASE2 0x0000006c +#define SCALER_DISPALPHA2 0x00000070 +#define SCALER_GAMADDR 0x00000078 +#define SCALER_GAMDATA 0x000000e0 +#define SCALER_DLIST_START 0x00002000 +#define SCALER_DLIST_SIZE 0x00004000 + +#define VC4_HDMI_CORE_REV 0x000 + +#define VC4_HDMI_SW_RESET_CONTROL 0x004 +# define VC4_HDMI_SW_RESET_FORMAT_DETECT BIT(1) +# define VC4_HDMI_SW_RESET_HDMI BIT(0) + +#define VC4_HDMI_HOTPLUG_INT 0x008 + +#define VC4_HDMI_HOTPLUG 0x00c +# define VC4_HDMI_HOTPLUG_CONNECTED BIT(0) + +#define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 +# define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) + +#define VC4_HDMI_HORZA 0x0c4 +# define VC4_HDMI_HORZA_VPOS BIT(14) +# define VC4_HDMI_HORZA_HPOS BIT(13) +/* Horizontal active pixels (hdisplay). */ +# define VC4_HDMI_HORZA_HAP_MASK VC4_MASK(12, 0) +# define VC4_HDMI_HORZA_HAP_SHIFT 0 + +#define VC4_HDMI_HORZB 0x0c8 +/* Horizontal pack porch (htotal - hsync_end). */ +# define VC4_HDMI_HORZB_HBP_MASK VC4_MASK(29, 20) +# define VC4_HDMI_HORZB_HBP_SHIFT 20 +/* Horizontal sync pulse (hsync_end - hsync_start). */ +# define VC4_HDMI_HORZB_HSP_MASK VC4_MASK(19, 10) +# define VC4_HDMI_HORZB_HSP_SHIFT 10 +/* Horizontal front porch (hsync_start - hdisplay). */ +# define VC4_HDMI_HORZB_HFP_MASK VC4_MASK(9, 0) +# define VC4_HDMI_HORZB_HFP_SHIFT 0 + +#define VC4_HDMI_FIFO_CTL 0x05c +# define VC4_HDMI_FIFO_CTL_RECENTER_DONE BIT(14) +# define VC4_HDMI_FIFO_CTL_USE_EMPTY BIT(13) +# define VC4_HDMI_FIFO_CTL_ON_VB BIT(7) +# define VC4_HDMI_FIFO_CTL_RECENTER BIT(6) +# define VC4_HDMI_FIFO_CTL_FIFO_RESET BIT(5) +# define VC4_HDMI_FIFO_CTL_USE_PLL_LOCK BIT(4) +# define VC4_HDMI_FIFO_CTL_INV_CLK_XFR BIT(3) +# define VC4_HDMI_FIFO_CTL_CAPTURE_PTR BIT(2) +# define VC4_HDMI_FIFO_CTL_USE_FULL BIT(1) +# define VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N BIT(0) +# define VC4_HDMI_FIFO_VALID_WRITE_MASK 0xefff + +#define VC4_HDMI_SCHEDULER_CONTROL 0x0c0 +# define VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT BIT(15) +# define VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS BIT(5) +# define VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT BIT(3) +# define VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE BIT(1) +# define VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI BIT(0) + +#define VC4_HDMI_VERTA0 0x0cc +#define VC4_HDMI_VERTA1 0x0d4 +/* Vertical sync pulse (vsync_end - vsync_start). */ +# define VC4_HDMI_VERTA_VSP_MASK VC4_MASK(24, 20) +# define VC4_HDMI_VERTA_VSP_SHIFT 20 +/* Vertical front porch (vsync_start - vdisplay). */ +# define VC4_HDMI_VERTA_VFP_MASK VC4_MASK(19, 13) +# define VC4_HDMI_VERTA_VFP_SHIFT 13 +/* Vertical active lines (vdisplay). */ +# define VC4_HDMI_VERTA_VAL_MASK VC4_MASK(12, 0) +# define VC4_HDMI_VERTA_VAL_SHIFT 0 + +#define VC4_HDMI_VERTB0 0x0d0 +#define VC4_HDMI_VERTB1 0x0d8 +/* Vertical sync pulse offset (for interlaced) */ +# define VC4_HDMI_VERTB_VSPO_MASK VC4_MASK(21, 9) +# define VC4_HDMI_VERTB_VSPO_SHIFT 9 +/* Vertical pack porch (vtotal - vsync_end). */ +# define VC4_HDMI_VERTB_VBP_MASK VC4_MASK(8, 0) +# define VC4_HDMI_VERTB_VBP_SHIFT 0 + +#define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 + +#define VC4_HD_M_CTL 0x00c +# define VC4_HD_M_SW_RST BIT(2) +# define VC4_HD_M_ENABLE BIT(0) + +#define VC4_HD_MAI_CTL 0x014 + +#define VC4_HD_VID_CTL 0x038 +# define VC4_HD_VID_CTL_ENABLE BIT(31) +# define VC4_HD_VID_CTL_UNDERFLOW_ENABLE BIT(30) +# define VC4_HD_VID_CTL_FRAME_COUNTER_RESET BIT(29) +# define VC4_HD_VID_CTL_VSYNC_LOW BIT(28) +# define VC4_HD_VID_CTL_HSYNC_LOW BIT(27) + +#define VC4_HD_CSC_CTL 0x040 +# define VC4_HD_CSC_CTL_ORDER_MASK VC4_MASK(7, 5) +# define VC4_HD_CSC_CTL_ORDER_SHIFT 5 +# define VC4_HD_CSC_CTL_ORDER_RGB 0 +# define VC4_HD_CSC_CTL_ORDER_BGR 1 +# define VC4_HD_CSC_CTL_ORDER_BRG 2 +# define VC4_HD_CSC_CTL_ORDER_GRB 3 +# define VC4_HD_CSC_CTL_ORDER_GBR 4 +# define VC4_HD_CSC_CTL_ORDER_RBG 5 +# define VC4_HD_CSC_CTL_PADMSB BIT(4) +# define VC4_HD_CSC_CTL_MODE_MASK VC4_MASK(3, 2) +# define VC4_HD_CSC_CTL_MODE_SHIFT 2 +# define VC4_HD_CSC_CTL_MODE_RGB_TO_SD_YPRPB 0 +# define VC4_HD_CSC_CTL_MODE_RGB_TO_HD_YPRPB 1 +# define VC4_HD_CSC_CTL_MODE_CUSTOM 2 +# define VC4_HD_CSC_CTL_RGB2YCC BIT(1) +# define VC4_HD_CSC_CTL_ENABLE BIT(0) + +#define VC4_HD_FRAME_COUNT 0x068 + +/* HVS display list information. */ +#define HVS_BOOTLOADER_DLIST_END 32 + +enum hvs_pixel_format { + /* 8bpp */ + HVS_PIXEL_FORMAT_RGB332 = 0, + /* 16bpp */ + HVS_PIXEL_FORMAT_RGBA4444 = 1, + HVS_PIXEL_FORMAT_RGB555 = 2, + HVS_PIXEL_FORMAT_RGBA5551 = 3, + HVS_PIXEL_FORMAT_RGB565 = 4, + /* 24bpp */ + HVS_PIXEL_FORMAT_RGB888 = 5, + HVS_PIXEL_FORMAT_RGBA6666 = 6, + /* 32bpp */ + HVS_PIXEL_FORMAT_RGBA8888 = 7 +}; + +/* Note: the LSB is the rightmost character shown. Only valid for + * HVS_PIXEL_FORMAT_RGB8888, not RGB888. + */ +#define HVS_PIXEL_ORDER_RGBA 0 +#define HVS_PIXEL_ORDER_BGRA 1 +#define HVS_PIXEL_ORDER_ARGB 2 +#define HVS_PIXEL_ORDER_ABGR 3 + +#define HVS_PIXEL_ORDER_XBRG 0 +#define HVS_PIXEL_ORDER_XRBG 1 +#define HVS_PIXEL_ORDER_XRGB 2 +#define HVS_PIXEL_ORDER_XBGR 3 + +#define HVS_PIXEL_ORDER_XYCBCR 0 +#define HVS_PIXEL_ORDER_XYCRCB 1 +#define HVS_PIXEL_ORDER_YXCBCR 2 +#define HVS_PIXEL_ORDER_YXCRCB 3 + +#define SCALER_CTL0_END BIT(31) +#define SCALER_CTL0_VALID BIT(30) + +#define SCALER_CTL0_SIZE_MASK VC4_MASK(29, 24) +#define SCALER_CTL0_SIZE_SHIFT 24 + +#define SCALER_CTL0_HFLIP BIT(16) +#define SCALER_CTL0_VFLIP BIT(15) + +#define SCALER_CTL0_ORDER_MASK VC4_MASK(14, 13) +#define SCALER_CTL0_ORDER_SHIFT 13 + +/* Set to indicate no scaling. */ +#define SCALER_CTL0_UNITY BIT(4) + +#define SCALER_CTL0_PIXEL_FORMAT_MASK VC4_MASK(3, 0) +#define SCALER_CTL0_PIXEL_FORMAT_SHIFT 0 + +#define SCALER_POS0_FIXED_ALPHA_MASK VC4_MASK(31, 24) +#define SCALER_POS0_FIXED_ALPHA_SHIFT 24 + +#define SCALER_POS0_START_Y_MASK VC4_MASK(23, 12) +#define SCALER_POS0_START_Y_SHIFT 12 + +#define SCALER_POS0_START_X_MASK VC4_MASK(11, 0) +#define SCALER_POS0_START_X_SHIFT 0 + +#define SCALER_POS2_ALPHA_MODE_MASK VC4_MASK(31, 30) +#define SCALER_POS2_ALPHA_MODE_SHIFT 30 +#define SCALER_POS2_ALPHA_MODE_PIPELINE 0 +#define SCALER_POS2_ALPHA_MODE_FIXED 1 +#define SCALER_POS2_ALPHA_MODE_FIXED_NONZERO 2 +#define SCALER_POS2_ALPHA_MODE_FIXED_OVER_0x07 3 + +#define SCALER_POS2_HEIGHT_MASK VC4_MASK(27, 16) +#define SCALER_POS2_HEIGHT_SHIFT 16 + +#define SCALER_POS2_WIDTH_MASK VC4_MASK(11, 0) +#define SCALER_POS2_WIDTH_SHIFT 0 + +#define SCALER_SRC_PITCH_MASK VC4_MASK(15, 0) +#define SCALER_SRC_PITCH_SHIFT 0 + +#endif /* VC4_REGS_H */ diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index 860062ef8814..c503a840fd88 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c @@ -235,66 +235,13 @@ unlock: return ret; } -int vgem_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_vma_offset_node *node; - struct drm_gem_object *obj; - struct drm_vgem_gem_object *vgem_obj; - int ret = 0; - - mutex_lock(&dev->struct_mutex); - - node = drm_vma_offset_exact_lookup(dev->vma_offset_manager, - vma->vm_pgoff, - vma_pages(vma)); - if (!node) { - ret = -EINVAL; - goto out_unlock; - } else if (!drm_vma_node_is_allowed(node, filp)) { - ret = -EACCES; - goto out_unlock; - } - - obj = container_of(node, struct drm_gem_object, vma_node); - - vgem_obj = to_vgem_bo(obj); - - if (obj->dma_buf && vgem_obj->use_dma_buf) { - ret = dma_buf_mmap(obj->dma_buf, vma, 0); - goto out_unlock; - } - - if (!obj->dev->driver->gem_vm_ops) { - ret = -EINVAL; - goto out_unlock; - } - - vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_ops = obj->dev->driver->gem_vm_ops; - vma->vm_private_data = vgem_obj; - vma->vm_page_prot = - pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); - - mutex_unlock(&dev->struct_mutex); - drm_gem_vm_open(vma); - return ret; - -out_unlock: - mutex_unlock(&dev->struct_mutex); - - return ret; -} - - static struct drm_ioctl_desc vgem_ioctls[] = { }; static const struct file_operations vgem_driver_fops = { .owner = THIS_MODULE, .open = drm_open, - .mmap = vgem_drm_gem_mmap, + .mmap = drm_gem_mmap, .poll = drm_poll, .read = drm_read, .unlocked_ioctl = drm_ioctl, diff --git a/drivers/gpu/drm/via/via_drv.h b/drivers/gpu/drm/via/via_drv.h index ef8c500b4a00..286a785fab4f 100644 --- a/drivers/gpu/drm/via/via_drv.h +++ b/drivers/gpu/drm/via/via_drv.h @@ -102,6 +102,10 @@ typedef struct drm_via_private { uint32_t dma_diff; } drm_via_private_t; +struct via_file_private { + struct list_head obj_list; +}; + enum via_family { VIA_OTHER = 0, /* Baseline */ VIA_PRO_GROUP_A, /* Another video engine and DMA commands */ @@ -136,9 +140,9 @@ extern int via_init_context(struct drm_device *dev, int context); extern int via_final_context(struct drm_device *dev, int context); extern int via_do_cleanup_map(struct drm_device *dev); -extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc); -extern int via_enable_vblank(struct drm_device *dev, int crtc); -extern void via_disable_vblank(struct drm_device *dev, int crtc); +extern u32 via_get_vblank_counter(struct drm_device *dev, unsigned int pipe); +extern int via_enable_vblank(struct drm_device *dev, unsigned int pipe); +extern void via_disable_vblank(struct drm_device *dev, unsigned int pipe); extern irqreturn_t via_driver_irq_handler(int irq, void *arg); extern void via_driver_irq_preinstall(struct drm_device *dev); diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c index 1319433816d3..ea8172c747a2 100644 --- a/drivers/gpu/drm/via/via_irq.c +++ b/drivers/gpu/drm/via/via_irq.c @@ -95,10 +95,11 @@ static unsigned time_diff(struct timeval *now, struct timeval *then) 1000000 - (then->tv_usec - now->tv_usec); } -u32 via_get_vblank_counter(struct drm_device *dev, int crtc) +u32 via_get_vblank_counter(struct drm_device *dev, unsigned int pipe) { drm_via_private_t *dev_priv = dev->dev_private; - if (crtc != 0) + + if (pipe != 0) return 0; return atomic_read(&dev_priv->vbl_received); @@ -170,13 +171,13 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t *dev_priv) } } -int via_enable_vblank(struct drm_device *dev, int crtc) +int via_enable_vblank(struct drm_device *dev, unsigned int pipe) { drm_via_private_t *dev_priv = dev->dev_private; u32 status; - if (crtc != 0) { - DRM_ERROR("%s: bad crtc %d\n", __func__, crtc); + if (pipe != 0) { + DRM_ERROR("%s: bad crtc %u\n", __func__, pipe); return -EINVAL; } @@ -189,7 +190,7 @@ int via_enable_vblank(struct drm_device *dev, int crtc) return 0; } -void via_disable_vblank(struct drm_device *dev, int crtc) +void via_disable_vblank(struct drm_device *dev, unsigned int pipe) { drm_via_private_t *dev_priv = dev->dev_private; u32 status; @@ -200,8 +201,8 @@ void via_disable_vblank(struct drm_device *dev, int crtc) VIA_WRITE8(0x83d4, 0x11); VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30); - if (crtc != 0) - DRM_ERROR("%s: bad crtc %d\n", __func__, crtc); + if (pipe != 0) + DRM_ERROR("%s: bad crtc %u\n", __func__, pipe); } static int diff --git a/drivers/gpu/drm/virtio/Makefile b/drivers/gpu/drm/virtio/Makefile index 2ee1602d77d4..3fb8eac1084f 100644 --- a/drivers/gpu/drm/virtio/Makefile +++ b/drivers/gpu/drm/virtio/Makefile @@ -6,6 +6,7 @@ ccflags-y := -Iinclude/drm virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_drm_bus.o virtgpu_gem.o \ virtgpu_fb.o virtgpu_display.o virtgpu_vq.o virtgpu_ttm.o \ - virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o + virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o \ + virtgpu_ioctl.o virtgpu_prime.o obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio-gpu.o diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 4e160efc9402..f545913a56c7 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -90,6 +90,14 @@ static int virtio_gpu_crtc_cursor_set(struct drm_crtc *crtc, cpu_to_le32(64), cpu_to_le32(64), 0, 0, &fence); + ret = virtio_gpu_object_reserve(qobj, false); + if (!ret) { + reservation_object_add_excl_fence(qobj->tbo.resv, + &fence->f); + fence_put(&fence->f); + virtio_gpu_object_unreserve(qobj); + virtio_gpu_object_wait(qobj, false); + } output->cursor.hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR); output->cursor.resource_id = cpu_to_le32(qobj->hw_res_handle); @@ -117,6 +125,51 @@ static int virtio_gpu_crtc_cursor_move(struct drm_crtc *crtc, return 0; } +static int virtio_gpu_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t flags) +{ + struct virtio_gpu_device *vgdev = crtc->dev->dev_private; + struct virtio_gpu_output *output = + container_of(crtc, struct virtio_gpu_output, crtc); + struct drm_plane *plane = crtc->primary; + struct virtio_gpu_framebuffer *vgfb; + struct virtio_gpu_object *bo; + unsigned long irqflags; + uint32_t handle; + + plane->fb = fb; + vgfb = to_virtio_gpu_framebuffer(plane->fb); + bo = gem_to_virtio_gpu_obj(vgfb->obj); + handle = bo->hw_res_handle; + + DRM_DEBUG("handle 0x%x%s, crtc %dx%d\n", handle, + bo->dumb ? ", dumb" : "", + crtc->mode.hdisplay, crtc->mode.vdisplay); + if (bo->dumb) { + virtio_gpu_cmd_transfer_to_host_2d + (vgdev, handle, 0, + cpu_to_le32(crtc->mode.hdisplay), + cpu_to_le32(crtc->mode.vdisplay), + 0, 0, NULL); + } + virtio_gpu_cmd_set_scanout(vgdev, output->index, handle, + crtc->mode.hdisplay, + crtc->mode.vdisplay, 0, 0); + virtio_gpu_cmd_resource_flush(vgdev, handle, 0, 0, + crtc->mode.hdisplay, + crtc->mode.vdisplay); + + if (event) { + spin_lock_irqsave(&crtc->dev->event_lock, irqflags); + drm_send_vblank_event(crtc->dev, -1, event); + spin_unlock_irqrestore(&crtc->dev->event_lock, irqflags); + } + + return 0; +} + static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = { .cursor_set2 = virtio_gpu_crtc_cursor_set, .cursor_move = virtio_gpu_crtc_cursor_move, @@ -124,9 +177,7 @@ static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .destroy = drm_crtc_cleanup, -#if 0 /* not (yet) working without vblank support according to docs */ - .page_flip = drm_atomic_helper_page_flip, -#endif + .page_flip = virtio_gpu_page_flip, .reset = drm_atomic_helper_crtc_reset, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 7d9610aaeff9..b40ed6061f05 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -73,6 +73,14 @@ static struct virtio_device_id id_table[] = { }; static unsigned int features[] = { +#ifdef __LITTLE_ENDIAN + /* + * Gallium command stream send by virgl is native endian. + * Because of that we only support little endian guests on + * little endian hosts. + */ + VIRTIO_GPU_F_VIRGL, +#endif }; static struct virtio_driver virtio_gpu_driver = { .feature_table = features, @@ -110,10 +118,12 @@ static const struct file_operations virtio_gpu_driver_fops = { static struct drm_driver driver = { - .driver_features = DRIVER_MODESET | DRIVER_GEM, + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER, .set_busid = drm_virtio_set_busid, .load = virtio_gpu_driver_load, .unload = virtio_gpu_driver_unload, + .open = virtio_gpu_driver_open, + .postclose = virtio_gpu_driver_postclose, .dumb_create = virtio_gpu_mode_dumb_create, .dumb_map_offset = virtio_gpu_mode_dumb_mmap, @@ -123,10 +133,26 @@ static struct drm_driver driver = { .debugfs_init = virtio_gpu_debugfs_init, .debugfs_cleanup = virtio_gpu_debugfs_takedown, #endif + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_pin = virtgpu_gem_prime_pin, + .gem_prime_unpin = virtgpu_gem_prime_unpin, + .gem_prime_get_sg_table = virtgpu_gem_prime_get_sg_table, + .gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table, + .gem_prime_vmap = virtgpu_gem_prime_vmap, + .gem_prime_vunmap = virtgpu_gem_prime_vunmap, + .gem_prime_mmap = virtgpu_gem_prime_mmap, .gem_free_object = virtio_gpu_gem_free_object, + .gem_open_object = virtio_gpu_gem_object_open, + .gem_close_object = virtio_gpu_gem_object_close, .fops = &virtio_gpu_driver_fops, + .ioctls = virtio_gpu_ioctls, + .num_ioctls = DRM_VIRTIO_NUM_IOCTLS, + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 6d4db2dba90b..79f0abe69b64 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -146,6 +146,21 @@ struct virtio_gpu_queue { struct work_struct dequeue_work; }; +struct virtio_gpu_drv_capset { + uint32_t id; + uint32_t max_version; + uint32_t max_size; +}; + +struct virtio_gpu_drv_cap_cache { + struct list_head head; + void *caps_cache; + uint32_t id; + uint32_t version; + uint32_t size; + atomic_t is_valid; +}; + struct virtio_gpu_device { struct device *dev; struct drm_device *ddev; @@ -179,7 +194,13 @@ struct virtio_gpu_device { struct idr ctx_id_idr; spinlock_t ctx_id_idr_lock; + bool has_virgl_3d; + struct work_struct config_changed_work; + + struct virtio_gpu_drv_capset *capsets; + uint32_t num_capsets; + struct list_head cap_cache; }; struct virtio_gpu_fpriv { @@ -193,6 +214,8 @@ extern struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS]; /* virtio_kms.c */ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags); int virtio_gpu_driver_unload(struct drm_device *dev); +int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file); +void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file); /* virtio_gem.c */ void virtio_gpu_gem_free_object(struct drm_gem_object *gem_obj); @@ -203,6 +226,10 @@ int virtio_gpu_gem_create(struct drm_file *file, uint64_t size, struct drm_gem_object **obj_p, uint32_t *handle_p); +int virtio_gpu_gem_object_open(struct drm_gem_object *obj, + struct drm_file *file); +void virtio_gpu_gem_object_close(struct drm_gem_object *obj, + struct drm_file *file); struct virtio_gpu_object *virtio_gpu_alloc_object(struct drm_device *dev, size_t size, bool kernel, bool pinned); @@ -260,10 +287,43 @@ void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev, int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev); void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgdev, uint32_t resource_id); +int virtio_gpu_cmd_get_capset_info(struct virtio_gpu_device *vgdev, int idx); +int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev, + int idx, int version, + struct virtio_gpu_drv_cap_cache **cache_p); +void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id, + uint32_t nlen, const char *name); +void virtio_gpu_cmd_context_destroy(struct virtio_gpu_device *vgdev, + uint32_t id); +void virtio_gpu_cmd_context_attach_resource(struct virtio_gpu_device *vgdev, + uint32_t ctx_id, + uint32_t resource_id); +void virtio_gpu_cmd_context_detach_resource(struct virtio_gpu_device *vgdev, + uint32_t ctx_id, + uint32_t resource_id); +void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev, + void *data, uint32_t data_size, + uint32_t ctx_id, struct virtio_gpu_fence **fence); +void virtio_gpu_cmd_transfer_from_host_3d(struct virtio_gpu_device *vgdev, + uint32_t resource_id, uint32_t ctx_id, + uint64_t offset, uint32_t level, + struct virtio_gpu_box *box, + struct virtio_gpu_fence **fence); +void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev, + uint32_t resource_id, uint32_t ctx_id, + uint64_t offset, uint32_t level, + struct virtio_gpu_box *box, + struct virtio_gpu_fence **fence); +void +virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, + struct virtio_gpu_resource_create_3d *rc_3d, + struct virtio_gpu_fence **fence); void virtio_gpu_ctrl_ack(struct virtqueue *vq); void virtio_gpu_cursor_ack(struct virtqueue *vq); +void virtio_gpu_fence_ack(struct virtqueue *vq); void virtio_gpu_dequeue_ctrl_func(struct work_struct *work); void virtio_gpu_dequeue_cursor_func(struct work_struct *work); +void virtio_gpu_dequeue_fence_func(struct work_struct *work); /* virtio_gpu_display.c */ int virtio_gpu_framebuffer_init(struct drm_device *dev, @@ -299,6 +359,18 @@ int virtio_gpu_object_get_sg_table(struct virtio_gpu_device *qdev, void virtio_gpu_object_free_sg_table(struct virtio_gpu_object *bo); int virtio_gpu_object_wait(struct virtio_gpu_object *bo, bool no_wait); +/* virtgpu_prime.c */ +int virtgpu_gem_prime_pin(struct drm_gem_object *obj); +void virtgpu_gem_prime_unpin(struct drm_gem_object *obj); +struct sg_table *virtgpu_gem_prime_get_sg_table(struct drm_gem_object *obj); +struct drm_gem_object *virtgpu_gem_prime_import_sg_table( + struct drm_device *dev, struct dma_buf_attachment *attach, + struct sg_table *sgt); +void *virtgpu_gem_prime_vmap(struct drm_gem_object *obj); +void virtgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); +int virtgpu_gem_prime_mmap(struct drm_gem_object *obj, + struct vm_area_struct *vma); + static inline struct virtio_gpu_object* virtio_gpu_object_ref(struct virtio_gpu_object *bo) { diff --git a/drivers/gpu/drm/virtio/virtgpu_fence.c b/drivers/gpu/drm/virtio/virtgpu_fence.c index 1da632631dac..793ad9f631fd 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fence.c +++ b/drivers/gpu/drm/virtio/virtgpu_fence.c @@ -81,7 +81,7 @@ int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv; unsigned long irq_flags; - *fence = kmalloc(sizeof(struct virtio_gpu_fence), GFP_KERNEL); + *fence = kmalloc(sizeof(struct virtio_gpu_fence), GFP_ATOMIC); if ((*fence) == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c index cfa0d27150bd..1feb7cee3f0d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_gem.c +++ b/drivers/gpu/drm/virtio/virtgpu_gem.c @@ -138,3 +138,44 @@ int virtio_gpu_mode_dumb_mmap(struct drm_file *file_priv, drm_gem_object_unreference_unlocked(gobj); return 0; } + +int virtio_gpu_gem_object_open(struct drm_gem_object *obj, + struct drm_file *file) +{ + struct virtio_gpu_device *vgdev = obj->dev->dev_private; + struct virtio_gpu_fpriv *vfpriv = file->driver_priv; + struct virtio_gpu_object *qobj = gem_to_virtio_gpu_obj(obj); + int r; + + if (!vgdev->has_virgl_3d) + return 0; + + r = virtio_gpu_object_reserve(qobj, false); + if (r) + return r; + + virtio_gpu_cmd_context_attach_resource(vgdev, vfpriv->ctx_id, + qobj->hw_res_handle); + virtio_gpu_object_unreserve(qobj); + return 0; +} + +void virtio_gpu_gem_object_close(struct drm_gem_object *obj, + struct drm_file *file) +{ + struct virtio_gpu_device *vgdev = obj->dev->dev_private; + struct virtio_gpu_fpriv *vfpriv = file->driver_priv; + struct virtio_gpu_object *qobj = gem_to_virtio_gpu_obj(obj); + int r; + + if (!vgdev->has_virgl_3d) + return; + + r = virtio_gpu_object_reserve(qobj, false); + if (r) + return; + + virtio_gpu_cmd_context_detach_resource(vgdev, vfpriv->ctx_id, + qobj->hw_res_handle); + virtio_gpu_object_unreserve(qobj); +} diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c new file mode 100644 index 000000000000..b4de18e65db8 --- /dev/null +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -0,0 +1,573 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * All Rights Reserved. + * + * Authors: + * Dave Airlie + * Alon Levy + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <drm/drmP.h> +#include "virtgpu_drv.h" +#include <drm/virtgpu_drm.h> +#include "ttm/ttm_execbuf_util.h" + +static void convert_to_hw_box(struct virtio_gpu_box *dst, + const struct drm_virtgpu_3d_box *src) +{ + dst->x = cpu_to_le32(src->x); + dst->y = cpu_to_le32(src->y); + dst->z = cpu_to_le32(src->z); + dst->w = cpu_to_le32(src->w); + dst->h = cpu_to_le32(src->h); + dst->d = cpu_to_le32(src->d); +} + +static int virtio_gpu_map_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct virtio_gpu_device *vgdev = dev->dev_private; + struct drm_virtgpu_map *virtio_gpu_map = data; + + return virtio_gpu_mode_dumb_mmap(file_priv, vgdev->ddev, + virtio_gpu_map->handle, + &virtio_gpu_map->offset); +} + +static int virtio_gpu_object_list_validate(struct ww_acquire_ctx *ticket, + struct list_head *head) +{ + struct ttm_validate_buffer *buf; + struct ttm_buffer_object *bo; + struct virtio_gpu_object *qobj; + int ret; + + ret = ttm_eu_reserve_buffers(ticket, head, true, NULL); + if (ret != 0) + return ret; + + list_for_each_entry(buf, head, head) { + bo = buf->bo; + qobj = container_of(bo, struct virtio_gpu_object, tbo); + ret = ttm_bo_validate(bo, &qobj->placement, false, false); + if (ret) { + ttm_eu_backoff_reservation(ticket, head); + return ret; + } + } + return 0; +} + +static void virtio_gpu_unref_list(struct list_head *head) +{ + struct ttm_validate_buffer *buf; + struct ttm_buffer_object *bo; + struct virtio_gpu_object *qobj; + list_for_each_entry(buf, head, head) { + bo = buf->bo; + qobj = container_of(bo, struct virtio_gpu_object, tbo); + + drm_gem_object_unreference_unlocked(&qobj->gem_base); + } +} + +static int virtio_gpu_execbuffer(struct drm_device *dev, + struct drm_virtgpu_execbuffer *exbuf, + struct drm_file *drm_file) +{ + struct virtio_gpu_device *vgdev = dev->dev_private; + struct virtio_gpu_fpriv *vfpriv = drm_file->driver_priv; + struct drm_gem_object *gobj; + struct virtio_gpu_fence *fence; + struct virtio_gpu_object *qobj; + int ret; + uint32_t *bo_handles = NULL; + void __user *user_bo_handles = NULL; + struct list_head validate_list; + struct ttm_validate_buffer *buflist = NULL; + int i; + struct ww_acquire_ctx ticket; + void *buf; + + if (vgdev->has_virgl_3d == false) + return -ENOSYS; + + INIT_LIST_HEAD(&validate_list); + if (exbuf->num_bo_handles) { + + bo_handles = drm_malloc_ab(exbuf->num_bo_handles, + sizeof(uint32_t)); + buflist = drm_calloc_large(exbuf->num_bo_handles, + sizeof(struct ttm_validate_buffer)); + if (!bo_handles || !buflist) { + drm_free_large(bo_handles); + drm_free_large(buflist); + return -ENOMEM; + } + + user_bo_handles = (void __user *)(uintptr_t)exbuf->bo_handles; + if (copy_from_user(bo_handles, user_bo_handles, + exbuf->num_bo_handles * sizeof(uint32_t))) { + ret = -EFAULT; + drm_free_large(bo_handles); + drm_free_large(buflist); + return ret; + } + + for (i = 0; i < exbuf->num_bo_handles; i++) { + gobj = drm_gem_object_lookup(dev, + drm_file, bo_handles[i]); + if (!gobj) { + drm_free_large(bo_handles); + drm_free_large(buflist); + return -ENOENT; + } + + qobj = gem_to_virtio_gpu_obj(gobj); + buflist[i].bo = &qobj->tbo; + + list_add(&buflist[i].head, &validate_list); + } + drm_free_large(bo_handles); + } + + ret = virtio_gpu_object_list_validate(&ticket, &validate_list); + if (ret) + goto out_free; + + buf = kmalloc(exbuf->size, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto out_unresv; + } + if (copy_from_user(buf, (void __user *)(uintptr_t)exbuf->command, + exbuf->size)) { + kfree(buf); + ret = -EFAULT; + goto out_unresv; + } + virtio_gpu_cmd_submit(vgdev, buf, exbuf->size, + vfpriv->ctx_id, &fence); + + ttm_eu_fence_buffer_objects(&ticket, &validate_list, &fence->f); + + /* fence the command bo */ + virtio_gpu_unref_list(&validate_list); + drm_free_large(buflist); + fence_put(&fence->f); + return 0; + +out_unresv: + ttm_eu_backoff_reservation(&ticket, &validate_list); +out_free: + virtio_gpu_unref_list(&validate_list); + drm_free_large(buflist); + return ret; +} + +/* + * Usage of execbuffer: + * Relocations need to take into account the full VIRTIO_GPUDrawable size. + * However, the command as passed from user space must *not* contain the initial + * VIRTIO_GPUReleaseInfo struct (first XXX bytes) + */ +static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_virtgpu_execbuffer *execbuffer = data; + return virtio_gpu_execbuffer(dev, execbuffer, file_priv); +} + + +static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct virtio_gpu_device *vgdev = dev->dev_private; + struct drm_virtgpu_getparam *param = data; + int value; + + switch (param->param) { + case VIRTGPU_PARAM_3D_FEATURES: + value = vgdev->has_virgl_3d == true ? 1 : 0; + break; + default: + return -EINVAL; + } + if (copy_to_user((void __user *)(unsigned long)param->value, + &value, sizeof(int))) { + return -EFAULT; + } + return 0; +} + +static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct virtio_gpu_device *vgdev = dev->dev_private; + struct drm_virtgpu_resource_create *rc = data; + int ret; + uint32_t res_id; + struct virtio_gpu_object *qobj; + struct drm_gem_object *obj; + uint32_t handle = 0; + uint32_t size; + struct list_head validate_list; + struct ttm_validate_buffer mainbuf; + struct virtio_gpu_fence *fence = NULL; + struct ww_acquire_ctx ticket; + struct virtio_gpu_resource_create_3d rc_3d; + + if (vgdev->has_virgl_3d == false) { + if (rc->depth > 1) + return -EINVAL; + if (rc->nr_samples > 1) + return -EINVAL; + if (rc->last_level > 1) + return -EINVAL; + if (rc->target != 2) + return -EINVAL; + if (rc->array_size > 1) + return -EINVAL; + } + + INIT_LIST_HEAD(&validate_list); + memset(&mainbuf, 0, sizeof(struct ttm_validate_buffer)); + + virtio_gpu_resource_id_get(vgdev, &res_id); + + size = rc->size; + + /* allocate a single page size object */ + if (size == 0) + size = PAGE_SIZE; + + qobj = virtio_gpu_alloc_object(dev, size, false, false); + if (IS_ERR(qobj)) { + ret = PTR_ERR(qobj); + goto fail_id; + } + obj = &qobj->gem_base; + + if (!vgdev->has_virgl_3d) { + virtio_gpu_cmd_create_resource(vgdev, res_id, rc->format, + rc->width, rc->height); + + ret = virtio_gpu_object_attach(vgdev, qobj, res_id, NULL); + } else { + /* use a gem reference since unref list undoes them */ + drm_gem_object_reference(&qobj->gem_base); + mainbuf.bo = &qobj->tbo; + list_add(&mainbuf.head, &validate_list); + + ret = virtio_gpu_object_list_validate(&ticket, &validate_list); + if (ret) { + DRM_DEBUG("failed to validate\n"); + goto fail_unref; + } + + rc_3d.resource_id = cpu_to_le32(res_id); + rc_3d.target = cpu_to_le32(rc->target); + rc_3d.format = cpu_to_le32(rc->format); + rc_3d.bind = cpu_to_le32(rc->bind); + rc_3d.width = cpu_to_le32(rc->width); + rc_3d.height = cpu_to_le32(rc->height); + rc_3d.depth = cpu_to_le32(rc->depth); + rc_3d.array_size = cpu_to_le32(rc->array_size); + rc_3d.last_level = cpu_to_le32(rc->last_level); + rc_3d.nr_samples = cpu_to_le32(rc->nr_samples); + rc_3d.flags = cpu_to_le32(rc->flags); + + virtio_gpu_cmd_resource_create_3d(vgdev, &rc_3d, NULL); + ret = virtio_gpu_object_attach(vgdev, qobj, res_id, &fence); + if (ret) { + ttm_eu_backoff_reservation(&ticket, &validate_list); + goto fail_unref; + } + ttm_eu_fence_buffer_objects(&ticket, &validate_list, &fence->f); + } + + qobj->hw_res_handle = res_id; + + ret = drm_gem_handle_create(file_priv, obj, &handle); + if (ret) { + + drm_gem_object_release(obj); + if (vgdev->has_virgl_3d) { + virtio_gpu_unref_list(&validate_list); + fence_put(&fence->f); + } + return ret; + } + drm_gem_object_unreference_unlocked(obj); + + rc->res_handle = res_id; /* similiar to a VM address */ + rc->bo_handle = handle; + + if (vgdev->has_virgl_3d) { + virtio_gpu_unref_list(&validate_list); + fence_put(&fence->f); + } + return 0; +fail_unref: + if (vgdev->has_virgl_3d) { + virtio_gpu_unref_list(&validate_list); + fence_put(&fence->f); + } +//fail_obj: +// drm_gem_object_handle_unreference_unlocked(obj); +fail_id: + virtio_gpu_resource_id_put(vgdev, res_id); + return ret; +} + +static int virtio_gpu_resource_info_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_virtgpu_resource_info *ri = data; + struct drm_gem_object *gobj = NULL; + struct virtio_gpu_object *qobj = NULL; + + gobj = drm_gem_object_lookup(dev, file_priv, ri->bo_handle); + if (gobj == NULL) + return -ENOENT; + + qobj = gem_to_virtio_gpu_obj(gobj); + + ri->size = qobj->gem_base.size; + ri->res_handle = qobj->hw_res_handle; + drm_gem_object_unreference_unlocked(gobj); + return 0; +} + +static int virtio_gpu_transfer_from_host_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file) +{ + struct virtio_gpu_device *vgdev = dev->dev_private; + struct virtio_gpu_fpriv *vfpriv = file->driver_priv; + struct drm_virtgpu_3d_transfer_from_host *args = data; + struct drm_gem_object *gobj = NULL; + struct virtio_gpu_object *qobj = NULL; + struct virtio_gpu_fence *fence; + int ret; + u32 offset = args->offset; + struct virtio_gpu_box box; + + if (vgdev->has_virgl_3d == false) + return -ENOSYS; + + gobj = drm_gem_object_lookup(dev, file, args->bo_handle); + if (gobj == NULL) + return -ENOENT; + + qobj = gem_to_virtio_gpu_obj(gobj); + + ret = virtio_gpu_object_reserve(qobj, false); + if (ret) + goto out; + + ret = ttm_bo_validate(&qobj->tbo, &qobj->placement, + true, false); + if (unlikely(ret)) + goto out_unres; + + convert_to_hw_box(&box, &args->box); + virtio_gpu_cmd_transfer_from_host_3d + (vgdev, qobj->hw_res_handle, + vfpriv->ctx_id, offset, args->level, + &box, &fence); + reservation_object_add_excl_fence(qobj->tbo.resv, + &fence->f); + + fence_put(&fence->f); +out_unres: + virtio_gpu_object_unreserve(qobj); +out: + drm_gem_object_unreference_unlocked(gobj); + return ret; +} + +static int virtio_gpu_transfer_to_host_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct virtio_gpu_device *vgdev = dev->dev_private; + struct virtio_gpu_fpriv *vfpriv = file->driver_priv; + struct drm_virtgpu_3d_transfer_to_host *args = data; + struct drm_gem_object *gobj = NULL; + struct virtio_gpu_object *qobj = NULL; + struct virtio_gpu_fence *fence; + struct virtio_gpu_box box; + int ret; + u32 offset = args->offset; + + gobj = drm_gem_object_lookup(dev, file, args->bo_handle); + if (gobj == NULL) + return -ENOENT; + + qobj = gem_to_virtio_gpu_obj(gobj); + + ret = virtio_gpu_object_reserve(qobj, false); + if (ret) + goto out; + + ret = ttm_bo_validate(&qobj->tbo, &qobj->placement, + true, false); + if (unlikely(ret)) + goto out_unres; + + convert_to_hw_box(&box, &args->box); + if (!vgdev->has_virgl_3d) { + virtio_gpu_cmd_transfer_to_host_2d + (vgdev, qobj->hw_res_handle, offset, + box.w, box.h, box.x, box.y, NULL); + } else { + virtio_gpu_cmd_transfer_to_host_3d + (vgdev, qobj->hw_res_handle, + vfpriv ? vfpriv->ctx_id : 0, offset, + args->level, &box, &fence); + reservation_object_add_excl_fence(qobj->tbo.resv, + &fence->f); + fence_put(&fence->f); + } + +out_unres: + virtio_gpu_object_unreserve(qobj); +out: + drm_gem_object_unreference_unlocked(gobj); + return ret; +} + +static int virtio_gpu_wait_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_virtgpu_3d_wait *args = data; + struct drm_gem_object *gobj = NULL; + struct virtio_gpu_object *qobj = NULL; + int ret; + bool nowait = false; + + gobj = drm_gem_object_lookup(dev, file, args->handle); + if (gobj == NULL) + return -ENOENT; + + qobj = gem_to_virtio_gpu_obj(gobj); + + if (args->flags & VIRTGPU_WAIT_NOWAIT) + nowait = true; + ret = virtio_gpu_object_wait(qobj, nowait); + + drm_gem_object_unreference_unlocked(gobj); + return ret; +} + +static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, + void *data, struct drm_file *file) +{ + struct virtio_gpu_device *vgdev = dev->dev_private; + struct drm_virtgpu_get_caps *args = data; + int size; + int i; + int found_valid = -1; + int ret; + struct virtio_gpu_drv_cap_cache *cache_ent; + void *ptr; + if (vgdev->num_capsets == 0) + return -ENOSYS; + + spin_lock(&vgdev->display_info_lock); + for (i = 0; i < vgdev->num_capsets; i++) { + if (vgdev->capsets[i].id == args->cap_set_id) { + if (vgdev->capsets[i].max_version >= args->cap_set_ver) { + found_valid = i; + break; + } + } + } + + if (found_valid == -1) { + spin_unlock(&vgdev->display_info_lock); + return -EINVAL; + } + + size = vgdev->capsets[found_valid].max_size; + if (args->size > size) { + spin_unlock(&vgdev->display_info_lock); + return -EINVAL; + } + + list_for_each_entry(cache_ent, &vgdev->cap_cache, head) { + if (cache_ent->id == args->cap_set_id && + cache_ent->version == args->cap_set_ver) { + ptr = cache_ent->caps_cache; + spin_unlock(&vgdev->display_info_lock); + goto copy_exit; + } + } + spin_unlock(&vgdev->display_info_lock); + + /* not in cache - need to talk to hw */ + virtio_gpu_cmd_get_capset(vgdev, found_valid, args->cap_set_ver, + &cache_ent); + + ret = wait_event_timeout(vgdev->resp_wq, + atomic_read(&cache_ent->is_valid), 5 * HZ); + + ptr = cache_ent->caps_cache; + +copy_exit: + if (copy_to_user((void __user *)(unsigned long)args->addr, ptr, size)) + return -EFAULT; + + return 0; +} + +struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = { + DRM_IOCTL_DEF_DRV(VIRTGPU_MAP, virtio_gpu_map_ioctl, + DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + + DRM_IOCTL_DEF_DRV(VIRTGPU_EXECBUFFER, virtio_gpu_execbuffer_ioctl, + DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + + DRM_IOCTL_DEF_DRV(VIRTGPU_GETPARAM, virtio_gpu_getparam_ioctl, + DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + + DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_CREATE, + virtio_gpu_resource_create_ioctl, + DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + + DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_INFO, virtio_gpu_resource_info_ioctl, + DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + + /* make transfer async to the main ring? - no sure, can we + thread these in the underlying GL */ + DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_FROM_HOST, + virtio_gpu_transfer_from_host_ioctl, + DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_TO_HOST, + virtio_gpu_transfer_to_host_ioctl, + DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + + DRM_IOCTL_DEF_DRV(VIRTGPU_WAIT, virtio_gpu_wait_ioctl, + DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + + DRM_IOCTL_DEF_DRV(VIRTGPU_GET_CAPS, virtio_gpu_get_caps_ioctl, + DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), +}; diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 782766c00d70..06496a128162 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -52,6 +52,41 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work) events_clear, &events_clear); } +static void virtio_gpu_ctx_id_get(struct virtio_gpu_device *vgdev, + uint32_t *resid) +{ + int handle; + + idr_preload(GFP_KERNEL); + spin_lock(&vgdev->ctx_id_idr_lock); + handle = idr_alloc(&vgdev->ctx_id_idr, NULL, 1, 0, 0); + spin_unlock(&vgdev->ctx_id_idr_lock); + idr_preload_end(); + *resid = handle; +} + +static void virtio_gpu_ctx_id_put(struct virtio_gpu_device *vgdev, uint32_t id) +{ + spin_lock(&vgdev->ctx_id_idr_lock); + idr_remove(&vgdev->ctx_id_idr, id); + spin_unlock(&vgdev->ctx_id_idr_lock); +} + +static void virtio_gpu_context_create(struct virtio_gpu_device *vgdev, + uint32_t nlen, const char *name, + uint32_t *ctx_id) +{ + virtio_gpu_ctx_id_get(vgdev, ctx_id); + virtio_gpu_cmd_context_create(vgdev, *ctx_id, nlen, name); +} + +static void virtio_gpu_context_destroy(struct virtio_gpu_device *vgdev, + uint32_t ctx_id) +{ + virtio_gpu_cmd_context_destroy(vgdev, ctx_id); + virtio_gpu_ctx_id_put(vgdev, ctx_id); +} + static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq, void (*work_func)(struct work_struct *work)) { @@ -60,6 +95,36 @@ static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq, INIT_WORK(&vgvq->dequeue_work, work_func); } +static void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev, + int num_capsets) +{ + int i, ret; + + vgdev->capsets = kcalloc(num_capsets, + sizeof(struct virtio_gpu_drv_capset), + GFP_KERNEL); + if (!vgdev->capsets) { + DRM_ERROR("failed to allocate cap sets\n"); + return; + } + for (i = 0; i < num_capsets; i++) { + virtio_gpu_cmd_get_capset_info(vgdev, i); + ret = wait_event_timeout(vgdev->resp_wq, + vgdev->capsets[i].id > 0, 5 * HZ); + if (ret == 0) { + DRM_ERROR("timed out waiting for cap set %d\n", i); + kfree(vgdev->capsets); + vgdev->capsets = NULL; + return; + } + DRM_INFO("cap set %d: id %d, max-version %d, max-size %d\n", + i, vgdev->capsets[i].id, + vgdev->capsets[i].max_version, + vgdev->capsets[i].max_size); + } + vgdev->num_capsets = num_capsets; +} + int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) { static vq_callback_t *callbacks[] = { @@ -70,7 +135,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) struct virtio_gpu_device *vgdev; /* this will expand later */ struct virtqueue *vqs[2]; - u32 num_scanouts; + u32 num_scanouts, num_capsets; int ret; if (!virtio_has_feature(dev->virtdev, VIRTIO_F_VERSION_1)) @@ -96,9 +161,15 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&vgdev->fence_drv.lock); INIT_LIST_HEAD(&vgdev->fence_drv.fences); + INIT_LIST_HEAD(&vgdev->cap_cache); INIT_WORK(&vgdev->config_changed_work, virtio_gpu_config_changed_work_func); + if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_VIRGL)) + vgdev->has_virgl_3d = true; + DRM_INFO("virgl 3d acceleration %s\n", + vgdev->has_virgl_3d ? "enabled" : "not available"); + ret = vgdev->vdev->config->find_vqs(vgdev->vdev, 2, vqs, callbacks, names); if (ret) { @@ -129,6 +200,11 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) ret = -EINVAL; goto err_scanouts; } + DRM_INFO("number of scanouts: %d\n", num_scanouts); + + virtio_cread(vgdev->vdev, struct virtio_gpu_config, + num_capsets, &num_capsets); + DRM_INFO("number of cap sets: %d\n", num_capsets); ret = virtio_gpu_modeset_init(vgdev); if (ret) @@ -137,6 +213,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) virtio_device_ready(vgdev->vdev); vgdev->vqs_ready = true; + if (num_capsets) + virtio_gpu_get_capsets(vgdev, num_capsets); virtio_gpu_cmd_get_display_info(vgdev); wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending, 5 * HZ); @@ -157,6 +235,16 @@ err_vqs: return ret; } +static void virtio_gpu_cleanup_cap_cache(struct virtio_gpu_device *vgdev) +{ + struct virtio_gpu_drv_cap_cache *cache_ent, *tmp; + + list_for_each_entry_safe(cache_ent, tmp, &vgdev->cap_cache, head) { + kfree(cache_ent->caps_cache); + kfree(cache_ent); + } +} + int virtio_gpu_driver_unload(struct drm_device *dev) { struct virtio_gpu_device *vgdev = dev->dev_private; @@ -170,6 +258,49 @@ int virtio_gpu_driver_unload(struct drm_device *dev) virtio_gpu_modeset_fini(vgdev); virtio_gpu_ttm_fini(vgdev); virtio_gpu_free_vbufs(vgdev); + virtio_gpu_cleanup_cap_cache(vgdev); + kfree(vgdev->capsets); kfree(vgdev); return 0; } + +int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file) +{ + struct virtio_gpu_device *vgdev = dev->dev_private; + struct virtio_gpu_fpriv *vfpriv; + uint32_t id; + char dbgname[64], tmpname[TASK_COMM_LEN]; + + /* can't create contexts without 3d renderer */ + if (!vgdev->has_virgl_3d) + return 0; + + get_task_comm(tmpname, current); + snprintf(dbgname, sizeof(dbgname), "%s", tmpname); + dbgname[63] = 0; + /* allocate a virt GPU context for this opener */ + vfpriv = kzalloc(sizeof(*vfpriv), GFP_KERNEL); + if (!vfpriv) + return -ENOMEM; + + virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname, &id); + + vfpriv->ctx_id = id; + file->driver_priv = vfpriv; + return 0; +} + +void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file) +{ + struct virtio_gpu_device *vgdev = dev->dev_private; + struct virtio_gpu_fpriv *vfpriv; + + if (!vgdev->has_virgl_3d) + return; + + vfpriv = file->driver_priv; + + virtio_gpu_context_destroy(vgdev, vfpriv->ctx_id); + kfree(vfpriv); + file->driver_priv = NULL; +} diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index 2c624c784c1d..f300eba95bb1 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -82,24 +82,19 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, size = roundup(size, PAGE_SIZE); ret = drm_gem_object_init(vgdev->ddev, &bo->gem_base, size); if (ret != 0) - goto err_gem_init; + return ret; bo->dumb = false; virtio_gpu_init_ttm_placement(bo, pinned); ret = ttm_bo_init(&vgdev->mman.bdev, &bo->tbo, size, type, &bo->placement, 0, !kernel, NULL, acc_size, NULL, NULL, &virtio_gpu_ttm_bo_destroy); + /* ttm_bo_init failure will call the destroy */ if (ret != 0) - goto err_ttm_init; + return ret; *bo_ptr = bo; return 0; - -err_ttm_init: - drm_gem_object_release(&bo->gem_base); -err_gem_init: - kfree(bo); - return ret; } int virtio_gpu_object_kmap(struct virtio_gpu_object *bo, void **ptr) diff --git a/drivers/gpu/drm/virtio/virtgpu_prime.c b/drivers/gpu/drm/virtio/virtgpu_prime.c new file mode 100644 index 000000000000..385e0eb9826a --- /dev/null +++ b/drivers/gpu/drm/virtio/virtgpu_prime.c @@ -0,0 +1,71 @@ +/* + * Copyright 2014 Canonical + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Andreas Pokorny + */ + +#include "virtgpu_drv.h" + +/* Empty Implementations as there should not be any other driver for a virtual + * device that might share buffers with virtgpu */ + +int virtgpu_gem_prime_pin(struct drm_gem_object *obj) +{ + WARN_ONCE(1, "not implemented"); + return -ENODEV; +} + +void virtgpu_gem_prime_unpin(struct drm_gem_object *obj) +{ + WARN_ONCE(1, "not implemented"); +} + + +struct sg_table *virtgpu_gem_prime_get_sg_table(struct drm_gem_object *obj) +{ + WARN_ONCE(1, "not implemented"); + return ERR_PTR(-ENODEV); +} + +struct drm_gem_object *virtgpu_gem_prime_import_sg_table( + struct drm_device *dev, struct dma_buf_attachment *attach, + struct sg_table *table) +{ + WARN_ONCE(1, "not implemented"); + return ERR_PTR(-ENODEV); +} + +void *virtgpu_gem_prime_vmap(struct drm_gem_object *obj) +{ + WARN_ONCE(1, "not implemented"); + return ERR_PTR(-ENODEV); +} + +void virtgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) +{ + WARN_ONCE(1, "not implemented"); +} + +int virtgpu_gem_prime_mmap(struct drm_gem_object *obj, + struct vm_area_struct *area) +{ + return -ENODEV; +} diff --git a/drivers/gpu/drm/virtio/virtgpu_ttm.c b/drivers/gpu/drm/virtio/virtgpu_ttm.c index b092d7b9a292..9fd924cd2b7f 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ttm.c +++ b/drivers/gpu/drm/virtio/virtgpu_ttm.c @@ -32,6 +32,7 @@ #include <ttm/ttm_module.h> #include <drm/drmP.h> #include <drm/drm.h> +#include <drm/virtgpu_drm.h> #include "virtgpu_drv.h" #include <linux/delay.h> diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 1698669f4185..5a0f8a745b9d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -293,8 +293,8 @@ void virtio_gpu_dequeue_cursor_func(struct work_struct *work) wake_up(&vgdev->cursorq.ack_queue); } -static int virtio_gpu_queue_ctrl_buffer(struct virtio_gpu_device *vgdev, - struct virtio_gpu_vbuffer *vbuf) +static int virtio_gpu_queue_ctrl_buffer_locked(struct virtio_gpu_device *vgdev, + struct virtio_gpu_vbuffer *vbuf) { struct virtqueue *vq = vgdev->ctrlq.vq; struct scatterlist *sgs[3], vcmd, vout, vresp; @@ -320,7 +320,6 @@ static int virtio_gpu_queue_ctrl_buffer(struct virtio_gpu_device *vgdev, incnt++; } - spin_lock(&vgdev->ctrlq.qlock); retry: ret = virtqueue_add_sgs(vq, sgs, outcnt, incnt, vbuf, GFP_ATOMIC); if (ret == -ENOSPC) { @@ -331,13 +330,55 @@ retry: } else { virtqueue_kick(vq); } - spin_unlock(&vgdev->ctrlq.qlock); if (!ret) ret = vq->num_free; return ret; } +static int virtio_gpu_queue_ctrl_buffer(struct virtio_gpu_device *vgdev, + struct virtio_gpu_vbuffer *vbuf) +{ + int rc; + + spin_lock(&vgdev->ctrlq.qlock); + rc = virtio_gpu_queue_ctrl_buffer_locked(vgdev, vbuf); + spin_unlock(&vgdev->ctrlq.qlock); + return rc; +} + +static int virtio_gpu_queue_fenced_ctrl_buffer(struct virtio_gpu_device *vgdev, + struct virtio_gpu_vbuffer *vbuf, + struct virtio_gpu_ctrl_hdr *hdr, + struct virtio_gpu_fence **fence) +{ + struct virtqueue *vq = vgdev->ctrlq.vq; + int rc; + +again: + spin_lock(&vgdev->ctrlq.qlock); + + /* + * Make sure we have enouth space in the virtqueue. If not + * wait here until we have. + * + * Without that virtio_gpu_queue_ctrl_buffer_nolock might have + * to wait for free space, which can result in fence ids being + * submitted out-of-order. + */ + if (vq->num_free < 3) { + spin_unlock(&vgdev->ctrlq.qlock); + wait_event(vgdev->ctrlq.ack_queue, vq->num_free >= 3); + goto again; + } + + if (fence) + virtio_gpu_fence_emit(vgdev, hdr, fence); + rc = virtio_gpu_queue_ctrl_buffer_locked(vgdev, vbuf); + spin_unlock(&vgdev->ctrlq.qlock); + return rc; +} + static int virtio_gpu_queue_cursor(struct virtio_gpu_device *vgdev, struct virtio_gpu_vbuffer *vbuf) { @@ -490,9 +531,7 @@ void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev, cmd_p->r.x = x; cmd_p->r.y = y; - if (fence) - virtio_gpu_fence_emit(vgdev, &cmd_p->hdr, fence); - virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); + virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence); } static void @@ -515,9 +554,7 @@ virtio_gpu_cmd_resource_attach_backing(struct virtio_gpu_device *vgdev, vbuf->data_buf = ents; vbuf->data_size = sizeof(*ents) * nents; - if (fence) - virtio_gpu_fence_emit(vgdev, &cmd_p->hdr, fence); - virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); + virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence); } static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev, @@ -549,6 +586,47 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev, drm_kms_helper_hotplug_event(vgdev->ddev); } +static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev, + struct virtio_gpu_vbuffer *vbuf) +{ + struct virtio_gpu_get_capset_info *cmd = + (struct virtio_gpu_get_capset_info *)vbuf->buf; + struct virtio_gpu_resp_capset_info *resp = + (struct virtio_gpu_resp_capset_info *)vbuf->resp_buf; + int i = le32_to_cpu(cmd->capset_index); + + spin_lock(&vgdev->display_info_lock); + vgdev->capsets[i].id = le32_to_cpu(resp->capset_id); + vgdev->capsets[i].max_version = le32_to_cpu(resp->capset_max_version); + vgdev->capsets[i].max_size = le32_to_cpu(resp->capset_max_size); + spin_unlock(&vgdev->display_info_lock); + wake_up(&vgdev->resp_wq); +} + +static void virtio_gpu_cmd_capset_cb(struct virtio_gpu_device *vgdev, + struct virtio_gpu_vbuffer *vbuf) +{ + struct virtio_gpu_get_capset *cmd = + (struct virtio_gpu_get_capset *)vbuf->buf; + struct virtio_gpu_resp_capset *resp = + (struct virtio_gpu_resp_capset *)vbuf->resp_buf; + struct virtio_gpu_drv_cap_cache *cache_ent; + + spin_lock(&vgdev->display_info_lock); + list_for_each_entry(cache_ent, &vgdev->cap_cache, head) { + if (cache_ent->version == le32_to_cpu(cmd->capset_version) && + cache_ent->id == le32_to_cpu(cmd->capset_id)) { + memcpy(cache_ent->caps_cache, resp->capset_data, + cache_ent->size); + atomic_set(&cache_ent->is_valid, 1); + break; + } + } + spin_unlock(&vgdev->display_info_lock); + wake_up(&vgdev->resp_wq); +} + + int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev) { struct virtio_gpu_ctrl_hdr *cmd_p; @@ -572,6 +650,230 @@ int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev) return 0; } +int virtio_gpu_cmd_get_capset_info(struct virtio_gpu_device *vgdev, int idx) +{ + struct virtio_gpu_get_capset_info *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + void *resp_buf; + + resp_buf = kzalloc(sizeof(struct virtio_gpu_resp_capset_info), + GFP_KERNEL); + if (!resp_buf) + return -ENOMEM; + + cmd_p = virtio_gpu_alloc_cmd_resp + (vgdev, &virtio_gpu_cmd_get_capset_info_cb, &vbuf, + sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_capset_info), + resp_buf); + memset(cmd_p, 0, sizeof(*cmd_p)); + + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_GET_CAPSET_INFO); + cmd_p->capset_index = cpu_to_le32(idx); + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); + return 0; +} + +int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev, + int idx, int version, + struct virtio_gpu_drv_cap_cache **cache_p) +{ + struct virtio_gpu_get_capset *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + int max_size = vgdev->capsets[idx].max_size; + struct virtio_gpu_drv_cap_cache *cache_ent; + void *resp_buf; + + if (idx > vgdev->num_capsets) + return -EINVAL; + + if (version > vgdev->capsets[idx].max_version) + return -EINVAL; + + cache_ent = kzalloc(sizeof(*cache_ent), GFP_KERNEL); + if (!cache_ent) + return -ENOMEM; + + cache_ent->caps_cache = kmalloc(max_size, GFP_KERNEL); + if (!cache_ent->caps_cache) { + kfree(cache_ent); + return -ENOMEM; + } + + resp_buf = kzalloc(sizeof(struct virtio_gpu_resp_capset) + max_size, + GFP_KERNEL); + if (!resp_buf) { + kfree(cache_ent->caps_cache); + kfree(cache_ent); + return -ENOMEM; + } + + cache_ent->version = version; + cache_ent->id = vgdev->capsets[idx].id; + atomic_set(&cache_ent->is_valid, 0); + cache_ent->size = max_size; + spin_lock(&vgdev->display_info_lock); + list_add_tail(&cache_ent->head, &vgdev->cap_cache); + spin_unlock(&vgdev->display_info_lock); + + cmd_p = virtio_gpu_alloc_cmd_resp + (vgdev, &virtio_gpu_cmd_capset_cb, &vbuf, sizeof(*cmd_p), + sizeof(struct virtio_gpu_resp_capset) + max_size, + resp_buf); + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_GET_CAPSET); + cmd_p->capset_id = cpu_to_le32(vgdev->capsets[idx].id); + cmd_p->capset_version = cpu_to_le32(version); + *cache_p = cache_ent; + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); + + return 0; +} + +void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id, + uint32_t nlen, const char *name) +{ + struct virtio_gpu_ctx_create *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + + 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_CTX_CREATE); + cmd_p->hdr.ctx_id = cpu_to_le32(id); + cmd_p->nlen = cpu_to_le32(nlen); + strncpy(cmd_p->debug_name, name, sizeof(cmd_p->debug_name)-1); + cmd_p->debug_name[sizeof(cmd_p->debug_name)-1] = 0; + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); +} + +void virtio_gpu_cmd_context_destroy(struct virtio_gpu_device *vgdev, + uint32_t id) +{ + struct virtio_gpu_ctx_destroy *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + + 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_CTX_DESTROY); + cmd_p->hdr.ctx_id = cpu_to_le32(id); + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); +} + +void virtio_gpu_cmd_context_attach_resource(struct virtio_gpu_device *vgdev, + uint32_t ctx_id, + uint32_t resource_id) +{ + struct virtio_gpu_ctx_resource *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + + 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_CTX_ATTACH_RESOURCE); + cmd_p->hdr.ctx_id = cpu_to_le32(ctx_id); + cmd_p->resource_id = cpu_to_le32(resource_id); + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); + +} + +void virtio_gpu_cmd_context_detach_resource(struct virtio_gpu_device *vgdev, + uint32_t ctx_id, + uint32_t resource_id) +{ + struct virtio_gpu_ctx_resource *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + + 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_CTX_DETACH_RESOURCE); + cmd_p->hdr.ctx_id = cpu_to_le32(ctx_id); + cmd_p->resource_id = cpu_to_le32(resource_id); + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); +} + +void +virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, + struct virtio_gpu_resource_create_3d *rc_3d, + struct virtio_gpu_fence **fence) +{ + struct virtio_gpu_resource_create_3d *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + + cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p)); + memset(cmd_p, 0, sizeof(*cmd_p)); + + *cmd_p = *rc_3d; + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_3D); + cmd_p->hdr.flags = 0; + + virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence); +} + +void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev, + uint32_t resource_id, uint32_t ctx_id, + uint64_t offset, uint32_t level, + struct virtio_gpu_box *box, + struct virtio_gpu_fence **fence) +{ + struct virtio_gpu_transfer_host_3d *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + + 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_TRANSFER_TO_HOST_3D); + cmd_p->hdr.ctx_id = cpu_to_le32(ctx_id); + cmd_p->resource_id = cpu_to_le32(resource_id); + cmd_p->box = *box; + cmd_p->offset = cpu_to_le64(offset); + cmd_p->level = cpu_to_le32(level); + + virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence); +} + +void virtio_gpu_cmd_transfer_from_host_3d(struct virtio_gpu_device *vgdev, + uint32_t resource_id, uint32_t ctx_id, + uint64_t offset, uint32_t level, + struct virtio_gpu_box *box, + struct virtio_gpu_fence **fence) +{ + struct virtio_gpu_transfer_host_3d *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + + 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_TRANSFER_FROM_HOST_3D); + cmd_p->hdr.ctx_id = cpu_to_le32(ctx_id); + cmd_p->resource_id = cpu_to_le32(resource_id); + cmd_p->box = *box; + cmd_p->offset = cpu_to_le64(offset); + cmd_p->level = cpu_to_le32(level); + + virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence); +} + +void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev, + void *data, uint32_t data_size, + uint32_t ctx_id, struct virtio_gpu_fence **fence) +{ + struct virtio_gpu_cmd_submit *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + + cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p)); + memset(cmd_p, 0, sizeof(*cmd_p)); + + vbuf->data_buf = data; + vbuf->data_size = data_size; + + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_SUBMIT_3D); + cmd_p->hdr.ctx_id = cpu_to_le32(ctx_id); + cmd_p->size = cpu_to_le32(data_size); + + virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence); +} + int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *obj, uint32_t resource_id, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index 5ae8f921da2a..8a76821177a6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -681,6 +681,14 @@ static bool vmw_cmdbuf_try_alloc(struct vmw_cmdbuf_man *man, 0, 0, DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT); + if (ret) { + (void) vmw_cmdbuf_man_process(man); + ret = drm_mm_insert_node_generic(&man->mm, info->node, + info->page_size, 0, 0, + DRM_MM_SEARCH_DEFAULT, + DRM_MM_CREATE_DEFAULT); + } + spin_unlock_bh(&man->lock); info->done = !ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 2c7a25c71af2..b7525f78ac51 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -146,73 +146,73 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(VMW_GET_PARAM, vmw_getparam_ioctl, - DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl, - DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl, - DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CURSOR_BYPASS, vmw_kms_cursor_bypass_ioctl, - DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), + DRM_MASTER | DRM_CONTROL_ALLOW), VMW_IOCTL_DEF(VMW_CONTROL_STREAM, vmw_overlay_ioctl, - DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), + DRM_MASTER | DRM_CONTROL_ALLOW), VMW_IOCTL_DEF(VMW_CLAIM_STREAM, vmw_stream_claim_ioctl, - DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), + DRM_MASTER | DRM_CONTROL_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_STREAM, vmw_stream_unref_ioctl, - DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), + DRM_MASTER | DRM_CONTROL_ALLOW), VMW_IOCTL_DEF(VMW_CREATE_CONTEXT, vmw_context_define_ioctl, - DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, - DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CREATE_SURFACE, vmw_surface_define_ioctl, - DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, - DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_REF_SURFACE, vmw_surface_reference_ioctl, - DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_EXECBUF, NULL, DRM_AUTH | DRM_UNLOCKED | + DRM_AUTH | DRM_RENDER_ALLOW), + VMW_IOCTL_DEF(VMW_EXECBUF, NULL, DRM_AUTH | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl, - DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_FENCE_SIGNALED, vmw_fence_obj_signaled_ioctl, - DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_FENCE_UNREF, vmw_fence_obj_unref_ioctl, - DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_FENCE_EVENT, vmw_fence_event_ioctl, - DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, - DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), /* these allow direct access to the framebuffers mark as master only */ VMW_IOCTL_DEF(VMW_PRESENT, vmw_present_ioctl, - DRM_MASTER | DRM_AUTH | DRM_UNLOCKED), + DRM_MASTER | DRM_AUTH), VMW_IOCTL_DEF(VMW_PRESENT_READBACK, vmw_present_readback_ioctl, - DRM_MASTER | DRM_AUTH | DRM_UNLOCKED), + DRM_MASTER | DRM_AUTH), VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT, vmw_kms_update_layout_ioctl, - DRM_MASTER | DRM_UNLOCKED), + DRM_MASTER), VMW_IOCTL_DEF(VMW_CREATE_SHADER, vmw_shader_define_ioctl, - DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_SHADER, vmw_shader_destroy_ioctl, - DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE, vmw_gb_surface_define_ioctl, - DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_GB_SURFACE_REF, vmw_gb_surface_reference_ioctl, - DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_SYNCCPU, vmw_user_dmabuf_synccpu_ioctl, - DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT, vmw_extended_context_define_ioctl, - DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_AUTH | DRM_RENDER_ALLOW), }; static struct pci_device_id vmw_pci_id_list[] = { @@ -1062,14 +1062,6 @@ static struct vmw_master *vmw_master_check(struct drm_device *dev, mutex_unlock(&dev->master_mutex); /* - * Taking the drm_global_mutex after the TTM lock might deadlock - */ - if (!(flags & DRM_UNLOCKED)) { - DRM_ERROR("Refusing locked ioctl access.\n"); - return ERR_PTR(-EDEADLK); - } - - /* * Take the TTM lock. Possibly sleep waiting for the authenticating * master to become master again, or for a SIGTERM if the * authenticating master exits. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index f19fd39b43e1..a613bd4851ba 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -914,9 +914,9 @@ void vmw_kms_idle_workqueues(struct vmw_master *vmaster); bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv, uint32_t pitch, uint32_t height); -u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc); -int vmw_enable_vblank(struct drm_device *dev, int crtc); -void vmw_disable_vblank(struct drm_device *dev, int crtc); +u32 vmw_get_vblank_counter(struct drm_device *dev, unsigned int pipe); +int vmw_enable_vblank(struct drm_device *dev, unsigned int pipe); +void vmw_disable_vblank(struct drm_device *dev, unsigned int pipe); int vmw_kms_present(struct vmw_private *dev_priv, struct drm_file *file_priv, struct vmw_framebuffer *vfb, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 15a6c01cd016..03ffab2a6a9c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1263,7 +1263,7 @@ bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv, /** * Function called by DRM code called with vbl_lock held. */ -u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc) +u32 vmw_get_vblank_counter(struct drm_device *dev, unsigned int pipe) { return 0; } @@ -1271,7 +1271,7 @@ u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc) /** * Function called by DRM code called with vbl_lock held. */ -int vmw_enable_vblank(struct drm_device *dev, int crtc) +int vmw_enable_vblank(struct drm_device *dev, unsigned int pipe) { return -ENOSYS; } @@ -1279,7 +1279,7 @@ int vmw_enable_vblank(struct drm_device *dev, int crtc) /** * Function called by DRM code called with vbl_lock held. */ -void vmw_disable_vblank(struct drm_device *dev, int crtc) +void vmw_disable_vblank(struct drm_device *dev, unsigned int pipe) { } diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c index 9ef2e1f54ca4..d3ad5347342c 100644 --- a/drivers/gpu/ipu-v3/ipu-dc.c +++ b/drivers/gpu/ipu-v3/ipu-dc.c @@ -183,12 +183,19 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, } if (interlaced) { - dc_link_event(dc, DC_EVT_NL, 0, 3); - dc_link_event(dc, DC_EVT_EOL, 0, 2); - dc_link_event(dc, DC_EVT_NEW_DATA, 0, 1); + int addr; + + if (dc->di) + addr = 1; + else + addr = 0; + + dc_link_event(dc, DC_EVT_NL, addr, 3); + dc_link_event(dc, DC_EVT_EOL, addr, 2); + dc_link_event(dc, DC_EVT_NEW_DATA, addr, 1); /* Init template microcode */ - dc_write_tmpl(dc, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8, 1); + dc_write_tmpl(dc, addr, WROD(0), 0, map, SYNC_WAVE, 0, 6, 1); } else { if (dc->di) { dc_link_event(dc, DC_EVT_NL, 2, 3); diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c index 2970c6bb668c..359268e3a166 100644 --- a/drivers/gpu/ipu-v3/ipu-di.c +++ b/drivers/gpu/ipu-v3/ipu-di.c @@ -71,6 +71,10 @@ enum di_sync_wave { DI_SYNC_HSYNC = 3, DI_SYNC_VSYNC = 4, DI_SYNC_DE = 6, + + DI_SYNC_CNT1 = 2, /* counter >= 2 only */ + DI_SYNC_CNT4 = 5, /* counter >= 5 only */ + DI_SYNC_CNT5 = 6, /* counter >= 6 only */ }; #define SYNC_WAVE 0 @@ -211,66 +215,59 @@ static void ipu_di_sync_config_interlaced(struct ipu_di *di, sig->mode.hback_porch + sig->mode.hfront_porch; u32 v_total = sig->mode.vactive + sig->mode.vsync_len + sig->mode.vback_porch + sig->mode.vfront_porch; - u32 reg; struct di_sync_config cfg[] = { { - .run_count = h_total / 2 - 1, - .run_src = DI_SYNC_CLK, + /* 1: internal VSYNC for each frame */ + .run_count = v_total * 2 - 1, + .run_src = 3, /* == counter 7 */ }, { - .run_count = h_total - 11, + /* PIN2: HSYNC waveform */ + .run_count = h_total - 1, .run_src = DI_SYNC_CLK, - .cnt_down = 4, + .cnt_polarity_gen_en = 1, + .cnt_polarity_trigger_src = DI_SYNC_CLK, + .cnt_down = sig->mode.hsync_len * 2, }, { - .run_count = v_total * 2 - 1, - .run_src = DI_SYNC_INT_HSYNC, - .offset_count = 1, - .offset_src = DI_SYNC_INT_HSYNC, - .cnt_down = 4, + /* PIN3: VSYNC waveform */ + .run_count = v_total - 1, + .run_src = 4, /* == counter 7 */ + .cnt_polarity_gen_en = 1, + .cnt_polarity_trigger_src = 4, /* == counter 7 */ + .cnt_down = sig->mode.vsync_len * 2, + .cnt_clr_src = DI_SYNC_CNT1, }, { - .run_count = v_total / 2 - 1, + /* 4: Field */ + .run_count = v_total / 2, .run_src = DI_SYNC_HSYNC, - .offset_count = sig->mode.vback_porch, - .offset_src = DI_SYNC_HSYNC, + .offset_count = h_total / 2, + .offset_src = DI_SYNC_CLK, .repeat_count = 2, - .cnt_clr_src = DI_SYNC_VSYNC, - }, { - .run_src = DI_SYNC_HSYNC, - .repeat_count = sig->mode.vactive / 2, - .cnt_clr_src = 4, - }, { - .run_count = v_total - 1, - .run_src = DI_SYNC_HSYNC, + .cnt_clr_src = DI_SYNC_CNT1, }, { - .run_count = v_total / 2 - 1, + /* 5: Active lines */ .run_src = DI_SYNC_HSYNC, - .offset_count = 9, + .offset_count = (sig->mode.vsync_len + + sig->mode.vback_porch) / 2, .offset_src = DI_SYNC_HSYNC, - .repeat_count = 2, - .cnt_clr_src = DI_SYNC_VSYNC, + .repeat_count = sig->mode.vactive / 2, + .cnt_clr_src = DI_SYNC_CNT4, }, { + /* 6: Active pixel, referenced by DC */ .run_src = DI_SYNC_CLK, - .offset_count = sig->mode.hback_porch, + .offset_count = sig->mode.hsync_len + + sig->mode.hback_porch, .offset_src = DI_SYNC_CLK, .repeat_count = sig->mode.hactive, - .cnt_clr_src = 5, + .cnt_clr_src = DI_SYNC_CNT5, }, { - .run_count = v_total - 1, - .run_src = DI_SYNC_INT_HSYNC, - .offset_count = v_total / 2, - .offset_src = DI_SYNC_INT_HSYNC, - .cnt_clr_src = DI_SYNC_HSYNC, - .cnt_down = 4, + /* 7: Half line HSYNC */ + .run_count = h_total / 2 - 1, + .run_src = DI_SYNC_CLK, } }; ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg)); - /* set gentime select and tag sel */ - reg = ipu_di_read(di, DI_SW_GEN1(9)); - reg &= 0x1FFFFFFF; - reg |= (3 - 1) << 29 | 0x00008000; - ipu_di_write(di, reg, DI_SW_GEN1(9)); - ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF); } @@ -543,6 +540,29 @@ int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode) } EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode); +static u32 ipu_di_gen_polarity(int pin) +{ + switch (pin) { + case 1: + return DI_GEN_POLARITY_1; + case 2: + return DI_GEN_POLARITY_2; + case 3: + return DI_GEN_POLARITY_3; + case 4: + return DI_GEN_POLARITY_4; + case 5: + return DI_GEN_POLARITY_5; + case 6: + return DI_GEN_POLARITY_6; + case 7: + return DI_GEN_POLARITY_7; + case 8: + return DI_GEN_POLARITY_8; + } + return 0; +} + int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) { u32 reg; @@ -582,15 +602,8 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) /* set y_sel = 1 */ di_gen |= 0x10000000; - di_gen |= DI_GEN_POLARITY_5; - di_gen |= DI_GEN_POLARITY_8; - - vsync_cnt = 7; - if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH) - di_gen |= DI_GEN_POLARITY_3; - if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH) - di_gen |= DI_GEN_POLARITY_2; + vsync_cnt = 3; } else { ipu_di_sync_config_noninterlaced(di, sig, div); @@ -602,25 +615,13 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) */ if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3)) vsync_cnt = 6; - - if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH) { - if (sig->hsync_pin == 2) - di_gen |= DI_GEN_POLARITY_2; - else if (sig->hsync_pin == 4) - di_gen |= DI_GEN_POLARITY_4; - else if (sig->hsync_pin == 7) - di_gen |= DI_GEN_POLARITY_7; - } - if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH) { - if (sig->vsync_pin == 3) - di_gen |= DI_GEN_POLARITY_3; - else if (sig->vsync_pin == 6) - di_gen |= DI_GEN_POLARITY_6; - else if (sig->vsync_pin == 8) - di_gen |= DI_GEN_POLARITY_8; - } } + if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH) + di_gen |= ipu_di_gen_polarity(sig->hsync_pin); + if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH) + di_gen |= ipu_di_gen_polarity(sig->vsync_pin); + if (sig->clk_pol) di_gen |= DI_GEN_POLARITY_DISP_CLK; diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index 86c03b53e7bf..af0d372ff7d4 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -84,9 +84,9 @@ * @fb_info: framebuffer to which console is remapped on switching * @pwr_state: current power state * @ops: client callbacks - * @id: client identifier, see enum vga_switcheroo_client_id. - * Determining the id requires the handler, so GPUs are initially - * assigned -1 and later given their true id in vga_switcheroo_enable() + * @id: client identifier. Determining the id requires the handler, + * so gpus are initially assigned VGA_SWITCHEROO_UNKNOWN_ID + * and later given their true id in vga_switcheroo_enable() * @active: whether the outputs are currently switched to this client * @driver_power_control: whether power state is controlled by the driver's * runtime pm. If true, writing ON and OFF to the vga_switcheroo debugfs @@ -100,9 +100,9 @@ struct vga_switcheroo_client { struct pci_dev *pdev; struct fb_info *fb_info; - int pwr_state; + enum vga_switcheroo_state pwr_state; const struct vga_switcheroo_client_ops *ops; - int id; + enum vga_switcheroo_client_id id; bool active; bool driver_power_control; struct list_head list; @@ -145,7 +145,8 @@ struct vgasr_priv { #define ID_BIT_AUDIO 0x100 #define client_is_audio(c) ((c)->id & ID_BIT_AUDIO) -#define client_is_vga(c) ((c)->id == -1 || !client_is_audio(c)) +#define client_is_vga(c) ((c)->id == VGA_SWITCHEROO_UNKNOWN_ID || \ + !client_is_audio(c)) #define client_id(c) ((c)->id & ~ID_BIT_AUDIO) static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv); @@ -173,7 +174,7 @@ static void vga_switcheroo_enable(void) vgasr_priv.handler->init(); list_for_each_entry(client, &vgasr_priv.clients, list) { - if (client->id != -1) + if (client->id != VGA_SWITCHEROO_UNKNOWN_ID) continue; ret = vgasr_priv.handler->get_client_id(client->pdev); if (ret < 0) @@ -232,7 +233,8 @@ EXPORT_SYMBOL(vga_switcheroo_unregister_handler); static int register_client(struct pci_dev *pdev, const struct vga_switcheroo_client_ops *ops, - int id, bool active, bool driver_power_control) + enum vga_switcheroo_client_id id, bool active, + bool driver_power_control) { struct vga_switcheroo_client *client; @@ -277,7 +279,7 @@ int vga_switcheroo_register_client(struct pci_dev *pdev, const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { - return register_client(pdev, ops, -1, + return register_client(pdev, ops, VGA_SWITCHEROO_UNKNOWN_ID, pdev == vga_default_device(), driver_power_control); } @@ -287,7 +289,7 @@ EXPORT_SYMBOL(vga_switcheroo_register_client); * vga_switcheroo_register_audio_client - register audio client * @pdev: client pci device * @ops: client callbacks - * @id: client identifier, see enum vga_switcheroo_client_id + * @id: client identifier * * Register audio client (audio device on a GPU). The power state of the * client is assumed to be ON. @@ -296,7 +298,7 @@ EXPORT_SYMBOL(vga_switcheroo_register_client); */ int vga_switcheroo_register_audio_client(struct pci_dev *pdev, const struct vga_switcheroo_client_ops *ops, - int id) + enum vga_switcheroo_client_id id) { return register_client(pdev, ops, id | ID_BIT_AUDIO, false, false); } @@ -314,7 +316,8 @@ find_client_from_pci(struct list_head *head, struct pci_dev *pdev) } static struct vga_switcheroo_client * -find_client_from_id(struct list_head *head, int client_id) +find_client_from_id(struct list_head *head, + enum vga_switcheroo_client_id client_id) { struct vga_switcheroo_client *client; @@ -344,16 +347,21 @@ find_active_client(struct list_head *head) * * Return: Power state. */ -int vga_switcheroo_get_client_state(struct pci_dev *pdev) +enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *pdev) { struct vga_switcheroo_client *client; + enum vga_switcheroo_state ret; + mutex_lock(&vgasr_mutex); client = find_client_from_pci(&vgasr_priv.clients, pdev); if (!client) - return VGA_SWITCHEROO_NOT_FOUND; - if (!vgasr_priv.active) - return VGA_SWITCHEROO_INIT; - return client->pwr_state; + ret = VGA_SWITCHEROO_NOT_FOUND; + else if (!vgasr_priv.active) + ret = VGA_SWITCHEROO_INIT; + else + ret = client->pwr_state; + mutex_unlock(&vgasr_mutex); + return ret; } EXPORT_SYMBOL(vga_switcheroo_get_client_state); @@ -491,7 +499,8 @@ static int vga_switchoff(struct vga_switcheroo_client *client) return 0; } -static void set_audio_state(int id, int state) +static void set_audio_state(enum vga_switcheroo_client_id id, + enum vga_switcheroo_state state) { struct vga_switcheroo_client *client; @@ -578,7 +587,7 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, int ret; bool delay = false, can_switch; bool just_mux = false; - int client_id = -1; + enum vga_switcheroo_client_id client_id = VGA_SWITCHEROO_UNKNOWN_ID; struct vga_switcheroo_client *client = NULL; if (cnt > 63) @@ -647,7 +656,7 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, client_id = VGA_SWITCHEROO_DIS; } - if (client_id == -1) + if (client_id == VGA_SWITCHEROO_UNKNOWN_ID) goto out; client = find_client_from_id(&vgasr_priv.clients, client_id); if (!client) @@ -845,15 +854,16 @@ void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, { struct vga_switcheroo_client *client; + mutex_lock(&vgasr_mutex); client = find_client_from_pci(&vgasr_priv.clients, pdev); - if (!client) - return; - - if (!client->driver_power_control) + if (!client || !client->driver_power_control) { + mutex_unlock(&vgasr_mutex); return; + } client->pwr_state = dynamic; set_audio_state(client->id, dynamic); + mutex_unlock(&vgasr_mutex); } EXPORT_SYMBOL(vga_switcheroo_set_dynamic_switch); @@ -866,9 +876,11 @@ static int vga_switcheroo_runtime_suspend(struct device *dev) ret = dev->bus->pm->runtime_suspend(dev); if (ret) return ret; + mutex_lock(&vgasr_mutex); if (vgasr_priv.handler->switchto) vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD); vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF); + mutex_unlock(&vgasr_mutex); return 0; } @@ -877,7 +889,9 @@ static int vga_switcheroo_runtime_resume(struct device *dev) struct pci_dev *pdev = to_pci_dev(dev); int ret; + mutex_lock(&vgasr_mutex); vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON); + mutex_unlock(&vgasr_mutex); ret = dev->bus->pm->runtime_resume(dev); if (ret) return ret; @@ -923,29 +937,33 @@ EXPORT_SYMBOL(vga_switcheroo_fini_domain_pm_ops); static int vga_switcheroo_runtime_resume_hdmi_audio(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); + struct vga_switcheroo_client *client; + struct device *video_dev = NULL; int ret; - struct vga_switcheroo_client *client, *found = NULL; /* we need to check if we have to switch back on the video device so the audio device can come back */ + mutex_lock(&vgasr_mutex); list_for_each_entry(client, &vgasr_priv.clients, list) { if (PCI_SLOT(client->pdev->devfn) == PCI_SLOT(pdev->devfn) && client_is_vga(client)) { - found = client; - ret = pm_runtime_get_sync(&client->pdev->dev); - if (ret) { - if (ret != 1) - return ret; - } + video_dev = &client->pdev->dev; break; } } + mutex_unlock(&vgasr_mutex); + + if (video_dev) { + ret = pm_runtime_get_sync(video_dev); + if (ret && ret != 1) + return ret; + } ret = dev->bus->pm->runtime_resume(dev); /* put the reference for the gpu */ - if (found) { - pm_runtime_mark_last_busy(&found->pdev->dev); - pm_runtime_put_autosuspend(&found->pdev->dev); + if (video_dev) { + pm_runtime_mark_last_busy(video_dev); + pm_runtime_put_autosuspend(video_dev); } return ret; } diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index a0b433456107..3166e4bc4eb6 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -531,7 +531,7 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev) return false; /* Allocate structure */ - vgadev = kmalloc(sizeof(struct vga_device), GFP_KERNEL); + vgadev = kzalloc(sizeof(struct vga_device), GFP_KERNEL); if (vgadev == NULL) { pr_err("failed to allocate pci device\n"); /* @@ -541,8 +541,6 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev) return false; } - memset(vgadev, 0, sizeof(*vgadev)); - /* Take lock & check for duplicates */ spin_lock_irqsave(&vga_lock, flags); if (vgadev_find(pdev) != NULL) { |