diff options
Diffstat (limited to 'drivers/gpu')
99 files changed, 3937 insertions, 1127 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index ec4036a09f3e..a625b9137da2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | |||
| @@ -187,12 +187,12 @@ int init_pipelines(struct device_queue_manager *dqm, | |||
| 187 | unsigned int get_first_pipe(struct device_queue_manager *dqm); | 187 | unsigned int get_first_pipe(struct device_queue_manager *dqm); |
| 188 | unsigned int get_pipes_num(struct device_queue_manager *dqm); | 188 | unsigned int get_pipes_num(struct device_queue_manager *dqm); |
| 189 | 189 | ||
| 190 | extern inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd) | 190 | static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd) |
| 191 | { | 191 | { |
| 192 | return (pdd->lds_base >> 16) & 0xFF; | 192 | return (pdd->lds_base >> 16) & 0xFF; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | extern inline unsigned int | 195 | static inline unsigned int |
| 196 | get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd) | 196 | get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd) |
| 197 | { | 197 | { |
| 198 | return (pdd->lds_base >> 60) & 0x0E; | 198 | return (pdd->lds_base >> 60) & 0x0E; |
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index d0d5f4baf72d..80113c335966 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h | |||
| @@ -617,10 +617,7 @@ int kgd2kfd_resume(struct kfd_dev *kfd); | |||
| 617 | int kfd_init_apertures(struct kfd_process *process); | 617 | int kfd_init_apertures(struct kfd_process *process); |
| 618 | 618 | ||
| 619 | /* Queue Context Management */ | 619 | /* Queue Context Management */ |
| 620 | inline uint32_t lower_32(uint64_t x); | ||
| 621 | inline uint32_t upper_32(uint64_t x); | ||
| 622 | struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd); | 620 | struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd); |
| 623 | inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m); | ||
| 624 | 621 | ||
| 625 | int init_queue(struct queue **q, struct queue_properties properties); | 622 | int init_queue(struct queue **q, struct queue_properties properties); |
| 626 | void uninit_queue(struct queue *q); | 623 | void uninit_queue(struct queue *q); |
diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c index 381c5fcbf903..ccbdadb108dc 100644 --- a/drivers/gpu/drm/arc/arcpgu_drv.c +++ b/drivers/gpu/drm/arc/arcpgu_drv.c | |||
| @@ -211,15 +211,8 @@ static int arcpgu_probe(struct platform_device *pdev) | |||
| 211 | if (ret) | 211 | if (ret) |
| 212 | goto err_unload; | 212 | goto err_unload; |
| 213 | 213 | ||
| 214 | ret = drm_connector_register_all(drm); | ||
| 215 | if (ret) | ||
| 216 | goto err_unregister; | ||
| 217 | |||
| 218 | return 0; | 214 | return 0; |
| 219 | 215 | ||
| 220 | err_unregister: | ||
| 221 | drm_dev_unregister(drm); | ||
| 222 | |||
| 223 | err_unload: | 216 | err_unload: |
| 224 | arcpgu_unload(drm); | 217 | arcpgu_unload(drm); |
| 225 | 218 | ||
| @@ -233,7 +226,6 @@ static int arcpgu_remove(struct platform_device *pdev) | |||
| 233 | { | 226 | { |
| 234 | struct drm_device *drm = platform_get_drvdata(pdev); | 227 | struct drm_device *drm = platform_get_drvdata(pdev); |
| 235 | 228 | ||
| 236 | drm_connector_unregister_all(drm); | ||
| 237 | drm_dev_unregister(drm); | 229 | drm_dev_unregister(drm); |
| 238 | arcpgu_unload(drm); | 230 | arcpgu_unload(drm); |
| 239 | drm_dev_unref(drm); | 231 | drm_dev_unref(drm); |
diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig index eaed454e043c..1b2906568a48 100644 --- a/drivers/gpu/drm/arm/Kconfig +++ b/drivers/gpu/drm/arm/Kconfig | |||
| @@ -25,3 +25,19 @@ config DRM_HDLCD_SHOW_UNDERRUN | |||
| 25 | Enable this option to show in red colour the pixels that the | 25 | Enable this option to show in red colour the pixels that the |
| 26 | HDLCD device did not fetch from framebuffer due to underrun | 26 | HDLCD device did not fetch from framebuffer due to underrun |
| 27 | conditions. | 27 | conditions. |
| 28 | |||
| 29 | config DRM_MALI_DISPLAY | ||
| 30 | tristate "ARM Mali Display Processor" | ||
| 31 | depends on DRM && OF && (ARM || ARM64) | ||
| 32 | depends on COMMON_CLK | ||
| 33 | select DRM_ARM | ||
| 34 | select DRM_KMS_HELPER | ||
| 35 | select DRM_KMS_CMA_HELPER | ||
| 36 | select DRM_GEM_CMA_HELPER | ||
| 37 | select VIDEOMODE_HELPERS | ||
| 38 | help | ||
| 39 | Choose this option if you want to compile the ARM Mali Display | ||
| 40 | Processor driver. It supports the DP500, DP550 and DP650 variants | ||
| 41 | of the hardware. | ||
| 42 | |||
| 43 | If compiled as a module it will be called mali-dp. | ||
diff --git a/drivers/gpu/drm/arm/Makefile b/drivers/gpu/drm/arm/Makefile index 89dcb7bab93a..bb8b158ff90d 100644 --- a/drivers/gpu/drm/arm/Makefile +++ b/drivers/gpu/drm/arm/Makefile | |||
| @@ -1,2 +1,4 @@ | |||
| 1 | hdlcd-y := hdlcd_drv.o hdlcd_crtc.o | 1 | hdlcd-y := hdlcd_drv.o hdlcd_crtc.o |
| 2 | obj-$(CONFIG_DRM_HDLCD) += hdlcd.o | 2 | obj-$(CONFIG_DRM_HDLCD) += hdlcd.o |
| 3 | mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o | ||
| 4 | obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o | ||
diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c new file mode 100644 index 000000000000..08e6a71f5d05 --- /dev/null +++ b/drivers/gpu/drm/arm/malidp_crtc.c | |||
| @@ -0,0 +1,216 @@ | |||
| 1 | /* | ||
| 2 | * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. | ||
| 3 | * Author: Liviu Dudau <Liviu.Dudau@arm.com> | ||
| 4 | * | ||
| 5 | * This program is free software and is provided to you under the terms of the | ||
| 6 | * GNU General Public License version 2 as published by the Free Software | ||
| 7 | * Foundation, and any use by you of this program is subject to the terms | ||
| 8 | * of such GNU licence. | ||
| 9 | * | ||
| 10 | * ARM Mali DP500/DP550/DP650 driver (crtc operations) | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <drm/drmP.h> | ||
| 14 | #include <drm/drm_atomic.h> | ||
| 15 | #include <drm/drm_atomic_helper.h> | ||
| 16 | #include <drm/drm_crtc.h> | ||
| 17 | #include <drm/drm_crtc_helper.h> | ||
| 18 | #include <linux/clk.h> | ||
| 19 | #include <video/videomode.h> | ||
| 20 | |||
| 21 | #include "malidp_drv.h" | ||
| 22 | #include "malidp_hw.h" | ||
| 23 | |||
| 24 | static bool malidp_crtc_mode_fixup(struct drm_crtc *crtc, | ||
| 25 | const struct drm_display_mode *mode, | ||
| 26 | struct drm_display_mode *adjusted_mode) | ||
| 27 | { | ||
| 28 | struct malidp_drm *malidp = crtc_to_malidp_device(crtc); | ||
| 29 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 30 | |||
| 31 | /* | ||
| 32 | * check that the hardware can drive the required clock rate, | ||
| 33 | * but skip the check if the clock is meant to be disabled (req_rate = 0) | ||
| 34 | */ | ||
| 35 | long rate, req_rate = mode->crtc_clock * 1000; | ||
| 36 | |||
| 37 | if (req_rate) { | ||
| 38 | rate = clk_round_rate(hwdev->mclk, req_rate); | ||
| 39 | if (rate < req_rate) { | ||
| 40 | DRM_DEBUG_DRIVER("mclk clock unable to reach %d kHz\n", | ||
| 41 | mode->crtc_clock); | ||
| 42 | return false; | ||
| 43 | } | ||
| 44 | |||
| 45 | rate = clk_round_rate(hwdev->pxlclk, req_rate); | ||
| 46 | if (rate != req_rate) { | ||
| 47 | DRM_DEBUG_DRIVER("pxlclk doesn't support %ld Hz\n", | ||
| 48 | req_rate); | ||
| 49 | return false; | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | return true; | ||
| 54 | } | ||
| 55 | |||
| 56 | static void malidp_crtc_enable(struct drm_crtc *crtc) | ||
| 57 | { | ||
| 58 | struct malidp_drm *malidp = crtc_to_malidp_device(crtc); | ||
| 59 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 60 | struct videomode vm; | ||
| 61 | |||
| 62 | drm_display_mode_to_videomode(&crtc->state->adjusted_mode, &vm); | ||
| 63 | |||
| 64 | clk_prepare_enable(hwdev->pxlclk); | ||
| 65 | |||
| 66 | /* mclk needs to be set to the same or higher rate than pxlclk */ | ||
| 67 | clk_set_rate(hwdev->mclk, crtc->state->adjusted_mode.crtc_clock * 1000); | ||
| 68 | clk_set_rate(hwdev->pxlclk, crtc->state->adjusted_mode.crtc_clock * 1000); | ||
| 69 | |||
| 70 | hwdev->modeset(hwdev, &vm); | ||
| 71 | hwdev->leave_config_mode(hwdev); | ||
| 72 | drm_crtc_vblank_on(crtc); | ||
| 73 | } | ||
| 74 | |||
| 75 | static void malidp_crtc_disable(struct drm_crtc *crtc) | ||
| 76 | { | ||
| 77 | struct malidp_drm *malidp = crtc_to_malidp_device(crtc); | ||
| 78 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 79 | |||
| 80 | drm_crtc_vblank_off(crtc); | ||
| 81 | hwdev->enter_config_mode(hwdev); | ||
| 82 | clk_disable_unprepare(hwdev->pxlclk); | ||
| 83 | } | ||
| 84 | |||
| 85 | static int malidp_crtc_atomic_check(struct drm_crtc *crtc, | ||
| 86 | struct drm_crtc_state *state) | ||
| 87 | { | ||
| 88 | struct malidp_drm *malidp = crtc_to_malidp_device(crtc); | ||
| 89 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 90 | struct drm_plane *plane; | ||
| 91 | const struct drm_plane_state *pstate; | ||
| 92 | u32 rot_mem_free, rot_mem_usable; | ||
| 93 | int rotated_planes = 0; | ||
| 94 | |||
| 95 | /* | ||
| 96 | * check if there is enough rotation memory available for planes | ||
| 97 | * that need 90° and 270° rotation. Each plane has set its required | ||
| 98 | * memory size in the ->plane_check() callback, here we only make | ||
| 99 | * sure that the sums are less that the total usable memory. | ||
| 100 | * | ||
| 101 | * The rotation memory allocation algorithm (for each plane): | ||
| 102 | * a. If no more rotated planes exist, all remaining rotate | ||
| 103 | * memory in the bank is available for use by the plane. | ||
| 104 | * b. If other rotated planes exist, and plane's layer ID is | ||
| 105 | * DE_VIDEO1, it can use all the memory from first bank if | ||
| 106 | * secondary rotation memory bank is available, otherwise it can | ||
| 107 | * use up to half the bank's memory. | ||
| 108 | * c. If other rotated planes exist, and plane's layer ID is not | ||
| 109 | * DE_VIDEO1, it can use half of the available memory | ||
| 110 | * | ||
| 111 | * Note: this algorithm assumes that the order in which the planes are | ||
| 112 | * checked always has DE_VIDEO1 plane first in the list if it is | ||
| 113 | * rotated. Because that is how we create the planes in the first | ||
| 114 | * place, under current DRM version things work, but if ever the order | ||
| 115 | * in which drm_atomic_crtc_state_for_each_plane() iterates over planes | ||
| 116 | * changes, we need to pre-sort the planes before validation. | ||
| 117 | */ | ||
| 118 | |||
| 119 | /* first count the number of rotated planes */ | ||
| 120 | drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) { | ||
| 121 | if (pstate->rotation & MALIDP_ROTATED_MASK) | ||
| 122 | rotated_planes++; | ||
| 123 | } | ||
| 124 | |||
| 125 | rot_mem_free = hwdev->rotation_memory[0]; | ||
| 126 | /* | ||
| 127 | * if we have more than 1 plane using rotation memory, use the second | ||
| 128 | * block of rotation memory as well | ||
| 129 | */ | ||
| 130 | if (rotated_planes > 1) | ||
| 131 | rot_mem_free += hwdev->rotation_memory[1]; | ||
| 132 | |||
| 133 | /* now validate the rotation memory requirements */ | ||
| 134 | drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) { | ||
| 135 | struct malidp_plane *mp = to_malidp_plane(plane); | ||
| 136 | struct malidp_plane_state *ms = to_malidp_plane_state(pstate); | ||
| 137 | |||
| 138 | if (pstate->rotation & MALIDP_ROTATED_MASK) { | ||
| 139 | /* process current plane */ | ||
| 140 | rotated_planes--; | ||
| 141 | |||
| 142 | if (!rotated_planes) { | ||
| 143 | /* no more rotated planes, we can use what's left */ | ||
| 144 | rot_mem_usable = rot_mem_free; | ||
| 145 | } else { | ||
| 146 | if ((mp->layer->id != DE_VIDEO1) || | ||
| 147 | (hwdev->rotation_memory[1] == 0)) | ||
| 148 | rot_mem_usable = rot_mem_free / 2; | ||
| 149 | else | ||
| 150 | rot_mem_usable = hwdev->rotation_memory[0]; | ||
| 151 | } | ||
| 152 | |||
| 153 | rot_mem_free -= rot_mem_usable; | ||
| 154 | |||
| 155 | if (ms->rotmem_size > rot_mem_usable) | ||
| 156 | return -EINVAL; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | return 0; | ||
| 161 | } | ||
| 162 | |||
| 163 | static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = { | ||
| 164 | .mode_fixup = malidp_crtc_mode_fixup, | ||
| 165 | .enable = malidp_crtc_enable, | ||
| 166 | .disable = malidp_crtc_disable, | ||
| 167 | .atomic_check = malidp_crtc_atomic_check, | ||
| 168 | }; | ||
| 169 | |||
| 170 | static const struct drm_crtc_funcs malidp_crtc_funcs = { | ||
| 171 | .destroy = drm_crtc_cleanup, | ||
| 172 | .set_config = drm_atomic_helper_set_config, | ||
| 173 | .page_flip = drm_atomic_helper_page_flip, | ||
| 174 | .reset = drm_atomic_helper_crtc_reset, | ||
| 175 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | ||
| 176 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | ||
| 177 | }; | ||
| 178 | |||
| 179 | int malidp_crtc_init(struct drm_device *drm) | ||
| 180 | { | ||
| 181 | struct malidp_drm *malidp = drm->dev_private; | ||
| 182 | struct drm_plane *primary = NULL, *plane; | ||
| 183 | int ret; | ||
| 184 | |||
| 185 | ret = malidp_de_planes_init(drm); | ||
| 186 | if (ret < 0) { | ||
| 187 | DRM_ERROR("Failed to initialise planes\n"); | ||
| 188 | return ret; | ||
| 189 | } | ||
| 190 | |||
| 191 | drm_for_each_plane(plane, drm) { | ||
| 192 | if (plane->type == DRM_PLANE_TYPE_PRIMARY) { | ||
| 193 | primary = plane; | ||
| 194 | break; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | if (!primary) { | ||
| 199 | DRM_ERROR("no primary plane found\n"); | ||
| 200 | ret = -EINVAL; | ||
| 201 | goto crtc_cleanup_planes; | ||
| 202 | } | ||
| 203 | |||
| 204 | ret = drm_crtc_init_with_planes(drm, &malidp->crtc, primary, NULL, | ||
| 205 | &malidp_crtc_funcs, NULL); | ||
| 206 | |||
| 207 | if (!ret) { | ||
| 208 | drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs); | ||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | |||
| 212 | crtc_cleanup_planes: | ||
| 213 | malidp_de_planes_destroy(drm); | ||
| 214 | |||
| 215 | return ret; | ||
| 216 | } | ||
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c new file mode 100644 index 000000000000..e5b44e92f8cf --- /dev/null +++ b/drivers/gpu/drm/arm/malidp_drv.c | |||
| @@ -0,0 +1,512 @@ | |||
| 1 | /* | ||
| 2 | * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. | ||
| 3 | * Author: Liviu Dudau <Liviu.Dudau@arm.com> | ||
| 4 | * | ||
| 5 | * This program is free software and is provided to you under the terms of the | ||
| 6 | * GNU General Public License version 2 as published by the Free Software | ||
| 7 | * Foundation, and any use by you of this program is subject to the terms | ||
| 8 | * of such GNU licence. | ||
| 9 | * | ||
| 10 | * ARM Mali DP500/DP550/DP650 KMS/DRM driver | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/clk.h> | ||
| 15 | #include <linux/component.h> | ||
| 16 | #include <linux/of_device.h> | ||
| 17 | #include <linux/of_graph.h> | ||
| 18 | #include <linux/of_reserved_mem.h> | ||
| 19 | |||
| 20 | #include <drm/drmP.h> | ||
| 21 | #include <drm/drm_atomic.h> | ||
| 22 | #include <drm/drm_atomic_helper.h> | ||
| 23 | #include <drm/drm_crtc.h> | ||
| 24 | #include <drm/drm_crtc_helper.h> | ||
| 25 | #include <drm/drm_fb_helper.h> | ||
| 26 | #include <drm/drm_fb_cma_helper.h> | ||
| 27 | #include <drm/drm_gem_cma_helper.h> | ||
| 28 | #include <drm/drm_of.h> | ||
| 29 | |||
| 30 | #include "malidp_drv.h" | ||
| 31 | #include "malidp_regs.h" | ||
| 32 | #include "malidp_hw.h" | ||
| 33 | |||
| 34 | #define MALIDP_CONF_VALID_TIMEOUT 250 | ||
| 35 | |||
| 36 | /* | ||
| 37 | * set the "config valid" bit and wait until the hardware acts on it | ||
| 38 | */ | ||
| 39 | static int malidp_set_and_wait_config_valid(struct drm_device *drm) | ||
| 40 | { | ||
| 41 | struct malidp_drm *malidp = drm->dev_private; | ||
| 42 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 43 | int ret; | ||
| 44 | |||
| 45 | hwdev->set_config_valid(hwdev); | ||
| 46 | /* don't wait for config_valid flag if we are in config mode */ | ||
| 47 | if (hwdev->in_config_mode(hwdev)) | ||
| 48 | return 0; | ||
| 49 | |||
| 50 | ret = wait_event_interruptible_timeout(malidp->wq, | ||
| 51 | atomic_read(&malidp->config_valid) == 1, | ||
| 52 | msecs_to_jiffies(MALIDP_CONF_VALID_TIMEOUT)); | ||
| 53 | |||
| 54 | return (ret > 0) ? 0 : -ETIMEDOUT; | ||
| 55 | } | ||
| 56 | |||
| 57 | static void malidp_output_poll_changed(struct drm_device *drm) | ||
| 58 | { | ||
| 59 | struct malidp_drm *malidp = drm->dev_private; | ||
| 60 | |||
| 61 | drm_fbdev_cma_hotplug_event(malidp->fbdev); | ||
| 62 | } | ||
| 63 | |||
| 64 | static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state) | ||
| 65 | { | ||
| 66 | struct drm_pending_vblank_event *event; | ||
| 67 | struct drm_device *drm = state->dev; | ||
| 68 | struct malidp_drm *malidp = drm->dev_private; | ||
| 69 | int ret = malidp_set_and_wait_config_valid(drm); | ||
| 70 | |||
| 71 | if (ret) | ||
| 72 | DRM_DEBUG_DRIVER("timed out waiting for updated configuration\n"); | ||
| 73 | |||
| 74 | event = malidp->crtc.state->event; | ||
| 75 | if (event) { | ||
| 76 | malidp->crtc.state->event = NULL; | ||
| 77 | |||
| 78 | spin_lock_irq(&drm->event_lock); | ||
| 79 | if (drm_crtc_vblank_get(&malidp->crtc) == 0) | ||
| 80 | drm_crtc_arm_vblank_event(&malidp->crtc, event); | ||
| 81 | else | ||
| 82 | drm_crtc_send_vblank_event(&malidp->crtc, event); | ||
| 83 | spin_unlock_irq(&drm->event_lock); | ||
| 84 | } | ||
| 85 | drm_atomic_helper_commit_hw_done(state); | ||
| 86 | } | ||
| 87 | |||
| 88 | static void malidp_atomic_commit_tail(struct drm_atomic_state *state) | ||
| 89 | { | ||
| 90 | struct drm_device *drm = state->dev; | ||
| 91 | |||
| 92 | drm_atomic_helper_commit_modeset_disables(drm, state); | ||
| 93 | drm_atomic_helper_commit_modeset_enables(drm, state); | ||
| 94 | drm_atomic_helper_commit_planes(drm, state, true); | ||
| 95 | |||
| 96 | malidp_atomic_commit_hw_done(state); | ||
| 97 | |||
| 98 | drm_atomic_helper_wait_for_vblanks(drm, state); | ||
| 99 | |||
| 100 | drm_atomic_helper_cleanup_planes(drm, state); | ||
| 101 | } | ||
| 102 | |||
| 103 | static struct drm_mode_config_helper_funcs malidp_mode_config_helpers = { | ||
| 104 | .atomic_commit_tail = malidp_atomic_commit_tail, | ||
| 105 | }; | ||
| 106 | |||
| 107 | static const struct drm_mode_config_funcs malidp_mode_config_funcs = { | ||
| 108 | .fb_create = drm_fb_cma_create, | ||
| 109 | .output_poll_changed = malidp_output_poll_changed, | ||
| 110 | .atomic_check = drm_atomic_helper_check, | ||
| 111 | .atomic_commit = drm_atomic_helper_commit, | ||
| 112 | }; | ||
| 113 | |||
| 114 | static int malidp_enable_vblank(struct drm_device *drm, unsigned int crtc) | ||
| 115 | { | ||
| 116 | struct malidp_drm *malidp = drm->dev_private; | ||
| 117 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 118 | |||
| 119 | malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK, | ||
| 120 | hwdev->map.de_irq_map.vsync_irq); | ||
| 121 | return 0; | ||
| 122 | } | ||
| 123 | |||
| 124 | static void malidp_disable_vblank(struct drm_device *drm, unsigned int pipe) | ||
| 125 | { | ||
| 126 | struct malidp_drm *malidp = drm->dev_private; | ||
| 127 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 128 | |||
| 129 | malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, | ||
| 130 | hwdev->map.de_irq_map.vsync_irq); | ||
| 131 | } | ||
| 132 | |||
| 133 | static int malidp_init(struct drm_device *drm) | ||
| 134 | { | ||
| 135 | int ret; | ||
| 136 | struct malidp_drm *malidp = drm->dev_private; | ||
| 137 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 138 | |||
| 139 | drm_mode_config_init(drm); | ||
| 140 | |||
| 141 | drm->mode_config.min_width = hwdev->min_line_size; | ||
| 142 | drm->mode_config.min_height = hwdev->min_line_size; | ||
| 143 | drm->mode_config.max_width = hwdev->max_line_size; | ||
| 144 | drm->mode_config.max_height = hwdev->max_line_size; | ||
| 145 | drm->mode_config.funcs = &malidp_mode_config_funcs; | ||
| 146 | drm->mode_config.helper_private = &malidp_mode_config_helpers; | ||
| 147 | |||
| 148 | ret = malidp_crtc_init(drm); | ||
| 149 | if (ret) { | ||
| 150 | drm_mode_config_cleanup(drm); | ||
| 151 | return ret; | ||
| 152 | } | ||
| 153 | |||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | static int malidp_irq_init(struct platform_device *pdev) | ||
| 158 | { | ||
| 159 | int irq_de, irq_se, ret = 0; | ||
| 160 | struct drm_device *drm = dev_get_drvdata(&pdev->dev); | ||
| 161 | |||
| 162 | /* fetch the interrupts from DT */ | ||
| 163 | irq_de = platform_get_irq_byname(pdev, "DE"); | ||
| 164 | if (irq_de < 0) { | ||
| 165 | DRM_ERROR("no 'DE' IRQ specified!\n"); | ||
| 166 | return irq_de; | ||
| 167 | } | ||
| 168 | irq_se = platform_get_irq_byname(pdev, "SE"); | ||
| 169 | if (irq_se < 0) { | ||
| 170 | DRM_ERROR("no 'SE' IRQ specified!\n"); | ||
| 171 | return irq_se; | ||
| 172 | } | ||
| 173 | |||
| 174 | ret = malidp_de_irq_init(drm, irq_de); | ||
| 175 | if (ret) | ||
| 176 | return ret; | ||
| 177 | |||
| 178 | ret = malidp_se_irq_init(drm, irq_se); | ||
| 179 | if (ret) { | ||
| 180 | malidp_de_irq_fini(drm); | ||
| 181 | return ret; | ||
| 182 | } | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | static void malidp_lastclose(struct drm_device *drm) | ||
| 188 | { | ||
| 189 | struct malidp_drm *malidp = drm->dev_private; | ||
| 190 | |||
| 191 | drm_fbdev_cma_restore_mode(malidp->fbdev); | ||
| 192 | } | ||
| 193 | |||
| 194 | static const struct file_operations fops = { | ||
| 195 | .owner = THIS_MODULE, | ||
| 196 | .open = drm_open, | ||
| 197 | .release = drm_release, | ||
| 198 | .unlocked_ioctl = drm_ioctl, | ||
| 199 | #ifdef CONFIG_COMPAT | ||
| 200 | .compat_ioctl = drm_compat_ioctl, | ||
| 201 | #endif | ||
| 202 | .poll = drm_poll, | ||
| 203 | .read = drm_read, | ||
| 204 | .llseek = noop_llseek, | ||
| 205 | .mmap = drm_gem_cma_mmap, | ||
| 206 | }; | ||
| 207 | |||
| 208 | static struct drm_driver malidp_driver = { | ||
| 209 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC | | ||
| 210 | DRIVER_PRIME, | ||
| 211 | .lastclose = malidp_lastclose, | ||
| 212 | .get_vblank_counter = drm_vblank_no_hw_counter, | ||
| 213 | .enable_vblank = malidp_enable_vblank, | ||
| 214 | .disable_vblank = malidp_disable_vblank, | ||
| 215 | .gem_free_object_unlocked = drm_gem_cma_free_object, | ||
| 216 | .gem_vm_ops = &drm_gem_cma_vm_ops, | ||
| 217 | .dumb_create = drm_gem_cma_dumb_create, | ||
| 218 | .dumb_map_offset = drm_gem_cma_dumb_map_offset, | ||
| 219 | .dumb_destroy = drm_gem_dumb_destroy, | ||
| 220 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | ||
| 221 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | ||
| 222 | .gem_prime_export = drm_gem_prime_export, | ||
| 223 | .gem_prime_import = drm_gem_prime_import, | ||
| 224 | .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, | ||
| 225 | .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, | ||
| 226 | .gem_prime_vmap = drm_gem_cma_prime_vmap, | ||
| 227 | .gem_prime_vunmap = drm_gem_cma_prime_vunmap, | ||
| 228 | .gem_prime_mmap = drm_gem_cma_prime_mmap, | ||
| 229 | .fops = &fops, | ||
| 230 | .name = "mali-dp", | ||
| 231 | .desc = "ARM Mali Display Processor driver", | ||
| 232 | .date = "20160106", | ||
| 233 | .major = 1, | ||
| 234 | .minor = 0, | ||
| 235 | }; | ||
| 236 | |||
| 237 | static const struct of_device_id malidp_drm_of_match[] = { | ||
| 238 | { | ||
| 239 | .compatible = "arm,mali-dp500", | ||
| 240 | .data = &malidp_device[MALIDP_500] | ||
| 241 | }, | ||
| 242 | { | ||
| 243 | .compatible = "arm,mali-dp550", | ||
| 244 | .data = &malidp_device[MALIDP_550] | ||
| 245 | }, | ||
| 246 | { | ||
| 247 | .compatible = "arm,mali-dp650", | ||
| 248 | .data = &malidp_device[MALIDP_650] | ||
| 249 | }, | ||
| 250 | {}, | ||
| 251 | }; | ||
| 252 | MODULE_DEVICE_TABLE(of, malidp_drm_of_match); | ||
| 253 | |||
| 254 | #define MAX_OUTPUT_CHANNELS 3 | ||
| 255 | |||
| 256 | static int malidp_bind(struct device *dev) | ||
| 257 | { | ||
| 258 | struct resource *res; | ||
| 259 | struct drm_device *drm; | ||
| 260 | struct malidp_drm *malidp; | ||
| 261 | struct malidp_hw_device *hwdev; | ||
| 262 | struct platform_device *pdev = to_platform_device(dev); | ||
| 263 | /* number of lines for the R, G and B output */ | ||
| 264 | u8 output_width[MAX_OUTPUT_CHANNELS]; | ||
| 265 | int ret = 0, i; | ||
| 266 | u32 version, out_depth = 0; | ||
| 267 | |||
| 268 | malidp = devm_kzalloc(dev, sizeof(*malidp), GFP_KERNEL); | ||
| 269 | if (!malidp) | ||
| 270 | return -ENOMEM; | ||
| 271 | |||
| 272 | hwdev = devm_kzalloc(dev, sizeof(*hwdev), GFP_KERNEL); | ||
| 273 | if (!hwdev) | ||
| 274 | return -ENOMEM; | ||
| 275 | |||
| 276 | /* | ||
| 277 | * copy the associated data from malidp_drm_of_match to avoid | ||
| 278 | * having to keep a reference to the OF node after binding | ||
| 279 | */ | ||
| 280 | memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev)); | ||
| 281 | malidp->dev = hwdev; | ||
| 282 | |||
| 283 | INIT_LIST_HEAD(&malidp->event_list); | ||
| 284 | |||
| 285 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 286 | hwdev->regs = devm_ioremap_resource(dev, res); | ||
| 287 | if (IS_ERR(hwdev->regs)) { | ||
| 288 | DRM_ERROR("Failed to map control registers area\n"); | ||
| 289 | return PTR_ERR(hwdev->regs); | ||
| 290 | } | ||
| 291 | |||
| 292 | hwdev->pclk = devm_clk_get(dev, "pclk"); | ||
| 293 | if (IS_ERR(hwdev->pclk)) | ||
| 294 | return PTR_ERR(hwdev->pclk); | ||
| 295 | |||
| 296 | hwdev->aclk = devm_clk_get(dev, "aclk"); | ||
| 297 | if (IS_ERR(hwdev->aclk)) | ||
| 298 | return PTR_ERR(hwdev->aclk); | ||
| 299 | |||
| 300 | hwdev->mclk = devm_clk_get(dev, "mclk"); | ||
| 301 | if (IS_ERR(hwdev->mclk)) | ||
| 302 | return PTR_ERR(hwdev->mclk); | ||
| 303 | |||
| 304 | hwdev->pxlclk = devm_clk_get(dev, "pxlclk"); | ||
| 305 | if (IS_ERR(hwdev->pxlclk)) | ||
| 306 | return PTR_ERR(hwdev->pxlclk); | ||
| 307 | |||
| 308 | /* Get the optional framebuffer memory resource */ | ||
| 309 | ret = of_reserved_mem_device_init(dev); | ||
| 310 | if (ret && ret != -ENODEV) | ||
| 311 | return ret; | ||
| 312 | |||
| 313 | drm = drm_dev_alloc(&malidp_driver, dev); | ||
| 314 | if (!drm) { | ||
| 315 | ret = -ENOMEM; | ||
| 316 | goto alloc_fail; | ||
| 317 | } | ||
| 318 | |||
| 319 | /* Enable APB clock in order to get access to the registers */ | ||
| 320 | clk_prepare_enable(hwdev->pclk); | ||
| 321 | /* | ||
| 322 | * Enable AXI clock and main clock so that prefetch can start once | ||
| 323 | * the registers are set | ||
| 324 | */ | ||
| 325 | clk_prepare_enable(hwdev->aclk); | ||
| 326 | clk_prepare_enable(hwdev->mclk); | ||
| 327 | |||
| 328 | ret = hwdev->query_hw(hwdev); | ||
| 329 | if (ret) { | ||
| 330 | DRM_ERROR("Invalid HW configuration\n"); | ||
| 331 | goto query_hw_fail; | ||
| 332 | } | ||
| 333 | |||
| 334 | version = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_DE_CORE_ID); | ||
| 335 | DRM_INFO("found ARM Mali-DP%3x version r%dp%d\n", version >> 16, | ||
| 336 | (version >> 12) & 0xf, (version >> 8) & 0xf); | ||
| 337 | |||
| 338 | /* set the number of lines used for output of RGB data */ | ||
| 339 | ret = of_property_read_u8_array(dev->of_node, | ||
| 340 | "arm,malidp-output-port-lines", | ||
| 341 | output_width, MAX_OUTPUT_CHANNELS); | ||
| 342 | if (ret) | ||
| 343 | goto query_hw_fail; | ||
| 344 | |||
| 345 | for (i = 0; i < MAX_OUTPUT_CHANNELS; i++) | ||
| 346 | out_depth = (out_depth << 8) | (output_width[i] & 0xf); | ||
| 347 | malidp_hw_write(hwdev, out_depth, hwdev->map.out_depth_base); | ||
| 348 | |||
| 349 | drm->dev_private = malidp; | ||
| 350 | dev_set_drvdata(dev, drm); | ||
| 351 | atomic_set(&malidp->config_valid, 0); | ||
| 352 | init_waitqueue_head(&malidp->wq); | ||
| 353 | |||
| 354 | ret = malidp_init(drm); | ||
| 355 | if (ret < 0) | ||
| 356 | goto init_fail; | ||
| 357 | |||
| 358 | ret = drm_dev_register(drm, 0); | ||
| 359 | if (ret) | ||
| 360 | goto register_fail; | ||
| 361 | |||
| 362 | /* Set the CRTC's port so that the encoder component can find it */ | ||
| 363 | malidp->crtc.port = of_graph_get_next_endpoint(dev->of_node, NULL); | ||
| 364 | |||
| 365 | ret = component_bind_all(dev, drm); | ||
| 366 | of_node_put(malidp->crtc.port); | ||
| 367 | |||
| 368 | if (ret) { | ||
| 369 | DRM_ERROR("Failed to bind all components\n"); | ||
| 370 | goto bind_fail; | ||
| 371 | } | ||
| 372 | |||
| 373 | ret = malidp_irq_init(pdev); | ||
| 374 | if (ret < 0) | ||
| 375 | goto irq_init_fail; | ||
| 376 | |||
| 377 | ret = drm_vblank_init(drm, drm->mode_config.num_crtc); | ||
| 378 | if (ret < 0) { | ||
| 379 | DRM_ERROR("failed to initialise vblank\n"); | ||
| 380 | goto vblank_fail; | ||
| 381 | } | ||
| 382 | |||
| 383 | drm_mode_config_reset(drm); | ||
| 384 | |||
| 385 | malidp->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc, | ||
| 386 | drm->mode_config.num_connector); | ||
| 387 | |||
| 388 | if (IS_ERR(malidp->fbdev)) { | ||
| 389 | ret = PTR_ERR(malidp->fbdev); | ||
| 390 | malidp->fbdev = NULL; | ||
| 391 | goto fbdev_fail; | ||
| 392 | } | ||
| 393 | |||
| 394 | drm_kms_helper_poll_init(drm); | ||
| 395 | return 0; | ||
| 396 | |||
| 397 | fbdev_fail: | ||
| 398 | drm_vblank_cleanup(drm); | ||
| 399 | vblank_fail: | ||
| 400 | malidp_se_irq_fini(drm); | ||
| 401 | malidp_de_irq_fini(drm); | ||
| 402 | irq_init_fail: | ||
| 403 | component_unbind_all(dev, drm); | ||
| 404 | bind_fail: | ||
| 405 | drm_dev_unregister(drm); | ||
| 406 | register_fail: | ||
| 407 | malidp_de_planes_destroy(drm); | ||
| 408 | drm_mode_config_cleanup(drm); | ||
| 409 | init_fail: | ||
| 410 | drm->dev_private = NULL; | ||
| 411 | dev_set_drvdata(dev, NULL); | ||
| 412 | query_hw_fail: | ||
| 413 | clk_disable_unprepare(hwdev->mclk); | ||
| 414 | clk_disable_unprepare(hwdev->aclk); | ||
| 415 | clk_disable_unprepare(hwdev->pclk); | ||
| 416 | drm_dev_unref(drm); | ||
| 417 | alloc_fail: | ||
| 418 | of_reserved_mem_device_release(dev); | ||
| 419 | |||
| 420 | return ret; | ||
| 421 | } | ||
| 422 | |||
| 423 | static void malidp_unbind(struct device *dev) | ||
| 424 | { | ||
| 425 | struct drm_device *drm = dev_get_drvdata(dev); | ||
| 426 | struct malidp_drm *malidp = drm->dev_private; | ||
| 427 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 428 | |||
| 429 | if (malidp->fbdev) { | ||
| 430 | drm_fbdev_cma_fini(malidp->fbdev); | ||
| 431 | malidp->fbdev = NULL; | ||
| 432 | } | ||
| 433 | drm_kms_helper_poll_fini(drm); | ||
| 434 | malidp_se_irq_fini(drm); | ||
| 435 | malidp_de_irq_fini(drm); | ||
| 436 | drm_vblank_cleanup(drm); | ||
| 437 | component_unbind_all(dev, drm); | ||
| 438 | drm_dev_unregister(drm); | ||
| 439 | malidp_de_planes_destroy(drm); | ||
| 440 | drm_mode_config_cleanup(drm); | ||
| 441 | drm->dev_private = NULL; | ||
| 442 | dev_set_drvdata(dev, NULL); | ||
| 443 | clk_disable_unprepare(hwdev->mclk); | ||
| 444 | clk_disable_unprepare(hwdev->aclk); | ||
| 445 | clk_disable_unprepare(hwdev->pclk); | ||
| 446 | drm_dev_unref(drm); | ||
| 447 | of_reserved_mem_device_release(dev); | ||
| 448 | } | ||
| 449 | |||
| 450 | static const struct component_master_ops malidp_master_ops = { | ||
| 451 | .bind = malidp_bind, | ||
| 452 | .unbind = malidp_unbind, | ||
| 453 | }; | ||
| 454 | |||
| 455 | static int malidp_compare_dev(struct device *dev, void *data) | ||
| 456 | { | ||
| 457 | struct device_node *np = data; | ||
| 458 | |||
| 459 | return dev->of_node == np; | ||
| 460 | } | ||
| 461 | |||
| 462 | static int malidp_platform_probe(struct platform_device *pdev) | ||
| 463 | { | ||
| 464 | struct device_node *port, *ep; | ||
| 465 | struct component_match *match = NULL; | ||
| 466 | |||
| 467 | if (!pdev->dev.of_node) | ||
| 468 | return -ENODEV; | ||
| 469 | |||
| 470 | /* there is only one output port inside each device, find it */ | ||
| 471 | ep = of_graph_get_next_endpoint(pdev->dev.of_node, NULL); | ||
| 472 | if (!ep) | ||
| 473 | return -ENODEV; | ||
| 474 | |||
| 475 | if (!of_device_is_available(ep)) { | ||
| 476 | of_node_put(ep); | ||
| 477 | return -ENODEV; | ||
| 478 | } | ||
| 479 | |||
| 480 | /* add the remote encoder port as component */ | ||
| 481 | port = of_graph_get_remote_port_parent(ep); | ||
| 482 | of_node_put(ep); | ||
| 483 | if (!port || !of_device_is_available(port)) { | ||
| 484 | of_node_put(port); | ||
| 485 | return -EAGAIN; | ||
| 486 | } | ||
| 487 | |||
| 488 | component_match_add(&pdev->dev, &match, malidp_compare_dev, port); | ||
| 489 | return component_master_add_with_match(&pdev->dev, &malidp_master_ops, | ||
| 490 | match); | ||
| 491 | } | ||
| 492 | |||
| 493 | static int malidp_platform_remove(struct platform_device *pdev) | ||
| 494 | { | ||
| 495 | component_master_del(&pdev->dev, &malidp_master_ops); | ||
| 496 | return 0; | ||
| 497 | } | ||
| 498 | |||
| 499 | static struct platform_driver malidp_platform_driver = { | ||
| 500 | .probe = malidp_platform_probe, | ||
| 501 | .remove = malidp_platform_remove, | ||
| 502 | .driver = { | ||
| 503 | .name = "mali-dp", | ||
| 504 | .of_match_table = malidp_drm_of_match, | ||
| 505 | }, | ||
| 506 | }; | ||
| 507 | |||
| 508 | module_platform_driver(malidp_platform_driver); | ||
| 509 | |||
| 510 | MODULE_AUTHOR("Liviu Dudau <Liviu.Dudau@arm.com>"); | ||
| 511 | MODULE_DESCRIPTION("ARM Mali DP DRM driver"); | ||
| 512 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h new file mode 100644 index 000000000000..95558fde214b --- /dev/null +++ b/drivers/gpu/drm/arm/malidp_drv.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* | ||
| 2 | * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. | ||
| 3 | * Author: Liviu Dudau <Liviu.Dudau@arm.com> | ||
| 4 | * | ||
| 5 | * This program is free software and is provided to you under the terms of the | ||
| 6 | * GNU General Public License version 2 as published by the Free Software | ||
| 7 | * Foundation, and any use by you of this program is subject to the terms | ||
| 8 | * of such GNU licence. | ||
| 9 | * | ||
| 10 | * ARM Mali DP500/DP550/DP650 KMS/DRM driver structures | ||
| 11 | */ | ||
| 12 | |||
| 13 | #ifndef __MALIDP_DRV_H__ | ||
| 14 | #define __MALIDP_DRV_H__ | ||
| 15 | |||
| 16 | #include <linux/mutex.h> | ||
| 17 | #include <linux/wait.h> | ||
| 18 | #include "malidp_hw.h" | ||
| 19 | |||
| 20 | struct malidp_drm { | ||
| 21 | struct malidp_hw_device *dev; | ||
| 22 | struct drm_fbdev_cma *fbdev; | ||
| 23 | struct list_head event_list; | ||
| 24 | struct drm_crtc crtc; | ||
| 25 | wait_queue_head_t wq; | ||
| 26 | atomic_t config_valid; | ||
| 27 | }; | ||
| 28 | |||
| 29 | #define crtc_to_malidp_device(x) container_of(x, struct malidp_drm, crtc) | ||
| 30 | |||
| 31 | struct malidp_plane { | ||
| 32 | struct drm_plane base; | ||
| 33 | struct malidp_hw_device *hwdev; | ||
| 34 | const struct malidp_layer *layer; | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct malidp_plane_state { | ||
| 38 | struct drm_plane_state base; | ||
| 39 | |||
| 40 | /* size of the required rotation memory if plane is rotated */ | ||
| 41 | u32 rotmem_size; | ||
| 42 | }; | ||
| 43 | |||
| 44 | #define to_malidp_plane(x) container_of(x, struct malidp_plane, base) | ||
| 45 | #define to_malidp_plane_state(x) container_of(x, struct malidp_plane_state, base) | ||
| 46 | |||
| 47 | int malidp_de_planes_init(struct drm_device *drm); | ||
| 48 | void malidp_de_planes_destroy(struct drm_device *drm); | ||
| 49 | int malidp_crtc_init(struct drm_device *drm); | ||
| 50 | |||
| 51 | /* often used combination of rotational bits */ | ||
| 52 | #define MALIDP_ROTATED_MASK (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270)) | ||
| 53 | |||
| 54 | #endif /* __MALIDP_DRV_H__ */ | ||
diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c new file mode 100644 index 000000000000..a6132f1d58c1 --- /dev/null +++ b/drivers/gpu/drm/arm/malidp_hw.c | |||
| @@ -0,0 +1,691 @@ | |||
| 1 | /* | ||
| 2 | * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. | ||
| 3 | * Author: Liviu Dudau <Liviu.Dudau@arm.com> | ||
| 4 | * | ||
| 5 | * This program is free software and is provided to you under the terms of the | ||
| 6 | * GNU General Public License version 2 as published by the Free Software | ||
| 7 | * Foundation, and any use by you of this program is subject to the terms | ||
| 8 | * of such GNU licence. | ||
| 9 | * | ||
| 10 | * ARM Mali DP500/DP550/DP650 hardware manipulation routines. This is where | ||
| 11 | * the difference between various versions of the hardware is being dealt with | ||
| 12 | * in an attempt to provide to the rest of the driver code a unified view | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/types.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | #include <drm/drmP.h> | ||
| 18 | #include <video/videomode.h> | ||
| 19 | #include <video/display_timing.h> | ||
| 20 | |||
| 21 | #include "malidp_drv.h" | ||
| 22 | #include "malidp_hw.h" | ||
| 23 | |||
| 24 | static const struct malidp_input_format malidp500_de_formats[] = { | ||
| 25 | /* fourcc, layers supporting the format, internal id */ | ||
| 26 | { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 0 }, | ||
| 27 | { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 1 }, | ||
| 28 | { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 2 }, | ||
| 29 | { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 3 }, | ||
| 30 | { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 4 }, | ||
| 31 | { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 5 }, | ||
| 32 | { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 6 }, | ||
| 33 | { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 7 }, | ||
| 34 | { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 8 }, | ||
| 35 | { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 9 }, | ||
| 36 | { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 }, | ||
| 37 | { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 }, | ||
| 38 | { DRM_FORMAT_UYVY, DE_VIDEO1, 12 }, | ||
| 39 | { DRM_FORMAT_YUYV, DE_VIDEO1, 13 }, | ||
| 40 | { DRM_FORMAT_NV12, DE_VIDEO1, 14 }, | ||
| 41 | { DRM_FORMAT_YUV420, DE_VIDEO1, 15 }, | ||
| 42 | }; | ||
| 43 | |||
| 44 | #define MALIDP_ID(__group, __format) \ | ||
| 45 | ((((__group) & 0x7) << 3) | ((__format) & 0x7)) | ||
| 46 | |||
| 47 | #define MALIDP_COMMON_FORMATS \ | ||
| 48 | /* fourcc, layers supporting the format, internal id */ \ | ||
| 49 | { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 0) }, \ | ||
| 50 | { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 1) }, \ | ||
| 51 | { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 2) }, \ | ||
| 52 | { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 3) }, \ | ||
| 53 | { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \ | ||
| 54 | { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \ | ||
| 55 | { DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \ | ||
| 56 | { DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \ | ||
| 57 | { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 0) }, \ | ||
| 58 | { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 1) }, \ | ||
| 59 | { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 2) }, \ | ||
| 60 | { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 3) }, \ | ||
| 61 | { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 0) }, \ | ||
| 62 | { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 1) }, \ | ||
| 63 | { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \ | ||
| 64 | { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \ | ||
| 65 | { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \ | ||
| 66 | { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \ | ||
| 67 | { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) }, \ | ||
| 68 | { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) }, \ | ||
| 69 | { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) }, \ | ||
| 70 | { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) } | ||
| 71 | |||
| 72 | static const struct malidp_input_format malidp550_de_formats[] = { | ||
| 73 | MALIDP_COMMON_FORMATS, | ||
| 74 | }; | ||
| 75 | |||
| 76 | static const struct malidp_layer malidp500_layers[] = { | ||
| 77 | { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE }, | ||
| 78 | { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE }, | ||
| 79 | { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE }, | ||
| 80 | }; | ||
| 81 | |||
| 82 | static const struct malidp_layer malidp550_layers[] = { | ||
| 83 | { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE }, | ||
| 84 | { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE }, | ||
| 85 | { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE }, | ||
| 86 | { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE }, | ||
| 87 | }; | ||
| 88 | |||
| 89 | #define MALIDP_DE_DEFAULT_PREFETCH_START 5 | ||
| 90 | |||
| 91 | static int malidp500_query_hw(struct malidp_hw_device *hwdev) | ||
| 92 | { | ||
| 93 | u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID); | ||
| 94 | /* bit 4 of the CONFIG_ID register holds the line size multiplier */ | ||
| 95 | u8 ln_size_mult = conf & 0x10 ? 2 : 1; | ||
| 96 | |||
| 97 | hwdev->min_line_size = 2; | ||
| 98 | hwdev->max_line_size = SZ_2K * ln_size_mult; | ||
| 99 | hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult; | ||
| 100 | hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */ | ||
| 101 | |||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev) | ||
| 106 | { | ||
| 107 | u32 status, count = 100; | ||
| 108 | |||
| 109 | malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL); | ||
| 110 | while (count) { | ||
| 111 | status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); | ||
| 112 | if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ) | ||
| 113 | break; | ||
| 114 | /* | ||
| 115 | * entering config mode can take as long as the rendering | ||
| 116 | * of a full frame, hence the long sleep here | ||
| 117 | */ | ||
| 118 | usleep_range(1000, 10000); | ||
| 119 | count--; | ||
| 120 | } | ||
| 121 | WARN(count == 0, "timeout while entering config mode"); | ||
| 122 | } | ||
| 123 | |||
| 124 | static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev) | ||
| 125 | { | ||
| 126 | u32 status, count = 100; | ||
| 127 | |||
| 128 | malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL); | ||
| 129 | while (count) { | ||
| 130 | status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); | ||
| 131 | if ((status & MALIDP500_DC_CONFIG_REQ) == 0) | ||
| 132 | break; | ||
| 133 | usleep_range(100, 1000); | ||
| 134 | count--; | ||
| 135 | } | ||
| 136 | WARN(count == 0, "timeout while leaving config mode"); | ||
| 137 | } | ||
| 138 | |||
| 139 | static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev) | ||
| 140 | { | ||
| 141 | u32 status; | ||
| 142 | |||
| 143 | status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); | ||
| 144 | if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ) | ||
| 145 | return true; | ||
| 146 | |||
| 147 | return false; | ||
| 148 | } | ||
| 149 | |||
| 150 | static void malidp500_set_config_valid(struct malidp_hw_device *hwdev) | ||
| 151 | { | ||
| 152 | malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); | ||
| 153 | } | ||
| 154 | |||
| 155 | static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode) | ||
| 156 | { | ||
| 157 | u32 val = 0; | ||
| 158 | |||
| 159 | malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL); | ||
| 160 | if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH) | ||
| 161 | val |= MALIDP500_HSYNCPOL; | ||
| 162 | if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH) | ||
| 163 | val |= MALIDP500_VSYNCPOL; | ||
| 164 | val |= MALIDP_DE_DEFAULT_PREFETCH_START; | ||
| 165 | malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL); | ||
| 166 | |||
| 167 | /* | ||
| 168 | * Mali-DP500 encodes the background color like this: | ||
| 169 | * - red @ MALIDP500_BGND_COLOR[12:0] | ||
| 170 | * - green @ MALIDP500_BGND_COLOR[27:16] | ||
| 171 | * - blue @ (MALIDP500_BGND_COLOR + 4)[12:0] | ||
| 172 | */ | ||
| 173 | val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) | | ||
| 174 | (MALIDP_BGND_COLOR_R & 0xfff); | ||
| 175 | malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR); | ||
| 176 | malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4); | ||
| 177 | |||
| 178 | val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) | | ||
| 179 | MALIDP_DE_H_BACKPORCH(mode->hback_porch); | ||
| 180 | malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS); | ||
| 181 | |||
| 182 | val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) | | ||
| 183 | MALIDP_DE_V_BACKPORCH(mode->vback_porch); | ||
| 184 | malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS); | ||
| 185 | |||
| 186 | val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) | | ||
| 187 | MALIDP_DE_V_SYNCWIDTH(mode->vsync_len); | ||
| 188 | malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH); | ||
| 189 | |||
| 190 | val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive); | ||
| 191 | malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE); | ||
| 192 | |||
| 193 | if (mode->flags & DISPLAY_FLAGS_INTERLACED) | ||
| 194 | malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); | ||
| 195 | else | ||
| 196 | malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); | ||
| 197 | } | ||
| 198 | |||
| 199 | static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt) | ||
| 200 | { | ||
| 201 | unsigned int depth; | ||
| 202 | int bpp; | ||
| 203 | |||
| 204 | /* RGB888 or BGR888 can't be rotated */ | ||
| 205 | if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888)) | ||
| 206 | return -EINVAL; | ||
| 207 | |||
| 208 | /* | ||
| 209 | * Each layer needs enough rotation memory to fit 8 lines | ||
| 210 | * worth of pixel data. Required size is then: | ||
| 211 | * size = rotated_width * (bpp / 8) * 8; | ||
| 212 | */ | ||
| 213 | drm_fb_get_bpp_depth(fmt, &depth, &bpp); | ||
| 214 | |||
| 215 | return w * bpp; | ||
| 216 | } | ||
| 217 | |||
| 218 | static int malidp550_query_hw(struct malidp_hw_device *hwdev) | ||
| 219 | { | ||
| 220 | u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); | ||
| 221 | u8 ln_size = (conf >> 4) & 0x3, rsize; | ||
| 222 | |||
| 223 | hwdev->min_line_size = 2; | ||
| 224 | |||
| 225 | switch (ln_size) { | ||
| 226 | case 0: | ||
| 227 | hwdev->max_line_size = SZ_2K; | ||
| 228 | /* two banks of 64KB for rotation memory */ | ||
| 229 | rsize = 64; | ||
| 230 | break; | ||
| 231 | case 1: | ||
| 232 | hwdev->max_line_size = SZ_4K; | ||
| 233 | /* two banks of 128KB for rotation memory */ | ||
| 234 | rsize = 128; | ||
| 235 | break; | ||
| 236 | case 2: | ||
| 237 | hwdev->max_line_size = 1280; | ||
| 238 | /* two banks of 40KB for rotation memory */ | ||
| 239 | rsize = 40; | ||
| 240 | break; | ||
| 241 | case 3: | ||
| 242 | /* reserved value */ | ||
| 243 | hwdev->max_line_size = 0; | ||
| 244 | return -EINVAL; | ||
| 245 | } | ||
| 246 | |||
| 247 | hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K; | ||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev) | ||
| 252 | { | ||
| 253 | u32 status, count = 100; | ||
| 254 | |||
| 255 | malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL); | ||
| 256 | while (count) { | ||
| 257 | status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); | ||
| 258 | if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ) | ||
| 259 | break; | ||
| 260 | /* | ||
| 261 | * entering config mode can take as long as the rendering | ||
| 262 | * of a full frame, hence the long sleep here | ||
| 263 | */ | ||
| 264 | usleep_range(1000, 10000); | ||
| 265 | count--; | ||
| 266 | } | ||
| 267 | WARN(count == 0, "timeout while entering config mode"); | ||
| 268 | } | ||
| 269 | |||
| 270 | static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev) | ||
| 271 | { | ||
| 272 | u32 status, count = 100; | ||
| 273 | |||
| 274 | malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL); | ||
| 275 | while (count) { | ||
| 276 | status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); | ||
| 277 | if ((status & MALIDP550_DC_CONFIG_REQ) == 0) | ||
| 278 | break; | ||
| 279 | usleep_range(100, 1000); | ||
| 280 | count--; | ||
| 281 | } | ||
| 282 | WARN(count == 0, "timeout while leaving config mode"); | ||
| 283 | } | ||
| 284 | |||
| 285 | static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev) | ||
| 286 | { | ||
| 287 | u32 status; | ||
| 288 | |||
| 289 | status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); | ||
| 290 | if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ) | ||
| 291 | return true; | ||
| 292 | |||
| 293 | return false; | ||
| 294 | } | ||
| 295 | |||
| 296 | static void malidp550_set_config_valid(struct malidp_hw_device *hwdev) | ||
| 297 | { | ||
| 298 | malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); | ||
| 299 | } | ||
| 300 | |||
| 301 | static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode) | ||
| 302 | { | ||
| 303 | u32 val = MALIDP_DE_DEFAULT_PREFETCH_START; | ||
| 304 | |||
| 305 | malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL); | ||
| 306 | /* | ||
| 307 | * Mali-DP550 and Mali-DP650 encode the background color like this: | ||
| 308 | * - red @ MALIDP550_DE_BGND_COLOR[23:16] | ||
| 309 | * - green @ MALIDP550_DE_BGND_COLOR[15:8] | ||
| 310 | * - blue @ MALIDP550_DE_BGND_COLOR[7:0] | ||
| 311 | * | ||
| 312 | * We need to truncate the least significant 4 bits from the default | ||
| 313 | * MALIDP_BGND_COLOR_x values | ||
| 314 | */ | ||
| 315 | val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) | | ||
| 316 | (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) | | ||
| 317 | ((MALIDP_BGND_COLOR_B >> 4) & 0xff); | ||
| 318 | malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR); | ||
| 319 | |||
| 320 | val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) | | ||
| 321 | MALIDP_DE_H_BACKPORCH(mode->hback_porch); | ||
| 322 | malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS); | ||
| 323 | |||
| 324 | val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) | | ||
| 325 | MALIDP_DE_V_BACKPORCH(mode->vback_porch); | ||
| 326 | malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS); | ||
| 327 | |||
| 328 | val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) | | ||
| 329 | MALIDP_DE_V_SYNCWIDTH(mode->vsync_len); | ||
| 330 | if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH) | ||
| 331 | val |= MALIDP550_HSYNCPOL; | ||
| 332 | if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH) | ||
| 333 | val |= MALIDP550_VSYNCPOL; | ||
| 334 | malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH); | ||
| 335 | |||
| 336 | val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive); | ||
| 337 | malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE); | ||
| 338 | |||
| 339 | if (mode->flags & DISPLAY_FLAGS_INTERLACED) | ||
| 340 | malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); | ||
| 341 | else | ||
| 342 | malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); | ||
| 343 | } | ||
| 344 | |||
| 345 | static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt) | ||
| 346 | { | ||
| 347 | u32 bytes_per_col; | ||
| 348 | |||
| 349 | /* raw RGB888 or BGR888 can't be rotated */ | ||
| 350 | if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888)) | ||
| 351 | return -EINVAL; | ||
| 352 | |||
| 353 | switch (fmt) { | ||
| 354 | /* 8 lines at 4 bytes per pixel */ | ||
| 355 | case DRM_FORMAT_ARGB2101010: | ||
| 356 | case DRM_FORMAT_ABGR2101010: | ||
| 357 | case DRM_FORMAT_RGBA1010102: | ||
| 358 | case DRM_FORMAT_BGRA1010102: | ||
| 359 | case DRM_FORMAT_ARGB8888: | ||
| 360 | case DRM_FORMAT_ABGR8888: | ||
| 361 | case DRM_FORMAT_RGBA8888: | ||
| 362 | case DRM_FORMAT_BGRA8888: | ||
| 363 | case DRM_FORMAT_XRGB8888: | ||
| 364 | case DRM_FORMAT_XBGR8888: | ||
| 365 | case DRM_FORMAT_RGBX8888: | ||
| 366 | case DRM_FORMAT_BGRX8888: | ||
| 367 | case DRM_FORMAT_RGB888: | ||
| 368 | case DRM_FORMAT_BGR888: | ||
| 369 | /* 16 lines at 2 bytes per pixel */ | ||
| 370 | case DRM_FORMAT_RGBA5551: | ||
| 371 | case DRM_FORMAT_ABGR1555: | ||
| 372 | case DRM_FORMAT_RGB565: | ||
| 373 | case DRM_FORMAT_BGR565: | ||
| 374 | case DRM_FORMAT_UYVY: | ||
| 375 | case DRM_FORMAT_YUYV: | ||
| 376 | bytes_per_col = 32; | ||
| 377 | break; | ||
| 378 | /* 16 lines at 1.5 bytes per pixel */ | ||
| 379 | case DRM_FORMAT_NV12: | ||
| 380 | case DRM_FORMAT_YUV420: | ||
| 381 | bytes_per_col = 24; | ||
| 382 | break; | ||
| 383 | default: | ||
| 384 | return -EINVAL; | ||
| 385 | } | ||
| 386 | |||
| 387 | return w * bytes_per_col; | ||
| 388 | } | ||
| 389 | |||
| 390 | static int malidp650_query_hw(struct malidp_hw_device *hwdev) | ||
| 391 | { | ||
| 392 | u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); | ||
| 393 | u8 ln_size = (conf >> 4) & 0x3, rsize; | ||
| 394 | |||
| 395 | hwdev->min_line_size = 4; | ||
| 396 | |||
| 397 | switch (ln_size) { | ||
| 398 | case 0: | ||
| 399 | case 2: | ||
| 400 | /* reserved values */ | ||
| 401 | hwdev->max_line_size = 0; | ||
| 402 | return -EINVAL; | ||
| 403 | case 1: | ||
| 404 | hwdev->max_line_size = SZ_4K; | ||
| 405 | /* two banks of 128KB for rotation memory */ | ||
| 406 | rsize = 128; | ||
| 407 | break; | ||
| 408 | case 3: | ||
| 409 | hwdev->max_line_size = 2560; | ||
| 410 | /* two banks of 80KB for rotation memory */ | ||
| 411 | rsize = 80; | ||
| 412 | } | ||
| 413 | |||
| 414 | hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K; | ||
| 415 | return 0; | ||
| 416 | } | ||
| 417 | |||
| 418 | const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { | ||
| 419 | [MALIDP_500] = { | ||
| 420 | .map = { | ||
| 421 | .se_base = MALIDP500_SE_BASE, | ||
| 422 | .dc_base = MALIDP500_DC_BASE, | ||
| 423 | .out_depth_base = MALIDP500_OUTPUT_DEPTH, | ||
| 424 | .features = 0, /* no CLEARIRQ register */ | ||
| 425 | .n_layers = ARRAY_SIZE(malidp500_layers), | ||
| 426 | .layers = malidp500_layers, | ||
| 427 | .de_irq_map = { | ||
| 428 | .irq_mask = MALIDP_DE_IRQ_UNDERRUN | | ||
| 429 | MALIDP500_DE_IRQ_AXI_ERR | | ||
| 430 | MALIDP500_DE_IRQ_VSYNC | | ||
| 431 | MALIDP500_DE_IRQ_GLOBAL, | ||
| 432 | .vsync_irq = MALIDP500_DE_IRQ_VSYNC, | ||
| 433 | }, | ||
| 434 | .se_irq_map = { | ||
| 435 | .irq_mask = MALIDP500_SE_IRQ_CONF_MODE, | ||
| 436 | .vsync_irq = 0, | ||
| 437 | }, | ||
| 438 | .dc_irq_map = { | ||
| 439 | .irq_mask = MALIDP500_DE_IRQ_CONF_VALID, | ||
| 440 | .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID, | ||
| 441 | }, | ||
| 442 | .input_formats = malidp500_de_formats, | ||
| 443 | .n_input_formats = ARRAY_SIZE(malidp500_de_formats), | ||
| 444 | }, | ||
| 445 | .query_hw = malidp500_query_hw, | ||
| 446 | .enter_config_mode = malidp500_enter_config_mode, | ||
| 447 | .leave_config_mode = malidp500_leave_config_mode, | ||
| 448 | .in_config_mode = malidp500_in_config_mode, | ||
| 449 | .set_config_valid = malidp500_set_config_valid, | ||
| 450 | .modeset = malidp500_modeset, | ||
| 451 | .rotmem_required = malidp500_rotmem_required, | ||
| 452 | }, | ||
| 453 | [MALIDP_550] = { | ||
| 454 | .map = { | ||
| 455 | .se_base = MALIDP550_SE_BASE, | ||
| 456 | .dc_base = MALIDP550_DC_BASE, | ||
| 457 | .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, | ||
| 458 | .features = MALIDP_REGMAP_HAS_CLEARIRQ, | ||
| 459 | .n_layers = ARRAY_SIZE(malidp550_layers), | ||
| 460 | .layers = malidp550_layers, | ||
| 461 | .de_irq_map = { | ||
| 462 | .irq_mask = MALIDP_DE_IRQ_UNDERRUN | | ||
| 463 | MALIDP550_DE_IRQ_VSYNC, | ||
| 464 | .vsync_irq = MALIDP550_DE_IRQ_VSYNC, | ||
| 465 | }, | ||
| 466 | .se_irq_map = { | ||
| 467 | .irq_mask = MALIDP550_SE_IRQ_EOW | | ||
| 468 | MALIDP550_SE_IRQ_AXI_ERR, | ||
| 469 | }, | ||
| 470 | .dc_irq_map = { | ||
| 471 | .irq_mask = MALIDP550_DC_IRQ_CONF_VALID, | ||
| 472 | .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, | ||
| 473 | }, | ||
| 474 | .input_formats = malidp550_de_formats, | ||
| 475 | .n_input_formats = ARRAY_SIZE(malidp550_de_formats), | ||
| 476 | }, | ||
| 477 | .query_hw = malidp550_query_hw, | ||
| 478 | .enter_config_mode = malidp550_enter_config_mode, | ||
| 479 | .leave_config_mode = malidp550_leave_config_mode, | ||
| 480 | .in_config_mode = malidp550_in_config_mode, | ||
| 481 | .set_config_valid = malidp550_set_config_valid, | ||
| 482 | .modeset = malidp550_modeset, | ||
| 483 | .rotmem_required = malidp550_rotmem_required, | ||
| 484 | }, | ||
| 485 | [MALIDP_650] = { | ||
| 486 | .map = { | ||
| 487 | .se_base = MALIDP550_SE_BASE, | ||
| 488 | .dc_base = MALIDP550_DC_BASE, | ||
| 489 | .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, | ||
| 490 | .features = MALIDP_REGMAP_HAS_CLEARIRQ, | ||
| 491 | .n_layers = ARRAY_SIZE(malidp550_layers), | ||
| 492 | .layers = malidp550_layers, | ||
| 493 | .de_irq_map = { | ||
| 494 | .irq_mask = MALIDP_DE_IRQ_UNDERRUN | | ||
| 495 | MALIDP650_DE_IRQ_DRIFT | | ||
| 496 | MALIDP550_DE_IRQ_VSYNC, | ||
| 497 | .vsync_irq = MALIDP550_DE_IRQ_VSYNC, | ||
| 498 | }, | ||
| 499 | .se_irq_map = { | ||
| 500 | .irq_mask = MALIDP550_SE_IRQ_EOW | | ||
| 501 | MALIDP550_SE_IRQ_AXI_ERR, | ||
| 502 | }, | ||
| 503 | .dc_irq_map = { | ||
| 504 | .irq_mask = MALIDP550_DC_IRQ_CONF_VALID, | ||
| 505 | .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, | ||
| 506 | }, | ||
| 507 | .input_formats = malidp550_de_formats, | ||
| 508 | .n_input_formats = ARRAY_SIZE(malidp550_de_formats), | ||
| 509 | }, | ||
| 510 | .query_hw = malidp650_query_hw, | ||
| 511 | .enter_config_mode = malidp550_enter_config_mode, | ||
| 512 | .leave_config_mode = malidp550_leave_config_mode, | ||
| 513 | .in_config_mode = malidp550_in_config_mode, | ||
| 514 | .set_config_valid = malidp550_set_config_valid, | ||
| 515 | .modeset = malidp550_modeset, | ||
| 516 | .rotmem_required = malidp550_rotmem_required, | ||
| 517 | }, | ||
| 518 | }; | ||
| 519 | |||
| 520 | u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map, | ||
| 521 | u8 layer_id, u32 format) | ||
| 522 | { | ||
| 523 | unsigned int i; | ||
| 524 | |||
| 525 | for (i = 0; i < map->n_input_formats; i++) { | ||
| 526 | if (((map->input_formats[i].layer & layer_id) == layer_id) && | ||
| 527 | (map->input_formats[i].format == format)) | ||
| 528 | return map->input_formats[i].id; | ||
| 529 | } | ||
| 530 | |||
| 531 | return MALIDP_INVALID_FORMAT_ID; | ||
| 532 | } | ||
| 533 | |||
| 534 | static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq) | ||
| 535 | { | ||
| 536 | u32 base = malidp_get_block_base(hwdev, block); | ||
| 537 | |||
| 538 | if (hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) | ||
| 539 | malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ); | ||
| 540 | else | ||
| 541 | malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS); | ||
| 542 | } | ||
| 543 | |||
| 544 | static irqreturn_t malidp_de_irq(int irq, void *arg) | ||
| 545 | { | ||
| 546 | struct drm_device *drm = arg; | ||
| 547 | struct malidp_drm *malidp = drm->dev_private; | ||
| 548 | struct malidp_hw_device *hwdev; | ||
| 549 | const struct malidp_irq_map *de; | ||
| 550 | u32 status, mask, dc_status; | ||
| 551 | irqreturn_t ret = IRQ_NONE; | ||
| 552 | |||
| 553 | if (!drm->dev_private) | ||
| 554 | return IRQ_HANDLED; | ||
| 555 | |||
| 556 | hwdev = malidp->dev; | ||
| 557 | de = &hwdev->map.de_irq_map; | ||
| 558 | |||
| 559 | /* first handle the config valid IRQ */ | ||
| 560 | dc_status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); | ||
| 561 | if (dc_status & hwdev->map.dc_irq_map.vsync_irq) { | ||
| 562 | /* we have a page flip event */ | ||
| 563 | atomic_set(&malidp->config_valid, 1); | ||
| 564 | malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status); | ||
| 565 | ret = IRQ_WAKE_THREAD; | ||
| 566 | } | ||
| 567 | |||
| 568 | status = malidp_hw_read(hwdev, MALIDP_REG_STATUS); | ||
| 569 | if (!(status & de->irq_mask)) | ||
| 570 | return ret; | ||
| 571 | |||
| 572 | mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ); | ||
| 573 | status &= mask; | ||
| 574 | if (status & de->vsync_irq) | ||
| 575 | drm_crtc_handle_vblank(&malidp->crtc); | ||
| 576 | |||
| 577 | malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status); | ||
| 578 | |||
| 579 | return (ret == IRQ_NONE) ? IRQ_HANDLED : ret; | ||
| 580 | } | ||
| 581 | |||
| 582 | static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg) | ||
| 583 | { | ||
| 584 | struct drm_device *drm = arg; | ||
| 585 | struct malidp_drm *malidp = drm->dev_private; | ||
| 586 | |||
| 587 | wake_up(&malidp->wq); | ||
| 588 | |||
| 589 | return IRQ_HANDLED; | ||
| 590 | } | ||
| 591 | |||
| 592 | int malidp_de_irq_init(struct drm_device *drm, int irq) | ||
| 593 | { | ||
| 594 | struct malidp_drm *malidp = drm->dev_private; | ||
| 595 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 596 | int ret; | ||
| 597 | |||
| 598 | /* ensure interrupts are disabled */ | ||
| 599 | malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff); | ||
| 600 | malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff); | ||
| 601 | malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff); | ||
| 602 | malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff); | ||
| 603 | |||
| 604 | ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq, | ||
| 605 | malidp_de_irq_thread_handler, | ||
| 606 | IRQF_SHARED, "malidp-de", drm); | ||
| 607 | if (ret < 0) { | ||
| 608 | DRM_ERROR("failed to install DE IRQ handler\n"); | ||
| 609 | return ret; | ||
| 610 | } | ||
| 611 | |||
| 612 | /* first enable the DC block IRQs */ | ||
| 613 | malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK, | ||
| 614 | hwdev->map.dc_irq_map.irq_mask); | ||
| 615 | |||
| 616 | /* now enable the DE block IRQs */ | ||
| 617 | malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK, | ||
| 618 | hwdev->map.de_irq_map.irq_mask); | ||
| 619 | |||
| 620 | return 0; | ||
| 621 | } | ||
| 622 | |||
| 623 | void malidp_de_irq_fini(struct drm_device *drm) | ||
| 624 | { | ||
| 625 | struct malidp_drm *malidp = drm->dev_private; | ||
| 626 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 627 | |||
| 628 | malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, | ||
| 629 | hwdev->map.de_irq_map.irq_mask); | ||
| 630 | malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, | ||
| 631 | hwdev->map.dc_irq_map.irq_mask); | ||
| 632 | } | ||
| 633 | |||
| 634 | static irqreturn_t malidp_se_irq(int irq, void *arg) | ||
| 635 | { | ||
| 636 | struct drm_device *drm = arg; | ||
| 637 | struct malidp_drm *malidp = drm->dev_private; | ||
| 638 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 639 | u32 status, mask; | ||
| 640 | |||
| 641 | status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS); | ||
| 642 | if (!(status & hwdev->map.se_irq_map.irq_mask)) | ||
| 643 | return IRQ_NONE; | ||
| 644 | |||
| 645 | mask = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_MASKIRQ); | ||
| 646 | status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS); | ||
| 647 | status &= mask; | ||
| 648 | /* ToDo: status decoding and firing up of VSYNC and page flip events */ | ||
| 649 | |||
| 650 | malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status); | ||
| 651 | |||
| 652 | return IRQ_HANDLED; | ||
| 653 | } | ||
| 654 | |||
| 655 | static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg) | ||
| 656 | { | ||
| 657 | return IRQ_HANDLED; | ||
| 658 | } | ||
| 659 | |||
| 660 | int malidp_se_irq_init(struct drm_device *drm, int irq) | ||
| 661 | { | ||
| 662 | struct malidp_drm *malidp = drm->dev_private; | ||
| 663 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 664 | int ret; | ||
| 665 | |||
| 666 | /* ensure interrupts are disabled */ | ||
| 667 | malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff); | ||
| 668 | malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff); | ||
| 669 | |||
| 670 | ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq, | ||
| 671 | malidp_se_irq_thread_handler, | ||
| 672 | IRQF_SHARED, "malidp-se", drm); | ||
| 673 | if (ret < 0) { | ||
| 674 | DRM_ERROR("failed to install SE IRQ handler\n"); | ||
| 675 | return ret; | ||
| 676 | } | ||
| 677 | |||
| 678 | malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK, | ||
| 679 | hwdev->map.se_irq_map.irq_mask); | ||
| 680 | |||
| 681 | return 0; | ||
| 682 | } | ||
| 683 | |||
| 684 | void malidp_se_irq_fini(struct drm_device *drm) | ||
| 685 | { | ||
| 686 | struct malidp_drm *malidp = drm->dev_private; | ||
| 687 | struct malidp_hw_device *hwdev = malidp->dev; | ||
| 688 | |||
| 689 | malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, | ||
| 690 | hwdev->map.se_irq_map.irq_mask); | ||
| 691 | } | ||
diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h new file mode 100644 index 000000000000..141743e9f3a6 --- /dev/null +++ b/drivers/gpu/drm/arm/malidp_hw.h | |||
| @@ -0,0 +1,241 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * (C) COPYRIGHT 2013-2016 ARM Limited. All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software and is provided to you under the terms of the | ||
| 6 | * GNU General Public License version 2 as published by the Free Software | ||
| 7 | * Foundation, and any use by you of this program is subject to the terms | ||
| 8 | * of such GNU licence. | ||
| 9 | * | ||
| 10 | * ARM Mali DP hardware manipulation routines. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #ifndef __MALIDP_HW_H__ | ||
| 14 | #define __MALIDP_HW_H__ | ||
| 15 | |||
| 16 | #include <linux/bitops.h> | ||
| 17 | #include "malidp_regs.h" | ||
| 18 | |||
| 19 | struct videomode; | ||
| 20 | struct clk; | ||
| 21 | |||
| 22 | /* Mali DP IP blocks */ | ||
| 23 | enum { | ||
| 24 | MALIDP_DE_BLOCK = 0, | ||
| 25 | MALIDP_SE_BLOCK, | ||
| 26 | MALIDP_DC_BLOCK | ||
| 27 | }; | ||
| 28 | |||
| 29 | /* Mali DP layer IDs */ | ||
| 30 | enum { | ||
| 31 | DE_VIDEO1 = BIT(0), | ||
| 32 | DE_GRAPHICS1 = BIT(1), | ||
| 33 | DE_GRAPHICS2 = BIT(2), /* used only in DP500 */ | ||
| 34 | DE_VIDEO2 = BIT(3), | ||
| 35 | DE_SMART = BIT(4), | ||
| 36 | }; | ||
| 37 | |||
| 38 | struct malidp_input_format { | ||
| 39 | u32 format; /* DRM fourcc */ | ||
| 40 | u8 layer; /* bitmask of layers supporting it */ | ||
| 41 | u8 id; /* used internally */ | ||
| 42 | }; | ||
| 43 | |||
| 44 | #define MALIDP_INVALID_FORMAT_ID 0xff | ||
| 45 | |||
| 46 | /* | ||
| 47 | * hide the differences between register maps | ||
| 48 | * by using a common structure to hold the | ||
| 49 | * base register offsets | ||
| 50 | */ | ||
| 51 | |||
| 52 | struct malidp_irq_map { | ||
| 53 | u32 irq_mask; /* mask of IRQs that can be enabled in the block */ | ||
| 54 | u32 vsync_irq; /* IRQ bit used for signaling during VSYNC */ | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct malidp_layer { | ||
| 58 | u16 id; /* layer ID */ | ||
| 59 | u16 base; /* address offset for the register bank */ | ||
| 60 | u16 ptr; /* address offset for the pointer register */ | ||
| 61 | }; | ||
| 62 | |||
| 63 | /* regmap features */ | ||
| 64 | #define MALIDP_REGMAP_HAS_CLEARIRQ (1 << 0) | ||
| 65 | |||
| 66 | struct malidp_hw_regmap { | ||
| 67 | /* address offset of the DE register bank */ | ||
| 68 | /* is always 0x0000 */ | ||
| 69 | /* address offset of the SE registers bank */ | ||
| 70 | const u16 se_base; | ||
| 71 | /* address offset of the DC registers bank */ | ||
| 72 | const u16 dc_base; | ||
| 73 | |||
| 74 | /* address offset for the output depth register */ | ||
| 75 | const u16 out_depth_base; | ||
| 76 | |||
| 77 | /* bitmap with register map features */ | ||
| 78 | const u8 features; | ||
| 79 | |||
| 80 | /* list of supported layers */ | ||
| 81 | const u8 n_layers; | ||
| 82 | const struct malidp_layer *layers; | ||
| 83 | |||
| 84 | const struct malidp_irq_map de_irq_map; | ||
| 85 | const struct malidp_irq_map se_irq_map; | ||
| 86 | const struct malidp_irq_map dc_irq_map; | ||
| 87 | |||
| 88 | /* list of supported input formats for each layer */ | ||
| 89 | const struct malidp_input_format *input_formats; | ||
| 90 | const u8 n_input_formats; | ||
| 91 | }; | ||
| 92 | |||
| 93 | struct malidp_hw_device { | ||
| 94 | const struct malidp_hw_regmap map; | ||
| 95 | void __iomem *regs; | ||
| 96 | |||
| 97 | /* APB clock */ | ||
| 98 | struct clk *pclk; | ||
| 99 | /* AXI clock */ | ||
| 100 | struct clk *aclk; | ||
| 101 | /* main clock for display core */ | ||
| 102 | struct clk *mclk; | ||
| 103 | /* pixel clock for display core */ | ||
| 104 | struct clk *pxlclk; | ||
| 105 | |||
| 106 | /* | ||
| 107 | * Validate the driver instance against the hardware bits | ||
| 108 | */ | ||
| 109 | int (*query_hw)(struct malidp_hw_device *hwdev); | ||
| 110 | |||
| 111 | /* | ||
| 112 | * Set the hardware into config mode, ready to accept mode changes | ||
| 113 | */ | ||
| 114 | void (*enter_config_mode)(struct malidp_hw_device *hwdev); | ||
| 115 | |||
| 116 | /* | ||
| 117 | * Tell hardware to exit configuration mode | ||
| 118 | */ | ||
| 119 | void (*leave_config_mode)(struct malidp_hw_device *hwdev); | ||
| 120 | |||
| 121 | /* | ||
| 122 | * Query if hardware is in configuration mode | ||
| 123 | */ | ||
| 124 | bool (*in_config_mode)(struct malidp_hw_device *hwdev); | ||
| 125 | |||
| 126 | /* | ||
| 127 | * Set configuration valid flag for hardware parameters that can | ||
| 128 | * be changed outside the configuration mode. Hardware will use | ||
| 129 | * the new settings when config valid is set after the end of the | ||
| 130 | * current buffer scanout | ||
| 131 | */ | ||
| 132 | void (*set_config_valid)(struct malidp_hw_device *hwdev); | ||
| 133 | |||
| 134 | /* | ||
| 135 | * Set a new mode in hardware. Requires the hardware to be in | ||
| 136 | * configuration mode before this function is called. | ||
| 137 | */ | ||
| 138 | void (*modeset)(struct malidp_hw_device *hwdev, struct videomode *m); | ||
| 139 | |||
| 140 | /* | ||
| 141 | * Calculate the required rotation memory given the active area | ||
| 142 | * and the buffer format. | ||
| 143 | */ | ||
| 144 | int (*rotmem_required)(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt); | ||
| 145 | |||
| 146 | u8 features; | ||
| 147 | |||
| 148 | u8 min_line_size; | ||
| 149 | u16 max_line_size; | ||
| 150 | |||
| 151 | /* size of memory used for rotating layers, up to two banks available */ | ||
| 152 | u32 rotation_memory[2]; | ||
| 153 | }; | ||
| 154 | |||
| 155 | /* Supported variants of the hardware */ | ||
| 156 | enum { | ||
| 157 | MALIDP_500 = 0, | ||
| 158 | MALIDP_550, | ||
| 159 | MALIDP_650, | ||
| 160 | /* keep the next entry last */ | ||
| 161 | MALIDP_MAX_DEVICES | ||
| 162 | }; | ||
| 163 | |||
| 164 | extern const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES]; | ||
| 165 | |||
| 166 | static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg) | ||
| 167 | { | ||
| 168 | return readl(hwdev->regs + reg); | ||
| 169 | } | ||
| 170 | |||
| 171 | static inline void malidp_hw_write(struct malidp_hw_device *hwdev, | ||
| 172 | u32 value, u32 reg) | ||
| 173 | { | ||
| 174 | writel(value, hwdev->regs + reg); | ||
| 175 | } | ||
| 176 | |||
| 177 | static inline void malidp_hw_setbits(struct malidp_hw_device *hwdev, | ||
| 178 | u32 mask, u32 reg) | ||
| 179 | { | ||
| 180 | u32 data = malidp_hw_read(hwdev, reg); | ||
| 181 | |||
| 182 | data |= mask; | ||
| 183 | malidp_hw_write(hwdev, data, reg); | ||
| 184 | } | ||
| 185 | |||
| 186 | static inline void malidp_hw_clearbits(struct malidp_hw_device *hwdev, | ||
| 187 | u32 mask, u32 reg) | ||
| 188 | { | ||
| 189 | u32 data = malidp_hw_read(hwdev, reg); | ||
| 190 | |||
| 191 | data &= ~mask; | ||
| 192 | malidp_hw_write(hwdev, data, reg); | ||
| 193 | } | ||
| 194 | |||
| 195 | static inline u32 malidp_get_block_base(struct malidp_hw_device *hwdev, | ||
| 196 | u8 block) | ||
| 197 | { | ||
| 198 | switch (block) { | ||
| 199 | case MALIDP_SE_BLOCK: | ||
| 200 | return hwdev->map.se_base; | ||
| 201 | case MALIDP_DC_BLOCK: | ||
| 202 | return hwdev->map.dc_base; | ||
| 203 | } | ||
| 204 | |||
| 205 | return 0; | ||
| 206 | } | ||
| 207 | |||
| 208 | static inline void malidp_hw_disable_irq(struct malidp_hw_device *hwdev, | ||
| 209 | u8 block, u32 irq) | ||
| 210 | { | ||
| 211 | u32 base = malidp_get_block_base(hwdev, block); | ||
| 212 | |||
| 213 | malidp_hw_clearbits(hwdev, irq, base + MALIDP_REG_MASKIRQ); | ||
| 214 | } | ||
| 215 | |||
| 216 | static inline void malidp_hw_enable_irq(struct malidp_hw_device *hwdev, | ||
| 217 | u8 block, u32 irq) | ||
| 218 | { | ||
| 219 | u32 base = malidp_get_block_base(hwdev, block); | ||
| 220 | |||
| 221 | malidp_hw_setbits(hwdev, irq, base + MALIDP_REG_MASKIRQ); | ||
| 222 | } | ||
| 223 | |||
| 224 | int malidp_de_irq_init(struct drm_device *drm, int irq); | ||
| 225 | void malidp_de_irq_fini(struct drm_device *drm); | ||
| 226 | int malidp_se_irq_init(struct drm_device *drm, int irq); | ||
| 227 | void malidp_se_irq_fini(struct drm_device *drm); | ||
| 228 | |||
| 229 | u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map, | ||
| 230 | u8 layer_id, u32 format); | ||
| 231 | |||
| 232 | /* | ||
| 233 | * background color components are defined as 12bits values, | ||
| 234 | * they will be shifted right when stored on hardware that | ||
| 235 | * supports only 8bits per channel | ||
| 236 | */ | ||
| 237 | #define MALIDP_BGND_COLOR_R 0x000 | ||
| 238 | #define MALIDP_BGND_COLOR_G 0x000 | ||
| 239 | #define MALIDP_BGND_COLOR_B 0x000 | ||
| 240 | |||
| 241 | #endif /* __MALIDP_HW_H__ */ | ||
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c new file mode 100644 index 000000000000..725098d6179a --- /dev/null +++ b/drivers/gpu/drm/arm/malidp_planes.c | |||
| @@ -0,0 +1,298 @@ | |||
| 1 | /* | ||
| 2 | * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. | ||
| 3 | * Author: Liviu Dudau <Liviu.Dudau@arm.com> | ||
| 4 | * | ||
| 5 | * This program is free software and is provided to you under the terms of the | ||
| 6 | * GNU General Public License version 2 as published by the Free Software | ||
| 7 | * Foundation, and any use by you of this program is subject to the terms | ||
| 8 | * of such GNU licence. | ||
| 9 | * | ||
| 10 | * ARM Mali DP plane manipulation routines. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <drm/drmP.h> | ||
| 14 | #include <drm/drm_atomic_helper.h> | ||
| 15 | #include <drm/drm_fb_cma_helper.h> | ||
| 16 | #include <drm/drm_gem_cma_helper.h> | ||
| 17 | #include <drm/drm_plane_helper.h> | ||
| 18 | |||
| 19 | #include "malidp_hw.h" | ||
| 20 | #include "malidp_drv.h" | ||
| 21 | |||
| 22 | /* Layer specific register offsets */ | ||
| 23 | #define MALIDP_LAYER_FORMAT 0x000 | ||
| 24 | #define MALIDP_LAYER_CONTROL 0x004 | ||
| 25 | #define LAYER_ENABLE (1 << 0) | ||
| 26 | #define LAYER_ROT_OFFSET 8 | ||
| 27 | #define LAYER_H_FLIP (1 << 10) | ||
| 28 | #define LAYER_V_FLIP (1 << 11) | ||
| 29 | #define LAYER_ROT_MASK (0xf << 8) | ||
| 30 | #define MALIDP_LAYER_SIZE 0x00c | ||
| 31 | #define LAYER_H_VAL(x) (((x) & 0x1fff) << 0) | ||
| 32 | #define LAYER_V_VAL(x) (((x) & 0x1fff) << 16) | ||
| 33 | #define MALIDP_LAYER_COMP_SIZE 0x010 | ||
| 34 | #define MALIDP_LAYER_OFFSET 0x014 | ||
| 35 | #define MALIDP_LAYER_STRIDE 0x018 | ||
| 36 | |||
| 37 | static void malidp_de_plane_destroy(struct drm_plane *plane) | ||
| 38 | { | ||
| 39 | struct malidp_plane *mp = to_malidp_plane(plane); | ||
| 40 | |||
| 41 | if (mp->base.fb) | ||
| 42 | drm_framebuffer_unreference(mp->base.fb); | ||
| 43 | |||
| 44 | drm_plane_helper_disable(plane); | ||
| 45 | drm_plane_cleanup(plane); | ||
| 46 | devm_kfree(plane->dev->dev, mp); | ||
| 47 | } | ||
| 48 | |||
| 49 | struct drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane) | ||
| 50 | { | ||
| 51 | struct malidp_plane_state *state, *m_state; | ||
| 52 | |||
| 53 | if (!plane->state) | ||
| 54 | return NULL; | ||
| 55 | |||
| 56 | state = kmalloc(sizeof(*state), GFP_KERNEL); | ||
| 57 | if (state) { | ||
| 58 | m_state = to_malidp_plane_state(plane->state); | ||
| 59 | __drm_atomic_helper_plane_duplicate_state(plane, &state->base); | ||
| 60 | state->rotmem_size = m_state->rotmem_size; | ||
| 61 | } | ||
| 62 | |||
| 63 | return &state->base; | ||
| 64 | } | ||
| 65 | |||
| 66 | void malidp_destroy_plane_state(struct drm_plane *plane, | ||
| 67 | struct drm_plane_state *state) | ||
| 68 | { | ||
| 69 | struct malidp_plane_state *m_state = to_malidp_plane_state(state); | ||
| 70 | |||
| 71 | __drm_atomic_helper_plane_destroy_state(state); | ||
| 72 | kfree(m_state); | ||
| 73 | } | ||
| 74 | |||
| 75 | static const struct drm_plane_funcs malidp_de_plane_funcs = { | ||
| 76 | .update_plane = drm_atomic_helper_update_plane, | ||
| 77 | .disable_plane = drm_atomic_helper_disable_plane, | ||
| 78 | .destroy = malidp_de_plane_destroy, | ||
| 79 | .reset = drm_atomic_helper_plane_reset, | ||
| 80 | .atomic_duplicate_state = malidp_duplicate_plane_state, | ||
| 81 | .atomic_destroy_state = malidp_destroy_plane_state, | ||
| 82 | }; | ||
| 83 | |||
| 84 | static int malidp_de_plane_check(struct drm_plane *plane, | ||
| 85 | struct drm_plane_state *state) | ||
| 86 | { | ||
| 87 | struct malidp_plane *mp = to_malidp_plane(plane); | ||
| 88 | struct malidp_plane_state *ms = to_malidp_plane_state(state); | ||
| 89 | u8 format_id; | ||
| 90 | u32 src_w, src_h; | ||
| 91 | |||
| 92 | if (!state->crtc || !state->fb) | ||
| 93 | return 0; | ||
| 94 | |||
| 95 | format_id = malidp_hw_get_format_id(&mp->hwdev->map, mp->layer->id, | ||
| 96 | state->fb->pixel_format); | ||
| 97 | if (format_id == MALIDP_INVALID_FORMAT_ID) | ||
| 98 | return -EINVAL; | ||
| 99 | |||
| 100 | src_w = state->src_w >> 16; | ||
| 101 | src_h = state->src_h >> 16; | ||
| 102 | |||
| 103 | if ((state->crtc_w > mp->hwdev->max_line_size) || | ||
| 104 | (state->crtc_h > mp->hwdev->max_line_size) || | ||
| 105 | (state->crtc_w < mp->hwdev->min_line_size) || | ||
| 106 | (state->crtc_h < mp->hwdev->min_line_size) || | ||
| 107 | (state->crtc_w != src_w) || (state->crtc_h != src_h)) | ||
| 108 | return -EINVAL; | ||
| 109 | |||
| 110 | /* packed RGB888 / BGR888 can't be rotated or flipped */ | ||
| 111 | if (state->rotation != BIT(DRM_ROTATE_0) && | ||
| 112 | (state->fb->pixel_format == DRM_FORMAT_RGB888 || | ||
| 113 | state->fb->pixel_format == DRM_FORMAT_BGR888)) | ||
| 114 | return -EINVAL; | ||
| 115 | |||
| 116 | ms->rotmem_size = 0; | ||
| 117 | if (state->rotation & MALIDP_ROTATED_MASK) { | ||
| 118 | int val; | ||
| 119 | |||
| 120 | val = mp->hwdev->rotmem_required(mp->hwdev, state->crtc_h, | ||
| 121 | state->crtc_w, | ||
| 122 | state->fb->pixel_format); | ||
| 123 | if (val < 0) | ||
| 124 | return val; | ||
| 125 | |||
| 126 | ms->rotmem_size = val; | ||
| 127 | } | ||
| 128 | |||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | static void malidp_de_plane_update(struct drm_plane *plane, | ||
| 133 | struct drm_plane_state *old_state) | ||
| 134 | { | ||
| 135 | struct drm_gem_cma_object *obj; | ||
| 136 | struct malidp_plane *mp; | ||
| 137 | const struct malidp_hw_regmap *map; | ||
| 138 | u8 format_id; | ||
| 139 | u16 ptr; | ||
| 140 | u32 format, src_w, src_h, dest_w, dest_h, val = 0; | ||
| 141 | int num_planes, i; | ||
| 142 | |||
| 143 | mp = to_malidp_plane(plane); | ||
| 144 | |||
| 145 | map = &mp->hwdev->map; | ||
| 146 | format = plane->state->fb->pixel_format; | ||
| 147 | format_id = malidp_hw_get_format_id(map, mp->layer->id, format); | ||
| 148 | num_planes = drm_format_num_planes(format); | ||
| 149 | |||
| 150 | /* convert src values from Q16 fixed point to integer */ | ||
| 151 | src_w = plane->state->src_w >> 16; | ||
| 152 | src_h = plane->state->src_h >> 16; | ||
| 153 | if (plane->state->rotation & MALIDP_ROTATED_MASK) { | ||
| 154 | dest_w = plane->state->crtc_h; | ||
| 155 | dest_h = plane->state->crtc_w; | ||
| 156 | } else { | ||
| 157 | dest_w = plane->state->crtc_w; | ||
| 158 | dest_h = plane->state->crtc_h; | ||
| 159 | } | ||
| 160 | |||
| 161 | malidp_hw_write(mp->hwdev, format_id, mp->layer->base); | ||
| 162 | |||
| 163 | for (i = 0; i < num_planes; i++) { | ||
| 164 | /* calculate the offset for the layer's plane registers */ | ||
| 165 | ptr = mp->layer->ptr + (i << 4); | ||
| 166 | |||
| 167 | obj = drm_fb_cma_get_gem_obj(plane->state->fb, i); | ||
| 168 | malidp_hw_write(mp->hwdev, lower_32_bits(obj->paddr), ptr); | ||
| 169 | malidp_hw_write(mp->hwdev, upper_32_bits(obj->paddr), ptr + 4); | ||
| 170 | malidp_hw_write(mp->hwdev, plane->state->fb->pitches[i], | ||
| 171 | mp->layer->base + MALIDP_LAYER_STRIDE); | ||
| 172 | } | ||
| 173 | |||
| 174 | malidp_hw_write(mp->hwdev, LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h), | ||
| 175 | mp->layer->base + MALIDP_LAYER_SIZE); | ||
| 176 | |||
| 177 | malidp_hw_write(mp->hwdev, LAYER_H_VAL(dest_w) | LAYER_V_VAL(dest_h), | ||
| 178 | mp->layer->base + MALIDP_LAYER_COMP_SIZE); | ||
| 179 | |||
| 180 | malidp_hw_write(mp->hwdev, LAYER_H_VAL(plane->state->crtc_x) | | ||
| 181 | LAYER_V_VAL(plane->state->crtc_y), | ||
| 182 | mp->layer->base + MALIDP_LAYER_OFFSET); | ||
| 183 | |||
| 184 | /* first clear the rotation bits in the register */ | ||
| 185 | malidp_hw_clearbits(mp->hwdev, LAYER_ROT_MASK, | ||
| 186 | mp->layer->base + MALIDP_LAYER_CONTROL); | ||
| 187 | |||
| 188 | /* setup the rotation and axis flip bits */ | ||
| 189 | if (plane->state->rotation & DRM_ROTATE_MASK) | ||
| 190 | val = ilog2(plane->state->rotation & DRM_ROTATE_MASK) << LAYER_ROT_OFFSET; | ||
| 191 | if (plane->state->rotation & BIT(DRM_REFLECT_X)) | ||
| 192 | val |= LAYER_V_FLIP; | ||
| 193 | if (plane->state->rotation & BIT(DRM_REFLECT_Y)) | ||
| 194 | val |= LAYER_H_FLIP; | ||
| 195 | |||
| 196 | /* set the 'enable layer' bit */ | ||
| 197 | val |= LAYER_ENABLE; | ||
| 198 | |||
| 199 | malidp_hw_setbits(mp->hwdev, val, | ||
| 200 | mp->layer->base + MALIDP_LAYER_CONTROL); | ||
| 201 | } | ||
| 202 | |||
| 203 | static void malidp_de_plane_disable(struct drm_plane *plane, | ||
| 204 | struct drm_plane_state *state) | ||
| 205 | { | ||
| 206 | struct malidp_plane *mp = to_malidp_plane(plane); | ||
| 207 | |||
| 208 | malidp_hw_clearbits(mp->hwdev, LAYER_ENABLE, | ||
| 209 | mp->layer->base + MALIDP_LAYER_CONTROL); | ||
| 210 | } | ||
| 211 | |||
| 212 | static const struct drm_plane_helper_funcs malidp_de_plane_helper_funcs = { | ||
| 213 | .atomic_check = malidp_de_plane_check, | ||
| 214 | .atomic_update = malidp_de_plane_update, | ||
| 215 | .atomic_disable = malidp_de_plane_disable, | ||
| 216 | }; | ||
| 217 | |||
| 218 | int malidp_de_planes_init(struct drm_device *drm) | ||
| 219 | { | ||
| 220 | struct malidp_drm *malidp = drm->dev_private; | ||
| 221 | const struct malidp_hw_regmap *map = &malidp->dev->map; | ||
| 222 | struct malidp_plane *plane = NULL; | ||
| 223 | enum drm_plane_type plane_type; | ||
| 224 | unsigned long crtcs = 1 << drm->mode_config.num_crtc; | ||
| 225 | u32 *formats; | ||
| 226 | int ret, i, j, n; | ||
| 227 | |||
| 228 | formats = kcalloc(map->n_input_formats, sizeof(*formats), GFP_KERNEL); | ||
| 229 | if (!formats) { | ||
| 230 | ret = -ENOMEM; | ||
| 231 | goto cleanup; | ||
| 232 | } | ||
| 233 | |||
| 234 | for (i = 0; i < map->n_layers; i++) { | ||
| 235 | u8 id = map->layers[i].id; | ||
| 236 | |||
| 237 | plane = kzalloc(sizeof(*plane), GFP_KERNEL); | ||
| 238 | if (!plane) { | ||
| 239 | ret = -ENOMEM; | ||
| 240 | goto cleanup; | ||
| 241 | } | ||
| 242 | |||
| 243 | /* build the list of DRM supported formats based on the map */ | ||
| 244 | for (n = 0, j = 0; j < map->n_input_formats; j++) { | ||
| 245 | if ((map->input_formats[j].layer & id) == id) | ||
| 246 | formats[n++] = map->input_formats[j].format; | ||
| 247 | } | ||
| 248 | |||
| 249 | plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY : | ||
| 250 | DRM_PLANE_TYPE_OVERLAY; | ||
| 251 | ret = drm_universal_plane_init(drm, &plane->base, crtcs, | ||
| 252 | &malidp_de_plane_funcs, formats, | ||
| 253 | n, plane_type, NULL); | ||
| 254 | if (ret < 0) | ||
| 255 | goto cleanup; | ||
| 256 | |||
| 257 | if (!drm->mode_config.rotation_property) { | ||
| 258 | unsigned long flags = BIT(DRM_ROTATE_0) | | ||
| 259 | BIT(DRM_ROTATE_90) | | ||
| 260 | BIT(DRM_ROTATE_180) | | ||
| 261 | BIT(DRM_ROTATE_270) | | ||
| 262 | BIT(DRM_REFLECT_X) | | ||
| 263 | BIT(DRM_REFLECT_Y); | ||
| 264 | drm->mode_config.rotation_property = | ||
| 265 | drm_mode_create_rotation_property(drm, flags); | ||
| 266 | } | ||
| 267 | /* SMART layer can't be rotated */ | ||
| 268 | if (drm->mode_config.rotation_property && (id != DE_SMART)) | ||
| 269 | drm_object_attach_property(&plane->base.base, | ||
| 270 | drm->mode_config.rotation_property, | ||
| 271 | BIT(DRM_ROTATE_0)); | ||
| 272 | |||
| 273 | drm_plane_helper_add(&plane->base, | ||
| 274 | &malidp_de_plane_helper_funcs); | ||
| 275 | plane->hwdev = malidp->dev; | ||
| 276 | plane->layer = &map->layers[i]; | ||
| 277 | } | ||
| 278 | |||
| 279 | kfree(formats); | ||
| 280 | |||
| 281 | return 0; | ||
| 282 | |||
| 283 | cleanup: | ||
| 284 | malidp_de_planes_destroy(drm); | ||
| 285 | kfree(formats); | ||
| 286 | |||
| 287 | return ret; | ||
| 288 | } | ||
| 289 | |||
| 290 | void malidp_de_planes_destroy(struct drm_device *drm) | ||
| 291 | { | ||
| 292 | struct drm_plane *p, *pt; | ||
| 293 | |||
| 294 | list_for_each_entry_safe(p, pt, &drm->mode_config.plane_list, head) { | ||
| 295 | drm_plane_cleanup(p); | ||
| 296 | kfree(p); | ||
| 297 | } | ||
| 298 | } | ||
diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h new file mode 100644 index 000000000000..73fecb38f955 --- /dev/null +++ b/drivers/gpu/drm/arm/malidp_regs.h | |||
| @@ -0,0 +1,172 @@ | |||
| 1 | /* | ||
| 2 | * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. | ||
| 3 | * Author: Liviu Dudau <Liviu.Dudau@arm.com> | ||
| 4 | * | ||
| 5 | * This program is free software and is provided to you under the terms of the | ||
| 6 | * GNU General Public License version 2 as published by the Free Software | ||
| 7 | * Foundation, and any use by you of this program is subject to the terms | ||
| 8 | * of such GNU licence. | ||
| 9 | * | ||
| 10 | * ARM Mali DP500/DP550/DP650 registers definition. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #ifndef __MALIDP_REGS_H__ | ||
| 14 | #define __MALIDP_REGS_H__ | ||
| 15 | |||
| 16 | /* | ||
| 17 | * abbreviations used: | ||
| 18 | * - DC - display core (general settings) | ||
| 19 | * - DE - display engine | ||
| 20 | * - SE - scaling engine | ||
| 21 | */ | ||
| 22 | |||
| 23 | /* interrupt bit masks */ | ||
| 24 | #define MALIDP_DE_IRQ_UNDERRUN (1 << 0) | ||
| 25 | |||
| 26 | #define MALIDP500_DE_IRQ_AXI_ERR (1 << 4) | ||
| 27 | #define MALIDP500_DE_IRQ_VSYNC (1 << 5) | ||
| 28 | #define MALIDP500_DE_IRQ_PROG_LINE (1 << 6) | ||
| 29 | #define MALIDP500_DE_IRQ_SATURATION (1 << 7) | ||
| 30 | #define MALIDP500_DE_IRQ_CONF_VALID (1 << 8) | ||
| 31 | #define MALIDP500_DE_IRQ_CONF_MODE (1 << 11) | ||
| 32 | #define MALIDP500_DE_IRQ_CONF_ACTIVE (1 << 17) | ||
| 33 | #define MALIDP500_DE_IRQ_PM_ACTIVE (1 << 18) | ||
| 34 | #define MALIDP500_DE_IRQ_TESTMODE_ACTIVE (1 << 19) | ||
| 35 | #define MALIDP500_DE_IRQ_FORCE_BLNK_ACTIVE (1 << 24) | ||
| 36 | #define MALIDP500_DE_IRQ_AXI_BUSY (1 << 28) | ||
| 37 | #define MALIDP500_DE_IRQ_GLOBAL (1 << 31) | ||
| 38 | #define MALIDP500_SE_IRQ_CONF_MODE (1 << 0) | ||
| 39 | #define MALIDP500_SE_IRQ_CONF_VALID (1 << 4) | ||
| 40 | #define MALIDP500_SE_IRQ_INIT_BUSY (1 << 5) | ||
| 41 | #define MALIDP500_SE_IRQ_AXI_ERROR (1 << 8) | ||
| 42 | #define MALIDP500_SE_IRQ_OVERRUN (1 << 9) | ||
| 43 | #define MALIDP500_SE_IRQ_PROG_LINE1 (1 << 12) | ||
| 44 | #define MALIDP500_SE_IRQ_PROG_LINE2 (1 << 13) | ||
| 45 | #define MALIDP500_SE_IRQ_CONF_ACTIVE (1 << 17) | ||
| 46 | #define MALIDP500_SE_IRQ_PM_ACTIVE (1 << 18) | ||
| 47 | #define MALIDP500_SE_IRQ_AXI_BUSY (1 << 28) | ||
| 48 | #define MALIDP500_SE_IRQ_GLOBAL (1 << 31) | ||
| 49 | |||
| 50 | #define MALIDP550_DE_IRQ_SATURATION (1 << 8) | ||
| 51 | #define MALIDP550_DE_IRQ_VSYNC (1 << 12) | ||
| 52 | #define MALIDP550_DE_IRQ_PROG_LINE (1 << 13) | ||
| 53 | #define MALIDP550_DE_IRQ_AXI_ERR (1 << 16) | ||
| 54 | #define MALIDP550_SE_IRQ_EOW (1 << 0) | ||
| 55 | #define MALIDP550_SE_IRQ_AXI_ERR (1 << 16) | ||
| 56 | #define MALIDP550_DC_IRQ_CONF_VALID (1 << 0) | ||
| 57 | #define MALIDP550_DC_IRQ_CONF_MODE (1 << 4) | ||
| 58 | #define MALIDP550_DC_IRQ_CONF_ACTIVE (1 << 16) | ||
| 59 | #define MALIDP550_DC_IRQ_DE (1 << 20) | ||
| 60 | #define MALIDP550_DC_IRQ_SE (1 << 24) | ||
| 61 | |||
| 62 | #define MALIDP650_DE_IRQ_DRIFT (1 << 4) | ||
| 63 | |||
| 64 | /* bit masks that are common between products */ | ||
| 65 | #define MALIDP_CFG_VALID (1 << 0) | ||
| 66 | #define MALIDP_DISP_FUNC_ILACED (1 << 8) | ||
| 67 | |||
| 68 | /* register offsets for IRQ management */ | ||
| 69 | #define MALIDP_REG_STATUS 0x00000 | ||
| 70 | #define MALIDP_REG_SETIRQ 0x00004 | ||
| 71 | #define MALIDP_REG_MASKIRQ 0x00008 | ||
| 72 | #define MALIDP_REG_CLEARIRQ 0x0000c | ||
| 73 | |||
| 74 | /* register offsets */ | ||
| 75 | #define MALIDP_DE_CORE_ID 0x00018 | ||
| 76 | #define MALIDP_DE_DISPLAY_FUNC 0x00020 | ||
| 77 | |||
| 78 | /* these offsets are relative to MALIDP5x0_TIMINGS_BASE */ | ||
| 79 | #define MALIDP_DE_H_TIMINGS 0x0 | ||
| 80 | #define MALIDP_DE_V_TIMINGS 0x4 | ||
| 81 | #define MALIDP_DE_SYNC_WIDTH 0x8 | ||
| 82 | #define MALIDP_DE_HV_ACTIVE 0xc | ||
| 83 | |||
| 84 | /* macros to set values into registers */ | ||
| 85 | #define MALIDP_DE_H_FRONTPORCH(x) (((x) & 0xfff) << 0) | ||
| 86 | #define MALIDP_DE_H_BACKPORCH(x) (((x) & 0x3ff) << 16) | ||
| 87 | #define MALIDP500_DE_V_FRONTPORCH(x) (((x) & 0xff) << 0) | ||
| 88 | #define MALIDP550_DE_V_FRONTPORCH(x) (((x) & 0xfff) << 0) | ||
| 89 | #define MALIDP_DE_V_BACKPORCH(x) (((x) & 0xff) << 16) | ||
| 90 | #define MALIDP_DE_H_SYNCWIDTH(x) (((x) & 0x3ff) << 0) | ||
| 91 | #define MALIDP_DE_V_SYNCWIDTH(x) (((x) & 0xff) << 16) | ||
| 92 | #define MALIDP_DE_H_ACTIVE(x) (((x) & 0x1fff) << 0) | ||
| 93 | #define MALIDP_DE_V_ACTIVE(x) (((x) & 0x1fff) << 16) | ||
| 94 | |||
| 95 | /* register offsets and bits specific to DP500 */ | ||
| 96 | #define MALIDP500_DC_BASE 0x00000 | ||
| 97 | #define MALIDP500_DC_CONTROL 0x0000c | ||
| 98 | #define MALIDP500_DC_CONFIG_REQ (1 << 17) | ||
| 99 | #define MALIDP500_HSYNCPOL (1 << 20) | ||
| 100 | #define MALIDP500_VSYNCPOL (1 << 21) | ||
| 101 | #define MALIDP500_DC_CLEAR_MASK 0x300fff | ||
| 102 | #define MALIDP500_DE_LINE_COUNTER 0x00010 | ||
| 103 | #define MALIDP500_DE_AXI_CONTROL 0x00014 | ||
| 104 | #define MALIDP500_DE_SECURE_CTRL 0x0001c | ||
| 105 | #define MALIDP500_DE_CHROMA_KEY 0x00024 | ||
| 106 | #define MALIDP500_TIMINGS_BASE 0x00028 | ||
| 107 | |||
| 108 | #define MALIDP500_CONFIG_3D 0x00038 | ||
| 109 | #define MALIDP500_BGND_COLOR 0x0003c | ||
| 110 | #define MALIDP500_OUTPUT_DEPTH 0x00044 | ||
| 111 | #define MALIDP500_YUV_RGB_COEF 0x00048 | ||
| 112 | #define MALIDP500_COLOR_ADJ_COEF 0x00078 | ||
| 113 | #define MALIDP500_COEF_TABLE_ADDR 0x000a8 | ||
| 114 | #define MALIDP500_COEF_TABLE_DATA 0x000ac | ||
| 115 | #define MALIDP500_DE_LV_BASE 0x00100 | ||
| 116 | #define MALIDP500_DE_LV_PTR_BASE 0x00124 | ||
| 117 | #define MALIDP500_DE_LG1_BASE 0x00200 | ||
| 118 | #define MALIDP500_DE_LG1_PTR_BASE 0x0021c | ||
| 119 | #define MALIDP500_DE_LG2_BASE 0x00300 | ||
| 120 | #define MALIDP500_DE_LG2_PTR_BASE 0x0031c | ||
| 121 | #define MALIDP500_SE_BASE 0x00c00 | ||
| 122 | #define MALIDP500_SE_PTR_BASE 0x00e0c | ||
| 123 | #define MALIDP500_DC_IRQ_BASE 0x00f00 | ||
| 124 | #define MALIDP500_CONFIG_VALID 0x00f00 | ||
| 125 | #define MALIDP500_CONFIG_ID 0x00fd4 | ||
| 126 | |||
| 127 | /* register offsets and bits specific to DP550/DP650 */ | ||
| 128 | #define MALIDP550_DE_CONTROL 0x00010 | ||
| 129 | #define MALIDP550_DE_LINE_COUNTER 0x00014 | ||
| 130 | #define MALIDP550_DE_AXI_CONTROL 0x00018 | ||
| 131 | #define MALIDP550_DE_QOS 0x0001c | ||
| 132 | #define MALIDP550_TIMINGS_BASE 0x00030 | ||
| 133 | #define MALIDP550_HSYNCPOL (1 << 12) | ||
| 134 | #define MALIDP550_VSYNCPOL (1 << 28) | ||
| 135 | |||
| 136 | #define MALIDP550_DE_DISP_SIDEBAND 0x00040 | ||
| 137 | #define MALIDP550_DE_BGND_COLOR 0x00044 | ||
| 138 | #define MALIDP550_DE_OUTPUT_DEPTH 0x0004c | ||
| 139 | #define MALIDP550_DE_COLOR_COEF 0x00050 | ||
| 140 | #define MALIDP550_DE_COEF_TABLE_ADDR 0x00080 | ||
| 141 | #define MALIDP550_DE_COEF_TABLE_DATA 0x00084 | ||
| 142 | #define MALIDP550_DE_LV1_BASE 0x00100 | ||
| 143 | #define MALIDP550_DE_LV1_PTR_BASE 0x00124 | ||
| 144 | #define MALIDP550_DE_LV2_BASE 0x00200 | ||
| 145 | #define MALIDP550_DE_LV2_PTR_BASE 0x00224 | ||
| 146 | #define MALIDP550_DE_LG_BASE 0x00300 | ||
| 147 | #define MALIDP550_DE_LG_PTR_BASE 0x0031c | ||
| 148 | #define MALIDP550_DE_LS_BASE 0x00400 | ||
| 149 | #define MALIDP550_DE_LS_PTR_BASE 0x0042c | ||
| 150 | #define MALIDP550_DE_PERF_BASE 0x00500 | ||
| 151 | #define MALIDP550_SE_BASE 0x08000 | ||
| 152 | #define MALIDP550_DC_BASE 0x0c000 | ||
| 153 | #define MALIDP550_DC_CONTROL 0x0c010 | ||
| 154 | #define MALIDP550_DC_CONFIG_REQ (1 << 16) | ||
| 155 | #define MALIDP550_CONFIG_VALID 0x0c014 | ||
| 156 | #define MALIDP550_CONFIG_ID 0x0ffd4 | ||
| 157 | |||
| 158 | /* | ||
| 159 | * Starting with DP550 the register map blocks has been standardised to the | ||
| 160 | * following layout: | ||
| 161 | * | ||
| 162 | * Offset Block registers | ||
| 163 | * 0x00000 Display Engine | ||
| 164 | * 0x08000 Scaling Engine | ||
| 165 | * 0x0c000 Display Core | ||
| 166 | * 0x10000 Secure control | ||
| 167 | * | ||
| 168 | * The old DP500 IP mixes some DC with the DE registers, hence the need | ||
| 169 | * for a mapping structure. | ||
| 170 | */ | ||
| 171 | |||
| 172 | #endif /* __MALIDP_REGS_H__ */ | ||
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index cb21c0b6374a..f5ebdd681445 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c | |||
| @@ -189,7 +189,6 @@ static struct drm_driver armada_drm_driver = { | |||
| 189 | .load = armada_drm_load, | 189 | .load = armada_drm_load, |
| 190 | .lastclose = armada_drm_lastclose, | 190 | .lastclose = armada_drm_lastclose, |
| 191 | .unload = armada_drm_unload, | 191 | .unload = armada_drm_unload, |
| 192 | .set_busid = drm_platform_set_busid, | ||
| 193 | .get_vblank_counter = drm_vblank_no_hw_counter, | 192 | .get_vblank_counter = drm_vblank_no_hw_counter, |
| 194 | .enable_vblank = armada_drm_enable_vblank, | 193 | .enable_vblank = armada_drm_enable_vblank, |
| 195 | .disable_vblank = armada_drm_disable_vblank, | 194 | .disable_vblank = armada_drm_disable_vblank, |
diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 148e8a42b2c6..1ee707ef6b8d 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c | |||
| @@ -121,6 +121,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, | |||
| 121 | int ret; | 121 | int ret; |
| 122 | 122 | ||
| 123 | ret = drm_plane_helper_check_update(plane, crtc, fb, &src, &dest, &clip, | 123 | ret = drm_plane_helper_check_update(plane, crtc, fb, &src, &dest, &clip, |
| 124 | BIT(DRM_ROTATE_0), | ||
| 124 | 0, INT_MAX, true, false, &visible); | 125 | 0, INT_MAX, true, false, &visible); |
| 125 | if (ret) | 126 | if (ret) |
| 126 | return ret; | 127 | return ret; |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 9ecf16c7911d..d4a3d61b7b06 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | |||
| @@ -691,13 +691,6 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev) | |||
| 691 | destroy_workqueue(dc->wq); | 691 | destroy_workqueue(dc->wq); |
| 692 | } | 692 | } |
| 693 | 693 | ||
| 694 | static void atmel_hlcdc_dc_connector_unplug_all(struct drm_device *dev) | ||
| 695 | { | ||
| 696 | mutex_lock(&dev->mode_config.mutex); | ||
| 697 | drm_connector_unregister_all(dev); | ||
| 698 | mutex_unlock(&dev->mode_config.mutex); | ||
| 699 | } | ||
| 700 | |||
| 701 | static void atmel_hlcdc_dc_lastclose(struct drm_device *dev) | 694 | static void atmel_hlcdc_dc_lastclose(struct drm_device *dev) |
| 702 | { | 695 | { |
| 703 | struct atmel_hlcdc_dc *dc = dev->dev_private; | 696 | struct atmel_hlcdc_dc *dc = dev->dev_private; |
| @@ -815,15 +808,8 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev) | |||
| 815 | if (ret) | 808 | if (ret) |
| 816 | goto err_unload; | 809 | goto err_unload; |
| 817 | 810 | ||
| 818 | ret = drm_connector_register_all(ddev); | ||
| 819 | if (ret) | ||
| 820 | goto err_unregister; | ||
| 821 | |||
| 822 | return 0; | 811 | return 0; |
| 823 | 812 | ||
| 824 | err_unregister: | ||
| 825 | drm_dev_unregister(ddev); | ||
| 826 | |||
| 827 | err_unload: | 813 | err_unload: |
| 828 | atmel_hlcdc_dc_unload(ddev); | 814 | atmel_hlcdc_dc_unload(ddev); |
| 829 | 815 | ||
| @@ -837,7 +823,6 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev) | |||
| 837 | { | 823 | { |
| 838 | struct drm_device *ddev = platform_get_drvdata(pdev); | 824 | struct drm_device *ddev = platform_get_drvdata(pdev); |
| 839 | 825 | ||
| 840 | atmel_hlcdc_dc_connector_unplug_all(ddev); | ||
| 841 | drm_dev_unregister(ddev); | 826 | drm_dev_unregister(ddev); |
| 842 | atmel_hlcdc_dc_unload(ddev); | 827 | atmel_hlcdc_dc_unload(ddev); |
| 843 | drm_dev_unref(ddev); | 828 | drm_dev_unref(ddev); |
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 8f7423f18da5..a141921445f4 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig | |||
| @@ -50,6 +50,14 @@ config DRM_PARADE_PS8622 | |||
| 50 | ---help--- | 50 | ---help--- |
| 51 | Parade eDP-LVDS bridge chip driver. | 51 | Parade eDP-LVDS bridge chip driver. |
| 52 | 52 | ||
| 53 | config DRM_SII902X | ||
| 54 | tristate "Silicon Image sii902x RGB/HDMI bridge" | ||
| 55 | depends on OF | ||
| 56 | select DRM_KMS_HELPER | ||
| 57 | select REGMAP_I2C | ||
| 58 | ---help--- | ||
| 59 | Silicon Image sii902x bridge chip driver. | ||
| 60 | |||
| 53 | source "drivers/gpu/drm/bridge/analogix/Kconfig" | 61 | source "drivers/gpu/drm/bridge/analogix/Kconfig" |
| 54 | 62 | ||
| 55 | endmenu | 63 | endmenu |
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 96b13b30e6ab..bfec9f8cb9d2 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile | |||
| @@ -5,4 +5,5 @@ obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o | |||
| 5 | obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o | 5 | obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o |
| 6 | obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o | 6 | obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o |
| 7 | obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o | 7 | obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o |
| 8 | obj-$(CONFIG_DRM_SII902X) += sii902x.o | ||
| 8 | obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ | 9 | obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ |
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c new file mode 100644 index 000000000000..9126d0306ab5 --- /dev/null +++ b/drivers/gpu/drm/bridge/sii902x.c | |||
| @@ -0,0 +1,467 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 Atmel | ||
| 3 | * Bo Shen <voice.shen@atmel.com> | ||
| 4 | * | ||
| 5 | * Authors: Bo Shen <voice.shen@atmel.com> | ||
| 6 | * Boris Brezillon <boris.brezillon@free-electrons.com> | ||
| 7 | * Wu, Songjun <Songjun.Wu@atmel.com> | ||
| 8 | * | ||
| 9 | * | ||
| 10 | * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2 of the License, or | ||
| 15 | * (at your option) any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/gpio/consumer.h> | ||
| 24 | #include <linux/i2c.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/regmap.h> | ||
| 27 | |||
| 28 | #include <drm/drmP.h> | ||
| 29 | #include <drm/drm_atomic_helper.h> | ||
| 30 | #include <drm/drm_crtc_helper.h> | ||
| 31 | #include <drm/drm_edid.h> | ||
| 32 | |||
| 33 | #define SII902X_TPI_VIDEO_DATA 0x0 | ||
| 34 | |||
| 35 | #define SII902X_TPI_PIXEL_REPETITION 0x8 | ||
| 36 | #define SII902X_TPI_AVI_PIXEL_REP_BUS_24BIT BIT(5) | ||
| 37 | #define SII902X_TPI_AVI_PIXEL_REP_RISING_EDGE BIT(4) | ||
| 38 | #define SII902X_TPI_AVI_PIXEL_REP_4X 3 | ||
| 39 | #define SII902X_TPI_AVI_PIXEL_REP_2X 1 | ||
| 40 | #define SII902X_TPI_AVI_PIXEL_REP_NONE 0 | ||
| 41 | #define SII902X_TPI_CLK_RATIO_HALF (0 << 6) | ||
| 42 | #define SII902X_TPI_CLK_RATIO_1X (1 << 6) | ||
| 43 | #define SII902X_TPI_CLK_RATIO_2X (2 << 6) | ||
| 44 | #define SII902X_TPI_CLK_RATIO_4X (3 << 6) | ||
| 45 | |||
| 46 | #define SII902X_TPI_AVI_IN_FORMAT 0x9 | ||
| 47 | #define SII902X_TPI_AVI_INPUT_BITMODE_12BIT BIT(7) | ||
| 48 | #define SII902X_TPI_AVI_INPUT_DITHER BIT(6) | ||
| 49 | #define SII902X_TPI_AVI_INPUT_RANGE_LIMITED (2 << 2) | ||
| 50 | #define SII902X_TPI_AVI_INPUT_RANGE_FULL (1 << 2) | ||
| 51 | #define SII902X_TPI_AVI_INPUT_RANGE_AUTO (0 << 2) | ||
| 52 | #define SII902X_TPI_AVI_INPUT_COLORSPACE_BLACK (3 << 0) | ||
| 53 | #define SII902X_TPI_AVI_INPUT_COLORSPACE_YUV422 (2 << 0) | ||
| 54 | #define SII902X_TPI_AVI_INPUT_COLORSPACE_YUV444 (1 << 0) | ||
| 55 | #define SII902X_TPI_AVI_INPUT_COLORSPACE_RGB (0 << 0) | ||
| 56 | |||
| 57 | #define SII902X_TPI_AVI_INFOFRAME 0x0c | ||
| 58 | |||
| 59 | #define SII902X_SYS_CTRL_DATA 0x1a | ||
| 60 | #define SII902X_SYS_CTRL_PWR_DWN BIT(4) | ||
| 61 | #define SII902X_SYS_CTRL_AV_MUTE BIT(3) | ||
| 62 | #define SII902X_SYS_CTRL_DDC_BUS_REQ BIT(2) | ||
| 63 | #define SII902X_SYS_CTRL_DDC_BUS_GRTD BIT(1) | ||
| 64 | #define SII902X_SYS_CTRL_OUTPUT_MODE BIT(0) | ||
| 65 | #define SII902X_SYS_CTRL_OUTPUT_HDMI 1 | ||
| 66 | #define SII902X_SYS_CTRL_OUTPUT_DVI 0 | ||
| 67 | |||
| 68 | #define SII902X_REG_CHIPID(n) (0x1b + (n)) | ||
| 69 | |||
| 70 | #define SII902X_PWR_STATE_CTRL 0x1e | ||
| 71 | #define SII902X_AVI_POWER_STATE_MSK GENMASK(1, 0) | ||
| 72 | #define SII902X_AVI_POWER_STATE_D(l) ((l) & SII902X_AVI_POWER_STATE_MSK) | ||
| 73 | |||
| 74 | #define SII902X_INT_ENABLE 0x3c | ||
| 75 | #define SII902X_INT_STATUS 0x3d | ||
| 76 | #define SII902X_HOTPLUG_EVENT BIT(0) | ||
| 77 | #define SII902X_PLUGGED_STATUS BIT(2) | ||
| 78 | |||
| 79 | #define SII902X_REG_TPI_RQB 0xc7 | ||
| 80 | |||
| 81 | #define SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS 500 | ||
| 82 | |||
| 83 | struct sii902x { | ||
| 84 | struct i2c_client *i2c; | ||
| 85 | struct regmap *regmap; | ||
| 86 | struct drm_bridge bridge; | ||
| 87 | struct drm_connector connector; | ||
| 88 | struct gpio_desc *reset_gpio; | ||
| 89 | }; | ||
| 90 | |||
| 91 | static inline struct sii902x *bridge_to_sii902x(struct drm_bridge *bridge) | ||
| 92 | { | ||
| 93 | return container_of(bridge, struct sii902x, bridge); | ||
| 94 | } | ||
| 95 | |||
| 96 | static inline struct sii902x *connector_to_sii902x(struct drm_connector *con) | ||
| 97 | { | ||
| 98 | return container_of(con, struct sii902x, connector); | ||
| 99 | } | ||
| 100 | |||
| 101 | static void sii902x_reset(struct sii902x *sii902x) | ||
| 102 | { | ||
| 103 | if (!sii902x->reset_gpio) | ||
| 104 | return; | ||
| 105 | |||
| 106 | gpiod_set_value(sii902x->reset_gpio, 1); | ||
| 107 | |||
| 108 | /* The datasheet says treset-min = 100us. Make it 150us to be sure. */ | ||
| 109 | usleep_range(150, 200); | ||
| 110 | |||
| 111 | gpiod_set_value(sii902x->reset_gpio, 0); | ||
| 112 | } | ||
| 113 | |||
| 114 | static enum drm_connector_status | ||
| 115 | sii902x_connector_detect(struct drm_connector *connector, bool force) | ||
| 116 | { | ||
| 117 | struct sii902x *sii902x = connector_to_sii902x(connector); | ||
| 118 | unsigned int status; | ||
| 119 | |||
| 120 | regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); | ||
| 121 | |||
| 122 | return (status & SII902X_PLUGGED_STATUS) ? | ||
| 123 | connector_status_connected : connector_status_disconnected; | ||
| 124 | } | ||
| 125 | |||
| 126 | static const struct drm_connector_funcs sii902x_connector_funcs = { | ||
| 127 | .dpms = drm_atomic_helper_connector_dpms, | ||
| 128 | .detect = sii902x_connector_detect, | ||
| 129 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
| 130 | .destroy = drm_connector_cleanup, | ||
| 131 | .reset = drm_atomic_helper_connector_reset, | ||
| 132 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
| 133 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
| 134 | }; | ||
| 135 | |||
| 136 | static int sii902x_get_modes(struct drm_connector *connector) | ||
| 137 | { | ||
| 138 | struct sii902x *sii902x = connector_to_sii902x(connector); | ||
| 139 | struct regmap *regmap = sii902x->regmap; | ||
| 140 | u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; | ||
| 141 | unsigned long timeout; | ||
| 142 | unsigned int status; | ||
| 143 | struct edid *edid; | ||
| 144 | int num = 0; | ||
| 145 | int ret; | ||
| 146 | |||
| 147 | ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA, | ||
| 148 | SII902X_SYS_CTRL_DDC_BUS_REQ, | ||
| 149 | SII902X_SYS_CTRL_DDC_BUS_REQ); | ||
| 150 | if (ret) | ||
| 151 | return ret; | ||
| 152 | |||
| 153 | timeout = jiffies + | ||
| 154 | msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS); | ||
| 155 | do { | ||
| 156 | ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status); | ||
| 157 | if (ret) | ||
| 158 | return ret; | ||
| 159 | } while (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD) && | ||
| 160 | time_before(jiffies, timeout)); | ||
| 161 | |||
| 162 | if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) { | ||
| 163 | dev_err(&sii902x->i2c->dev, "failed to acquire the i2c bus"); | ||
| 164 | return -ETIMEDOUT; | ||
| 165 | } | ||
| 166 | |||
| 167 | ret = regmap_write(regmap, SII902X_SYS_CTRL_DATA, status); | ||
| 168 | if (ret) | ||
| 169 | return ret; | ||
| 170 | |||
| 171 | edid = drm_get_edid(connector, sii902x->i2c->adapter); | ||
| 172 | drm_mode_connector_update_edid_property(connector, edid); | ||
| 173 | if (edid) { | ||
| 174 | num = drm_add_edid_modes(connector, edid); | ||
| 175 | kfree(edid); | ||
| 176 | } | ||
| 177 | |||
| 178 | ret = drm_display_info_set_bus_formats(&connector->display_info, | ||
| 179 | &bus_format, 1); | ||
| 180 | if (ret) | ||
| 181 | return ret; | ||
| 182 | |||
| 183 | ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status); | ||
| 184 | if (ret) | ||
| 185 | return ret; | ||
| 186 | |||
| 187 | ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA, | ||
| 188 | SII902X_SYS_CTRL_DDC_BUS_REQ | | ||
| 189 | SII902X_SYS_CTRL_DDC_BUS_GRTD, 0); | ||
| 190 | if (ret) | ||
| 191 | return ret; | ||
| 192 | |||
| 193 | timeout = jiffies + | ||
| 194 | msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS); | ||
| 195 | do { | ||
| 196 | ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status); | ||
| 197 | if (ret) | ||
| 198 | return ret; | ||
| 199 | } while (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | | ||
| 200 | SII902X_SYS_CTRL_DDC_BUS_GRTD) && | ||
| 201 | time_before(jiffies, timeout)); | ||
| 202 | |||
| 203 | if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | | ||
| 204 | SII902X_SYS_CTRL_DDC_BUS_GRTD)) { | ||
| 205 | dev_err(&sii902x->i2c->dev, "failed to release the i2c bus"); | ||
| 206 | return -ETIMEDOUT; | ||
| 207 | } | ||
| 208 | |||
| 209 | return num; | ||
| 210 | } | ||
| 211 | |||
| 212 | static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector, | ||
| 213 | struct drm_display_mode *mode) | ||
| 214 | { | ||
| 215 | /* TODO: check mode */ | ||
| 216 | |||
| 217 | return MODE_OK; | ||
| 218 | } | ||
| 219 | |||
| 220 | static const struct drm_connector_helper_funcs sii902x_connector_helper_funcs = { | ||
| 221 | .get_modes = sii902x_get_modes, | ||
| 222 | .mode_valid = sii902x_mode_valid, | ||
| 223 | }; | ||
| 224 | |||
| 225 | static void sii902x_bridge_disable(struct drm_bridge *bridge) | ||
| 226 | { | ||
| 227 | struct sii902x *sii902x = bridge_to_sii902x(bridge); | ||
| 228 | |||
| 229 | regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, | ||
| 230 | SII902X_SYS_CTRL_PWR_DWN, | ||
| 231 | SII902X_SYS_CTRL_PWR_DWN); | ||
| 232 | } | ||
| 233 | |||
| 234 | static void sii902x_bridge_enable(struct drm_bridge *bridge) | ||
| 235 | { | ||
| 236 | struct sii902x *sii902x = bridge_to_sii902x(bridge); | ||
| 237 | |||
| 238 | regmap_update_bits(sii902x->regmap, SII902X_PWR_STATE_CTRL, | ||
| 239 | SII902X_AVI_POWER_STATE_MSK, | ||
| 240 | SII902X_AVI_POWER_STATE_D(0)); | ||
| 241 | regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, | ||
| 242 | SII902X_SYS_CTRL_PWR_DWN, 0); | ||
| 243 | } | ||
| 244 | |||
| 245 | static void sii902x_bridge_mode_set(struct drm_bridge *bridge, | ||
| 246 | struct drm_display_mode *mode, | ||
| 247 | struct drm_display_mode *adj) | ||
| 248 | { | ||
| 249 | struct sii902x *sii902x = bridge_to_sii902x(bridge); | ||
| 250 | struct regmap *regmap = sii902x->regmap; | ||
| 251 | u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; | ||
| 252 | struct hdmi_avi_infoframe frame; | ||
| 253 | int ret; | ||
| 254 | |||
| 255 | buf[0] = adj->clock; | ||
| 256 | buf[1] = adj->clock >> 8; | ||
| 257 | buf[2] = adj->vrefresh; | ||
| 258 | buf[3] = 0x00; | ||
| 259 | buf[4] = adj->hdisplay; | ||
| 260 | buf[5] = adj->hdisplay >> 8; | ||
| 261 | buf[6] = adj->vdisplay; | ||
| 262 | buf[7] = adj->vdisplay >> 8; | ||
| 263 | buf[8] = SII902X_TPI_CLK_RATIO_1X | SII902X_TPI_AVI_PIXEL_REP_NONE | | ||
| 264 | SII902X_TPI_AVI_PIXEL_REP_BUS_24BIT; | ||
| 265 | buf[9] = SII902X_TPI_AVI_INPUT_RANGE_AUTO | | ||
| 266 | SII902X_TPI_AVI_INPUT_COLORSPACE_RGB; | ||
| 267 | |||
| 268 | ret = regmap_bulk_write(regmap, SII902X_TPI_VIDEO_DATA, buf, 10); | ||
| 269 | if (ret) | ||
| 270 | return; | ||
| 271 | |||
| 272 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, adj); | ||
| 273 | if (ret < 0) { | ||
| 274 | DRM_ERROR("couldn't fill AVI infoframe\n"); | ||
| 275 | return; | ||
| 276 | } | ||
| 277 | |||
| 278 | ret = hdmi_avi_infoframe_pack(&frame, buf, sizeof(buf)); | ||
| 279 | if (ret < 0) { | ||
| 280 | DRM_ERROR("failed to pack AVI infoframe: %d\n", ret); | ||
| 281 | return; | ||
| 282 | } | ||
| 283 | |||
| 284 | /* Do not send the infoframe header, but keep the CRC field. */ | ||
| 285 | regmap_bulk_write(regmap, SII902X_TPI_AVI_INFOFRAME, | ||
| 286 | buf + HDMI_INFOFRAME_HEADER_SIZE - 1, | ||
| 287 | HDMI_AVI_INFOFRAME_SIZE + 1); | ||
| 288 | } | ||
| 289 | |||
| 290 | static int sii902x_bridge_attach(struct drm_bridge *bridge) | ||
| 291 | { | ||
| 292 | struct sii902x *sii902x = bridge_to_sii902x(bridge); | ||
| 293 | struct drm_device *drm = bridge->dev; | ||
| 294 | int ret; | ||
| 295 | |||
| 296 | drm_connector_helper_add(&sii902x->connector, | ||
| 297 | &sii902x_connector_helper_funcs); | ||
| 298 | |||
| 299 | if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) { | ||
| 300 | dev_err(&sii902x->i2c->dev, | ||
| 301 | "sii902x driver is only compatible with DRM devices supporting atomic updates"); | ||
| 302 | return -ENOTSUPP; | ||
| 303 | } | ||
| 304 | |||
| 305 | ret = drm_connector_init(drm, &sii902x->connector, | ||
| 306 | &sii902x_connector_funcs, | ||
| 307 | DRM_MODE_CONNECTOR_HDMIA); | ||
| 308 | if (ret) | ||
| 309 | return ret; | ||
| 310 | |||
| 311 | if (sii902x->i2c->irq > 0) | ||
| 312 | sii902x->connector.polled = DRM_CONNECTOR_POLL_HPD; | ||
| 313 | else | ||
| 314 | sii902x->connector.polled = DRM_CONNECTOR_POLL_CONNECT; | ||
| 315 | |||
| 316 | drm_mode_connector_attach_encoder(&sii902x->connector, bridge->encoder); | ||
| 317 | |||
| 318 | return 0; | ||
| 319 | } | ||
| 320 | |||
| 321 | static const struct drm_bridge_funcs sii902x_bridge_funcs = { | ||
| 322 | .attach = sii902x_bridge_attach, | ||
| 323 | .mode_set = sii902x_bridge_mode_set, | ||
| 324 | .disable = sii902x_bridge_disable, | ||
| 325 | .enable = sii902x_bridge_enable, | ||
| 326 | }; | ||
| 327 | |||
| 328 | static const struct regmap_range sii902x_volatile_ranges[] = { | ||
| 329 | { .range_min = 0, .range_max = 0xff }, | ||
| 330 | }; | ||
| 331 | |||
| 332 | static const struct regmap_access_table sii902x_volatile_table = { | ||
| 333 | .yes_ranges = sii902x_volatile_ranges, | ||
| 334 | .n_yes_ranges = ARRAY_SIZE(sii902x_volatile_ranges), | ||
| 335 | }; | ||
| 336 | |||
| 337 | static const struct regmap_config sii902x_regmap_config = { | ||
| 338 | .reg_bits = 8, | ||
| 339 | .val_bits = 8, | ||
| 340 | .volatile_table = &sii902x_volatile_table, | ||
| 341 | .cache_type = REGCACHE_NONE, | ||
| 342 | }; | ||
| 343 | |||
| 344 | static irqreturn_t sii902x_interrupt(int irq, void *data) | ||
| 345 | { | ||
| 346 | struct sii902x *sii902x = data; | ||
| 347 | unsigned int status = 0; | ||
| 348 | |||
| 349 | regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); | ||
| 350 | regmap_write(sii902x->regmap, SII902X_INT_STATUS, status); | ||
| 351 | |||
| 352 | if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev) | ||
| 353 | drm_helper_hpd_irq_event(sii902x->bridge.dev); | ||
| 354 | |||
| 355 | return IRQ_HANDLED; | ||
| 356 | } | ||
| 357 | |||
| 358 | static int sii902x_probe(struct i2c_client *client, | ||
| 359 | const struct i2c_device_id *id) | ||
| 360 | { | ||
| 361 | struct device *dev = &client->dev; | ||
| 362 | unsigned int status = 0; | ||
| 363 | struct sii902x *sii902x; | ||
| 364 | u8 chipid[4]; | ||
| 365 | int ret; | ||
| 366 | |||
| 367 | sii902x = devm_kzalloc(dev, sizeof(*sii902x), GFP_KERNEL); | ||
| 368 | if (!sii902x) | ||
| 369 | return -ENOMEM; | ||
| 370 | |||
| 371 | sii902x->i2c = client; | ||
| 372 | sii902x->regmap = devm_regmap_init_i2c(client, &sii902x_regmap_config); | ||
| 373 | if (IS_ERR(sii902x->regmap)) | ||
| 374 | return PTR_ERR(sii902x->regmap); | ||
| 375 | |||
| 376 | sii902x->reset_gpio = devm_gpiod_get_optional(dev, "reset", | ||
| 377 | GPIOD_OUT_LOW); | ||
| 378 | if (IS_ERR(sii902x->reset_gpio)) { | ||
| 379 | dev_err(dev, "Failed to retrieve/request reset gpio: %ld\n", | ||
| 380 | PTR_ERR(sii902x->reset_gpio)); | ||
| 381 | return PTR_ERR(sii902x->reset_gpio); | ||
| 382 | } | ||
| 383 | |||
| 384 | sii902x_reset(sii902x); | ||
| 385 | |||
| 386 | ret = regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x0); | ||
| 387 | if (ret) | ||
| 388 | return ret; | ||
| 389 | |||
| 390 | ret = regmap_bulk_read(sii902x->regmap, SII902X_REG_CHIPID(0), | ||
| 391 | &chipid, 4); | ||
| 392 | if (ret) { | ||
| 393 | dev_err(dev, "regmap_read failed %d\n", ret); | ||
| 394 | return ret; | ||
| 395 | } | ||
| 396 | |||
| 397 | if (chipid[0] != 0xb0) { | ||
| 398 | dev_err(dev, "Invalid chipid: %02x (expecting 0xb0)\n", | ||
| 399 | chipid[0]); | ||
| 400 | return -EINVAL; | ||
| 401 | } | ||
| 402 | |||
| 403 | /* Clear all pending interrupts */ | ||
| 404 | regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); | ||
| 405 | regmap_write(sii902x->regmap, SII902X_INT_STATUS, status); | ||
| 406 | |||
| 407 | if (client->irq > 0) { | ||
| 408 | regmap_write(sii902x->regmap, SII902X_INT_ENABLE, | ||
| 409 | SII902X_HOTPLUG_EVENT); | ||
| 410 | |||
| 411 | ret = devm_request_threaded_irq(dev, client->irq, NULL, | ||
| 412 | sii902x_interrupt, | ||
| 413 | IRQF_ONESHOT, dev_name(dev), | ||
| 414 | sii902x); | ||
| 415 | if (ret) | ||
| 416 | return ret; | ||
| 417 | } | ||
| 418 | |||
| 419 | sii902x->bridge.funcs = &sii902x_bridge_funcs; | ||
| 420 | sii902x->bridge.of_node = dev->of_node; | ||
| 421 | ret = drm_bridge_add(&sii902x->bridge); | ||
| 422 | if (ret) { | ||
| 423 | dev_err(dev, "Failed to add drm_bridge\n"); | ||
| 424 | return ret; | ||
| 425 | } | ||
| 426 | |||
| 427 | i2c_set_clientdata(client, sii902x); | ||
| 428 | |||
| 429 | return 0; | ||
| 430 | } | ||
| 431 | |||
| 432 | static int sii902x_remove(struct i2c_client *client) | ||
| 433 | |||
| 434 | { | ||
| 435 | struct sii902x *sii902x = i2c_get_clientdata(client); | ||
| 436 | |||
| 437 | drm_bridge_remove(&sii902x->bridge); | ||
| 438 | |||
| 439 | return 0; | ||
| 440 | } | ||
| 441 | |||
| 442 | static const struct of_device_id sii902x_dt_ids[] = { | ||
| 443 | { .compatible = "sil,sii9022", }, | ||
| 444 | { } | ||
| 445 | }; | ||
| 446 | MODULE_DEVICE_TABLE(of, sii902x_dt_ids); | ||
| 447 | |||
| 448 | static const struct i2c_device_id sii902x_i2c_ids[] = { | ||
| 449 | { "sii9022", 0 }, | ||
| 450 | { }, | ||
| 451 | }; | ||
| 452 | MODULE_DEVICE_TABLE(i2c, sii902x_i2c_ids); | ||
| 453 | |||
| 454 | static struct i2c_driver sii902x_driver = { | ||
| 455 | .probe = sii902x_probe, | ||
| 456 | .remove = sii902x_remove, | ||
| 457 | .driver = { | ||
| 458 | .name = "sii902x", | ||
| 459 | .of_match_table = sii902x_dt_ids, | ||
| 460 | }, | ||
| 461 | .id_table = sii902x_i2c_ids, | ||
| 462 | }; | ||
| 463 | module_i2c_driver(sii902x_driver); | ||
| 464 | |||
| 465 | MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>"); | ||
| 466 | MODULE_DESCRIPTION("SII902x RGB -> HDMI bridges"); | ||
| 467 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index 50d0baa06db0..4153e8a193af 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c | |||
| @@ -30,25 +30,36 @@ | |||
| 30 | 30 | ||
| 31 | #include <drm/drmP.h> | 31 | #include <drm/drmP.h> |
| 32 | #include "drm_internal.h" | 32 | #include "drm_internal.h" |
| 33 | #include "drm_legacy.h" | ||
| 33 | 34 | ||
| 34 | /** | 35 | /** |
| 35 | * drm_getmagic - Get unique magic of a client | 36 | * DOC: master and authentication |
| 36 | * @dev: DRM device to operate on | ||
| 37 | * @data: ioctl data containing the drm_auth object | ||
| 38 | * @file_priv: DRM file that performs the operation | ||
| 39 | * | 37 | * |
| 40 | * This looks up the unique magic of the passed client and returns it. If the | 38 | * struct &drm_master is used to track groups of clients with open |
| 41 | * client did not have a magic assigned, yet, a new one is registered. The magic | 39 | * primary/legacy device nodes. For every struct &drm_file which has had at |
| 42 | * is stored in the passed drm_auth object. | 40 | * least once successfully became the device master (either through the |
| 41 | * SET_MASTER IOCTL, or implicitly through opening the primary device node when | ||
| 42 | * no one else is the current master that time) there exists one &drm_master. | ||
| 43 | * This is noted in the is_master member of &drm_file. All other clients have | ||
| 44 | * just a pointer to the &drm_master they are associated with. | ||
| 43 | * | 45 | * |
| 44 | * Returns: 0 on success, negative error code on failure. | 46 | * In addition only one &drm_master can be the current master for a &drm_device. |
| 47 | * It can be switched through the DROP_MASTER and SET_MASTER IOCTL, or | ||
| 48 | * implicitly through closing/openeing the primary device node. See also | ||
| 49 | * drm_is_current_master(). | ||
| 50 | * | ||
| 51 | * Clients can authenticate against the current master (if it matches their own) | ||
| 52 | * using the GETMAGIC and AUTHMAGIC IOCTLs. Together with exchanging masters, | ||
| 53 | * this allows controlled access to the device for an entire group of mutually | ||
| 54 | * trusted clients. | ||
| 45 | */ | 55 | */ |
| 56 | |||
| 46 | int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) | 57 | int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) |
| 47 | { | 58 | { |
| 48 | struct drm_auth *auth = data; | 59 | struct drm_auth *auth = data; |
| 49 | int ret = 0; | 60 | int ret = 0; |
| 50 | 61 | ||
| 51 | mutex_lock(&dev->struct_mutex); | 62 | mutex_lock(&dev->master_mutex); |
| 52 | if (!file_priv->magic) { | 63 | if (!file_priv->magic) { |
| 53 | ret = idr_alloc(&file_priv->master->magic_map, file_priv, | 64 | ret = idr_alloc(&file_priv->master->magic_map, file_priv, |
| 54 | 1, 0, GFP_KERNEL); | 65 | 1, 0, GFP_KERNEL); |
| @@ -56,23 +67,13 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 56 | file_priv->magic = ret; | 67 | file_priv->magic = ret; |
| 57 | } | 68 | } |
| 58 | auth->magic = file_priv->magic; | 69 | auth->magic = file_priv->magic; |
| 59 | mutex_unlock(&dev->struct_mutex); | 70 | mutex_unlock(&dev->master_mutex); |
| 60 | 71 | ||
| 61 | DRM_DEBUG("%u\n", auth->magic); | 72 | DRM_DEBUG("%u\n", auth->magic); |
| 62 | 73 | ||
| 63 | return ret < 0 ? ret : 0; | 74 | return ret < 0 ? ret : 0; |
| 64 | } | 75 | } |
| 65 | 76 | ||
| 66 | /** | ||
| 67 | * drm_authmagic - Authenticate client with a magic | ||
| 68 | * @dev: DRM device to operate on | ||
| 69 | * @data: ioctl data containing the drm_auth object | ||
| 70 | * @file_priv: DRM file that performs the operation | ||
| 71 | * | ||
| 72 | * This looks up a DRM client by the passed magic and authenticates it. | ||
| 73 | * | ||
| 74 | * Returns: 0 on success, negative error code on failure. | ||
| 75 | */ | ||
| 76 | int drm_authmagic(struct drm_device *dev, void *data, | 77 | int drm_authmagic(struct drm_device *dev, void *data, |
| 77 | struct drm_file *file_priv) | 78 | struct drm_file *file_priv) |
| 78 | { | 79 | { |
| @@ -81,13 +82,253 @@ int drm_authmagic(struct drm_device *dev, void *data, | |||
| 81 | 82 | ||
| 82 | DRM_DEBUG("%u\n", auth->magic); | 83 | DRM_DEBUG("%u\n", auth->magic); |
| 83 | 84 | ||
| 84 | mutex_lock(&dev->struct_mutex); | 85 | mutex_lock(&dev->master_mutex); |
| 85 | file = idr_find(&file_priv->master->magic_map, auth->magic); | 86 | file = idr_find(&file_priv->master->magic_map, auth->magic); |
| 86 | if (file) { | 87 | if (file) { |
| 87 | file->authenticated = 1; | 88 | file->authenticated = 1; |
| 88 | idr_replace(&file_priv->master->magic_map, NULL, auth->magic); | 89 | idr_replace(&file_priv->master->magic_map, NULL, auth->magic); |
| 89 | } | 90 | } |
| 90 | mutex_unlock(&dev->struct_mutex); | 91 | mutex_unlock(&dev->master_mutex); |
| 91 | 92 | ||
| 92 | return file ? 0 : -EINVAL; | 93 | return file ? 0 : -EINVAL; |
| 93 | } | 94 | } |
| 95 | |||
| 96 | static struct drm_master *drm_master_create(struct drm_device *dev) | ||
| 97 | { | ||
| 98 | struct drm_master *master; | ||
| 99 | |||
| 100 | master = kzalloc(sizeof(*master), GFP_KERNEL); | ||
| 101 | if (!master) | ||
| 102 | return NULL; | ||
| 103 | |||
| 104 | kref_init(&master->refcount); | ||
| 105 | spin_lock_init(&master->lock.spinlock); | ||
| 106 | init_waitqueue_head(&master->lock.lock_queue); | ||
| 107 | idr_init(&master->magic_map); | ||
| 108 | master->dev = dev; | ||
| 109 | |||
| 110 | return master; | ||
| 111 | } | ||
| 112 | |||
| 113 | static int drm_set_master(struct drm_device *dev, struct drm_file *fpriv, | ||
| 114 | bool new_master) | ||
| 115 | { | ||
| 116 | int ret = 0; | ||
| 117 | |||
| 118 | dev->master = drm_master_get(fpriv->master); | ||
| 119 | if (dev->driver->master_set) { | ||
| 120 | ret = dev->driver->master_set(dev, fpriv, new_master); | ||
| 121 | if (unlikely(ret != 0)) { | ||
| 122 | drm_master_put(&dev->master); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | return ret; | ||
| 127 | } | ||
| 128 | |||
| 129 | static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv) | ||
| 130 | { | ||
| 131 | struct drm_master *old_master; | ||
| 132 | int ret; | ||
| 133 | |||
| 134 | lockdep_assert_held_once(&dev->master_mutex); | ||
| 135 | |||
| 136 | old_master = fpriv->master; | ||
| 137 | fpriv->master = drm_master_create(dev); | ||
| 138 | if (!fpriv->master) { | ||
| 139 | fpriv->master = old_master; | ||
| 140 | return -ENOMEM; | ||
| 141 | } | ||
| 142 | |||
| 143 | if (dev->driver->master_create) { | ||
| 144 | ret = dev->driver->master_create(dev, fpriv->master); | ||
| 145 | if (ret) | ||
| 146 | goto out_err; | ||
| 147 | } | ||
| 148 | fpriv->is_master = 1; | ||
| 149 | fpriv->authenticated = 1; | ||
| 150 | |||
| 151 | ret = drm_set_master(dev, fpriv, true); | ||
| 152 | if (ret) | ||
| 153 | goto out_err; | ||
| 154 | |||
| 155 | if (old_master) | ||
| 156 | drm_master_put(&old_master); | ||
| 157 | |||
| 158 | return 0; | ||
| 159 | |||
| 160 | out_err: | ||
| 161 | /* drop references and restore old master on failure */ | ||
| 162 | drm_master_put(&fpriv->master); | ||
| 163 | fpriv->master = old_master; | ||
| 164 | |||
| 165 | return ret; | ||
| 166 | } | ||
| 167 | |||
| 168 | int drm_setmaster_ioctl(struct drm_device *dev, void *data, | ||
| 169 | struct drm_file *file_priv) | ||
| 170 | { | ||
| 171 | int ret = 0; | ||
| 172 | |||
| 173 | mutex_lock(&dev->master_mutex); | ||
| 174 | if (drm_is_current_master(file_priv)) | ||
| 175 | goto out_unlock; | ||
| 176 | |||
| 177 | if (dev->master) { | ||
| 178 | ret = -EINVAL; | ||
| 179 | goto out_unlock; | ||
| 180 | } | ||
| 181 | |||
| 182 | if (!file_priv->master) { | ||
| 183 | ret = -EINVAL; | ||
| 184 | goto out_unlock; | ||
| 185 | } | ||
| 186 | |||
| 187 | if (!file_priv->is_master) { | ||
| 188 | ret = drm_new_set_master(dev, file_priv); | ||
| 189 | goto out_unlock; | ||
| 190 | } | ||
| 191 | |||
| 192 | ret = drm_set_master(dev, file_priv, false); | ||
| 193 | out_unlock: | ||
| 194 | mutex_unlock(&dev->master_mutex); | ||
| 195 | return ret; | ||
| 196 | } | ||
| 197 | |||
| 198 | static void drm_drop_master(struct drm_device *dev, | ||
| 199 | struct drm_file *fpriv) | ||
| 200 | { | ||
| 201 | if (dev->driver->master_drop) | ||
| 202 | dev->driver->master_drop(dev, fpriv); | ||
| 203 | drm_master_put(&dev->master); | ||
| 204 | } | ||
| 205 | |||
| 206 | int drm_dropmaster_ioctl(struct drm_device *dev, void *data, | ||
| 207 | struct drm_file *file_priv) | ||
| 208 | { | ||
| 209 | int ret = -EINVAL; | ||
| 210 | |||
| 211 | mutex_lock(&dev->master_mutex); | ||
| 212 | if (!drm_is_current_master(file_priv)) | ||
| 213 | goto out_unlock; | ||
| 214 | |||
| 215 | if (!dev->master) | ||
| 216 | goto out_unlock; | ||
| 217 | |||
| 218 | ret = 0; | ||
| 219 | drm_drop_master(dev, file_priv); | ||
| 220 | out_unlock: | ||
| 221 | mutex_unlock(&dev->master_mutex); | ||
| 222 | return ret; | ||
| 223 | } | ||
| 224 | |||
| 225 | int drm_master_open(struct drm_file *file_priv) | ||
| 226 | { | ||
| 227 | struct drm_device *dev = file_priv->minor->dev; | ||
| 228 | int ret = 0; | ||
| 229 | |||
| 230 | /* if there is no current master make this fd it, but do not create | ||
| 231 | * any master object for render clients */ | ||
| 232 | mutex_lock(&dev->master_mutex); | ||
| 233 | if (!dev->master) | ||
| 234 | ret = drm_new_set_master(dev, file_priv); | ||
| 235 | else | ||
| 236 | file_priv->master = drm_master_get(dev->master); | ||
| 237 | mutex_unlock(&dev->master_mutex); | ||
| 238 | |||
| 239 | return ret; | ||
| 240 | } | ||
| 241 | |||
| 242 | void drm_master_release(struct drm_file *file_priv) | ||
| 243 | { | ||
| 244 | struct drm_device *dev = file_priv->minor->dev; | ||
| 245 | struct drm_master *master = file_priv->master; | ||
| 246 | |||
| 247 | mutex_lock(&dev->master_mutex); | ||
| 248 | if (file_priv->magic) | ||
| 249 | idr_remove(&file_priv->master->magic_map, file_priv->magic); | ||
| 250 | |||
| 251 | if (!drm_is_current_master(file_priv)) | ||
| 252 | goto out; | ||
| 253 | |||
| 254 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 255 | /* | ||
| 256 | * Since the master is disappearing, so is the | ||
| 257 | * possibility to lock. | ||
| 258 | */ | ||
| 259 | mutex_lock(&dev->struct_mutex); | ||
| 260 | if (master->lock.hw_lock) { | ||
| 261 | if (dev->sigdata.lock == master->lock.hw_lock) | ||
| 262 | dev->sigdata.lock = NULL; | ||
| 263 | master->lock.hw_lock = NULL; | ||
| 264 | master->lock.file_priv = NULL; | ||
| 265 | wake_up_interruptible_all(&master->lock.lock_queue); | ||
| 266 | } | ||
| 267 | mutex_unlock(&dev->struct_mutex); | ||
| 268 | } | ||
| 269 | |||
| 270 | if (dev->master == file_priv->master) | ||
| 271 | drm_drop_master(dev, file_priv); | ||
| 272 | out: | ||
| 273 | /* drop the master reference held by the file priv */ | ||
| 274 | if (file_priv->master) | ||
| 275 | drm_master_put(&file_priv->master); | ||
| 276 | mutex_unlock(&dev->master_mutex); | ||
| 277 | } | ||
| 278 | |||
| 279 | /** | ||
| 280 | * drm_is_current_master - checks whether @priv is the current master | ||
| 281 | * @fpriv: DRM file private | ||
| 282 | * | ||
| 283 | * Checks whether @fpriv is current master on its device. This decides whether a | ||
| 284 | * client is allowed to run DRM_MASTER IOCTLs. | ||
| 285 | * | ||
| 286 | * Most of the modern IOCTL which require DRM_MASTER are for kernel modesetting | ||
| 287 | * - the current master is assumed to own the non-shareable display hardware. | ||
| 288 | */ | ||
| 289 | bool drm_is_current_master(struct drm_file *fpriv) | ||
| 290 | { | ||
| 291 | return fpriv->is_master && fpriv->master == fpriv->minor->dev->master; | ||
| 292 | } | ||
| 293 | EXPORT_SYMBOL(drm_is_current_master); | ||
| 294 | |||
| 295 | /** | ||
| 296 | * drm_master_get - reference a master pointer | ||
| 297 | * @master: struct &drm_master | ||
| 298 | * | ||
| 299 | * Increments the reference count of @master and returns a pointer to @master. | ||
| 300 | */ | ||
| 301 | struct drm_master *drm_master_get(struct drm_master *master) | ||
| 302 | { | ||
| 303 | kref_get(&master->refcount); | ||
| 304 | return master; | ||
| 305 | } | ||
| 306 | EXPORT_SYMBOL(drm_master_get); | ||
| 307 | |||
| 308 | static void drm_master_destroy(struct kref *kref) | ||
| 309 | { | ||
| 310 | struct drm_master *master = container_of(kref, struct drm_master, refcount); | ||
| 311 | struct drm_device *dev = master->dev; | ||
| 312 | |||
| 313 | if (dev->driver->master_destroy) | ||
| 314 | dev->driver->master_destroy(dev, master); | ||
| 315 | |||
| 316 | drm_legacy_master_rmmaps(dev, master); | ||
| 317 | |||
| 318 | idr_destroy(&master->magic_map); | ||
| 319 | kfree(master->unique); | ||
| 320 | kfree(master); | ||
| 321 | } | ||
| 322 | |||
| 323 | /** | ||
| 324 | * drm_master_put - unreference and clear a master pointer | ||
| 325 | * @master: pointer to a pointer of struct &drm_master | ||
| 326 | * | ||
| 327 | * This decrements the &drm_master behind @master and sets it to NULL. | ||
| 328 | */ | ||
| 329 | void drm_master_put(struct drm_master **master) | ||
| 330 | { | ||
| 331 | kref_put(&(*master)->refcount, drm_master_destroy); | ||
| 332 | *master = NULL; | ||
| 333 | } | ||
| 334 | EXPORT_SYMBOL(drm_master_put); | ||
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 9b34158c0f77..c3a12cd8bd0d 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c | |||
| @@ -51,7 +51,7 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, | |||
| 51 | */ | 51 | */ |
| 52 | if (!entry->map || | 52 | if (!entry->map || |
| 53 | map->type != entry->map->type || | 53 | map->type != entry->map->type || |
| 54 | entry->master != dev->primary->master) | 54 | entry->master != dev->master) |
| 55 | continue; | 55 | continue; |
| 56 | switch (map->type) { | 56 | switch (map->type) { |
| 57 | case _DRM_SHM: | 57 | case _DRM_SHM: |
| @@ -245,12 +245,12 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, | |||
| 245 | map->offset = (unsigned long)map->handle; | 245 | map->offset = (unsigned long)map->handle; |
| 246 | if (map->flags & _DRM_CONTAINS_LOCK) { | 246 | if (map->flags & _DRM_CONTAINS_LOCK) { |
| 247 | /* Prevent a 2nd X Server from creating a 2nd lock */ | 247 | /* Prevent a 2nd X Server from creating a 2nd lock */ |
| 248 | if (dev->primary->master->lock.hw_lock != NULL) { | 248 | if (dev->master->lock.hw_lock != NULL) { |
| 249 | vfree(map->handle); | 249 | vfree(map->handle); |
| 250 | kfree(map); | 250 | kfree(map); |
| 251 | return -EBUSY; | 251 | return -EBUSY; |
| 252 | } | 252 | } |
| 253 | dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle; /* Pointer to lock */ | 253 | dev->sigdata.lock = dev->master->lock.hw_lock = map->handle; /* Pointer to lock */ |
| 254 | } | 254 | } |
| 255 | break; | 255 | break; |
| 256 | case _DRM_AGP: { | 256 | case _DRM_AGP: { |
| @@ -356,7 +356,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, | |||
| 356 | mutex_unlock(&dev->struct_mutex); | 356 | mutex_unlock(&dev->struct_mutex); |
| 357 | 357 | ||
| 358 | if (!(map->flags & _DRM_DRIVER)) | 358 | if (!(map->flags & _DRM_DRIVER)) |
| 359 | list->master = dev->primary->master; | 359 | list->master = dev->master; |
| 360 | *maplist = list; | 360 | *maplist = list; |
| 361 | return 0; | 361 | return 0; |
| 362 | } | 362 | } |
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 4ec35f9e6de5..fd93e9c79d28 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | #include <drm/drm_fourcc.h> | 39 | #include <drm/drm_fourcc.h> |
| 40 | #include <drm/drm_modeset_lock.h> | 40 | #include <drm/drm_modeset_lock.h> |
| 41 | #include <drm/drm_atomic.h> | 41 | #include <drm/drm_atomic.h> |
| 42 | #include <drm/drm_auth.h> | ||
| 42 | 43 | ||
| 43 | #include "drm_crtc_internal.h" | 44 | #include "drm_crtc_internal.h" |
| 44 | #include "drm_internal.h" | 45 | #include "drm_internal.h" |
| @@ -608,6 +609,31 @@ static unsigned int drm_num_crtcs(struct drm_device *dev) | |||
| 608 | return num; | 609 | return num; |
| 609 | } | 610 | } |
| 610 | 611 | ||
| 612 | static int drm_crtc_register_all(struct drm_device *dev) | ||
| 613 | { | ||
| 614 | struct drm_crtc *crtc; | ||
| 615 | int ret = 0; | ||
| 616 | |||
| 617 | drm_for_each_crtc(crtc, dev) { | ||
| 618 | if (crtc->funcs->late_register) | ||
| 619 | ret = crtc->funcs->late_register(crtc); | ||
| 620 | if (ret) | ||
| 621 | return ret; | ||
| 622 | } | ||
| 623 | |||
| 624 | return 0; | ||
| 625 | } | ||
| 626 | |||
| 627 | static void drm_crtc_unregister_all(struct drm_device *dev) | ||
| 628 | { | ||
| 629 | struct drm_crtc *crtc; | ||
| 630 | |||
| 631 | drm_for_each_crtc(crtc, dev) { | ||
| 632 | if (crtc->funcs->early_unregister) | ||
| 633 | crtc->funcs->early_unregister(crtc); | ||
| 634 | } | ||
| 635 | } | ||
| 636 | |||
| 611 | /** | 637 | /** |
| 612 | * drm_crtc_init_with_planes - Initialise a new CRTC object with | 638 | * drm_crtc_init_with_planes - Initialise a new CRTC object with |
| 613 | * specified primary and cursor planes. | 639 | * specified primary and cursor planes. |
| @@ -938,6 +964,12 @@ void drm_connector_cleanup(struct drm_connector *connector) | |||
| 938 | struct drm_device *dev = connector->dev; | 964 | struct drm_device *dev = connector->dev; |
| 939 | struct drm_display_mode *mode, *t; | 965 | struct drm_display_mode *mode, *t; |
| 940 | 966 | ||
| 967 | /* The connector should have been removed from userspace long before | ||
| 968 | * it is finally destroyed. | ||
| 969 | */ | ||
| 970 | if (WARN_ON(connector->registered)) | ||
| 971 | drm_connector_unregister(connector); | ||
| 972 | |||
| 941 | if (connector->tile_group) { | 973 | if (connector->tile_group) { |
| 942 | drm_mode_put_tile_group(dev, connector->tile_group); | 974 | drm_mode_put_tile_group(dev, connector->tile_group); |
| 943 | connector->tile_group = NULL; | 975 | connector->tile_group = NULL; |
| @@ -984,19 +1016,34 @@ int drm_connector_register(struct drm_connector *connector) | |||
| 984 | { | 1016 | { |
| 985 | int ret; | 1017 | int ret; |
| 986 | 1018 | ||
| 1019 | if (connector->registered) | ||
| 1020 | return 0; | ||
| 1021 | |||
| 987 | ret = drm_sysfs_connector_add(connector); | 1022 | ret = drm_sysfs_connector_add(connector); |
| 988 | if (ret) | 1023 | if (ret) |
| 989 | return ret; | 1024 | return ret; |
| 990 | 1025 | ||
| 991 | ret = drm_debugfs_connector_add(connector); | 1026 | ret = drm_debugfs_connector_add(connector); |
| 992 | if (ret) { | 1027 | if (ret) { |
| 993 | drm_sysfs_connector_remove(connector); | 1028 | goto err_sysfs; |
| 994 | return ret; | 1029 | } |
| 1030 | |||
| 1031 | if (connector->funcs->late_register) { | ||
| 1032 | ret = connector->funcs->late_register(connector); | ||
| 1033 | if (ret) | ||
| 1034 | goto err_debugfs; | ||
| 995 | } | 1035 | } |
| 996 | 1036 | ||
| 997 | drm_mode_object_register(connector->dev, &connector->base); | 1037 | drm_mode_object_register(connector->dev, &connector->base); |
| 998 | 1038 | ||
| 1039 | connector->registered = true; | ||
| 999 | return 0; | 1040 | return 0; |
| 1041 | |||
| 1042 | err_debugfs: | ||
| 1043 | drm_debugfs_connector_remove(connector); | ||
| 1044 | err_sysfs: | ||
| 1045 | drm_sysfs_connector_remove(connector); | ||
| 1046 | return ret; | ||
| 1000 | } | 1047 | } |
| 1001 | EXPORT_SYMBOL(drm_connector_register); | 1048 | EXPORT_SYMBOL(drm_connector_register); |
| 1002 | 1049 | ||
| @@ -1008,8 +1055,16 @@ EXPORT_SYMBOL(drm_connector_register); | |||
| 1008 | */ | 1055 | */ |
| 1009 | void drm_connector_unregister(struct drm_connector *connector) | 1056 | void drm_connector_unregister(struct drm_connector *connector) |
| 1010 | { | 1057 | { |
| 1058 | if (!connector->registered) | ||
| 1059 | return; | ||
| 1060 | |||
| 1061 | if (connector->funcs->early_unregister) | ||
| 1062 | connector->funcs->early_unregister(connector); | ||
| 1063 | |||
| 1011 | drm_sysfs_connector_remove(connector); | 1064 | drm_sysfs_connector_remove(connector); |
| 1012 | drm_debugfs_connector_remove(connector); | 1065 | drm_debugfs_connector_remove(connector); |
| 1066 | |||
| 1067 | connector->registered = false; | ||
| 1013 | } | 1068 | } |
| 1014 | EXPORT_SYMBOL(drm_connector_unregister); | 1069 | EXPORT_SYMBOL(drm_connector_unregister); |
| 1015 | 1070 | ||
| @@ -1018,9 +1073,9 @@ EXPORT_SYMBOL(drm_connector_unregister); | |||
| 1018 | * @dev: drm device | 1073 | * @dev: drm device |
| 1019 | * | 1074 | * |
| 1020 | * This function registers all connectors in sysfs and other places so that | 1075 | * This function registers all connectors in sysfs and other places so that |
| 1021 | * userspace can start to access them. Drivers can call it after calling | 1076 | * userspace can start to access them. drm_connector_register_all() is called |
| 1022 | * drm_dev_register() to complete the device registration, if they don't call | 1077 | * automatically from drm_dev_register() to complete the device registration, |
| 1023 | * drm_connector_register() on each connector individually. | 1078 | * if they don't call drm_connector_register() on each connector individually. |
| 1024 | * | 1079 | * |
| 1025 | * When a device is unplugged and should be removed from userspace access, | 1080 | * When a device is unplugged and should be removed from userspace access, |
| 1026 | * call drm_connector_unregister_all(), which is the inverse of this | 1081 | * call drm_connector_unregister_all(), which is the inverse of this |
| @@ -1073,6 +1128,31 @@ void drm_connector_unregister_all(struct drm_device *dev) | |||
| 1073 | } | 1128 | } |
| 1074 | EXPORT_SYMBOL(drm_connector_unregister_all); | 1129 | EXPORT_SYMBOL(drm_connector_unregister_all); |
| 1075 | 1130 | ||
| 1131 | static int drm_encoder_register_all(struct drm_device *dev) | ||
| 1132 | { | ||
| 1133 | struct drm_encoder *encoder; | ||
| 1134 | int ret = 0; | ||
| 1135 | |||
| 1136 | drm_for_each_encoder(encoder, dev) { | ||
| 1137 | if (encoder->funcs->late_register) | ||
| 1138 | ret = encoder->funcs->late_register(encoder); | ||
| 1139 | if (ret) | ||
| 1140 | return ret; | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | return 0; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | static void drm_encoder_unregister_all(struct drm_device *dev) | ||
| 1147 | { | ||
| 1148 | struct drm_encoder *encoder; | ||
| 1149 | |||
| 1150 | drm_for_each_encoder(encoder, dev) { | ||
| 1151 | if (encoder->funcs->early_unregister) | ||
| 1152 | encoder->funcs->early_unregister(encoder); | ||
| 1153 | } | ||
| 1154 | } | ||
| 1155 | |||
| 1076 | /** | 1156 | /** |
| 1077 | * drm_encoder_init - Init a preallocated encoder | 1157 | * drm_encoder_init - Init a preallocated encoder |
| 1078 | * @dev: drm device | 1158 | * @dev: drm device |
| @@ -1261,6 +1341,31 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
| 1261 | } | 1341 | } |
| 1262 | EXPORT_SYMBOL(drm_universal_plane_init); | 1342 | EXPORT_SYMBOL(drm_universal_plane_init); |
| 1263 | 1343 | ||
| 1344 | static int drm_plane_register_all(struct drm_device *dev) | ||
| 1345 | { | ||
| 1346 | struct drm_plane *plane; | ||
| 1347 | int ret = 0; | ||
| 1348 | |||
| 1349 | drm_for_each_plane(plane, dev) { | ||
| 1350 | if (plane->funcs->late_register) | ||
| 1351 | ret = plane->funcs->late_register(plane); | ||
| 1352 | if (ret) | ||
| 1353 | return ret; | ||
| 1354 | } | ||
| 1355 | |||
| 1356 | return 0; | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | static void drm_plane_unregister_all(struct drm_device *dev) | ||
| 1360 | { | ||
| 1361 | struct drm_plane *plane; | ||
| 1362 | |||
| 1363 | drm_for_each_plane(plane, dev) { | ||
| 1364 | if (plane->funcs->early_unregister) | ||
| 1365 | plane->funcs->early_unregister(plane); | ||
| 1366 | } | ||
| 1367 | } | ||
| 1368 | |||
| 1264 | /** | 1369 | /** |
| 1265 | * drm_plane_init - Initialize a legacy plane | 1370 | * drm_plane_init - Initialize a legacy plane |
| 1266 | * @dev: DRM device | 1371 | * @dev: DRM device |
| @@ -1383,6 +1488,46 @@ void drm_plane_force_disable(struct drm_plane *plane) | |||
| 1383 | } | 1488 | } |
| 1384 | EXPORT_SYMBOL(drm_plane_force_disable); | 1489 | EXPORT_SYMBOL(drm_plane_force_disable); |
| 1385 | 1490 | ||
| 1491 | int drm_modeset_register_all(struct drm_device *dev) | ||
| 1492 | { | ||
| 1493 | int ret; | ||
| 1494 | |||
| 1495 | ret = drm_plane_register_all(dev); | ||
| 1496 | if (ret) | ||
| 1497 | goto err_plane; | ||
| 1498 | |||
| 1499 | ret = drm_crtc_register_all(dev); | ||
| 1500 | if (ret) | ||
| 1501 | goto err_crtc; | ||
| 1502 | |||
| 1503 | ret = drm_encoder_register_all(dev); | ||
| 1504 | if (ret) | ||
| 1505 | goto err_encoder; | ||
| 1506 | |||
| 1507 | ret = drm_connector_register_all(dev); | ||
| 1508 | if (ret) | ||
| 1509 | goto err_connector; | ||
| 1510 | |||
| 1511 | return 0; | ||
| 1512 | |||
| 1513 | err_connector: | ||
| 1514 | drm_encoder_unregister_all(dev); | ||
| 1515 | err_encoder: | ||
| 1516 | drm_crtc_unregister_all(dev); | ||
| 1517 | err_crtc: | ||
| 1518 | drm_plane_unregister_all(dev); | ||
| 1519 | err_plane: | ||
| 1520 | return ret; | ||
| 1521 | } | ||
| 1522 | |||
| 1523 | void drm_modeset_unregister_all(struct drm_device *dev) | ||
| 1524 | { | ||
| 1525 | drm_connector_unregister_all(dev); | ||
| 1526 | drm_encoder_unregister_all(dev); | ||
| 1527 | drm_crtc_unregister_all(dev); | ||
| 1528 | drm_plane_unregister_all(dev); | ||
| 1529 | } | ||
| 1530 | |||
| 1386 | static int drm_mode_create_standard_properties(struct drm_device *dev) | 1531 | static int drm_mode_create_standard_properties(struct drm_device *dev) |
| 1387 | { | 1532 | { |
| 1388 | struct drm_property *prop; | 1533 | struct drm_property *prop; |
| @@ -3499,7 +3644,7 @@ int drm_mode_getfb(struct drm_device *dev, | |||
| 3499 | r->bpp = fb->bits_per_pixel; | 3644 | r->bpp = fb->bits_per_pixel; |
| 3500 | r->pitch = fb->pitches[0]; | 3645 | r->pitch = fb->pitches[0]; |
| 3501 | if (fb->funcs->create_handle) { | 3646 | if (fb->funcs->create_handle) { |
| 3502 | if (file_priv->is_master || capable(CAP_SYS_ADMIN) || | 3647 | if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) || |
| 3503 | drm_is_control_client(file_priv)) { | 3648 | drm_is_control_client(file_priv)) { |
| 3504 | ret = fb->funcs->create_handle(fb, file_priv, | 3649 | ret = fb->funcs->create_handle(fb, file_priv, |
| 3505 | &r->handle); | 3650 | &r->handle); |
| @@ -3656,6 +3801,13 @@ void drm_fb_release(struct drm_file *priv) | |||
| 3656 | } | 3801 | } |
| 3657 | } | 3802 | } |
| 3658 | 3803 | ||
| 3804 | static bool drm_property_type_valid(struct drm_property *property) | ||
| 3805 | { | ||
| 3806 | if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) | ||
| 3807 | return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE); | ||
| 3808 | return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE); | ||
| 3809 | } | ||
| 3810 | |||
| 3659 | /** | 3811 | /** |
| 3660 | * drm_property_create - create a new property type | 3812 | * drm_property_create - create a new property type |
| 3661 | * @dev: drm device | 3813 | * @dev: drm device |
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index bf10d7046aa6..d61591274ff6 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
| @@ -232,6 +232,9 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) | |||
| 232 | */ | 232 | */ |
| 233 | void drm_helper_disable_unused_functions(struct drm_device *dev) | 233 | void drm_helper_disable_unused_functions(struct drm_device *dev) |
| 234 | { | 234 | { |
| 235 | if (drm_core_check_feature(dev, DRIVER_ATOMIC)) | ||
| 236 | DRM_ERROR("Called for atomic driver, this is not what you want.\n"); | ||
| 237 | |||
| 235 | drm_modeset_lock_all(dev); | 238 | drm_modeset_lock_all(dev); |
| 236 | __drm_helper_disable_unused_functions(dev); | 239 | __drm_helper_disable_unused_functions(dev); |
| 237 | drm_modeset_unlock_all(dev); | 240 | drm_modeset_unlock_all(dev); |
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index a78c138282ea..47a500b90fd7 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h | |||
| @@ -31,14 +31,100 @@ | |||
| 31 | * and are not exported to drivers. | 31 | * and are not exported to drivers. |
| 32 | */ | 32 | */ |
| 33 | 33 | ||
| 34 | |||
| 35 | /* drm_crtc.c */ | ||
| 36 | void drm_connector_ida_init(void); | ||
| 37 | void drm_connector_ida_destroy(void); | ||
| 34 | int drm_mode_object_get(struct drm_device *dev, | 38 | int drm_mode_object_get(struct drm_device *dev, |
| 35 | struct drm_mode_object *obj, uint32_t obj_type); | 39 | struct drm_mode_object *obj, uint32_t obj_type); |
| 36 | void drm_mode_object_unregister(struct drm_device *dev, | 40 | void drm_mode_object_unregister(struct drm_device *dev, |
| 37 | struct drm_mode_object *object); | 41 | struct drm_mode_object *object); |
| 42 | bool drm_property_change_valid_get(struct drm_property *property, | ||
| 43 | uint64_t value, | ||
| 44 | struct drm_mode_object **ref); | ||
| 45 | void drm_property_change_valid_put(struct drm_property *property, | ||
| 46 | struct drm_mode_object *ref); | ||
| 47 | |||
| 48 | int drm_plane_check_pixel_format(const struct drm_plane *plane, | ||
| 49 | u32 format); | ||
| 50 | int drm_crtc_check_viewport(const struct drm_crtc *crtc, | ||
| 51 | int x, int y, | ||
| 52 | const struct drm_display_mode *mode, | ||
| 53 | const struct drm_framebuffer *fb); | ||
| 54 | |||
| 55 | void drm_fb_release(struct drm_file *file_priv); | ||
| 56 | void drm_property_destroy_user_blobs(struct drm_device *dev, | ||
| 57 | struct drm_file *file_priv); | ||
| 58 | |||
| 59 | /* dumb buffer support IOCTLs */ | ||
| 60 | int drm_mode_create_dumb_ioctl(struct drm_device *dev, | ||
| 61 | void *data, struct drm_file *file_priv); | ||
| 62 | int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, | ||
| 63 | void *data, struct drm_file *file_priv); | ||
| 64 | int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, | ||
| 65 | void *data, struct drm_file *file_priv); | ||
| 66 | |||
| 67 | /* framebuffer IOCTLs */ | ||
| 68 | extern int drm_mode_addfb(struct drm_device *dev, | ||
| 69 | void *data, struct drm_file *file_priv); | ||
| 70 | extern int drm_mode_addfb2(struct drm_device *dev, | ||
| 71 | void *data, struct drm_file *file_priv); | ||
| 72 | int drm_mode_rmfb(struct drm_device *dev, | ||
| 73 | void *data, struct drm_file *file_priv); | ||
| 74 | int drm_mode_getfb(struct drm_device *dev, | ||
| 75 | void *data, struct drm_file *file_priv); | ||
| 76 | int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | ||
| 77 | void *data, struct drm_file *file_priv); | ||
| 78 | |||
| 79 | /* IOCTLs */ | ||
| 80 | int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | ||
| 81 | struct drm_file *file_priv); | ||
| 82 | int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | ||
| 83 | struct drm_file *file_priv); | ||
| 84 | |||
| 85 | int drm_mode_getresources(struct drm_device *dev, | ||
| 86 | void *data, struct drm_file *file_priv); | ||
| 87 | int drm_mode_getplane_res(struct drm_device *dev, void *data, | ||
| 88 | struct drm_file *file_priv); | ||
| 89 | int drm_mode_getcrtc(struct drm_device *dev, | ||
| 90 | void *data, struct drm_file *file_priv); | ||
| 91 | int drm_mode_getconnector(struct drm_device *dev, | ||
| 92 | void *data, struct drm_file *file_priv); | ||
| 93 | int drm_mode_setcrtc(struct drm_device *dev, | ||
| 94 | void *data, struct drm_file *file_priv); | ||
| 95 | int drm_mode_getplane(struct drm_device *dev, | ||
| 96 | void *data, struct drm_file *file_priv); | ||
| 97 | int drm_mode_setplane(struct drm_device *dev, | ||
| 98 | void *data, struct drm_file *file_priv); | ||
| 99 | int drm_mode_cursor_ioctl(struct drm_device *dev, | ||
| 100 | void *data, struct drm_file *file_priv); | ||
| 101 | int drm_mode_cursor2_ioctl(struct drm_device *dev, | ||
| 102 | void *data, struct drm_file *file_priv); | ||
| 103 | int drm_mode_getproperty_ioctl(struct drm_device *dev, | ||
| 104 | void *data, struct drm_file *file_priv); | ||
| 105 | int drm_mode_getblob_ioctl(struct drm_device *dev, | ||
| 106 | void *data, struct drm_file *file_priv); | ||
| 107 | int drm_mode_createblob_ioctl(struct drm_device *dev, | ||
| 108 | void *data, struct drm_file *file_priv); | ||
| 109 | int drm_mode_destroyblob_ioctl(struct drm_device *dev, | ||
| 110 | void *data, struct drm_file *file_priv); | ||
| 111 | int drm_mode_connector_property_set_ioctl(struct drm_device *dev, | ||
| 112 | void *data, struct drm_file *file_priv); | ||
| 113 | int drm_mode_getencoder(struct drm_device *dev, | ||
| 114 | void *data, struct drm_file *file_priv); | ||
| 115 | int drm_mode_gamma_get_ioctl(struct drm_device *dev, | ||
| 116 | void *data, struct drm_file *file_priv); | ||
| 117 | int drm_mode_gamma_set_ioctl(struct drm_device *dev, | ||
| 118 | void *data, struct drm_file *file_priv); | ||
| 119 | |||
| 120 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
| 121 | void *data, struct drm_file *file_priv); | ||
| 38 | 122 | ||
| 39 | /* drm_atomic.c */ | 123 | /* drm_atomic.c */ |
| 40 | int drm_atomic_get_property(struct drm_mode_object *obj, | 124 | int drm_atomic_get_property(struct drm_mode_object *obj, |
| 41 | struct drm_property *property, uint64_t *val); | 125 | struct drm_property *property, uint64_t *val); |
| 42 | int drm_mode_atomic_ioctl(struct drm_device *dev, | 126 | int drm_mode_atomic_ioctl(struct drm_device *dev, |
| 43 | void *data, struct drm_file *file_priv); | 127 | void *data, struct drm_file *file_priv); |
| 44 | 128 | ||
| 129 | int drm_modeset_register_all(struct drm_device *dev); | ||
| 130 | void drm_modeset_unregister_all(struct drm_device *dev); | ||
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 3bcf8e6a85b3..fa10cef2ba37 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c | |||
| @@ -46,11 +46,8 @@ | |||
| 46 | 46 | ||
| 47 | static const struct drm_info_list drm_debugfs_list[] = { | 47 | static const struct drm_info_list drm_debugfs_list[] = { |
| 48 | {"name", drm_name_info, 0}, | 48 | {"name", drm_name_info, 0}, |
| 49 | {"vm", drm_vm_info, 0}, | ||
| 50 | {"clients", drm_clients_info, 0}, | 49 | {"clients", drm_clients_info, 0}, |
| 51 | {"bufs", drm_bufs_info, 0}, | ||
| 52 | {"gem_names", drm_gem_name_info, DRIVER_GEM}, | 50 | {"gem_names", drm_gem_name_info, DRIVER_GEM}, |
| 53 | {"vma", drm_vma_info, 0}, | ||
| 54 | }; | 51 | }; |
| 55 | #define DRM_DEBUGFS_ENTRIES ARRAY_SIZE(drm_debugfs_list) | 52 | #define DRM_DEBUGFS_ENTRIES ARRAY_SIZE(drm_debugfs_list) |
| 56 | 53 | ||
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index eeaf5a7c3aa7..091053e995e5 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c | |||
| @@ -708,8 +708,6 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, | |||
| 708 | 708 | ||
| 709 | memset(&msg, 0, sizeof(msg)); | 709 | memset(&msg, 0, sizeof(msg)); |
| 710 | 710 | ||
| 711 | mutex_lock(&aux->hw_mutex); | ||
| 712 | |||
| 713 | for (i = 0; i < num; i++) { | 711 | for (i = 0; i < num; i++) { |
| 714 | msg.address = msgs[i].addr; | 712 | msg.address = msgs[i].addr; |
| 715 | drm_dp_i2c_msg_set_request(&msg, &msgs[i]); | 713 | drm_dp_i2c_msg_set_request(&msg, &msgs[i]); |
| @@ -764,8 +762,6 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, | |||
| 764 | msg.size = 0; | 762 | msg.size = 0; |
| 765 | (void)drm_dp_i2c_do_msg(aux, &msg); | 763 | (void)drm_dp_i2c_do_msg(aux, &msg); |
| 766 | 764 | ||
| 767 | mutex_unlock(&aux->hw_mutex); | ||
| 768 | |||
| 769 | return err; | 765 | return err; |
| 770 | } | 766 | } |
| 771 | 767 | ||
| @@ -774,22 +770,64 @@ static const struct i2c_algorithm drm_dp_i2c_algo = { | |||
| 774 | .master_xfer = drm_dp_i2c_xfer, | 770 | .master_xfer = drm_dp_i2c_xfer, |
| 775 | }; | 771 | }; |
| 776 | 772 | ||
| 773 | static struct drm_dp_aux *i2c_to_aux(struct i2c_adapter *i2c) | ||
| 774 | { | ||
| 775 | return container_of(i2c, struct drm_dp_aux, ddc); | ||
| 776 | } | ||
| 777 | |||
| 778 | static void lock_bus(struct i2c_adapter *i2c, unsigned int flags) | ||
| 779 | { | ||
| 780 | mutex_lock(&i2c_to_aux(i2c)->hw_mutex); | ||
| 781 | } | ||
| 782 | |||
| 783 | static int trylock_bus(struct i2c_adapter *i2c, unsigned int flags) | ||
| 784 | { | ||
| 785 | return mutex_trylock(&i2c_to_aux(i2c)->hw_mutex); | ||
| 786 | } | ||
| 787 | |||
| 788 | static void unlock_bus(struct i2c_adapter *i2c, unsigned int flags) | ||
| 789 | { | ||
| 790 | mutex_unlock(&i2c_to_aux(i2c)->hw_mutex); | ||
| 791 | } | ||
| 792 | |||
| 777 | /** | 793 | /** |
| 778 | * drm_dp_aux_register() - initialise and register aux channel | 794 | * drm_dp_aux_init() - minimally initialise an aux channel |
| 779 | * @aux: DisplayPort AUX channel | 795 | * @aux: DisplayPort AUX channel |
| 780 | * | 796 | * |
| 781 | * Returns 0 on success or a negative error code on failure. | 797 | * If you need to use the drm_dp_aux's i2c adapter prior to registering it |
| 798 | * with the outside world, call drm_dp_aux_init() first. You must still | ||
| 799 | * call drm_dp_aux_register() once the connector has been registered to | ||
| 800 | * allow userspace access to the auxiliary DP channel. | ||
| 782 | */ | 801 | */ |
| 783 | int drm_dp_aux_register(struct drm_dp_aux *aux) | 802 | void drm_dp_aux_init(struct drm_dp_aux *aux) |
| 784 | { | 803 | { |
| 785 | int ret; | ||
| 786 | |||
| 787 | mutex_init(&aux->hw_mutex); | 804 | mutex_init(&aux->hw_mutex); |
| 788 | 805 | ||
| 789 | aux->ddc.algo = &drm_dp_i2c_algo; | 806 | aux->ddc.algo = &drm_dp_i2c_algo; |
| 790 | aux->ddc.algo_data = aux; | 807 | aux->ddc.algo_data = aux; |
| 791 | aux->ddc.retries = 3; | 808 | aux->ddc.retries = 3; |
| 792 | 809 | ||
| 810 | aux->ddc.lock_bus = lock_bus; | ||
| 811 | aux->ddc.trylock_bus = trylock_bus; | ||
| 812 | aux->ddc.unlock_bus = unlock_bus; | ||
| 813 | } | ||
| 814 | EXPORT_SYMBOL(drm_dp_aux_init); | ||
| 815 | |||
| 816 | /** | ||
| 817 | * drm_dp_aux_register() - initialise and register aux channel | ||
| 818 | * @aux: DisplayPort AUX channel | ||
| 819 | * | ||
| 820 | * Automatically calls drm_dp_aux_init() if this hasn't been done yet. | ||
| 821 | * | ||
| 822 | * Returns 0 on success or a negative error code on failure. | ||
| 823 | */ | ||
| 824 | int drm_dp_aux_register(struct drm_dp_aux *aux) | ||
| 825 | { | ||
| 826 | int ret; | ||
| 827 | |||
| 828 | if (!aux->ddc.algo) | ||
| 829 | drm_dp_aux_init(aux); | ||
| 830 | |||
| 793 | aux->ddc.class = I2C_CLASS_DDC; | 831 | aux->ddc.class = I2C_CLASS_DDC; |
| 794 | aux->ddc.owner = THIS_MODULE; | 832 | aux->ddc.owner = THIS_MODULE; |
| 795 | aux->ddc.dev.parent = aux->dev; | 833 | aux->ddc.dev.parent = aux->dev; |
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 8b2582aeaab6..aead9ffcbe29 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
| @@ -34,8 +34,10 @@ | |||
| 34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
| 35 | #include <drm/drmP.h> | 35 | #include <drm/drmP.h> |
| 36 | #include <drm/drm_core.h> | 36 | #include <drm/drm_core.h> |
| 37 | #include "drm_crtc_internal.h" | ||
| 37 | #include "drm_legacy.h" | 38 | #include "drm_legacy.h" |
| 38 | #include "drm_internal.h" | 39 | #include "drm_internal.h" |
| 40 | #include "drm_crtc_internal.h" | ||
| 39 | 41 | ||
| 40 | /* | 42 | /* |
| 41 | * drm_debug: Enable debug output. | 43 | * drm_debug: Enable debug output. |
| @@ -93,114 +95,6 @@ void drm_ut_debug_printk(const char *function_name, const char *format, ...) | |||
| 93 | } | 95 | } |
| 94 | EXPORT_SYMBOL(drm_ut_debug_printk); | 96 | EXPORT_SYMBOL(drm_ut_debug_printk); |
| 95 | 97 | ||
| 96 | struct drm_master *drm_master_create(struct drm_minor *minor) | ||
| 97 | { | ||
| 98 | struct drm_master *master; | ||
| 99 | |||
| 100 | master = kzalloc(sizeof(*master), GFP_KERNEL); | ||
| 101 | if (!master) | ||
| 102 | return NULL; | ||
| 103 | |||
| 104 | kref_init(&master->refcount); | ||
| 105 | spin_lock_init(&master->lock.spinlock); | ||
| 106 | init_waitqueue_head(&master->lock.lock_queue); | ||
| 107 | idr_init(&master->magic_map); | ||
| 108 | master->minor = minor; | ||
| 109 | |||
| 110 | return master; | ||
| 111 | } | ||
| 112 | |||
| 113 | struct drm_master *drm_master_get(struct drm_master *master) | ||
| 114 | { | ||
| 115 | kref_get(&master->refcount); | ||
| 116 | return master; | ||
| 117 | } | ||
| 118 | EXPORT_SYMBOL(drm_master_get); | ||
| 119 | |||
| 120 | static void drm_master_destroy(struct kref *kref) | ||
| 121 | { | ||
| 122 | struct drm_master *master = container_of(kref, struct drm_master, refcount); | ||
| 123 | struct drm_device *dev = master->minor->dev; | ||
| 124 | |||
| 125 | if (dev->driver->master_destroy) | ||
| 126 | dev->driver->master_destroy(dev, master); | ||
| 127 | |||
| 128 | drm_legacy_master_rmmaps(dev, master); | ||
| 129 | |||
| 130 | idr_destroy(&master->magic_map); | ||
| 131 | kfree(master->unique); | ||
| 132 | kfree(master); | ||
| 133 | } | ||
| 134 | |||
| 135 | void drm_master_put(struct drm_master **master) | ||
| 136 | { | ||
| 137 | kref_put(&(*master)->refcount, drm_master_destroy); | ||
| 138 | *master = NULL; | ||
| 139 | } | ||
| 140 | EXPORT_SYMBOL(drm_master_put); | ||
| 141 | |||
| 142 | int drm_setmaster_ioctl(struct drm_device *dev, void *data, | ||
| 143 | struct drm_file *file_priv) | ||
| 144 | { | ||
| 145 | int ret = 0; | ||
| 146 | |||
| 147 | mutex_lock(&dev->master_mutex); | ||
| 148 | if (file_priv->is_master) | ||
| 149 | goto out_unlock; | ||
| 150 | |||
| 151 | if (file_priv->minor->master) { | ||
| 152 | ret = -EINVAL; | ||
| 153 | goto out_unlock; | ||
| 154 | } | ||
| 155 | |||
| 156 | if (!file_priv->master) { | ||
| 157 | ret = -EINVAL; | ||
| 158 | goto out_unlock; | ||
| 159 | } | ||
| 160 | |||
| 161 | if (!file_priv->allowed_master) { | ||
| 162 | ret = drm_new_set_master(dev, file_priv); | ||
| 163 | goto out_unlock; | ||
| 164 | } | ||
| 165 | |||
| 166 | file_priv->minor->master = drm_master_get(file_priv->master); | ||
| 167 | file_priv->is_master = 1; | ||
| 168 | if (dev->driver->master_set) { | ||
| 169 | ret = dev->driver->master_set(dev, file_priv, false); | ||
| 170 | if (unlikely(ret != 0)) { | ||
| 171 | file_priv->is_master = 0; | ||
| 172 | drm_master_put(&file_priv->minor->master); | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | out_unlock: | ||
| 177 | mutex_unlock(&dev->master_mutex); | ||
| 178 | return ret; | ||
| 179 | } | ||
| 180 | |||
| 181 | int drm_dropmaster_ioctl(struct drm_device *dev, void *data, | ||
| 182 | struct drm_file *file_priv) | ||
| 183 | { | ||
| 184 | int ret = -EINVAL; | ||
| 185 | |||
| 186 | mutex_lock(&dev->master_mutex); | ||
| 187 | if (!file_priv->is_master) | ||
| 188 | goto out_unlock; | ||
| 189 | |||
| 190 | if (!file_priv->minor->master) | ||
| 191 | goto out_unlock; | ||
| 192 | |||
| 193 | ret = 0; | ||
| 194 | if (dev->driver->master_drop) | ||
| 195 | dev->driver->master_drop(dev, file_priv, false); | ||
| 196 | drm_master_put(&file_priv->minor->master); | ||
| 197 | file_priv->is_master = 0; | ||
| 198 | |||
| 199 | out_unlock: | ||
| 200 | mutex_unlock(&dev->master_mutex); | ||
| 201 | return ret; | ||
| 202 | } | ||
| 203 | |||
| 204 | /* | 98 | /* |
| 205 | * DRM Minors | 99 | * DRM Minors |
| 206 | * A DRM device can provide several char-dev interfaces on the DRM-Major. Each | 100 | * A DRM device can provide several char-dev interfaces on the DRM-Major. Each |
| @@ -405,10 +299,9 @@ void drm_minor_release(struct drm_minor *minor) | |||
| 405 | * callbacks implemented by the driver. The driver then needs to initialize all | 299 | * callbacks implemented by the driver. The driver then needs to initialize all |
| 406 | * the various subsystems for the drm device like memory management, vblank | 300 | * the various subsystems for the drm device like memory management, vblank |
| 407 | * handling, modesetting support and intial output configuration plus obviously | 301 | * handling, modesetting support and intial output configuration plus obviously |
| 408 | * initialize all the corresponding hardware bits. An important part of this is | 302 | * initialize all the corresponding hardware bits. Finally when everything is up |
| 409 | * also calling drm_dev_set_unique() to set the userspace-visible unique name of | 303 | * and running and ready for userspace the device instance can be published |
| 410 | * this device instance. Finally when everything is up and running and ready for | 304 | * using drm_dev_register(). |
| 411 | * userspace the device instance can be published using drm_dev_register(). | ||
| 412 | * | 305 | * |
| 413 | * There is also deprecated support for initalizing device instances using | 306 | * There is also deprecated support for initalizing device instances using |
| 414 | * bus-specific helpers and the ->load() callback. But due to | 307 | * bus-specific helpers and the ->load() callback. But due to |
| @@ -430,6 +323,14 @@ void drm_minor_release(struct drm_minor *minor) | |||
| 430 | * dev_priv field of &drm_device. | 323 | * dev_priv field of &drm_device. |
| 431 | */ | 324 | */ |
| 432 | 325 | ||
| 326 | static int drm_dev_set_unique(struct drm_device *dev, const char *name) | ||
| 327 | { | ||
| 328 | kfree(dev->unique); | ||
| 329 | dev->unique = kstrdup(name, GFP_KERNEL); | ||
| 330 | |||
| 331 | return dev->unique ? 0 : -ENOMEM; | ||
| 332 | } | ||
| 333 | |||
| 433 | /** | 334 | /** |
| 434 | * drm_put_dev - Unregister and release a DRM device | 335 | * drm_put_dev - Unregister and release a DRM device |
| 435 | * @dev: DRM device | 336 | * @dev: DRM device |
| @@ -549,11 +450,12 @@ static void drm_fs_inode_free(struct inode *inode) | |||
| 549 | } | 450 | } |
| 550 | 451 | ||
| 551 | /** | 452 | /** |
| 552 | * drm_dev_alloc - Allocate new DRM device | 453 | * drm_dev_init - Initialise new DRM device |
| 553 | * @driver: DRM driver to allocate device for | 454 | * @dev: DRM device |
| 455 | * @driver: DRM driver | ||
| 554 | * @parent: Parent device object | 456 | * @parent: Parent device object |
| 555 | * | 457 | * |
| 556 | * Allocate and initialize a new DRM device. No device registration is done. | 458 | * Initialize a new DRM device. No device registration is done. |
| 557 | * Call drm_dev_register() to advertice the device to user space and register it | 459 | * Call drm_dev_register() to advertice the device to user space and register it |
| 558 | * with other core subsystems. This should be done last in the device | 460 | * with other core subsystems. This should be done last in the device |
| 559 | * initialization sequence to make sure userspace can't access an inconsistent | 461 | * initialization sequence to make sure userspace can't access an inconsistent |
| @@ -564,19 +466,18 @@ static void drm_fs_inode_free(struct inode *inode) | |||
| 564 | * | 466 | * |
| 565 | * Note that for purely virtual devices @parent can be NULL. | 467 | * Note that for purely virtual devices @parent can be NULL. |
| 566 | * | 468 | * |
| 469 | * Drivers that do not want to allocate their own device struct | ||
| 470 | * embedding struct &drm_device can call drm_dev_alloc() instead. | ||
| 471 | * | ||
| 567 | * RETURNS: | 472 | * RETURNS: |
| 568 | * Pointer to new DRM device, or NULL if out of memory. | 473 | * 0 on success, or error code on failure. |
| 569 | */ | 474 | */ |
| 570 | struct drm_device *drm_dev_alloc(struct drm_driver *driver, | 475 | int drm_dev_init(struct drm_device *dev, |
| 571 | struct device *parent) | 476 | struct drm_driver *driver, |
| 477 | struct device *parent) | ||
| 572 | { | 478 | { |
| 573 | struct drm_device *dev; | ||
| 574 | int ret; | 479 | int ret; |
| 575 | 480 | ||
| 576 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
| 577 | if (!dev) | ||
| 578 | return NULL; | ||
| 579 | |||
| 580 | kref_init(&dev->ref); | 481 | kref_init(&dev->ref); |
| 581 | dev->dev = parent; | 482 | dev->dev = parent; |
| 582 | dev->driver = driver; | 483 | dev->driver = driver; |
| @@ -617,7 +518,8 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, | |||
| 617 | if (ret) | 518 | if (ret) |
| 618 | goto err_minors; | 519 | goto err_minors; |
| 619 | 520 | ||
| 620 | if (drm_ht_create(&dev->map_hash, 12)) | 521 | ret = drm_ht_create(&dev->map_hash, 12); |
| 522 | if (ret) | ||
| 621 | goto err_minors; | 523 | goto err_minors; |
| 622 | 524 | ||
| 623 | drm_legacy_ctxbitmap_init(dev); | 525 | drm_legacy_ctxbitmap_init(dev); |
| @@ -630,13 +532,13 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, | |||
| 630 | } | 532 | } |
| 631 | } | 533 | } |
| 632 | 534 | ||
| 633 | if (parent) { | 535 | /* Use the parent device name as DRM device unique identifier, but fall |
| 634 | ret = drm_dev_set_unique(dev, dev_name(parent)); | 536 | * back to the driver name for virtual devices like vgem. */ |
| 635 | if (ret) | 537 | ret = drm_dev_set_unique(dev, parent ? dev_name(parent) : driver->name); |
| 636 | goto err_setunique; | 538 | if (ret) |
| 637 | } | 539 | goto err_setunique; |
| 638 | 540 | ||
| 639 | return dev; | 541 | return 0; |
| 640 | 542 | ||
| 641 | err_setunique: | 543 | err_setunique: |
| 642 | if (drm_core_check_feature(dev, DRIVER_GEM)) | 544 | if (drm_core_check_feature(dev, DRIVER_GEM)) |
| @@ -651,8 +553,49 @@ err_minors: | |||
| 651 | drm_fs_inode_free(dev->anon_inode); | 553 | drm_fs_inode_free(dev->anon_inode); |
| 652 | err_free: | 554 | err_free: |
| 653 | mutex_destroy(&dev->master_mutex); | 555 | mutex_destroy(&dev->master_mutex); |
| 654 | kfree(dev); | 556 | return ret; |
| 655 | return NULL; | 557 | } |
| 558 | EXPORT_SYMBOL(drm_dev_init); | ||
| 559 | |||
| 560 | /** | ||
| 561 | * drm_dev_alloc - Allocate new DRM device | ||
| 562 | * @driver: DRM driver to allocate device for | ||
| 563 | * @parent: Parent device object | ||
| 564 | * | ||
| 565 | * Allocate and initialize a new DRM device. No device registration is done. | ||
| 566 | * Call drm_dev_register() to advertice the device to user space and register it | ||
| 567 | * with other core subsystems. This should be done last in the device | ||
| 568 | * initialization sequence to make sure userspace can't access an inconsistent | ||
| 569 | * state. | ||
| 570 | * | ||
| 571 | * The initial ref-count of the object is 1. Use drm_dev_ref() and | ||
| 572 | * drm_dev_unref() to take and drop further ref-counts. | ||
| 573 | * | ||
| 574 | * Note that for purely virtual devices @parent can be NULL. | ||
| 575 | * | ||
| 576 | * Drivers that wish to subclass or embed struct &drm_device into their | ||
| 577 | * own struct should look at using drm_dev_init() instead. | ||
| 578 | * | ||
| 579 | * RETURNS: | ||
| 580 | * Pointer to new DRM device, or NULL if out of memory. | ||
| 581 | */ | ||
| 582 | struct drm_device *drm_dev_alloc(struct drm_driver *driver, | ||
| 583 | struct device *parent) | ||
| 584 | { | ||
| 585 | struct drm_device *dev; | ||
| 586 | int ret; | ||
| 587 | |||
| 588 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
| 589 | if (!dev) | ||
| 590 | return NULL; | ||
| 591 | |||
| 592 | ret = drm_dev_init(dev, driver, parent); | ||
| 593 | if (ret) { | ||
| 594 | kfree(dev); | ||
| 595 | return NULL; | ||
| 596 | } | ||
| 597 | |||
| 598 | return dev; | ||
| 656 | } | 599 | } |
| 657 | EXPORT_SYMBOL(drm_dev_alloc); | 600 | EXPORT_SYMBOL(drm_dev_alloc); |
| 658 | 601 | ||
| @@ -716,11 +659,7 @@ EXPORT_SYMBOL(drm_dev_unref); | |||
| 716 | * | 659 | * |
| 717 | * Register the DRM device @dev with the system, advertise device to user-space | 660 | * Register the DRM device @dev with the system, advertise device to user-space |
| 718 | * and start normal device operation. @dev must be allocated via drm_dev_alloc() | 661 | * and start normal device operation. @dev must be allocated via drm_dev_alloc() |
| 719 | * previously. Right after drm_dev_register() the driver should call | 662 | * previously. |
| 720 | * drm_connector_register_all() to register all connectors in sysfs. This is | ||
| 721 | * a separate call for backward compatibility with drivers still using | ||
| 722 | * the deprecated ->load() callback, where connectors are registered from within | ||
| 723 | * the ->load() callback. | ||
| 724 | * | 663 | * |
| 725 | * Never call this twice on any device! | 664 | * Never call this twice on any device! |
| 726 | * | 665 | * |
| @@ -757,6 +696,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) | |||
| 757 | goto err_minors; | 696 | goto err_minors; |
| 758 | } | 697 | } |
| 759 | 698 | ||
| 699 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
| 700 | drm_modeset_register_all(dev); | ||
| 701 | |||
| 760 | ret = 0; | 702 | ret = 0; |
| 761 | goto out_unlock; | 703 | goto out_unlock; |
| 762 | 704 | ||
| @@ -787,6 +729,9 @@ void drm_dev_unregister(struct drm_device *dev) | |||
| 787 | 729 | ||
| 788 | drm_lastclose(dev); | 730 | drm_lastclose(dev); |
| 789 | 731 | ||
| 732 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
| 733 | drm_modeset_unregister_all(dev); | ||
| 734 | |||
| 790 | if (dev->driver->unload) | 735 | if (dev->driver->unload) |
| 791 | dev->driver->unload(dev); | 736 | dev->driver->unload(dev); |
| 792 | 737 | ||
| @@ -804,26 +749,6 @@ void drm_dev_unregister(struct drm_device *dev) | |||
| 804 | } | 749 | } |
| 805 | EXPORT_SYMBOL(drm_dev_unregister); | 750 | EXPORT_SYMBOL(drm_dev_unregister); |
| 806 | 751 | ||
| 807 | /** | ||
| 808 | * drm_dev_set_unique - Set the unique name of a DRM device | ||
| 809 | * @dev: device of which to set the unique name | ||
| 810 | * @name: unique name | ||
| 811 | * | ||
| 812 | * Sets the unique name of a DRM device using the specified string. Drivers | ||
| 813 | * can use this at driver probe time if the unique name of the devices they | ||
| 814 | * drive is static. | ||
| 815 | * | ||
| 816 | * Return: 0 on success or a negative error code on failure. | ||
| 817 | */ | ||
| 818 | int drm_dev_set_unique(struct drm_device *dev, const char *name) | ||
| 819 | { | ||
| 820 | kfree(dev->unique); | ||
| 821 | dev->unique = kstrdup(name, GFP_KERNEL); | ||
| 822 | |||
| 823 | return dev->unique ? 0 : -ENOMEM; | ||
| 824 | } | ||
| 825 | EXPORT_SYMBOL(drm_dev_set_unique); | ||
| 826 | |||
| 827 | /* | 752 | /* |
| 828 | * DRM Core | 753 | * DRM Core |
| 829 | * The DRM core module initializes all global DRM objects and makes them | 754 | * The DRM core module initializes all global DRM objects and makes them |
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 0bac5246e5a7..ce54e985d91b 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
| @@ -464,7 +464,7 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) | |||
| 464 | 464 | ||
| 465 | /* Sometimes user space wants everything disabled, so don't steal the | 465 | /* Sometimes user space wants everything disabled, so don't steal the |
| 466 | * display if there's a master. */ | 466 | * display if there's a master. */ |
| 467 | if (dev->primary->master) | 467 | if (lockless_dereference(dev->master)) |
| 468 | return false; | 468 | return false; |
| 469 | 469 | ||
| 470 | drm_for_each_crtc(crtc, dev) { | 470 | drm_for_each_crtc(crtc, dev) { |
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index a27bc7cda975..323c238fcac7 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include <linux/module.h> | 40 | #include <linux/module.h> |
| 41 | #include "drm_legacy.h" | 41 | #include "drm_legacy.h" |
| 42 | #include "drm_internal.h" | 42 | #include "drm_internal.h" |
| 43 | #include "drm_crtc_internal.h" | ||
| 43 | 44 | ||
| 44 | /* from BKL pushdown */ | 45 | /* from BKL pushdown */ |
| 45 | DEFINE_MUTEX(drm_global_mutex); | 46 | DEFINE_MUTEX(drm_global_mutex); |
| @@ -168,60 +169,6 @@ static int drm_cpu_valid(void) | |||
| 168 | } | 169 | } |
| 169 | 170 | ||
| 170 | /* | 171 | /* |
| 171 | * drm_new_set_master - Allocate a new master object and become master for the | ||
| 172 | * associated master realm. | ||
| 173 | * | ||
| 174 | * @dev: The associated device. | ||
| 175 | * @fpriv: File private identifying the client. | ||
| 176 | * | ||
| 177 | * This function must be called with dev::struct_mutex held. | ||
| 178 | * Returns negative error code on failure. Zero on success. | ||
| 179 | */ | ||
| 180 | int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv) | ||
| 181 | { | ||
| 182 | struct drm_master *old_master; | ||
| 183 | int ret; | ||
| 184 | |||
| 185 | lockdep_assert_held_once(&dev->master_mutex); | ||
| 186 | |||
| 187 | /* create a new master */ | ||
| 188 | fpriv->minor->master = drm_master_create(fpriv->minor); | ||
| 189 | if (!fpriv->minor->master) | ||
| 190 | return -ENOMEM; | ||
| 191 | |||
| 192 | /* take another reference for the copy in the local file priv */ | ||
| 193 | old_master = fpriv->master; | ||
| 194 | fpriv->master = drm_master_get(fpriv->minor->master); | ||
| 195 | |||
| 196 | if (dev->driver->master_create) { | ||
| 197 | ret = dev->driver->master_create(dev, fpriv->master); | ||
| 198 | if (ret) | ||
| 199 | goto out_err; | ||
| 200 | } | ||
| 201 | if (dev->driver->master_set) { | ||
| 202 | ret = dev->driver->master_set(dev, fpriv, true); | ||
| 203 | if (ret) | ||
| 204 | goto out_err; | ||
| 205 | } | ||
| 206 | |||
| 207 | fpriv->is_master = 1; | ||
| 208 | fpriv->allowed_master = 1; | ||
| 209 | fpriv->authenticated = 1; | ||
| 210 | if (old_master) | ||
| 211 | drm_master_put(&old_master); | ||
| 212 | |||
| 213 | return 0; | ||
| 214 | |||
| 215 | out_err: | ||
| 216 | /* drop both references and restore old master on failure */ | ||
| 217 | drm_master_put(&fpriv->minor->master); | ||
| 218 | drm_master_put(&fpriv->master); | ||
| 219 | fpriv->master = old_master; | ||
| 220 | |||
| 221 | return ret; | ||
| 222 | } | ||
| 223 | |||
| 224 | /* | ||
| 225 | * Called whenever a process opens /dev/drm. | 172 | * Called whenever a process opens /dev/drm. |
| 226 | * | 173 | * |
| 227 | * \param filp file pointer. | 174 | * \param filp file pointer. |
| @@ -283,19 +230,11 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) | |||
| 283 | goto out_prime_destroy; | 230 | goto out_prime_destroy; |
| 284 | } | 231 | } |
| 285 | 232 | ||
| 286 | /* if there is no current master make this fd it, but do not create | 233 | if (drm_is_primary_client(priv)) { |
| 287 | * any master object for render clients */ | 234 | ret = drm_master_open(priv); |
| 288 | mutex_lock(&dev->master_mutex); | ||
| 289 | if (drm_is_primary_client(priv) && !priv->minor->master) { | ||
| 290 | /* create a new master */ | ||
| 291 | ret = drm_new_set_master(dev, priv); | ||
| 292 | if (ret) | 235 | if (ret) |
| 293 | goto out_close; | 236 | goto out_close; |
| 294 | } else if (drm_is_primary_client(priv)) { | ||
| 295 | /* get a reference to the master */ | ||
| 296 | priv->master = drm_master_get(priv->minor->master); | ||
| 297 | } | 237 | } |
| 298 | mutex_unlock(&dev->master_mutex); | ||
| 299 | 238 | ||
| 300 | mutex_lock(&dev->filelist_mutex); | 239 | mutex_lock(&dev->filelist_mutex); |
| 301 | list_add(&priv->lhead, &dev->filelist); | 240 | list_add(&priv->lhead, &dev->filelist); |
| @@ -324,7 +263,6 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) | |||
| 324 | return 0; | 263 | return 0; |
| 325 | 264 | ||
| 326 | out_close: | 265 | out_close: |
| 327 | mutex_unlock(&dev->master_mutex); | ||
| 328 | if (dev->driver->postclose) | 266 | if (dev->driver->postclose) |
| 329 | dev->driver->postclose(dev, priv); | 267 | dev->driver->postclose(dev, priv); |
| 330 | out_prime_destroy: | 268 | out_prime_destroy: |
| @@ -338,18 +276,6 @@ out_prime_destroy: | |||
| 338 | return ret; | 276 | return ret; |
| 339 | } | 277 | } |
| 340 | 278 | ||
| 341 | static void drm_master_release(struct drm_device *dev, struct file *filp) | ||
| 342 | { | ||
| 343 | struct drm_file *file_priv = filp->private_data; | ||
| 344 | |||
| 345 | if (drm_legacy_i_have_hw_lock(dev, file_priv)) { | ||
| 346 | DRM_DEBUG("File %p released, freeing lock for context %d\n", | ||
| 347 | filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); | ||
| 348 | drm_legacy_lock_free(&file_priv->master->lock, | ||
| 349 | _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | static void drm_events_release(struct drm_file *file_priv) | 279 | static void drm_events_release(struct drm_file *file_priv) |
| 354 | { | 280 | { |
| 355 | struct drm_device *dev = file_priv->minor->dev; | 281 | struct drm_device *dev = file_priv->minor->dev; |
| @@ -451,11 +377,6 @@ int drm_release(struct inode *inode, struct file *filp) | |||
| 451 | list_del(&file_priv->lhead); | 377 | list_del(&file_priv->lhead); |
| 452 | mutex_unlock(&dev->filelist_mutex); | 378 | mutex_unlock(&dev->filelist_mutex); |
| 453 | 379 | ||
| 454 | mutex_lock(&dev->struct_mutex); | ||
| 455 | if (file_priv->magic) | ||
| 456 | idr_remove(&file_priv->master->magic_map, file_priv->magic); | ||
| 457 | mutex_unlock(&dev->struct_mutex); | ||
| 458 | |||
| 459 | if (dev->driver->preclose) | 380 | if (dev->driver->preclose) |
| 460 | dev->driver->preclose(dev, file_priv); | 381 | dev->driver->preclose(dev, file_priv); |
| 461 | 382 | ||
| @@ -468,9 +389,8 @@ int drm_release(struct inode *inode, struct file *filp) | |||
| 468 | (long)old_encode_dev(file_priv->minor->kdev->devt), | 389 | (long)old_encode_dev(file_priv->minor->kdev->devt), |
| 469 | dev->open_count); | 390 | dev->open_count); |
| 470 | 391 | ||
| 471 | /* if the master has gone away we can't do anything with the lock */ | 392 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| 472 | if (file_priv->minor->master) | 393 | drm_legacy_lock_release(dev, filp); |
| 473 | drm_master_release(dev, filp); | ||
| 474 | 394 | ||
| 475 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) | 395 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) |
| 476 | drm_legacy_reclaim_buffers(dev, file_priv); | 396 | drm_legacy_reclaim_buffers(dev, file_priv); |
| @@ -487,43 +407,12 @@ int drm_release(struct inode *inode, struct file *filp) | |||
| 487 | 407 | ||
| 488 | drm_legacy_ctxbitmap_flush(dev, file_priv); | 408 | drm_legacy_ctxbitmap_flush(dev, file_priv); |
| 489 | 409 | ||
| 490 | mutex_lock(&dev->master_mutex); | 410 | if (drm_is_primary_client(file_priv)) |
| 491 | 411 | drm_master_release(file_priv); | |
| 492 | if (file_priv->is_master) { | ||
| 493 | struct drm_master *master = file_priv->master; | ||
| 494 | |||
| 495 | /* | ||
| 496 | * Since the master is disappearing, so is the | ||
| 497 | * possibility to lock. | ||
| 498 | */ | ||
| 499 | mutex_lock(&dev->struct_mutex); | ||
| 500 | if (master->lock.hw_lock) { | ||
| 501 | if (dev->sigdata.lock == master->lock.hw_lock) | ||
| 502 | dev->sigdata.lock = NULL; | ||
| 503 | master->lock.hw_lock = NULL; | ||
| 504 | master->lock.file_priv = NULL; | ||
| 505 | wake_up_interruptible_all(&master->lock.lock_queue); | ||
| 506 | } | ||
| 507 | mutex_unlock(&dev->struct_mutex); | ||
| 508 | |||
| 509 | if (file_priv->minor->master == file_priv->master) { | ||
| 510 | /* drop the reference held my the minor */ | ||
| 511 | if (dev->driver->master_drop) | ||
| 512 | dev->driver->master_drop(dev, file_priv, true); | ||
| 513 | drm_master_put(&file_priv->minor->master); | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | /* drop the master reference held by the file priv */ | ||
| 518 | if (file_priv->master) | ||
| 519 | drm_master_put(&file_priv->master); | ||
| 520 | file_priv->is_master = 0; | ||
| 521 | mutex_unlock(&dev->master_mutex); | ||
| 522 | 412 | ||
| 523 | if (dev->driver->postclose) | 413 | if (dev->driver->postclose) |
| 524 | dev->driver->postclose(dev, file_priv); | 414 | dev->driver->postclose(dev, file_priv); |
| 525 | 415 | ||
| 526 | |||
| 527 | if (drm_core_check_feature(dev, DRIVER_PRIME)) | 416 | if (drm_core_check_feature(dev, DRIVER_PRIME)) |
| 528 | drm_prime_destroy_file_private(&file_priv->prime); | 417 | drm_prime_destroy_file_private(&file_priv->prime); |
| 529 | 418 | ||
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index 5d469b2f26f4..9ae353f4dd06 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c | |||
| @@ -50,106 +50,24 @@ int drm_name_info(struct seq_file *m, void *data) | |||
| 50 | struct drm_info_node *node = (struct drm_info_node *) m->private; | 50 | struct drm_info_node *node = (struct drm_info_node *) m->private; |
| 51 | struct drm_minor *minor = node->minor; | 51 | struct drm_minor *minor = node->minor; |
| 52 | struct drm_device *dev = minor->dev; | 52 | struct drm_device *dev = minor->dev; |
| 53 | struct drm_master *master = minor->master; | 53 | struct drm_master *master; |
| 54 | if (!master) | ||
| 55 | return 0; | ||
| 56 | |||
| 57 | if (master->unique) { | ||
| 58 | seq_printf(m, "%s %s %s\n", | ||
| 59 | dev->driver->name, | ||
| 60 | dev_name(dev->dev), master->unique); | ||
| 61 | } else { | ||
| 62 | seq_printf(m, "%s %s\n", | ||
| 63 | dev->driver->name, dev_name(dev->dev)); | ||
| 64 | } | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Called when "/proc/dri/.../vm" is read. | ||
| 70 | * | ||
| 71 | * Prints information about all mappings in drm_device::maplist. | ||
| 72 | */ | ||
| 73 | int drm_vm_info(struct seq_file *m, void *data) | ||
| 74 | { | ||
| 75 | struct drm_info_node *node = (struct drm_info_node *) m->private; | ||
| 76 | struct drm_device *dev = node->minor->dev; | ||
| 77 | struct drm_local_map *map; | ||
| 78 | struct drm_map_list *r_list; | ||
| 79 | |||
| 80 | /* Hardcoded from _DRM_FRAME_BUFFER, | ||
| 81 | _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and | ||
| 82 | _DRM_SCATTER_GATHER and _DRM_CONSISTENT */ | ||
| 83 | const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" }; | ||
| 84 | const char *type; | ||
| 85 | int i; | ||
| 86 | |||
| 87 | mutex_lock(&dev->struct_mutex); | ||
| 88 | seq_printf(m, "slot offset size type flags address mtrr\n\n"); | ||
| 89 | i = 0; | ||
| 90 | list_for_each_entry(r_list, &dev->maplist, head) { | ||
| 91 | map = r_list->map; | ||
| 92 | if (!map) | ||
| 93 | continue; | ||
| 94 | if (map->type < 0 || map->type > 5) | ||
| 95 | type = "??"; | ||
| 96 | else | ||
| 97 | type = types[map->type]; | ||
| 98 | |||
| 99 | seq_printf(m, "%4d 0x%016llx 0x%08lx %4.4s 0x%02x 0x%08lx ", | ||
| 100 | i, | ||
| 101 | (unsigned long long)map->offset, | ||
| 102 | map->size, type, map->flags, | ||
| 103 | (unsigned long) r_list->user_token); | ||
| 104 | if (map->mtrr < 0) | ||
| 105 | seq_printf(m, "none\n"); | ||
| 106 | else | ||
| 107 | seq_printf(m, "%4d\n", map->mtrr); | ||
| 108 | i++; | ||
| 109 | } | ||
| 110 | mutex_unlock(&dev->struct_mutex); | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | 54 | ||
| 114 | /** | 55 | mutex_lock(&dev->master_mutex); |
| 115 | * Called when "/proc/dri/.../bufs" is read. | 56 | master = dev->master; |
| 116 | */ | 57 | if (!master) |
| 117 | int drm_bufs_info(struct seq_file *m, void *data) | 58 | goto out_unlock; |
| 118 | { | 59 | |
| 119 | struct drm_info_node *node = (struct drm_info_node *) m->private; | 60 | seq_printf(m, "%s", dev->driver->name); |
| 120 | struct drm_device *dev = node->minor->dev; | 61 | if (dev->dev) |
| 121 | struct drm_device_dma *dma; | 62 | seq_printf(m, " dev=%s", dev_name(dev->dev)); |
| 122 | int i, seg_pages; | 63 | if (master && master->unique) |
| 123 | 64 | seq_printf(m, " master=%s", master->unique); | |
| 124 | mutex_lock(&dev->struct_mutex); | 65 | if (dev->unique) |
| 125 | dma = dev->dma; | 66 | seq_printf(m, " unique=%s", dev->unique); |
| 126 | if (!dma) { | ||
| 127 | mutex_unlock(&dev->struct_mutex); | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | seq_printf(m, " o size count free segs pages kB\n\n"); | ||
| 132 | for (i = 0; i <= DRM_MAX_ORDER; i++) { | ||
| 133 | if (dma->bufs[i].buf_count) { | ||
| 134 | seg_pages = dma->bufs[i].seg_count * (1 << dma->bufs[i].page_order); | ||
| 135 | seq_printf(m, "%2d %8d %5d %5d %5d %5d %5ld\n", | ||
| 136 | i, | ||
| 137 | dma->bufs[i].buf_size, | ||
| 138 | dma->bufs[i].buf_count, | ||
| 139 | 0, | ||
| 140 | dma->bufs[i].seg_count, | ||
| 141 | seg_pages, | ||
| 142 | seg_pages * PAGE_SIZE / 1024); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | seq_printf(m, "\n"); | ||
| 146 | for (i = 0; i < dma->buf_count; i++) { | ||
| 147 | if (i && !(i % 32)) | ||
| 148 | seq_printf(m, "\n"); | ||
| 149 | seq_printf(m, " %d", dma->buflist[i]->list); | ||
| 150 | } | ||
| 151 | seq_printf(m, "\n"); | 67 | seq_printf(m, "\n"); |
| 152 | mutex_unlock(&dev->struct_mutex); | 68 | out_unlock: |
| 69 | mutex_unlock(&dev->master_mutex); | ||
| 70 | |||
| 153 | return 0; | 71 | return 0; |
| 154 | } | 72 | } |
| 155 | 73 | ||
| @@ -184,7 +102,7 @@ int drm_clients_info(struct seq_file *m, void *data) | |||
| 184 | task ? task->comm : "<unknown>", | 102 | task ? task->comm : "<unknown>", |
| 185 | pid_vnr(priv->pid), | 103 | pid_vnr(priv->pid), |
| 186 | priv->minor->index, | 104 | priv->minor->index, |
| 187 | priv->is_master ? 'y' : 'n', | 105 | drm_is_current_master(priv) ? 'y' : 'n', |
| 188 | priv->authenticated ? 'y' : 'n', | 106 | priv->authenticated ? 'y' : 'n', |
| 189 | from_kuid_munged(seq_user_ns(m), priv->uid), | 107 | from_kuid_munged(seq_user_ns(m), priv->uid), |
| 190 | priv->magic); | 108 | priv->magic); |
| @@ -194,7 +112,6 @@ int drm_clients_info(struct seq_file *m, void *data) | |||
| 194 | return 0; | 112 | return 0; |
| 195 | } | 113 | } |
| 196 | 114 | ||
| 197 | |||
| 198 | static int drm_gem_one_name_info(int id, void *ptr, void *data) | 115 | static int drm_gem_one_name_info(int id, void *ptr, void *data) |
| 199 | { | 116 | { |
| 200 | struct drm_gem_object *obj = ptr; | 117 | struct drm_gem_object *obj = ptr; |
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 902cf6a15212..b86dc9b921a5 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h | |||
| @@ -29,15 +29,9 @@ extern struct mutex drm_global_mutex; | |||
| 29 | void drm_lastclose(struct drm_device *dev); | 29 | void drm_lastclose(struct drm_device *dev); |
| 30 | 30 | ||
| 31 | /* drm_pci.c */ | 31 | /* drm_pci.c */ |
| 32 | int drm_pci_set_unique(struct drm_device *dev, | ||
| 33 | struct drm_master *master, | ||
| 34 | struct drm_unique *u); | ||
| 35 | int drm_irq_by_busid(struct drm_device *dev, void *data, | 32 | int drm_irq_by_busid(struct drm_device *dev, void *data, |
| 36 | struct drm_file *file_priv); | 33 | struct drm_file *file_priv); |
| 37 | 34 | ||
| 38 | /* drm_vm.c */ | ||
| 39 | int drm_vma_info(struct seq_file *m, void *data); | ||
| 40 | |||
| 41 | /* drm_prime.c */ | 35 | /* drm_prime.c */ |
| 42 | int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data, | 36 | int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data, |
| 43 | struct drm_file *file_priv); | 37 | struct drm_file *file_priv); |
| @@ -51,8 +45,6 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr | |||
| 51 | 45 | ||
| 52 | /* drm_info.c */ | 46 | /* drm_info.c */ |
| 53 | int drm_name_info(struct seq_file *m, void *data); | 47 | int drm_name_info(struct seq_file *m, void *data); |
| 54 | int drm_vm_info(struct seq_file *m, void *data); | ||
| 55 | int drm_bufs_info(struct seq_file *m, void *data); | ||
| 56 | int drm_clients_info(struct seq_file *m, void* data); | 48 | int drm_clients_info(struct seq_file *m, void* data); |
| 57 | int drm_gem_name_info(struct seq_file *m, void *data); | 49 | int drm_gem_name_info(struct seq_file *m, void *data); |
| 58 | 50 | ||
| @@ -67,6 +59,12 @@ int drm_getmagic(struct drm_device *dev, void *data, | |||
| 67 | struct drm_file *file_priv); | 59 | struct drm_file *file_priv); |
| 68 | int drm_authmagic(struct drm_device *dev, void *data, | 60 | int drm_authmagic(struct drm_device *dev, void *data, |
| 69 | struct drm_file *file_priv); | 61 | struct drm_file *file_priv); |
| 62 | int drm_setmaster_ioctl(struct drm_device *dev, void *data, | ||
| 63 | struct drm_file *file_priv); | ||
| 64 | int drm_dropmaster_ioctl(struct drm_device *dev, void *data, | ||
| 65 | struct drm_file *file_priv); | ||
| 66 | int drm_master_open(struct drm_file *file_priv); | ||
| 67 | void drm_master_release(struct drm_file *file_priv); | ||
| 70 | 68 | ||
| 71 | /* drm_sysfs.c */ | 69 | /* drm_sysfs.c */ |
| 72 | extern struct class *drm_class; | 70 | extern struct class *drm_class; |
| @@ -92,13 +90,6 @@ int drm_gem_open_ioctl(struct drm_device *dev, void *data, | |||
| 92 | void drm_gem_open(struct drm_device *dev, struct drm_file *file_private); | 90 | void drm_gem_open(struct drm_device *dev, struct drm_file *file_private); |
| 93 | void drm_gem_release(struct drm_device *dev, struct drm_file *file_private); | 91 | void drm_gem_release(struct drm_device *dev, struct drm_file *file_private); |
| 94 | 92 | ||
| 95 | /* drm_drv.c */ | ||
| 96 | int drm_setmaster_ioctl(struct drm_device *dev, void *data, | ||
| 97 | struct drm_file *file_priv); | ||
| 98 | int drm_dropmaster_ioctl(struct drm_device *dev, void *data, | ||
| 99 | struct drm_file *file_priv); | ||
| 100 | struct drm_master *drm_master_create(struct drm_minor *minor); | ||
| 101 | |||
| 102 | /* drm_debugfs.c */ | 93 | /* drm_debugfs.c */ |
| 103 | #if defined(CONFIG_DEBUG_FS) | 94 | #if defined(CONFIG_DEBUG_FS) |
| 104 | int drm_debugfs_init(struct drm_minor *minor, int minor_id, | 95 | int drm_debugfs_init(struct drm_minor *minor, int minor_id, |
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index b7a39771c152..1f84ff5f1bf8 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | 30 | ||
| 31 | #include <drm/drmP.h> | 31 | #include <drm/drmP.h> |
| 32 | #include <drm/drm_core.h> | 32 | #include <drm/drm_core.h> |
| 33 | #include <drm/drm_auth.h> | ||
| 33 | #include "drm_legacy.h" | 34 | #include "drm_legacy.h" |
| 34 | #include "drm_internal.h" | 35 | #include "drm_internal.h" |
| 35 | #include "drm_crtc_internal.h" | 36 | #include "drm_crtc_internal.h" |
| @@ -37,6 +38,64 @@ | |||
| 37 | #include <linux/pci.h> | 38 | #include <linux/pci.h> |
| 38 | #include <linux/export.h> | 39 | #include <linux/export.h> |
| 39 | 40 | ||
| 41 | /** | ||
| 42 | * DOC: getunique and setversion story | ||
| 43 | * | ||
| 44 | * BEWARE THE DRAGONS! MIND THE TRAPDOORS! | ||
| 45 | * | ||
| 46 | * In an attempt to warn anyone else who's trying to figure out what's going | ||
| 47 | * on here, I'll try to summarize the story. First things first, let's clear up | ||
| 48 | * the names, because the kernel internals, libdrm and the ioctls are all named | ||
| 49 | * differently: | ||
| 50 | * | ||
| 51 | * - GET_UNIQUE ioctl, implemented by drm_getunique is wrapped up in libdrm | ||
| 52 | * through the drmGetBusid function. | ||
| 53 | * - The libdrm drmSetBusid function is backed by the SET_UNIQUE ioctl. All | ||
| 54 | * that code is nerved in the kernel with drm_invalid_op(). | ||
| 55 | * - The internal set_busid kernel functions and driver callbacks are | ||
| 56 | * exclusively use by the SET_VERSION ioctl, because only drm 1.0 (which is | ||
| 57 | * nerved) allowed userspace to set the busid through the above ioctl. | ||
| 58 | * - Other ioctls and functions involved are named consistently. | ||
| 59 | * | ||
| 60 | * For anyone wondering what's the difference between drm 1.1 and 1.4: Correctly | ||
| 61 | * handling pci domains in the busid on ppc. Doing this correctly was only | ||
| 62 | * implemented in libdrm in 2010, hence can't be nerved yet. No one knows what's | ||
| 63 | * special with drm 1.2 and 1.3. | ||
| 64 | * | ||
| 65 | * Now the actual horror story of how device lookup in drm works. At large, | ||
| 66 | * there's 2 different ways, either by busid, or by device driver name. | ||
| 67 | * | ||
| 68 | * Opening by busid is fairly simple: | ||
| 69 | * | ||
| 70 | * 1. First call SET_VERSION to make sure pci domains are handled properly. As a | ||
| 71 | * side-effect this fills out the unique name in the master structure. | ||
| 72 | * 2. Call GET_UNIQUE to read out the unique name from the master structure, | ||
| 73 | * which matches the busid thanks to step 1. If it doesn't, proceed to try | ||
| 74 | * the next device node. | ||
| 75 | * | ||
| 76 | * Opening by name is slightly different: | ||
| 77 | * | ||
| 78 | * 1. Directly call VERSION to get the version and to match against the driver | ||
| 79 | * name returned by that ioctl. Note that SET_VERSION is not called, which | ||
| 80 | * means the the unique name for the master node just opening is _not_ filled | ||
| 81 | * out. This despite that with current drm device nodes are always bound to | ||
| 82 | * one device, and can't be runtime assigned like with drm 1.0. | ||
| 83 | * 2. Match driver name. If it mismatches, proceed to the next device node. | ||
| 84 | * 3. Call GET_UNIQUE, and check whether the unique name has length zero (by | ||
| 85 | * checking that the first byte in the string is 0). If that's not the case | ||
| 86 | * libdrm skips and proceeds to the next device node. Probably this is just | ||
| 87 | * copypasta from drm 1.0 times where a set unique name meant that the driver | ||
| 88 | * was in use already, but that's just conjecture. | ||
| 89 | * | ||
| 90 | * Long story short: To keep the open by name logic working, GET_UNIQUE must | ||
| 91 | * _not_ return a unique string when SET_VERSION hasn't been called yet, | ||
| 92 | * otherwise libdrm breaks. Even when that unique string can't ever change, and | ||
| 93 | * is totally irrelevant for actually opening the device because runtime | ||
| 94 | * assignable device instances were only support in drm 1.0, which is long dead. | ||
| 95 | * But the libdrm code in drmOpenByName somehow survived, hence this can't be | ||
| 96 | * broken. | ||
| 97 | */ | ||
| 98 | |||
| 40 | static int drm_version(struct drm_device *dev, void *data, | 99 | static int drm_version(struct drm_device *dev, void *data, |
| 41 | struct drm_file *file_priv); | 100 | struct drm_file *file_priv); |
| 42 | 101 | ||
| @@ -75,51 +134,6 @@ drm_unset_busid(struct drm_device *dev, | |||
| 75 | master->unique_len = 0; | 134 | master->unique_len = 0; |
| 76 | } | 135 | } |
| 77 | 136 | ||
| 78 | /* | ||
| 79 | * Set the bus id. | ||
| 80 | * | ||
| 81 | * \param inode device inode. | ||
| 82 | * \param file_priv DRM file private. | ||
| 83 | * \param cmd command. | ||
| 84 | * \param arg user argument, pointing to a drm_unique structure. | ||
| 85 | * \return zero on success or a negative number on failure. | ||
| 86 | * | ||
| 87 | * Copies the bus id from userspace into drm_device::unique, and verifies that | ||
| 88 | * it matches the device this DRM is attached to (EINVAL otherwise). Deprecated | ||
| 89 | * in interface version 1.1 and will return EBUSY when setversion has requested | ||
| 90 | * version 1.1 or greater. Also note that KMS is all version 1.1 and later and | ||
| 91 | * UMS was only ever supported on pci devices. | ||
| 92 | */ | ||
| 93 | static int drm_setunique(struct drm_device *dev, void *data, | ||
| 94 | struct drm_file *file_priv) | ||
| 95 | { | ||
| 96 | struct drm_unique *u = data; | ||
| 97 | struct drm_master *master = file_priv->master; | ||
| 98 | int ret; | ||
| 99 | |||
| 100 | if (master->unique_len || master->unique) | ||
| 101 | return -EBUSY; | ||
| 102 | |||
| 103 | if (!u->unique_len || u->unique_len > 1024) | ||
| 104 | return -EINVAL; | ||
| 105 | |||
| 106 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
| 107 | return 0; | ||
| 108 | |||
| 109 | if (WARN_ON(!dev->pdev)) | ||
| 110 | return -EINVAL; | ||
| 111 | |||
| 112 | ret = drm_pci_set_unique(dev, master, u); | ||
| 113 | if (ret) | ||
| 114 | goto err; | ||
| 115 | |||
| 116 | return 0; | ||
| 117 | |||
| 118 | err: | ||
| 119 | drm_unset_busid(dev, master); | ||
| 120 | return ret; | ||
| 121 | } | ||
| 122 | |||
| 123 | static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) | 137 | static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) |
| 124 | { | 138 | { |
| 125 | struct drm_master *master = file_priv->master; | 139 | struct drm_master *master = file_priv->master; |
| @@ -135,12 +149,7 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) | |||
| 135 | return ret; | 149 | return ret; |
| 136 | } | 150 | } |
| 137 | } else { | 151 | } else { |
| 138 | if (WARN(dev->unique == NULL, | 152 | WARN_ON(!dev->unique); |
| 139 | "No drm_driver.set_busid() implementation provided by " | ||
| 140 | "%ps. Use drm_dev_set_unique() to set the unique " | ||
| 141 | "name explicitly.", dev->driver)) | ||
| 142 | return -EINVAL; | ||
| 143 | |||
| 144 | master->unique = kstrdup(dev->unique, GFP_KERNEL); | 153 | master->unique = kstrdup(dev->unique, GFP_KERNEL); |
| 145 | if (master->unique) | 154 | if (master->unique) |
| 146 | master->unique_len = strlen(dev->unique); | 155 | master->unique_len = strlen(dev->unique); |
| @@ -473,7 +482,8 @@ int drm_ioctl_permit(u32 flags, struct drm_file *file_priv) | |||
| 473 | return -EACCES; | 482 | return -EACCES; |
| 474 | 483 | ||
| 475 | /* MASTER is only for master or control clients */ | 484 | /* MASTER is only for master or control clients */ |
| 476 | if (unlikely((flags & DRM_MASTER) && !file_priv->is_master && | 485 | if (unlikely((flags & DRM_MASTER) && |
| 486 | !drm_is_current_master(file_priv) && | ||
| 477 | !drm_is_control_client(file_priv))) | 487 | !drm_is_control_client(file_priv))) |
| 478 | return -EACCES; | 488 | return -EACCES; |
| 479 | 489 | ||
| @@ -504,7 +514,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { | |||
| 504 | DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, | 514 | DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, |
| 505 | DRM_UNLOCKED|DRM_RENDER_ALLOW|DRM_CONTROL_ALLOW), | 515 | DRM_UNLOCKED|DRM_RENDER_ALLOW|DRM_CONTROL_ALLOW), |
| 506 | DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), | 516 | DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), |
| 507 | DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), | 517 | DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, DRM_UNLOCKED), |
| 508 | DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY), | 518 | DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY), |
| 509 | DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_legacy_getmap_ioctl, DRM_UNLOCKED), | 519 | DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_legacy_getmap_ioctl, DRM_UNLOCKED), |
| 510 | DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, DRM_UNLOCKED), | 520 | DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, DRM_UNLOCKED), |
| @@ -513,10 +523,10 @@ static const struct drm_ioctl_desc drm_ioctls[] = { | |||
| 513 | DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0), | 523 | DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0), |
| 514 | DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER), | 524 | DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER), |
| 515 | 525 | ||
| 516 | DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 526 | DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
| 517 | DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 527 | DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
| 518 | DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 528 | DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
| 519 | DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER), | 529 | DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_UNLOCKED|DRM_MASTER), |
| 520 | 530 | ||
| 521 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_legacy_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 531 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_legacy_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
| 522 | DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_legacy_rmmap_ioctl, DRM_AUTH), | 532 | DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_legacy_rmmap_ioctl, DRM_AUTH), |
| @@ -524,8 +534,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = { | |||
| 524 | DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_legacy_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 534 | DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_legacy_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
| 525 | DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_legacy_getsareactx, DRM_AUTH), | 535 | DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_legacy_getsareactx, DRM_AUTH), |
| 526 | 536 | ||
| 527 | DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY), | 537 | DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_UNLOCKED|DRM_ROOT_ONLY), |
| 528 | DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY), | 538 | DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_UNLOCKED|DRM_ROOT_ONLY), |
| 529 | 539 | ||
| 530 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_legacy_addctx, DRM_AUTH|DRM_ROOT_ONLY), | 540 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_legacy_addctx, DRM_AUTH|DRM_ROOT_ONLY), |
| 531 | DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_legacy_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 541 | DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_legacy_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 76e39c50c90c..8ca3d2bf2bda 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
| @@ -994,10 +994,10 @@ static void send_vblank_event(struct drm_device *dev, | |||
| 994 | e->event.tv_sec = now->tv_sec; | 994 | e->event.tv_sec = now->tv_sec; |
| 995 | e->event.tv_usec = now->tv_usec; | 995 | e->event.tv_usec = now->tv_usec; |
| 996 | 996 | ||
| 997 | drm_send_event_locked(dev, &e->base); | ||
| 998 | |||
| 999 | trace_drm_vblank_event_delivered(e->base.pid, e->pipe, | 997 | trace_drm_vblank_event_delivered(e->base.pid, e->pipe, |
| 1000 | e->event.sequence); | 998 | e->event.sequence); |
| 999 | |||
| 1000 | drm_send_event_locked(dev, &e->base); | ||
| 1001 | } | 1001 | } |
| 1002 | 1002 | ||
| 1003 | /** | 1003 | /** |
diff --git a/drivers/gpu/drm/drm_legacy.h b/drivers/gpu/drm/drm_legacy.h index d3b6ee357a2b..c6f422e879dd 100644 --- a/drivers/gpu/drm/drm_legacy.h +++ b/drivers/gpu/drm/drm_legacy.h | |||
| @@ -88,14 +88,10 @@ struct drm_agp_mem { | |||
| 88 | struct list_head head; | 88 | struct list_head head; |
| 89 | }; | 89 | }; |
| 90 | 90 | ||
| 91 | /* | 91 | /* drm_lock.c */ |
| 92 | * Generic Userspace Locking-API | ||
| 93 | */ | ||
| 94 | |||
| 95 | int drm_legacy_i_have_hw_lock(struct drm_device *d, struct drm_file *f); | ||
| 96 | int drm_legacy_lock(struct drm_device *d, void *v, struct drm_file *f); | 92 | int drm_legacy_lock(struct drm_device *d, void *v, struct drm_file *f); |
| 97 | int drm_legacy_unlock(struct drm_device *d, void *v, struct drm_file *f); | 93 | int drm_legacy_unlock(struct drm_device *d, void *v, struct drm_file *f); |
| 98 | int drm_legacy_lock_free(struct drm_lock_data *lock, unsigned int ctx); | 94 | void drm_legacy_lock_release(struct drm_device *dev, struct file *filp); |
| 99 | 95 | ||
| 100 | /* DMA support */ | 96 | /* DMA support */ |
| 101 | int drm_legacy_dma_setup(struct drm_device *dev); | 97 | int drm_legacy_dma_setup(struct drm_device *dev); |
diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index daa2ff12101b..48ac0ebbd663 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c | |||
| @@ -41,6 +41,110 @@ | |||
| 41 | static int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context); | 41 | static int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context); |
| 42 | 42 | ||
| 43 | /** | 43 | /** |
| 44 | * Take the heavyweight lock. | ||
| 45 | * | ||
| 46 | * \param lock lock pointer. | ||
| 47 | * \param context locking context. | ||
| 48 | * \return one if the lock is held, or zero otherwise. | ||
| 49 | * | ||
| 50 | * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction. | ||
| 51 | */ | ||
| 52 | static | ||
| 53 | int drm_lock_take(struct drm_lock_data *lock_data, | ||
| 54 | unsigned int context) | ||
| 55 | { | ||
| 56 | unsigned int old, new, prev; | ||
| 57 | volatile unsigned int *lock = &lock_data->hw_lock->lock; | ||
| 58 | |||
| 59 | spin_lock_bh(&lock_data->spinlock); | ||
| 60 | do { | ||
| 61 | old = *lock; | ||
| 62 | if (old & _DRM_LOCK_HELD) | ||
| 63 | new = old | _DRM_LOCK_CONT; | ||
| 64 | else { | ||
| 65 | new = context | _DRM_LOCK_HELD | | ||
| 66 | ((lock_data->user_waiters + lock_data->kernel_waiters > 1) ? | ||
| 67 | _DRM_LOCK_CONT : 0); | ||
| 68 | } | ||
| 69 | prev = cmpxchg(lock, old, new); | ||
| 70 | } while (prev != old); | ||
| 71 | spin_unlock_bh(&lock_data->spinlock); | ||
| 72 | |||
| 73 | if (_DRM_LOCKING_CONTEXT(old) == context) { | ||
| 74 | if (old & _DRM_LOCK_HELD) { | ||
| 75 | if (context != DRM_KERNEL_CONTEXT) { | ||
| 76 | DRM_ERROR("%d holds heavyweight lock\n", | ||
| 77 | context); | ||
| 78 | } | ||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) { | ||
| 84 | /* Have lock */ | ||
| 85 | return 1; | ||
| 86 | } | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | /** | ||
| 91 | * This takes a lock forcibly and hands it to context. Should ONLY be used | ||
| 92 | * inside *_unlock to give lock to kernel before calling *_dma_schedule. | ||
| 93 | * | ||
| 94 | * \param dev DRM device. | ||
| 95 | * \param lock lock pointer. | ||
| 96 | * \param context locking context. | ||
| 97 | * \return always one. | ||
| 98 | * | ||
| 99 | * Resets the lock file pointer. | ||
| 100 | * Marks the lock as held by the given context, via the \p cmpxchg instruction. | ||
| 101 | */ | ||
| 102 | static int drm_lock_transfer(struct drm_lock_data *lock_data, | ||
| 103 | unsigned int context) | ||
| 104 | { | ||
| 105 | unsigned int old, new, prev; | ||
| 106 | volatile unsigned int *lock = &lock_data->hw_lock->lock; | ||
| 107 | |||
| 108 | lock_data->file_priv = NULL; | ||
| 109 | do { | ||
| 110 | old = *lock; | ||
| 111 | new = context | _DRM_LOCK_HELD; | ||
| 112 | prev = cmpxchg(lock, old, new); | ||
| 113 | } while (prev != old); | ||
| 114 | return 1; | ||
| 115 | } | ||
| 116 | |||
| 117 | static int drm_legacy_lock_free(struct drm_lock_data *lock_data, | ||
| 118 | unsigned int context) | ||
| 119 | { | ||
| 120 | unsigned int old, new, prev; | ||
| 121 | volatile unsigned int *lock = &lock_data->hw_lock->lock; | ||
| 122 | |||
| 123 | spin_lock_bh(&lock_data->spinlock); | ||
| 124 | if (lock_data->kernel_waiters != 0) { | ||
| 125 | drm_lock_transfer(lock_data, 0); | ||
| 126 | lock_data->idle_has_lock = 1; | ||
| 127 | spin_unlock_bh(&lock_data->spinlock); | ||
| 128 | return 1; | ||
| 129 | } | ||
| 130 | spin_unlock_bh(&lock_data->spinlock); | ||
| 131 | |||
| 132 | do { | ||
| 133 | old = *lock; | ||
| 134 | new = _DRM_LOCKING_CONTEXT(old); | ||
| 135 | prev = cmpxchg(lock, old, new); | ||
| 136 | } while (prev != old); | ||
| 137 | |||
| 138 | if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { | ||
| 139 | DRM_ERROR("%d freed heavyweight lock held by %d\n", | ||
| 140 | context, _DRM_LOCKING_CONTEXT(old)); | ||
| 141 | return 1; | ||
| 142 | } | ||
| 143 | wake_up_interruptible(&lock_data->lock_queue); | ||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | /** | ||
| 44 | * Lock ioctl. | 148 | * Lock ioctl. |
| 45 | * | 149 | * |
| 46 | * \param inode device inode. | 150 | * \param inode device inode. |
| @@ -115,7 +219,7 @@ int drm_legacy_lock(struct drm_device *dev, void *data, | |||
| 115 | /* don't set the block all signals on the master process for now | 219 | /* don't set the block all signals on the master process for now |
| 116 | * really probably not the correct answer but lets us debug xkb | 220 | * really probably not the correct answer but lets us debug xkb |
| 117 | * xserver for now */ | 221 | * xserver for now */ |
| 118 | if (!file_priv->is_master) { | 222 | if (!drm_is_current_master(file_priv)) { |
| 119 | dev->sigdata.context = lock->context; | 223 | dev->sigdata.context = lock->context; |
| 120 | dev->sigdata.lock = master->lock.hw_lock; | 224 | dev->sigdata.lock = master->lock.hw_lock; |
| 121 | } | 225 | } |
| @@ -165,120 +269,6 @@ int drm_legacy_unlock(struct drm_device *dev, void *data, struct drm_file *file_ | |||
| 165 | } | 269 | } |
| 166 | 270 | ||
| 167 | /** | 271 | /** |
| 168 | * Take the heavyweight lock. | ||
| 169 | * | ||
| 170 | * \param lock lock pointer. | ||
| 171 | * \param context locking context. | ||
| 172 | * \return one if the lock is held, or zero otherwise. | ||
| 173 | * | ||
| 174 | * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction. | ||
| 175 | */ | ||
| 176 | static | ||
| 177 | int drm_lock_take(struct drm_lock_data *lock_data, | ||
| 178 | unsigned int context) | ||
| 179 | { | ||
| 180 | unsigned int old, new, prev; | ||
| 181 | volatile unsigned int *lock = &lock_data->hw_lock->lock; | ||
| 182 | |||
| 183 | spin_lock_bh(&lock_data->spinlock); | ||
| 184 | do { | ||
| 185 | old = *lock; | ||
| 186 | if (old & _DRM_LOCK_HELD) | ||
| 187 | new = old | _DRM_LOCK_CONT; | ||
| 188 | else { | ||
| 189 | new = context | _DRM_LOCK_HELD | | ||
| 190 | ((lock_data->user_waiters + lock_data->kernel_waiters > 1) ? | ||
| 191 | _DRM_LOCK_CONT : 0); | ||
| 192 | } | ||
| 193 | prev = cmpxchg(lock, old, new); | ||
| 194 | } while (prev != old); | ||
| 195 | spin_unlock_bh(&lock_data->spinlock); | ||
| 196 | |||
| 197 | if (_DRM_LOCKING_CONTEXT(old) == context) { | ||
| 198 | if (old & _DRM_LOCK_HELD) { | ||
| 199 | if (context != DRM_KERNEL_CONTEXT) { | ||
| 200 | DRM_ERROR("%d holds heavyweight lock\n", | ||
| 201 | context); | ||
| 202 | } | ||
| 203 | return 0; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) { | ||
| 208 | /* Have lock */ | ||
| 209 | return 1; | ||
| 210 | } | ||
| 211 | return 0; | ||
| 212 | } | ||
| 213 | |||
| 214 | /** | ||
| 215 | * This takes a lock forcibly and hands it to context. Should ONLY be used | ||
| 216 | * inside *_unlock to give lock to kernel before calling *_dma_schedule. | ||
| 217 | * | ||
| 218 | * \param dev DRM device. | ||
| 219 | * \param lock lock pointer. | ||
| 220 | * \param context locking context. | ||
| 221 | * \return always one. | ||
| 222 | * | ||
| 223 | * Resets the lock file pointer. | ||
| 224 | * Marks the lock as held by the given context, via the \p cmpxchg instruction. | ||
| 225 | */ | ||
| 226 | static int drm_lock_transfer(struct drm_lock_data *lock_data, | ||
| 227 | unsigned int context) | ||
| 228 | { | ||
| 229 | unsigned int old, new, prev; | ||
| 230 | volatile unsigned int *lock = &lock_data->hw_lock->lock; | ||
| 231 | |||
| 232 | lock_data->file_priv = NULL; | ||
| 233 | do { | ||
| 234 | old = *lock; | ||
| 235 | new = context | _DRM_LOCK_HELD; | ||
| 236 | prev = cmpxchg(lock, old, new); | ||
| 237 | } while (prev != old); | ||
| 238 | return 1; | ||
| 239 | } | ||
| 240 | |||
| 241 | /** | ||
| 242 | * Free lock. | ||
| 243 | * | ||
| 244 | * \param dev DRM device. | ||
| 245 | * \param lock lock. | ||
| 246 | * \param context context. | ||
| 247 | * | ||
| 248 | * Resets the lock file pointer. | ||
| 249 | * Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task | ||
| 250 | * waiting on the lock queue. | ||
| 251 | */ | ||
| 252 | int drm_legacy_lock_free(struct drm_lock_data *lock_data, unsigned int context) | ||
| 253 | { | ||
| 254 | unsigned int old, new, prev; | ||
| 255 | volatile unsigned int *lock = &lock_data->hw_lock->lock; | ||
| 256 | |||
| 257 | spin_lock_bh(&lock_data->spinlock); | ||
| 258 | if (lock_data->kernel_waiters != 0) { | ||
| 259 | drm_lock_transfer(lock_data, 0); | ||
| 260 | lock_data->idle_has_lock = 1; | ||
| 261 | spin_unlock_bh(&lock_data->spinlock); | ||
| 262 | return 1; | ||
| 263 | } | ||
| 264 | spin_unlock_bh(&lock_data->spinlock); | ||
| 265 | |||
| 266 | do { | ||
| 267 | old = *lock; | ||
| 268 | new = _DRM_LOCKING_CONTEXT(old); | ||
| 269 | prev = cmpxchg(lock, old, new); | ||
| 270 | } while (prev != old); | ||
| 271 | |||
| 272 | if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { | ||
| 273 | DRM_ERROR("%d freed heavyweight lock held by %d\n", | ||
| 274 | context, _DRM_LOCKING_CONTEXT(old)); | ||
| 275 | return 1; | ||
| 276 | } | ||
| 277 | wake_up_interruptible(&lock_data->lock_queue); | ||
| 278 | return 0; | ||
| 279 | } | ||
| 280 | |||
| 281 | /** | ||
| 282 | * This function returns immediately and takes the hw lock | 272 | * This function returns immediately and takes the hw lock |
| 283 | * with the kernel context if it is free, otherwise it gets the highest priority when and if | 273 | * with the kernel context if it is free, otherwise it gets the highest priority when and if |
| 284 | * it is eventually released. | 274 | * it is eventually released. |
| @@ -330,11 +320,27 @@ void drm_legacy_idlelock_release(struct drm_lock_data *lock_data) | |||
| 330 | } | 320 | } |
| 331 | EXPORT_SYMBOL(drm_legacy_idlelock_release); | 321 | EXPORT_SYMBOL(drm_legacy_idlelock_release); |
| 332 | 322 | ||
| 333 | int drm_legacy_i_have_hw_lock(struct drm_device *dev, | 323 | static int drm_legacy_i_have_hw_lock(struct drm_device *dev, |
| 334 | struct drm_file *file_priv) | 324 | struct drm_file *file_priv) |
| 335 | { | 325 | { |
| 336 | struct drm_master *master = file_priv->master; | 326 | struct drm_master *master = file_priv->master; |
| 337 | return (file_priv->lock_count && master->lock.hw_lock && | 327 | return (file_priv->lock_count && master->lock.hw_lock && |
| 338 | _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) && | 328 | _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) && |
| 339 | master->lock.file_priv == file_priv); | 329 | master->lock.file_priv == file_priv); |
| 340 | } | 330 | } |
| 331 | |||
| 332 | void drm_legacy_lock_release(struct drm_device *dev, struct file *filp) | ||
| 333 | { | ||
| 334 | struct drm_file *file_priv = filp->private_data; | ||
| 335 | |||
| 336 | /* if the master has gone away we can't do anything with the lock */ | ||
| 337 | if (!dev->master) | ||
| 338 | return; | ||
| 339 | |||
| 340 | if (drm_legacy_i_have_hw_lock(dev, file_priv)) { | ||
| 341 | DRM_DEBUG("File %p released, freeing lock for context %d\n", | ||
| 342 | filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); | ||
| 343 | drm_legacy_lock_free(&file_priv->master->lock, | ||
| 344 | _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); | ||
| 345 | } | ||
| 346 | } | ||
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 29d5a548d07a..b2f8f1062d5f 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c | |||
| @@ -144,50 +144,6 @@ int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) | |||
| 144 | } | 144 | } |
| 145 | EXPORT_SYMBOL(drm_pci_set_busid); | 145 | EXPORT_SYMBOL(drm_pci_set_busid); |
| 146 | 146 | ||
| 147 | int drm_pci_set_unique(struct drm_device *dev, | ||
| 148 | struct drm_master *master, | ||
| 149 | struct drm_unique *u) | ||
| 150 | { | ||
| 151 | int domain, bus, slot, func, ret; | ||
| 152 | |||
| 153 | master->unique_len = u->unique_len; | ||
| 154 | master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL); | ||
| 155 | if (!master->unique) { | ||
| 156 | ret = -ENOMEM; | ||
| 157 | goto err; | ||
| 158 | } | ||
| 159 | |||
| 160 | if (copy_from_user(master->unique, u->unique, master->unique_len)) { | ||
| 161 | ret = -EFAULT; | ||
| 162 | goto err; | ||
| 163 | } | ||
| 164 | |||
| 165 | master->unique[master->unique_len] = '\0'; | ||
| 166 | |||
| 167 | /* Return error if the busid submitted doesn't match the device's actual | ||
| 168 | * busid. | ||
| 169 | */ | ||
| 170 | ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); | ||
| 171 | if (ret != 3) { | ||
| 172 | ret = -EINVAL; | ||
| 173 | goto err; | ||
| 174 | } | ||
| 175 | |||
| 176 | domain = bus >> 8; | ||
| 177 | bus &= 0xff; | ||
| 178 | |||
| 179 | if ((domain != drm_get_pci_domain(dev)) || | ||
| 180 | (bus != dev->pdev->bus->number) || | ||
| 181 | (slot != PCI_SLOT(dev->pdev->devfn)) || | ||
| 182 | (func != PCI_FUNC(dev->pdev->devfn))) { | ||
| 183 | ret = -EINVAL; | ||
| 184 | goto err; | ||
| 185 | } | ||
| 186 | return 0; | ||
| 187 | err: | ||
| 188 | return ret; | ||
| 189 | } | ||
| 190 | |||
| 191 | static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) | 147 | static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) |
| 192 | { | 148 | { |
| 193 | if ((p->busnum >> 8) != drm_get_pci_domain(dev) || | 149 | if ((p->busnum >> 8) != drm_get_pci_domain(dev) || |
| @@ -444,13 +400,6 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, | |||
| 444 | { | 400 | { |
| 445 | return -EINVAL; | 401 | return -EINVAL; |
| 446 | } | 402 | } |
| 447 | |||
| 448 | int drm_pci_set_unique(struct drm_device *dev, | ||
| 449 | struct drm_master *master, | ||
| 450 | struct drm_unique *u) | ||
| 451 | { | ||
| 452 | return -EINVAL; | ||
| 453 | } | ||
| 454 | #endif | 403 | #endif |
| 455 | 404 | ||
| 456 | EXPORT_SYMBOL(drm_pci_init); | 405 | EXPORT_SYMBOL(drm_pci_init); |
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index fc51306fe365..16c4a7bd7465 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c | |||
| @@ -115,6 +115,7 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc, | |||
| 115 | * @src: source coordinates in 16.16 fixed point | 115 | * @src: source coordinates in 16.16 fixed point |
| 116 | * @dest: integer destination coordinates | 116 | * @dest: integer destination coordinates |
| 117 | * @clip: integer clipping coordinates | 117 | * @clip: integer clipping coordinates |
| 118 | * @rotation: plane rotation | ||
| 118 | * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point | 119 | * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point |
| 119 | * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point | 120 | * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point |
| 120 | * @can_position: is it legal to position the plane such that it | 121 | * @can_position: is it legal to position the plane such that it |
| @@ -134,16 +135,17 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc, | |||
| 134 | * Zero if update appears valid, error code on failure | 135 | * Zero if update appears valid, error code on failure |
| 135 | */ | 136 | */ |
| 136 | int drm_plane_helper_check_update(struct drm_plane *plane, | 137 | int drm_plane_helper_check_update(struct drm_plane *plane, |
| 137 | struct drm_crtc *crtc, | 138 | struct drm_crtc *crtc, |
| 138 | struct drm_framebuffer *fb, | 139 | struct drm_framebuffer *fb, |
| 139 | struct drm_rect *src, | 140 | struct drm_rect *src, |
| 140 | struct drm_rect *dest, | 141 | struct drm_rect *dest, |
| 141 | const struct drm_rect *clip, | 142 | const struct drm_rect *clip, |
| 142 | int min_scale, | 143 | unsigned int rotation, |
| 143 | int max_scale, | 144 | int min_scale, |
| 144 | bool can_position, | 145 | int max_scale, |
| 145 | bool can_update_disabled, | 146 | bool can_position, |
| 146 | bool *visible) | 147 | bool can_update_disabled, |
| 148 | bool *visible) | ||
| 147 | { | 149 | { |
| 148 | int hscale, vscale; | 150 | int hscale, vscale; |
| 149 | 151 | ||
| @@ -163,6 +165,8 @@ int drm_plane_helper_check_update(struct drm_plane *plane, | |||
| 163 | return -EINVAL; | 165 | return -EINVAL; |
| 164 | } | 166 | } |
| 165 | 167 | ||
| 168 | drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation); | ||
| 169 | |||
| 166 | /* Check scaling */ | 170 | /* Check scaling */ |
| 167 | hscale = drm_rect_calc_hscale(src, dest, min_scale, max_scale); | 171 | hscale = drm_rect_calc_hscale(src, dest, min_scale, max_scale); |
| 168 | vscale = drm_rect_calc_vscale(src, dest, min_scale, max_scale); | 172 | vscale = drm_rect_calc_vscale(src, dest, min_scale, max_scale); |
| @@ -174,6 +178,9 @@ int drm_plane_helper_check_update(struct drm_plane *plane, | |||
| 174 | } | 178 | } |
| 175 | 179 | ||
| 176 | *visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale); | 180 | *visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale); |
| 181 | |||
| 182 | drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); | ||
| 183 | |||
| 177 | if (!*visible) | 184 | if (!*visible) |
| 178 | /* | 185 | /* |
| 179 | * Plane isn't visible; some drivers can handle this | 186 | * Plane isn't visible; some drivers can handle this |
| @@ -267,6 +274,7 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, | |||
| 267 | 274 | ||
| 268 | ret = drm_plane_helper_check_update(plane, crtc, fb, | 275 | ret = drm_plane_helper_check_update(plane, crtc, fb, |
| 269 | &src, &dest, &clip, | 276 | &src, &dest, &clip, |
| 277 | BIT(DRM_ROTATE_0), | ||
| 270 | DRM_PLANE_HELPER_NO_SCALING, | 278 | DRM_PLANE_HELPER_NO_SCALING, |
| 271 | DRM_PLANE_HELPER_NO_SCALING, | 279 | DRM_PLANE_HELPER_NO_SCALING, |
| 272 | false, false, &visible); | 280 | false, false, &visible); |
diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 644169e1a029..2c819ef90090 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c | |||
| @@ -68,24 +68,6 @@ err_free: | |||
| 68 | return ret; | 68 | return ret; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | int drm_platform_set_busid(struct drm_device *dev, struct drm_master *master) | ||
| 72 | { | ||
| 73 | int id; | ||
| 74 | |||
| 75 | id = dev->platformdev->id; | ||
| 76 | if (id < 0) | ||
| 77 | id = 0; | ||
| 78 | |||
| 79 | master->unique = kasprintf(GFP_KERNEL, "platform:%s:%02d", | ||
| 80 | dev->platformdev->name, id); | ||
| 81 | if (!master->unique) | ||
| 82 | return -ENOMEM; | ||
| 83 | |||
| 84 | master->unique_len = strlen(master->unique); | ||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | EXPORT_SYMBOL(drm_platform_set_busid); | ||
| 88 | |||
| 89 | /** | 71 | /** |
| 90 | * drm_platform_init - Register a platform device with the DRM subsystem | 72 | * drm_platform_init - Register a platform device with the DRM subsystem |
| 91 | * @driver: DRM device driver | 73 | * @driver: DRM device driver |
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index b2071d495ada..0db36d27e90b 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c | |||
| @@ -105,6 +105,7 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, | |||
| 105 | ret = drm_plane_helper_check_update(plane, &pipe->crtc, | 105 | ret = drm_plane_helper_check_update(plane, &pipe->crtc, |
| 106 | plane_state->fb, | 106 | plane_state->fb, |
| 107 | &src, &dest, &clip, | 107 | &src, &dest, &clip, |
| 108 | plane_state->rotation, | ||
| 108 | DRM_PLANE_HELPER_NO_SCALING, | 109 | DRM_PLANE_HELPER_NO_SCALING, |
| 109 | DRM_PLANE_HELPER_NO_SCALING, | 110 | DRM_PLANE_HELPER_NO_SCALING, |
| 110 | false, true, &visible); | 111 | false, true, &visible); |
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index ac9f4b3ec615..43ff44a2b8e7 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c | |||
| @@ -670,57 +670,3 @@ void drm_legacy_vma_flush(struct drm_device *dev) | |||
| 670 | kfree(vma); | 670 | kfree(vma); |
| 671 | } | 671 | } |
| 672 | } | 672 | } |
| 673 | |||
| 674 | int drm_vma_info(struct seq_file *m, void *data) | ||
| 675 | { | ||
| 676 | struct drm_info_node *node = (struct drm_info_node *) m->private; | ||
| 677 | struct drm_device *dev = node->minor->dev; | ||
| 678 | struct drm_vma_entry *pt; | ||
| 679 | struct vm_area_struct *vma; | ||
| 680 | unsigned long vma_count = 0; | ||
| 681 | #if defined(__i386__) | ||
| 682 | unsigned int pgprot; | ||
| 683 | #endif | ||
| 684 | |||
| 685 | mutex_lock(&dev->struct_mutex); | ||
| 686 | list_for_each_entry(pt, &dev->vmalist, head) | ||
| 687 | vma_count++; | ||
| 688 | |||
| 689 | seq_printf(m, "vma use count: %lu, high_memory = %pK, 0x%pK\n", | ||
| 690 | vma_count, high_memory, | ||
| 691 | (void *)(unsigned long)virt_to_phys(high_memory)); | ||
| 692 | |||
| 693 | list_for_each_entry(pt, &dev->vmalist, head) { | ||
| 694 | vma = pt->vma; | ||
| 695 | if (!vma) | ||
| 696 | continue; | ||
| 697 | seq_printf(m, | ||
| 698 | "\n%5d 0x%pK-0x%pK %c%c%c%c%c%c 0x%08lx000", | ||
| 699 | pt->pid, | ||
| 700 | (void *)vma->vm_start, (void *)vma->vm_end, | ||
| 701 | vma->vm_flags & VM_READ ? 'r' : '-', | ||
| 702 | vma->vm_flags & VM_WRITE ? 'w' : '-', | ||
| 703 | vma->vm_flags & VM_EXEC ? 'x' : '-', | ||
| 704 | vma->vm_flags & VM_MAYSHARE ? 's' : 'p', | ||
| 705 | vma->vm_flags & VM_LOCKED ? 'l' : '-', | ||
| 706 | vma->vm_flags & VM_IO ? 'i' : '-', | ||
| 707 | vma->vm_pgoff); | ||
| 708 | |||
| 709 | #if defined(__i386__) | ||
| 710 | pgprot = pgprot_val(vma->vm_page_prot); | ||
| 711 | seq_printf(m, " %c%c%c%c%c%c%c%c%c", | ||
| 712 | pgprot & _PAGE_PRESENT ? 'p' : '-', | ||
| 713 | pgprot & _PAGE_RW ? 'w' : 'r', | ||
| 714 | pgprot & _PAGE_USER ? 'u' : 's', | ||
| 715 | pgprot & _PAGE_PWT ? 't' : 'b', | ||
| 716 | pgprot & _PAGE_PCD ? 'u' : 'c', | ||
| 717 | pgprot & _PAGE_ACCESSED ? 'a' : '-', | ||
| 718 | pgprot & _PAGE_DIRTY ? 'd' : '-', | ||
| 719 | pgprot & _PAGE_PSE ? 'm' : 'k', | ||
| 720 | pgprot & _PAGE_GLOBAL ? 'g' : 'l'); | ||
| 721 | #endif | ||
| 722 | seq_printf(m, "\n"); | ||
| 723 | } | ||
| 724 | mutex_unlock(&dev->struct_mutex); | ||
| 725 | return 0; | ||
| 726 | } | ||
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index 3d4f56df8359..340d390306d8 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c | |||
| @@ -496,7 +496,6 @@ static struct drm_driver etnaviv_drm_driver = { | |||
| 496 | DRIVER_RENDER, | 496 | DRIVER_RENDER, |
| 497 | .open = etnaviv_open, | 497 | .open = etnaviv_open, |
| 498 | .preclose = etnaviv_preclose, | 498 | .preclose = etnaviv_preclose, |
| 499 | .set_busid = drm_platform_set_busid, | ||
| 500 | .gem_free_object_unlocked = etnaviv_gem_free_object, | 499 | .gem_free_object_unlocked = etnaviv_gem_free_object, |
| 501 | .gem_vm_ops = &vm_ops, | 500 | .gem_vm_ops = &vm_ops, |
| 502 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | 501 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 4a679fb9bb02..13d28d4229e2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c | |||
| @@ -407,7 +407,6 @@ static struct drm_driver exynos_drm_driver = { | |||
| 407 | .preclose = exynos_drm_preclose, | 407 | .preclose = exynos_drm_preclose, |
| 408 | .lastclose = exynos_drm_lastclose, | 408 | .lastclose = exynos_drm_lastclose, |
| 409 | .postclose = exynos_drm_postclose, | 409 | .postclose = exynos_drm_postclose, |
| 410 | .set_busid = drm_platform_set_busid, | ||
| 411 | .get_vblank_counter = drm_vblank_no_hw_counter, | 410 | .get_vblank_counter = drm_vblank_no_hw_counter, |
| 412 | .enable_vblank = exynos_drm_crtc_enable_vblank, | 411 | .enable_vblank = exynos_drm_crtc_enable_vblank, |
| 413 | .disable_vblank = exynos_drm_crtc_disable_vblank, | 412 | .disable_vblank = exynos_drm_crtc_disable_vblank, |
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c index c564ec612b59..a6e4cd591960 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c | |||
| @@ -37,23 +37,22 @@ int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev) | |||
| 37 | 37 | ||
| 38 | ret = fsl_dcu_drm_crtc_create(fsl_dev); | 38 | ret = fsl_dcu_drm_crtc_create(fsl_dev); |
| 39 | if (ret) | 39 | if (ret) |
| 40 | return ret; | 40 | goto err; |
| 41 | 41 | ||
| 42 | ret = fsl_dcu_drm_encoder_create(fsl_dev, &fsl_dev->crtc); | 42 | ret = fsl_dcu_drm_encoder_create(fsl_dev, &fsl_dev->crtc); |
| 43 | if (ret) | 43 | if (ret) |
| 44 | goto fail_encoder; | 44 | goto err; |
| 45 | 45 | ||
| 46 | ret = fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder); | 46 | ret = fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder); |
| 47 | if (ret) | 47 | if (ret) |
| 48 | goto fail_connector; | 48 | goto err; |
| 49 | 49 | ||
| 50 | drm_mode_config_reset(fsl_dev->drm); | 50 | drm_mode_config_reset(fsl_dev->drm); |
| 51 | drm_kms_helper_poll_init(fsl_dev->drm); | 51 | drm_kms_helper_poll_init(fsl_dev->drm); |
| 52 | 52 | ||
| 53 | return 0; | 53 | return 0; |
| 54 | fail_encoder: | 54 | |
| 55 | fsl_dev->crtc.funcs->destroy(&fsl_dev->crtc); | 55 | err: |
| 56 | fail_connector: | 56 | drm_mode_config_cleanup(fsl_dev->drm); |
| 57 | fsl_dev->encoder.funcs->destroy(&fsl_dev->encoder); | ||
| 58 | return ret; | 57 | return ret; |
| 59 | } | 58 | } |
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index 193657259ee9..1edd9bc80294 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | |||
| @@ -171,7 +171,6 @@ static struct drm_driver kirin_drm_driver = { | |||
| 171 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | | 171 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | |
| 172 | DRIVER_ATOMIC | DRIVER_HAVE_IRQ, | 172 | DRIVER_ATOMIC | DRIVER_HAVE_IRQ, |
| 173 | .fops = &kirin_drm_fops, | 173 | .fops = &kirin_drm_fops, |
| 174 | .set_busid = drm_platform_set_busid, | ||
| 175 | 174 | ||
| 176 | .gem_free_object_unlocked = drm_gem_cma_free_object, | 175 | .gem_free_object_unlocked = drm_gem_cma_free_object, |
| 177 | .gem_vm_ops = &drm_gem_cma_vm_ops, | 176 | .gem_vm_ops = &drm_gem_cma_vm_ops, |
| @@ -221,19 +220,12 @@ static int kirin_drm_bind(struct device *dev) | |||
| 221 | if (ret) | 220 | if (ret) |
| 222 | goto err_kms_cleanup; | 221 | goto err_kms_cleanup; |
| 223 | 222 | ||
| 224 | /* connectors should be registered after drm device register */ | ||
| 225 | ret = drm_connector_register_all(drm_dev); | ||
| 226 | if (ret) | ||
| 227 | goto err_drm_dev_unregister; | ||
| 228 | |||
| 229 | DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", | 223 | DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", |
| 230 | driver->name, driver->major, driver->minor, driver->patchlevel, | 224 | driver->name, driver->major, driver->minor, driver->patchlevel, |
| 231 | driver->date, drm_dev->primary->index); | 225 | driver->date, drm_dev->primary->index); |
| 232 | 226 | ||
| 233 | return 0; | 227 | return 0; |
| 234 | 228 | ||
| 235 | err_drm_dev_unregister: | ||
| 236 | drm_dev_unregister(drm_dev); | ||
| 237 | err_kms_cleanup: | 229 | err_kms_cleanup: |
| 238 | kirin_drm_kms_cleanup(drm_dev); | 230 | kirin_drm_kms_cleanup(drm_dev); |
| 239 | err_drm_dev_unref: | 231 | err_drm_dev_unref: |
| @@ -246,7 +238,6 @@ static void kirin_drm_unbind(struct device *dev) | |||
| 246 | { | 238 | { |
| 247 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 239 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
| 248 | 240 | ||
| 249 | drm_connector_unregister_all(drm_dev); | ||
| 250 | drm_dev_unregister(drm_dev); | 241 | drm_dev_unregister(drm_dev); |
| 251 | kirin_drm_kms_cleanup(drm_dev); | 242 | kirin_drm_kms_cleanup(drm_dev); |
| 252 | drm_dev_unref(drm_dev); | 243 | drm_dev_unref(drm_dev); |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index de4bf367c66c..24a86c64d22e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | #include <drm/intel-gtt.h> | 47 | #include <drm/intel-gtt.h> |
| 48 | #include <drm/drm_legacy.h> /* for struct drm_dma_handle */ | 48 | #include <drm/drm_legacy.h> /* for struct drm_dma_handle */ |
| 49 | #include <drm/drm_gem.h> | 49 | #include <drm/drm_gem.h> |
| 50 | #include <drm/drm_auth.h> | ||
| 50 | 51 | ||
| 51 | #include "i915_params.h" | 52 | #include "i915_params.h" |
| 52 | #include "i915_reg.h" | 53 | #include "i915_reg.h" |
| @@ -3720,7 +3721,7 @@ extern void intel_modeset_init_hw(struct drm_device *dev); | |||
| 3720 | extern void intel_modeset_init(struct drm_device *dev); | 3721 | extern void intel_modeset_init(struct drm_device *dev); |
| 3721 | extern void intel_modeset_gem_init(struct drm_device *dev); | 3722 | extern void intel_modeset_gem_init(struct drm_device *dev); |
| 3722 | extern void intel_modeset_cleanup(struct drm_device *dev); | 3723 | extern void intel_modeset_cleanup(struct drm_device *dev); |
| 3723 | extern void intel_connector_unregister(struct intel_connector *); | 3724 | extern void intel_connector_unregister(struct drm_connector *); |
| 3724 | extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); | 3725 | extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); |
| 3725 | extern void intel_display_resume(struct drm_device *dev); | 3726 | extern void intel_display_resume(struct drm_device *dev); |
| 3726 | extern void i915_redisable_vga(struct drm_device *dev); | 3727 | extern void i915_redisable_vga(struct drm_device *dev); |
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 8097698b9622..7941f1fe9cd2 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c | |||
| @@ -1446,7 +1446,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, | |||
| 1446 | 1446 | ||
| 1447 | dispatch_flags = 0; | 1447 | dispatch_flags = 0; |
| 1448 | if (args->flags & I915_EXEC_SECURE) { | 1448 | if (args->flags & I915_EXEC_SECURE) { |
| 1449 | if (!file->is_master || !capable(CAP_SYS_ADMIN)) | 1449 | if (!drm_is_current_master(file) || !capable(CAP_SYS_ADMIN)) |
| 1450 | return -EPERM; | 1450 | return -EPERM; |
| 1451 | 1451 | ||
| 1452 | dispatch_flags |= I915_DISPATCH_SECURE; | 1452 | dispatch_flags |= I915_DISPATCH_SECURE; |
| @@ -1553,7 +1553,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, | |||
| 1553 | batch_obj, | 1553 | batch_obj, |
| 1554 | args->batch_start_offset, | 1554 | args->batch_start_offset, |
| 1555 | args->batch_len, | 1555 | args->batch_len, |
| 1556 | file->is_master); | 1556 | drm_is_current_master(file)); |
| 1557 | if (IS_ERR(parsed_batch_obj)) { | 1557 | if (IS_ERR(parsed_batch_obj)) { |
| 1558 | ret = PTR_ERR(parsed_batch_obj); | 1558 | ret = PTR_ERR(parsed_batch_obj); |
| 1559 | goto err; | 1559 | goto err; |
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 9465de4135aa..e115bcc6766f 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c | |||
| @@ -743,6 +743,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = { | |||
| 743 | .dpms = drm_atomic_helper_connector_dpms, | 743 | .dpms = drm_atomic_helper_connector_dpms, |
| 744 | .detect = intel_crt_detect, | 744 | .detect = intel_crt_detect, |
| 745 | .fill_modes = drm_helper_probe_single_connector_modes, | 745 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 746 | .early_unregister = intel_connector_unregister, | ||
| 746 | .destroy = intel_crt_destroy, | 747 | .destroy = intel_crt_destroy, |
| 747 | .set_property = intel_crt_set_property, | 748 | .set_property = intel_crt_set_property, |
| 748 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 749 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| @@ -875,7 +876,6 @@ void intel_crt_init(struct drm_device *dev) | |||
| 875 | crt->base.get_hw_state = intel_crt_get_hw_state; | 876 | crt->base.get_hw_state = intel_crt_get_hw_state; |
| 876 | } | 877 | } |
| 877 | intel_connector->get_hw_state = intel_connector_get_hw_state; | 878 | intel_connector->get_hw_state = intel_connector_get_hw_state; |
| 878 | intel_connector->unregister = intel_connector_unregister; | ||
| 879 | 879 | ||
| 880 | drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); | 880 | drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); |
| 881 | 881 | ||
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8c6f4e2a2cb8..0b2cd669ac05 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
| @@ -14184,6 +14184,7 @@ intel_check_primary_plane(struct drm_plane *plane, | |||
| 14184 | 14184 | ||
| 14185 | return drm_plane_helper_check_update(plane, crtc, fb, &state->src, | 14185 | return drm_plane_helper_check_update(plane, crtc, fb, &state->src, |
| 14186 | &state->dst, &state->clip, | 14186 | &state->dst, &state->clip, |
| 14187 | state->base.rotation, | ||
| 14187 | min_scale, max_scale, | 14188 | min_scale, max_scale, |
| 14188 | can_position, true, | 14189 | can_position, true, |
| 14189 | &state->visible); | 14190 | &state->visible); |
| @@ -14375,6 +14376,7 @@ intel_check_cursor_plane(struct drm_plane *plane, | |||
| 14375 | 14376 | ||
| 14376 | ret = drm_plane_helper_check_update(plane, crtc, fb, &state->src, | 14377 | ret = drm_plane_helper_check_update(plane, crtc, fb, &state->src, |
| 14377 | &state->dst, &state->clip, | 14378 | &state->dst, &state->clip, |
| 14379 | state->base.rotation, | ||
| 14378 | DRM_PLANE_HELPER_NO_SCALING, | 14380 | DRM_PLANE_HELPER_NO_SCALING, |
| 14379 | DRM_PLANE_HELPER_NO_SCALING, | 14381 | DRM_PLANE_HELPER_NO_SCALING, |
| 14380 | true, true, &state->visible); | 14382 | true, true, &state->visible); |
| @@ -16311,23 +16313,20 @@ void intel_modeset_gem_init(struct drm_device *dev) | |||
| 16311 | intel_backlight_register(dev); | 16313 | intel_backlight_register(dev); |
| 16312 | } | 16314 | } |
| 16313 | 16315 | ||
| 16314 | void intel_connector_unregister(struct intel_connector *intel_connector) | 16316 | void intel_connector_unregister(struct drm_connector *connector) |
| 16315 | { | 16317 | { |
| 16316 | struct drm_connector *connector = &intel_connector->base; | 16318 | struct intel_connector *intel_connector = to_intel_connector(connector); |
| 16317 | 16319 | ||
| 16320 | intel_backlight_device_unregister(intel_connector); | ||
| 16318 | intel_panel_destroy_backlight(connector); | 16321 | intel_panel_destroy_backlight(connector); |
| 16319 | drm_connector_unregister(connector); | ||
| 16320 | } | 16322 | } |
| 16321 | 16323 | ||
| 16322 | void intel_modeset_cleanup(struct drm_device *dev) | 16324 | void intel_modeset_cleanup(struct drm_device *dev) |
| 16323 | { | 16325 | { |
| 16324 | struct drm_i915_private *dev_priv = dev->dev_private; | 16326 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 16325 | struct intel_connector *connector; | ||
| 16326 | 16327 | ||
| 16327 | intel_disable_gt_powersave(dev_priv); | 16328 | intel_disable_gt_powersave(dev_priv); |
| 16328 | 16329 | ||
| 16329 | intel_backlight_unregister(dev); | ||
| 16330 | |||
| 16331 | /* | 16330 | /* |
| 16332 | * Interrupts and polling as the first thing to avoid creating havoc. | 16331 | * Interrupts and polling as the first thing to avoid creating havoc. |
| 16333 | * Too much stuff here (turning of connectors, ...) would | 16332 | * Too much stuff here (turning of connectors, ...) would |
| @@ -16348,9 +16347,7 @@ void intel_modeset_cleanup(struct drm_device *dev) | |||
| 16348 | /* flush any delayed tasks or pending work */ | 16347 | /* flush any delayed tasks or pending work */ |
| 16349 | flush_scheduled_work(); | 16348 | flush_scheduled_work(); |
| 16350 | 16349 | ||
| 16351 | /* destroy the backlight and sysfs files before encoders/connectors */ | 16350 | drm_connector_unregister_all(dev); |
| 16352 | for_each_intel_connector(dev, connector) | ||
| 16353 | connector->unregister(connector); | ||
| 16354 | 16351 | ||
| 16355 | drm_mode_config_cleanup(dev); | 16352 | drm_mode_config_cleanup(dev); |
| 16356 | 16353 | ||
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index be083519dac9..0b84f8e5df50 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
| @@ -1177,7 +1177,6 @@ static void intel_aux_reg_init(struct intel_dp *intel_dp) | |||
| 1177 | static void | 1177 | static void |
| 1178 | intel_dp_aux_fini(struct intel_dp *intel_dp) | 1178 | intel_dp_aux_fini(struct intel_dp *intel_dp) |
| 1179 | { | 1179 | { |
| 1180 | drm_dp_aux_unregister(&intel_dp->aux); | ||
| 1181 | kfree(intel_dp->aux.name); | 1180 | kfree(intel_dp->aux.name); |
| 1182 | } | 1181 | } |
| 1183 | 1182 | ||
| @@ -1212,15 +1211,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector) | |||
| 1212 | return 0; | 1211 | return 0; |
| 1213 | } | 1212 | } |
| 1214 | 1213 | ||
| 1215 | static void | ||
| 1216 | intel_dp_connector_unregister(struct intel_connector *intel_connector) | ||
| 1217 | { | ||
| 1218 | struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base); | ||
| 1219 | |||
| 1220 | intel_dp_aux_fini(intel_dp); | ||
| 1221 | intel_connector_unregister(intel_connector); | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | static int | 1214 | static int |
| 1225 | intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates) | 1215 | intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates) |
| 1226 | { | 1216 | { |
| @@ -4457,6 +4447,13 @@ done: | |||
| 4457 | } | 4447 | } |
| 4458 | 4448 | ||
| 4459 | static void | 4449 | static void |
| 4450 | intel_dp_connector_unregister(struct drm_connector *connector) | ||
| 4451 | { | ||
| 4452 | drm_dp_aux_unregister(&intel_attached_dp(connector)->aux); | ||
| 4453 | intel_connector_unregister(connector); | ||
| 4454 | } | ||
| 4455 | |||
| 4456 | static void | ||
| 4460 | intel_dp_connector_destroy(struct drm_connector *connector) | 4457 | intel_dp_connector_destroy(struct drm_connector *connector) |
| 4461 | { | 4458 | { |
| 4462 | struct intel_connector *intel_connector = to_intel_connector(connector); | 4459 | struct intel_connector *intel_connector = to_intel_connector(connector); |
| @@ -4496,6 +4493,9 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) | |||
| 4496 | intel_dp->edp_notifier.notifier_call = NULL; | 4493 | intel_dp->edp_notifier.notifier_call = NULL; |
| 4497 | } | 4494 | } |
| 4498 | } | 4495 | } |
| 4496 | |||
| 4497 | intel_dp_aux_fini(intel_dp); | ||
| 4498 | |||
| 4499 | drm_encoder_cleanup(encoder); | 4499 | drm_encoder_cleanup(encoder); |
| 4500 | kfree(intel_dig_port); | 4500 | kfree(intel_dig_port); |
| 4501 | } | 4501 | } |
| @@ -4572,6 +4572,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = { | |||
| 4572 | .fill_modes = drm_helper_probe_single_connector_modes, | 4572 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 4573 | .set_property = intel_dp_set_property, | 4573 | .set_property = intel_dp_set_property, |
| 4574 | .atomic_get_property = intel_connector_atomic_get_property, | 4574 | .atomic_get_property = intel_connector_atomic_get_property, |
| 4575 | .early_unregister = intel_dp_connector_unregister, | ||
| 4575 | .destroy = intel_dp_connector_destroy, | 4576 | .destroy = intel_dp_connector_destroy, |
| 4576 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 4577 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| 4577 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 4578 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
| @@ -5487,7 +5488,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, | |||
| 5487 | intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; | 5488 | intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; |
| 5488 | else | 5489 | else |
| 5489 | intel_connector->get_hw_state = intel_connector_get_hw_state; | 5490 | intel_connector->get_hw_state = intel_connector_get_hw_state; |
| 5490 | intel_connector->unregister = intel_dp_connector_unregister; | ||
| 5491 | 5491 | ||
| 5492 | /* Set up the hotplug pin. */ | 5492 | /* Set up the hotplug pin. */ |
| 5493 | switch (port) { | 5493 | switch (port) { |
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index f62ca9a126b3..9646816604be 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c | |||
| @@ -336,6 +336,7 @@ static const struct drm_connector_funcs intel_dp_mst_connector_funcs = { | |||
| 336 | .fill_modes = drm_helper_probe_single_connector_modes, | 336 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 337 | .set_property = intel_dp_mst_set_property, | 337 | .set_property = intel_dp_mst_set_property, |
| 338 | .atomic_get_property = intel_connector_atomic_get_property, | 338 | .atomic_get_property = intel_connector_atomic_get_property, |
| 339 | .early_unregister = intel_connector_unregister, | ||
| 339 | .destroy = intel_dp_mst_connector_destroy, | 340 | .destroy = intel_dp_mst_connector_destroy, |
| 340 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 341 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| 341 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 342 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
| @@ -455,7 +456,6 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo | |||
| 455 | drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort); | 456 | drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort); |
| 456 | drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs); | 457 | drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs); |
| 457 | 458 | ||
| 458 | intel_connector->unregister = intel_connector_unregister; | ||
| 459 | intel_connector->get_hw_state = intel_dp_mst_get_hw_state; | 459 | intel_connector->get_hw_state = intel_dp_mst_get_hw_state; |
| 460 | intel_connector->mst_port = intel_dp; | 460 | intel_connector->mst_port = intel_dp; |
| 461 | intel_connector->port = port; | 461 | intel_connector->port = port; |
| @@ -489,7 +489,7 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, | |||
| 489 | struct intel_connector *intel_connector = to_intel_connector(connector); | 489 | struct intel_connector *intel_connector = to_intel_connector(connector); |
| 490 | struct drm_device *dev = connector->dev; | 490 | struct drm_device *dev = connector->dev; |
| 491 | 491 | ||
| 492 | intel_connector->unregister(intel_connector); | 492 | drm_connector_unregister(connector); |
| 493 | 493 | ||
| 494 | /* need to nuke the connector */ | 494 | /* need to nuke the connector */ |
| 495 | drm_modeset_lock_all(dev); | 495 | drm_modeset_lock_all(dev); |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0c1dc9bae170..7d0e071fe355 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
| @@ -242,14 +242,6 @@ struct intel_connector { | |||
| 242 | * and active (i.e. dpms ON state). */ | 242 | * and active (i.e. dpms ON state). */ |
| 243 | bool (*get_hw_state)(struct intel_connector *); | 243 | bool (*get_hw_state)(struct intel_connector *); |
| 244 | 244 | ||
| 245 | /* | ||
| 246 | * Removes all interfaces through which the connector is accessible | ||
| 247 | * - like sysfs, debugfs entries -, so that no new operations can be | ||
| 248 | * started on the connector. Also makes sure all currently pending | ||
| 249 | * operations finish before returing. | ||
| 250 | */ | ||
| 251 | void (*unregister)(struct intel_connector *); | ||
| 252 | |||
| 253 | /* Panel info for eDP and LVDS */ | 245 | /* Panel info for eDP and LVDS */ |
| 254 | struct intel_panel panel; | 246 | struct intel_panel panel; |
| 255 | 247 | ||
| @@ -1509,7 +1501,14 @@ extern struct drm_display_mode *intel_find_panel_downclock( | |||
| 1509 | struct drm_display_mode *fixed_mode, | 1501 | struct drm_display_mode *fixed_mode, |
| 1510 | struct drm_connector *connector); | 1502 | struct drm_connector *connector); |
| 1511 | void intel_backlight_register(struct drm_device *dev); | 1503 | void intel_backlight_register(struct drm_device *dev); |
| 1512 | void intel_backlight_unregister(struct drm_device *dev); | 1504 | |
| 1505 | #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) | ||
| 1506 | void intel_backlight_device_unregister(struct intel_connector *connector); | ||
| 1507 | #else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ | ||
| 1508 | static inline void intel_backlight_device_unregister(struct intel_connector *connector) | ||
| 1509 | { | ||
| 1510 | } | ||
| 1511 | #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ | ||
| 1513 | 1512 | ||
| 1514 | 1513 | ||
| 1515 | /* intel_psr.c */ | 1514 | /* intel_psr.c */ |
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 10e12829b13f..b444d0e35a98 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c | |||
| @@ -1390,6 +1390,7 @@ static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs | |||
| 1390 | static const struct drm_connector_funcs intel_dsi_connector_funcs = { | 1390 | static const struct drm_connector_funcs intel_dsi_connector_funcs = { |
| 1391 | .dpms = drm_atomic_helper_connector_dpms, | 1391 | .dpms = drm_atomic_helper_connector_dpms, |
| 1392 | .detect = intel_dsi_detect, | 1392 | .detect = intel_dsi_detect, |
| 1393 | .early_unregister = intel_connector_unregister, | ||
| 1393 | .destroy = intel_dsi_connector_destroy, | 1394 | .destroy = intel_dsi_connector_destroy, |
| 1394 | .fill_modes = drm_helper_probe_single_connector_modes, | 1395 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 1395 | .set_property = intel_dsi_set_property, | 1396 | .set_property = intel_dsi_set_property, |
| @@ -1466,7 +1467,6 @@ void intel_dsi_init(struct drm_device *dev) | |||
| 1466 | intel_encoder->get_config = intel_dsi_get_config; | 1467 | intel_encoder->get_config = intel_dsi_get_config; |
| 1467 | 1468 | ||
| 1468 | intel_connector->get_hw_state = intel_connector_get_hw_state; | 1469 | intel_connector->get_hw_state = intel_connector_get_hw_state; |
| 1469 | intel_connector->unregister = intel_connector_unregister; | ||
| 1470 | 1470 | ||
| 1471 | /* | 1471 | /* |
| 1472 | * On BYT/CHV, pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI | 1472 | * On BYT/CHV, pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI |
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index c86f88ed92fd..60e4ddf2ec6d 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c | |||
| @@ -341,6 +341,7 @@ static void intel_dvo_destroy(struct drm_connector *connector) | |||
| 341 | static const struct drm_connector_funcs intel_dvo_connector_funcs = { | 341 | static const struct drm_connector_funcs intel_dvo_connector_funcs = { |
| 342 | .dpms = drm_atomic_helper_connector_dpms, | 342 | .dpms = drm_atomic_helper_connector_dpms, |
| 343 | .detect = intel_dvo_detect, | 343 | .detect = intel_dvo_detect, |
| 344 | .early_unregister = intel_connector_unregister, | ||
| 344 | .destroy = intel_dvo_destroy, | 345 | .destroy = intel_dvo_destroy, |
| 345 | .fill_modes = drm_helper_probe_single_connector_modes, | 346 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 346 | .atomic_get_property = intel_connector_atomic_get_property, | 347 | .atomic_get_property = intel_connector_atomic_get_property, |
| @@ -447,7 +448,6 @@ void intel_dvo_init(struct drm_device *dev) | |||
| 447 | intel_encoder->compute_config = intel_dvo_compute_config; | 448 | intel_encoder->compute_config = intel_dvo_compute_config; |
| 448 | intel_encoder->pre_enable = intel_dvo_pre_enable; | 449 | intel_encoder->pre_enable = intel_dvo_pre_enable; |
| 449 | intel_connector->get_hw_state = intel_dvo_connector_get_hw_state; | 450 | intel_connector->get_hw_state = intel_dvo_connector_get_hw_state; |
| 450 | intel_connector->unregister = intel_connector_unregister; | ||
| 451 | 451 | ||
| 452 | /* Now, try to find a controller */ | 452 | /* Now, try to find a controller */ |
| 453 | for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { | 453 | for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { |
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ad0c71b3e242..fb21626ada64 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c | |||
| @@ -1774,6 +1774,7 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = { | |||
| 1774 | .fill_modes = drm_helper_probe_single_connector_modes, | 1774 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 1775 | .set_property = intel_hdmi_set_property, | 1775 | .set_property = intel_hdmi_set_property, |
| 1776 | .atomic_get_property = intel_connector_atomic_get_property, | 1776 | .atomic_get_property = intel_connector_atomic_get_property, |
| 1777 | .early_unregister = intel_connector_unregister, | ||
| 1777 | .destroy = intel_hdmi_destroy, | 1778 | .destroy = intel_hdmi_destroy, |
| 1778 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 1779 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| 1779 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 1780 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
| @@ -1909,7 +1910,6 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, | |||
| 1909 | intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; | 1910 | intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; |
| 1910 | else | 1911 | else |
| 1911 | intel_connector->get_hw_state = intel_connector_get_hw_state; | 1912 | intel_connector->get_hw_state = intel_connector_get_hw_state; |
| 1912 | intel_connector->unregister = intel_connector_unregister; | ||
| 1913 | 1913 | ||
| 1914 | intel_hdmi_add_properties(intel_hdmi, connector); | 1914 | intel_hdmi_add_properties(intel_hdmi, connector); |
| 1915 | 1915 | ||
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index e06b9036bebc..e9082185a375 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
| @@ -555,6 +555,7 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = { | |||
| 555 | .fill_modes = drm_helper_probe_single_connector_modes, | 555 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 556 | .set_property = intel_lvds_set_property, | 556 | .set_property = intel_lvds_set_property, |
| 557 | .atomic_get_property = intel_connector_atomic_get_property, | 557 | .atomic_get_property = intel_connector_atomic_get_property, |
| 558 | .early_unregister = intel_connector_unregister, | ||
| 558 | .destroy = intel_lvds_destroy, | 559 | .destroy = intel_lvds_destroy, |
| 559 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 560 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| 560 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 561 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
| @@ -991,7 +992,6 @@ void intel_lvds_init(struct drm_device *dev) | |||
| 991 | intel_encoder->get_hw_state = intel_lvds_get_hw_state; | 992 | intel_encoder->get_hw_state = intel_lvds_get_hw_state; |
| 992 | intel_encoder->get_config = intel_lvds_get_config; | 993 | intel_encoder->get_config = intel_lvds_get_config; |
| 993 | intel_connector->get_hw_state = intel_connector_get_hw_state; | 994 | intel_connector->get_hw_state = intel_connector_get_hw_state; |
| 994 | intel_connector->unregister = intel_connector_unregister; | ||
| 995 | 995 | ||
| 996 | intel_connector_attach_encoder(intel_connector, intel_encoder); | 996 | intel_connector_attach_encoder(intel_connector, intel_encoder); |
| 997 | intel_encoder->type = INTEL_OUTPUT_LVDS; | 997 | intel_encoder->type = INTEL_OUTPUT_LVDS; |
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index f0b1602c3258..bf721781c259 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c | |||
| @@ -1216,7 +1216,7 @@ static int intel_backlight_device_register(struct intel_connector *connector) | |||
| 1216 | return 0; | 1216 | return 0; |
| 1217 | } | 1217 | } |
| 1218 | 1218 | ||
| 1219 | static void intel_backlight_device_unregister(struct intel_connector *connector) | 1219 | void intel_backlight_device_unregister(struct intel_connector *connector) |
| 1220 | { | 1220 | { |
| 1221 | struct intel_panel *panel = &connector->panel; | 1221 | struct intel_panel *panel = &connector->panel; |
| 1222 | 1222 | ||
| @@ -1230,9 +1230,6 @@ static int intel_backlight_device_register(struct intel_connector *connector) | |||
| 1230 | { | 1230 | { |
| 1231 | return 0; | 1231 | return 0; |
| 1232 | } | 1232 | } |
| 1233 | static void intel_backlight_device_unregister(struct intel_connector *connector) | ||
| 1234 | { | ||
| 1235 | } | ||
| 1236 | #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ | 1233 | #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ |
| 1237 | 1234 | ||
| 1238 | /* | 1235 | /* |
| @@ -1820,11 +1817,3 @@ void intel_backlight_register(struct drm_device *dev) | |||
| 1820 | for_each_intel_connector(dev, connector) | 1817 | for_each_intel_connector(dev, connector) |
| 1821 | intel_backlight_device_register(connector); | 1818 | intel_backlight_device_register(connector); |
| 1822 | } | 1819 | } |
| 1823 | |||
| 1824 | void intel_backlight_unregister(struct drm_device *dev) | ||
| 1825 | { | ||
| 1826 | struct intel_connector *connector; | ||
| 1827 | |||
| 1828 | for_each_intel_connector(dev, connector) | ||
| 1829 | intel_backlight_device_unregister(connector); | ||
| 1830 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index ab2d0658abe6..02b4a6695528 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
| @@ -2177,12 +2177,23 @@ done: | |||
| 2177 | #undef CHECK_PROPERTY | 2177 | #undef CHECK_PROPERTY |
| 2178 | } | 2178 | } |
| 2179 | 2179 | ||
| 2180 | static void | ||
| 2181 | intel_sdvo_connector_unregister(struct drm_connector *connector) | ||
| 2182 | { | ||
| 2183 | struct intel_sdvo *sdvo = intel_attached_sdvo(connector); | ||
| 2184 | |||
| 2185 | sysfs_remove_link(&connector->kdev->kobj, | ||
| 2186 | sdvo->ddc.dev.kobj.name); | ||
| 2187 | intel_connector_unregister(connector); | ||
| 2188 | } | ||
| 2189 | |||
| 2180 | static const struct drm_connector_funcs intel_sdvo_connector_funcs = { | 2190 | static const struct drm_connector_funcs intel_sdvo_connector_funcs = { |
| 2181 | .dpms = drm_atomic_helper_connector_dpms, | 2191 | .dpms = drm_atomic_helper_connector_dpms, |
| 2182 | .detect = intel_sdvo_detect, | 2192 | .detect = intel_sdvo_detect, |
| 2183 | .fill_modes = drm_helper_probe_single_connector_modes, | 2193 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 2184 | .set_property = intel_sdvo_set_property, | 2194 | .set_property = intel_sdvo_set_property, |
| 2185 | .atomic_get_property = intel_connector_atomic_get_property, | 2195 | .atomic_get_property = intel_connector_atomic_get_property, |
| 2196 | .early_unregister = intel_sdvo_connector_unregister, | ||
| 2186 | .destroy = intel_sdvo_destroy, | 2197 | .destroy = intel_sdvo_destroy, |
| 2187 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 2198 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| 2188 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 2199 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
| @@ -2345,20 +2356,6 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, struct intel_sdvo *sdvo) | |||
| 2345 | return 0x72; | 2356 | return 0x72; |
| 2346 | } | 2357 | } |
| 2347 | 2358 | ||
| 2348 | static void | ||
| 2349 | intel_sdvo_connector_unregister(struct intel_connector *intel_connector) | ||
| 2350 | { | ||
| 2351 | struct drm_connector *drm_connector; | ||
| 2352 | struct intel_sdvo *sdvo_encoder; | ||
| 2353 | |||
| 2354 | drm_connector = &intel_connector->base; | ||
| 2355 | sdvo_encoder = intel_attached_sdvo(&intel_connector->base); | ||
| 2356 | |||
| 2357 | sysfs_remove_link(&drm_connector->kdev->kobj, | ||
| 2358 | sdvo_encoder->ddc.dev.kobj.name); | ||
| 2359 | intel_connector_unregister(intel_connector); | ||
| 2360 | } | ||
| 2361 | |||
| 2362 | static int | 2359 | static int |
| 2363 | intel_sdvo_connector_init(struct intel_sdvo_connector *connector, | 2360 | intel_sdvo_connector_init(struct intel_sdvo_connector *connector, |
| 2364 | struct intel_sdvo *encoder) | 2361 | struct intel_sdvo *encoder) |
| @@ -2381,7 +2378,6 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector, | |||
| 2381 | connector->base.base.doublescan_allowed = 0; | 2378 | connector->base.base.doublescan_allowed = 0; |
| 2382 | connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; | 2379 | connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; |
| 2383 | connector->base.get_hw_state = intel_sdvo_connector_get_hw_state; | 2380 | connector->base.get_hw_state = intel_sdvo_connector_get_hw_state; |
| 2384 | connector->base.unregister = intel_sdvo_connector_unregister; | ||
| 2385 | 2381 | ||
| 2386 | intel_connector_attach_encoder(&connector->base, &encoder->base); | 2382 | intel_connector_attach_encoder(&connector->base, &encoder->base); |
| 2387 | ret = drm_connector_register(drm_connector); | 2383 | ret = drm_connector_register(drm_connector); |
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 7ac9e9b0e2c3..4ce70a9f9df2 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c | |||
| @@ -1501,6 +1501,7 @@ out: | |||
| 1501 | static const struct drm_connector_funcs intel_tv_connector_funcs = { | 1501 | static const struct drm_connector_funcs intel_tv_connector_funcs = { |
| 1502 | .dpms = drm_atomic_helper_connector_dpms, | 1502 | .dpms = drm_atomic_helper_connector_dpms, |
| 1503 | .detect = intel_tv_detect, | 1503 | .detect = intel_tv_detect, |
| 1504 | .early_unregister = intel_connector_unregister, | ||
| 1504 | .destroy = intel_tv_destroy, | 1505 | .destroy = intel_tv_destroy, |
| 1505 | .set_property = intel_tv_set_property, | 1506 | .set_property = intel_tv_set_property, |
| 1506 | .atomic_get_property = intel_connector_atomic_get_property, | 1507 | .atomic_get_property = intel_connector_atomic_get_property, |
| @@ -1599,7 +1600,6 @@ intel_tv_init(struct drm_device *dev) | |||
| 1599 | intel_encoder->disable = intel_disable_tv; | 1600 | intel_encoder->disable = intel_disable_tv; |
| 1600 | intel_encoder->get_hw_state = intel_tv_get_hw_state; | 1601 | intel_encoder->get_hw_state = intel_tv_get_hw_state; |
| 1601 | intel_connector->get_hw_state = intel_connector_get_hw_state; | 1602 | intel_connector->get_hw_state = intel_connector_get_hw_state; |
| 1602 | intel_connector->unregister = intel_connector_unregister; | ||
| 1603 | 1603 | ||
| 1604 | intel_connector_attach_encoder(intel_connector, intel_encoder); | 1604 | intel_connector_attach_encoder(intel_connector, intel_encoder); |
| 1605 | intel_encoder->type = INTEL_OUTPUT_TVOUT; | 1605 | intel_encoder->type = INTEL_OUTPUT_TVOUT; |
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 82656654fb21..7746418a4c08 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c | |||
| @@ -407,7 +407,6 @@ static struct drm_driver imx_drm_driver = { | |||
| 407 | .load = imx_drm_driver_load, | 407 | .load = imx_drm_driver_load, |
| 408 | .unload = imx_drm_driver_unload, | 408 | .unload = imx_drm_driver_unload, |
| 409 | .lastclose = imx_drm_driver_lastclose, | 409 | .lastclose = imx_drm_driver_lastclose, |
| 410 | .set_busid = drm_platform_set_busid, | ||
| 411 | .gem_free_object_unlocked = drm_gem_cma_free_object, | 410 | .gem_free_object_unlocked = drm_gem_cma_free_object, |
| 412 | .gem_vm_ops = &drm_gem_cma_vm_ops, | 411 | .gem_vm_ops = &drm_gem_cma_vm_ops, |
| 413 | .dumb_create = drm_gem_cma_dumb_create, | 412 | .dumb_create = drm_gem_cma_dumb_create, |
diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig index eeefc971801a..9eefecedc3da 100644 --- a/drivers/gpu/drm/mediatek/Kconfig +++ b/drivers/gpu/drm/mediatek/Kconfig | |||
| @@ -6,7 +6,6 @@ config DRM_MEDIATEK | |||
| 6 | select DRM_KMS_HELPER | 6 | select DRM_KMS_HELPER |
| 7 | select DRM_MIPI_DSI | 7 | select DRM_MIPI_DSI |
| 8 | select DRM_PANEL | 8 | select DRM_PANEL |
| 9 | select IOMMU_DMA | ||
| 10 | select MEMORY | 9 | select MEMORY |
| 11 | select MTK_SMI | 10 | select MTK_SMI |
| 12 | help | 11 | help |
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index c33bf98c5d5e..eebb7d881c2b 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c | |||
| @@ -280,8 +280,6 @@ static int mtk_drm_bind(struct device *dev) | |||
| 280 | if (!drm) | 280 | if (!drm) |
| 281 | return -ENOMEM; | 281 | return -ENOMEM; |
| 282 | 282 | ||
| 283 | drm_dev_set_unique(drm, dev_name(dev)); | ||
| 284 | |||
| 285 | drm->dev_private = private; | 283 | drm->dev_private = private; |
| 286 | private->drm = drm; | 284 | private->drm = drm; |
| 287 | 285 | ||
| @@ -293,14 +291,8 @@ static int mtk_drm_bind(struct device *dev) | |||
| 293 | if (ret < 0) | 291 | if (ret < 0) |
| 294 | goto err_deinit; | 292 | goto err_deinit; |
| 295 | 293 | ||
| 296 | ret = drm_connector_register_all(drm); | ||
| 297 | if (ret < 0) | ||
| 298 | goto err_unregister; | ||
| 299 | |||
| 300 | return 0; | 294 | return 0; |
| 301 | 295 | ||
| 302 | err_unregister: | ||
| 303 | drm_dev_unregister(drm); | ||
| 304 | err_deinit: | 296 | err_deinit: |
| 305 | mtk_drm_kms_deinit(drm); | 297 | mtk_drm_kms_deinit(drm); |
| 306 | err_free: | 298 | err_free: |
| @@ -455,7 +447,6 @@ static int mtk_drm_remove(struct platform_device *pdev) | |||
| 455 | struct drm_device *drm = private->drm; | 447 | struct drm_device *drm = private->drm; |
| 456 | int i; | 448 | int i; |
| 457 | 449 | ||
| 458 | drm_connector_unregister_all(drm); | ||
| 459 | drm_dev_unregister(drm); | 450 | drm_dev_unregister(drm); |
| 460 | mtk_drm_kms_deinit(drm); | 451 | mtk_drm_kms_deinit(drm); |
| 461 | drm_dev_unref(drm); | 452 | drm_dev_unref(drm); |
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 51bc8988fc26..3995765a90dc 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c | |||
| @@ -170,6 +170,7 @@ static int mtk_plane_atomic_check(struct drm_plane *plane, | |||
| 170 | 170 | ||
| 171 | return drm_plane_helper_check_update(plane, state->crtc, fb, | 171 | return drm_plane_helper_check_update(plane, state->crtc, fb, |
| 172 | &src, &dest, &clip, | 172 | &src, &dest, &clip, |
| 173 | state->rotation, | ||
| 173 | DRM_PLANE_HELPER_NO_SCALING, | 174 | DRM_PLANE_HELPER_NO_SCALING, |
| 174 | DRM_PLANE_HELPER_NO_SCALING, | 175 | DRM_PLANE_HELPER_NO_SCALING, |
| 175 | true, true, &visible); | 176 | true, true, &visible); |
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 9c654092ef78..a02dc2b27739 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c | |||
| @@ -197,8 +197,6 @@ static int msm_drm_uninit(struct device *dev) | |||
| 197 | 197 | ||
| 198 | drm_kms_helper_poll_fini(ddev); | 198 | drm_kms_helper_poll_fini(ddev); |
| 199 | 199 | ||
| 200 | drm_connector_unregister_all(ddev); | ||
| 201 | |||
| 202 | drm_dev_unregister(ddev); | 200 | drm_dev_unregister(ddev); |
| 203 | 201 | ||
| 204 | #ifdef CONFIG_DRM_FBDEV_EMULATION | 202 | #ifdef CONFIG_DRM_FBDEV_EMULATION |
| @@ -431,12 +429,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) | |||
| 431 | if (ret) | 429 | if (ret) |
| 432 | goto fail; | 430 | goto fail; |
| 433 | 431 | ||
| 434 | ret = drm_connector_register_all(ddev); | ||
| 435 | if (ret) { | ||
| 436 | dev_err(dev, "failed to register connectors\n"); | ||
| 437 | goto fail; | ||
| 438 | } | ||
| 439 | |||
| 440 | drm_mode_config_reset(ddev); | 432 | drm_mode_config_reset(ddev); |
| 441 | 433 | ||
| 442 | #ifdef CONFIG_DRM_FBDEV_EMULATION | 434 | #ifdef CONFIG_DRM_FBDEV_EMULATION |
| @@ -730,7 +722,6 @@ static struct drm_driver msm_driver = { | |||
| 730 | .open = msm_open, | 722 | .open = msm_open, |
| 731 | .preclose = msm_preclose, | 723 | .preclose = msm_preclose, |
| 732 | .lastclose = msm_lastclose, | 724 | .lastclose = msm_lastclose, |
| 733 | .set_busid = drm_platform_set_busid, | ||
| 734 | .irq_handler = msm_irq, | 725 | .irq_handler = msm_irq, |
| 735 | .irq_preinstall = msm_irq_preinstall, | 726 | .irq_preinstall = msm_irq_preinstall, |
| 736 | .irq_postinstall = msm_irq_postinstall, | 727 | .irq_postinstall = msm_irq_postinstall, |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index c00ff6e786a3..295e7621cc68 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
| @@ -1070,7 +1070,6 @@ nouveau_drm_init(void) | |||
| 1070 | driver_pci = driver_stub; | 1070 | driver_pci = driver_stub; |
| 1071 | driver_pci.set_busid = drm_pci_set_busid; | 1071 | driver_pci.set_busid = drm_pci_set_busid; |
| 1072 | driver_platform = driver_stub; | 1072 | driver_platform = driver_stub; |
| 1073 | driver_platform.set_busid = drm_platform_set_busid; | ||
| 1074 | 1073 | ||
| 1075 | nouveau_display_options(); | 1074 | nouveau_display_options(); |
| 1076 | 1075 | ||
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 6b97011154bf..26c6134eb744 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c | |||
| @@ -801,7 +801,6 @@ static struct drm_driver omap_drm_driver = { | |||
| 801 | .unload = dev_unload, | 801 | .unload = dev_unload, |
| 802 | .open = dev_open, | 802 | .open = dev_open, |
| 803 | .lastclose = dev_lastclose, | 803 | .lastclose = dev_lastclose, |
| 804 | .set_busid = drm_platform_set_busid, | ||
| 805 | .get_vblank_counter = drm_vblank_no_hw_counter, | 804 | .get_vblank_counter = drm_vblank_no_hw_counter, |
| 806 | .enable_vblank = omap_irq_enable_vblank, | 805 | .enable_vblank = omap_irq_enable_vblank, |
| 807 | .disable_vblank = omap_irq_disable_vblank, | 806 | .disable_vblank = omap_irq_disable_vblank, |
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 31dfa0893416..adb10fbe918d 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c | |||
| @@ -279,9 +279,6 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) | |||
| 279 | if (ret) | 279 | if (ret) |
| 280 | goto fini; | 280 | goto fini; |
| 281 | 281 | ||
| 282 | /* disable all the possible outputs/crtcs before entering KMS mode */ | ||
| 283 | drm_helper_disable_unused_functions(dev); | ||
| 284 | |||
| 285 | ret = drm_fb_helper_initial_config(helper, 32); | 282 | ret = drm_fb_helper_initial_config(helper, 32); |
| 286 | if (ret) | 283 | if (ret) |
| 287 | goto fini; | 284 | goto fini; |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 48ec4b6e8b26..d1c0512e4a9e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c | |||
| @@ -278,7 +278,6 @@ static int rcar_du_remove(struct platform_device *pdev) | |||
| 278 | struct rcar_du_device *rcdu = platform_get_drvdata(pdev); | 278 | struct rcar_du_device *rcdu = platform_get_drvdata(pdev); |
| 279 | struct drm_device *ddev = rcdu->ddev; | 279 | struct drm_device *ddev = rcdu->ddev; |
| 280 | 280 | ||
| 281 | drm_connector_unregister_all(ddev); | ||
| 282 | drm_dev_unregister(ddev); | 281 | drm_dev_unregister(ddev); |
| 283 | 282 | ||
| 284 | if (rcdu->fbdev) | 283 | if (rcdu->fbdev) |
| @@ -320,8 +319,6 @@ static int rcar_du_probe(struct platform_device *pdev) | |||
| 320 | if (!ddev) | 319 | if (!ddev) |
| 321 | return -ENOMEM; | 320 | return -ENOMEM; |
| 322 | 321 | ||
| 323 | drm_dev_set_unique(ddev, dev_name(&pdev->dev)); | ||
| 324 | |||
| 325 | rcdu->ddev = ddev; | 322 | rcdu->ddev = ddev; |
| 326 | ddev->dev_private = rcdu; | 323 | ddev->dev_private = rcdu; |
| 327 | 324 | ||
| @@ -360,10 +357,6 @@ static int rcar_du_probe(struct platform_device *pdev) | |||
| 360 | if (ret) | 357 | if (ret) |
| 361 | goto error; | 358 | goto error; |
| 362 | 359 | ||
| 363 | ret = drm_connector_register_all(ddev); | ||
| 364 | if (ret < 0) | ||
| 365 | goto error; | ||
| 366 | |||
| 367 | DRM_INFO("Device %s probed\n", dev_name(&pdev->dev)); | 360 | DRM_INFO("Device %s probed\n", dev_name(&pdev->dev)); |
| 368 | 361 | ||
| 369 | return 0; | 362 | return 0; |
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index d30bdc38a760..e48611e83c03 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig | |||
| @@ -2,6 +2,7 @@ config DRM_ROCKCHIP | |||
| 2 | tristate "DRM Support for Rockchip" | 2 | tristate "DRM Support for Rockchip" |
| 3 | depends on DRM && ROCKCHIP_IOMMU | 3 | depends on DRM && ROCKCHIP_IOMMU |
| 4 | depends on RESET_CONTROLLER | 4 | depends on RESET_CONTROLLER |
| 5 | select DRM_GEM_CMA_HELPER | ||
| 5 | select DRM_KMS_HELPER | 6 | select DRM_KMS_HELPER |
| 6 | select DRM_KMS_FB_HELPER | 7 | select DRM_KMS_FB_HELPER |
| 7 | select DRM_PANEL | 8 | select DRM_PANEL |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index c2bcc5ea1abe..d665fb04d264 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c | |||
| @@ -146,16 +146,12 @@ static int rockchip_drm_bind(struct device *dev) | |||
| 146 | if (!drm_dev) | 146 | if (!drm_dev) |
| 147 | return -ENOMEM; | 147 | return -ENOMEM; |
| 148 | 148 | ||
| 149 | ret = drm_dev_register(drm_dev, 0); | ||
| 150 | if (ret) | ||
| 151 | goto err_free; | ||
| 152 | |||
| 153 | dev_set_drvdata(dev, drm_dev); | 149 | dev_set_drvdata(dev, drm_dev); |
| 154 | 150 | ||
| 155 | private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL); | 151 | private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL); |
| 156 | if (!private) { | 152 | if (!private) { |
| 157 | ret = -ENOMEM; | 153 | ret = -ENOMEM; |
| 158 | goto err_unregister; | 154 | goto err_free; |
| 159 | } | 155 | } |
| 160 | 156 | ||
| 161 | drm_dev->dev_private = private; | 157 | drm_dev->dev_private = private; |
| @@ -197,12 +193,6 @@ static int rockchip_drm_bind(struct device *dev) | |||
| 197 | if (ret) | 193 | if (ret) |
| 198 | goto err_detach_device; | 194 | goto err_detach_device; |
| 199 | 195 | ||
| 200 | ret = drm_connector_register_all(drm_dev); | ||
| 201 | if (ret) { | ||
| 202 | dev_err(dev, "failed to register connectors\n"); | ||
| 203 | goto err_unbind; | ||
| 204 | } | ||
| 205 | |||
| 206 | /* init kms poll for handling hpd */ | 196 | /* init kms poll for handling hpd */ |
| 207 | drm_kms_helper_poll_init(drm_dev); | 197 | drm_kms_helper_poll_init(drm_dev); |
| 208 | 198 | ||
| @@ -222,14 +212,19 @@ static int rockchip_drm_bind(struct device *dev) | |||
| 222 | if (ret) | 212 | if (ret) |
| 223 | goto err_vblank_cleanup; | 213 | goto err_vblank_cleanup; |
| 224 | 214 | ||
| 215 | ret = drm_dev_register(drm_dev, 0); | ||
| 216 | if (ret) | ||
| 217 | goto err_fbdev_fini; | ||
| 218 | |||
| 225 | if (is_support_iommu) | 219 | if (is_support_iommu) |
| 226 | arm_iommu_release_mapping(mapping); | 220 | arm_iommu_release_mapping(mapping); |
| 227 | return 0; | 221 | return 0; |
| 222 | err_fbdev_fini: | ||
| 223 | rockchip_drm_fbdev_fini(drm_dev); | ||
| 228 | err_vblank_cleanup: | 224 | err_vblank_cleanup: |
| 229 | drm_vblank_cleanup(drm_dev); | 225 | drm_vblank_cleanup(drm_dev); |
| 230 | err_kms_helper_poll_fini: | 226 | err_kms_helper_poll_fini: |
| 231 | drm_kms_helper_poll_fini(drm_dev); | 227 | drm_kms_helper_poll_fini(drm_dev); |
| 232 | err_unbind: | ||
| 233 | component_unbind_all(dev, drm_dev); | 228 | component_unbind_all(dev, drm_dev); |
| 234 | err_detach_device: | 229 | err_detach_device: |
| 235 | if (is_support_iommu) | 230 | if (is_support_iommu) |
| @@ -240,8 +235,6 @@ err_release_mapping: | |||
| 240 | err_config_cleanup: | 235 | err_config_cleanup: |
| 241 | drm_mode_config_cleanup(drm_dev); | 236 | drm_mode_config_cleanup(drm_dev); |
| 242 | drm_dev->dev_private = NULL; | 237 | drm_dev->dev_private = NULL; |
| 243 | err_unregister: | ||
| 244 | drm_dev_unregister(drm_dev); | ||
| 245 | err_free: | 238 | err_free: |
| 246 | drm_dev_unref(drm_dev); | 239 | drm_dev_unref(drm_dev); |
| 247 | return ret; | 240 | return ret; |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 8cd840f602b7..6255e5bcd954 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c | |||
| @@ -626,6 +626,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane, | |||
| 626 | 626 | ||
| 627 | ret = drm_plane_helper_check_update(plane, crtc, state->fb, | 627 | ret = drm_plane_helper_check_update(plane, crtc, state->fb, |
| 628 | src, dest, &clip, | 628 | src, dest, &clip, |
| 629 | state->rotation, | ||
| 629 | min_scale, | 630 | min_scale, |
| 630 | max_scale, | 631 | max_scale, |
| 631 | true, true, &visible); | 632 | true, true, &visible); |
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index ee79264b5b6a..f0492603ea88 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c | |||
| @@ -259,7 +259,6 @@ static struct drm_driver shmob_drm_driver = { | |||
| 259 | | DRIVER_PRIME, | 259 | | DRIVER_PRIME, |
| 260 | .load = shmob_drm_load, | 260 | .load = shmob_drm_load, |
| 261 | .unload = shmob_drm_unload, | 261 | .unload = shmob_drm_unload, |
| 262 | .set_busid = drm_platform_set_busid, | ||
| 263 | .irq_handler = shmob_drm_irq, | 262 | .irq_handler = shmob_drm_irq, |
| 264 | .get_vblank_counter = drm_vblank_no_hw_counter, | 263 | .get_vblank_counter = drm_vblank_no_hw_counter, |
| 265 | .enable_vblank = shmob_drm_enable_vblank, | 264 | .enable_vblank = shmob_drm_enable_vblank, |
diff --git a/drivers/gpu/drm/sis/sis_mm.c b/drivers/gpu/drm/sis/sis_mm.c index 93ad8a5704d1..03defda77766 100644 --- a/drivers/gpu/drm/sis/sis_mm.c +++ b/drivers/gpu/drm/sis/sis_mm.c | |||
| @@ -316,7 +316,7 @@ void sis_reclaim_buffers_locked(struct drm_device *dev, | |||
| 316 | struct sis_file_private *file_priv = file->driver_priv; | 316 | struct sis_file_private *file_priv = file->driver_priv; |
| 317 | struct sis_memblock *entry, *next; | 317 | struct sis_memblock *entry, *next; |
| 318 | 318 | ||
| 319 | if (!(file->minor->master && file->master->lock.hw_lock)) | 319 | if (!(dev->master && file->master->lock.hw_lock)) |
| 320 | return; | 320 | return; |
| 321 | 321 | ||
| 322 | drm_legacy_idlelock_take(&file->master->lock); | 322 | drm_legacy_idlelock_take(&file->master->lock); |
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index 3d2fa3ab33df..794148ff0e57 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c | |||
| @@ -55,6 +55,26 @@ struct sti_compositor_data stih416_compositor_data = { | |||
| 55 | }, | 55 | }, |
| 56 | }; | 56 | }; |
| 57 | 57 | ||
| 58 | int sti_compositor_debufs_init(struct sti_compositor *compo, | ||
| 59 | struct drm_minor *minor) | ||
| 60 | { | ||
| 61 | int ret = 0, i; | ||
| 62 | |||
| 63 | for (i = 0; compo->vid[i]; i++) { | ||
| 64 | ret = vid_debugfs_init(compo->vid[i], minor); | ||
| 65 | if (ret) | ||
| 66 | return ret; | ||
| 67 | } | ||
| 68 | |||
| 69 | for (i = 0; compo->mixer[i]; i++) { | ||
| 70 | ret = sti_mixer_debugfs_init(compo->mixer[i], minor); | ||
| 71 | if (ret) | ||
| 72 | return ret; | ||
| 73 | } | ||
| 74 | |||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 58 | static int sti_compositor_bind(struct device *dev, | 78 | static int sti_compositor_bind(struct device *dev, |
| 59 | struct device *master, | 79 | struct device *master, |
| 60 | void *data) | 80 | void *data) |
diff --git a/drivers/gpu/drm/sti/sti_compositor.h b/drivers/gpu/drm/sti/sti_compositor.h index 1a4a73dab11e..24444ef42a98 100644 --- a/drivers/gpu/drm/sti/sti_compositor.h +++ b/drivers/gpu/drm/sti/sti_compositor.h | |||
| @@ -81,4 +81,7 @@ struct sti_compositor { | |||
| 81 | struct notifier_block vtg_vblank_nb; | 81 | struct notifier_block vtg_vblank_nb; |
| 82 | }; | 82 | }; |
| 83 | 83 | ||
| 84 | int sti_compositor_debufs_init(struct sti_compositor *compo, | ||
| 85 | struct drm_minor *minor); | ||
| 86 | |||
| 84 | #endif | 87 | #endif |
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index e04deedabd4a..7fab3af7473b 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c | |||
| @@ -331,6 +331,17 @@ void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe) | |||
| 331 | } | 331 | } |
| 332 | } | 332 | } |
| 333 | 333 | ||
| 334 | static int sti_crtc_late_register(struct drm_crtc *crtc) | ||
| 335 | { | ||
| 336 | struct sti_mixer *mixer = to_sti_mixer(crtc); | ||
| 337 | struct sti_compositor *compo = dev_get_drvdata(mixer->dev); | ||
| 338 | |||
| 339 | if (drm_crtc_index(crtc) == 0) | ||
| 340 | return sti_compositor_debufs_init(compo, crtc->dev->primary); | ||
| 341 | |||
| 342 | return 0; | ||
| 343 | } | ||
| 344 | |||
| 334 | static const struct drm_crtc_funcs sti_crtc_funcs = { | 345 | static const struct drm_crtc_funcs sti_crtc_funcs = { |
| 335 | .set_config = drm_atomic_helper_set_config, | 346 | .set_config = drm_atomic_helper_set_config, |
| 336 | .page_flip = drm_atomic_helper_page_flip, | 347 | .page_flip = drm_atomic_helper_page_flip, |
| @@ -339,6 +350,7 @@ static const struct drm_crtc_funcs sti_crtc_funcs = { | |||
| 339 | .reset = drm_atomic_helper_crtc_reset, | 350 | .reset = drm_atomic_helper_crtc_reset, |
| 340 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | 351 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, |
| 341 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | 352 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, |
| 353 | .late_register = sti_crtc_late_register, | ||
| 342 | }; | 354 | }; |
| 343 | 355 | ||
| 344 | bool sti_crtc_is_main(struct drm_crtc *crtc) | 356 | bool sti_crtc_is_main(struct drm_crtc *crtc) |
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index 53aa0029295b..a263bbba4119 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c | |||
| @@ -329,6 +329,33 @@ static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = { | |||
| 329 | .atomic_disable = sti_cursor_atomic_disable, | 329 | .atomic_disable = sti_cursor_atomic_disable, |
| 330 | }; | 330 | }; |
| 331 | 331 | ||
| 332 | static void sti_cursor_destroy(struct drm_plane *drm_plane) | ||
| 333 | { | ||
| 334 | DRM_DEBUG_DRIVER("\n"); | ||
| 335 | |||
| 336 | drm_plane_helper_disable(drm_plane); | ||
| 337 | drm_plane_cleanup(drm_plane); | ||
| 338 | } | ||
| 339 | |||
| 340 | static int sti_cursor_late_register(struct drm_plane *drm_plane) | ||
| 341 | { | ||
| 342 | struct sti_plane *plane = to_sti_plane(drm_plane); | ||
| 343 | struct sti_cursor *cursor = to_sti_cursor(plane); | ||
| 344 | |||
| 345 | return cursor_debugfs_init(cursor, drm_plane->dev->primary); | ||
| 346 | } | ||
| 347 | |||
| 348 | struct drm_plane_funcs sti_cursor_plane_helpers_funcs = { | ||
| 349 | .update_plane = drm_atomic_helper_update_plane, | ||
| 350 | .disable_plane = drm_atomic_helper_disable_plane, | ||
| 351 | .destroy = sti_cursor_destroy, | ||
| 352 | .set_property = sti_plane_set_property, | ||
| 353 | .reset = drm_atomic_helper_plane_reset, | ||
| 354 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | ||
| 355 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | ||
| 356 | .late_register = sti_cursor_late_register, | ||
| 357 | }; | ||
| 358 | |||
| 332 | struct drm_plane *sti_cursor_create(struct drm_device *drm_dev, | 359 | struct drm_plane *sti_cursor_create(struct drm_device *drm_dev, |
| 333 | struct device *dev, int desc, | 360 | struct device *dev, int desc, |
| 334 | void __iomem *baseaddr, | 361 | void __iomem *baseaddr, |
| @@ -363,7 +390,7 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev, | |||
| 363 | 390 | ||
| 364 | res = drm_universal_plane_init(drm_dev, &cursor->plane.drm_plane, | 391 | res = drm_universal_plane_init(drm_dev, &cursor->plane.drm_plane, |
| 365 | possible_crtcs, | 392 | possible_crtcs, |
| 366 | &sti_plane_helpers_funcs, | 393 | &sti_cursor_plane_helpers_funcs, |
| 367 | cursor_supported_formats, | 394 | cursor_supported_formats, |
| 368 | ARRAY_SIZE(cursor_supported_formats), | 395 | ARRAY_SIZE(cursor_supported_formats), |
| 369 | DRM_PLANE_TYPE_CURSOR, NULL); | 396 | DRM_PLANE_TYPE_CURSOR, NULL); |
| @@ -377,9 +404,6 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev, | |||
| 377 | 404 | ||
| 378 | sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR); | 405 | sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR); |
| 379 | 406 | ||
| 380 | if (cursor_debugfs_init(cursor, drm_dev->primary)) | ||
| 381 | DRM_ERROR("CURSOR debugfs setup failed\n"); | ||
| 382 | |||
| 383 | return &cursor->plane.drm_plane; | 407 | return &cursor->plane.drm_plane; |
| 384 | 408 | ||
| 385 | err_plane: | 409 | err_plane: |
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index dd2c400c4a46..96bd3d08b2d4 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c | |||
| @@ -226,8 +226,28 @@ static int sti_atomic_commit(struct drm_device *drm, | |||
| 226 | return 0; | 226 | return 0; |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | static void sti_output_poll_changed(struct drm_device *ddev) | ||
| 230 | { | ||
| 231 | struct sti_private *private = ddev->dev_private; | ||
| 232 | |||
| 233 | if (!ddev->mode_config.num_connector) | ||
| 234 | return; | ||
| 235 | |||
| 236 | if (private->fbdev) { | ||
| 237 | drm_fbdev_cma_hotplug_event(private->fbdev); | ||
| 238 | return; | ||
| 239 | } | ||
| 240 | |||
| 241 | private->fbdev = drm_fbdev_cma_init(ddev, 32, | ||
| 242 | ddev->mode_config.num_crtc, | ||
| 243 | ddev->mode_config.num_connector); | ||
| 244 | if (IS_ERR(private->fbdev)) | ||
| 245 | private->fbdev = NULL; | ||
| 246 | } | ||
| 247 | |||
| 229 | static const struct drm_mode_config_funcs sti_mode_config_funcs = { | 248 | static const struct drm_mode_config_funcs sti_mode_config_funcs = { |
| 230 | .fb_create = drm_fb_cma_create, | 249 | .fb_create = drm_fb_cma_create, |
| 250 | .output_poll_changed = sti_output_poll_changed, | ||
| 231 | .atomic_check = drm_atomic_helper_check, | 251 | .atomic_check = drm_atomic_helper_check, |
| 232 | .atomic_commit = sti_atomic_commit, | 252 | .atomic_commit = sti_atomic_commit, |
| 233 | }; | 253 | }; |
| @@ -248,45 +268,6 @@ static void sti_mode_config_init(struct drm_device *dev) | |||
| 248 | dev->mode_config.funcs = &sti_mode_config_funcs; | 268 | dev->mode_config.funcs = &sti_mode_config_funcs; |
| 249 | } | 269 | } |
| 250 | 270 | ||
| 251 | static int sti_load(struct drm_device *dev, unsigned long flags) | ||
| 252 | { | ||
| 253 | struct sti_private *private; | ||
| 254 | int ret; | ||
| 255 | |||
| 256 | private = kzalloc(sizeof(*private), GFP_KERNEL); | ||
| 257 | if (!private) { | ||
| 258 | DRM_ERROR("Failed to allocate private\n"); | ||
| 259 | return -ENOMEM; | ||
| 260 | } | ||
| 261 | dev->dev_private = (void *)private; | ||
| 262 | private->drm_dev = dev; | ||
| 263 | |||
| 264 | mutex_init(&private->commit.lock); | ||
| 265 | INIT_WORK(&private->commit.work, sti_atomic_work); | ||
| 266 | |||
| 267 | drm_mode_config_init(dev); | ||
| 268 | drm_kms_helper_poll_init(dev); | ||
| 269 | |||
| 270 | sti_mode_config_init(dev); | ||
| 271 | |||
| 272 | ret = component_bind_all(dev->dev, dev); | ||
| 273 | if (ret) { | ||
| 274 | drm_kms_helper_poll_fini(dev); | ||
| 275 | drm_mode_config_cleanup(dev); | ||
| 276 | kfree(private); | ||
| 277 | return ret; | ||
| 278 | } | ||
| 279 | |||
| 280 | drm_mode_config_reset(dev); | ||
| 281 | |||
| 282 | drm_helper_disable_unused_functions(dev); | ||
| 283 | drm_fbdev_cma_init(dev, 32, | ||
| 284 | dev->mode_config.num_crtc, | ||
| 285 | dev->mode_config.num_connector); | ||
| 286 | |||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | |||
| 290 | static const struct file_operations sti_driver_fops = { | 271 | static const struct file_operations sti_driver_fops = { |
| 291 | .owner = THIS_MODULE, | 272 | .owner = THIS_MODULE, |
| 292 | .open = drm_open, | 273 | .open = drm_open, |
| @@ -303,7 +284,6 @@ static const struct file_operations sti_driver_fops = { | |||
| 303 | static struct drm_driver sti_driver = { | 284 | static struct drm_driver sti_driver = { |
| 304 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | | 285 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | |
| 305 | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, | 286 | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, |
| 306 | .load = sti_load, | ||
| 307 | .gem_free_object_unlocked = drm_gem_cma_free_object, | 287 | .gem_free_object_unlocked = drm_gem_cma_free_object, |
| 308 | .gem_vm_ops = &drm_gem_cma_vm_ops, | 288 | .gem_vm_ops = &drm_gem_cma_vm_ops, |
| 309 | .dumb_create = drm_gem_cma_dumb_create, | 289 | .dumb_create = drm_gem_cma_dumb_create, |
| @@ -340,14 +320,88 @@ static int compare_of(struct device *dev, void *data) | |||
| 340 | return dev->of_node == data; | 320 | return dev->of_node == data; |
| 341 | } | 321 | } |
| 342 | 322 | ||
| 323 | static int sti_init(struct drm_device *ddev) | ||
| 324 | { | ||
| 325 | struct sti_private *private; | ||
| 326 | |||
| 327 | private = kzalloc(sizeof(*private), GFP_KERNEL); | ||
| 328 | if (!private) | ||
| 329 | return -ENOMEM; | ||
| 330 | |||
| 331 | ddev->dev_private = (void *)private; | ||
| 332 | dev_set_drvdata(ddev->dev, ddev); | ||
| 333 | private->drm_dev = ddev; | ||
| 334 | |||
| 335 | mutex_init(&private->commit.lock); | ||
| 336 | INIT_WORK(&private->commit.work, sti_atomic_work); | ||
| 337 | |||
| 338 | drm_mode_config_init(ddev); | ||
| 339 | |||
| 340 | sti_mode_config_init(ddev); | ||
| 341 | |||
| 342 | drm_kms_helper_poll_init(ddev); | ||
| 343 | |||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | |||
| 347 | static void sti_cleanup(struct drm_device *ddev) | ||
| 348 | { | ||
| 349 | struct sti_private *private = ddev->dev_private; | ||
| 350 | |||
| 351 | if (private->fbdev) { | ||
| 352 | drm_fbdev_cma_fini(private->fbdev); | ||
| 353 | private->fbdev = NULL; | ||
| 354 | } | ||
| 355 | |||
| 356 | drm_kms_helper_poll_fini(ddev); | ||
| 357 | drm_vblank_cleanup(ddev); | ||
| 358 | kfree(private); | ||
| 359 | ddev->dev_private = NULL; | ||
| 360 | } | ||
| 361 | |||
| 343 | static int sti_bind(struct device *dev) | 362 | static int sti_bind(struct device *dev) |
| 344 | { | 363 | { |
| 345 | return drm_platform_init(&sti_driver, to_platform_device(dev)); | 364 | struct drm_device *ddev; |
| 365 | int ret; | ||
| 366 | |||
| 367 | ddev = drm_dev_alloc(&sti_driver, dev); | ||
| 368 | if (!ddev) | ||
| 369 | return -ENOMEM; | ||
| 370 | |||
| 371 | ddev->platformdev = to_platform_device(dev); | ||
| 372 | |||
| 373 | ret = sti_init(ddev); | ||
| 374 | if (ret) | ||
| 375 | goto err_drm_dev_unref; | ||
| 376 | |||
| 377 | ret = component_bind_all(ddev->dev, ddev); | ||
| 378 | if (ret) | ||
| 379 | goto err_cleanup; | ||
| 380 | |||
| 381 | ret = drm_dev_register(ddev, 0); | ||
| 382 | if (ret) | ||
| 383 | goto err_register; | ||
| 384 | |||
| 385 | drm_mode_config_reset(ddev); | ||
| 386 | |||
| 387 | return 0; | ||
| 388 | |||
| 389 | err_register: | ||
| 390 | drm_mode_config_cleanup(ddev); | ||
| 391 | err_cleanup: | ||
| 392 | sti_cleanup(ddev); | ||
| 393 | err_drm_dev_unref: | ||
| 394 | drm_dev_unref(ddev); | ||
| 395 | return ret; | ||
| 346 | } | 396 | } |
| 347 | 397 | ||
| 348 | static void sti_unbind(struct device *dev) | 398 | static void sti_unbind(struct device *dev) |
| 349 | { | 399 | { |
| 350 | drm_put_dev(dev_get_drvdata(dev)); | 400 | struct drm_device *ddev = dev_get_drvdata(dev); |
| 401 | |||
| 402 | drm_dev_unregister(ddev); | ||
| 403 | sti_cleanup(ddev); | ||
| 404 | drm_dev_unref(ddev); | ||
| 351 | } | 405 | } |
| 352 | 406 | ||
| 353 | static const struct component_master_ops sti_ops = { | 407 | static const struct component_master_ops sti_ops = { |
diff --git a/drivers/gpu/drm/sti/sti_drv.h b/drivers/gpu/drm/sti/sti_drv.h index 30ddc20841c3..78ebe5e30f53 100644 --- a/drivers/gpu/drm/sti/sti_drv.h +++ b/drivers/gpu/drm/sti/sti_drv.h | |||
| @@ -24,6 +24,7 @@ struct sti_private { | |||
| 24 | struct sti_compositor *compo; | 24 | struct sti_compositor *compo; |
| 25 | struct drm_property *plane_zorder_property; | 25 | struct drm_property *plane_zorder_property; |
| 26 | struct drm_device *drm_dev; | 26 | struct drm_device *drm_dev; |
| 27 | struct drm_fbdev_cma *fbdev; | ||
| 27 | 28 | ||
| 28 | struct { | 29 | struct { |
| 29 | struct drm_atomic_state *state; | 30 | struct drm_atomic_state *state; |
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index e2901667eceb..ec3108074350 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c | |||
| @@ -404,24 +404,29 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force) | |||
| 404 | return connector_status_disconnected; | 404 | return connector_status_disconnected; |
| 405 | } | 405 | } |
| 406 | 406 | ||
| 407 | static void sti_dvo_connector_destroy(struct drm_connector *connector) | 407 | static int sti_dvo_late_register(struct drm_connector *connector) |
| 408 | { | 408 | { |
| 409 | struct sti_dvo_connector *dvo_connector | 409 | struct sti_dvo_connector *dvo_connector |
| 410 | = to_sti_dvo_connector(connector); | 410 | = to_sti_dvo_connector(connector); |
| 411 | struct sti_dvo *dvo = dvo_connector->dvo; | ||
| 412 | |||
| 413 | if (dvo_debugfs_init(dvo, dvo->drm_dev->primary)) { | ||
| 414 | DRM_ERROR("DVO debugfs setup failed\n"); | ||
| 415 | return -EINVAL; | ||
| 416 | } | ||
| 411 | 417 | ||
| 412 | drm_connector_unregister(connector); | 418 | return 0; |
| 413 | drm_connector_cleanup(connector); | ||
| 414 | kfree(dvo_connector); | ||
| 415 | } | 419 | } |
| 416 | 420 | ||
| 417 | static const struct drm_connector_funcs sti_dvo_connector_funcs = { | 421 | static const struct drm_connector_funcs sti_dvo_connector_funcs = { |
| 418 | .dpms = drm_atomic_helper_connector_dpms, | 422 | .dpms = drm_atomic_helper_connector_dpms, |
| 419 | .fill_modes = drm_helper_probe_single_connector_modes, | 423 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 420 | .detect = sti_dvo_connector_detect, | 424 | .detect = sti_dvo_connector_detect, |
| 421 | .destroy = sti_dvo_connector_destroy, | 425 | .destroy = drm_connector_cleanup, |
| 422 | .reset = drm_atomic_helper_connector_reset, | 426 | .reset = drm_atomic_helper_connector_reset, |
| 423 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 427 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
| 424 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 428 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| 429 | .late_register = sti_dvo_late_register, | ||
| 425 | }; | 430 | }; |
| 426 | 431 | ||
| 427 | static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev) | 432 | static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev) |
| @@ -492,26 +497,16 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) | |||
| 492 | drm_connector_helper_add(drm_connector, | 497 | drm_connector_helper_add(drm_connector, |
| 493 | &sti_dvo_connector_helper_funcs); | 498 | &sti_dvo_connector_helper_funcs); |
| 494 | 499 | ||
| 495 | err = drm_connector_register(drm_connector); | ||
| 496 | if (err) | ||
| 497 | goto err_connector; | ||
| 498 | |||
| 499 | err = drm_mode_connector_attach_encoder(drm_connector, encoder); | 500 | err = drm_mode_connector_attach_encoder(drm_connector, encoder); |
| 500 | if (err) { | 501 | if (err) { |
| 501 | DRM_ERROR("Failed to attach a connector to a encoder\n"); | 502 | DRM_ERROR("Failed to attach a connector to a encoder\n"); |
| 502 | goto err_sysfs; | 503 | goto err_sysfs; |
| 503 | } | 504 | } |
| 504 | 505 | ||
| 505 | if (dvo_debugfs_init(dvo, drm_dev->primary)) | ||
| 506 | DRM_ERROR("DVO debugfs setup failed\n"); | ||
| 507 | |||
| 508 | return 0; | 506 | return 0; |
| 509 | 507 | ||
| 510 | err_sysfs: | 508 | err_sysfs: |
| 511 | drm_connector_unregister(drm_connector); | ||
| 512 | err_connector: | ||
| 513 | drm_bridge_remove(bridge); | 509 | drm_bridge_remove(bridge); |
| 514 | drm_connector_cleanup(drm_connector); | ||
| 515 | return -EINVAL; | 510 | return -EINVAL; |
| 516 | } | 511 | } |
| 517 | 512 | ||
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index fdf69b5a041b..bf63086a3dc8 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c | |||
| @@ -866,6 +866,33 @@ static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = { | |||
| 866 | .atomic_disable = sti_gdp_atomic_disable, | 866 | .atomic_disable = sti_gdp_atomic_disable, |
| 867 | }; | 867 | }; |
| 868 | 868 | ||
| 869 | static void sti_gdp_destroy(struct drm_plane *drm_plane) | ||
| 870 | { | ||
| 871 | DRM_DEBUG_DRIVER("\n"); | ||
| 872 | |||
| 873 | drm_plane_helper_disable(drm_plane); | ||
| 874 | drm_plane_cleanup(drm_plane); | ||
| 875 | } | ||
| 876 | |||
| 877 | static int sti_gdp_late_register(struct drm_plane *drm_plane) | ||
| 878 | { | ||
| 879 | struct sti_plane *plane = to_sti_plane(drm_plane); | ||
| 880 | struct sti_gdp *gdp = to_sti_gdp(plane); | ||
| 881 | |||
| 882 | return gdp_debugfs_init(gdp, drm_plane->dev->primary); | ||
| 883 | } | ||
| 884 | |||
| 885 | struct drm_plane_funcs sti_gdp_plane_helpers_funcs = { | ||
| 886 | .update_plane = drm_atomic_helper_update_plane, | ||
| 887 | .disable_plane = drm_atomic_helper_disable_plane, | ||
| 888 | .destroy = sti_gdp_destroy, | ||
| 889 | .set_property = sti_plane_set_property, | ||
| 890 | .reset = drm_atomic_helper_plane_reset, | ||
| 891 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | ||
| 892 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | ||
| 893 | .late_register = sti_gdp_late_register, | ||
| 894 | }; | ||
| 895 | |||
| 869 | struct drm_plane *sti_gdp_create(struct drm_device *drm_dev, | 896 | struct drm_plane *sti_gdp_create(struct drm_device *drm_dev, |
| 870 | struct device *dev, int desc, | 897 | struct device *dev, int desc, |
| 871 | void __iomem *baseaddr, | 898 | void __iomem *baseaddr, |
| @@ -892,7 +919,7 @@ struct drm_plane *sti_gdp_create(struct drm_device *drm_dev, | |||
| 892 | 919 | ||
| 893 | res = drm_universal_plane_init(drm_dev, &gdp->plane.drm_plane, | 920 | res = drm_universal_plane_init(drm_dev, &gdp->plane.drm_plane, |
| 894 | possible_crtcs, | 921 | possible_crtcs, |
| 895 | &sti_plane_helpers_funcs, | 922 | &sti_gdp_plane_helpers_funcs, |
| 896 | gdp_supported_formats, | 923 | gdp_supported_formats, |
| 897 | ARRAY_SIZE(gdp_supported_formats), | 924 | ARRAY_SIZE(gdp_supported_formats), |
| 898 | type, NULL); | 925 | type, NULL); |
| @@ -905,9 +932,6 @@ struct drm_plane *sti_gdp_create(struct drm_device *drm_dev, | |||
| 905 | 932 | ||
| 906 | sti_plane_init_property(&gdp->plane, type); | 933 | sti_plane_init_property(&gdp->plane, type); |
| 907 | 934 | ||
| 908 | if (gdp_debugfs_init(gdp, drm_dev->primary)) | ||
| 909 | DRM_ERROR("GDP debugfs setup failed\n"); | ||
| 910 | |||
| 911 | return &gdp->plane.drm_plane; | 935 | return &gdp->plane.drm_plane; |
| 912 | 936 | ||
| 913 | err: | 937 | err: |
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index dcec5a8eda59..8505569f75de 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c | |||
| @@ -681,24 +681,29 @@ sti_hda_connector_detect(struct drm_connector *connector, bool force) | |||
| 681 | return connector_status_connected; | 681 | return connector_status_connected; |
| 682 | } | 682 | } |
| 683 | 683 | ||
| 684 | static void sti_hda_connector_destroy(struct drm_connector *connector) | 684 | static int sti_hda_late_register(struct drm_connector *connector) |
| 685 | { | 685 | { |
| 686 | struct sti_hda_connector *hda_connector | 686 | struct sti_hda_connector *hda_connector |
| 687 | = to_sti_hda_connector(connector); | 687 | = to_sti_hda_connector(connector); |
| 688 | struct sti_hda *hda = hda_connector->hda; | ||
| 689 | |||
| 690 | if (hda_debugfs_init(hda, hda->drm_dev->primary)) { | ||
| 691 | DRM_ERROR("HDA debugfs setup failed\n"); | ||
| 692 | return -EINVAL; | ||
| 693 | } | ||
| 688 | 694 | ||
| 689 | drm_connector_unregister(connector); | 695 | return 0; |
| 690 | drm_connector_cleanup(connector); | ||
| 691 | kfree(hda_connector); | ||
| 692 | } | 696 | } |
| 693 | 697 | ||
| 694 | static const struct drm_connector_funcs sti_hda_connector_funcs = { | 698 | static const struct drm_connector_funcs sti_hda_connector_funcs = { |
| 695 | .dpms = drm_atomic_helper_connector_dpms, | 699 | .dpms = drm_atomic_helper_connector_dpms, |
| 696 | .fill_modes = drm_helper_probe_single_connector_modes, | 700 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 697 | .detect = sti_hda_connector_detect, | 701 | .detect = sti_hda_connector_detect, |
| 698 | .destroy = sti_hda_connector_destroy, | 702 | .destroy = drm_connector_cleanup, |
| 699 | .reset = drm_atomic_helper_connector_reset, | 703 | .reset = drm_atomic_helper_connector_reset, |
| 700 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 704 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
| 701 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 705 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| 706 | .late_register = sti_hda_late_register, | ||
| 702 | }; | 707 | }; |
| 703 | 708 | ||
| 704 | static struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev) | 709 | static struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev) |
| @@ -756,10 +761,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) | |||
| 756 | drm_connector_helper_add(drm_connector, | 761 | drm_connector_helper_add(drm_connector, |
| 757 | &sti_hda_connector_helper_funcs); | 762 | &sti_hda_connector_helper_funcs); |
| 758 | 763 | ||
| 759 | err = drm_connector_register(drm_connector); | ||
| 760 | if (err) | ||
| 761 | goto err_connector; | ||
| 762 | |||
| 763 | err = drm_mode_connector_attach_encoder(drm_connector, encoder); | 764 | err = drm_mode_connector_attach_encoder(drm_connector, encoder); |
| 764 | if (err) { | 765 | if (err) { |
| 765 | DRM_ERROR("Failed to attach a connector to a encoder\n"); | 766 | DRM_ERROR("Failed to attach a connector to a encoder\n"); |
| @@ -769,15 +770,10 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) | |||
| 769 | /* force to disable hd dacs at startup */ | 770 | /* force to disable hd dacs at startup */ |
| 770 | hda_enable_hd_dacs(hda, false); | 771 | hda_enable_hd_dacs(hda, false); |
| 771 | 772 | ||
| 772 | if (hda_debugfs_init(hda, drm_dev->primary)) | ||
| 773 | DRM_ERROR("HDA debugfs setup failed\n"); | ||
| 774 | |||
| 775 | return 0; | 773 | return 0; |
| 776 | 774 | ||
| 777 | err_sysfs: | 775 | err_sysfs: |
| 778 | drm_connector_unregister(drm_connector); | 776 | drm_bridge_remove(bridge); |
| 779 | err_connector: | ||
| 780 | drm_connector_cleanup(drm_connector); | ||
| 781 | return -EINVAL; | 777 | return -EINVAL; |
| 782 | } | 778 | } |
| 783 | 779 | ||
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 36d9d6635784..8d1402b245bf 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c | |||
| @@ -915,16 +915,6 @@ sti_hdmi_connector_detect(struct drm_connector *connector, bool force) | |||
| 915 | return connector_status_disconnected; | 915 | return connector_status_disconnected; |
| 916 | } | 916 | } |
| 917 | 917 | ||
| 918 | static void sti_hdmi_connector_destroy(struct drm_connector *connector) | ||
| 919 | { | ||
| 920 | struct sti_hdmi_connector *hdmi_connector | ||
| 921 | = to_sti_hdmi_connector(connector); | ||
| 922 | |||
| 923 | drm_connector_unregister(connector); | ||
| 924 | drm_connector_cleanup(connector); | ||
| 925 | kfree(hdmi_connector); | ||
| 926 | } | ||
| 927 | |||
| 928 | static void sti_hdmi_connector_init_property(struct drm_device *drm_dev, | 918 | static void sti_hdmi_connector_init_property(struct drm_device *drm_dev, |
| 929 | struct drm_connector *connector) | 919 | struct drm_connector *connector) |
| 930 | { | 920 | { |
| @@ -1007,17 +997,31 @@ sti_hdmi_connector_get_property(struct drm_connector *connector, | |||
| 1007 | return -EINVAL; | 997 | return -EINVAL; |
| 1008 | } | 998 | } |
| 1009 | 999 | ||
| 1000 | static int sti_hdmi_late_register(struct drm_connector *connector) | ||
| 1001 | { | ||
| 1002 | struct sti_hdmi_connector *hdmi_connector | ||
| 1003 | = to_sti_hdmi_connector(connector); | ||
| 1004 | struct sti_hdmi *hdmi = hdmi_connector->hdmi; | ||
| 1005 | |||
| 1006 | if (hdmi_debugfs_init(hdmi, hdmi->drm_dev->primary)) { | ||
| 1007 | DRM_ERROR("HDMI debugfs setup failed\n"); | ||
| 1008 | return -EINVAL; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | return 0; | ||
| 1012 | } | ||
| 1013 | |||
| 1010 | static const struct drm_connector_funcs sti_hdmi_connector_funcs = { | 1014 | static const struct drm_connector_funcs sti_hdmi_connector_funcs = { |
| 1011 | .dpms = drm_atomic_helper_connector_dpms, | ||
| 1012 | .fill_modes = drm_helper_probe_single_connector_modes, | 1015 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 1013 | .detect = sti_hdmi_connector_detect, | 1016 | .detect = sti_hdmi_connector_detect, |
| 1014 | .destroy = sti_hdmi_connector_destroy, | 1017 | .destroy = drm_connector_cleanup, |
| 1015 | .reset = drm_atomic_helper_connector_reset, | 1018 | .reset = drm_atomic_helper_connector_reset, |
| 1016 | .set_property = drm_atomic_helper_connector_set_property, | 1019 | .set_property = drm_atomic_helper_connector_set_property, |
| 1017 | .atomic_set_property = sti_hdmi_connector_set_property, | 1020 | .atomic_set_property = sti_hdmi_connector_set_property, |
| 1018 | .atomic_get_property = sti_hdmi_connector_get_property, | 1021 | .atomic_get_property = sti_hdmi_connector_get_property, |
| 1019 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 1022 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
| 1020 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 1023 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| 1024 | .late_register = sti_hdmi_late_register, | ||
| 1021 | }; | 1025 | }; |
| 1022 | 1026 | ||
| 1023 | static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev) | 1027 | static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev) |
| @@ -1078,10 +1082,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
| 1078 | /* initialise property */ | 1082 | /* initialise property */ |
| 1079 | sti_hdmi_connector_init_property(drm_dev, drm_connector); | 1083 | sti_hdmi_connector_init_property(drm_dev, drm_connector); |
| 1080 | 1084 | ||
| 1081 | err = drm_connector_register(drm_connector); | ||
| 1082 | if (err) | ||
| 1083 | goto err_connector; | ||
| 1084 | |||
| 1085 | err = drm_mode_connector_attach_encoder(drm_connector, encoder); | 1085 | err = drm_mode_connector_attach_encoder(drm_connector, encoder); |
| 1086 | if (err) { | 1086 | if (err) { |
| 1087 | DRM_ERROR("Failed to attach a connector to a encoder\n"); | 1087 | DRM_ERROR("Failed to attach a connector to a encoder\n"); |
| @@ -1091,16 +1091,10 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
| 1091 | /* Enable default interrupts */ | 1091 | /* Enable default interrupts */ |
| 1092 | hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN); | 1092 | hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN); |
| 1093 | 1093 | ||
| 1094 | if (hdmi_debugfs_init(hdmi, drm_dev->primary)) | ||
| 1095 | DRM_ERROR("HDMI debugfs setup failed\n"); | ||
| 1096 | |||
| 1097 | return 0; | 1094 | return 0; |
| 1098 | 1095 | ||
| 1099 | err_sysfs: | 1096 | err_sysfs: |
| 1100 | drm_connector_unregister(drm_connector); | 1097 | drm_bridge_remove(bridge); |
| 1101 | err_connector: | ||
| 1102 | drm_connector_cleanup(drm_connector); | ||
| 1103 | |||
| 1104 | return -EINVAL; | 1098 | return -EINVAL; |
| 1105 | } | 1099 | } |
| 1106 | 1100 | ||
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index 1c06a50fddca..33d2f42550cc 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c | |||
| @@ -1234,6 +1234,33 @@ static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = { | |||
| 1234 | .atomic_disable = sti_hqvdp_atomic_disable, | 1234 | .atomic_disable = sti_hqvdp_atomic_disable, |
| 1235 | }; | 1235 | }; |
| 1236 | 1236 | ||
| 1237 | static void sti_hqvdp_destroy(struct drm_plane *drm_plane) | ||
| 1238 | { | ||
| 1239 | DRM_DEBUG_DRIVER("\n"); | ||
| 1240 | |||
| 1241 | drm_plane_helper_disable(drm_plane); | ||
| 1242 | drm_plane_cleanup(drm_plane); | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | static int sti_hqvdp_late_register(struct drm_plane *drm_plane) | ||
| 1246 | { | ||
| 1247 | struct sti_plane *plane = to_sti_plane(drm_plane); | ||
| 1248 | struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); | ||
| 1249 | |||
| 1250 | return hqvdp_debugfs_init(hqvdp, drm_plane->dev->primary); | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | struct drm_plane_funcs sti_hqvdp_plane_helpers_funcs = { | ||
| 1254 | .update_plane = drm_atomic_helper_update_plane, | ||
| 1255 | .disable_plane = drm_atomic_helper_disable_plane, | ||
| 1256 | .destroy = sti_hqvdp_destroy, | ||
| 1257 | .set_property = sti_plane_set_property, | ||
| 1258 | .reset = drm_atomic_helper_plane_reset, | ||
| 1259 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | ||
| 1260 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | ||
| 1261 | .late_register = sti_hqvdp_late_register, | ||
| 1262 | }; | ||
| 1263 | |||
| 1237 | static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev, | 1264 | static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev, |
| 1238 | struct device *dev, int desc) | 1265 | struct device *dev, int desc) |
| 1239 | { | 1266 | { |
| @@ -1246,7 +1273,7 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev, | |||
| 1246 | sti_hqvdp_init(hqvdp); | 1273 | sti_hqvdp_init(hqvdp); |
| 1247 | 1274 | ||
| 1248 | res = drm_universal_plane_init(drm_dev, &hqvdp->plane.drm_plane, 1, | 1275 | res = drm_universal_plane_init(drm_dev, &hqvdp->plane.drm_plane, 1, |
| 1249 | &sti_plane_helpers_funcs, | 1276 | &sti_hqvdp_plane_helpers_funcs, |
| 1250 | hqvdp_supported_formats, | 1277 | hqvdp_supported_formats, |
| 1251 | ARRAY_SIZE(hqvdp_supported_formats), | 1278 | ARRAY_SIZE(hqvdp_supported_formats), |
| 1252 | DRM_PLANE_TYPE_OVERLAY, NULL); | 1279 | DRM_PLANE_TYPE_OVERLAY, NULL); |
| @@ -1259,9 +1286,6 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev, | |||
| 1259 | 1286 | ||
| 1260 | sti_plane_init_property(&hqvdp->plane, DRM_PLANE_TYPE_OVERLAY); | 1287 | sti_plane_init_property(&hqvdp->plane, DRM_PLANE_TYPE_OVERLAY); |
| 1261 | 1288 | ||
| 1262 | if (hqvdp_debugfs_init(hqvdp, drm_dev->primary)) | ||
| 1263 | DRM_ERROR("HQVDP debugfs setup failed\n"); | ||
| 1264 | |||
| 1265 | return &hqvdp->plane.drm_plane; | 1289 | return &hqvdp->plane.drm_plane; |
| 1266 | } | 1290 | } |
| 1267 | 1291 | ||
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c index 6f86f2b2b6a5..1885c7ab5a8b 100644 --- a/drivers/gpu/drm/sti/sti_mixer.c +++ b/drivers/gpu/drm/sti/sti_mixer.c | |||
| @@ -181,7 +181,7 @@ static struct drm_info_list mixer1_debugfs_files[] = { | |||
| 181 | { "mixer_aux", mixer_dbg_show, 0, NULL }, | 181 | { "mixer_aux", mixer_dbg_show, 0, NULL }, |
| 182 | }; | 182 | }; |
| 183 | 183 | ||
| 184 | static int mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor) | 184 | int sti_mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor) |
| 185 | { | 185 | { |
| 186 | unsigned int i; | 186 | unsigned int i; |
| 187 | struct drm_info_list *mixer_debugfs_files; | 187 | struct drm_info_list *mixer_debugfs_files; |
| @@ -393,8 +393,5 @@ struct sti_mixer *sti_mixer_create(struct device *dev, | |||
| 393 | DRM_DEBUG_DRIVER("%s created. Regs=%p\n", | 393 | DRM_DEBUG_DRIVER("%s created. Regs=%p\n", |
| 394 | sti_mixer_to_str(mixer), mixer->regs); | 394 | sti_mixer_to_str(mixer), mixer->regs); |
| 395 | 395 | ||
| 396 | if (mixer_debugfs_init(mixer, drm_dev->primary)) | ||
| 397 | DRM_ERROR("MIXER debugfs setup failed\n"); | ||
| 398 | |||
| 399 | return mixer; | 396 | return mixer; |
| 400 | } | 397 | } |
diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h index 6f35fc086873..830a3c42d886 100644 --- a/drivers/gpu/drm/sti/sti_mixer.h +++ b/drivers/gpu/drm/sti/sti_mixer.h | |||
| @@ -55,6 +55,8 @@ int sti_mixer_active_video_area(struct sti_mixer *mixer, | |||
| 55 | 55 | ||
| 56 | void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable); | 56 | void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable); |
| 57 | 57 | ||
| 58 | int sti_mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor); | ||
| 59 | |||
| 58 | /* depth in Cross-bar control = z order */ | 60 | /* depth in Cross-bar control = z order */ |
| 59 | #define GAM_MIXER_NB_DEPTH_LEVEL 6 | 61 | #define GAM_MIXER_NB_DEPTH_LEVEL 6 |
| 60 | 62 | ||
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c index f10c98d3f012..85cee9098439 100644 --- a/drivers/gpu/drm/sti/sti_plane.c +++ b/drivers/gpu/drm/sti/sti_plane.c | |||
| @@ -106,17 +106,9 @@ void sti_plane_update_fps(struct sti_plane *plane, | |||
| 106 | plane->fps_info.fips_str); | 106 | plane->fps_info.fips_str); |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | static void sti_plane_destroy(struct drm_plane *drm_plane) | 109 | int sti_plane_set_property(struct drm_plane *drm_plane, |
| 110 | { | 110 | struct drm_property *property, |
| 111 | DRM_DEBUG_DRIVER("\n"); | 111 | uint64_t val) |
| 112 | |||
| 113 | drm_plane_helper_disable(drm_plane); | ||
| 114 | drm_plane_cleanup(drm_plane); | ||
| 115 | } | ||
| 116 | |||
| 117 | static int sti_plane_set_property(struct drm_plane *drm_plane, | ||
| 118 | struct drm_property *property, | ||
| 119 | uint64_t val) | ||
| 120 | { | 112 | { |
| 121 | struct drm_device *dev = drm_plane->dev; | 113 | struct drm_device *dev = drm_plane->dev; |
| 122 | struct sti_private *private = dev->dev_private; | 114 | struct sti_private *private = dev->dev_private; |
| @@ -170,13 +162,3 @@ void sti_plane_init_property(struct sti_plane *plane, | |||
| 170 | plane->drm_plane.base.id, | 162 | plane->drm_plane.base.id, |
| 171 | sti_plane_to_str(plane), plane->zorder); | 163 | sti_plane_to_str(plane), plane->zorder); |
| 172 | } | 164 | } |
| 173 | |||
| 174 | struct drm_plane_funcs sti_plane_helpers_funcs = { | ||
| 175 | .update_plane = drm_atomic_helper_update_plane, | ||
| 176 | .disable_plane = drm_atomic_helper_disable_plane, | ||
| 177 | .destroy = sti_plane_destroy, | ||
| 178 | .set_property = sti_plane_set_property, | ||
| 179 | .reset = drm_atomic_helper_plane_reset, | ||
| 180 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | ||
| 181 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | ||
| 182 | }; | ||
diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h index c50a3b9f5d37..39d39f5b7dd9 100644 --- a/drivers/gpu/drm/sti/sti_plane.h +++ b/drivers/gpu/drm/sti/sti_plane.h | |||
| @@ -11,8 +11,6 @@ | |||
| 11 | #include <drm/drm_atomic_helper.h> | 11 | #include <drm/drm_atomic_helper.h> |
| 12 | #include <drm/drm_plane_helper.h> | 12 | #include <drm/drm_plane_helper.h> |
| 13 | 13 | ||
| 14 | extern struct drm_plane_funcs sti_plane_helpers_funcs; | ||
| 15 | |||
| 16 | #define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane) | 14 | #define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane) |
| 17 | 15 | ||
| 18 | #define STI_PLANE_TYPE_SHIFT 8 | 16 | #define STI_PLANE_TYPE_SHIFT 8 |
| @@ -83,6 +81,11 @@ const char *sti_plane_to_str(struct sti_plane *plane); | |||
| 83 | void sti_plane_update_fps(struct sti_plane *plane, | 81 | void sti_plane_update_fps(struct sti_plane *plane, |
| 84 | bool new_frame, | 82 | bool new_frame, |
| 85 | bool new_field); | 83 | bool new_field); |
| 84 | |||
| 85 | int sti_plane_set_property(struct drm_plane *drm_plane, | ||
| 86 | struct drm_property *property, | ||
| 87 | uint64_t val); | ||
| 88 | |||
| 86 | void sti_plane_init_property(struct sti_plane *plane, | 89 | void sti_plane_init_property(struct sti_plane *plane, |
| 87 | enum drm_plane_type type); | 90 | enum drm_plane_type type); |
| 88 | #endif | 91 | #endif |
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index 60fe0afa5644..e25995b35715 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c | |||
| @@ -112,6 +112,7 @@ struct sti_tvout { | |||
| 112 | struct drm_encoder *hdmi; | 112 | struct drm_encoder *hdmi; |
| 113 | struct drm_encoder *hda; | 113 | struct drm_encoder *hda; |
| 114 | struct drm_encoder *dvo; | 114 | struct drm_encoder *dvo; |
| 115 | bool debugfs_registered; | ||
| 115 | }; | 116 | }; |
| 116 | 117 | ||
| 117 | struct sti_tvout_encoder { | 118 | struct sti_tvout_encoder { |
| @@ -625,8 +626,37 @@ static void sti_tvout_encoder_destroy(struct drm_encoder *encoder) | |||
| 625 | kfree(sti_encoder); | 626 | kfree(sti_encoder); |
| 626 | } | 627 | } |
| 627 | 628 | ||
| 629 | static int sti_tvout_late_register(struct drm_encoder *encoder) | ||
| 630 | { | ||
| 631 | struct sti_tvout *tvout = to_sti_tvout(encoder); | ||
| 632 | int ret; | ||
| 633 | |||
| 634 | if (tvout->debugfs_registered) | ||
| 635 | return 0; | ||
| 636 | |||
| 637 | ret = tvout_debugfs_init(tvout, encoder->dev->primary); | ||
| 638 | if (ret) | ||
| 639 | return ret; | ||
| 640 | |||
| 641 | tvout->debugfs_registered = true; | ||
| 642 | return 0; | ||
| 643 | } | ||
| 644 | |||
| 645 | static void sti_tvout_early_unregister(struct drm_encoder *encoder) | ||
| 646 | { | ||
| 647 | struct sti_tvout *tvout = to_sti_tvout(encoder); | ||
| 648 | |||
| 649 | if (!tvout->debugfs_registered) | ||
| 650 | return; | ||
| 651 | |||
| 652 | tvout_debugfs_exit(tvout, encoder->dev->primary); | ||
| 653 | tvout->debugfs_registered = false; | ||
| 654 | } | ||
| 655 | |||
| 628 | static const struct drm_encoder_funcs sti_tvout_encoder_funcs = { | 656 | static const struct drm_encoder_funcs sti_tvout_encoder_funcs = { |
| 629 | .destroy = sti_tvout_encoder_destroy, | 657 | .destroy = sti_tvout_encoder_destroy, |
| 658 | .late_register = sti_tvout_late_register, | ||
| 659 | .early_unregister = sti_tvout_early_unregister, | ||
| 630 | }; | 660 | }; |
| 631 | 661 | ||
| 632 | static void sti_dvo_encoder_enable(struct drm_encoder *encoder) | 662 | static void sti_dvo_encoder_enable(struct drm_encoder *encoder) |
| @@ -813,9 +843,6 @@ static int sti_tvout_bind(struct device *dev, struct device *master, void *data) | |||
| 813 | 843 | ||
| 814 | sti_tvout_create_encoders(drm_dev, tvout); | 844 | sti_tvout_create_encoders(drm_dev, tvout); |
| 815 | 845 | ||
| 816 | if (tvout_debugfs_init(tvout, drm_dev->primary)) | ||
| 817 | DRM_ERROR("TVOUT debugfs setup failed\n"); | ||
| 818 | |||
| 819 | return 0; | 846 | return 0; |
| 820 | } | 847 | } |
| 821 | 848 | ||
| @@ -823,11 +850,8 @@ static void sti_tvout_unbind(struct device *dev, struct device *master, | |||
| 823 | void *data) | 850 | void *data) |
| 824 | { | 851 | { |
| 825 | struct sti_tvout *tvout = dev_get_drvdata(dev); | 852 | struct sti_tvout *tvout = dev_get_drvdata(dev); |
| 826 | struct drm_device *drm_dev = data; | ||
| 827 | 853 | ||
| 828 | sti_tvout_destroy_encoders(tvout); | 854 | sti_tvout_destroy_encoders(tvout); |
| 829 | |||
| 830 | tvout_debugfs_exit(tvout, drm_dev->primary); | ||
| 831 | } | 855 | } |
| 832 | 856 | ||
| 833 | static const struct component_ops sti_tvout_ops = { | 857 | static const struct component_ops sti_tvout_ops = { |
diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c index 0132aaebe598..47634a0251fc 100644 --- a/drivers/gpu/drm/sti/sti_vid.c +++ b/drivers/gpu/drm/sti/sti_vid.c | |||
| @@ -123,7 +123,7 @@ static struct drm_info_list vid_debugfs_files[] = { | |||
| 123 | { "vid", vid_dbg_show, 0, NULL }, | 123 | { "vid", vid_dbg_show, 0, NULL }, |
| 124 | }; | 124 | }; |
| 125 | 125 | ||
| 126 | static int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor) | 126 | int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor) |
| 127 | { | 127 | { |
| 128 | unsigned int i; | 128 | unsigned int i; |
| 129 | 129 | ||
| @@ -220,8 +220,5 @@ struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev, | |||
| 220 | 220 | ||
| 221 | sti_vid_init(vid); | 221 | sti_vid_init(vid); |
| 222 | 222 | ||
| 223 | if (vid_debugfs_init(vid, drm_dev->primary)) | ||
| 224 | DRM_ERROR("VID debugfs setup failed\n"); | ||
| 225 | |||
| 226 | return vid; | 223 | return vid; |
| 227 | } | 224 | } |
diff --git a/drivers/gpu/drm/sti/sti_vid.h b/drivers/gpu/drm/sti/sti_vid.h index 6c842344f3d8..fdc90f922a05 100644 --- a/drivers/gpu/drm/sti/sti_vid.h +++ b/drivers/gpu/drm/sti/sti_vid.h | |||
| @@ -26,4 +26,6 @@ void sti_vid_disable(struct sti_vid *vid); | |||
| 26 | struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev, | 26 | struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev, |
| 27 | int id, void __iomem *baseaddr); | 27 | int id, void __iomem *baseaddr); |
| 28 | 28 | ||
| 29 | int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor); | ||
| 30 | |||
| 29 | #endif | 31 | #endif |
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 68e9d85085fb..9a67f927a53e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c | |||
| @@ -24,34 +24,6 @@ | |||
| 24 | #include "sun4i_layer.h" | 24 | #include "sun4i_layer.h" |
| 25 | #include "sun4i_tcon.h" | 25 | #include "sun4i_tcon.h" |
| 26 | 26 | ||
| 27 | static int sun4i_drv_connector_plug_all(struct drm_device *drm) | ||
| 28 | { | ||
| 29 | struct drm_connector *connector, *failed; | ||
| 30 | int ret; | ||
| 31 | |||
| 32 | mutex_lock(&drm->mode_config.mutex); | ||
| 33 | list_for_each_entry(connector, &drm->mode_config.connector_list, head) { | ||
| 34 | ret = drm_connector_register(connector); | ||
| 35 | if (ret) { | ||
| 36 | failed = connector; | ||
| 37 | goto err; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | mutex_unlock(&drm->mode_config.mutex); | ||
| 41 | return 0; | ||
| 42 | |||
| 43 | err: | ||
| 44 | list_for_each_entry(connector, &drm->mode_config.connector_list, head) { | ||
| 45 | if (failed == connector) | ||
| 46 | break; | ||
| 47 | |||
| 48 | drm_connector_unregister(connector); | ||
| 49 | } | ||
| 50 | mutex_unlock(&drm->mode_config.mutex); | ||
| 51 | |||
| 52 | return ret; | ||
| 53 | } | ||
| 54 | |||
| 55 | static int sun4i_drv_enable_vblank(struct drm_device *drm, unsigned int pipe) | 27 | static int sun4i_drv_enable_vblank(struct drm_device *drm, unsigned int pipe) |
| 56 | { | 28 | { |
| 57 | struct sun4i_drv *drv = drm->dev_private; | 29 | struct sun4i_drv *drv = drm->dev_private; |
| @@ -135,10 +107,6 @@ static int sun4i_drv_bind(struct device *dev) | |||
| 135 | if (!drm) | 107 | if (!drm) |
| 136 | return -ENOMEM; | 108 | return -ENOMEM; |
| 137 | 109 | ||
| 138 | ret = drm_dev_set_unique(drm, dev_name(drm->dev)); | ||
| 139 | if (ret) | ||
| 140 | goto free_drm; | ||
| 141 | |||
| 142 | drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); | 110 | drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); |
| 143 | if (!drv) { | 111 | if (!drv) { |
| 144 | ret = -ENOMEM; | 112 | ret = -ENOMEM; |
| @@ -187,14 +155,8 @@ static int sun4i_drv_bind(struct device *dev) | |||
| 187 | if (ret) | 155 | if (ret) |
| 188 | goto free_drm; | 156 | goto free_drm; |
| 189 | 157 | ||
| 190 | ret = sun4i_drv_connector_plug_all(drm); | ||
| 191 | if (ret) | ||
| 192 | goto unregister_drm; | ||
| 193 | |||
| 194 | return 0; | 158 | return 0; |
| 195 | 159 | ||
| 196 | unregister_drm: | ||
| 197 | drm_dev_unregister(drm); | ||
| 198 | free_drm: | 160 | free_drm: |
| 199 | drm_dev_unref(drm); | 161 | drm_dev_unref(drm); |
| 200 | return ret; | 162 | return ret; |
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 308e197908fc..d27809372d54 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c | |||
| @@ -541,7 +541,6 @@ static struct drm_driver tilcdc_driver = { | |||
| 541 | .load = tilcdc_load, | 541 | .load = tilcdc_load, |
| 542 | .unload = tilcdc_unload, | 542 | .unload = tilcdc_unload, |
| 543 | .lastclose = tilcdc_lastclose, | 543 | .lastclose = tilcdc_lastclose, |
| 544 | .set_busid = drm_platform_set_busid, | ||
| 545 | .irq_handler = tilcdc_irq, | 544 | .irq_handler = tilcdc_irq, |
| 546 | .irq_preinstall = tilcdc_irq_preinstall, | 545 | .irq_preinstall = tilcdc_irq_preinstall, |
| 547 | .irq_postinstall = tilcdc_irq_postinstall, | 546 | .irq_postinstall = tilcdc_irq_postinstall, |
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 58b8fc036332..9e88231b8906 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c | |||
| @@ -176,7 +176,6 @@ static int vc4_drm_bind(struct device *dev) | |||
| 176 | { | 176 | { |
| 177 | struct platform_device *pdev = to_platform_device(dev); | 177 | struct platform_device *pdev = to_platform_device(dev); |
| 178 | struct drm_device *drm; | 178 | struct drm_device *drm; |
| 179 | struct drm_connector *connector; | ||
| 180 | struct vc4_dev *vc4; | 179 | struct vc4_dev *vc4; |
| 181 | int ret = 0; | 180 | int ret = 0; |
| 182 | 181 | ||
| @@ -211,22 +210,10 @@ static int vc4_drm_bind(struct device *dev) | |||
| 211 | if (ret < 0) | 210 | if (ret < 0) |
| 212 | goto unbind_all; | 211 | goto unbind_all; |
| 213 | 212 | ||
| 214 | /* Connector registration has to occur after DRM device | ||
| 215 | * registration, because it creates sysfs entries based on the | ||
| 216 | * DRM device. | ||
| 217 | */ | ||
| 218 | list_for_each_entry(connector, &drm->mode_config.connector_list, head) { | ||
| 219 | ret = drm_connector_register(connector); | ||
| 220 | if (ret) | ||
| 221 | goto unregister; | ||
| 222 | } | ||
| 223 | |||
| 224 | vc4_kms_load(drm); | 213 | vc4_kms_load(drm); |
| 225 | 214 | ||
| 226 | return 0; | 215 | return 0; |
| 227 | 216 | ||
| 228 | unregister: | ||
| 229 | drm_dev_unregister(drm); | ||
| 230 | unbind_all: | 217 | unbind_all: |
| 231 | component_unbind_all(dev, drm); | 218 | component_unbind_all(dev, drm); |
| 232 | gem_destroy: | 219 | gem_destroy: |
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index 1b4cc8b27080..35ea5d02a827 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c | |||
| @@ -260,8 +260,6 @@ static int __init vgem_init(void) | |||
| 260 | goto out; | 260 | goto out; |
| 261 | } | 261 | } |
| 262 | 262 | ||
| 263 | drm_dev_set_unique(vgem_device, "vgem"); | ||
| 264 | |||
| 265 | ret = drm_dev_register(vgem_device, 0); | 263 | ret = drm_dev_register(vgem_device, 0); |
| 266 | 264 | ||
| 267 | if (ret) | 265 | if (ret) |
diff --git a/drivers/gpu/drm/via/via_mm.c b/drivers/gpu/drm/via/via_mm.c index 4f20742e7788..a04ef1c992d9 100644 --- a/drivers/gpu/drm/via/via_mm.c +++ b/drivers/gpu/drm/via/via_mm.c | |||
| @@ -208,7 +208,7 @@ void via_reclaim_buffers_locked(struct drm_device *dev, | |||
| 208 | struct via_file_private *file_priv = file->driver_priv; | 208 | struct via_file_private *file_priv = file->driver_priv; |
| 209 | struct via_memblock *entry, *next; | 209 | struct via_memblock *entry, *next; |
| 210 | 210 | ||
| 211 | if (!(file->minor->master && file->master->lock.hw_lock)) | 211 | if (!(dev->master && file->master->lock.hw_lock)) |
| 212 | return; | 212 | return; |
| 213 | 213 | ||
| 214 | drm_legacy_idlelock_take(&file->master->lock); | 214 | drm_legacy_idlelock_take(&file->master->lock); |
diff --git a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c index 88a39165edd5..7f0e93f87a55 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c +++ b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c | |||
| @@ -27,16 +27,6 @@ | |||
| 27 | 27 | ||
| 28 | #include "virtgpu_drv.h" | 28 | #include "virtgpu_drv.h" |
| 29 | 29 | ||
| 30 | int drm_virtio_set_busid(struct drm_device *dev, struct drm_master *master) | ||
| 31 | { | ||
| 32 | struct pci_dev *pdev = dev->pdev; | ||
| 33 | |||
| 34 | if (pdev) { | ||
| 35 | return drm_pci_set_busid(dev, master); | ||
| 36 | } | ||
| 37 | return 0; | ||
| 38 | } | ||
| 39 | |||
| 40 | static void virtio_pci_kick_out_firmware_fb(struct pci_dev *pci_dev) | 30 | static void virtio_pci_kick_out_firmware_fb(struct pci_dev *pci_dev) |
| 41 | { | 31 | { |
| 42 | struct apertures_struct *ap; | 32 | struct apertures_struct *ap; |
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 5820b7020ae5..c13f70cfc461 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c | |||
| @@ -117,7 +117,6 @@ static const struct file_operations virtio_gpu_driver_fops = { | |||
| 117 | 117 | ||
| 118 | static struct drm_driver driver = { | 118 | static struct drm_driver driver = { |
| 119 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC, | 119 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC, |
| 120 | .set_busid = drm_virtio_set_busid, | ||
| 121 | .load = virtio_gpu_driver_load, | 120 | .load = virtio_gpu_driver_load, |
| 122 | .unload = virtio_gpu_driver_unload, | 121 | .unload = virtio_gpu_driver_unload, |
| 123 | .open = virtio_gpu_driver_open, | 122 | .open = virtio_gpu_driver_open, |
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index acf556a35cb2..b18ef3111f0c 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h | |||
| @@ -49,7 +49,6 @@ | |||
| 49 | #define DRIVER_PATCHLEVEL 1 | 49 | #define DRIVER_PATCHLEVEL 1 |
| 50 | 50 | ||
| 51 | /* virtgpu_drm_bus.c */ | 51 | /* virtgpu_drm_bus.c */ |
| 52 | int drm_virtio_set_busid(struct drm_device *dev, struct drm_master *master); | ||
| 53 | int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev); | 52 | int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev); |
| 54 | 53 | ||
| 55 | struct virtio_gpu_object { | 54 | struct virtio_gpu_object { |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 9fcd8200d485..60646644bef3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
| @@ -1049,7 +1049,7 @@ static struct vmw_master *vmw_master_check(struct drm_device *dev, | |||
| 1049 | if (unlikely(ret != 0)) | 1049 | if (unlikely(ret != 0)) |
| 1050 | return ERR_PTR(-ERESTARTSYS); | 1050 | return ERR_PTR(-ERESTARTSYS); |
| 1051 | 1051 | ||
| 1052 | if (file_priv->is_master) { | 1052 | if (drm_is_current_master(file_priv)) { |
| 1053 | mutex_unlock(&dev->master_mutex); | 1053 | mutex_unlock(&dev->master_mutex); |
| 1054 | return NULL; | 1054 | return NULL; |
| 1055 | } | 1055 | } |
| @@ -1228,8 +1228,7 @@ static int vmw_master_set(struct drm_device *dev, | |||
| 1228 | } | 1228 | } |
| 1229 | 1229 | ||
| 1230 | static void vmw_master_drop(struct drm_device *dev, | 1230 | static void vmw_master_drop(struct drm_device *dev, |
| 1231 | struct drm_file *file_priv, | 1231 | struct drm_file *file_priv) |
| 1232 | bool from_release) | ||
| 1233 | { | 1232 | { |
| 1234 | struct vmw_private *dev_priv = vmw_priv(dev); | 1233 | struct vmw_private *dev_priv = vmw_priv(dev); |
| 1235 | struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); | 1234 | struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 1980e2a28265..9a90f824814e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <drm/drmP.h> | 32 | #include <drm/drmP.h> |
| 33 | #include <drm/vmwgfx_drm.h> | 33 | #include <drm/vmwgfx_drm.h> |
| 34 | #include <drm/drm_hashtab.h> | 34 | #include <drm/drm_hashtab.h> |
| 35 | #include <drm/drm_auth.h> | ||
| 35 | #include <linux/suspend.h> | 36 | #include <linux/suspend.h> |
| 36 | #include <drm/ttm/ttm_bo_driver.h> | 37 | #include <drm/ttm/ttm_bo_driver.h> |
| 37 | #include <drm/ttm/ttm_object.h> | 38 | #include <drm/ttm/ttm_object.h> |
