]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
Merge tag 'drm-intel-next-2015-03-27-merge' of git://anongit.freedesktop.org/drm...
authorDave Airlie <airlied@redhat.com>
Tue, 31 Mar 2015 22:21:46 +0000 (08:21 +1000)
committerDave Airlie <airlied@redhat.com>
Tue, 31 Mar 2015 22:21:46 +0000 (08:21 +1000)
This backmerges 4.0-rc6 due to the recent fixes in rc5/6

- DP link rate refactoring from Ville
- byt/bsw rps tuning from Chris
- kerneldoc for the shrinker code
- more dynamic ppgtt pte work (Michel, Ben, ...)
- vlv dpll code refactoring to prep fro bxt (Imre)
- refactoring the sprite colorkey code (Ville)
- rotated ggtt view support from Tvrtko
- roll out struct drm_atomic_state to prep for atomic update (Ander)

* tag 'drm-intel-next-2015-03-27-merge' of git://anongit.freedesktop.org/drm-intel: (473 commits)
  Linux 4.0-rc6
  arm64: juno: Fix misleading name of UART reference clock
  drm/i915: Update DRIVER_DATE to 20150327
  drm/i915: Skip allocating shadow batch for 0-length batches
  drm/i915: Handle error to get connector state when staging config
  drm/i915: Compare GGTT view structs instead of types
  drm/i915: fix simple_return.cocci warnings
  drm/i915: Add module param to test the load detect code
  drm/i915: Remove usage of encoder->new_crtc from clock computations
  drm/i915: Don't look at staged config crtc when changing DRRS state
  drm/i915: Convert intel_pipe_will_have_type() to using atomic state
  drm/i915: Pass an atomic state to modeset_global_resources() functions
  drm/i915: Add dynamic page trace events
  drm/i915: Finish gen6/7 dynamic page table allocation
  drm/i915: Remove unnecessary gen6_ppgtt_unmap_pages
  drm/i915: Fix i915_dma_map_single positive error code
  drm/i915: Prevent out of range pt in gen6_for_each_pde
  drm/i915: fix definition of the DRM_IOCTL_I915_GET_SPRITE_COLORKEY ioctl
  drm/i915: Rip out GET_SPRITE_COLORKEY ioctl
  watchdog: imgpdc: Fix default heartbeat
  ...

89 files changed:
MAINTAINERS
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
drivers/gpu/drm/amd/amdkfd/kfd_device.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
drivers/gpu/drm/amd/amdkfd/kfd_module.c
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/amdkfd/kfd_process.c
drivers/gpu/drm/amd/amdkfd/kfd_topology.c
drivers/gpu/drm/amd/include/kgd_kfd_interface.h
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_bridge.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_fb_cma_helper.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_ioc32.c
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/drm_plane_helper.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/i2c/adv7511.c
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/btc_dpm.c
drivers/gpu/drm/radeon/ci_dpm.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/kv_dpm.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/ni_dpm.c
drivers/gpu/drm/radeon/ni_reg.h
drivers/gpu/drm/radeon/nid.h
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_audio.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_dp_auxch.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_dp_mst.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kfd.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/rs780_dpm.c
drivers/gpu/drm/radeon/rv6xx_dpm.c
drivers/gpu/drm/radeon/rv770_dpm.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/radeon/sumo_dpm.c
drivers/gpu/drm/radeon/trinity_dpm.c
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
drivers/gpu/drm/rcar-du/rcar_du_drv.c
drivers/gpu/drm/rcar-du/rcar_du_plane.c
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.h
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/sti/sti_drm_crtc.c
drivers/gpu/drm/sti/sti_drm_drv.c
drivers/gpu/drm/sti/sti_drm_drv.h
drivers/gpu/drm/sti/sti_drm_plane.c
drivers/gpu/drm/sti/sti_dvo.c
drivers/gpu/drm/sti/sti_hda.c
drivers/gpu/drm/sti/sti_hdmi.c
include/drm/drm_crtc.h
include/drm/drm_dp_helper.h
include/drm/drm_dp_mst_helper.h
include/drm/drm_fb_helper.h
include/uapi/drm/radeon_drm.h

index 1de6afa8ee51c747b592e6a10fce1cf742d2bc96..36cf1007037c0464d73d83a7357d2c55638e0aff 100644 (file)
@@ -3397,7 +3397,6 @@ T:        git git://people.freedesktop.org/~airlied/linux
 S:     Supported
 F:     drivers/gpu/drm/rcar-du/
 F:     drivers/gpu/drm/shmobile/
-F:     include/linux/platform_data/rcar-du.h
 F:     include/linux/platform_data/shmob_drm.h
 
 DSBR100 USB FM RADIO DRIVER
index 5c50aa8a8908379980b299ad12fd3868c23fb70c..19a4fba46e4e26ea4e31044b597e0f50f45fb9fd 100644 (file)
@@ -435,21 +435,22 @@ static int kfd_ioctl_get_clock_counters(struct file *filep,
 {
        struct kfd_ioctl_get_clock_counters_args *args = data;
        struct kfd_dev *dev;
-       struct timespec time;
+       struct timespec64 time;
 
        dev = kfd_device_by_id(args->gpu_id);
        if (dev == NULL)
                return -EINVAL;
 
        /* Reading GPU clock counter from KGD */
-       args->gpu_clock_counter = kfd2kgd->get_gpu_clock_counter(dev->kgd);
+       args->gpu_clock_counter =
+               dev->kfd2kgd->get_gpu_clock_counter(dev->kgd);
 
        /* No access to rdtsc. Using raw monotonic time */
-       getrawmonotonic(&time);
-       args->cpu_clock_counter = (uint64_t)timespec_to_ns(&time);
+       getrawmonotonic64(&time);
+       args->cpu_clock_counter = (uint64_t)timespec64_to_ns(&time);
 
-       get_monotonic_boottime(&time);
-       args->system_clock_counter = (uint64_t)timespec_to_ns(&time);
+       get_monotonic_boottime64(&time);
+       args->system_clock_counter = (uint64_t)timespec64_to_ns(&time);
 
        /* Since the counter is in nano-seconds we use 1GHz frequency */
        args->system_clock_freq = 1000000000;
index 5bc32c26b9890eb1f1bf2cf70b1d7e7822bf64fc..ca7f2d3af2ff048301864158b4df492b5e43eb1e 100644 (file)
@@ -94,7 +94,8 @@ static const struct kfd_device_info *lookup_device_info(unsigned short did)
        return NULL;
 }
 
-struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev)
+struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd,
+       struct pci_dev *pdev, const struct kfd2kgd_calls *f2g)
 {
        struct kfd_dev *kfd;
 
@@ -112,6 +113,11 @@ struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev)
        kfd->device_info = device_info;
        kfd->pdev = pdev;
        kfd->init_complete = false;
+       kfd->kfd2kgd = f2g;
+
+       mutex_init(&kfd->doorbell_mutex);
+       memset(&kfd->doorbell_available_index, 0,
+               sizeof(kfd->doorbell_available_index));
 
        return kfd;
 }
@@ -200,8 +206,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
        /* add another 512KB for all other allocations on gart (HPD, fences) */
        size += 512 * 1024;
 
-       if (kfd2kgd->init_gtt_mem_allocation(kfd->kgd, size, &kfd->gtt_mem,
-                       &kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr)) {
+       if (kfd->kfd2kgd->init_gtt_mem_allocation(
+                       kfd->kgd, size, &kfd->gtt_mem,
+                       &kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr)){
                dev_err(kfd_device,
                        "Could not allocate %d bytes for device (%x:%x)\n",
                        size, kfd->pdev->vendor, kfd->pdev->device);
@@ -270,7 +277,7 @@ device_iommu_pasid_error:
 kfd_topology_add_device_error:
        kfd_gtt_sa_fini(kfd);
 kfd_gtt_sa_init_error:
-       kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
+       kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
        dev_err(kfd_device,
                "device (%x:%x) NOT added due to errors\n",
                kfd->pdev->vendor, kfd->pdev->device);
@@ -285,7 +292,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
                amd_iommu_free_device(kfd->pdev);
                kfd_topology_remove_device(kfd);
                kfd_gtt_sa_fini(kfd);
-               kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
+               kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
        }
 
        kfree(kfd);
index d8135adb2238012460cfb67165d0f322f809230a..69af73f153103075f00c9344f836bd7eb3b24668 100644 (file)
@@ -82,7 +82,8 @@ static inline unsigned int get_pipes_num_cpsch(void)
 void program_sh_mem_settings(struct device_queue_manager *dqm,
                                        struct qcm_process_device *qpd)
 {
-       return kfd2kgd->program_sh_mem_settings(dqm->dev->kgd, qpd->vmid,
+       return dqm->dev->kfd2kgd->program_sh_mem_settings(
+                                               dqm->dev->kgd, qpd->vmid,
                                                qpd->sh_mem_config,
                                                qpd->sh_mem_ape1_base,
                                                qpd->sh_mem_ape1_limit,
@@ -457,9 +458,12 @@ set_pasid_vmid_mapping(struct device_queue_manager *dqm, unsigned int pasid,
 {
        uint32_t pasid_mapping;
 
-       pasid_mapping = (pasid == 0) ? 0 : (uint32_t)pasid |
-                                               ATC_VMID_PASID_MAPPING_VALID;
-       return kfd2kgd->set_pasid_vmid_mapping(dqm->dev->kgd, pasid_mapping,
+       pasid_mapping = (pasid == 0) ? 0 :
+               (uint32_t)pasid |
+               ATC_VMID_PASID_MAPPING_VALID;
+
+       return dqm->dev->kfd2kgd->set_pasid_vmid_mapping(
+                                               dqm->dev->kgd, pasid_mapping,
                                                vmid);
 }
 
@@ -511,7 +515,7 @@ int init_pipelines(struct device_queue_manager *dqm,
                pipe_hpd_addr = dqm->pipelines_addr + i * CIK_HPD_EOP_BYTES;
                pr_debug("kfd: pipeline address %llX\n", pipe_hpd_addr);
                /* = log2(bytes/4)-1 */
-               kfd2kgd->init_pipeline(dqm->dev->kgd, inx,
+               dqm->dev->kfd2kgd->init_pipeline(dqm->dev->kgd, inx,
                                CIK_HPD_EOP_BYTES_LOG2 - 3, pipe_hpd_addr);
        }
 
@@ -905,7 +909,7 @@ out:
        return retval;
 }
 
-static int fence_wait_timeout(unsigned int *fence_addr,
+static int amdkfd_fence_wait_timeout(unsigned int *fence_addr,
                                unsigned int fence_value,
                                unsigned long timeout)
 {
@@ -961,7 +965,7 @@ static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock)
        pm_send_query_status(&dqm->packets, dqm->fence_gpu_addr,
                                KFD_FENCE_COMPLETED);
        /* should be timed out */
-       fence_wait_timeout(dqm->fence_addr, KFD_FENCE_COMPLETED,
+       amdkfd_fence_wait_timeout(dqm->fence_addr, KFD_FENCE_COMPLETED,
                                QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS);
        pm_release_ib(&dqm->packets);
        dqm->active_runlist = false;
index 1a9b355dd114595f8bcf156907e486ebe2bbbdb4..17e56dcc8540ff8bbb8e18599094dd49405c9ccf 100644 (file)
@@ -32,9 +32,6 @@
  * and that's assures that any user process won't get access to the
  * kernel doorbells page
  */
-static DEFINE_MUTEX(doorbell_mutex);
-static unsigned long doorbell_available_index[
-       DIV_ROUND_UP(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS, BITS_PER_LONG)] = { 0 };
 
 #define KERNEL_DOORBELL_PASID 1
 #define KFD_SIZE_OF_DOORBELL_IN_BYTES 4
@@ -170,12 +167,12 @@ u32 __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd,
 
        BUG_ON(!kfd || !doorbell_off);
 
-       mutex_lock(&doorbell_mutex);
-       inx = find_first_zero_bit(doorbell_available_index,
+       mutex_lock(&kfd->doorbell_mutex);
+       inx = find_first_zero_bit(kfd->doorbell_available_index,
                                        KFD_MAX_NUM_OF_QUEUES_PER_PROCESS);
 
-       __set_bit(inx, doorbell_available_index);
-       mutex_unlock(&doorbell_mutex);
+       __set_bit(inx, kfd->doorbell_available_index);
+       mutex_unlock(&kfd->doorbell_mutex);
 
        if (inx >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
                return NULL;
@@ -203,9 +200,9 @@ void kfd_release_kernel_doorbell(struct kfd_dev *kfd, u32 __iomem *db_addr)
 
        inx = (unsigned int)(db_addr - kfd->doorbell_kernel_ptr);
 
-       mutex_lock(&doorbell_mutex);
-       __clear_bit(inx, doorbell_available_index);
-       mutex_unlock(&doorbell_mutex);
+       mutex_lock(&kfd->doorbell_mutex);
+       __clear_bit(inx, kfd->doorbell_available_index);
+       mutex_unlock(&kfd->doorbell_mutex);
 }
 
 inline void write_kernel_doorbell(u32 __iomem *db, u32 value)
index 3f34ae16f0750a04365c75cf448d66574e16e9b6..4e0a68f13a77bc4153256161224c0ab4fc3cf5bc 100644 (file)
@@ -34,7 +34,6 @@
 #define KFD_DRIVER_MINOR       7
 #define KFD_DRIVER_PATCHLEVEL  1
 
-const struct kfd2kgd_calls *kfd2kgd;
 static const struct kgd2kfd_calls kgd2kfd = {
        .exit           = kgd2kfd_exit,
        .probe          = kgd2kfd_probe,
@@ -55,9 +54,7 @@ module_param(max_num_of_queues_per_device, int, 0444);
 MODULE_PARM_DESC(max_num_of_queues_per_device,
        "Maximum number of supported queues per device (1 = Minimum, 4096 = default)");
 
-bool kgd2kfd_init(unsigned interface_version,
-                 const struct kfd2kgd_calls *f2g,
-                 const struct kgd2kfd_calls **g2f)
+bool kgd2kfd_init(unsigned interface_version, const struct kgd2kfd_calls **g2f)
 {
        /*
         * Only one interface version is supported,
@@ -66,11 +63,6 @@ bool kgd2kfd_init(unsigned interface_version,
        if (interface_version != KFD_INTERFACE_VERSION)
                return false;
 
-       /* Protection against multiple amd kgd loads */
-       if (kfd2kgd)
-               return true;
-
-       kfd2kgd = f2g;
        *g2f = &kgd2kfd;
 
        return true;
@@ -85,8 +77,6 @@ static int __init kfd_module_init(void)
 {
        int err;
 
-       kfd2kgd = NULL;
-
        /* Verify module parameters */
        if ((sched_policy < KFD_SCHED_POLICY_HWS) ||
                (sched_policy > KFD_SCHED_POLICY_NO_HWS)) {
index a09e18a339f34ef1268ce9ccd8c6ef0804c9ff76..434979428fc01264647b6189d41aea235d4fda4b 100644 (file)
@@ -151,14 +151,15 @@ static void uninit_mqd_sdma(struct mqd_manager *mm, void *mqd,
 static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id,
                        uint32_t queue_id, uint32_t __user *wptr)
 {
-       return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
+       return mm->dev->kfd2kgd->hqd_load
+               (mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
 }
 
 static int load_mqd_sdma(struct mqd_manager *mm, void *mqd,
                        uint32_t pipe_id, uint32_t queue_id,
                        uint32_t __user *wptr)
 {
-       return kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd);
+       return mm->dev->kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd);
 }
 
 static int update_mqd(struct mqd_manager *mm, void *mqd,
@@ -245,7 +246,7 @@ static int destroy_mqd(struct mqd_manager *mm, void *mqd,
                        unsigned int timeout, uint32_t pipe_id,
                        uint32_t queue_id)
 {
-       return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
+       return mm->dev->kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
                                        pipe_id, queue_id);
 }
 
@@ -258,7 +259,7 @@ static int destroy_mqd_sdma(struct mqd_manager *mm, void *mqd,
                                unsigned int timeout, uint32_t pipe_id,
                                uint32_t queue_id)
 {
-       return kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout);
+       return mm->dev->kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout);
 }
 
 static bool is_occupied(struct mqd_manager *mm, void *mqd,
@@ -266,7 +267,7 @@ static bool is_occupied(struct mqd_manager *mm, void *mqd,
                        uint32_t queue_id)
 {
 
-       return kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
+       return mm->dev->kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
                                        pipe_id, queue_id);
 
 }
@@ -275,7 +276,7 @@ static bool is_occupied_sdma(struct mqd_manager *mm, void *mqd,
                        uint64_t queue_address, uint32_t pipe_id,
                        uint32_t queue_id)
 {
-       return kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd);
+       return mm->dev->kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd);
 }
 
 /*
index 5a44f2fecf3826b7b90e18cf3d22b7f64c113a26..f21fccebd75b2bd082a6b3c6c45aa6cd7353ef5d 100644 (file)
@@ -148,6 +148,11 @@ struct kfd_dev {
 
        struct kgd2kfd_shared_resources shared_resources;
 
+       const struct kfd2kgd_calls *kfd2kgd;
+       struct mutex doorbell_mutex;
+       unsigned long doorbell_available_index[DIV_ROUND_UP(
+               KFD_MAX_NUM_OF_QUEUES_PER_PROCESS, BITS_PER_LONG)];
+
        void *gtt_mem;
        uint64_t gtt_start_gpu_addr;
        void *gtt_start_cpu_ptr;
@@ -164,13 +169,12 @@ struct kfd_dev {
 
 /* KGD2KFD callbacks */
 void kgd2kfd_exit(void);
-struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev);
+struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd,
+                       struct pci_dev *pdev, const struct kfd2kgd_calls *f2g);
 bool kgd2kfd_device_init(struct kfd_dev *kfd,
-                        const struct kgd2kfd_shared_resources *gpu_resources);
+                       const struct kgd2kfd_shared_resources *gpu_resources);
 void kgd2kfd_device_exit(struct kfd_dev *kfd);
 
-extern const struct kfd2kgd_calls *kfd2kgd;
-
 enum kfd_mempool {
        KFD_MEMPOOL_SYSTEM_CACHEABLE = 1,
        KFD_MEMPOOL_SYSTEM_WRITECOMBINE = 2,
@@ -378,8 +382,6 @@ struct qcm_process_device {
        /* The Device Queue Manager that owns this data */
        struct device_queue_manager *dqm;
        struct process_queue_manager *pqm;
-       /* Device Queue Manager lock */
-       struct mutex *lock;
        /* Queues list */
        struct list_head queues_list;
        struct list_head priv_queue_list;
index a369c149d1727e78cb67413578e6fe7ddd11d614..945d6226dc51d5b9b55e6af19229a5a9e872f802 100644 (file)
@@ -162,10 +162,16 @@ static void kfd_process_wq_release(struct work_struct *work)
 
        p = my_work->p;
 
+       pr_debug("Releasing process (pasid %d) in workqueue\n",
+                       p->pasid);
+
        mutex_lock(&p->mutex);
 
        list_for_each_entry_safe(pdd, temp, &p->per_device_data,
                                                        per_device_list) {
+               pr_debug("Releasing pdd (topology id %d) for process (pasid %d) in workqueue\n",
+                               pdd->dev->id, p->pasid);
+
                amd_iommu_unbind_pasid(pdd->dev->pdev, p->pasid);
                list_del(&pdd->per_device_list);
 
index 498399323a8cd503f35fb3e828abf08c2368cad8..661c6605d31b39033a42a5d4297e1684ed734011 100644 (file)
@@ -726,13 +726,14 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
                }
 
                sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
-                               kfd2kgd->get_max_engine_clock_in_mhz(
+                       dev->gpu->kfd2kgd->get_max_engine_clock_in_mhz(
                                        dev->gpu->kgd));
                sysfs_show_64bit_prop(buffer, "local_mem_size",
-                               kfd2kgd->get_vmem_size(dev->gpu->kgd));
+                       dev->gpu->kfd2kgd->get_vmem_size(
+                                       dev->gpu->kgd));
 
                sysfs_show_32bit_prop(buffer, "fw_version",
-                               kfd2kgd->get_fw_version(
+                       dev->gpu->kfd2kgd->get_fw_version(
                                                dev->gpu->kgd,
                                                KGD_ENGINE_MEC1));
        }
@@ -1099,8 +1100,9 @@ static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu)
        buf[2] = gpu->pdev->subsystem_device;
        buf[3] = gpu->pdev->device;
        buf[4] = gpu->pdev->bus->number;
-       buf[5] = (uint32_t)(kfd2kgd->get_vmem_size(gpu->kgd) & 0xffffffff);
-       buf[6] = (uint32_t)(kfd2kgd->get_vmem_size(gpu->kgd) >> 32);
+       buf[5] = (uint32_t)(gpu->kfd2kgd->get_vmem_size(gpu->kgd)
+                       & 0xffffffff);
+       buf[6] = (uint32_t)(gpu->kfd2kgd->get_vmem_size(gpu->kgd) >> 32);
 
        for (i = 0, hashout = 0; i < 7; i++)
                hashout ^= hash_32(buf[i], KFD_GPU_ID_HASH_WIDTH);
index 239bc16a1ddd61c9fd65d3d1f1284025fd69df2c..dabd94446b7b2a5d771cd7a2cc704d73cddff087 100644 (file)
@@ -76,37 +76,6 @@ struct kgd2kfd_shared_resources {
        size_t doorbell_start_offset;
 };
 
-/**
- * struct kgd2kfd_calls
- *
- * @exit: Notifies amdkfd that kgd module is unloaded
- *
- * @probe: Notifies amdkfd about a probe done on a device in the kgd driver.
- *
- * @device_init: Initialize the newly probed device (if it is a device that
- * amdkfd supports)
- *
- * @device_exit: Notifies amdkfd about a removal of a kgd device
- *
- * @suspend: Notifies amdkfd about a suspend action done to a kgd device
- *
- * @resume: Notifies amdkfd about a resume action done to a kgd device
- *
- * This structure contains function callback pointers so the kgd driver
- * will notify to the amdkfd about certain status changes.
- *
- */
-struct kgd2kfd_calls {
-       void (*exit)(void);
-       struct kfd_dev* (*probe)(struct kgd_dev *kgd, struct pci_dev *pdev);
-       bool (*device_init)(struct kfd_dev *kfd,
-                       const struct kgd2kfd_shared_resources *gpu_resources);
-       void (*device_exit)(struct kfd_dev *kfd);
-       void (*interrupt)(struct kfd_dev *kfd, const void *ih_ring_entry);
-       void (*suspend)(struct kfd_dev *kfd);
-       int (*resume)(struct kfd_dev *kfd);
-};
-
 /**
  * struct kfd2kgd_calls
  *
@@ -196,8 +165,39 @@ struct kfd2kgd_calls {
                                enum kgd_engine_type type);
 };
 
+/**
+ * struct kgd2kfd_calls
+ *
+ * @exit: Notifies amdkfd that kgd module is unloaded
+ *
+ * @probe: Notifies amdkfd about a probe done on a device in the kgd driver.
+ *
+ * @device_init: Initialize the newly probed device (if it is a device that
+ * amdkfd supports)
+ *
+ * @device_exit: Notifies amdkfd about a removal of a kgd device
+ *
+ * @suspend: Notifies amdkfd about a suspend action done to a kgd device
+ *
+ * @resume: Notifies amdkfd about a resume action done to a kgd device
+ *
+ * This structure contains function callback pointers so the kgd driver
+ * will notify to the amdkfd about certain status changes.
+ *
+ */
+struct kgd2kfd_calls {
+       void (*exit)(void);
+       struct kfd_dev* (*probe)(struct kgd_dev *kgd, struct pci_dev *pdev,
+               const struct kfd2kgd_calls *f2g);
+       bool (*device_init)(struct kfd_dev *kfd,
+                       const struct kgd2kfd_shared_resources *gpu_resources);
+       void (*device_exit)(struct kfd_dev *kfd);
+       void (*interrupt)(struct kfd_dev *kfd, const void *ih_ring_entry);
+       void (*suspend)(struct kfd_dev *kfd);
+       int (*resume)(struct kfd_dev *kfd);
+};
+
 bool kgd2kfd_init(unsigned interface_version,
-               const struct kfd2kgd_calls *f2g,
                const struct kgd2kfd_calls **g2f);
 
 #endif /* KGD_KFD_INTERFACE_H_INCLUDED */
index d55c0c232e1d40c73520220d24a5ef2f5bc25488..f69b92535505b5ae1c899d6f9b08f76501851fa7 100644 (file)
@@ -207,6 +207,27 @@ static void atmel_hlcdc_crtc_enable(struct drm_crtc *c)
        crtc->enabled = true;
 }
 
+void atmel_hlcdc_crtc_suspend(struct drm_crtc *c)
+{
+       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+
+       if (crtc->enabled) {
+               atmel_hlcdc_crtc_disable(c);
+               /* save enable state for resume */
+               crtc->enabled = true;
+       }
+}
+
+void atmel_hlcdc_crtc_resume(struct drm_crtc *c)
+{
+       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+
+       if (crtc->enabled) {
+               crtc->enabled = false;
+               atmel_hlcdc_crtc_enable(c);
+       }
+}
+
 static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c,
                                         struct drm_crtc_state *s)
 {
index c4bb1f9f95c63382250e9f09a95b9a1cf2dd6216..60b0c13d7ff5cc6f4c338c9ed3d7f423d684c84e 100644 (file)
@@ -569,14 +569,8 @@ static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
                return 0;
 
        drm_modeset_lock_all(drm_dev);
-       list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
-               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-               if (crtc->enabled) {
-                       crtc_funcs->disable(crtc);
-                       /* save enable state for resume */
-                       crtc->enabled = true;
-               }
-       }
+       list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head)
+               atmel_hlcdc_crtc_suspend(crtc);
        drm_modeset_unlock_all(drm_dev);
        return 0;
 }
@@ -590,13 +584,8 @@ static int atmel_hlcdc_dc_drm_resume(struct device *dev)
                return 0;
 
        drm_modeset_lock_all(drm_dev);
-       list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
-               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-               if (crtc->enabled) {
-                       crtc->enabled = false;
-                       crtc_funcs->enable(crtc);
-               }
-       }
+       list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head)
+               atmel_hlcdc_crtc_resume(crtc);
        drm_modeset_unlock_all(drm_dev);
        return 0;
 }
index 1ea9c2ccd8a74f0a1e4918a2a1a3f7127aa0adda..cf6b375bc38d1430c892ea2bf69cdf144047efd8 100644 (file)
@@ -155,6 +155,9 @@ void atmel_hlcdc_crtc_irq(struct drm_crtc *c);
 void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc,
                                       struct drm_file *file);
 
+void atmel_hlcdc_crtc_suspend(struct drm_crtc *crtc);
+void atmel_hlcdc_crtc_resume(struct drm_crtc *crtc);
+
 int atmel_hlcdc_crtc_create(struct drm_device *dev);
 
 int atmel_hlcdc_create_outputs(struct drm_device *dev);
index a7458813af2b8b7dcf81ccca746f0e8ae6d60634..d9ed9a54fd1e318196439e4ad006e575b8c9d912 100644 (file)
@@ -151,7 +151,7 @@ steal_encoder(struct drm_atomic_state *state,
 static int
 update_connector_routing(struct drm_atomic_state *state, int conn_idx)
 {
-       struct drm_connector_helper_funcs *funcs;
+       const struct drm_connector_helper_funcs *funcs;
        struct drm_encoder *new_encoder;
        struct drm_crtc *encoder_crtc;
        struct drm_connector *connector;
@@ -264,7 +264,7 @@ mode_fixup(struct drm_atomic_state *state)
        }
 
        for (i = 0; i < state->num_connector; i++) {
-               struct drm_encoder_helper_funcs *funcs;
+               const struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
 
                conn_state = state->connector_states[i];
@@ -317,7 +317,7 @@ mode_fixup(struct drm_atomic_state *state)
        }
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc;
 
                crtc_state = state->crtc_states[i];
@@ -346,7 +346,7 @@ needs_modeset(struct drm_crtc_state *state)
 }
 
 /**
- * drm_atomic_helper_check - validate state object for modeset changes
+ * drm_atomic_helper_check_modeset - validate state object for modeset changes
  * @dev: DRM device
  * @state: the driver state object
  *
@@ -461,7 +461,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
 EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
 
 /**
- * drm_atomic_helper_check - validate state object for modeset changes
+ * drm_atomic_helper_check_planes - validate state object for planes changes
  * @dev: DRM device
  * @state: the driver state object
  *
@@ -481,7 +481,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
        int i, ret = 0;
 
        for (i = 0; i < nplanes; i++) {
-               struct drm_plane_helper_funcs *funcs;
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = state->planes[i];
                struct drm_plane_state *plane_state = state->plane_states[i];
 
@@ -504,7 +504,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
        }
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc = state->crtcs[i];
 
                if (!crtc)
@@ -571,9 +571,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
        int i;
 
        for (i = 0; i < old_state->num_connector; i++) {
+               const struct drm_encoder_helper_funcs *funcs;
                struct drm_connector_state *old_conn_state;
                struct drm_connector *connector;
-               struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
                struct drm_crtc_state *old_crtc_state;
 
@@ -605,7 +605,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 
                /*
                 * Each encoder has at most one connector (since we always steal
-                * it away), so we won't call call disable hooks twice.
+                * it away), so we won't call disable hooks twice.
                 */
                if (encoder->bridge)
                        encoder->bridge->funcs->disable(encoder->bridge);
@@ -623,7 +623,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
        }
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc;
                struct drm_crtc_state *old_crtc_state;
 
@@ -713,7 +713,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
        int i;
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc;
 
                crtc = old_state->crtcs[i];
@@ -732,9 +732,9 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
        }
 
        for (i = 0; i < old_state->num_connector; i++) {
+               const struct drm_encoder_helper_funcs *funcs;
                struct drm_connector *connector;
                struct drm_crtc_state *new_crtc_state;
-               struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
                struct drm_display_mode *mode, *adjusted_mode;
 
@@ -757,7 +757,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
 
                /*
                 * Each encoder has at most one connector (since we always steal
-                * it away), so we won't call call mode_set hooks twice.
+                * it away), so we won't call mode_set hooks twice.
                 */
                if (funcs->mode_set)
                        funcs->mode_set(encoder, mode, adjusted_mode);
@@ -812,7 +812,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
        int i;
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc;
 
                crtc = old_state->crtcs[i];
@@ -838,8 +838,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
        }
 
        for (i = 0; i < old_state->num_connector; i++) {
+               const struct drm_encoder_helper_funcs *funcs;
                struct drm_connector *connector;
-               struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
 
                connector = old_state->connectors[i];
@@ -858,7 +858,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 
                /*
                 * Each encoder has at most one connector (since we always steal
-                * it away), so we won't call call enable hooks twice.
+                * it away), so we won't call enable hooks twice.
                 */
                if (encoder->bridge)
                        encoder->bridge->funcs->pre_enable(encoder->bridge);
@@ -1025,7 +1025,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 
        /*
         * Everything below can be run asynchronously without the need to grab
-        * any modeset locks at all under one conditions: It must be guaranteed
+        * any modeset locks at all under one condition: It must be guaranteed
         * that the asynchronous work has either been cancelled (if the driver
         * supports it, which at least requires that the framebuffers get
         * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
@@ -1114,7 +1114,7 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,
        int ret, i;
 
        for (i = 0; i < nplanes; i++) {
-               struct drm_plane_helper_funcs *funcs;
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = state->planes[i];
                struct drm_plane_state *plane_state = state->plane_states[i];
                struct drm_framebuffer *fb;
@@ -1137,7 +1137,7 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,
 
 fail:
        for (i--; i >= 0; i--) {
-               struct drm_plane_helper_funcs *funcs;
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = state->planes[i];
                struct drm_plane_state *plane_state = state->plane_states[i];
                struct drm_framebuffer *fb;
@@ -1179,7 +1179,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
        int i;
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc = old_state->crtcs[i];
 
                if (!crtc)
@@ -1194,7 +1194,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
        }
 
        for (i = 0; i < nplanes; i++) {
-               struct drm_plane_helper_funcs *funcs;
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = old_state->planes[i];
                struct drm_plane_state *old_plane_state;
 
@@ -1219,7 +1219,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
        }
 
        for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
+               const struct drm_crtc_helper_funcs *funcs;
                struct drm_crtc *crtc = old_state->crtcs[i];
 
                if (!crtc)
@@ -1254,7 +1254,7 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
        int i;
 
        for (i = 0; i < nplanes; i++) {
-               struct drm_plane_helper_funcs *funcs;
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = old_state->planes[i];
                struct drm_plane_state *plane_state = old_state->plane_states[i];
                struct drm_framebuffer *old_fb;
@@ -2001,10 +2001,10 @@ retry:
        WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
 
        list_for_each_entry(tmp_connector, &config->connector_list, head) {
-               if (connector->state->crtc != crtc)
+               if (tmp_connector->state->crtc != crtc)
                        continue;
 
-               if (connector->dpms == DRM_MODE_DPMS_ON) {
+               if (tmp_connector->dpms == DRM_MODE_DPMS_ON) {
                        active = true;
                        break;
                }
index d1187e571c6dd038648aa86b73d0cb2ddd526792..eaa5790c2a6f89a384f01d398bef81ef74cacb48 100644 (file)
@@ -49,7 +49,7 @@ void drm_bridge_remove(struct drm_bridge *bridge)
 }
 EXPORT_SYMBOL(drm_bridge_remove);
 
-extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
+int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
 {
        if (!dev || !bridge)
                return -EINVAL;
index 9f970c2d481912d3db2adb498940c6dcf7ca9b4a..d576a4dea64fa3e41db38efb63f00985458ac5df 100644 (file)
@@ -660,6 +660,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
        struct drm_mode_config *config = &dev->mode_config;
        int ret;
 
+       WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY);
+       WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR);
+
        crtc->dev = dev;
        crtc->funcs = funcs;
        crtc->invert_dimensions = false;
index f1283878ff6df3000608773de43ee22e77cd7b59..d5368ea56a0fc12e4265d4e1f52cd87816514e20 100644 (file)
@@ -427,11 +427,13 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter)
  * retrying the transaction as appropriate.  It is assumed that the
  * aux->transfer function does not modify anything in the msg other than the
  * reply field.
+ *
+ * Returns bytes transferred on success, or a negative error code on failure.
  */
 static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 {
        unsigned int retry;
-       int err;
+       int ret;
 
        /*
         * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device
@@ -440,14 +442,14 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
         */
        for (retry = 0; retry < 7; retry++) {
                mutex_lock(&aux->hw_mutex);
-               err = aux->transfer(aux, msg);
+               ret = aux->transfer(aux, msg);
                mutex_unlock(&aux->hw_mutex);
-               if (err < 0) {
-                       if (err == -EBUSY)
+               if (ret < 0) {
+                       if (ret == -EBUSY)
                                continue;
 
-                       DRM_DEBUG_KMS("transaction failed: %d\n", err);
-                       return err;
+                       DRM_DEBUG_KMS("transaction failed: %d\n", ret);
+                       return ret;
                }
 
 
@@ -488,9 +490,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
                         * Both native ACK and I2C ACK replies received. We
                         * can assume the transfer was successful.
                         */
-                       if (err < msg->size)
-                               return -EPROTO;
-                       return 0;
+                       return ret;
 
                case DP_AUX_I2C_REPLY_NACK:
                        DRM_DEBUG_KMS("I2C nack\n");
@@ -513,14 +513,55 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        return -EREMOTEIO;
 }
 
+/*
+ * Keep retrying drm_dp_i2c_do_msg until all data has been transferred.
+ *
+ * Returns an error code on failure, or a recommended transfer size on success.
+ */
+static int drm_dp_i2c_drain_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *orig_msg)
+{
+       int err, ret = orig_msg->size;
+       struct drm_dp_aux_msg msg = *orig_msg;
+
+       while (msg.size > 0) {
+               err = drm_dp_i2c_do_msg(aux, &msg);
+               if (err <= 0)
+                       return err == 0 ? -EPROTO : err;
+
+               if (err < msg.size && err < ret) {
+                       DRM_DEBUG_KMS("Partial I2C reply: requested %zu bytes got %d bytes\n",
+                                     msg.size, err);
+                       ret = err;
+               }
+
+               msg.size -= err;
+               msg.buffer += err;
+       }
+
+       return ret;
+}
+
+/*
+ * Bizlink designed DP->DVI-D Dual Link adapters require the I2C over AUX
+ * packets to be as large as possible. If not, the I2C transactions never
+ * succeed. Hence the default is maximum.
+ */
+static int dp_aux_i2c_transfer_size __read_mostly = DP_AUX_MAX_PAYLOAD_BYTES;
+module_param_unsafe(dp_aux_i2c_transfer_size, int, 0644);
+MODULE_PARM_DESC(dp_aux_i2c_transfer_size,
+                "Number of bytes to transfer in a single I2C over DP AUX CH message, (1-16, default 16)");
+
 static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
                           int num)
 {
        struct drm_dp_aux *aux = adapter->algo_data;
        unsigned int i, j;
+       unsigned transfer_size;
        struct drm_dp_aux_msg msg;
        int err = 0;
 
+       dp_aux_i2c_transfer_size = clamp(dp_aux_i2c_transfer_size, 1, DP_AUX_MAX_PAYLOAD_BYTES);
+
        memset(&msg, 0, sizeof(msg));
 
        for (i = 0; i < num; i++) {
@@ -538,20 +579,19 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
                err = drm_dp_i2c_do_msg(aux, &msg);
                if (err < 0)
                        break;
-               /*
-                * Many hardware implementations support FIFOs larger than a
-                * single byte, but it has been empirically determined that
-                * transferring data in larger chunks can actually lead to
-                * decreased performance. Therefore each message is simply
-                * transferred byte-by-byte.
+               /* We want each transaction to be as large as possible, but
+                * we'll go to smaller sizes if the hardware gives us a
+                * short reply.
                 */
-               for (j = 0; j < msgs[i].len; j++) {
+               transfer_size = dp_aux_i2c_transfer_size;
+               for (j = 0; j < msgs[i].len; j += msg.size) {
                        msg.buffer = msgs[i].buf + j;
-                       msg.size = 1;
+                       msg.size = min(transfer_size, msgs[i].len - j);
 
-                       err = drm_dp_i2c_do_msg(aux, &msg);
+                       err = drm_dp_i2c_drain_msg(aux, &msg);
                        if (err < 0)
                                break;
+                       transfer_size = err;
                }
                if (err < 0)
                        break;
index 379ab45557568c6e21615526a96a60e145ed1ee5..132581ca4ad84fff6b25abe13d84af96f0c1c11b 100644 (file)
@@ -2324,6 +2324,19 @@ out:
 }
 EXPORT_SYMBOL(drm_dp_mst_allocate_vcpi);
 
+int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
+{
+       int slots = 0;
+       port = drm_dp_get_validated_port_ref(mgr, port);
+       if (!port)
+               return slots;
+
+       slots = port->vcpi.num_slots;
+       drm_dp_put_port(port);
+       return slots;
+}
+EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots);
+
 /**
  * drm_dp_mst_reset_vcpi_slots() - Reset number of slots to 0 for VCPI
  * @mgr: manager for this port
index d51213464672a9c1b7d3362f355b6ddde29c2403..48f7359e2a6bfed94791c98f78431aab824f7b94 100644 (file)
@@ -70,7 +70,7 @@ void drm_err(const char *format, ...)
        vaf.fmt = format;
        vaf.va = &args;
 
-       printk(KERN_ERR "[" DRM_NAME ":%pf] *ERROR* %pV",
+       printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV",
               __builtin_return_address(0), &vaf);
 
        va_end(args);
index cc0ae047ed3bd8fcc265e38a06d8ec86207deb55..5c1aca443e54f851cf7abeb9679962f3ec96ef29 100644 (file)
@@ -304,7 +304,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
        }
 
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
-       drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+       drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
        offset = fbi->var.xoffset * bytes_per_pixel;
        offset += fbi->var.yoffset * fb->pitches[0];
index 1e6a0c760c5df9447852672728739225ce48b63b..1a20db7c971f4bc3c5f48c76307d3625ffc1b92a 100644 (file)
@@ -1034,23 +1034,45 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
        crtc_count = 0;
        for (i = 0; i < fb_helper->crtc_count; i++) {
                struct drm_display_mode *desired_mode;
-               int x, y;
+               struct drm_mode_set *mode_set;
+               int x, y, j;
+               /* in case of tile group, are we the last tile vert or horiz?
+                * If no tile group you are always the last one both vertically
+                * and horizontally
+                */
+               bool lastv = true, lasth = true;
+
                desired_mode = fb_helper->crtc_info[i].desired_mode;
+               mode_set = &fb_helper->crtc_info[i].mode_set;
+
+               if (!desired_mode)
+                       continue;
+
+               crtc_count++;
+
                x = fb_helper->crtc_info[i].x;
                y = fb_helper->crtc_info[i].y;
-               if (desired_mode) {
-                       if (gamma_size == 0)
-                               gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
-                       if (desired_mode->hdisplay + x < sizes.fb_width)
-                               sizes.fb_width = desired_mode->hdisplay + x;
-                       if (desired_mode->vdisplay + y < sizes.fb_height)
-                               sizes.fb_height = desired_mode->vdisplay + y;
-                       if (desired_mode->hdisplay + x > sizes.surface_width)
-                               sizes.surface_width = desired_mode->hdisplay + x;
-                       if (desired_mode->vdisplay + y > sizes.surface_height)
-                               sizes.surface_height = desired_mode->vdisplay + y;
-                       crtc_count++;
+
+               if (gamma_size == 0)
+                       gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
+
+               sizes.surface_width  = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
+               sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
+
+               for (j = 0; j < mode_set->num_connectors; j++) {
+                       struct drm_connector *connector = mode_set->connectors[j];
+                       if (connector->has_tile) {
+                               lasth = (connector->tile_h_loc == (connector->num_h_tile - 1));
+                               lastv = (connector->tile_v_loc == (connector->num_v_tile - 1));
+                               /* cloning to multiple tiles is just crazy-talk, so: */
+                               break;
+                       }
                }
+
+               if (lasth)
+                       sizes.fb_width  = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width);
+               if (lastv)
+                       sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
        }
 
        if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
index f1b32f91d94163bcdca46a6ee5f29bd789e23336..cbb4fc0fc969ee2236e112cbb5974742ceffc191 100644 (file)
@@ -37,6 +37,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_gem.h>
 
+#include "drm_internal.h"
 #include "drm_legacy.h"
 
 /**
index 2f4c4343dfa32f5a3f2c81e83a67f9409a31e11f..aa8bbb460c5715a619988d6d4350b4a4507173f8 100644 (file)
@@ -1016,7 +1016,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
        return 0;
 }
 
-drm_ioctl_compat_t *drm_compat_ioctls[] = {
+static drm_ioctl_compat_t *drm_compat_ioctls[] = {
        [DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version,
        [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE32)] = compat_drm_getunique,
        [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP32)] = compat_drm_getmap,
index fd29f03645b8e465b42add64384b339c13229dc2..1b1bd42b03687683202eb600425c5d7e582c61ad 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
 #include <drm/drmP.h>
+#include "drm_internal.h"
 #include "drm_legacy.h"
 
 /**
index b62b036350503c8eb70dee380342b097b796c2c7..33807e0adac71d9e28e4747dfd26d8a5219cf71a 100644 (file)
@@ -353,13 +353,14 @@ static struct drm_plane *create_primary_plane(struct drm_device *dev)
        if (primary == NULL) {
                DRM_DEBUG_KMS("Failed to allocate primary plane\n");
                return NULL;
-               /*
-                * Remove the format_default field from drm_plane when dropping
-                * this helper.
-                */
-               primary->format_default = true;
        }
 
+       /*
+        * Remove the format_default field from drm_plane when dropping
+        * this helper.
+        */
+       primary->format_default = true;
+
        /* possible_crtc's will be filled in later by crtc_init */
        ret = drm_universal_plane_init(dev, primary, 0,
                                       &drm_primary_helper_funcs,
index 4a2c328959e59348ef7ee5f4bb0797835cd92ba5..aab49ee4ed40d2ce5b525554209fd3ffe40340b4 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/slab.h>
 #endif
 #include <asm/pgtable.h>
+#include "drm_internal.h"
 #include "drm_legacy.h"
 
 struct drm_vma_entry {
index 84f8dfe1c5ec02ec383b0d74cf615b7906388d9a..e71e331f0188c009f56bffe1fa81b2ec0be29164 100644 (file)
@@ -76,6 +76,7 @@ static struct fb_ops exynos_drm_fb_ops = {
 };
 
 static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
+                                    struct drm_fb_helper_surface_size *sizes,
                                     struct drm_framebuffer *fb)
 {
        struct fb_info *fbi = helper->fbdev;
@@ -85,7 +86,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
        unsigned long offset;
 
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
-       drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+       drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
        /* RGB formats use only one buffer */
        buffer = exynos_drm_fb_buffer(fb, 0);
@@ -189,7 +190,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
                goto err_destroy_framebuffer;
        }
 
-       ret = exynos_drm_fbdev_update(helper, helper->fb);
+       ret = exynos_drm_fbdev_update(helper, sizes, helper->fb);
        if (ret < 0)
                goto err_dealloc_cmap;
 
index 61aa824d45d2115efe9dd716efee3e2e2785c6c9..b728523e194f7581b8e9740b7ddb13e6f5606d56 100644 (file)
@@ -27,12 +27,13 @@ struct adv7511 {
        struct regmap *regmap;
        struct regmap *packet_memory_regmap;
        enum drm_connector_status status;
-       int dpms_mode;
+       bool powered;
 
        unsigned int f_tmds;
 
        unsigned int current_edid_segment;
        uint8_t edid_buf[256];
+       bool edid_read;
 
        wait_queue_head_t wq;
        struct drm_encoder *encoder;
@@ -357,6 +358,48 @@ static void adv7511_set_link_config(struct adv7511 *adv7511,
        adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
 }
 
+static void adv7511_power_on(struct adv7511 *adv7511)
+{
+       adv7511->current_edid_segment = -1;
+
+       regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
+                    ADV7511_INT0_EDID_READY);
+       regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
+                    ADV7511_INT1_DDC_ERROR);
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+                          ADV7511_POWER_POWER_DOWN, 0);
+
+       /*
+        * Per spec it is allowed to pulse the HDP signal to indicate that the
+        * EDID information has changed. Some monitors do this when they wakeup
+        * from standby or are enabled. When the HDP goes low the adv7511 is
+        * reset and the outputs are disabled which might cause the monitor to
+        * go to standby again. To avoid this we ignore the HDP pin for the
+        * first few seconds after enabling the output.
+        */
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
+                          ADV7511_REG_POWER2_HDP_SRC_MASK,
+                          ADV7511_REG_POWER2_HDP_SRC_NONE);
+
+       /*
+        * Most of the registers are reset during power down or when HPD is low.
+        */
+       regcache_sync(adv7511->regmap);
+
+       adv7511->powered = true;
+}
+
+static void adv7511_power_off(struct adv7511 *adv7511)
+{
+       /* TODO: setup additional power down modes */
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+                          ADV7511_POWER_POWER_DOWN,
+                          ADV7511_POWER_POWER_DOWN);
+       regcache_mark_dirty(adv7511->regmap);
+
+       adv7511->powered = false;
+}
+
 /* -----------------------------------------------------------------------------
  * Interrupt and hotplug detection
  */
@@ -379,69 +422,71 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
        return false;
 }
 
-static irqreturn_t adv7511_irq_handler(int irq, void *devid)
-{
-       struct adv7511 *adv7511 = devid;
-
-       if (adv7511_hpd(adv7511))
-               drm_helper_hpd_irq_event(adv7511->encoder->dev);
-
-       wake_up_all(&adv7511->wq);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned int adv7511_is_interrupt_pending(struct adv7511 *adv7511,
-                                                unsigned int irq)
+static int adv7511_irq_process(struct adv7511 *adv7511)
 {
        unsigned int irq0, irq1;
-       unsigned int pending;
        int ret;
 
        ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0);
        if (ret < 0)
-               return 0;
+               return ret;
+
        ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1);
        if (ret < 0)
-               return 0;
+               return ret;
 
-       pending = (irq1 << 8) | irq0;
+       regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
+       regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-       return pending & irq;
+       if (irq0 & ADV7511_INT0_HDP)
+               drm_helper_hpd_irq_event(adv7511->encoder->dev);
+
+       if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
+               adv7511->edid_read = true;
+
+               if (adv7511->i2c_main->irq)
+                       wake_up_all(&adv7511->wq);
+       }
+
+       return 0;
 }
 
-static int adv7511_wait_for_interrupt(struct adv7511 *adv7511, int irq,
-                                     int timeout)
+static irqreturn_t adv7511_irq_handler(int irq, void *devid)
+{
+       struct adv7511 *adv7511 = devid;
+       int ret;
+
+       ret = adv7511_irq_process(adv7511);
+       return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * EDID retrieval
+ */
+
+static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout)
 {
-       unsigned int pending;
        int ret;
 
        if (adv7511->i2c_main->irq) {
                ret = wait_event_interruptible_timeout(adv7511->wq,
-                               adv7511_is_interrupt_pending(adv7511, irq),
-                               msecs_to_jiffies(timeout));
-               if (ret <= 0)
-                       return 0;
-               pending = adv7511_is_interrupt_pending(adv7511, irq);
+                               adv7511->edid_read, msecs_to_jiffies(timeout));
        } else {
-               if (timeout < 25)
-                       timeout = 25;
-               do {
-                       pending = adv7511_is_interrupt_pending(adv7511, irq);
-                       if (pending)
+               for (; timeout > 0; timeout -= 25) {
+                       ret = adv7511_irq_process(adv7511);
+                       if (ret < 0)
                                break;
+
+                       if (adv7511->edid_read)
+                               break;
+
                        msleep(25);
-                       timeout -= 25;
-               } while (timeout >= 25);
+               }
        }
 
-       return pending;
+       return adv7511->edid_read ? 0 : -EIO;
 }
 
-/* -----------------------------------------------------------------------------
- * EDID retrieval
- */
-
 static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
                                  size_t len)
 {
@@ -463,19 +508,14 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
                        return ret;
 
                if (status != 2) {
+                       adv7511->edid_read = false;
                        regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT,
                                     block);
-                       ret = adv7511_wait_for_interrupt(adv7511,
-                                       ADV7511_INT0_EDID_READY |
-                                       ADV7511_INT1_DDC_ERROR, 200);
-
-                       if (!(ret & ADV7511_INT0_EDID_READY))
-                               return -EIO;
+                       ret = adv7511_wait_for_edid(adv7511, 200);
+                       if (ret < 0)
+                               return ret;
                }
 
-               regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-                            ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR);
-
                /* Break this apart, hopefully more I2C controllers will
                 * support 64 byte transfers than 256 byte transfers
                 */
@@ -526,9 +566,11 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
        unsigned int count;
 
        /* Reading the EDID only works if the device is powered */
-       if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) {
+       if (!adv7511->powered) {
                regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-                            ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR);
+                            ADV7511_INT0_EDID_READY);
+               regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
+                            ADV7511_INT1_DDC_ERROR);
                regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
                                   ADV7511_POWER_POWER_DOWN, 0);
                adv7511->current_edid_segment = -1;
@@ -536,7 +578,7 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
 
        edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
 
-       if (adv7511->dpms_mode != DRM_MODE_DPMS_ON)
+       if (!adv7511->powered)
                regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
                                   ADV7511_POWER_POWER_DOWN,
                                   ADV7511_POWER_POWER_DOWN);
@@ -558,41 +600,10 @@ static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
        struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
 
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               adv7511->current_edid_segment = -1;
-
-               regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-                            ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR);
-               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
-                                  ADV7511_POWER_POWER_DOWN, 0);
-               /*
-                * Per spec it is allowed to pulse the HDP signal to indicate
-                * that the EDID information has changed. Some monitors do this
-                * when they wakeup from standby or are enabled. When the HDP
-                * goes low the adv7511 is reset and the outputs are disabled
-                * which might cause the monitor to go to standby again. To
-                * avoid this we ignore the HDP pin for the first few seconds
-                * after enabling the output.
-                */
-               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
-                                  ADV7511_REG_POWER2_HDP_SRC_MASK,
-                                  ADV7511_REG_POWER2_HDP_SRC_NONE);
-               /* Most of the registers are reset during power down or
-                * when HPD is low
-                */
-               regcache_sync(adv7511->regmap);
-               break;
-       default:
-               /* TODO: setup additional power down modes */
-               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
-                                  ADV7511_POWER_POWER_DOWN,
-                                  ADV7511_POWER_POWER_DOWN);
-               regcache_mark_dirty(adv7511->regmap);
-               break;
-       }
-
-       adv7511->dpms_mode = mode;
+       if (mode == DRM_MODE_DPMS_ON)
+               adv7511_power_on(adv7511);
+       else
+               adv7511_power_off(adv7511);
 }
 
 static enum drm_connector_status
@@ -620,10 +631,9 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
         * there is a pending HPD interrupt and the cable is connected there was
         * at least one transition from disconnected to connected and the chip
         * has to be reinitialized. */
-       if (status == connector_status_connected && hpd &&
-           adv7511->dpms_mode == DRM_MODE_DPMS_ON) {
+       if (status == connector_status_connected && hpd && adv7511->powered) {
                regcache_mark_dirty(adv7511->regmap);
-               adv7511_encoder_dpms(encoder, adv7511->dpms_mode);
+               adv7511_power_on(adv7511);
                adv7511_get_modes(encoder, connector);
                if (adv7511->status == connector_status_connected)
                        status = connector_status_disconnected;
@@ -858,7 +868,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
        if (!adv7511)
                return -ENOMEM;
 
-       adv7511->dpms_mode = DRM_MODE_DPMS_OFF;
+       adv7511->powered = false;
        adv7511->status = connector_status_disconnected;
 
        ret = adv7511_parse_dt(dev->of_node, &link_config);
@@ -918,10 +928,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
        regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
                     ADV7511_CEC_CTRL_POWER_DOWN);
 
-       regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
-                          ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN);
-
-       adv7511->current_edid_segment = -1;
+       adv7511_power_off(adv7511);
 
        i2c_set_clientdata(i2c, adv7511);
 
index 4605633e253b1b36a6cde19f4df2d9ff9db0b0c6..dea53e36a2ef3aa77fe5d0e68a2864db619b85c5 100644 (file)
@@ -81,7 +81,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
        rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
        trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \
        ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o \
-       radeon_sync.o radeon_audio.o
+       radeon_sync.o radeon_audio.o radeon_dp_auxch.o radeon_dp_mst.o
 
 radeon-$(CONFIG_MMU_NOTIFIER) += radeon_mn.o
 
index 86807ee91bd13a7640f5b925aa4b5a4c0d9d615d..dac78ad24b31558aa53d917fb802865b6a122b61 100644 (file)
@@ -330,8 +330,10 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
                misc |= ATOM_COMPOSITESYNC;
        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                misc |= ATOM_INTERLACE;
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
                misc |= ATOM_DOUBLE_CLOCK_MODE;
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
 
        args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
        args.ucCRTC = radeon_crtc->crtc_id;
@@ -374,8 +376,10 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc,
                misc |= ATOM_COMPOSITESYNC;
        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                misc |= ATOM_INTERLACE;
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
                misc |= ATOM_DOUBLE_CLOCK_MODE;
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
 
        args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
        args.ucCRTC = radeon_crtc->crtc_id;
@@ -606,6 +610,13 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                }
        }
 
+       if (radeon_encoder->is_mst_encoder) {
+               struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv;
+               struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv;
+
+               dp_clock = dig_connector->dp_clock;
+       }
+
        /* use recommended ref_div for ss */
        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
                if (radeon_crtc->ss_enabled) {
@@ -952,7 +963,9 @@ static bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_
        radeon_crtc->bpc = 8;
        radeon_crtc->ss_enabled = false;
 
-       if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
+       if (radeon_encoder->is_mst_encoder) {
+               radeon_dp_mst_prepare_pll(crtc, mode);
+       } else if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
            (radeon_encoder_get_dp_bridge_encoder_id(radeon_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) {
                struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                struct drm_connector *connector =
@@ -2069,6 +2082,12 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
                radeon_crtc->connector = NULL;
                return false;
        }
+       if (radeon_crtc->encoder) {
+               struct radeon_encoder *radeon_encoder =
+                       to_radeon_encoder(radeon_crtc->encoder);
+
+               radeon_crtc->output_csc = radeon_encoder->output_csc;
+       }
        if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
                return false;
        if (!atombios_crtc_prepare_pll(crtc, adjusted_mode))
index 8d74de82456e880cb01d7e8132cf6c1caf5fa864..3e3290c203c625d781f7dfacc13977c50c54d34b 100644 (file)
@@ -158,7 +158,7 @@ done:
 #define HEADER_SIZE (BARE_ADDRESS_SIZE + 1)
 
 static ssize_t
-radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
+radeon_dp_aux_transfer_atom(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 {
        struct radeon_i2c_chan *chan =
                container_of(aux, struct radeon_i2c_chan, aux);
@@ -226,11 +226,20 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 
 void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
 {
+       struct drm_device *dev = radeon_connector->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
        int ret;
 
        radeon_connector->ddc_bus->rec.hpd = radeon_connector->hpd.hpd;
        radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev;
-       radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer;
+       if (ASIC_IS_DCE5(rdev)) {
+               if (radeon_auxch)
+                       radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_native;
+               else
+                       radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_atom;
+       } else {
+               radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_atom;
+       }
 
        ret = drm_dp_aux_register(&radeon_connector->ddc_bus->aux);
        if (!ret)
@@ -301,8 +310,8 @@ static int dp_get_max_dp_pix_clock(int link_rate,
 
 /***** radeon specific DP functions *****/
 
-static int radeon_dp_get_max_link_rate(struct drm_connector *connector,
-                                      u8 dpcd[DP_DPCD_SIZE])
+int radeon_dp_get_max_link_rate(struct drm_connector *connector,
+                               u8 dpcd[DP_DPCD_SIZE])
 {
        int max_link_rate;
 
index c39c1d0d9d4e328d8df7f19caf2b52c68b1988b3..f57c1ab617bc877b4576e828ee203381626b177c 100644 (file)
@@ -671,7 +671,15 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        struct drm_connector *connector;
        struct radeon_connector *radeon_connector;
        struct radeon_connector_atom_dig *dig_connector;
+       struct radeon_encoder_atom_dig *dig_enc;
 
+       if (radeon_encoder_is_digital(encoder)) {
+               dig_enc = radeon_encoder->enc_priv;
+               if (dig_enc->active_mst_links)
+                       return ATOM_ENCODER_MODE_DP_MST;
+       }
+       if (radeon_encoder->is_mst_encoder || radeon_encoder->offset)
+               return ATOM_ENCODER_MODE_DP_MST;
        /* dp bridges are always DP */
        if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)
                return ATOM_ENCODER_MODE_DP;
@@ -823,7 +831,7 @@ union dig_encoder_control {
 };
 
 void
-atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
+atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -920,7 +928,10 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
 
                        if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000))
                                args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
-                       args.v3.acConfig.ucDigSel = dig->dig_encoder;
+                       if (enc_override != -1)
+                               args.v3.acConfig.ucDigSel = enc_override;
+                       else
+                               args.v3.acConfig.ucDigSel = dig->dig_encoder;
                        args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder);
                        break;
                case 4:
@@ -948,7 +959,11 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
                                else
                                        args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ;
                        }
-                       args.v4.acConfig.ucDigSel = dig->dig_encoder;
+
+                       if (enc_override != -1)
+                               args.v4.acConfig.ucDigSel = enc_override;
+                       else
+                               args.v4.acConfig.ucDigSel = dig->dig_encoder;
                        args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder);
                        if (hpd_id == RADEON_HPD_NONE)
                                args.v4.ucHPD_ID = 0;
@@ -969,6 +984,12 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
 
 }
 
+void
+atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
+{
+       atombios_dig_encoder_setup2(encoder, action, panel_mode, -1);
+}
+
 union dig_transmitter_control {
        DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
        DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
@@ -978,7 +999,7 @@ union dig_transmitter_control {
 };
 
 void
-atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set)
+atombios_dig_transmitter_setup2(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set, int fe)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -1328,7 +1349,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                                args.v5.asConfig.ucHPDSel = 0;
                        else
                                args.v5.asConfig.ucHPDSel = hpd_id + 1;
-                       args.v5.ucDigEncoderSel = 1 << dig_encoder;
+                       args.v5.ucDigEncoderSel = (fe != -1) ? (1 << fe) : (1 << dig_encoder);
                        args.v5.ucDPLaneSet = lane_set;
                        break;
                default:
@@ -1344,6 +1365,12 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+void
+atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set)
+{
+       atombios_dig_transmitter_setup2(encoder, action, lane_num, lane_set, -1);
+}
+
 bool
 atombios_set_edp_panel_power(struct drm_connector *connector, int action)
 {
@@ -1687,6 +1714,11 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
        case DRM_MODE_DPMS_OFF:
+
+               /* don't power off encoders with active MST links */
+               if (dig->active_mst_links)
+                       return;
+
                if (ASIC_IS_DCE4(rdev)) {
                        if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector)
                                atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
@@ -1955,6 +1987,53 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
        radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
 }
 
+void
+atombios_set_mst_encoder_crtc_source(struct drm_encoder *encoder, int fe)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+       int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
+       uint8_t frev, crev;
+       union crtc_source_param args;
+
+       memset(&args, 0, sizeof(args));
+
+       if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+               return;
+
+       if (frev != 1 && crev != 2)
+               DRM_ERROR("Unknown table for MST %d, %d\n", frev, crev);
+
+       args.v2.ucCRTC = radeon_crtc->crtc_id;
+       args.v2.ucEncodeMode = ATOM_ENCODER_MODE_DP_MST;
+
+       switch (fe) {
+       case 0:
+               args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+               break;
+       case 1:
+               args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
+               break;
+       case 2:
+               args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
+               break;
+       case 3:
+               args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
+               break;
+       case 4:
+               args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
+               break;
+       case 5:
+               args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
+               break;
+       case 6:
+               args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID;
+               break;
+       }
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
 static void
 atombios_apply_encoder_quirks(struct drm_encoder *encoder,
                              struct drm_display_mode *mode)
@@ -2003,7 +2082,14 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
        }
 }
 
-static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
+void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx)
+{
+       if (enc_idx < 0)
+               return;
+       rdev->mode_info.active_encoders &= ~(1 << enc_idx);
+}
+
+int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -2012,71 +2098,79 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        struct drm_encoder *test_encoder;
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
        uint32_t dig_enc_in_use = 0;
+       int enc_idx = -1;
 
+       if (fe_idx >= 0) {
+               enc_idx = fe_idx;
+               goto assigned;
+       }
        if (ASIC_IS_DCE6(rdev)) {
                /* DCE6 */
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
                        if (dig->linkb)
-                               return 1;
+                               enc_idx = 1;
                        else
-                               return 0;
+                               enc_idx = 0;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
                        if (dig->linkb)
-                               return 3;
+                               enc_idx = 3;
                        else
-                               return 2;
+                               enc_idx = 2;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
                        if (dig->linkb)
-                               return 5;
+                               enc_idx = 5;
                        else
-                               return 4;
+                               enc_idx = 4;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
-                       return 6;
+                       enc_idx = 6;
                        break;
                }
+               goto assigned;
        } else if (ASIC_IS_DCE4(rdev)) {
                /* DCE4/5 */
                if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) {
                        /* ontario follows DCE4 */
                        if (rdev->family == CHIP_PALM) {
                                if (dig->linkb)
-                                       return 1;
+                                       enc_idx = 1;
                                else
-                                       return 0;
+                                       enc_idx = 0;
                        } else
                                /* llano follows DCE3.2 */
-                               return radeon_crtc->crtc_id;
+                               enc_idx = radeon_crtc->crtc_id;
                } else {
                        switch (radeon_encoder->encoder_id) {
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
                                if (dig->linkb)
-                                       return 1;
+                                       enc_idx = 1;
                                else
-                                       return 0;
+                                       enc_idx = 0;
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
                                if (dig->linkb)
-                                       return 3;
+                                       enc_idx = 3;
                                else
-                                       return 2;
+                                       enc_idx = 2;
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
                                if (dig->linkb)
-                                       return 5;
+                                       enc_idx = 5;
                                else
-                                       return 4;
+                                       enc_idx = 4;
                                break;
                        }
                }
+               goto assigned;
        }
 
        /* on DCE32 and encoder can driver any block so just crtc id */
        if (ASIC_IS_DCE32(rdev)) {
-               return radeon_crtc->crtc_id;
+               enc_idx = radeon_crtc->crtc_id;
+               goto assigned;
        }
 
        /* on DCE3 - LVTMA can only be driven by DIGB */
@@ -2104,6 +2198,17 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        if (!(dig_enc_in_use & 1))
                return 0;
        return 1;
+
+assigned:
+       if (enc_idx == -1) {
+               DRM_ERROR("Got encoder index incorrect - returning 0\n");
+               return 0;
+       }
+       if (rdev->mode_info.active_encoders & (1 << enc_idx)) {
+               DRM_ERROR("chosen encoder in use %d\n", enc_idx);
+       }
+       rdev->mode_info.active_encoders |= (1 << enc_idx);
+       return enc_idx;
 }
 
 /* This only needs to be called once at startup */
@@ -2362,7 +2467,9 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
             ENCODER_OBJECT_ID_NONE)) {
                struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                if (dig) {
-                       dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
+                       if (dig->dig_encoder >= 0)
+                               radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
+                       dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder, -1);
                        if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) {
                                if (rdev->family >= CHIP_R600)
                                        dig->afmt = rdev->mode_info.afmt[dig->dig_encoder];
@@ -2464,10 +2571,18 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
 
 disable_done:
        if (radeon_encoder_is_digital(encoder)) {
-               dig = radeon_encoder->enc_priv;
-               dig->dig_encoder = -1;
-       }
-       radeon_encoder->active_device = 0;
+               if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
+                       if (rdev->asic->display.hdmi_enable)
+                               radeon_hdmi_enable(rdev, encoder, false);
+               }
+               if (atombios_get_encoder_mode(encoder) != ATOM_ENCODER_MODE_DP_MST) {
+                       dig = radeon_encoder->enc_priv;
+                       radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
+                       dig->dig_encoder = -1;
+                       radeon_encoder->active_device = 0;
+               }
+       } else
+               radeon_encoder->active_device = 0;
 }
 
 /* these are handled by the primary encoders */
index db08f17be76b47ea0d312e57ff292f5d83eba221..69556f5e247e7f1b78a19da8201c970a98fd462d 100644 (file)
@@ -2751,13 +2751,54 @@ void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                else /* current_index == 2 */
                        pl = &ps->high;
                seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
-               if (rdev->family >= CHIP_CEDAR) {
-                       seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u vddci: %u\n",
-                                  current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
-               } else {
-                       seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u\n",
-                                  current_index, pl->sclk, pl->mclk, pl->vddc);
-               }
+               seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u vddci: %u\n",
+                          current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+       }
+}
+
+u32 btc_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return pl->sclk;
+       }
+}
+
+u32 btc_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return pl->mclk;
        }
 }
 
index bcd2f1fe803fa9e35fc654625c496d98efe29f69..8730562323a8b77d0dd86ec399207806a6807ddc 100644 (file)
@@ -5922,6 +5922,20 @@ void ci_dpm_print_power_state(struct radeon_device *rdev,
        r600_dpm_print_ps_status(rdev, rps);
 }
 
+u32 ci_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       u32 sclk = ci_get_average_sclk_freq(rdev);
+
+       return sclk;
+}
+
+u32 ci_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       u32 mclk = ci_get_average_mclk_freq(rdev);
+
+       return mclk;
+}
+
 u32 ci_dpm_get_sclk(struct radeon_device *rdev, bool low)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
index 3e670d344a2047151e289ab7dce348001ddf4280..28faea9996f9e111d6b35e547587025aa93c3089 100644 (file)
@@ -141,6 +141,39 @@ static void cik_fini_cg(struct radeon_device *rdev);
 static void cik_enable_gui_idle_interrupt(struct radeon_device *rdev,
                                          bool enable);
 
+/**
+ * cik_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int cik_get_allowed_info_register(struct radeon_device *rdev,
+                                 u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS2:
+       case GRBM_STATUS_SE0:
+       case GRBM_STATUS_SE1:
+       case GRBM_STATUS_SE2:
+       case GRBM_STATUS_SE3:
+       case SRBM_STATUS:
+       case SRBM_STATUS2:
+       case (SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET):
+       case (SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET):
+       case UVD_STATUS:
+       /* TODO VCE */
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 /* get temperature in millidegrees */
 int ci_get_temp(struct radeon_device *rdev)
 {
@@ -7394,12 +7427,12 @@ int cik_irq_set(struct radeon_device *rdev)
                (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
        cp_int_cntl |= PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE;
 
-       hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+       hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
 
        dma_cntl = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
        dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
@@ -7486,27 +7519,27 @@ int cik_irq_set(struct radeon_device *rdev)
        }
        if (rdev->irq.hpd[0]) {
                DRM_DEBUG("cik_irq_set: hpd 1\n");
-               hpd1 |= DC_HPDx_INT_EN;
+               hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[1]) {
                DRM_DEBUG("cik_irq_set: hpd 2\n");
-               hpd2 |= DC_HPDx_INT_EN;
+               hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[2]) {
                DRM_DEBUG("cik_irq_set: hpd 3\n");
-               hpd3 |= DC_HPDx_INT_EN;
+               hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[3]) {
                DRM_DEBUG("cik_irq_set: hpd 4\n");
-               hpd4 |= DC_HPDx_INT_EN;
+               hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[4]) {
                DRM_DEBUG("cik_irq_set: hpd 5\n");
-               hpd5 |= DC_HPDx_INT_EN;
+               hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[5]) {
                DRM_DEBUG("cik_irq_set: hpd 6\n");
-               hpd6 |= DC_HPDx_INT_EN;
+               hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
 
        WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
@@ -7678,6 +7711,36 @@ static inline void cik_irq_ack(struct radeon_device *rdev)
                tmp |= DC_HPDx_INT_ACK;
                WREG32(DC_HPD6_INT_CONTROL, tmp);
        }
+       if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD1_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD1_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD2_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD2_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD3_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD3_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD4_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD4_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD5_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD6_INT_CONTROL, tmp);
+       }
 }
 
 /**
@@ -7803,6 +7866,7 @@ int cik_irq_process(struct radeon_device *rdev)
        u8 me_id, pipe_id, queue_id;
        u32 ring_index;
        bool queue_hotplug = false;
+       bool queue_dp = false;
        bool queue_reset = false;
        u32 addr, status, mc_client;
        bool queue_thermal = false;
@@ -8048,6 +8112,48 @@ restart_ih:
                                        DRM_DEBUG("IH: HPD6\n");
                                }
                                break;
+                       case 6:
+                               if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 1\n");
+                               }
+                               break;
+                       case 7:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 2\n");
+                               }
+                               break;
+                       case 8:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 3\n");
+                               }
+                               break;
+                       case 9:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 4\n");
+                               }
+                               break;
+                       case 10:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 5\n");
+                               }
+                               break;
+                       case 11:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 6\n");
+                               }
+                               break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
                                break;
@@ -8256,6 +8362,8 @@ restart_ih:
                rptr &= rdev->ih.ptr_mask;
                WREG32(IH_RB_RPTR, rptr);
        }
+       if (queue_dp)
+               schedule_work(&rdev->dp_work);
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
        if (queue_reset) {
index c648e1996dabac449dfb838e018cad85b2d3bb61..4870df898230cb3c4f02f160be9cf024e8a003ac 100644 (file)
 #      define CLK_OD(x)                                ((x) << 6)
 #      define CLK_OD_MASK                              (0x1f << 6)
 
+#define UVD_STATUS                                     0xf6bc
+
 /* UVD clocks */
 
 #define CG_DCLK_CNTL                   0xC050009C
index 973df064c14feb193a81c99109665c2186d03dc6..f848acfd3fc8a94fb4674cf13d9442857e367567 100644 (file)
@@ -1006,6 +1006,34 @@ static void evergreen_init_golden_registers(struct radeon_device *rdev)
        }
 }
 
+/**
+ * evergreen_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int evergreen_get_allowed_info_register(struct radeon_device *rdev,
+                                       u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS_SE0:
+       case GRBM_STATUS_SE1:
+       case SRBM_STATUS:
+       case SRBM_STATUS2:
+       case DMA_STATUS_REG:
+       case UVD_STATUS:
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
                             unsigned *bankh, unsigned *mtaspect,
                             unsigned *tile_split)
@@ -4392,12 +4420,12 @@ int evergreen_irq_set(struct radeon_device *rdev)
                return 0;
        }
 
-       hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+       hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
        if (rdev->family == CHIP_ARUBA)
                thermal_int = RREG32(TN_CG_THERMAL_INT_CTRL) &
                        ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
@@ -4486,27 +4514,27 @@ int evergreen_irq_set(struct radeon_device *rdev)
        }
        if (rdev->irq.hpd[0]) {
                DRM_DEBUG("evergreen_irq_set: hpd 1\n");
-               hpd1 |= DC_HPDx_INT_EN;
+               hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[1]) {
                DRM_DEBUG("evergreen_irq_set: hpd 2\n");
-               hpd2 |= DC_HPDx_INT_EN;
+               hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[2]) {
                DRM_DEBUG("evergreen_irq_set: hpd 3\n");
-               hpd3 |= DC_HPDx_INT_EN;
+               hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[3]) {
                DRM_DEBUG("evergreen_irq_set: hpd 4\n");
-               hpd4 |= DC_HPDx_INT_EN;
+               hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[4]) {
                DRM_DEBUG("evergreen_irq_set: hpd 5\n");
-               hpd5 |= DC_HPDx_INT_EN;
+               hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[5]) {
                DRM_DEBUG("evergreen_irq_set: hpd 6\n");
-               hpd6 |= DC_HPDx_INT_EN;
+               hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.afmt[0]) {
                DRM_DEBUG("evergreen_irq_set: hdmi 0\n");
@@ -4700,6 +4728,38 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
                tmp |= DC_HPDx_INT_ACK;
                WREG32(DC_HPD6_INT_CONTROL, tmp);
        }
+
+       if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD1_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD1_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD2_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD2_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD3_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD3_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD4_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD4_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD5_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD6_INT_CONTROL, tmp);
+       }
+
        if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) {
                tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
                tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
@@ -4780,6 +4840,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
        u32 ring_index;
        bool queue_hotplug = false;
        bool queue_hdmi = false;
+       bool queue_dp = false;
        bool queue_thermal = false;
        u32 status, addr;
 
@@ -5019,6 +5080,48 @@ restart_ih:
                                        DRM_DEBUG("IH: HPD6\n");
                                }
                                break;
+                       case 6:
+                               if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 1\n");
+                               }
+                               break;
+                       case 7:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 2\n");
+                               }
+                               break;
+                       case 8:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 3\n");
+                               }
+                               break;
+                       case 9:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 4\n");
+                               }
+                               break;
+                       case 10:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 5\n");
+                               }
+                               break;
+                       case 11:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 6\n");
+                               }
+                               break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
                                break;
@@ -5151,6 +5254,8 @@ restart_ih:
                rptr &= rdev->ih.ptr_mask;
                WREG32(IH_RB_RPTR, rptr);
        }
+       if (queue_dp)
+               schedule_work(&rdev->dp_work);
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
        if (queue_hdmi)
index a8d1d5240fcb3088d1ea391ebcc8955c46f8c237..4aa5f755572b1593a8b6f7876cf5f7aed183715d 100644 (file)
 #define UVD_UDEC_DBW_ADDR_CONFIG                       0xef54
 #define UVD_RBC_RB_RPTR                                        0xf690
 #define UVD_RBC_RB_WPTR                                        0xf694
+#define UVD_STATUS                                     0xf6bc
 
 /*
  * PM4
index 0e236d067d6648a5a5a17c5a60ead839372d0c0d..2d71da448487d40401e45e80fb4331f247e62249 100644 (file)
@@ -2820,6 +2820,29 @@ void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
        }
 }
 
+u32 kv_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct kv_power_info *pi = kv_get_pi(rdev);
+       u32 current_index =
+               (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) >>
+               CURR_SCLK_INDEX_SHIFT;
+       u32 sclk;
+
+       if (current_index >= SMU__NUM_SCLK_DPM_STATE) {
+               return 0;
+       } else {
+               sclk = be32_to_cpu(pi->graphics_level[current_index].SclkFrequency);
+               return sclk;
+       }
+}
+
+u32 kv_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct kv_power_info *pi = kv_get_pi(rdev);
+
+       return pi->sys_info.bootup_uma_clk;
+}
+
 void kv_dpm_print_power_state(struct radeon_device *rdev,
                              struct radeon_ps *rps)
 {
index dab00812abaabeeeee6295041e730143c99fecba..e8a496ff007ee680d30a2bd688f30d094b58461c 100644 (file)
@@ -828,6 +828,35 @@ out:
        return err;
 }
 
+/**
+ * cayman_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int cayman_get_allowed_info_register(struct radeon_device *rdev,
+                                    u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS_SE0:
+       case GRBM_STATUS_SE1:
+       case SRBM_STATUS:
+       case SRBM_STATUS2:
+       case (DMA_STATUS_REG + DMA0_REGISTER_OFFSET):
+       case (DMA_STATUS_REG + DMA1_REGISTER_OFFSET):
+       case UVD_STATUS:
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 int tn_get_temp(struct radeon_device *rdev)
 {
        u32 temp = RREG32_SMC(TN_CURRENT_GNB_TEMP) & 0x7ff;
index 7bc9f8d9804aa18db5bf63f6e93dc5557bcdce11..c3d531a1114b69b5b882d895c59eb698f6b4e5de 100644 (file)
@@ -4319,6 +4319,42 @@ void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
        }
 }
 
+u32 ni_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct ni_ps *ps = ni_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               return 0;
+       } else {
+               pl = &ps->performance_levels[current_index];
+               return pl->sclk;
+       }
+}
+
+u32 ni_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct ni_ps *ps = ni_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               return 0;
+       } else {
+               pl = &ps->performance_levels[current_index];
+               return pl->mclk;
+       }
+}
+
 u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low)
 {
        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
index 5db7b7d6feb0d2379d076ef8ae80d868a42ae74d..da310a70c0f01b880f8bac9bf7bb2abe6da5d7a1 100644 (file)
 #       define NI_REGAMMA_PROG_B                       4
 #       define NI_OVL_REGAMMA_MODE(x)                  (((x) & 0x7) << 4)
 
+#define NI_DP_MSE_LINK_TIMING                          0x73a0
+#      define NI_DP_MSE_LINK_FRAME                     (((x) & 0x3ff) << 0)
+#      define NI_DP_MSE_LINK_LINE                      (((x) & 0x3) << 16)
+
+#define NI_DP_MSE_MISC_CNTL                            0x736c
+#       define NI_DP_MSE_BLANK_CODE                    (((x) & 0x1) << 0)
+#       define NI_DP_MSE_TIMESTAMP_MODE                (((x) & 0x1) << 4)
+#       define NI_DP_MSE_ZERO_ENCODER                  (((x) & 0x1) << 8)
+
+#define NI_DP_MSE_RATE_CNTL                            0x7384
+#       define NI_DP_MSE_RATE_Y(x)                   (((x) & 0x3ffffff) << 0)
+#       define NI_DP_MSE_RATE_X(x)                   (((x) & 0x3f) << 26)
+
+#define NI_DP_MSE_RATE_UPDATE                          0x738c
+
+#define NI_DP_MSE_SAT0                                 0x7390
+#       define NI_DP_MSE_SAT_SRC0(x)                   (((x) & 0x7) << 0)
+#       define NI_DP_MSE_SAT_SLOT_COUNT0(x)            (((x) & 0x3f) << 8)
+#       define NI_DP_MSE_SAT_SRC1(x)                   (((x) & 0x7) << 16)
+#       define NI_DP_MSE_SAT_SLOT_COUNT1(x)            (((x) & 0x3f) << 24)
+
+#define NI_DP_MSE_SAT1                                 0x7394
+
+#define NI_DP_MSE_SAT2                                 0x7398
+
+#define NI_DP_MSE_SAT_UPDATE                           0x739c
+
+#define NI_DIG_BE_CNTL                                 0x7140
+#       define NI_DIG_FE_SOURCE_SELECT(x)              (((x) & 0x7f) << 8)
+#       define NI_DIG_FE_DIG_MODE(x)                   (((x) & 0x7) << 16)
+#       define NI_DIG_MODE_DP_SST                      0
+#       define NI_DIG_MODE_LVDS                        1
+#       define NI_DIG_MODE_TMDS_DVI                    2
+#       define NI_DIG_MODE_TMDS_HDMI                   3
+#       define NI_DIG_MODE_DP_MST                      5
+#       define NI_DIG_HPD_SELECT(x)                    (((x) & 0x7) << 28)
+
+#define NI_DIG_FE_CNTL                                 0x7000
+#       define NI_DIG_SOURCE_SELECT(x)                 (((x) & 0x3) << 0)
+#       define NI_DIG_STEREOSYNC_SELECT(x)             (((x) & 0x3) << 4)
+#       define NI_DIG_STEREOSYNC_GATE_EN(x)            (((x) & 0x1) << 8)
+#       define NI_DIG_DUAL_LINK_ENABLE(x)              (((x) & 0x1) << 16)
+#       define NI_DIG_SWAP(x)                          (((x) & 0x1) << 18)
+#       define NI_DIG_SYMCLK_FE_ON                     (0x1 << 24)
 #endif
index 6b44580440d09a10053abcb53bf6f6c048d4e063..3b290838918cfc3d04910616c25fd20df810fa89 100644 (file)
 #define MC_PMG_CMD_MRS2                                 0x2b5c
 #define MC_SEQ_PMG_CMD_MRS2_LP                          0x2b60
 
+#define AUX_CONTROL                                    0x6200
+#define        AUX_EN                                  (1 << 0)
+#define        AUX_LS_READ_EN                          (1 << 8)
+#define        AUX_LS_UPDATE_DISABLE(x)                (((x) & 0x1) << 12)
+#define        AUX_HPD_DISCON(x)                       (((x) & 0x1) << 16)
+#define        AUX_DET_EN                              (1 << 18)
+#define        AUX_HPD_SEL(x)                          (((x) & 0x7) << 20)
+#define        AUX_IMPCAL_REQ_EN                       (1 << 24)
+#define        AUX_TEST_MODE                           (1 << 28)
+#define        AUX_DEGLITCH_EN                         (1 << 29)
+#define AUX_SW_CONTROL                                 0x6204
+#define        AUX_SW_GO                               (1 << 0)
+#define        AUX_LS_READ_TRIG                        (1 << 2)
+#define        AUX_SW_START_DELAY(x)                   (((x) & 0xf) << 4)
+#define        AUX_SW_WR_BYTES(x)                      (((x) & 0x1f) << 16)
+
+#define AUX_SW_INTERRUPT_CONTROL                       0x620c
+#define        AUX_SW_DONE_INT                         (1 << 0)
+#define        AUX_SW_DONE_ACK                         (1 << 1)
+#define        AUX_SW_DONE_MASK                        (1 << 2)
+#define        AUX_SW_LS_DONE_INT                      (1 << 4)
+#define        AUX_SW_LS_DONE_MASK                     (1 << 6)
+#define AUX_SW_STATUS                                  0x6210
+#define        AUX_SW_DONE                             (1 << 0)
+#define        AUX_SW_REQ                              (1 << 1)
+#define        AUX_SW_RX_TIMEOUT_STATE(x)              (((x) & 0x7) << 4)
+#define        AUX_SW_RX_TIMEOUT                       (1 << 7)
+#define        AUX_SW_RX_OVERFLOW                      (1 << 8)
+#define        AUX_SW_RX_HPD_DISCON                    (1 << 9)
+#define        AUX_SW_RX_PARTIAL_BYTE                  (1 << 10)
+#define        AUX_SW_NON_AUX_MODE                     (1 << 11)
+#define        AUX_SW_RX_MIN_COUNT_VIOL                (1 << 12)
+#define        AUX_SW_RX_INVALID_STOP                  (1 << 14)
+#define        AUX_SW_RX_SYNC_INVALID_L                (1 << 17)
+#define        AUX_SW_RX_SYNC_INVALID_H                (1 << 18)
+#define        AUX_SW_RX_INVALID_START                 (1 << 19)
+#define        AUX_SW_RX_RECV_NO_DET                   (1 << 20)
+#define        AUX_SW_RX_RECV_INVALID_H                (1 << 22)
+#define        AUX_SW_RX_RECV_INVALID_V                (1 << 23)
+
+#define AUX_SW_DATA                                    0x6218
+#define AUX_SW_DATA_RW                                 (1 << 0)
+#define AUX_SW_DATA_MASK(x)                            (((x) & 0xff) << 8)
+#define AUX_SW_DATA_INDEX(x)                           (((x) & 0x1f) << 16)
+#define AUX_SW_AUTOINCREMENT_DISABLE                   (1 << 31)
+
 #define        LB_SYNC_RESET_SEL                               0x6b28
 #define                LB_SYNC_RESET_SEL_MASK                  (3 << 0)
 #define                LB_SYNC_RESET_SEL_SHIFT                 0
 #define UVD_UDEC_DBW_ADDR_CONFIG                       0xEF54
 #define UVD_RBC_RB_RPTR                                        0xF690
 #define UVD_RBC_RB_WPTR                                        0xF694
+#define UVD_STATUS                                     0xf6bc
 
 /*
  * PM4
index 2fcad344492f526a98b46b34d2979cd9dd5a872e..8f6d862a188228101dc9070f5ab2ada5f819d1a6 100644 (file)
@@ -108,6 +108,32 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev);
 extern int evergreen_rlc_resume(struct radeon_device *rdev);
 extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev);
 
+/**
+ * r600_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int r600_get_allowed_info_register(struct radeon_device *rdev,
+                                  u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS2:
+       case R_000E50_SRBM_STATUS:
+       case DMA_STATUS_REG:
+       case UVD_STATUS:
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 /**
  * r600_get_xclk - get the xclk
  *
index 5587603b4a891c1f2cfcf7873dd8aa9e173907df..35ab65d53cc1cbdd6c7530000b203e4f4f6ef010 100644 (file)
@@ -111,6 +111,8 @@ extern int radeon_deep_color;
 extern int radeon_use_pflipirq;
 extern int radeon_bapm;
 extern int radeon_backlight;
+extern int radeon_auxch;
+extern int radeon_mst;
 
 /*
  * Copy from radeon_drv.h so we don't have to include both and have conflicting
@@ -1856,6 +1858,8 @@ struct radeon_asic {
        u32 (*get_xclk)(struct radeon_device *rdev);
        /* get the gpu clock counter */
        uint64_t (*get_gpu_clock_counter)(struct radeon_device *rdev);
+       /* get register for info ioctl */
+       int (*get_allowed_info_register)(struct radeon_device *rdev, u32 reg, u32 *val);
        /* gart */
        struct {
                void (*tlb_flush)(struct radeon_device *rdev);
@@ -1984,6 +1988,8 @@ struct radeon_asic {
                u32 (*fan_ctrl_get_mode)(struct radeon_device *rdev);
                int (*set_fan_speed_percent)(struct radeon_device *rdev, u32 speed);
                int (*get_fan_speed_percent)(struct radeon_device *rdev, u32 *speed);
+               u32 (*get_current_sclk)(struct radeon_device *rdev);
+               u32 (*get_current_mclk)(struct radeon_device *rdev);
        } dpm;
        /* pageflipping */
        struct {
@@ -2407,6 +2413,7 @@ struct radeon_device {
        struct radeon_rlc rlc;
        struct radeon_mec mec;
        struct work_struct hotplug_work;
+       struct work_struct dp_work;
        struct work_struct audio_work;
        int num_crtc; /* number of crtcs */
        struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
@@ -2931,6 +2938,7 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
 #define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev))
 #define radeon_get_xclk(rdev) (rdev)->asic->get_xclk((rdev))
 #define radeon_get_gpu_clock_counter(rdev) (rdev)->asic->get_gpu_clock_counter((rdev))
+#define radeon_get_allowed_info_register(rdev, r, v) (rdev)->asic->get_allowed_info_register((rdev), (r), (v))
 #define radeon_dpm_init(rdev) rdev->asic->dpm.init((rdev))
 #define radeon_dpm_setup_asic(rdev) rdev->asic->dpm.setup_asic((rdev))
 #define radeon_dpm_enable(rdev) rdev->asic->dpm.enable((rdev))
@@ -2949,6 +2957,8 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
 #define radeon_dpm_vblank_too_short(rdev) rdev->asic->dpm.vblank_too_short((rdev))
 #define radeon_dpm_powergate_uvd(rdev, g) rdev->asic->dpm.powergate_uvd((rdev), (g))
 #define radeon_dpm_enable_bapm(rdev, e) rdev->asic->dpm.enable_bapm((rdev), (e))
+#define radeon_dpm_get_current_sclk(rdev) rdev->asic->dpm.get_current_sclk((rdev))
+#define radeon_dpm_get_current_mclk(rdev) rdev->asic->dpm.get_current_mclk((rdev))
 
 /* Common functions */
 /* AGP */
index c0ecd128b14bf584964b0787637740ff76ba845c..fafd8ce4d58fc6a844b9615aa3b013cf793123c6 100644 (file)
@@ -136,6 +136,11 @@ static void radeon_register_accessor_init(struct radeon_device *rdev)
        }
 }
 
+static int radeon_invalid_get_allowed_info_register(struct radeon_device *rdev,
+                                                   u32 reg, u32 *val)
+{
+       return -EINVAL;
+}
 
 /* helper to disable agp */
 /**
@@ -199,6 +204,7 @@ static struct radeon_asic r100_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r100_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r100_pci_gart_tlb_flush,
                .get_page_entry = &r100_pci_gart_get_page_entry,
@@ -266,6 +272,7 @@ static struct radeon_asic r200_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r100_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r100_pci_gart_tlb_flush,
                .get_page_entry = &r100_pci_gart_get_page_entry,
@@ -361,6 +368,7 @@ static struct radeon_asic r300_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r300_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r100_pci_gart_tlb_flush,
                .get_page_entry = &r100_pci_gart_get_page_entry,
@@ -428,6 +436,7 @@ static struct radeon_asic r300_asic_pcie = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r300_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
                .get_page_entry = &rv370_pcie_gart_get_page_entry,
@@ -495,6 +504,7 @@ static struct radeon_asic r420_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r300_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
                .get_page_entry = &rv370_pcie_gart_get_page_entry,
@@ -562,6 +572,7 @@ static struct radeon_asic rs400_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &rs400_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rs400_gart_tlb_flush,
                .get_page_entry = &rs400_gart_get_page_entry,
@@ -629,6 +640,7 @@ static struct radeon_asic rs600_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &rs600_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rs600_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -696,6 +708,7 @@ static struct radeon_asic rs690_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &rs690_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rs400_gart_tlb_flush,
                .get_page_entry = &rs400_gart_get_page_entry,
@@ -763,6 +776,7 @@ static struct radeon_asic rv515_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &rv515_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
                .get_page_entry = &rv370_pcie_gart_get_page_entry,
@@ -830,6 +844,7 @@ static struct radeon_asic r520_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r520_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
                .get_page_entry = &rv370_pcie_gart_get_page_entry,
@@ -925,6 +940,7 @@ static struct radeon_asic r600_asic = {
        .mc_wait_for_idle = &r600_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = r600_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1009,6 +1025,7 @@ static struct radeon_asic rv6xx_asic = {
        .mc_wait_for_idle = &r600_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = r600_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1080,6 +1097,8 @@ static struct radeon_asic rv6xx_asic = {
                .print_power_state = &rv6xx_dpm_print_power_state,
                .debugfs_print_current_performance_level = &rv6xx_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv6xx_dpm_force_performance_level,
+               .get_current_sclk = &rv6xx_dpm_get_current_sclk,
+               .get_current_mclk = &rv6xx_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &rs600_page_flip,
@@ -1099,6 +1118,7 @@ static struct radeon_asic rs780_asic = {
        .mc_wait_for_idle = &r600_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = r600_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1170,6 +1190,8 @@ static struct radeon_asic rs780_asic = {
                .print_power_state = &rs780_dpm_print_power_state,
                .debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rs780_dpm_force_performance_level,
+               .get_current_sclk = &rs780_dpm_get_current_sclk,
+               .get_current_mclk = &rs780_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &rs600_page_flip,
@@ -1202,6 +1224,7 @@ static struct radeon_asic rv770_asic = {
        .mc_wait_for_idle = &r600_mc_wait_for_idle,
        .get_xclk = &rv770_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = r600_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1274,6 +1297,8 @@ static struct radeon_asic rv770_asic = {
                .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv770_dpm_force_performance_level,
                .vblank_too_short = &rv770_dpm_vblank_too_short,
+               .get_current_sclk = &rv770_dpm_get_current_sclk,
+               .get_current_mclk = &rv770_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &rv770_page_flip,
@@ -1319,6 +1344,7 @@ static struct radeon_asic evergreen_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &rv770_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = evergreen_get_allowed_info_register,
        .gart = {
                .tlb_flush = &evergreen_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1391,6 +1417,8 @@ static struct radeon_asic evergreen_asic = {
                .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv770_dpm_force_performance_level,
                .vblank_too_short = &cypress_dpm_vblank_too_short,
+               .get_current_sclk = &rv770_dpm_get_current_sclk,
+               .get_current_mclk = &rv770_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1410,6 +1438,7 @@ static struct radeon_asic sumo_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = evergreen_get_allowed_info_register,
        .gart = {
                .tlb_flush = &evergreen_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1481,6 +1510,8 @@ static struct radeon_asic sumo_asic = {
                .print_power_state = &sumo_dpm_print_power_state,
                .debugfs_print_current_performance_level = &sumo_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &sumo_dpm_force_performance_level,
+               .get_current_sclk = &sumo_dpm_get_current_sclk,
+               .get_current_mclk = &sumo_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1500,6 +1531,7 @@ static struct radeon_asic btc_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &rv770_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = evergreen_get_allowed_info_register,
        .gart = {
                .tlb_flush = &evergreen_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1572,6 +1604,8 @@ static struct radeon_asic btc_asic = {
                .debugfs_print_current_performance_level = &btc_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv770_dpm_force_performance_level,
                .vblank_too_short = &btc_dpm_vblank_too_short,
+               .get_current_sclk = &btc_dpm_get_current_sclk,
+               .get_current_mclk = &btc_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1634,6 +1668,7 @@ static struct radeon_asic cayman_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &rv770_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = cayman_get_allowed_info_register,
        .gart = {
                .tlb_flush = &cayman_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1717,6 +1752,8 @@ static struct radeon_asic cayman_asic = {
                .debugfs_print_current_performance_level = &ni_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &ni_dpm_force_performance_level,
                .vblank_too_short = &ni_dpm_vblank_too_short,
+               .get_current_sclk = &ni_dpm_get_current_sclk,
+               .get_current_mclk = &ni_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1736,6 +1773,7 @@ static struct radeon_asic trinity_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = cayman_get_allowed_info_register,
        .gart = {
                .tlb_flush = &cayman_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1819,6 +1857,8 @@ static struct radeon_asic trinity_asic = {
                .debugfs_print_current_performance_level = &trinity_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &trinity_dpm_force_performance_level,
                .enable_bapm = &trinity_dpm_enable_bapm,
+               .get_current_sclk = &trinity_dpm_get_current_sclk,
+               .get_current_mclk = &trinity_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1868,6 +1908,7 @@ static struct radeon_asic si_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &si_get_xclk,
        .get_gpu_clock_counter = &si_get_gpu_clock_counter,
+       .get_allowed_info_register = si_get_allowed_info_register,
        .gart = {
                .tlb_flush = &si_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1955,6 +1996,8 @@ static struct radeon_asic si_asic = {
                .fan_ctrl_get_mode = &si_fan_ctrl_get_mode,
                .get_fan_speed_percent = &si_fan_ctrl_get_fan_speed_percent,
                .set_fan_speed_percent = &si_fan_ctrl_set_fan_speed_percent,
+               .get_current_sclk = &si_dpm_get_current_sclk,
+               .get_current_mclk = &si_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -2032,6 +2075,7 @@ static struct radeon_asic ci_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &cik_get_xclk,
        .get_gpu_clock_counter = &cik_get_gpu_clock_counter,
+       .get_allowed_info_register = cik_get_allowed_info_register,
        .gart = {
                .tlb_flush = &cik_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -2123,6 +2167,8 @@ static struct radeon_asic ci_asic = {
                .fan_ctrl_get_mode = &ci_fan_ctrl_get_mode,
                .get_fan_speed_percent = &ci_fan_ctrl_get_fan_speed_percent,
                .set_fan_speed_percent = &ci_fan_ctrl_set_fan_speed_percent,
+               .get_current_sclk = &ci_dpm_get_current_sclk,
+               .get_current_mclk = &ci_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -2142,6 +2188,7 @@ static struct radeon_asic kv_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &cik_get_xclk,
        .get_gpu_clock_counter = &cik_get_gpu_clock_counter,
+       .get_allowed_info_register = cik_get_allowed_info_register,
        .gart = {
                .tlb_flush = &cik_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -2229,6 +2276,8 @@ static struct radeon_asic kv_asic = {
                .force_performance_level = &kv_dpm_force_performance_level,
                .powergate_uvd = &kv_dpm_powergate_uvd,
                .enable_bapm = &kv_dpm_enable_bapm,
+               .get_current_sclk = &kv_dpm_get_current_sclk,
+               .get_current_mclk = &kv_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
index 72bdd3bf0d8e1208e6eace5d4c9cd2735f99e110..cf0a90bb61cab3a7bce074a931440a3d12cfa115 100644 (file)
@@ -384,6 +384,8 @@ u32 r600_gfx_get_wptr(struct radeon_device *rdev,
                      struct radeon_ring *ring);
 void r600_gfx_set_wptr(struct radeon_device *rdev,
                       struct radeon_ring *ring);
+int r600_get_allowed_info_register(struct radeon_device *rdev,
+                                  u32 reg, u32 *val);
 /* r600 irq */
 int r600_irq_process(struct radeon_device *rdev);
 int r600_irq_init(struct radeon_device *rdev);
@@ -433,6 +435,8 @@ void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
                                                       struct seq_file *m);
 int rv6xx_dpm_force_performance_level(struct radeon_device *rdev,
                                      enum radeon_dpm_forced_level level);
+u32 rv6xx_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 rv6xx_dpm_get_current_mclk(struct radeon_device *rdev);
 /* rs780 dpm */
 int rs780_dpm_init(struct radeon_device *rdev);
 int rs780_dpm_enable(struct radeon_device *rdev);
@@ -449,6 +453,8 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
                                                       struct seq_file *m);
 int rs780_dpm_force_performance_level(struct radeon_device *rdev,
                                      enum radeon_dpm_forced_level level);
+u32 rs780_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 rs780_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /*
  * rv770,rv730,rv710,rv740
@@ -488,6 +494,8 @@ void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
 int rv770_dpm_force_performance_level(struct radeon_device *rdev,
                                      enum radeon_dpm_forced_level level);
 bool rv770_dpm_vblank_too_short(struct radeon_device *rdev);
+u32 rv770_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 rv770_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /*
  * evergreen
@@ -540,6 +548,8 @@ struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev,
                                        unsigned num_gpu_pages,
                                        struct reservation_object *resv);
 int evergreen_get_temp(struct radeon_device *rdev);
+int evergreen_get_allowed_info_register(struct radeon_device *rdev,
+                                       u32 reg, u32 *val);
 int sumo_get_temp(struct radeon_device *rdev);
 int tn_get_temp(struct radeon_device *rdev);
 int cypress_dpm_init(struct radeon_device *rdev);
@@ -563,6 +573,8 @@ u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low);
 bool btc_dpm_vblank_too_short(struct radeon_device *rdev);
 void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                                                     struct seq_file *m);
+u32 btc_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 btc_dpm_get_current_mclk(struct radeon_device *rdev);
 int sumo_dpm_init(struct radeon_device *rdev);
 int sumo_dpm_enable(struct radeon_device *rdev);
 int sumo_dpm_late_enable(struct radeon_device *rdev);
@@ -581,6 +593,8 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev
                                                      struct seq_file *m);
 int sumo_dpm_force_performance_level(struct radeon_device *rdev,
                                     enum radeon_dpm_forced_level level);
+u32 sumo_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 sumo_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /*
  * cayman
@@ -637,6 +651,8 @@ uint32_t cayman_dma_get_wptr(struct radeon_device *rdev,
                             struct radeon_ring *ring);
 void cayman_dma_set_wptr(struct radeon_device *rdev,
                         struct radeon_ring *ring);
+int cayman_get_allowed_info_register(struct radeon_device *rdev,
+                                    u32 reg, u32 *val);
 
 int ni_dpm_init(struct radeon_device *rdev);
 void ni_dpm_setup_asic(struct radeon_device *rdev);
@@ -655,6 +671,8 @@ void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
 int ni_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level);
 bool ni_dpm_vblank_too_short(struct radeon_device *rdev);
+u32 ni_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 ni_dpm_get_current_mclk(struct radeon_device *rdev);
 int trinity_dpm_init(struct radeon_device *rdev);
 int trinity_dpm_enable(struct radeon_device *rdev);
 int trinity_dpm_late_enable(struct radeon_device *rdev);
@@ -674,6 +692,8 @@ void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *r
 int trinity_dpm_force_performance_level(struct radeon_device *rdev,
                                        enum radeon_dpm_forced_level level);
 void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
+u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /* DCE6 - SI */
 void dce6_bandwidth_update(struct radeon_device *rdev);
@@ -726,6 +746,8 @@ u32 si_get_xclk(struct radeon_device *rdev);
 uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev);
 int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
 int si_get_temp(struct radeon_device *rdev);
+int si_get_allowed_info_register(struct radeon_device *rdev,
+                                u32 reg, u32 *val);
 int si_dpm_init(struct radeon_device *rdev);
 void si_dpm_setup_asic(struct radeon_device *rdev);
 int si_dpm_enable(struct radeon_device *rdev);
@@ -746,6 +768,8 @@ int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
                                                 u32 speed);
 u32 si_fan_ctrl_get_mode(struct radeon_device *rdev);
 void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode);
+u32 si_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 si_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /* DCE8 - CIK */
 void dce8_bandwidth_update(struct radeon_device *rdev);
@@ -841,6 +865,8 @@ void cik_sdma_set_wptr(struct radeon_device *rdev,
                       struct radeon_ring *ring);
 int ci_get_temp(struct radeon_device *rdev);
 int kv_get_temp(struct radeon_device *rdev);
+int cik_get_allowed_info_register(struct radeon_device *rdev,
+                                 u32 reg, u32 *val);
 
 int ci_dpm_init(struct radeon_device *rdev);
 int ci_dpm_enable(struct radeon_device *rdev);
@@ -862,6 +888,8 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level);
 bool ci_dpm_vblank_too_short(struct radeon_device *rdev);
 void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
+u32 ci_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 ci_dpm_get_current_mclk(struct radeon_device *rdev);
 
 int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
                                                 u32 *speed);
@@ -890,6 +918,8 @@ int kv_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level);
 void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
 void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
+u32 kv_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 kv_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /* uvd v1.0 */
 uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev,
index fc1b3f34cf1827c7498512e7b9f4e36039787d41..8f285244c839a8c85ad186a1b877f94749776a58 100644 (file)
@@ -845,6 +845,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
 
        radeon_link_encoder_connector(dev);
 
+       radeon_setup_mst_connector(dev);
        return true;
 }
 
index b21ef69a34ac2a2703f7adad0ee20a15f07d3509..48d49e651a30cf94212fe2b4482178e7870ed029 100644 (file)
@@ -520,16 +520,40 @@ static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
        struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector = NULL;
        u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
        struct hdmi_avi_infoframe frame;
        int err;
 
+       list_for_each_entry(connector,
+               &encoder->dev->mode_config.connector_list, head) {
+               if (connector->encoder == encoder) {
+                       radeon_connector = to_radeon_connector(connector);
+                       break;
+               }
+       }
+
+       if (!radeon_connector) {
+               DRM_ERROR("Couldn't find encoder's connector\n");
+               return -ENOENT;
+       }
+
        err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
        if (err < 0) {
                DRM_ERROR("failed to setup AVI infoframe: %d\n", err);
                return err;
        }
 
+       if (drm_rgb_quant_range_selectable(radeon_connector_edid(connector))) {
+               if (radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB)
+                       frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED;
+               else
+                       frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
+       } else {
+               frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
+       }
+
        err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
        if (err < 0) {
                DRM_ERROR("failed to pack AVI infoframe: %d\n", err);
index 27def67cb6beb31ca398956cf911ebdc0658755a..7ffa7d5563b9df9bdabd6a1b4afedf76061c371f 100644 (file)
@@ -27,6 +27,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_dp_mst_helper.h>
 #include <drm/radeon_drm.h>
 #include "radeon.h"
 #include "radeon_audio.h"
 
 #include <linux/pm_runtime.h>
 
+static int radeon_dp_handle_hpd(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       int ret;
+
+       ret = radeon_dp_mst_check_status(radeon_connector);
+       if (ret == -EINVAL)
+               return 1;
+       return 0;
+}
 void radeon_connector_hotplug(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 
+       if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+               struct radeon_connector_atom_dig *dig_connector =
+                       radeon_connector->con_priv;
+
+               if (radeon_connector->is_mst_connector)
+                       return;
+               if (dig_connector->is_mst) {
+                       radeon_dp_handle_hpd(connector);
+                       return;
+               }
+       }
        /* bail if the connector does not have hpd pin, e.g.,
         * VGA, TV, etc.
         */
@@ -725,6 +747,30 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct
                radeon_property_change_mode(&radeon_encoder->base);
        }
 
+       if (property == rdev->mode_info.output_csc_property) {
+               if (connector->encoder)
+                       radeon_encoder = to_radeon_encoder(connector->encoder);
+               else {
+                       struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
+                       radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
+               }
+
+               if (radeon_encoder->output_csc == val)
+                       return 0;
+
+               radeon_encoder->output_csc = val;
+
+               if (connector->encoder->crtc) {
+                       struct drm_crtc *crtc  = connector->encoder->crtc;
+                       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+                       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+
+                       radeon_crtc->output_csc = radeon_encoder->output_csc;
+
+                       (*crtc_funcs->load_lut)(crtc);
+               }
+       }
+
        return 0;
 }
 
@@ -1585,6 +1631,9 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
        struct drm_encoder *encoder = radeon_best_single_encoder(connector);
        int r;
 
+       if (radeon_dig_connector->is_mst)
+               return connector_status_disconnected;
+
        r = pm_runtime_get_sync(connector->dev->dev);
        if (r < 0)
                return connector_status_disconnected;
@@ -1643,12 +1692,21 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
                radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
                if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
                        ret = connector_status_connected;
-                       if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
+                       if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
                                radeon_dp_getdpcd(radeon_connector);
+                               r = radeon_dp_mst_probe(radeon_connector);
+                               if (r == 1)
+                                       ret = connector_status_disconnected;
+                       }
                } else {
                        if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
-                               if (radeon_dp_getdpcd(radeon_connector))
-                                       ret = connector_status_connected;
+                               if (radeon_dp_getdpcd(radeon_connector)) {
+                                       r = radeon_dp_mst_probe(radeon_connector);
+                                       if (r == 1)
+                                               ret = connector_status_disconnected;
+                                       else
+                                               ret = connector_status_connected;
+                               }
                        } else {
                                /* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */
                                if (radeon_ddc_probe(radeon_connector, false))
@@ -1872,6 +1930,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                        drm_object_attach_property(&radeon_connector->base.base,
                                                   dev->mode_config.scaling_mode_property,
                                                   DRM_MODE_SCALE_NONE);
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        break;
                case DRM_MODE_CONNECTOR_DVII:
                case DRM_MODE_CONNECTOR_DVID:
@@ -1904,6 +1966,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
 
                        subpixel_order = SubPixelHorizontalRGB;
                        connector->interlace_allowed = true;
@@ -1950,6 +2016,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           dev->mode_config.scaling_mode_property,
                                                           DRM_MODE_SCALE_NONE);
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        /* no HPD on analog connectors */
                        radeon_connector->hpd.hpd = RADEON_HPD_NONE;
                        connector->polled = DRM_CONNECTOR_POLL_CONNECT;
@@ -1972,6 +2042,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           dev->mode_config.scaling_mode_property,
                                                           DRM_MODE_SCALE_NONE);
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        /* no HPD on analog connectors */
                        radeon_connector->hpd.hpd = RADEON_HPD_NONE;
                        connector->interlace_allowed = true;
@@ -2023,6 +2097,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.load_detect_property,
                                                              1);
                        }
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        connector->interlace_allowed = true;
                        if (connector_type == DRM_MODE_CONNECTOR_DVII)
                                connector->doublescan_allowed = true;
@@ -2068,6 +2146,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
                        }
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        subpixel_order = SubPixelHorizontalRGB;
                        connector->interlace_allowed = true;
                        if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
@@ -2116,6 +2198,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
                        }
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        connector->interlace_allowed = true;
                        /* in theory with a DP to VGA converter... */
                        connector->doublescan_allowed = false;
@@ -2352,3 +2438,27 @@ radeon_add_legacy_connector(struct drm_device *dev,
        connector->display_info.subpixel_order = subpixel_order;
        drm_connector_register(connector);
 }
+
+void radeon_setup_mst_connector(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+
+       if (!ASIC_IS_DCE5(rdev))
+               return;
+
+       if (radeon_mst == 0)
+               return;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               int ret;
+
+               radeon_connector = to_radeon_connector(connector);
+
+               if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+                       continue;
+
+               ret = radeon_dp_mst_init(radeon_connector);
+       }
+}
index bd7519fdd3f431cbce8c2bc6bd3e588e525be5cd..b7ca4c51462120fab3ab146dd74f653e8bcb91cb 100644 (file)
@@ -1442,6 +1442,11 @@ int radeon_device_init(struct radeon_device *rdev,
                DRM_ERROR("registering gem debugfs failed (%d).\n", r);
        }
 
+       r = radeon_mst_debugfs_init(rdev);
+       if (r) {
+               DRM_ERROR("registering mst debugfs failed (%d).\n", r);
+       }
+
        if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) {
                /* Acceleration not working on AGP card try again
                 * with fallback to PCI or PCIE GART
index 913fafa597ad210180c03e03618002a702cda441..d2e9e9efc159c053b954aed21840ebe7d91f2739 100644 (file)
@@ -154,7 +154,7 @@ static void dce5_crtc_load_lut(struct drm_crtc *crtc)
               (NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) |
                NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS)));
        WREG32(NI_OUTPUT_CSC_CONTROL + radeon_crtc->crtc_offset,
-              (NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) |
+              (NI_OUTPUT_CSC_GRPH_MODE(radeon_crtc->output_csc) |
                NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS)));
        /* XXX match this to the depth of the crtc fmt block, move to modeset? */
        WREG32(0x6940 + radeon_crtc->crtc_offset, 0);
@@ -1382,6 +1382,13 @@ static struct drm_prop_enum_list radeon_dither_enum_list[] =
        { RADEON_FMT_DITHER_ENABLE, "on" },
 };
 
+static struct drm_prop_enum_list radeon_output_csc_enum_list[] =
+{      { RADEON_OUTPUT_CSC_BYPASS, "bypass" },
+       { RADEON_OUTPUT_CSC_TVRGB, "tvrgb" },
+       { RADEON_OUTPUT_CSC_YCBCR601, "ycbcr601" },
+       { RADEON_OUTPUT_CSC_YCBCR709, "ycbcr709" },
+};
+
 static int radeon_modeset_create_props(struct radeon_device *rdev)
 {
        int sz;
@@ -1444,6 +1451,12 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
                                         "dither",
                                         radeon_dither_enum_list, sz);
 
+       sz = ARRAY_SIZE(radeon_output_csc_enum_list);
+       rdev->mode_info.output_csc_property =
+               drm_property_create_enum(rdev->ddev, 0,
+                                        "output_csc",
+                                        radeon_output_csc_enum_list, sz);
+
        return 0;
 }
 
diff --git a/drivers/gpu/drm/radeon/radeon_dp_auxch.c b/drivers/gpu/drm/radeon/radeon_dp_auxch.c
new file mode 100644 (file)
index 0000000..bf1fecc
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2015 Red Hat Inc.
+ *
+ * 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: Dave Airlie
+ */
+#include <drm/drmP.h>
+#include <drm/radeon_drm.h>
+#include "radeon.h"
+#include "nid.h"
+
+#define AUX_RX_ERROR_FLAGS (AUX_SW_RX_OVERFLOW |            \
+                           AUX_SW_RX_HPD_DISCON |           \
+                           AUX_SW_RX_PARTIAL_BYTE |         \
+                           AUX_SW_NON_AUX_MODE |            \
+                           AUX_SW_RX_MIN_COUNT_VIOL |       \
+                           AUX_SW_RX_INVALID_STOP |         \
+                           AUX_SW_RX_SYNC_INVALID_L |       \
+                           AUX_SW_RX_SYNC_INVALID_H |       \
+                           AUX_SW_RX_INVALID_START |        \
+                           AUX_SW_RX_RECV_NO_DET |          \
+                           AUX_SW_RX_RECV_INVALID_H |       \
+                           AUX_SW_RX_RECV_INVALID_V)
+
+#define AUX_SW_REPLY_GET_BYTE_COUNT(x) (((x) >> 24) & 0x1f)
+
+#define BARE_ADDRESS_SIZE 3
+
+static const u32 aux_offset[] =
+{
+       0x6200 - 0x6200,
+       0x6250 - 0x6200,
+       0x62a0 - 0x6200,
+       0x6300 - 0x6200,
+       0x6350 - 0x6200,
+       0x63a0 - 0x6200,
+};
+
+ssize_t
+radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
+{
+       struct radeon_i2c_chan *chan =
+               container_of(aux, struct radeon_i2c_chan, aux);
+       struct drm_device *dev = chan->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int ret = 0, i;
+       uint32_t tmp, ack = 0;
+       int instance = chan->rec.i2c_id & 0xf;
+       u8 byte;
+       u8 *buf = msg->buffer;
+       int retry_count = 0;
+       int bytes;
+       int msize;
+       bool is_write = false;
+
+       if (WARN_ON(msg->size > 16))
+               return -E2BIG;
+
+       switch (msg->request & ~DP_AUX_I2C_MOT) {
+       case DP_AUX_NATIVE_WRITE:
+       case DP_AUX_I2C_WRITE:
+               is_write = true;
+               break;
+       case DP_AUX_NATIVE_READ:
+       case DP_AUX_I2C_READ:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* work out two sizes required */
+       msize = 0;
+       bytes = BARE_ADDRESS_SIZE;
+       if (msg->size) {
+               msize = msg->size - 1;
+               bytes++;
+               if (is_write)
+                       bytes += msg->size;
+       }
+
+       mutex_lock(&chan->mutex);
+
+       /* switch the pad to aux mode */
+       tmp = RREG32(chan->rec.mask_clk_reg);
+       tmp |= (1 << 16);
+       WREG32(chan->rec.mask_clk_reg, tmp);
+
+       /* setup AUX control register with correct HPD pin */
+       tmp = RREG32(AUX_CONTROL + aux_offset[instance]);
+
+       tmp &= AUX_HPD_SEL(0x7);
+       tmp |= AUX_HPD_SEL(chan->rec.hpd);
+       tmp |= AUX_EN | AUX_LS_READ_EN;
+
+       WREG32(AUX_CONTROL + aux_offset[instance], tmp);
+
+       /* atombios appears to write this twice lets copy it */
+       WREG32(AUX_SW_CONTROL + aux_offset[instance],
+              AUX_SW_WR_BYTES(bytes));
+       WREG32(AUX_SW_CONTROL + aux_offset[instance],
+              AUX_SW_WR_BYTES(bytes));
+
+       /* write the data header into the registers */
+       /* request, addres, msg size */
+       byte = (msg->request << 4);
+       WREG32(AUX_SW_DATA + aux_offset[instance],
+              AUX_SW_DATA_MASK(byte) | AUX_SW_AUTOINCREMENT_DISABLE);
+
+       byte = (msg->address >> 8) & 0xff;
+       WREG32(AUX_SW_DATA + aux_offset[instance],
+              AUX_SW_DATA_MASK(byte));
+
+       byte = msg->address & 0xff;
+       WREG32(AUX_SW_DATA + aux_offset[instance],
+              AUX_SW_DATA_MASK(byte));
+
+       byte = msize;
+       WREG32(AUX_SW_DATA + aux_offset[instance],
+              AUX_SW_DATA_MASK(byte));
+
+       /* if we are writing - write the msg buffer */
+       if (is_write) {
+               for (i = 0; i < msg->size; i++) {
+                       WREG32(AUX_SW_DATA + aux_offset[instance],
+                              AUX_SW_DATA_MASK(buf[i]));
+               }
+       }
+
+       /* clear the ACK */
+       WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK);
+
+       /* write the size and GO bits */
+       WREG32(AUX_SW_CONTROL + aux_offset[instance],
+              AUX_SW_WR_BYTES(bytes) | AUX_SW_GO);
+
+       /* poll the status registers - TODO irq support */
+       do {
+               tmp = RREG32(AUX_SW_STATUS + aux_offset[instance]);
+               if (tmp & AUX_SW_DONE) {
+                       break;
+               }
+               usleep_range(100, 200);
+       } while (retry_count++ < 1000);
+
+       if (retry_count >= 1000) {
+               DRM_ERROR("auxch hw never signalled completion, error %08x\n", tmp);
+               ret = -EIO;
+               goto done;
+       }
+
+       if (tmp & AUX_SW_RX_TIMEOUT) {
+               DRM_DEBUG_KMS("dp_aux_ch timed out\n");
+               ret = -ETIMEDOUT;
+               goto done;
+       }
+       if (tmp & AUX_RX_ERROR_FLAGS) {
+               DRM_DEBUG_KMS("dp_aux_ch flags not zero: %08x\n", tmp);
+               ret = -EIO;
+               goto done;
+       }
+
+       bytes = AUX_SW_REPLY_GET_BYTE_COUNT(tmp);
+       if (bytes) {
+               WREG32(AUX_SW_DATA + aux_offset[instance],
+                      AUX_SW_DATA_RW | AUX_SW_AUTOINCREMENT_DISABLE);
+
+               tmp = RREG32(AUX_SW_DATA + aux_offset[instance]);
+               ack = (tmp >> 8) & 0xff;
+
+               for (i = 0; i < bytes - 1; i++) {
+                       tmp = RREG32(AUX_SW_DATA + aux_offset[instance]);
+                       if (buf)
+                               buf[i] = (tmp >> 8) & 0xff;
+               }
+               if (buf)
+                       ret = bytes - 1;
+       }
+
+       WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK);
+
+       if (is_write)
+               ret = msg->size;
+done:
+       mutex_unlock(&chan->mutex);
+
+       if (ret >= 0)
+               msg->reply = ack >> 4;
+       return ret;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c
new file mode 100644 (file)
index 0000000..5952ff2
--- /dev/null
@@ -0,0 +1,782 @@
+
+#include <drm/drmP.h>
+#include <drm/drm_dp_mst_helper.h>
+#include <drm/drm_fb_helper.h>
+
+#include "radeon.h"
+#include "atom.h"
+#include "ni_reg.h"
+
+static struct radeon_encoder *radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector);
+
+static int radeon_atom_set_enc_offset(int id)
+{
+       static const int offsets[] = { EVERGREEN_CRTC0_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC1_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC2_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC3_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC4_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC5_REGISTER_OFFSET,
+                                      0x13830 - 0x7030 };
+
+       return offsets[id];
+}
+
+static int radeon_dp_mst_set_be_cntl(struct radeon_encoder *primary,
+                                    struct radeon_encoder_mst *mst_enc,
+                                    enum radeon_hpd_id hpd, bool enable)
+{
+       struct drm_device *dev = primary->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t reg;
+       int retries = 0;
+       uint32_t temp;
+
+       reg = RREG32(NI_DIG_BE_CNTL + primary->offset);
+
+       /* set MST mode */
+       reg &= ~NI_DIG_FE_DIG_MODE(7);
+       reg |= NI_DIG_FE_DIG_MODE(NI_DIG_MODE_DP_MST);
+
+       if (enable)
+               reg |= NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe);
+       else
+               reg &= ~NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe);
+
+       reg |= NI_DIG_HPD_SELECT(hpd);
+       DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DIG_BE_CNTL + primary->offset, reg);
+       WREG32(NI_DIG_BE_CNTL + primary->offset, reg);
+
+       if (enable) {
+               uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe);
+
+               do {
+                       temp = RREG32(NI_DIG_FE_CNTL + offset);
+               } while ((temp & NI_DIG_SYMCLK_FE_ON) && retries++ < 10000);
+               if (retries == 10000)
+                       DRM_ERROR("timed out waiting for FE %d %d\n", primary->offset, mst_enc->fe);
+       }
+       return 0;
+}
+
+static int radeon_dp_mst_set_stream_attrib(struct radeon_encoder *primary,
+                                          int stream_number,
+                                          int fe,
+                                          int slots)
+{
+       struct drm_device *dev = primary->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       u32 temp, val;
+       int retries  = 0;
+       int satreg, satidx;
+
+       satreg = stream_number >> 1;
+       satidx = stream_number & 1;
+
+       temp = RREG32(NI_DP_MSE_SAT0 + satreg + primary->offset);
+
+       val = NI_DP_MSE_SAT_SLOT_COUNT0(slots) | NI_DP_MSE_SAT_SRC0(fe);
+
+       val <<= (16 * satidx);
+
+       temp &= ~(0xffff << (16 * satidx));
+
+       temp |= val;
+
+       DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DP_MSE_SAT0 + satreg + primary->offset, temp);
+       WREG32(NI_DP_MSE_SAT0 + satreg + primary->offset, temp);
+
+       WREG32(NI_DP_MSE_SAT_UPDATE + primary->offset, 1);
+
+       do {
+               temp = RREG32(NI_DP_MSE_SAT_UPDATE + primary->offset);
+       } while ((temp & 0x1) && retries++ < 10000);
+
+       if (retries == 10000)
+               DRM_ERROR("timed out waitin for SAT update %d\n", primary->offset);
+
+       /* MTP 16 ? */
+       return 0;
+}
+
+static int radeon_dp_mst_update_stream_attribs(struct radeon_connector *mst_conn,
+                                              struct radeon_encoder *primary)
+{
+       struct drm_device *dev = mst_conn->base.dev;
+       struct stream_attribs new_attribs[6];
+       int i;
+       int idx = 0;
+       struct radeon_connector *radeon_connector;
+       struct drm_connector *connector;
+
+       memset(new_attribs, 0, sizeof(new_attribs));
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct radeon_encoder *subenc;
+               struct radeon_encoder_mst *mst_enc;
+
+               radeon_connector = to_radeon_connector(connector);
+               if (!radeon_connector->is_mst_connector)
+                       continue;
+
+               if (radeon_connector->mst_port != mst_conn)
+                       continue;
+
+               subenc = radeon_connector->mst_encoder;
+               mst_enc = subenc->enc_priv;
+
+               if (!mst_enc->enc_active)
+                       continue;
+
+               new_attribs[idx].fe = mst_enc->fe;
+               new_attribs[idx].slots = drm_dp_mst_get_vcpi_slots(&mst_conn->mst_mgr, mst_enc->port);
+               idx++;
+       }
+
+       for (i = 0; i < idx; i++) {
+               if (new_attribs[i].fe != mst_conn->cur_stream_attribs[i].fe ||
+                   new_attribs[i].slots != mst_conn->cur_stream_attribs[i].slots) {
+                       radeon_dp_mst_set_stream_attrib(primary, i, new_attribs[i].fe, new_attribs[i].slots);
+                       mst_conn->cur_stream_attribs[i].fe = new_attribs[i].fe;
+                       mst_conn->cur_stream_attribs[i].slots = new_attribs[i].slots;
+               }
+       }
+
+       for (i = idx; i < mst_conn->enabled_attribs; i++) {
+               radeon_dp_mst_set_stream_attrib(primary, i, 0, 0);
+               mst_conn->cur_stream_attribs[i].fe = 0;
+               mst_conn->cur_stream_attribs[i].slots = 0;
+       }
+       mst_conn->enabled_attribs = idx;
+       return 0;
+}
+
+static int radeon_dp_mst_set_vcp_size(struct radeon_encoder *mst, uint32_t x, uint32_t y)
+{
+       struct drm_device *dev = mst->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder_mst *mst_enc = mst->enc_priv;
+       uint32_t val, temp;
+       uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe);
+       int retries = 0;
+
+       val = NI_DP_MSE_RATE_X(x) | NI_DP_MSE_RATE_Y(y);
+
+       WREG32(NI_DP_MSE_RATE_CNTL + offset, val);
+
+       do {
+               temp = RREG32(NI_DP_MSE_RATE_UPDATE + offset);
+       } while ((temp & 0x1) && (retries++ < 10000));
+
+       if (retries >= 10000)
+               DRM_ERROR("timed out wait for rate cntl %d\n", mst_enc->fe);
+       return 0;
+}
+
+static int radeon_dp_mst_get_ddc_modes(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector *master = radeon_connector->mst_port;
+       struct edid *edid;
+       int ret = 0;
+
+       edid = drm_dp_mst_get_edid(connector, &master->mst_mgr, radeon_connector->port);
+       radeon_connector->edid = edid;
+       DRM_DEBUG_KMS("edid retrieved %p\n", edid);
+       if (radeon_connector->edid) {
+               drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
+               ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
+               drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid);
+               return ret;
+       }
+       drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
+
+       return ret;
+}
+
+static int radeon_dp_mst_get_modes(struct drm_connector *connector)
+{
+       return radeon_dp_mst_get_ddc_modes(connector);
+}
+
+static enum drm_mode_status
+radeon_dp_mst_mode_valid(struct drm_connector *connector,
+                       struct drm_display_mode *mode)
+{
+       /* TODO - validate mode against available PBN for link */
+       if (mode->clock < 10000)
+               return MODE_CLOCK_LOW;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+               return MODE_H_ILLEGAL;
+
+       return MODE_OK;
+}
+
+struct drm_encoder *radeon_mst_best_encoder(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+
+       return &radeon_connector->mst_encoder->base;
+}
+
+static const struct drm_connector_helper_funcs radeon_dp_mst_connector_helper_funcs = {
+       .get_modes = radeon_dp_mst_get_modes,
+       .mode_valid = radeon_dp_mst_mode_valid,
+       .best_encoder = radeon_mst_best_encoder,
+};
+
+static enum drm_connector_status
+radeon_dp_mst_detect(struct drm_connector *connector, bool force)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector *master = radeon_connector->mst_port;
+
+       return drm_dp_mst_detect_port(connector, &master->mst_mgr, radeon_connector->port);
+}
+
+static void
+radeon_dp_mst_connector_destroy(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_encoder *radeon_encoder = radeon_connector->mst_encoder;
+
+       drm_encoder_cleanup(&radeon_encoder->base);
+       kfree(radeon_encoder);
+       drm_connector_cleanup(connector);
+       kfree(radeon_connector);
+}
+
+static void radeon_connector_dpms(struct drm_connector *connector, int mode)
+{
+       DRM_DEBUG_KMS("\n");
+}
+
+static const struct drm_connector_funcs radeon_dp_mst_connector_funcs = {
+       .dpms = radeon_connector_dpms,
+       .detect = radeon_dp_mst_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = radeon_dp_mst_connector_destroy,
+};
+
+static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
+                                                        struct drm_dp_mst_port *port,
+                                                        const char *pathprop)
+{
+       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;
+
+       radeon_connector = kzalloc(sizeof(*radeon_connector), GFP_KERNEL);
+       if (!radeon_connector)
+               return NULL;
+
+       radeon_connector->is_mst_connector = true;
+       connector = &radeon_connector->base;
+       radeon_connector->port = port;
+       radeon_connector->mst_port = master;
+       DRM_DEBUG_KMS("\n");
+
+       drm_connector_init(dev, connector, &radeon_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort);
+       drm_connector_helper_add(connector, &radeon_dp_mst_connector_helper_funcs);
+       radeon_connector->mst_encoder = radeon_dp_create_fake_mst_encoder(master);
+
+       drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
+       drm_mode_connector_set_path_property(connector, pathprop);
+       drm_reinit_primary_mode_group(dev);
+
+       mutex_lock(&dev->mode_config.mutex);
+       radeon_fb_add_connector(rdev, connector);
+       mutex_unlock(&dev->mode_config.mutex);
+
+       drm_connector_register(connector);
+       return connector;
+}
+
+static void radeon_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
+                                           struct drm_connector *connector)
+{
+       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;
+
+       drm_connector_unregister(connector);
+       /* need to nuke the connector */
+       mutex_lock(&dev->mode_config.mutex);
+       /* dpms off */
+       radeon_fb_remove_connector(rdev, connector);
+
+       drm_connector_cleanup(connector);
+       mutex_unlock(&dev->mode_config.mutex);
+       drm_reinit_primary_mode_group(dev);
+
+
+       kfree(connector);
+       DRM_DEBUG_KMS("\n");
+}
+
+static void radeon_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
+{
+       struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
+       struct drm_device *dev = master->base.dev;
+
+       drm_kms_helper_hotplug_event(dev);
+}
+
+struct drm_dp_mst_topology_cbs mst_cbs = {
+       .add_connector = radeon_dp_add_mst_connector,
+       .destroy_connector = radeon_dp_destroy_mst_connector,
+       .hotplug = radeon_dp_mst_hotplug,
+};
+
+struct radeon_connector *radeon_mst_find_connector(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_connector *connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+               if (!connector->encoder)
+                       continue;
+               if (!radeon_connector->is_mst_connector)
+                       continue;
+
+               DRM_DEBUG_KMS("checking %p vs %p\n", connector->encoder, encoder);
+               if (connector->encoder == encoder)
+                       return radeon_connector;
+       }
+       return NULL;
+}
+
+void radeon_dp_mst_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(radeon_crtc->encoder);
+       struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv;
+       struct radeon_connector *radeon_connector = radeon_mst_find_connector(&radeon_encoder->base);
+       int dp_clock;
+       struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv;
+
+       if (radeon_connector) {
+               radeon_connector->pixelclock_for_modeset = mode->clock;
+               if (radeon_connector->base.display_info.bpc)
+                       radeon_crtc->bpc = radeon_connector->base.display_info.bpc;
+               else
+                       radeon_crtc->bpc = 8;
+       }
+
+       DRM_DEBUG_KMS("dp_clock %p %d\n", dig_connector, dig_connector->dp_clock);
+       dp_clock = dig_connector->dp_clock;
+       radeon_crtc->ss_enabled =
+               radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss,
+                                                ASIC_INTERNAL_SS_ON_DP,
+                                                dp_clock);
+}
+
+static void
+radeon_mst_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder, *primary;
+       struct radeon_encoder_mst *mst_enc;
+       struct radeon_encoder_atom_dig *dig_enc;
+       struct radeon_connector *radeon_connector;
+       struct drm_crtc *crtc;
+       struct radeon_crtc *radeon_crtc;
+       int ret, slots;
+
+       if (!ASIC_IS_DCE5(rdev)) {
+               DRM_ERROR("got mst dpms on non-DCE5\n");
+               return;
+       }
+
+       radeon_connector = radeon_mst_find_connector(encoder);
+       if (!radeon_connector)
+               return;
+
+       radeon_encoder = to_radeon_encoder(encoder);
+
+       mst_enc = radeon_encoder->enc_priv;
+
+       primary = mst_enc->primary;
+
+       dig_enc = primary->enc_priv;
+
+       crtc = encoder->crtc;
+       DRM_DEBUG_KMS("got connector %d\n", dig_enc->active_mst_links);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               dig_enc->active_mst_links++;
+
+               radeon_crtc = to_radeon_crtc(crtc);
+
+               if (dig_enc->active_mst_links == 1) {
+                       mst_enc->fe = dig_enc->dig_encoder;
+                       mst_enc->fe_from_be = true;
+                       atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe);
+
+                       atombios_dig_encoder_setup(&primary->base, ATOM_ENCODER_CMD_SETUP, 0);
+                       atombios_dig_transmitter_setup2(&primary->base, ATOM_TRANSMITTER_ACTION_ENABLE,
+                                                       0, 0, dig_enc->dig_encoder);
+
+                       if (radeon_dp_needs_link_train(mst_enc->connector) ||
+                           dig_enc->active_mst_links == 1) {
+                               radeon_dp_link_train(&primary->base, &mst_enc->connector->base);
+                       }
+
+               } else {
+                       mst_enc->fe = radeon_atom_pick_dig_encoder(encoder, radeon_crtc->crtc_id);
+                       if (mst_enc->fe == -1)
+                               DRM_ERROR("failed to get frontend for dig encoder\n");
+                       mst_enc->fe_from_be = false;
+                       atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe);
+               }
+
+               DRM_DEBUG_KMS("dig encoder is %d %d %d\n", dig_enc->dig_encoder,
+                             dig_enc->linkb, radeon_crtc->crtc_id);
+
+               ret = drm_dp_mst_allocate_vcpi(&radeon_connector->mst_port->mst_mgr,
+                                              radeon_connector->port,
+                                              mst_enc->pbn, &slots);
+               ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr);
+
+               radeon_dp_mst_set_be_cntl(primary, mst_enc,
+                                         radeon_connector->mst_port->hpd.hpd, true);
+
+               mst_enc->enc_active = true;
+               radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary);
+               radeon_dp_mst_set_vcp_size(radeon_encoder, slots, 0);
+
+               atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0,
+                                           mst_enc->fe);
+               ret = drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr);
+
+               ret = drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr);
+
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               DRM_ERROR("DPMS OFF %d\n", dig_enc->active_mst_links);
+
+               if (!mst_enc->enc_active)
+                       return;
+
+               drm_dp_mst_reset_vcpi_slots(&radeon_connector->mst_port->mst_mgr, mst_enc->port);
+               ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr);
+
+               drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr);
+               /* and this can also fail */
+               drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr);
+
+               drm_dp_mst_deallocate_vcpi(&radeon_connector->mst_port->mst_mgr, mst_enc->port);
+
+               mst_enc->enc_active = false;
+               radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary);
+
+               radeon_dp_mst_set_be_cntl(primary, mst_enc,
+                                         radeon_connector->mst_port->hpd.hpd, false);
+               atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0,
+                                           mst_enc->fe);
+
+               if (!mst_enc->fe_from_be)
+                       radeon_atom_release_dig_encoder(rdev, mst_enc->fe);
+
+               mst_enc->fe_from_be = false;
+               dig_enc->active_mst_links--;
+               if (dig_enc->active_mst_links == 0) {
+                       /* drop link */
+               }
+
+               break;
+       }
+
+}
+
+static bool radeon_mst_mode_fixup(struct drm_encoder *encoder,
+                                  const struct drm_display_mode *mode,
+                                  struct drm_display_mode *adjusted_mode)
+{
+       struct radeon_encoder_mst *mst_enc;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       int bpp = 24;
+
+       mst_enc = radeon_encoder->enc_priv;
+
+       mst_enc->pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp);
+
+       mst_enc->primary->active_device = mst_enc->primary->devices & mst_enc->connector->devices;
+       DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n",
+                     mst_enc->primary->active_device, mst_enc->primary->devices,
+                     mst_enc->connector->devices, mst_enc->primary->base.encoder_type);
+
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+       {
+         struct radeon_connector_atom_dig *dig_connector;
+
+         dig_connector = mst_enc->connector->con_priv;
+         dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd);
+         dig_connector->dp_clock = radeon_dp_get_max_link_rate(&mst_enc->connector->base,
+                                                               dig_connector->dpcd);
+         DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
+                       dig_connector->dp_lane_count, dig_connector->dp_clock);
+       }
+       return true;
+}
+
+static void radeon_mst_encoder_prepare(struct drm_encoder *encoder)
+{
+       struct radeon_connector *radeon_connector;
+       struct radeon_encoder *radeon_encoder, *primary;
+       struct radeon_encoder_mst *mst_enc;
+       struct radeon_encoder_atom_dig *dig_enc;
+
+       radeon_connector = radeon_mst_find_connector(encoder);
+       if (!radeon_connector) {
+               DRM_DEBUG_KMS("failed to find connector %p\n", encoder);
+               return;
+       }
+       radeon_encoder = to_radeon_encoder(encoder);
+
+       radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+       mst_enc = radeon_encoder->enc_priv;
+
+       primary = mst_enc->primary;
+
+       dig_enc = primary->enc_priv;
+
+       mst_enc->port = radeon_connector->port;
+
+       if (dig_enc->dig_encoder == -1) {
+               dig_enc->dig_encoder = radeon_atom_pick_dig_encoder(&primary->base, -1);
+               primary->offset = radeon_atom_set_enc_offset(dig_enc->dig_encoder);
+               atombios_set_mst_encoder_crtc_source(encoder, dig_enc->dig_encoder);
+
+
+       }
+       DRM_DEBUG_KMS("%d %d\n", dig_enc->dig_encoder, primary->offset);
+}
+
+static void
+radeon_mst_encoder_mode_set(struct drm_encoder *encoder,
+                            struct drm_display_mode *mode,
+                            struct drm_display_mode *adjusted_mode)
+{
+       DRM_DEBUG_KMS("\n");
+}
+
+static void radeon_mst_encoder_commit(struct drm_encoder *encoder)
+{
+       radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+       DRM_DEBUG_KMS("\n");
+}
+
+static const struct drm_encoder_helper_funcs radeon_mst_helper_funcs = {
+       .dpms = radeon_mst_encoder_dpms,
+       .mode_fixup = radeon_mst_mode_fixup,
+       .prepare = radeon_mst_encoder_prepare,
+       .mode_set = radeon_mst_encoder_mode_set,
+       .commit = radeon_mst_encoder_commit,
+};
+
+void radeon_dp_mst_encoder_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+       kfree(encoder);
+}
+
+static const struct drm_encoder_funcs radeon_dp_mst_enc_funcs = {
+       .destroy = radeon_dp_mst_encoder_destroy,
+};
+
+static struct radeon_encoder *
+radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder;
+       struct radeon_encoder_mst *mst_enc;
+       struct drm_encoder *encoder;
+       struct drm_connector_helper_funcs *connector_funcs = connector->base.helper_private;
+       struct drm_encoder *enc_master = connector_funcs->best_encoder(&connector->base);
+
+       DRM_DEBUG_KMS("enc master is %p\n", enc_master);
+       radeon_encoder = kzalloc(sizeof(*radeon_encoder), GFP_KERNEL);
+       if (!radeon_encoder)
+               return NULL;
+
+       radeon_encoder->enc_priv = kzalloc(sizeof(*mst_enc), GFP_KERNEL);
+       if (!radeon_encoder->enc_priv) {
+               kfree(radeon_encoder);
+               return NULL;
+       }
+       encoder = &radeon_encoder->base;
+       switch (rdev->num_crtc) {
+       case 1:
+               encoder->possible_crtcs = 0x1;
+               break;
+       case 2:
+       default:
+               encoder->possible_crtcs = 0x3;
+               break;
+       case 4:
+               encoder->possible_crtcs = 0xf;
+               break;
+       case 6:
+               encoder->possible_crtcs = 0x3f;
+               break;
+       }
+
+       drm_encoder_init(dev, &radeon_encoder->base, &radeon_dp_mst_enc_funcs,
+                        DRM_MODE_ENCODER_DPMST);
+       drm_encoder_helper_add(encoder, &radeon_mst_helper_funcs);
+
+       mst_enc = radeon_encoder->enc_priv;
+       mst_enc->connector = connector;
+       mst_enc->primary = to_radeon_encoder(enc_master);
+       radeon_encoder->is_mst_encoder = true;
+       return radeon_encoder;
+}
+
+int
+radeon_dp_mst_init(struct radeon_connector *radeon_connector)
+{
+       struct drm_device *dev = radeon_connector->base.dev;
+
+       if (!radeon_connector->ddc_bus->has_aux)
+               return 0;
+
+       radeon_connector->mst_mgr.cbs = &mst_cbs;
+       return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev->dev,
+                                           &radeon_connector->ddc_bus->aux, 16, 6,
+                                           radeon_connector->base.base.id);
+}
+
+int
+radeon_dp_mst_probe(struct radeon_connector *radeon_connector)
+{
+       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       int ret;
+       u8 msg[1];
+
+       if (dig_connector->dpcd[DP_DPCD_REV] < 0x12)
+               return 0;
+
+       ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_MSTM_CAP, msg,
+                              1);
+       if (ret) {
+               if (msg[0] & DP_MST_CAP) {
+                       DRM_DEBUG_KMS("Sink is MST capable\n");
+                       dig_connector->is_mst = true;
+               } else {
+                       DRM_DEBUG_KMS("Sink is not MST capable\n");
+                       dig_connector->is_mst = false;
+               }
+
+       }
+       drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr,
+                                       dig_connector->is_mst);
+       return dig_connector->is_mst;
+}
+
+int
+radeon_dp_mst_check_status(struct radeon_connector *radeon_connector)
+{
+       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       int retry;
+
+       if (dig_connector->is_mst) {
+               u8 esi[16] = { 0 };
+               int dret;
+               int ret = 0;
+               bool handled;
+
+               dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux,
+                                      DP_SINK_COUNT_ESI, esi, 8);
+go_again:
+               if (dret == 8) {
+                       DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+                       ret = drm_dp_mst_hpd_irq(&radeon_connector->mst_mgr, esi, &handled);
+
+                       if (handled) {
+                               for (retry = 0; retry < 3; retry++) {
+                                       int wret;
+                                       wret = drm_dp_dpcd_write(&radeon_connector->ddc_bus->aux,
+                                                                DP_SINK_COUNT_ESI + 1, &esi[1], 3);
+                                       if (wret == 3)
+                                               break;
+                               }
+
+                               dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux,
+                                                       DP_SINK_COUNT_ESI, esi, 8);
+                               if (dret == 8) {
+                                       DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+                                       goto go_again;
+                               }
+                       } else
+                               ret = 0;
+
+                       return ret;
+               } else {
+                       DRM_DEBUG_KMS("failed to get ESI - device may have failed %d\n", ret);
+                       dig_connector->is_mst = false;
+                       drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr,
+                                                       dig_connector->is_mst);
+                       /* send a hotplug event */
+               }
+       }
+       return -EINVAL;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+
+static int radeon_debugfs_mst_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *)m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+       struct radeon_connector_atom_dig *dig_connector;
+       int i;
+
+       drm_modeset_lock_all(dev);
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+                       continue;
+
+               radeon_connector = to_radeon_connector(connector);
+               dig_connector = radeon_connector->con_priv;
+               if (radeon_connector->is_mst_connector)
+                       continue;
+               if (!dig_connector->is_mst)
+                       continue;
+               drm_dp_mst_dump_topology(m, &radeon_connector->mst_mgr);
+
+               for (i = 0; i < radeon_connector->enabled_attribs; i++)
+                       seq_printf(m, "attrib %d: %d %d\n", i,
+                                  radeon_connector->cur_stream_attribs[i].fe,
+                                  radeon_connector->cur_stream_attribs[i].slots);
+       }
+       drm_modeset_unlock_all(dev);
+       return 0;
+}
+
+static struct drm_info_list radeon_debugfs_mst_list[] = {
+       {"radeon_mst_info", &radeon_debugfs_mst_info, 0, NULL},
+};
+#endif
+
+int radeon_mst_debugfs_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       return radeon_debugfs_add_files(rdev, radeon_debugfs_mst_list, 1);
+#endif
+       return 0;
+}
index 5d684beb48d32b9597fc604f6dee6790953fbf70..d688f6cd1ae4500a0de3741d35a0a7275489998f 100644 (file)
@@ -190,6 +190,8 @@ int radeon_deep_color = 0;
 int radeon_use_pflipirq = 2;
 int radeon_bapm = -1;
 int radeon_backlight = -1;
+int radeon_auxch = -1;
+int radeon_mst = 0;
 
 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -239,7 +241,7 @@ module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444);
 MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)");
 module_param_named(msi, radeon_msi, int, 0444);
 
-MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (defaul 10000 = 10 seconds, 0 = disable)");
+MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (default 10000 = 10 seconds, 0 = disable)");
 module_param_named(lockup_timeout, radeon_lockup_timeout, int, 0444);
 
 MODULE_PARM_DESC(fastfb, "Direct FB access for IGP chips (0 = disable, 1 = enable)");
@@ -275,6 +277,12 @@ module_param_named(bapm, radeon_bapm, int, 0444);
 MODULE_PARM_DESC(backlight, "backlight support (1 = enable, 0 = disable, -1 = auto)");
 module_param_named(backlight, radeon_backlight, int, 0444);
 
+MODULE_PARM_DESC(auxch, "Use native auxch experimental support (1 = enable, 0 = disable, -1 = auto)");
+module_param_named(auxch, radeon_auxch, int, 0444);
+
+MODULE_PARM_DESC(mst, "DisplayPort MST experimental support (1 = enable, 0 = disable)");
+module_param_named(mst, radeon_mst, int, 0444);
+
 static struct pci_device_id pciidlist[] = {
        radeon_PCI_IDS
 };
index 3a297037cc176250fff7b1dae4a2566a8fd3c1ca..ef99917f000d96a7dcf3fc88f089bdf08e0afc28 100644 (file)
@@ -247,7 +247,16 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder)
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                radeon_connector = to_radeon_connector(connector);
-               if (radeon_encoder->active_device & radeon_connector->devices)
+               if (radeon_encoder->is_mst_encoder) {
+                       struct radeon_encoder_mst *mst_enc;
+
+                       if (!radeon_connector->is_mst_connector)
+                               continue;
+
+                       mst_enc = radeon_encoder->enc_priv;
+                       if (mst_enc->connector == radeon_connector->mst_port)
+                               return connector;
+               } else if (radeon_encoder->active_device & radeon_connector->devices)
                        return connector;
        }
        return NULL;
@@ -393,6 +402,9 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
        case DRM_MODE_CONNECTOR_DVID:
        case DRM_MODE_CONNECTOR_HDMIA:
        case DRM_MODE_CONNECTOR_DisplayPort:
+               if (radeon_connector->is_mst_connector)
+                       return false;
+
                dig_connector = radeon_connector->con_priv;
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
                    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
index ea276ff6d174283d0fee755530c90ea36c6d526d..aeb676708e60cfb1871326bfc5a689631bb98741 100644 (file)
@@ -257,6 +257,7 @@ static int radeonfb_create(struct drm_fb_helper *helper,
        }
 
        info->par = rfbdev;
+       info->skip_vt_switch = true;
 
        ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
        if (ret) {
@@ -434,3 +435,13 @@ bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
                return true;
        return false;
 }
+
+void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector)
+{
+       drm_fb_helper_add_one_connector(&rdev->mode_info.rfbdev->helper, connector);
+}
+
+void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector)
+{
+       drm_fb_helper_remove_one_connector(&rdev->mode_info.rfbdev->helper, connector);
+}
index 00fc59762e0df3bba0758d1f18e90328e5726635..7162c935371c66a3abcf3fcf3734c1d234e3bb37 100644 (file)
@@ -87,6 +87,20 @@ static void radeon_hotplug_work_func(struct work_struct *work)
        drm_helper_hpd_irq_event(dev);
 }
 
+static void radeon_dp_work_func(struct work_struct *work)
+{
+       struct radeon_device *rdev = container_of(work, struct radeon_device,
+                                                 dp_work);
+       struct drm_device *dev = rdev->ddev;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_connector *connector;
+
+       /* this should take a mutex */
+       if (mode_config->num_connector) {
+               list_for_each_entry(connector, &mode_config->connector_list, head)
+                       radeon_connector_hotplug(connector);
+       }
+}
 /**
  * radeon_driver_irq_preinstall_kms - drm irq preinstall callback
  *
@@ -276,6 +290,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
        }
 
        INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
+       INIT_WORK(&rdev->dp_work, radeon_dp_work_func);
        INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
 
        rdev->irq.installed = true;
index 122eb5693ba191a7458a3496e6bb96b06aee1ac7..3db23007cdf469c8ee9271d23b25a4bbd078d2e6 100644 (file)
@@ -103,15 +103,14 @@ static const struct kgd2kfd_calls *kgd2kfd;
 bool radeon_kfd_init(void)
 {
 #if defined(CONFIG_HSA_AMD_MODULE)
-       bool (*kgd2kfd_init_p)(unsigned, const struct kfd2kgd_calls*,
-                               const struct kgd2kfd_calls**);
+       bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**);
 
        kgd2kfd_init_p = symbol_request(kgd2kfd_init);
 
        if (kgd2kfd_init_p == NULL)
                return false;
 
-       if (!kgd2kfd_init_p(KFD_INTERFACE_VERSION, &kfd2kgd, &kgd2kfd)) {
+       if (!kgd2kfd_init_p(KFD_INTERFACE_VERSION, &kgd2kfd)) {
                symbol_put(kgd2kfd_init);
                kgd2kfd = NULL;
 
@@ -120,7 +119,7 @@ bool radeon_kfd_init(void)
 
        return true;
 #elif defined(CONFIG_HSA_AMD)
-       if (!kgd2kfd_init(KFD_INTERFACE_VERSION, &kfd2kgd, &kgd2kfd)) {
+       if (!kgd2kfd_init(KFD_INTERFACE_VERSION, &kgd2kfd)) {
                kgd2kfd = NULL;
 
                return false;
@@ -143,7 +142,8 @@ void radeon_kfd_fini(void)
 void radeon_kfd_device_probe(struct radeon_device *rdev)
 {
        if (kgd2kfd)
-               rdev->kfd = kgd2kfd->probe((struct kgd_dev *)rdev, rdev->pdev);
+               rdev->kfd = kgd2kfd->probe((struct kgd_dev *)rdev,
+                       rdev->pdev, &kfd2kgd);
 }
 
 void radeon_kfd_device_init(struct radeon_device *rdev)
index 686411e4e4f6a3620289be34106ae5d38c9f6b93..7b2a7335cc5d557eafa6864d50cb6ebc9cdfb5ff 100644 (file)
@@ -547,6 +547,35 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                else
                        *value = 1;
                break;
+       case RADEON_INFO_CURRENT_GPU_TEMP:
+               /* get temperature in millidegrees C */
+               if (rdev->asic->pm.get_temperature)
+                       *value = radeon_get_temperature(rdev);
+               else
+                       *value = 0;
+               break;
+       case RADEON_INFO_CURRENT_GPU_SCLK:
+               /* get sclk in Mhz */
+               if (rdev->pm.dpm_enabled)
+                       *value = radeon_dpm_get_current_sclk(rdev) / 100;
+               else
+                       *value = rdev->pm.current_sclk / 100;
+               break;
+       case RADEON_INFO_CURRENT_GPU_MCLK:
+               /* get mclk in Mhz */
+               if (rdev->pm.dpm_enabled)
+                       *value = radeon_dpm_get_current_mclk(rdev) / 100;
+               else
+                       *value = rdev->pm.current_mclk / 100;
+               break;
+       case RADEON_INFO_READ_REG:
+               if (copy_from_user(value, value_ptr, sizeof(uint32_t))) {
+                       DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
+                       return -EFAULT;
+               }
+               if (radeon_get_allowed_info_register(rdev, *value, value))
+                       return -EINVAL;
+               break;
        default:
                DRM_DEBUG_KMS("Invalid request %d\n", info->request);
                return -EINVAL;
index 920a8be8abada71c8b1473f844e39ca3535807a8..fa91a17b81b69c715d162b8c92dd66a4a6add914 100644 (file)
@@ -33,6 +33,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_dp_helper.h>
+#include <drm/drm_dp_mst_helper.h>
 #include <drm/drm_fixed.h>
 #include <drm/drm_crtc_helper.h>
 #include <linux/i2c.h>
@@ -85,6 +86,13 @@ enum radeon_hpd_id {
        RADEON_HPD_NONE = 0xff,
 };
 
+enum radeon_output_csc {
+       RADEON_OUTPUT_CSC_BYPASS = 0,
+       RADEON_OUTPUT_CSC_TVRGB = 1,
+       RADEON_OUTPUT_CSC_YCBCR601 = 2,
+       RADEON_OUTPUT_CSC_YCBCR709 = 3,
+};
+
 #define RADEON_MAX_I2C_BUS 16
 
 /* radeon gpio-based i2c
@@ -255,6 +263,8 @@ struct radeon_mode_info {
        struct drm_property *audio_property;
        /* FMT dithering */
        struct drm_property *dither_property;
+       /* Output CSC */
+       struct drm_property *output_csc_property;
        /* hardcoded DFP edid from BIOS */
        struct edid *bios_hardcoded_edid;
        int bios_hardcoded_edid_size;
@@ -265,6 +275,9 @@ struct radeon_mode_info {
        u16 firmware_flags;
        /* pointer to backlight encoder */
        struct radeon_encoder *bl_encoder;
+
+       /* bitmask for active encoder frontends */
+       uint32_t active_encoders;
 };
 
 #define RADEON_MAX_BL_LEVEL 0xFF
@@ -357,6 +370,7 @@ struct radeon_crtc {
        u32 wm_low;
        u32 wm_high;
        struct drm_display_mode hw_mode;
+       enum radeon_output_csc output_csc;
 };
 
 struct radeon_encoder_primary_dac {
@@ -426,12 +440,24 @@ struct radeon_encoder_atom_dig {
        uint8_t backlight_level;
        int panel_mode;
        struct radeon_afmt *afmt;
+       int active_mst_links;
 };
 
 struct radeon_encoder_atom_dac {
        enum radeon_tv_std tv_std;
 };
 
+struct radeon_encoder_mst {
+       int crtc;
+       struct radeon_encoder *primary;
+       struct radeon_connector *connector;
+       struct drm_dp_mst_port *port;
+       int pbn;
+       int fe;
+       bool fe_from_be;
+       bool enc_active;
+};
+
 struct radeon_encoder {
        struct drm_encoder base;
        uint32_t encoder_enum;
@@ -450,6 +476,11 @@ struct radeon_encoder {
        bool is_ext_encoder;
        u16 caps;
        struct radeon_audio_funcs *audio;
+       enum radeon_output_csc output_csc;
+       bool can_mst;
+       uint32_t offset;
+       bool is_mst_encoder;
+       /* front end for this mst encoder */
 };
 
 struct radeon_connector_atom_dig {
@@ -460,6 +491,7 @@ struct radeon_connector_atom_dig {
        int dp_clock;
        int dp_lane_count;
        bool edp_on;
+       bool is_mst;
 };
 
 struct radeon_gpio_rec {
@@ -503,6 +535,11 @@ enum radeon_connector_dither {
        RADEON_FMT_DITHER_ENABLE = 1,
 };
 
+struct stream_attribs {
+       uint16_t fe;
+       uint16_t slots;
+};
+
 struct radeon_connector {
        struct drm_connector base;
        uint32_t connector_id;
@@ -524,6 +561,14 @@ struct radeon_connector {
        enum radeon_connector_audio audio;
        enum radeon_connector_dither dither;
        int pixelclock_for_modeset;
+       bool is_mst_connector;
+       struct radeon_connector *mst_port;
+       struct drm_dp_mst_port *port;
+       struct drm_dp_mst_topology_mgr mst_mgr;
+
+       struct radeon_encoder *mst_encoder;
+       struct stream_attribs cur_stream_attribs[6];
+       int enabled_attribs;
 };
 
 struct radeon_framebuffer {
@@ -708,15 +753,26 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
 extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
 extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
                                    struct drm_connector *connector);
+int radeon_dp_get_max_link_rate(struct drm_connector *connector,
+                               u8 *dpcd);
 extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
                                         u8 power_state);
 extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);
+extern ssize_t
+radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg);
+
 extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
+extern void atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override);
 extern void radeon_atom_encoder_init(struct radeon_device *rdev);
 extern void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev);
 extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,
                                           int action, uint8_t lane_num,
                                           uint8_t lane_set);
+extern void atombios_dig_transmitter_setup2(struct drm_encoder *encoder,
+                                           int action, uint8_t lane_num,
+                                           uint8_t lane_set, int fe);
+extern void atombios_set_mst_encoder_crtc_source(struct drm_encoder *encoder,
+                                                int fe);
 extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder);
 extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder);
 void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le);
@@ -929,7 +985,23 @@ bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
 void radeon_fb_output_poll_changed(struct radeon_device *rdev);
 
 void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id);
+
+void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector);
+void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector);
+
 void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id);
 
 int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled);
+
+/* mst */
+int radeon_dp_mst_init(struct radeon_connector *radeon_connector);
+int radeon_dp_mst_probe(struct radeon_connector *radeon_connector);
+int radeon_dp_mst_check_status(struct radeon_connector *radeon_connector);
+int radeon_mst_debugfs_init(struct radeon_device *rdev);
+void radeon_dp_mst_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode);
+
+void radeon_setup_mst_connector(struct drm_device *dev);
+
+int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx);
+void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx);
 #endif
index 9031f4b6982417462458b026f8c1503cde82397c..cb0afe78abed4562fe1df4e64769216f151285d8 100644 (file)
@@ -1001,6 +1001,28 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
                           ps->sclk_high, ps->max_voltage);
 }
 
+/* get the current sclk in 10 khz units */
+u32 rs780_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK;
+       u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
+       u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1;
+       u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 +
+               ((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1;
+       u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) /
+               (post_div * ref_div);
+
+       return sclk;
+}
+
+/* get the current mclk in 10 khz units */
+u32 rs780_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct igp_power_info *pi = rs780_get_pi(rdev);
+
+       return pi->bootup_uma_clk;
+}
+
 int rs780_dpm_force_performance_level(struct radeon_device *rdev,
                                      enum radeon_dpm_forced_level level)
 {
index 6a5c233361e9dbadbcb629c9583baf946e8abc7b..97e5a6f1ce5837fbaaba787991f83a0b4ab7f950 100644 (file)
@@ -2050,6 +2050,52 @@ void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
        }
 }
 
+/* get the current sclk in 10 khz units */
+u32 rv6xx_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct rv6xx_ps *ps = rv6xx_get_ps(rps);
+       struct rv6xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return pl->sclk;
+       }
+}
+
+/* get the current mclk in 10 khz units */
+u32 rv6xx_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct rv6xx_ps *ps = rv6xx_get_ps(rps);
+       struct rv6xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return pl->mclk;
+       }
+}
+
 void rv6xx_dpm_fini(struct radeon_device *rdev)
 {
        int i;
index 306732641b231aefb16ddc3186359ae872af5801..b9c770745a7a1f717cb9c894a6882c090fd8153c 100644 (file)
@@ -2492,6 +2492,50 @@ void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
        }
 }
 
+u32 rv770_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return  pl->sclk;
+       }
+}
+
+u32 rv770_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return  pl->mclk;
+       }
+}
+
 void rv770_dpm_fini(struct radeon_device *rdev)
 {
        int i;
index a7fb2735d4a929b7a20127bce4d7e3c759de2449..b1d74bc375d82f665dbb4455db5aa84db0c8d8dc 100644 (file)
@@ -1264,6 +1264,36 @@ static void si_init_golden_registers(struct radeon_device *rdev)
        }
 }
 
+/**
+ * si_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int si_get_allowed_info_register(struct radeon_device *rdev,
+                                u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS2:
+       case GRBM_STATUS_SE0:
+       case GRBM_STATUS_SE1:
+       case SRBM_STATUS:
+       case SRBM_STATUS2:
+       case (DMA_STATUS_REG + DMA0_REGISTER_OFFSET):
+       case (DMA_STATUS_REG + DMA1_REGISTER_OFFSET):
+       case UVD_STATUS:
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 #define PCIE_BUS_CLK                10000
 #define TCLK                        (PCIE_BUS_CLK / 10)
 
@@ -6055,12 +6085,12 @@ int si_irq_set(struct radeon_device *rdev)
                (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
 
        if (!ASIC_IS_NODCE(rdev)) {
-               hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+               hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
        }
 
        dma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
@@ -6123,27 +6153,27 @@ int si_irq_set(struct radeon_device *rdev)
        }
        if (rdev->irq.hpd[0]) {
                DRM_DEBUG("si_irq_set: hpd 1\n");
-               hpd1 |= DC_HPDx_INT_EN;
+               hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[1]) {
                DRM_DEBUG("si_irq_set: hpd 2\n");
-               hpd2 |= DC_HPDx_INT_EN;
+               hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[2]) {
                DRM_DEBUG("si_irq_set: hpd 3\n");
-               hpd3 |= DC_HPDx_INT_EN;
+               hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[3]) {
                DRM_DEBUG("si_irq_set: hpd 4\n");
-               hpd4 |= DC_HPDx_INT_EN;
+               hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[4]) {
                DRM_DEBUG("si_irq_set: hpd 5\n");
-               hpd5 |= DC_HPDx_INT_EN;
+               hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[5]) {
                DRM_DEBUG("si_irq_set: hpd 6\n");
-               hpd6 |= DC_HPDx_INT_EN;
+               hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
 
        WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
@@ -6306,6 +6336,37 @@ static inline void si_irq_ack(struct radeon_device *rdev)
                tmp |= DC_HPDx_INT_ACK;
                WREG32(DC_HPD6_INT_CONTROL, tmp);
        }
+
+       if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD1_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD1_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD2_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD2_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD3_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD3_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD4_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD4_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD5_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD6_INT_CONTROL, tmp);
+       }
 }
 
 static void si_irq_disable(struct radeon_device *rdev)
@@ -6371,6 +6432,7 @@ int si_irq_process(struct radeon_device *rdev)
        u32 src_id, src_data, ring_id;
        u32 ring_index;
        bool queue_hotplug = false;
+       bool queue_dp = false;
        bool queue_thermal = false;
        u32 status, addr;
 
@@ -6611,6 +6673,48 @@ restart_ih:
                                        DRM_DEBUG("IH: HPD6\n");
                                }
                                break;
+                       case 6:
+                               if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 1\n");
+                               }
+                               break;
+                       case 7:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 2\n");
+                               }
+                               break;
+                       case 8:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 3\n");
+                               }
+                               break;
+                       case 9:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 4\n");
+                               }
+                               break;
+                       case 10:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 5\n");
+                               }
+                               break;
+                       case 11:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 6\n");
+                               }
+                               break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
                                break;
@@ -6693,6 +6797,8 @@ restart_ih:
                rptr &= rdev->ih.ptr_mask;
                WREG32(IH_RB_RPTR, rptr);
        }
+       if (queue_dp)
+               schedule_work(&rdev->dp_work);
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
        if (queue_thermal && rdev->pm.dpm_enabled)
index 7be11651b7e6c8e5fded976e33ea1ba65ace4775..b35bccfeef79c402c33b6406e0e70755fd4098ad 100644 (file)
@@ -6993,3 +6993,39 @@ void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                           current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1);
        }
 }
+
+u32 si_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct ni_ps *ps = ni_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               return 0;
+       } else {
+               pl = &ps->performance_levels[current_index];
+               return pl->sclk;
+       }
+}
+
+u32 si_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct ni_ps *ps = ni_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               return 0;
+       } else {
+               pl = &ps->performance_levels[current_index];
+               return pl->mclk;
+       }
+}
index 99a9835c9f615919c063af1ce0ca0e596aed8c15..3afac301398388315f78d6cb7cb62e84e7314581 100644 (file)
 #define UVD_UDEC_DBW_ADDR_CONFIG                       0xEF54
 #define UVD_RBC_RB_RPTR                                        0xF690
 #define UVD_RBC_RB_WPTR                                        0xF694
+#define UVD_STATUS                                     0xf6bc
 
 #define        UVD_CGC_CTRL                                    0xF4B0
 #      define DCM                                      (1 << 0)
index 25fd4ced36c83491b4cbfb841a57f30c3ae65130..cd0862809adff2f2749f90eff0b85007cc5e1d4f 100644 (file)
@@ -1837,6 +1837,34 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev
        }
 }
 
+u32 sumo_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct sumo_power_info *pi = sumo_get_pi(rdev);
+       struct radeon_ps *rps = &pi->current_rps;
+       struct sumo_ps *ps = sumo_get_ps(rps);
+       struct sumo_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >>
+               CURR_INDEX_SHIFT;
+
+       if (current_index == BOOST_DPM_LEVEL) {
+               pl = &pi->boost_pl;
+               return pl->sclk;
+       } else if (current_index >= ps->num_levels) {
+               return 0;
+       } else {
+               pl = &ps->levels[current_index];
+               return pl->sclk;
+       }
+}
+
+u32 sumo_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+       return pi->sys_info.bootup_uma_clk;
+}
+
 void sumo_dpm_fini(struct radeon_device *rdev)
 {
        int i;
index 38dacb7a3689e80c3ae41eb4c1826442e792ea79..a5b02c575d775b7b1a4409142507470e7f3fc415 100644 (file)
@@ -1964,6 +1964,31 @@ void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *r
        }
 }
 
+u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct trinity_power_info *pi = trinity_get_pi(rdev);
+       struct radeon_ps *rps = &pi->current_rps;
+       struct trinity_ps *ps = trinity_get_ps(rps);
+       struct trinity_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
+               CURRENT_STATE_SHIFT;
+
+       if (current_index >= ps->num_levels) {
+               return 0;
+       } else {
+               pl = &ps->levels[current_index];
+               return pl->sclk;
+       }
+}
+
+u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+       return pi->sys_info.bootup_uma_clk;
+}
+
 void trinity_dpm_fini(struct radeon_device *rdev)
 {
        int i;
index 9e72133bb64b9ca37bb849e370e57dcbc215ab46..7d0b8ef9bea21ca04a7fc678f3913dc1768615fd 100644 (file)
@@ -486,8 +486,6 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc)
        unsigned long flags;
 
        if (event) {
-               event->pipe = rcrtc->index;
-
                WARN_ON(drm_crtc_vblank_get(crtc) != 0);
 
                spin_lock_irqsave(&dev->event_lock, flags);
index 1d9e4f8568aebdfb7313e0bfe4e184e40d7a343c..da1216a73969ef62f062486734d5946082ee093f 100644 (file)
@@ -252,7 +252,8 @@ static const struct file_operations rcar_du_fops = {
 };
 
 static struct drm_driver rcar_du_driver = {
-       .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME,
+       .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
+                               | DRIVER_ATOMIC,
        .load                   = rcar_du_load,
        .unload                 = rcar_du_unload,
        .preclose               = rcar_du_preclose,
index 35a2f04ab799a9afe78fb6de14d10b04c645d1d5..210e5c3fd9820d30f3347ce01fb4ecbb8b9f5fe5 100644 (file)
@@ -316,6 +316,9 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
 static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane,
                                               struct drm_plane_state *state)
 {
+       if (state->fb)
+               drm_framebuffer_unreference(state->fb);
+
        kfree(to_rcar_du_plane_state(state));
 }
 
index a5d889a8716bd776274462af116d873163ac5f87..d5c1248916b240aa5065f3ed1d04c1aacb96d50a 100644 (file)
@@ -71,7 +71,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
 
        size = mode_cmd.pitches[0] * mode_cmd.height;
 
-       rk_obj = rockchip_gem_create_object(dev, size);
+       rk_obj = rockchip_gem_create_object(dev, size, true);
        if (IS_ERR(rk_obj))
                return -ENOMEM;
 
@@ -106,7 +106,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
 
        fb = helper->fb;
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
-       drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+       drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
        offset = fbi->var.xoffset * bytes_per_pixel;
        offset += fbi->var.yoffset * fb->pitches[0];
index 7ca8799ef78498ca84cc3a48f1265d2f1ce2f6c9..eb2282cc4a56507819a5ab638af504499157157a 100644 (file)
@@ -22,7 +22,8 @@
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_gem.h"
 
-static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj)
+static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
+                                 bool alloc_kmap)
 {
        struct drm_gem_object *obj = &rk_obj->base;
        struct drm_device *drm = obj->dev;
@@ -30,7 +31,9 @@ static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj)
        init_dma_attrs(&rk_obj->dma_attrs);
        dma_set_attr(DMA_ATTR_WRITE_COMBINE, &rk_obj->dma_attrs);
 
-       /* TODO(djkurtz): Use DMA_ATTR_NO_KERNEL_MAPPING except for fbdev */
+       if (!alloc_kmap)
+               dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs);
+
        rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size,
                                         &rk_obj->dma_addr, GFP_KERNEL,
                                         &rk_obj->dma_attrs);
@@ -103,7 +106,8 @@ int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 }
 
 struct rockchip_gem_object *
-       rockchip_gem_create_object(struct drm_device *drm, unsigned int size)
+       rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
+                                  bool alloc_kmap)
 {
        struct rockchip_gem_object *rk_obj;
        struct drm_gem_object *obj;
@@ -119,7 +123,7 @@ struct rockchip_gem_object *
 
        drm_gem_private_object_init(drm, obj, size);
 
-       ret = rockchip_gem_alloc_buf(rk_obj);
+       ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap);
        if (ret)
                goto err_free_rk_obj;
 
@@ -163,7 +167,7 @@ rockchip_gem_create_with_handle(struct drm_file *file_priv,
        struct drm_gem_object *obj;
        int ret;
 
-       rk_obj = rockchip_gem_create_object(drm, size);
+       rk_obj = rockchip_gem_create_object(drm, size, false);
        if (IS_ERR(rk_obj))
                return ERR_CAST(rk_obj);
 
@@ -282,6 +286,9 @@ void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
 {
        struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
 
+       if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs))
+               return NULL;
+
        return rk_obj->kvaddr;
 }
 
index 67bcebe90003dbf5674e752aadd86f9041d6844a..ad22618473a488b10a10e1155f85bc79e1c8870e 100644 (file)
@@ -41,7 +41,8 @@ int rockchip_gem_mmap_buf(struct drm_gem_object *obj,
                          struct vm_area_struct *vma);
 
 struct rockchip_gem_object *
-       rockchip_gem_create_object(struct drm_device *drm, unsigned int size);
+       rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
+                                  bool alloc_kmap);
 
 void rockchip_gem_free_object(struct drm_gem_object *obj);
 
index 9a5c571b95fceb97dae7bfadf1b9782ede0f686e..d041921b3bb9b1f0fd67acf4f8ac43860542b6c3 100644 (file)
@@ -81,7 +81,7 @@ struct vop {
        struct drm_crtc crtc;
        struct device *dev;
        struct drm_device *drm_dev;
-       unsigned int dpms;
+       bool is_enabled;
 
        int connector_type;
        int connector_out_mode;
@@ -89,6 +89,7 @@ struct vop {
        /* mutex vsync_ work */
        struct mutex vsync_mutex;
        bool vsync_work_pending;
+       struct completion dsp_hold_completion;
 
        const struct vop_data *data;
 
@@ -382,11 +383,44 @@ static bool is_alpha_support(uint32_t format)
        }
 }
 
+static void vop_dsp_hold_valid_irq_enable(struct vop *vop)
+{
+       unsigned long flags;
+
+       if (WARN_ON(!vop->is_enabled))
+               return;
+
+       spin_lock_irqsave(&vop->irq_lock, flags);
+
+       vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
+                      DSP_HOLD_VALID_INTR_EN(1));
+
+       spin_unlock_irqrestore(&vop->irq_lock, flags);
+}
+
+static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
+{
+       unsigned long flags;
+
+       if (WARN_ON(!vop->is_enabled))
+               return;
+
+       spin_lock_irqsave(&vop->irq_lock, flags);
+
+       vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
+                      DSP_HOLD_VALID_INTR_EN(0));
+
+       spin_unlock_irqrestore(&vop->irq_lock, flags);
+}
+
 static void vop_enable(struct drm_crtc *crtc)
 {
        struct vop *vop = to_vop(crtc);
        int ret;
 
+       if (vop->is_enabled)
+               return;
+
        ret = clk_enable(vop->hclk);
        if (ret < 0) {
                dev_err(vop->dev, "failed to enable hclk - %d\n", ret);
@@ -417,6 +451,11 @@ static void vop_enable(struct drm_crtc *crtc)
                goto err_disable_aclk;
        }
 
+       /*
+        * At here, vop clock & iommu is enable, R/W vop regs would be safe.
+        */
+       vop->is_enabled = true;
+
        spin_lock(&vop->reg_lock);
 
        VOP_CTRL_SET(vop, standby, 0);
@@ -441,26 +480,41 @@ static void vop_disable(struct drm_crtc *crtc)
 {
        struct vop *vop = to_vop(crtc);
 
-       drm_vblank_off(crtc->dev, vop->pipe);
+       if (!vop->is_enabled)
+               return;
 
-       disable_irq(vop->irq);
+       drm_vblank_off(crtc->dev, vop->pipe);
 
        /*
-        * TODO: Since standby doesn't take effect until the next vblank,
-        * when we turn off dclk below, the vop is probably still active.
+        * Vop standby will take effect at end of current frame,
+        * if dsp hold valid irq happen, it means standby complete.
+        *
+        * we must wait standby complete when we want to disable aclk,
+        * if not, memory bus maybe dead.
         */
+       reinit_completion(&vop->dsp_hold_completion);
+       vop_dsp_hold_valid_irq_enable(vop);
+
        spin_lock(&vop->reg_lock);
 
        VOP_CTRL_SET(vop, standby, 1);
 
        spin_unlock(&vop->reg_lock);
+
+       wait_for_completion(&vop->dsp_hold_completion);
+
+       vop_dsp_hold_valid_irq_disable(vop);
+
+       disable_irq(vop->irq);
+
+       vop->is_enabled = false;
+
        /*
-        * disable dclk to stop frame scan, so we can safely detach iommu,
+        * vop standby complete, so iommu detach is safe.
         */
-       clk_disable(vop->dclk);
-
        rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev);
 
+       clk_disable(vop->dclk);
        clk_disable(vop->aclk);
        clk_disable(vop->hclk);
 }
@@ -742,7 +796,7 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
        struct vop *vop = to_vop(crtc);
        unsigned long flags;
 
-       if (vop->dpms != DRM_MODE_DPMS_ON)
+       if (!vop->is_enabled)
                return -EPERM;
 
        spin_lock_irqsave(&vop->irq_lock, flags);
@@ -759,8 +813,9 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
        struct vop *vop = to_vop(crtc);
        unsigned long flags;
 
-       if (vop->dpms != DRM_MODE_DPMS_ON)
+       if (!vop->is_enabled)
                return;
+
        spin_lock_irqsave(&vop->irq_lock, flags);
        vop_mask_write(vop, INTR_CTRL0, FS_INTR_MASK, FS_INTR_EN(0));
        spin_unlock_irqrestore(&vop->irq_lock, flags);
@@ -773,15 +828,8 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = {
 
 static void vop_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
-       struct vop *vop = to_vop(crtc);
-
        DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
 
-       if (vop->dpms == mode) {
-               DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
-               return;
-       }
-
        switch (mode) {
        case DRM_MODE_DPMS_ON:
                vop_enable(crtc);
@@ -795,8 +843,6 @@ static void vop_crtc_dpms(struct drm_crtc *crtc, int mode)
                DRM_DEBUG_KMS("unspecified mode %d\n", mode);
                break;
        }
-
-       vop->dpms = mode;
 }
 
 static void vop_crtc_prepare(struct drm_crtc *crtc)
@@ -874,8 +920,8 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
        VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode);
 
        val = 0x8;
-       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0;
-       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? (1 << 1) : 0;
+       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
+       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1);
        VOP_CTRL_SET(vop, pin_pol, val);
 
        VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len);
@@ -934,9 +980,9 @@ static int vop_crtc_page_flip(struct drm_crtc *crtc,
        struct drm_framebuffer *old_fb = crtc->primary->fb;
        int ret;
 
-       /* when the page flip is requested, crtc's dpms should be on */
-       if (vop->dpms > DRM_MODE_DPMS_ON) {
-               DRM_DEBUG("failed page flip request at dpms[%d].\n", vop->dpms);
+       /* when the page flip is requested, crtc should be on */
+       if (!vop->is_enabled) {
+               DRM_DEBUG("page flip request rejected because crtc is off.\n");
                return 0;
        }
 
@@ -1081,6 +1127,7 @@ static irqreturn_t vop_isr(int irq, void *data)
        struct vop *vop = data;
        uint32_t intr0_reg, active_irqs;
        unsigned long flags;
+       int ret = IRQ_NONE;
 
        /*
         * INTR_CTRL0 register has interrupt status, enable and clear bits, we
@@ -1099,15 +1146,23 @@ static irqreturn_t vop_isr(int irq, void *data)
        if (!active_irqs)
                return IRQ_NONE;
 
-       /* Only Frame Start Interrupt is enabled; other irqs are spurious. */
-       if (!(active_irqs & FS_INTR)) {
-               DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs);
-               return IRQ_NONE;
+       if (active_irqs & DSP_HOLD_VALID_INTR) {
+               complete(&vop->dsp_hold_completion);
+               active_irqs &= ~DSP_HOLD_VALID_INTR;
+               ret = IRQ_HANDLED;
        }
 
-       drm_handle_vblank(vop->drm_dev, vop->pipe);
+       if (active_irqs & FS_INTR) {
+               drm_handle_vblank(vop->drm_dev, vop->pipe);
+               active_irqs &= ~FS_INTR;
+               ret = (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+       }
 
-       return (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+       /* Unhandled irqs are spurious. */
+       if (active_irqs)
+               DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs);
+
+       return ret;
 }
 
 static int vop_create_crtc(struct vop *vop)
@@ -1189,6 +1244,7 @@ static int vop_create_crtc(struct vop *vop)
                goto err_cleanup_crtc;
        }
 
+       init_completion(&vop->dsp_hold_completion);
        crtc->port = port;
        vop->pipe = drm_crtc_index(crtc);
        rockchip_register_crtc_funcs(drm_dev, &private_crtc_funcs, vop->pipe);
@@ -1302,7 +1358,7 @@ static int vop_initial(struct vop *vop)
 
        clk_disable(vop->hclk);
 
-       vop->dpms = DRM_MODE_DPMS_OFF;
+       vop->is_enabled = false;
 
        return 0;
 
index e6f6ef7c4866ad94eb7bd503eabc9aee7e2b8181..6b641c5a2ec7d10609f20a38cbe6bab56c9f4c5e 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/clk.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_plane_helper.h>
 
@@ -77,22 +79,18 @@ static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc,
 }
 
 static int
-sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
-                     struct drm_display_mode *adjusted_mode, int x, int y,
-                     struct drm_framebuffer *old_fb)
+sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
 {
        struct sti_mixer *mixer = to_sti_mixer(crtc);
        struct device *dev = mixer->dev;
        struct sti_compositor *compo = dev_get_drvdata(dev);
-       struct sti_layer *layer;
        struct clk *clk;
        int rate = mode->clock * 1000;
        int res;
-       unsigned int w, h;
 
-       DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d mode:%d (%s)\n",
+       DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n",
                      crtc->base.id, sti_mixer_to_str(mixer),
-                     crtc->primary->fb->base.id, mode->base.id, mode->name);
+                     mode->base.id, mode->name);
 
        DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
                      mode->vrefresh, mode->clock,
@@ -122,72 +120,13 @@ sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
        sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ?
                        compo->vtg_main : compo->vtg_aux, &crtc->mode);
 
-       /* a GDP is reserved to the CRTC FB */
-       layer = to_sti_layer(crtc->primary);
-       if (!layer) {
-               DRM_ERROR("Can not find GDP0)\n");
-               return -EINVAL;
-       }
-
-       /* copy the mode data adjusted by mode_fixup() into crtc->mode
-        * so that hardware can be set to proper mode
-        */
-       memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
-
-       res = sti_mixer_set_layer_depth(mixer, layer);
-       if (res) {
-               DRM_ERROR("Can not set layer depth\n");
-               return -EINVAL;
-       }
        res = sti_mixer_active_video_area(mixer, &crtc->mode);
        if (res) {
                DRM_ERROR("Can not set active video area\n");
                return -EINVAL;
        }
 
-       w = crtc->primary->fb->width - x;
-       h = crtc->primary->fb->height - y;
-
-       return sti_layer_prepare(layer, crtc,
-                       crtc->primary->fb, &crtc->mode,
-                       mixer->id, 0, 0, w, h, x, y, w, h);
-}
-
-static int sti_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-                                     struct drm_framebuffer *old_fb)
-{
-       struct sti_mixer *mixer = to_sti_mixer(crtc);
-       struct sti_layer *layer;
-       unsigned int w, h;
-       int ret;
-
-       DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d (%d,%d)\n",
-                     crtc->base.id, sti_mixer_to_str(mixer),
-                     crtc->primary->fb->base.id, x, y);
-
-       /* GDP is reserved to the CRTC FB */
-       layer = to_sti_layer(crtc->primary);
-       if (!layer) {
-               DRM_ERROR("Can not find GDP0)\n");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       w = crtc->primary->fb->width - crtc->x;
-       h = crtc->primary->fb->height - crtc->y;
-
-       ret = sti_layer_prepare(layer, crtc,
-                               crtc->primary->fb, &crtc->mode,
-                               mixer->id, 0, 0, w, h,
-                               crtc->x, crtc->y, w, h);
-       if (ret) {
-               DRM_ERROR("Can not prepare layer\n");
-               goto out;
-       }
-
-       sti_drm_crtc_commit(crtc);
-out:
-       return ret;
+       return res;
 }
 
 static void sti_drm_crtc_disable(struct drm_crtc *crtc)
@@ -195,7 +134,6 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
        struct sti_mixer *mixer = to_sti_mixer(crtc);
        struct device *dev = mixer->dev;
        struct sti_compositor *compo = dev_get_drvdata(dev);
-       struct sti_layer *layer;
 
        if (!mixer->enabled)
                return;
@@ -205,24 +143,6 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
        /* Disable Background */
        sti_mixer_set_background_status(mixer, false);
 
-       /* Disable GDP */
-       layer = to_sti_layer(crtc->primary);
-       if (!layer) {
-               DRM_ERROR("Cannot find GDP0\n");
-               return;
-       }
-
-       /* Disable layer at mixer level */
-       if (sti_mixer_set_layer_status(mixer, layer, false))
-               DRM_ERROR("Can not disable %s layer at mixer\n",
-                               sti_layer_to_str(layer));
-
-       /* Wait a while to be sure that a Vsync event is received */
-       msleep(WAIT_NEXT_VSYNC_MS);
-
-       /* Then disable layer itself */
-       sti_layer_disable(layer);
-
        drm_crtc_vblank_off(crtc);
 
        /* Disable pixel clock and compo IP clocks */
@@ -237,64 +157,44 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
        mixer->enabled = false;
 }
 
-static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
-       .dpms = sti_drm_crtc_dpms,
-       .prepare = sti_drm_crtc_prepare,
-       .commit = sti_drm_crtc_commit,
-       .mode_fixup = sti_drm_crtc_mode_fixup,
-       .mode_set = sti_drm_crtc_mode_set,
-       .mode_set_base = sti_drm_crtc_mode_set_base,
-       .disable = sti_drm_crtc_disable,
-};
+static void
+sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+       sti_drm_crtc_prepare(crtc);
+       sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
+}
 
-static int sti_drm_crtc_page_flip(struct drm_crtc *crtc,
-                                 struct drm_framebuffer *fb,
-                                 struct drm_pending_vblank_event *event,
-                                 uint32_t page_flip_flags)
+static void sti_drm_atomic_begin(struct drm_crtc *crtc)
 {
-       struct drm_device *drm_dev = crtc->dev;
-       struct drm_framebuffer *old_fb;
        struct sti_mixer *mixer = to_sti_mixer(crtc);
-       unsigned long flags;
-       int ret;
 
-       DRM_DEBUG_KMS("fb %d --> fb %d\n",
-                       crtc->primary->fb->base.id, fb->base.id);
+       if (crtc->state->event) {
+               crtc->state->event->pipe = drm_crtc_index(crtc);
 
-       mutex_lock(&drm_dev->struct_mutex);
+               WARN_ON(drm_crtc_vblank_get(crtc) != 0);
 
-       old_fb = crtc->primary->fb;
-       crtc->primary->fb = fb;
-       ret = sti_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
-       if (ret) {
-               DRM_ERROR("failed\n");
-               crtc->primary->fb = old_fb;
-               goto out;
+               mixer->pending_event = crtc->state->event;
+               crtc->state->event = NULL;
        }
+}
 
-       if (event) {
-               event->pipe = mixer->id;
-
-               ret = drm_vblank_get(drm_dev, event->pipe);
-               if (ret) {
-                       DRM_ERROR("Cannot get vblank\n");
-                       goto out;
-               }
-
-               spin_lock_irqsave(&drm_dev->event_lock, flags);
-               if (mixer->pending_event) {
-                       drm_vblank_put(drm_dev, event->pipe);
-                       ret = -EBUSY;
-               } else {
-                       mixer->pending_event = event;
-               }
-               spin_unlock_irqrestore(&drm_dev->event_lock, flags);
-       }
-out:
-       mutex_unlock(&drm_dev->struct_mutex);
-       return ret;
+static void sti_drm_atomic_flush(struct drm_crtc *crtc)
+{
 }
 
+static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
+       .dpms = sti_drm_crtc_dpms,
+       .prepare = sti_drm_crtc_prepare,
+       .commit = sti_drm_crtc_commit,
+       .mode_fixup = sti_drm_crtc_mode_fixup,
+       .mode_set = drm_helper_crtc_mode_set,
+       .mode_set_nofb = sti_drm_crtc_mode_set_nofb,
+       .mode_set_base = drm_helper_crtc_mode_set_base,
+       .disable = sti_drm_crtc_disable,
+       .atomic_begin = sti_drm_atomic_begin,
+       .atomic_flush = sti_drm_atomic_flush,
+};
+
 static void sti_drm_crtc_destroy(struct drm_crtc *crtc)
 {
        DRM_DEBUG_KMS("\n");
@@ -380,10 +280,13 @@ void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
 EXPORT_SYMBOL(sti_drm_crtc_disable_vblank);
 
 static struct drm_crtc_funcs sti_crtc_funcs = {
-       .set_config = drm_crtc_helper_set_config,
-       .page_flip = sti_drm_crtc_page_flip,
+       .set_config = drm_atomic_helper_set_config,
+       .page_flip = drm_atomic_helper_page_flip,
        .destroy = sti_drm_crtc_destroy,
        .set_property = sti_drm_crtc_set_property,
+       .reset = drm_atomic_helper_crtc_reset,
+       .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
 };
 
 bool sti_drm_crtc_is_main(struct drm_crtc *crtc)
index 5239fa12172683cd2313e3863107acc26c7c08c0..59d558b400b33f390cdd6db00014ab29c94b84d4 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/module.h>
 #include <linux/of_platform.h>
 
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #define STI_MAX_FB_HEIGHT      4096
 #define STI_MAX_FB_WIDTH       4096
 
+static void sti_drm_atomic_schedule(struct sti_drm_private *private,
+                                 struct drm_atomic_state *state)
+{
+       private->commit.state = state;
+       schedule_work(&private->commit.work);
+}
+
+static void sti_drm_atomic_complete(struct sti_drm_private *private,
+                                 struct drm_atomic_state *state)
+{
+       struct drm_device *drm = private->drm_dev;
+
+       /*
+        * Everything below can be run asynchronously without the need to grab
+        * any modeset locks at all under one condition: It must be guaranteed
+        * that the asynchronous work has either been cancelled (if the driver
+        * supports it, which at least requires that the framebuffers get
+        * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
+        * before the new state gets committed on the software side with
+        * drm_atomic_helper_swap_state().
+        *
+        * This scheme allows new atomic state updates to be prepared and
+        * checked in parallel to the asynchronous completion of the previous
+        * update. Which is important since compositors need to figure out the
+        * composition of the next frame right after having submitted the
+        * current layout.
+        */
+
+       drm_atomic_helper_commit_modeset_disables(drm, state);
+       drm_atomic_helper_commit_planes(drm, state);
+       drm_atomic_helper_commit_modeset_enables(drm, state);
+
+       drm_atomic_helper_wait_for_vblanks(drm, state);
+
+       drm_atomic_helper_cleanup_planes(drm, state);
+       drm_atomic_state_free(state);
+}
+
+static void sti_drm_atomic_work(struct work_struct *work)
+{
+       struct sti_drm_private *private = container_of(work,
+                       struct sti_drm_private, commit.work);
+
+       sti_drm_atomic_complete(private, private->commit.state);
+}
+
+static int sti_drm_atomic_commit(struct drm_device *drm,
+                              struct drm_atomic_state *state, bool async)
+{
+       struct sti_drm_private *private = drm->dev_private;
+       int err;
+
+       err = drm_atomic_helper_prepare_planes(drm, state);
+       if (err)
+               return err;
+
+       /* serialize outstanding asynchronous commits */
+       mutex_lock(&private->commit.lock);
+       flush_work(&private->commit.work);
+
+       /*
+        * This is the point of no return - everything below never fails except
+        * when the hw goes bonghits. Which means we can commit the new state on
+        * the software side now.
+        */
+
+       drm_atomic_helper_swap_state(drm, state);
+
+       if (async)
+               sti_drm_atomic_schedule(private, state);
+       else
+               sti_drm_atomic_complete(private, state);
+
+       mutex_unlock(&private->commit.lock);
+       return 0;
+}
+
 static struct drm_mode_config_funcs sti_drm_mode_config_funcs = {
        .fb_create = drm_fb_cma_create,
+       .atomic_check = drm_atomic_helper_check,
+       .atomic_commit = sti_drm_atomic_commit,
 };
 
 static void sti_drm_mode_config_init(struct drm_device *dev)
@@ -61,6 +142,9 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags)
        dev->dev_private = (void *)private;
        private->drm_dev = dev;
 
+       mutex_init(&private->commit.lock);
+       INIT_WORK(&private->commit.work, sti_drm_atomic_work);
+
        drm_mode_config_init(dev);
        drm_kms_helper_poll_init(dev);
 
@@ -74,7 +158,7 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags)
                return ret;
        }
 
-       drm_helper_disable_unused_functions(dev);
+       drm_mode_config_reset(dev);
 
 #ifdef CONFIG_DRM_STI_FBDEV
        drm_fbdev_cma_init(dev, 32,
index ec5e2eb8dff91e24cc5c0a7321012b4b93d158ff..c413aa3ff4021449791f3ce73668d8beabdb94c9 100644 (file)
@@ -24,6 +24,12 @@ struct sti_drm_private {
        struct sti_compositor *compo;
        struct drm_property *plane_zorder_property;
        struct drm_device *drm_dev;
+
+       struct {
+               struct drm_atomic_state *state;
+               struct work_struct work;
+               struct mutex lock;
+       } commit;
 };
 
 #endif
index bb6a29339e1084bca0483e7ee643cfc62c06299a..64d4ed43dda3fa6e38a81a7bb4ba9bafba02287a 100644 (file)
@@ -6,6 +6,10 @@
  * License terms:  GNU General Public License (GPL), version 2
  */
 
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+
 #include "sti_compositor.h"
 #include "sti_drm_drv.h"
 #include "sti_drm_plane.h"
@@ -33,9 +37,9 @@ sti_drm_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        struct sti_mixer *mixer = to_sti_mixer(crtc);
        int res;
 
-       DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s) drm fb:%d\n",
+       DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
                      crtc->base.id, sti_mixer_to_str(mixer),
-                     plane->base.id, sti_layer_to_str(layer), fb->base.id);
+                     plane->base.id, sti_layer_to_str(layer));
        DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", crtc_w, crtc_h, crtc_x, crtc_y);
 
        res = sti_mixer_set_layer_depth(mixer, layer);
@@ -110,7 +114,7 @@ static void sti_drm_plane_destroy(struct drm_plane *plane)
 {
        DRM_DEBUG_DRIVER("\n");
 
-       sti_drm_disable_plane(plane);
+       drm_plane_helper_disable(plane);
        drm_plane_cleanup(plane);
 }
 
@@ -133,10 +137,58 @@ static int sti_drm_plane_set_property(struct drm_plane *plane,
 }
 
 static struct drm_plane_funcs sti_drm_plane_funcs = {
-       .update_plane = sti_drm_update_plane,
-       .disable_plane = sti_drm_disable_plane,
+       .update_plane = drm_atomic_helper_update_plane,
+       .disable_plane = drm_atomic_helper_disable_plane,
        .destroy = sti_drm_plane_destroy,
        .set_property = sti_drm_plane_set_property,
+       .reset = drm_atomic_helper_plane_reset,
+       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static int sti_drm_plane_prepare_fb(struct drm_plane *plane,
+                                 struct drm_framebuffer *fb,
+                                 const struct drm_plane_state *new_state)
+{
+       return 0;
+}
+
+static void sti_drm_plane_cleanup_fb(struct drm_plane *plane,
+                                  struct drm_framebuffer *fb,
+                                  const struct drm_plane_state *old_fb)
+{
+}
+
+static int sti_drm_plane_atomic_check(struct drm_plane *plane,
+                                     struct drm_plane_state *state)
+{
+       return 0;
+}
+
+static void sti_drm_plane_atomic_update(struct drm_plane *plane,
+                                       struct drm_plane_state *oldstate)
+{
+       struct drm_plane_state *state = plane->state;
+
+       sti_drm_update_plane(plane, state->crtc, state->fb,
+                           state->crtc_x, state->crtc_y,
+                           state->crtc_w, state->crtc_h,
+                           state->src_x, state->src_y,
+                           state->src_w, state->src_h);
+}
+
+static void sti_drm_plane_atomic_disable(struct drm_plane *plane,
+                                        struct drm_plane_state *oldstate)
+{
+       sti_drm_disable_plane(plane);
+}
+
+static const struct drm_plane_helper_funcs sti_drm_plane_helpers_funcs = {
+       .prepare_fb = sti_drm_plane_prepare_fb,
+       .cleanup_fb = sti_drm_plane_cleanup_fb,
+       .atomic_check = sti_drm_plane_atomic_check,
+       .atomic_update = sti_drm_plane_atomic_update,
+       .atomic_disable = sti_drm_plane_atomic_disable,
 };
 
 static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane,
@@ -178,11 +230,13 @@ struct drm_plane *sti_drm_plane_init(struct drm_device *dev,
                return NULL;
        }
 
+       drm_plane_helper_add(&layer->plane, &sti_drm_plane_helpers_funcs);
+
        for (i = 0; i < ARRAY_SIZE(sti_layer_default_zorder); i++)
                if (sti_layer_default_zorder[i] == layer->desc)
                        break;
 
-       default_zorder = i;
+       default_zorder = i + 1;
 
        if (type == DRM_PLANE_TYPE_OVERLAY)
                sti_drm_plane_attach_zorder_property(&layer->plane,
index aeb5070c8363fb6307ab7c6c768dab9fefece269..a9b678af85a6f315716fa82871674519e017b9f3 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/platform_device.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_panel.h>
 
@@ -364,10 +365,13 @@ static void sti_dvo_connector_destroy(struct drm_connector *connector)
 }
 
 static struct drm_connector_funcs sti_dvo_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = sti_dvo_connector_detect,
        .destroy = sti_dvo_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 struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev)
index a9bbb081ecadc1165031b9c794b753d083b9ee2f..598cd78b0b163cd2e86f92a68e5386325a3a357f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/platform_device.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 
 /* HDformatter registers */
@@ -611,10 +612,13 @@ static void sti_hda_connector_destroy(struct drm_connector *connector)
 }
 
 static struct drm_connector_funcs sti_hda_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = sti_hda_connector_detect,
        .destroy = sti_hda_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 struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev)
index 1485ade98710a3078de14c8b577db2a5bd15cd21..ae5424bd6b4cbd00d1ffc5b4fd35f11cb56a11cd 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/reset.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 
@@ -663,10 +664,13 @@ static void sti_hdmi_connector_destroy(struct drm_connector *connector)
 }
 
 static struct drm_connector_funcs sti_hdmi_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = sti_hdmi_connector_detect,
        .destroy = sti_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 struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev)
index adc9ea5acf02ea45437268c16298a4dbbd9fe35a..7b5c661b37d8c275712da25356d5d22e288b7ac4 100644 (file)
@@ -915,7 +915,7 @@ struct drm_bridge {
 };
 
 /**
- * struct struct drm_atomic_state - the global state object for atomic updates
+ * struct drm_atomic_state - the global state object for atomic updates
  * @dev: parent DRM device
  * @allow_modeset: allow full modeset
  * @legacy_cursor_update: hint to enforce legacy cursor ioctl semantics
index c5fdc2d3ca97275c36d86954d52b29b7e60c7f7b..523f04c90dea45826af4a3de70a43d54896f6043 100644 (file)
@@ -42,6 +42,8 @@
  * 1.2 formally includes both eDP and DPI definitions.
  */
 
+#define DP_AUX_MAX_PAYLOAD_BYTES       16
+
 #define DP_AUX_I2C_WRITE               0x0
 #define DP_AUX_I2C_READ                        0x1
 #define DP_AUX_I2C_STATUS              0x2
@@ -680,6 +682,9 @@ struct drm_dp_aux_msg {
  * transactions. The drm_dp_aux_register_i2c_bus() function registers an
  * I2C adapter that can be passed to drm_probe_ddc(). Upon removal, drivers
  * should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter.
+ * The I2C adapter uses long transfers by default; if a partial response is
+ * received, the adapter will drop down to the size given by the partial
+ * response for this transaction only.
  *
  * Note that the aux helper code assumes that the .transfer() function
  * only modifies the reply field of the drm_dp_aux_msg structure.  The
index 00c1da9272456e8e9bdec207affa286028664421..a2507817be4196606abe1cc038be09c612d6afd6 100644 (file)
@@ -486,6 +486,8 @@ int drm_dp_calc_pbn_mode(int clock, int bpp);
 
 bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn, int *slots);
 
+int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
+
 
 void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
 
index 21b944c456f69dceb9c4762384d04717d82b41ff..0dfd94def593526eaa7d5e414a85634f37509385 100644 (file)
@@ -44,6 +44,25 @@ struct drm_fb_helper_crtc {
        int x, y;
 };
 
+/**
+ * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size
+ * @fb_width: fbdev width
+ * @fb_height: fbdev height
+ * @surface_width: scanout buffer width
+ * @surface_height: scanout buffer height
+ * @surface_bpp: scanout buffer bpp
+ * @surface_depth: scanout buffer depth
+ *
+ * Note that the scanout surface width/height may be larger than the fbdev
+ * width/height.  In case of multiple displays, the scanout surface is sized
+ * according to the largest width/height (so it is large enough for all CRTCs
+ * to scanout).  But the fbdev width/height is sized to the minimum width/
+ * height of all the displays.  This ensures that fbcon fits on the smallest
+ * of the attached displays.
+ *
+ * So what is passed to drm_fb_helper_fill_var() should be fb_width/fb_height,
+ * rather than the surface size.
+ */
 struct drm_fb_helper_surface_size {
        u32 fb_width;
        u32 fb_height;
index 50d0fb41a3bf32cb2a796f3738adb10d79e3fb6c..871e73f99a4d7aa13b4cd6f5bc8969421c2a9301 100644 (file)
@@ -1034,6 +1034,10 @@ struct drm_radeon_cs {
 #define RADEON_INFO_VRAM_USAGE         0x1e
 #define RADEON_INFO_GTT_USAGE          0x1f
 #define RADEON_INFO_ACTIVE_CU_COUNT    0x20
+#define RADEON_INFO_CURRENT_GPU_TEMP   0x21
+#define RADEON_INFO_CURRENT_GPU_SCLK   0x22
+#define RADEON_INFO_CURRENT_GPU_MCLK   0x23
+#define RADEON_INFO_READ_REG           0x24
 
 struct drm_radeon_info {
        uint32_t                request;