diff options
author | Dave Airlie <airlied@redhat.com> | 2016-09-27 20:28:23 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-09-27 20:28:23 -0400 |
commit | 3f346d5dcb591c2a5a26653d093af710cf2e5a31 (patch) | |
tree | 24384b63b4ba23912afa6dac409f354b097156ff /drivers/gpu/drm | |
parent | 196ebdcc1db26977948c760664f024fa766950e4 (diff) | |
parent | 089cfdd9b0ec1b21d3356d2e057f69b89d46ae66 (diff) |
Merge tag 'topic/drm-misc-2016-09-25' of git://anongit.freedesktop.org/drm-intel into drm-next
- more core cleanup patches to prep drm_file to be used for
kernel-internal contexts (David Herrmann)
- more split-up+docs for drm_crtc.c
- lots of small fixes and polish all over
* tag 'topic/drm-misc-2016-09-25' of git://anongit.freedesktop.org/drm-intel: (37 commits)
drm: bridge: analogix/dp: mark symbols static where possible
drm/bochs: mark bochs_connector_get_modes() static
drm/bridge: analogix_dp: Improve panel on time
drm/bridge: analogix_dp: Don't read EDID if panel present
drm/bridge: analogix_dp: Remove duplicated code
Revert "drm/i2c: tda998x: don't register the connector"
drm: Fix plane type uabi breakage
dma-buf/sync_file: free fences array in num_fences is 1
drm/i2c: tda998x: don't register the connector
drm: Don't swallow error codes in drm_dev_alloc()
drm: Distinguish no name from ENOMEM in set_unique()
drm: Remove dirty property from docs
drm/doc: Document color space handling
drm: Extract drm_color_mgmt.[hc]
drm/doc: Polish plane composition property docs
drm: Conslidate blending properties in drm_blend.[hc]
drm/doc: Polish for drm_plane.[hc]
drm: Extract drm_plane.[hc]
drm/tilcdc: Add atomic and crtc headers to crtc.c
drm: Fix typo in encoder docs
...
Diffstat (limited to 'drivers/gpu/drm')
57 files changed, 1830 insertions, 2006 deletions
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 439d89b25ae0..25c720454017 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -14,7 +14,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ | |||
14 | drm_rect.o drm_vma_manager.o drm_flip_work.o \ | 14 | drm_rect.o drm_vma_manager.o drm_flip_work.o \ |
15 | drm_modeset_lock.o drm_atomic.o drm_bridge.o \ | 15 | drm_modeset_lock.o drm_atomic.o drm_bridge.o \ |
16 | drm_framebuffer.o drm_connector.o drm_blend.o \ | 16 | drm_framebuffer.o drm_connector.o drm_blend.o \ |
17 | drm_encoder.o drm_mode_object.o drm_property.o | 17 | drm_encoder.o drm_mode_object.o drm_property.o \ |
18 | drm_plane.o drm_color_mgmt.o | ||
18 | 19 | ||
19 | drm-$(CONFIG_COMPAT) += drm_ioc32.o | 20 | drm-$(CONFIG_COMPAT) += drm_ioc32.o |
20 | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o | 21 | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index dfb12237a6b0..b63969d7887c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | |||
@@ -246,7 +246,8 @@ static int amdgpu_verify_access(struct ttm_buffer_object *bo, struct file *filp) | |||
246 | 246 | ||
247 | if (amdgpu_ttm_tt_get_usermm(bo->ttm)) | 247 | if (amdgpu_ttm_tt_get_usermm(bo->ttm)) |
248 | return -EPERM; | 248 | return -EPERM; |
249 | return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp); | 249 | return drm_vma_node_verify_access(&rbo->gem_base.vma_node, |
250 | filp->private_data); | ||
250 | } | 251 | } |
251 | 252 | ||
252 | static void amdgpu_move_null(struct ttm_buffer_object *bo, | 253 | static void amdgpu_move_null(struct ttm_buffer_object *bo, |
diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c index 6d4ff34737cb..28e6471257d0 100644 --- a/drivers/gpu/drm/arc/arcpgu_drv.c +++ b/drivers/gpu/drm/arc/arcpgu_drv.c | |||
@@ -198,8 +198,8 @@ static int arcpgu_probe(struct platform_device *pdev) | |||
198 | int ret; | 198 | int ret; |
199 | 199 | ||
200 | drm = drm_dev_alloc(&arcpgu_drm_driver, &pdev->dev); | 200 | drm = drm_dev_alloc(&arcpgu_drm_driver, &pdev->dev); |
201 | if (!drm) | 201 | if (IS_ERR(drm)) |
202 | return -ENOMEM; | 202 | return PTR_ERR(drm); |
203 | 203 | ||
204 | ret = arcpgu_load(drm); | 204 | ret = arcpgu_load(drm); |
205 | if (ret) | 205 | if (ret) |
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index d83b46a30327..fb6a418ce6be 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c | |||
@@ -326,8 +326,8 @@ static int hdlcd_drm_bind(struct device *dev) | |||
326 | return -ENOMEM; | 326 | return -ENOMEM; |
327 | 327 | ||
328 | drm = drm_dev_alloc(&hdlcd_driver, dev); | 328 | drm = drm_dev_alloc(&hdlcd_driver, dev); |
329 | if (!drm) | 329 | if (IS_ERR(drm)) |
330 | return -ENOMEM; | 330 | return PTR_ERR(drm); |
331 | 331 | ||
332 | drm->dev_private = hdlcd; | 332 | drm->dev_private = hdlcd; |
333 | dev_set_drvdata(dev, drm); | 333 | dev_set_drvdata(dev, drm); |
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index c383d724527f..9280358b8f15 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c | |||
@@ -311,8 +311,8 @@ static int malidp_bind(struct device *dev) | |||
311 | return ret; | 311 | return ret; |
312 | 312 | ||
313 | drm = drm_dev_alloc(&malidp_driver, dev); | 313 | drm = drm_dev_alloc(&malidp_driver, dev); |
314 | if (!drm) { | 314 | if (IS_ERR(drm)) { |
315 | ret = -ENOMEM; | 315 | ret = PTR_ERR(drm); |
316 | goto alloc_fail; | 316 | goto alloc_fail; |
317 | } | 317 | } |
318 | 318 | ||
diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index b29a41218fc9..608df4c90520 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c | |||
@@ -150,7 +150,8 @@ static int ast_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) | |||
150 | { | 150 | { |
151 | struct ast_bo *astbo = ast_bo(bo); | 151 | struct ast_bo *astbo = ast_bo(bo); |
152 | 152 | ||
153 | return drm_vma_node_verify_access(&astbo->gem.vma_node, filp); | 153 | return drm_vma_node_verify_access(&astbo->gem.vma_node, |
154 | filp->private_data); | ||
154 | } | 155 | } |
155 | 156 | ||
156 | static int ast_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | 157 | static int ast_ttm_io_mem_reserve(struct ttm_bo_device *bdev, |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 8e7483d90c47..5f484310bee9 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | |||
@@ -797,8 +797,8 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev) | |||
797 | int ret; | 797 | int ret; |
798 | 798 | ||
799 | ddev = drm_dev_alloc(&atmel_hlcdc_dc_driver, &pdev->dev); | 799 | ddev = drm_dev_alloc(&atmel_hlcdc_dc_driver, &pdev->dev); |
800 | if (!ddev) | 800 | if (IS_ERR(ddev)) |
801 | return -ENOMEM; | 801 | return PTR_ERR(ddev); |
802 | 802 | ||
803 | ret = atmel_hlcdc_dc_load(ddev); | 803 | ret = atmel_hlcdc_dc_load(ddev); |
804 | if (ret) | 804 | if (ret) |
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index 207a2cbcc113..0b4e5d117043 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c | |||
@@ -178,7 +178,7 @@ static void bochs_encoder_init(struct drm_device *dev) | |||
178 | } | 178 | } |
179 | 179 | ||
180 | 180 | ||
181 | int bochs_connector_get_modes(struct drm_connector *connector) | 181 | static int bochs_connector_get_modes(struct drm_connector *connector) |
182 | { | 182 | { |
183 | int count; | 183 | int count; |
184 | 184 | ||
diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 5c5638a777a1..269cfca9ca06 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c | |||
@@ -128,7 +128,8 @@ static int bochs_bo_verify_access(struct ttm_buffer_object *bo, | |||
128 | { | 128 | { |
129 | struct bochs_bo *bochsbo = bochs_bo(bo); | 129 | struct bochs_bo *bochsbo = bochs_bo(bo); |
130 | 130 | ||
131 | return drm_vma_node_verify_access(&bochsbo->gem.vma_node, filp); | 131 | return drm_vma_node_verify_access(&bochsbo->gem.vma_node, |
132 | filp->private_data); | ||
132 | } | 133 | } |
133 | 134 | ||
134 | static int bochs_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | 135 | static int bochs_ttm_io_mem_reserve(struct ttm_bo_device *bdev, |
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index efac8aba6776..0f2e42310694 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <drm/bridge/analogix_dp.h> | 31 | #include <drm/bridge/analogix_dp.h> |
32 | 32 | ||
33 | #include "analogix_dp_core.h" | 33 | #include "analogix_dp_core.h" |
34 | #include "analogix_dp_reg.h" | ||
34 | 35 | ||
35 | #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) | 36 | #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) |
36 | 37 | ||
@@ -147,7 +148,7 @@ static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) | |||
147 | { | 148 | { |
148 | unsigned char psr_version; | 149 | unsigned char psr_version; |
149 | 150 | ||
150 | analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, &psr_version); | 151 | drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version); |
151 | dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); | 152 | dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); |
152 | 153 | ||
153 | return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; | 154 | return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; |
@@ -158,166 +159,37 @@ static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) | |||
158 | unsigned char psr_en; | 159 | unsigned char psr_en; |
159 | 160 | ||
160 | /* Disable psr function */ | 161 | /* Disable psr function */ |
161 | analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en); | 162 | drm_dp_dpcd_readb(&dp->aux, DP_PSR_EN_CFG, &psr_en); |
162 | psr_en &= ~DP_PSR_ENABLE; | 163 | psr_en &= ~DP_PSR_ENABLE; |
163 | analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); | 164 | drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en); |
164 | 165 | ||
165 | /* Main-Link transmitter remains active during PSR active states */ | 166 | /* Main-Link transmitter remains active during PSR active states */ |
166 | psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; | 167 | psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; |
167 | analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); | 168 | drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en); |
168 | 169 | ||
169 | /* Enable psr function */ | 170 | /* Enable psr function */ |
170 | psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | | 171 | psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | |
171 | DP_PSR_CRC_VERIFICATION; | 172 | DP_PSR_CRC_VERIFICATION; |
172 | analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); | 173 | drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en); |
173 | 174 | ||
174 | analogix_dp_enable_psr_crc(dp); | 175 | analogix_dp_enable_psr_crc(dp); |
175 | } | 176 | } |
176 | 177 | ||
177 | static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) | ||
178 | { | ||
179 | int i; | ||
180 | unsigned char sum = 0; | ||
181 | |||
182 | for (i = 0; i < EDID_BLOCK_LENGTH; i++) | ||
183 | sum = sum + edid_data[i]; | ||
184 | |||
185 | return sum; | ||
186 | } | ||
187 | |||
188 | static int analogix_dp_read_edid(struct analogix_dp_device *dp) | ||
189 | { | ||
190 | unsigned char *edid = dp->edid; | ||
191 | unsigned int extend_block = 0; | ||
192 | unsigned char sum; | ||
193 | unsigned char test_vector; | ||
194 | int retval; | ||
195 | |||
196 | /* | ||
197 | * EDID device address is 0x50. | ||
198 | * However, if necessary, you must have set upper address | ||
199 | * into E-EDID in I2C device, 0x30. | ||
200 | */ | ||
201 | |||
202 | /* Read Extension Flag, Number of 128-byte EDID extension blocks */ | ||
203 | retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, | ||
204 | EDID_EXTENSION_FLAG, | ||
205 | &extend_block); | ||
206 | if (retval) | ||
207 | return retval; | ||
208 | |||
209 | if (extend_block > 0) { | ||
210 | dev_dbg(dp->dev, "EDID data includes a single extension!\n"); | ||
211 | |||
212 | /* Read EDID data */ | ||
213 | retval = analogix_dp_read_bytes_from_i2c(dp, | ||
214 | I2C_EDID_DEVICE_ADDR, | ||
215 | EDID_HEADER_PATTERN, | ||
216 | EDID_BLOCK_LENGTH, | ||
217 | &edid[EDID_HEADER_PATTERN]); | ||
218 | if (retval != 0) { | ||
219 | dev_err(dp->dev, "EDID Read failed!\n"); | ||
220 | return -EIO; | ||
221 | } | ||
222 | sum = analogix_dp_calc_edid_check_sum(edid); | ||
223 | if (sum != 0) { | ||
224 | dev_err(dp->dev, "EDID bad checksum!\n"); | ||
225 | return -EIO; | ||
226 | } | ||
227 | |||
228 | /* Read additional EDID data */ | ||
229 | retval = analogix_dp_read_bytes_from_i2c(dp, | ||
230 | I2C_EDID_DEVICE_ADDR, | ||
231 | EDID_BLOCK_LENGTH, | ||
232 | EDID_BLOCK_LENGTH, | ||
233 | &edid[EDID_BLOCK_LENGTH]); | ||
234 | if (retval != 0) { | ||
235 | dev_err(dp->dev, "EDID Read failed!\n"); | ||
236 | return -EIO; | ||
237 | } | ||
238 | sum = analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); | ||
239 | if (sum != 0) { | ||
240 | dev_err(dp->dev, "EDID bad checksum!\n"); | ||
241 | return -EIO; | ||
242 | } | ||
243 | |||
244 | analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, | ||
245 | &test_vector); | ||
246 | if (test_vector & DP_TEST_LINK_EDID_READ) { | ||
247 | analogix_dp_write_byte_to_dpcd(dp, | ||
248 | DP_TEST_EDID_CHECKSUM, | ||
249 | edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); | ||
250 | analogix_dp_write_byte_to_dpcd(dp, | ||
251 | DP_TEST_RESPONSE, | ||
252 | DP_TEST_EDID_CHECKSUM_WRITE); | ||
253 | } | ||
254 | } else { | ||
255 | dev_info(dp->dev, "EDID data does not include any extensions.\n"); | ||
256 | |||
257 | /* Read EDID data */ | ||
258 | retval = analogix_dp_read_bytes_from_i2c(dp, | ||
259 | I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, | ||
260 | EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); | ||
261 | if (retval != 0) { | ||
262 | dev_err(dp->dev, "EDID Read failed!\n"); | ||
263 | return -EIO; | ||
264 | } | ||
265 | sum = analogix_dp_calc_edid_check_sum(edid); | ||
266 | if (sum != 0) { | ||
267 | dev_err(dp->dev, "EDID bad checksum!\n"); | ||
268 | return -EIO; | ||
269 | } | ||
270 | |||
271 | analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, | ||
272 | &test_vector); | ||
273 | if (test_vector & DP_TEST_LINK_EDID_READ) { | ||
274 | analogix_dp_write_byte_to_dpcd(dp, | ||
275 | DP_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); | ||
276 | analogix_dp_write_byte_to_dpcd(dp, | ||
277 | DP_TEST_RESPONSE, DP_TEST_EDID_CHECKSUM_WRITE); | ||
278 | } | ||
279 | } | ||
280 | |||
281 | dev_dbg(dp->dev, "EDID Read success!\n"); | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int analogix_dp_handle_edid(struct analogix_dp_device *dp) | ||
286 | { | ||
287 | u8 buf[12]; | ||
288 | int i; | ||
289 | int retval; | ||
290 | |||
291 | /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */ | ||
292 | retval = analogix_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, 12, buf); | ||
293 | if (retval) | ||
294 | return retval; | ||
295 | |||
296 | /* Read EDID */ | ||
297 | for (i = 0; i < 3; i++) { | ||
298 | retval = analogix_dp_read_edid(dp); | ||
299 | if (!retval) | ||
300 | break; | ||
301 | } | ||
302 | |||
303 | return retval; | ||
304 | } | ||
305 | |||
306 | static void | 178 | static void |
307 | analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp, | 179 | analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp, |
308 | bool enable) | 180 | bool enable) |
309 | { | 181 | { |
310 | u8 data; | 182 | u8 data; |
311 | 183 | ||
312 | analogix_dp_read_byte_from_dpcd(dp, DP_LANE_COUNT_SET, &data); | 184 | drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data); |
313 | 185 | ||
314 | if (enable) | 186 | if (enable) |
315 | analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, | 187 | drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, |
316 | DP_LANE_COUNT_ENHANCED_FRAME_EN | | 188 | DP_LANE_COUNT_ENHANCED_FRAME_EN | |
317 | DPCD_LANE_COUNT_SET(data)); | 189 | DPCD_LANE_COUNT_SET(data)); |
318 | else | 190 | else |
319 | analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, | 191 | drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, |
320 | DPCD_LANE_COUNT_SET(data)); | 192 | DPCD_LANE_COUNT_SET(data)); |
321 | } | 193 | } |
322 | 194 | ||
323 | static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp) | 195 | static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp) |
@@ -325,7 +197,7 @@ static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp) | |||
325 | u8 data; | 197 | u8 data; |
326 | int retval; | 198 | int retval; |
327 | 199 | ||
328 | analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); | 200 | drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data); |
329 | retval = DPCD_ENHANCED_FRAME_CAP(data); | 201 | retval = DPCD_ENHANCED_FRAME_CAP(data); |
330 | 202 | ||
331 | return retval; | 203 | return retval; |
@@ -344,8 +216,8 @@ static void analogix_dp_training_pattern_dis(struct analogix_dp_device *dp) | |||
344 | { | 216 | { |
345 | analogix_dp_set_training_pattern(dp, DP_NONE); | 217 | analogix_dp_set_training_pattern(dp, DP_NONE); |
346 | 218 | ||
347 | analogix_dp_write_byte_to_dpcd(dp, DP_TRAINING_PATTERN_SET, | 219 | drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, |
348 | DP_TRAINING_PATTERN_DISABLE); | 220 | DP_TRAINING_PATTERN_DISABLE); |
349 | } | 221 | } |
350 | 222 | ||
351 | static void | 223 | static void |
@@ -390,8 +262,8 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) | |||
390 | /* Setup RX configuration */ | 262 | /* Setup RX configuration */ |
391 | buf[0] = dp->link_train.link_rate; | 263 | buf[0] = dp->link_train.link_rate; |
392 | buf[1] = dp->link_train.lane_count; | 264 | buf[1] = dp->link_train.lane_count; |
393 | retval = analogix_dp_write_bytes_to_dpcd(dp, DP_LINK_BW_SET, 2, buf); | 265 | retval = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, 2); |
394 | if (retval) | 266 | if (retval < 0) |
395 | return retval; | 267 | return retval; |
396 | 268 | ||
397 | /* Set TX pre-emphasis to minimum */ | 269 | /* Set TX pre-emphasis to minimum */ |
@@ -415,20 +287,22 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) | |||
415 | analogix_dp_set_training_pattern(dp, TRAINING_PTN1); | 287 | analogix_dp_set_training_pattern(dp, TRAINING_PTN1); |
416 | 288 | ||
417 | /* Set RX training pattern */ | 289 | /* Set RX training pattern */ |
418 | retval = analogix_dp_write_byte_to_dpcd(dp, | 290 | retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, |
419 | DP_TRAINING_PATTERN_SET, | 291 | DP_LINK_SCRAMBLING_DISABLE | |
420 | DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1); | 292 | DP_TRAINING_PATTERN_1); |
421 | if (retval) | 293 | if (retval < 0) |
422 | return retval; | 294 | return retval; |
423 | 295 | ||
424 | for (lane = 0; lane < lane_count; lane++) | 296 | for (lane = 0; lane < lane_count; lane++) |
425 | buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 | | 297 | buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 | |
426 | DP_TRAIN_VOLTAGE_SWING_LEVEL_0; | 298 | DP_TRAIN_VOLTAGE_SWING_LEVEL_0; |
427 | 299 | ||
428 | retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, | 300 | retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, |
429 | lane_count, buf); | 301 | lane_count); |
302 | if (retval < 0) | ||
303 | return retval; | ||
430 | 304 | ||
431 | return retval; | 305 | return 0; |
432 | } | 306 | } |
433 | 307 | ||
434 | static unsigned char analogix_dp_get_lane_status(u8 link_status[2], int lane) | 308 | static unsigned char analogix_dp_get_lane_status(u8 link_status[2], int lane) |
@@ -580,25 +454,23 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) | |||
580 | 454 | ||
581 | lane_count = dp->link_train.lane_count; | 455 | lane_count = dp->link_train.lane_count; |
582 | 456 | ||
583 | retval = analogix_dp_read_bytes_from_dpcd(dp, | 457 | retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); |
584 | DP_LANE0_1_STATUS, 2, link_status); | 458 | if (retval < 0) |
585 | if (retval) | ||
586 | return retval; | 459 | return retval; |
587 | 460 | ||
588 | retval = analogix_dp_read_bytes_from_dpcd(dp, | 461 | retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, |
589 | DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); | 462 | adjust_request, 2); |
590 | if (retval) | 463 | if (retval < 0) |
591 | return retval; | 464 | return retval; |
592 | 465 | ||
593 | if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) { | 466 | if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) { |
594 | /* set training pattern 2 for EQ */ | 467 | /* set training pattern 2 for EQ */ |
595 | analogix_dp_set_training_pattern(dp, TRAINING_PTN2); | 468 | analogix_dp_set_training_pattern(dp, TRAINING_PTN2); |
596 | 469 | ||
597 | retval = analogix_dp_write_byte_to_dpcd(dp, | 470 | retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, |
598 | DP_TRAINING_PATTERN_SET, | 471 | DP_LINK_SCRAMBLING_DISABLE | |
599 | DP_LINK_SCRAMBLING_DISABLE | | 472 | DP_TRAINING_PATTERN_2); |
600 | DP_TRAINING_PATTERN_2); | 473 | if (retval < 0) |
601 | if (retval) | ||
602 | return retval; | 474 | return retval; |
603 | 475 | ||
604 | dev_info(dp->dev, "Link Training Clock Recovery success\n"); | 476 | dev_info(dp->dev, "Link Training Clock Recovery success\n"); |
@@ -636,13 +508,12 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) | |||
636 | analogix_dp_set_lane_link_training(dp, | 508 | analogix_dp_set_lane_link_training(dp, |
637 | dp->link_train.training_lane[lane], lane); | 509 | dp->link_train.training_lane[lane], lane); |
638 | 510 | ||
639 | retval = analogix_dp_write_bytes_to_dpcd(dp, | 511 | retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, |
640 | DP_TRAINING_LANE0_SET, lane_count, | 512 | dp->link_train.training_lane, lane_count); |
641 | dp->link_train.training_lane); | 513 | if (retval < 0) |
642 | if (retval) | ||
643 | return retval; | 514 | return retval; |
644 | 515 | ||
645 | return retval; | 516 | return 0; |
646 | } | 517 | } |
647 | 518 | ||
648 | static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) | 519 | static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) |
@@ -655,9 +526,8 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) | |||
655 | 526 | ||
656 | lane_count = dp->link_train.lane_count; | 527 | lane_count = dp->link_train.lane_count; |
657 | 528 | ||
658 | retval = analogix_dp_read_bytes_from_dpcd(dp, | 529 | retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); |
659 | DP_LANE0_1_STATUS, 2, link_status); | 530 | if (retval < 0) |
660 | if (retval) | ||
661 | return retval; | 531 | return retval; |
662 | 532 | ||
663 | if (analogix_dp_clock_recovery_ok(link_status, lane_count)) { | 533 | if (analogix_dp_clock_recovery_ok(link_status, lane_count)) { |
@@ -665,14 +535,14 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) | |||
665 | return -EIO; | 535 | return -EIO; |
666 | } | 536 | } |
667 | 537 | ||
668 | retval = analogix_dp_read_bytes_from_dpcd(dp, | 538 | retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, |
669 | DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); | 539 | adjust_request, 2); |
670 | if (retval) | 540 | if (retval < 0) |
671 | return retval; | 541 | return retval; |
672 | 542 | ||
673 | retval = analogix_dp_read_byte_from_dpcd(dp, | 543 | retval = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED, |
674 | DP_LANE_ALIGN_STATUS_UPDATED, &link_align); | 544 | &link_align); |
675 | if (retval) | 545 | if (retval < 0) |
676 | return retval; | 546 | return retval; |
677 | 547 | ||
678 | analogix_dp_get_adjust_training_lane(dp, adjust_request); | 548 | analogix_dp_get_adjust_training_lane(dp, adjust_request); |
@@ -713,10 +583,12 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) | |||
713 | analogix_dp_set_lane_link_training(dp, | 583 | analogix_dp_set_lane_link_training(dp, |
714 | dp->link_train.training_lane[lane], lane); | 584 | dp->link_train.training_lane[lane], lane); |
715 | 585 | ||
716 | retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, | 586 | retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, |
717 | lane_count, dp->link_train.training_lane); | 587 | dp->link_train.training_lane, lane_count); |
588 | if (retval < 0) | ||
589 | return retval; | ||
718 | 590 | ||
719 | return retval; | 591 | return 0; |
720 | } | 592 | } |
721 | 593 | ||
722 | static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp, | 594 | static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp, |
@@ -730,7 +602,7 @@ static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp, | |||
730 | * For DP rev.1.2, Maximum link rate of Main Link lanes | 602 | * For DP rev.1.2, Maximum link rate of Main Link lanes |
731 | * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps | 603 | * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps |
732 | */ | 604 | */ |
733 | analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data); | 605 | drm_dp_dpcd_readb(&dp->aux, DP_MAX_LINK_RATE, &data); |
734 | *bandwidth = data; | 606 | *bandwidth = data; |
735 | } | 607 | } |
736 | 608 | ||
@@ -743,7 +615,7 @@ static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp, | |||
743 | * For DP rev.1.1, Maximum number of Main Link lanes | 615 | * For DP rev.1.1, Maximum number of Main Link lanes |
744 | * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes | 616 | * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes |
745 | */ | 617 | */ |
746 | analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); | 618 | drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data); |
747 | *lane_count = DPCD_MAX_LANE_COUNT(data); | 619 | *lane_count = DPCD_MAX_LANE_COUNT(data); |
748 | } | 620 | } |
749 | 621 | ||
@@ -912,19 +784,15 @@ static void analogix_dp_enable_scramble(struct analogix_dp_device *dp, | |||
912 | if (enable) { | 784 | if (enable) { |
913 | analogix_dp_enable_scrambling(dp); | 785 | analogix_dp_enable_scrambling(dp); |
914 | 786 | ||
915 | analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, | 787 | drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data); |
916 | &data); | 788 | drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, |
917 | analogix_dp_write_byte_to_dpcd(dp, | 789 | (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); |
918 | DP_TRAINING_PATTERN_SET, | ||
919 | (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); | ||
920 | } else { | 790 | } else { |
921 | analogix_dp_disable_scrambling(dp); | 791 | analogix_dp_disable_scrambling(dp); |
922 | 792 | ||
923 | analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, | 793 | drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data); |
924 | &data); | 794 | drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, |
925 | analogix_dp_write_byte_to_dpcd(dp, | 795 | (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); |
926 | DP_TRAINING_PATTERN_SET, | ||
927 | (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); | ||
928 | } | 796 | } |
929 | } | 797 | } |
930 | 798 | ||
@@ -1050,33 +918,37 @@ out: | |||
1050 | return ret; | 918 | return ret; |
1051 | } | 919 | } |
1052 | 920 | ||
1053 | int analogix_dp_get_modes(struct drm_connector *connector) | 921 | static int analogix_dp_get_modes(struct drm_connector *connector) |
1054 | { | 922 | { |
1055 | struct analogix_dp_device *dp = to_dp(connector); | 923 | struct analogix_dp_device *dp = to_dp(connector); |
1056 | struct edid *edid = (struct edid *)dp->edid; | 924 | struct edid *edid; |
1057 | int ret, num_modes = 0; | 925 | int ret, num_modes = 0; |
1058 | 926 | ||
1059 | ret = analogix_dp_prepare_panel(dp, true, false); | 927 | if (dp->plat_data->panel) { |
1060 | if (ret) { | 928 | num_modes += drm_panel_get_modes(dp->plat_data->panel); |
1061 | DRM_ERROR("Failed to prepare panel (%d)\n", ret); | 929 | } else { |
1062 | return 0; | 930 | ret = analogix_dp_prepare_panel(dp, true, false); |
1063 | } | 931 | if (ret) { |
932 | DRM_ERROR("Failed to prepare panel (%d)\n", ret); | ||
933 | return 0; | ||
934 | } | ||
1064 | 935 | ||
1065 | if (analogix_dp_handle_edid(dp) == 0) { | 936 | edid = drm_get_edid(connector, &dp->aux.ddc); |
1066 | drm_mode_connector_update_edid_property(&dp->connector, edid); | 937 | if (edid) { |
1067 | num_modes += drm_add_edid_modes(&dp->connector, edid); | 938 | drm_mode_connector_update_edid_property(&dp->connector, |
1068 | } | 939 | edid); |
940 | num_modes += drm_add_edid_modes(&dp->connector, edid); | ||
941 | kfree(edid); | ||
942 | } | ||
1069 | 943 | ||
1070 | if (dp->plat_data->panel) | 944 | ret = analogix_dp_prepare_panel(dp, false, false); |
1071 | num_modes += drm_panel_get_modes(dp->plat_data->panel); | 945 | if (ret) |
946 | DRM_ERROR("Failed to unprepare panel (%d)\n", ret); | ||
947 | } | ||
1072 | 948 | ||
1073 | if (dp->plat_data->get_modes) | 949 | if (dp->plat_data->get_modes) |
1074 | num_modes += dp->plat_data->get_modes(dp->plat_data, connector); | 950 | num_modes += dp->plat_data->get_modes(dp->plat_data, connector); |
1075 | 951 | ||
1076 | ret = analogix_dp_prepare_panel(dp, false, false); | ||
1077 | if (ret) | ||
1078 | DRM_ERROR("Failed to unprepare panel (%d)\n", ret); | ||
1079 | |||
1080 | return num_modes; | 952 | return num_modes; |
1081 | } | 953 | } |
1082 | 954 | ||
@@ -1093,13 +965,16 @@ static const struct drm_connector_helper_funcs analogix_dp_connector_helper_func | |||
1093 | .best_encoder = analogix_dp_best_encoder, | 965 | .best_encoder = analogix_dp_best_encoder, |
1094 | }; | 966 | }; |
1095 | 967 | ||
1096 | enum drm_connector_status | 968 | static enum drm_connector_status |
1097 | analogix_dp_detect(struct drm_connector *connector, bool force) | 969 | analogix_dp_detect(struct drm_connector *connector, bool force) |
1098 | { | 970 | { |
1099 | struct analogix_dp_device *dp = to_dp(connector); | 971 | struct analogix_dp_device *dp = to_dp(connector); |
1100 | enum drm_connector_status status = connector_status_disconnected; | 972 | enum drm_connector_status status = connector_status_disconnected; |
1101 | int ret; | 973 | int ret; |
1102 | 974 | ||
975 | if (dp->plat_data->panel) | ||
976 | return connector_status_connected; | ||
977 | |||
1103 | ret = analogix_dp_prepare_panel(dp, true, false); | 978 | ret = analogix_dp_prepare_panel(dp, true, false); |
1104 | if (ret) { | 979 | if (ret) { |
1105 | DRM_ERROR("Failed to prepare panel (%d)\n", ret); | 980 | DRM_ERROR("Failed to prepare panel (%d)\n", ret); |
@@ -1395,6 +1270,14 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp) | |||
1395 | return 0; | 1270 | return 0; |
1396 | } | 1271 | } |
1397 | 1272 | ||
1273 | static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux, | ||
1274 | struct drm_dp_aux_msg *msg) | ||
1275 | { | ||
1276 | struct analogix_dp_device *dp = to_dp(aux); | ||
1277 | |||
1278 | return analogix_dp_transfer(dp, msg); | ||
1279 | } | ||
1280 | |||
1398 | int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, | 1281 | int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, |
1399 | struct analogix_dp_plat_data *plat_data) | 1282 | struct analogix_dp_plat_data *plat_data) |
1400 | { | 1283 | { |
@@ -1515,6 +1398,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, | |||
1515 | dp->drm_dev = drm_dev; | 1398 | dp->drm_dev = drm_dev; |
1516 | dp->encoder = dp->plat_data->encoder; | 1399 | dp->encoder = dp->plat_data->encoder; |
1517 | 1400 | ||
1401 | dp->aux.name = "DP-AUX"; | ||
1402 | dp->aux.transfer = analogix_dpaux_transfer; | ||
1403 | dp->aux.dev = &pdev->dev; | ||
1404 | |||
1405 | ret = drm_dp_aux_register(&dp->aux); | ||
1406 | if (ret) | ||
1407 | goto err_disable_pm_runtime; | ||
1408 | |||
1518 | ret = analogix_dp_create_bridge(drm_dev, dp); | 1409 | ret = analogix_dp_create_bridge(drm_dev, dp); |
1519 | if (ret) { | 1410 | if (ret) { |
1520 | DRM_ERROR("failed to create bridge (%d)\n", ret); | 1411 | DRM_ERROR("failed to create bridge (%d)\n", ret); |
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 473b9802b2d6..5c6a28806129 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | |||
@@ -20,15 +20,6 @@ | |||
20 | #define MAX_CR_LOOP 5 | 20 | #define MAX_CR_LOOP 5 |
21 | #define MAX_EQ_LOOP 5 | 21 | #define MAX_EQ_LOOP 5 |
22 | 22 | ||
23 | /* I2C EDID Chip ID, Slave Address */ | ||
24 | #define I2C_EDID_DEVICE_ADDR 0x50 | ||
25 | #define I2C_E_EDID_DEVICE_ADDR 0x30 | ||
26 | |||
27 | #define EDID_BLOCK_LENGTH 0x80 | ||
28 | #define EDID_HEADER_PATTERN 0x00 | ||
29 | #define EDID_EXTENSION_FLAG 0x7e | ||
30 | #define EDID_CHECKSUM 0x7f | ||
31 | |||
32 | /* DP_MAX_LANE_COUNT */ | 23 | /* DP_MAX_LANE_COUNT */ |
33 | #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) | 24 | #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) |
34 | #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) | 25 | #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) |
@@ -166,6 +157,7 @@ struct analogix_dp_device { | |||
166 | struct drm_device *drm_dev; | 157 | struct drm_device *drm_dev; |
167 | struct drm_connector connector; | 158 | struct drm_connector connector; |
168 | struct drm_bridge *bridge; | 159 | struct drm_bridge *bridge; |
160 | struct drm_dp_aux aux; | ||
169 | struct clk *clock; | 161 | struct clk *clock; |
170 | unsigned int irq; | 162 | unsigned int irq; |
171 | void __iomem *reg_base; | 163 | void __iomem *reg_base; |
@@ -176,7 +168,6 @@ struct analogix_dp_device { | |||
176 | int dpms_mode; | 168 | int dpms_mode; |
177 | int hpd_gpio; | 169 | int hpd_gpio; |
178 | bool force_hpd; | 170 | bool force_hpd; |
179 | unsigned char edid[EDID_BLOCK_LENGTH * 2]; | ||
180 | bool psr_support; | 171 | bool psr_support; |
181 | 172 | ||
182 | struct mutex panel_lock; | 173 | struct mutex panel_lock; |
@@ -210,33 +201,6 @@ void analogix_dp_reset_aux(struct analogix_dp_device *dp); | |||
210 | void analogix_dp_init_aux(struct analogix_dp_device *dp); | 201 | void analogix_dp_init_aux(struct analogix_dp_device *dp); |
211 | int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp); | 202 | int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp); |
212 | void analogix_dp_enable_sw_function(struct analogix_dp_device *dp); | 203 | void analogix_dp_enable_sw_function(struct analogix_dp_device *dp); |
213 | int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp); | ||
214 | int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp, | ||
215 | unsigned int reg_addr, | ||
216 | unsigned char data); | ||
217 | int analogix_dp_read_byte_from_dpcd(struct analogix_dp_device *dp, | ||
218 | unsigned int reg_addr, | ||
219 | unsigned char *data); | ||
220 | int analogix_dp_write_bytes_to_dpcd(struct analogix_dp_device *dp, | ||
221 | unsigned int reg_addr, | ||
222 | unsigned int count, | ||
223 | unsigned char data[]); | ||
224 | int analogix_dp_read_bytes_from_dpcd(struct analogix_dp_device *dp, | ||
225 | unsigned int reg_addr, | ||
226 | unsigned int count, | ||
227 | unsigned char data[]); | ||
228 | int analogix_dp_select_i2c_device(struct analogix_dp_device *dp, | ||
229 | unsigned int device_addr, | ||
230 | unsigned int reg_addr); | ||
231 | int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp, | ||
232 | unsigned int device_addr, | ||
233 | unsigned int reg_addr, | ||
234 | unsigned int *data); | ||
235 | int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp, | ||
236 | unsigned int device_addr, | ||
237 | unsigned int reg_addr, | ||
238 | unsigned int count, | ||
239 | unsigned char edid[]); | ||
240 | void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype); | 204 | void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype); |
241 | void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype); | 205 | void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype); |
242 | void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count); | 206 | void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count); |
@@ -285,5 +249,7 @@ void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); | |||
285 | void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); | 249 | void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); |
286 | void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, | 250 | void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, |
287 | struct edp_vsc_psr *vsc); | 251 | struct edp_vsc_psr *vsc); |
252 | ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, | ||
253 | struct drm_dp_aux_msg *msg); | ||
288 | 254 | ||
289 | #endif /* _ANALOGIX_DP_CORE_H */ | 255 | #endif /* _ANALOGIX_DP_CORE_H */ |
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index fae0293d509a..cd37ac058675 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | |||
@@ -585,330 +585,6 @@ int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp, | |||
585 | return retval; | 585 | return retval; |
586 | } | 586 | } |
587 | 587 | ||
588 | int analogix_dp_read_byte_from_dpcd(struct analogix_dp_device *dp, | ||
589 | unsigned int reg_addr, | ||
590 | unsigned char *data) | ||
591 | { | ||
592 | u32 reg; | ||
593 | int i; | ||
594 | int retval; | ||
595 | |||
596 | for (i = 0; i < 3; i++) { | ||
597 | /* Clear AUX CH data buffer */ | ||
598 | reg = BUF_CLR; | ||
599 | writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); | ||
600 | |||
601 | /* Select DPCD device address */ | ||
602 | reg = AUX_ADDR_7_0(reg_addr); | ||
603 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); | ||
604 | reg = AUX_ADDR_15_8(reg_addr); | ||
605 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); | ||
606 | reg = AUX_ADDR_19_16(reg_addr); | ||
607 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); | ||
608 | |||
609 | /* | ||
610 | * Set DisplayPort transaction and read 1 byte | ||
611 | * If bit 3 is 1, DisplayPort transaction. | ||
612 | * If Bit 3 is 0, I2C transaction. | ||
613 | */ | ||
614 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; | ||
615 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); | ||
616 | |||
617 | /* Start AUX transaction */ | ||
618 | retval = analogix_dp_start_aux_transaction(dp); | ||
619 | if (retval == 0) | ||
620 | break; | ||
621 | |||
622 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); | ||
623 | } | ||
624 | |||
625 | /* Read data buffer */ | ||
626 | reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0); | ||
627 | *data = (unsigned char)(reg & 0xff); | ||
628 | |||
629 | return retval; | ||
630 | } | ||
631 | |||
632 | int analogix_dp_write_bytes_to_dpcd(struct analogix_dp_device *dp, | ||
633 | unsigned int reg_addr, | ||
634 | unsigned int count, | ||
635 | unsigned char data[]) | ||
636 | { | ||
637 | u32 reg; | ||
638 | unsigned int start_offset; | ||
639 | unsigned int cur_data_count; | ||
640 | unsigned int cur_data_idx; | ||
641 | int i; | ||
642 | int retval = 0; | ||
643 | |||
644 | /* Clear AUX CH data buffer */ | ||
645 | reg = BUF_CLR; | ||
646 | writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); | ||
647 | |||
648 | start_offset = 0; | ||
649 | while (start_offset < count) { | ||
650 | /* Buffer size of AUX CH is 16 * 4bytes */ | ||
651 | if ((count - start_offset) > 16) | ||
652 | cur_data_count = 16; | ||
653 | else | ||
654 | cur_data_count = count - start_offset; | ||
655 | |||
656 | for (i = 0; i < 3; i++) { | ||
657 | /* Select DPCD device address */ | ||
658 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | ||
659 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); | ||
660 | reg = AUX_ADDR_15_8(reg_addr + start_offset); | ||
661 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); | ||
662 | reg = AUX_ADDR_19_16(reg_addr + start_offset); | ||
663 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); | ||
664 | |||
665 | for (cur_data_idx = 0; cur_data_idx < cur_data_count; | ||
666 | cur_data_idx++) { | ||
667 | reg = data[start_offset + cur_data_idx]; | ||
668 | writel(reg, dp->reg_base + | ||
669 | ANALOGIX_DP_BUF_DATA_0 + | ||
670 | 4 * cur_data_idx); | ||
671 | } | ||
672 | |||
673 | /* | ||
674 | * Set DisplayPort transaction and write | ||
675 | * If bit 3 is 1, DisplayPort transaction. | ||
676 | * If Bit 3 is 0, I2C transaction. | ||
677 | */ | ||
678 | reg = AUX_LENGTH(cur_data_count) | | ||
679 | AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; | ||
680 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); | ||
681 | |||
682 | /* Start AUX transaction */ | ||
683 | retval = analogix_dp_start_aux_transaction(dp); | ||
684 | if (retval == 0) | ||
685 | break; | ||
686 | |||
687 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", | ||
688 | __func__); | ||
689 | } | ||
690 | |||
691 | start_offset += cur_data_count; | ||
692 | } | ||
693 | |||
694 | return retval; | ||
695 | } | ||
696 | |||
697 | int analogix_dp_read_bytes_from_dpcd(struct analogix_dp_device *dp, | ||
698 | unsigned int reg_addr, | ||
699 | unsigned int count, | ||
700 | unsigned char data[]) | ||
701 | { | ||
702 | u32 reg; | ||
703 | unsigned int start_offset; | ||
704 | unsigned int cur_data_count; | ||
705 | unsigned int cur_data_idx; | ||
706 | int i; | ||
707 | int retval = 0; | ||
708 | |||
709 | /* Clear AUX CH data buffer */ | ||
710 | reg = BUF_CLR; | ||
711 | writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); | ||
712 | |||
713 | start_offset = 0; | ||
714 | while (start_offset < count) { | ||
715 | /* Buffer size of AUX CH is 16 * 4bytes */ | ||
716 | if ((count - start_offset) > 16) | ||
717 | cur_data_count = 16; | ||
718 | else | ||
719 | cur_data_count = count - start_offset; | ||
720 | |||
721 | /* AUX CH Request Transaction process */ | ||
722 | for (i = 0; i < 3; i++) { | ||
723 | /* Select DPCD device address */ | ||
724 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | ||
725 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); | ||
726 | reg = AUX_ADDR_15_8(reg_addr + start_offset); | ||
727 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); | ||
728 | reg = AUX_ADDR_19_16(reg_addr + start_offset); | ||
729 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); | ||
730 | |||
731 | /* | ||
732 | * Set DisplayPort transaction and read | ||
733 | * If bit 3 is 1, DisplayPort transaction. | ||
734 | * If Bit 3 is 0, I2C transaction. | ||
735 | */ | ||
736 | reg = AUX_LENGTH(cur_data_count) | | ||
737 | AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; | ||
738 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); | ||
739 | |||
740 | /* Start AUX transaction */ | ||
741 | retval = analogix_dp_start_aux_transaction(dp); | ||
742 | if (retval == 0) | ||
743 | break; | ||
744 | |||
745 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", | ||
746 | __func__); | ||
747 | } | ||
748 | |||
749 | for (cur_data_idx = 0; cur_data_idx < cur_data_count; | ||
750 | cur_data_idx++) { | ||
751 | reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 | ||
752 | + 4 * cur_data_idx); | ||
753 | data[start_offset + cur_data_idx] = | ||
754 | (unsigned char)reg; | ||
755 | } | ||
756 | |||
757 | start_offset += cur_data_count; | ||
758 | } | ||
759 | |||
760 | return retval; | ||
761 | } | ||
762 | |||
763 | int analogix_dp_select_i2c_device(struct analogix_dp_device *dp, | ||
764 | unsigned int device_addr, | ||
765 | unsigned int reg_addr) | ||
766 | { | ||
767 | u32 reg; | ||
768 | int retval; | ||
769 | |||
770 | /* Set EDID device address */ | ||
771 | reg = device_addr; | ||
772 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); | ||
773 | writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); | ||
774 | writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); | ||
775 | |||
776 | /* Set offset from base address of EDID device */ | ||
777 | writel(reg_addr, dp->reg_base + ANALOGIX_DP_BUF_DATA_0); | ||
778 | |||
779 | /* | ||
780 | * Set I2C transaction and write address | ||
781 | * If bit 3 is 1, DisplayPort transaction. | ||
782 | * If Bit 3 is 0, I2C transaction. | ||
783 | */ | ||
784 | reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | | ||
785 | AUX_TX_COMM_WRITE; | ||
786 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); | ||
787 | |||
788 | /* Start AUX transaction */ | ||
789 | retval = analogix_dp_start_aux_transaction(dp); | ||
790 | if (retval != 0) | ||
791 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); | ||
792 | |||
793 | return retval; | ||
794 | } | ||
795 | |||
796 | int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp, | ||
797 | unsigned int device_addr, | ||
798 | unsigned int reg_addr, | ||
799 | unsigned int *data) | ||
800 | { | ||
801 | u32 reg; | ||
802 | int i; | ||
803 | int retval; | ||
804 | |||
805 | for (i = 0; i < 3; i++) { | ||
806 | /* Clear AUX CH data buffer */ | ||
807 | reg = BUF_CLR; | ||
808 | writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); | ||
809 | |||
810 | /* Select EDID device */ | ||
811 | retval = analogix_dp_select_i2c_device(dp, device_addr, | ||
812 | reg_addr); | ||
813 | if (retval != 0) | ||
814 | continue; | ||
815 | |||
816 | /* | ||
817 | * Set I2C transaction and read data | ||
818 | * If bit 3 is 1, DisplayPort transaction. | ||
819 | * If Bit 3 is 0, I2C transaction. | ||
820 | */ | ||
821 | reg = AUX_TX_COMM_I2C_TRANSACTION | | ||
822 | AUX_TX_COMM_READ; | ||
823 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); | ||
824 | |||
825 | /* Start AUX transaction */ | ||
826 | retval = analogix_dp_start_aux_transaction(dp); | ||
827 | if (retval == 0) | ||
828 | break; | ||
829 | |||
830 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); | ||
831 | } | ||
832 | |||
833 | /* Read data */ | ||
834 | if (retval == 0) | ||
835 | *data = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0); | ||
836 | |||
837 | return retval; | ||
838 | } | ||
839 | |||
840 | int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp, | ||
841 | unsigned int device_addr, | ||
842 | unsigned int reg_addr, | ||
843 | unsigned int count, | ||
844 | unsigned char edid[]) | ||
845 | { | ||
846 | u32 reg; | ||
847 | unsigned int i, j; | ||
848 | unsigned int cur_data_idx; | ||
849 | unsigned int defer = 0; | ||
850 | int retval = 0; | ||
851 | |||
852 | for (i = 0; i < count; i += 16) { | ||
853 | for (j = 0; j < 3; j++) { | ||
854 | /* Clear AUX CH data buffer */ | ||
855 | reg = BUF_CLR; | ||
856 | writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); | ||
857 | |||
858 | /* Set normal AUX CH command */ | ||
859 | reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); | ||
860 | reg &= ~ADDR_ONLY; | ||
861 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); | ||
862 | |||
863 | /* | ||
864 | * If Rx sends defer, Tx sends only reads | ||
865 | * request without sending address | ||
866 | */ | ||
867 | if (!defer) | ||
868 | retval = analogix_dp_select_i2c_device(dp, | ||
869 | device_addr, reg_addr + i); | ||
870 | else | ||
871 | defer = 0; | ||
872 | |||
873 | if (retval == 0) { | ||
874 | /* | ||
875 | * Set I2C transaction and write data | ||
876 | * If bit 3 is 1, DisplayPort transaction. | ||
877 | * If Bit 3 is 0, I2C transaction. | ||
878 | */ | ||
879 | reg = AUX_LENGTH(16) | | ||
880 | AUX_TX_COMM_I2C_TRANSACTION | | ||
881 | AUX_TX_COMM_READ; | ||
882 | writel(reg, dp->reg_base + | ||
883 | ANALOGIX_DP_AUX_CH_CTL_1); | ||
884 | |||
885 | /* Start AUX transaction */ | ||
886 | retval = analogix_dp_start_aux_transaction(dp); | ||
887 | if (retval == 0) | ||
888 | break; | ||
889 | |||
890 | dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", | ||
891 | __func__); | ||
892 | } | ||
893 | /* Check if Rx sends defer */ | ||
894 | reg = readl(dp->reg_base + ANALOGIX_DP_AUX_RX_COMM); | ||
895 | if (reg == AUX_RX_COMM_AUX_DEFER || | ||
896 | reg == AUX_RX_COMM_I2C_DEFER) { | ||
897 | dev_err(dp->dev, "Defer: %d\n\n", reg); | ||
898 | defer = 1; | ||
899 | } | ||
900 | } | ||
901 | |||
902 | for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { | ||
903 | reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 | ||
904 | + 4 * cur_data_idx); | ||
905 | edid[i + cur_data_idx] = (unsigned char)reg; | ||
906 | } | ||
907 | } | ||
908 | |||
909 | return retval; | ||
910 | } | ||
911 | |||
912 | void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype) | 588 | void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype) |
913 | { | 589 | { |
914 | u32 reg; | 590 | u32 reg; |
@@ -1361,3 +1037,130 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, | |||
1361 | val |= IF_EN; | 1037 | val |= IF_EN; |
1362 | writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); | 1038 | writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); |
1363 | } | 1039 | } |
1040 | |||
1041 | ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, | ||
1042 | struct drm_dp_aux_msg *msg) | ||
1043 | { | ||
1044 | u32 reg; | ||
1045 | u8 *buffer = msg->buffer; | ||
1046 | int timeout_loop = 0; | ||
1047 | unsigned int i; | ||
1048 | int num_transferred = 0; | ||
1049 | |||
1050 | /* Buffer size of AUX CH is 16 bytes */ | ||
1051 | if (WARN_ON(msg->size > 16)) | ||
1052 | return -E2BIG; | ||
1053 | |||
1054 | /* Clear AUX CH data buffer */ | ||
1055 | reg = BUF_CLR; | ||
1056 | writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); | ||
1057 | |||
1058 | switch (msg->request & ~DP_AUX_I2C_MOT) { | ||
1059 | case DP_AUX_I2C_WRITE: | ||
1060 | reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_I2C_TRANSACTION; | ||
1061 | if (msg->request & DP_AUX_I2C_MOT) | ||
1062 | reg |= AUX_TX_COMM_MOT; | ||
1063 | break; | ||
1064 | |||
1065 | case DP_AUX_I2C_READ: | ||
1066 | reg = AUX_TX_COMM_READ | AUX_TX_COMM_I2C_TRANSACTION; | ||
1067 | if (msg->request & DP_AUX_I2C_MOT) | ||
1068 | reg |= AUX_TX_COMM_MOT; | ||
1069 | break; | ||
1070 | |||
1071 | case DP_AUX_NATIVE_WRITE: | ||
1072 | reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_DP_TRANSACTION; | ||
1073 | break; | ||
1074 | |||
1075 | case DP_AUX_NATIVE_READ: | ||
1076 | reg = AUX_TX_COMM_READ | AUX_TX_COMM_DP_TRANSACTION; | ||
1077 | break; | ||
1078 | |||
1079 | default: | ||
1080 | return -EINVAL; | ||
1081 | } | ||
1082 | |||
1083 | reg |= AUX_LENGTH(msg->size); | ||
1084 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); | ||
1085 | |||
1086 | /* Select DPCD device address */ | ||
1087 | reg = AUX_ADDR_7_0(msg->address); | ||
1088 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); | ||
1089 | reg = AUX_ADDR_15_8(msg->address); | ||
1090 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); | ||
1091 | reg = AUX_ADDR_19_16(msg->address); | ||
1092 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); | ||
1093 | |||
1094 | if (!(msg->request & DP_AUX_I2C_READ)) { | ||
1095 | for (i = 0; i < msg->size; i++) { | ||
1096 | reg = buffer[i]; | ||
1097 | writel(reg, dp->reg_base + ANALOGIX_DP_BUF_DATA_0 + | ||
1098 | 4 * i); | ||
1099 | num_transferred++; | ||
1100 | } | ||
1101 | } | ||
1102 | |||
1103 | /* Enable AUX CH operation */ | ||
1104 | reg = AUX_EN; | ||
1105 | |||
1106 | /* Zero-sized messages specify address-only transactions. */ | ||
1107 | if (msg->size < 1) | ||
1108 | reg |= ADDR_ONLY; | ||
1109 | |||
1110 | writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); | ||
1111 | |||
1112 | /* Is AUX CH command reply received? */ | ||
1113 | /* TODO: Wait for an interrupt instead of looping? */ | ||
1114 | reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); | ||
1115 | while (!(reg & RPLY_RECEIV)) { | ||
1116 | timeout_loop++; | ||
1117 | if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { | ||
1118 | dev_err(dp->dev, "AUX CH command reply failed!\n"); | ||
1119 | return -ETIMEDOUT; | ||
1120 | } | ||
1121 | reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); | ||
1122 | usleep_range(10, 11); | ||
1123 | } | ||
1124 | |||
1125 | /* Clear interrupt source for AUX CH command reply */ | ||
1126 | writel(RPLY_RECEIV, dp->reg_base + ANALOGIX_DP_INT_STA); | ||
1127 | |||
1128 | /* Clear interrupt source for AUX CH access error */ | ||
1129 | reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); | ||
1130 | if (reg & AUX_ERR) { | ||
1131 | writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA); | ||
1132 | return -EREMOTEIO; | ||
1133 | } | ||
1134 | |||
1135 | /* Check AUX CH error access status */ | ||
1136 | reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA); | ||
1137 | if ((reg & AUX_STATUS_MASK)) { | ||
1138 | dev_err(dp->dev, "AUX CH error happened: %d\n\n", | ||
1139 | reg & AUX_STATUS_MASK); | ||
1140 | return -EREMOTEIO; | ||
1141 | } | ||
1142 | |||
1143 | if (msg->request & DP_AUX_I2C_READ) { | ||
1144 | for (i = 0; i < msg->size; i++) { | ||
1145 | reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 + | ||
1146 | 4 * i); | ||
1147 | buffer[i] = (unsigned char)reg; | ||
1148 | num_transferred++; | ||
1149 | } | ||
1150 | } | ||
1151 | |||
1152 | /* Check if Rx sends defer */ | ||
1153 | reg = readl(dp->reg_base + ANALOGIX_DP_AUX_RX_COMM); | ||
1154 | if (reg == AUX_RX_COMM_AUX_DEFER) | ||
1155 | msg->reply = DP_AUX_NATIVE_REPLY_DEFER; | ||
1156 | else if (reg == AUX_RX_COMM_I2C_DEFER) | ||
1157 | msg->reply = DP_AUX_I2C_REPLY_DEFER; | ||
1158 | else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE || | ||
1159 | (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_READ) | ||
1160 | msg->reply = DP_AUX_I2C_REPLY_ACK; | ||
1161 | else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE || | ||
1162 | (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_READ) | ||
1163 | msg->reply = DP_AUX_NATIVE_REPLY_ACK; | ||
1164 | |||
1165 | return num_transferred; | ||
1166 | } | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index 1cc9ee607128..bb2438dd8733 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c | |||
@@ -150,7 +150,8 @@ static int cirrus_bo_verify_access(struct ttm_buffer_object *bo, struct file *fi | |||
150 | { | 150 | { |
151 | struct cirrus_bo *cirrusbo = cirrus_bo(bo); | 151 | struct cirrus_bo *cirrusbo = cirrus_bo(bo); |
152 | 152 | ||
153 | return drm_vma_node_verify_access(&cirrusbo->gem.vma_node, filp); | 153 | return drm_vma_node_verify_access(&cirrusbo->gem.vma_node, |
154 | filp->private_data); | ||
154 | } | 155 | } |
155 | 156 | ||
156 | static int cirrus_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | 157 | static int cirrus_ttm_io_mem_reserve(struct ttm_bo_device *bdev, |
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index ea78d70de9f3..c3f83476f996 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -1693,7 +1693,7 @@ fail: | |||
1693 | } | 1693 | } |
1694 | EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); | 1694 | EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); |
1695 | 1695 | ||
1696 | bool plane_crtc_active(struct drm_plane_state *state) | 1696 | static bool plane_crtc_active(const struct drm_plane_state *state) |
1697 | { | 1697 | { |
1698 | return state->crtc && state->crtc->state->active; | 1698 | return state->crtc && state->crtc->state->active; |
1699 | } | 1699 | } |
diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 0813b7e021be..85172a977bf3 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c | |||
@@ -25,12 +25,173 @@ | |||
25 | */ | 25 | */ |
26 | #include <drm/drmP.h> | 26 | #include <drm/drmP.h> |
27 | #include <drm/drm_atomic.h> | 27 | #include <drm/drm_atomic.h> |
28 | #include <drm/drm_crtc.h> | 28 | #include <drm/drm_blend.h> |
29 | #include <linux/export.h> | 29 | #include <linux/export.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/sort.h> | 31 | #include <linux/sort.h> |
32 | 32 | ||
33 | #include "drm_internal.h" | 33 | #include "drm_crtc_internal.h" |
34 | |||
35 | /** | ||
36 | * DOC: overview | ||
37 | * | ||
38 | * The basic plane composition model supported by standard plane properties only | ||
39 | * has a source rectangle (in logical pixels within the &drm_framebuffer), with | ||
40 | * sub-pixel accuracy, which is scaled up to a pixel-aligned destination | ||
41 | * rectangle in the visible area of a &drm_crtc. The visible area of a CRTC is | ||
42 | * defined by the horizontal and vertical visible pixels (stored in @hdisplay | ||
43 | * and @vdisplay) of the requested mode (stored in @mode in the | ||
44 | * &drm_crtc_state). These two rectangles are both stored in the | ||
45 | * &drm_plane_state. | ||
46 | * | ||
47 | * For the atomic ioctl the following standard (atomic) properties on the plane object | ||
48 | * encode the basic plane composition model: | ||
49 | * | ||
50 | * SRC_X: | ||
51 | * X coordinate offset for the source rectangle within the | ||
52 | * &drm_framebuffer, in 16.16 fixed point. Must be positive. | ||
53 | * SRC_Y: | ||
54 | * Y coordinate offset for the source rectangle within the | ||
55 | * &drm_framebuffer, in 16.16 fixed point. Must be positive. | ||
56 | * SRC_W: | ||
57 | * Width for the source rectangle within the &drm_framebuffer, in 16.16 | ||
58 | * fixed point. SRC_X plus SRC_W must be within the width of the source | ||
59 | * framebuffer. Must be positive. | ||
60 | * SRC_H: | ||
61 | * Height for the source rectangle within the &drm_framebuffer, in 16.16 | ||
62 | * fixed point. SRC_Y plus SRC_H must be within the height of the source | ||
63 | * framebuffer. Must be positive. | ||
64 | * CRTC_X: | ||
65 | * X coordinate offset for the destination rectangle. Can be negative. | ||
66 | * CRTC_Y: | ||
67 | * Y coordinate offset for the destination rectangle. Can be negative. | ||
68 | * CRTC_W: | ||
69 | * Width for the destination rectangle. CRTC_X plus CRTC_W can extend past | ||
70 | * the currently visible horizontal area of the &drm_crtc. | ||
71 | * CRTC_H: | ||
72 | * Height for the destination rectangle. CRTC_Y plus CRTC_H can extend past | ||
73 | * the currently visible vertical area of the &drm_crtc. | ||
74 | * FB_ID: | ||
75 | * Mode object ID of the &drm_framebuffer this plane should scan out. | ||
76 | * CRTC_ID: | ||
77 | * Mode object ID of the &drm_crtc this plane should be connected to. | ||
78 | * | ||
79 | * Note that the source rectangle must fully lie within the bounds of the | ||
80 | * &drm_framebuffer. The destination rectangle can lie outside of the visible | ||
81 | * area of the current mode of the CRTC. It must be apprpriately clipped by the | ||
82 | * driver, which can be done by calling drm_plane_helper_check_update(). Drivers | ||
83 | * are also allowed to round the subpixel sampling positions appropriately, but | ||
84 | * only to the next full pixel. No pixel outside of the source rectangle may | ||
85 | * ever be sampled, which is important when applying more sophisticated | ||
86 | * filtering than just a bilinear one when scaling. The filtering mode when | ||
87 | * scaling is unspecified. | ||
88 | * | ||
89 | * On top of this basic transformation additional properties can be exposed by | ||
90 | * the driver: | ||
91 | * | ||
92 | * - Rotation is set up with drm_mode_create_rotation_property(). It adds a | ||
93 | * rotation and reflection step between the source and destination rectangles. | ||
94 | * Without this property the rectangle is only scaled, but not rotated or | ||
95 | * reflected. | ||
96 | * | ||
97 | * - Z position is set up with drm_plane_create_zpos_immutable_property() and | ||
98 | * drm_plane_create_zpos_property(). It controls the visibility of overlapping | ||
99 | * planes. Without this property the primary plane is always below the cursor | ||
100 | * plane, and ordering between all other planes is undefined. | ||
101 | * | ||
102 | * Note that all the property extensions described here apply either to the | ||
103 | * plane or the CRTC (e.g. for the background color, which currently is not | ||
104 | * exposed and assumed to be black). | ||
105 | */ | ||
106 | |||
107 | /** | ||
108 | * drm_mode_create_rotation_property - create a new rotation property | ||
109 | * @dev: DRM device | ||
110 | * @supported_rotations: bitmask of supported rotations and reflections | ||
111 | * | ||
112 | * This creates a new property with the selected support for transformations. | ||
113 | * The resulting property should be stored in @rotation_property in | ||
114 | * &drm_mode_config. It then must be attached to each plane which supports | ||
115 | * rotations using drm_object_attach_property(). | ||
116 | * | ||
117 | * FIXME: Probably better if the rotation property is created on each plane, | ||
118 | * like the zpos property. Otherwise it's not possible to allow different | ||
119 | * rotation modes on different planes. | ||
120 | * | ||
121 | * Since a rotation by 180° degress is the same as reflecting both along the x | ||
122 | * and the y axis the rotation property is somewhat redundant. Drivers can use | ||
123 | * drm_rotation_simplify() to normalize values of this property. | ||
124 | * | ||
125 | * The property exposed to userspace is a bitmask property (see | ||
126 | * drm_property_create_bitmask()) called "rotation" and has the following | ||
127 | * bitmask enumaration values: | ||
128 | * | ||
129 | * DRM_ROTATE_0: | ||
130 | * "rotate-0" | ||
131 | * DRM_ROTATE_90: | ||
132 | * "rotate-90" | ||
133 | * DRM_ROTATE_180: | ||
134 | * "rotate-180" | ||
135 | * DRM_ROTATE_270: | ||
136 | * "rotate-270" | ||
137 | * DRM_REFLECT_X: | ||
138 | * "reflect-x" | ||
139 | * DRM_REFELCT_Y: | ||
140 | * "reflect-y" | ||
141 | * | ||
142 | * Rotation is the specified amount in degrees in counter clockwise direction, | ||
143 | * the X and Y axis are within the source rectangle, i.e. the X/Y axis before | ||
144 | * rotation. After reflection, the rotation is applied to the image sampled from | ||
145 | * the source rectangle, before scaling it to fit the destination rectangle. | ||
146 | */ | ||
147 | struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, | ||
148 | unsigned int supported_rotations) | ||
149 | { | ||
150 | static const struct drm_prop_enum_list props[] = { | ||
151 | { __builtin_ffs(DRM_ROTATE_0) - 1, "rotate-0" }, | ||
152 | { __builtin_ffs(DRM_ROTATE_90) - 1, "rotate-90" }, | ||
153 | { __builtin_ffs(DRM_ROTATE_180) - 1, "rotate-180" }, | ||
154 | { __builtin_ffs(DRM_ROTATE_270) - 1, "rotate-270" }, | ||
155 | { __builtin_ffs(DRM_REFLECT_X) - 1, "reflect-x" }, | ||
156 | { __builtin_ffs(DRM_REFLECT_Y) - 1, "reflect-y" }, | ||
157 | }; | ||
158 | |||
159 | return drm_property_create_bitmask(dev, 0, "rotation", | ||
160 | props, ARRAY_SIZE(props), | ||
161 | supported_rotations); | ||
162 | } | ||
163 | EXPORT_SYMBOL(drm_mode_create_rotation_property); | ||
164 | |||
165 | /** | ||
166 | * drm_rotation_simplify() - Try to simplify the rotation | ||
167 | * @rotation: Rotation to be simplified | ||
168 | * @supported_rotations: Supported rotations | ||
169 | * | ||
170 | * Attempt to simplify the rotation to a form that is supported. | ||
171 | * Eg. if the hardware supports everything except DRM_REFLECT_X | ||
172 | * one could call this function like this: | ||
173 | * | ||
174 | * drm_rotation_simplify(rotation, DRM_ROTATE_0 | | ||
175 | * DRM_ROTATE_90 | DRM_ROTATE_180 | | ||
176 | * DRM_ROTATE_270 | DRM_REFLECT_Y); | ||
177 | * | ||
178 | * to eliminate the DRM_ROTATE_X flag. Depending on what kind of | ||
179 | * transforms the hardware supports, this function may not | ||
180 | * be able to produce a supported transform, so the caller should | ||
181 | * check the result afterwards. | ||
182 | */ | ||
183 | unsigned int drm_rotation_simplify(unsigned int rotation, | ||
184 | unsigned int supported_rotations) | ||
185 | { | ||
186 | if (rotation & ~supported_rotations) { | ||
187 | rotation ^= DRM_REFLECT_X | DRM_REFLECT_Y; | ||
188 | rotation = (rotation & DRM_REFLECT_MASK) | | ||
189 | BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4); | ||
190 | } | ||
191 | |||
192 | return rotation; | ||
193 | } | ||
194 | EXPORT_SYMBOL(drm_rotation_simplify); | ||
34 | 195 | ||
35 | /** | 196 | /** |
36 | * drm_plane_create_zpos_property - create mutable zpos property | 197 | * drm_plane_create_zpos_property - create mutable zpos property |
@@ -49,10 +210,14 @@ | |||
49 | * If zpos of some planes cannot be changed (like fixed background or | 210 | * If zpos of some planes cannot be changed (like fixed background or |
50 | * cursor/topmost planes), driver should adjust min/max values and assign those | 211 | * cursor/topmost planes), driver should adjust min/max values and assign those |
51 | * planes immutable zpos property with lower or higher values (for more | 212 | * planes immutable zpos property with lower or higher values (for more |
52 | * information, see drm_mode_create_zpos_immutable_property() function). In such | 213 | * information, see drm_plane_create_zpos_immutable_property() function). In such |
53 | * case driver should also assign proper initial zpos values for all planes in | 214 | * case driver should also assign proper initial zpos values for all planes in |
54 | * its plane_reset() callback, so the planes will be always sorted properly. | 215 | * its plane_reset() callback, so the planes will be always sorted properly. |
55 | * | 216 | * |
217 | * See also drm_atomic_normalize_zpos(). | ||
218 | * | ||
219 | * The property exposed to userspace is called "zpos". | ||
220 | * | ||
56 | * Returns: | 221 | * Returns: |
57 | * Zero on success, negative errno on failure. | 222 | * Zero on success, negative errno on failure. |
58 | */ | 223 | */ |
@@ -88,7 +253,9 @@ EXPORT_SYMBOL(drm_plane_create_zpos_property); | |||
88 | * support for it in drm core. Using this property driver lets userspace | 253 | * support for it in drm core. Using this property driver lets userspace |
89 | * to get the arrangement of the planes for blending operation and notifies | 254 | * to get the arrangement of the planes for blending operation and notifies |
90 | * it that the hardware (or driver) doesn't support changing of the planes' | 255 | * it that the hardware (or driver) doesn't support changing of the planes' |
91 | * order. | 256 | * order. For mutable zpos see drm_plane_create_zpos_property(). |
257 | * | ||
258 | * The property exposed to userspace is called "zpos". | ||
92 | * | 259 | * |
93 | * Returns: | 260 | * Returns: |
94 | * Zero on success, negative errno on failure. | 261 | * Zero on success, negative errno on failure. |
@@ -127,20 +294,6 @@ static int drm_atomic_state_zpos_cmp(const void *a, const void *b) | |||
127 | return sa->plane->base.id - sb->plane->base.id; | 294 | return sa->plane->base.id - sb->plane->base.id; |
128 | } | 295 | } |
129 | 296 | ||
130 | /** | ||
131 | * drm_atomic_helper_crtc_normalize_zpos - calculate normalized zpos values | ||
132 | * @crtc: crtc with planes, which have to be considered for normalization | ||
133 | * @crtc_state: new atomic state to apply | ||
134 | * | ||
135 | * This function checks new states of all planes assigned to given crtc and | ||
136 | * calculates normalized zpos value for them. Planes are compared first by their | ||
137 | * zpos values, then by plane id (if zpos equals). Plane with lowest zpos value | ||
138 | * is at the bottom. The plane_state->normalized_zpos is then filled with unique | ||
139 | * values from 0 to number of active planes in crtc minus one. | ||
140 | * | ||
141 | * RETURNS | ||
142 | * Zero for success or -errno | ||
143 | */ | ||
144 | static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc, | 297 | static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc, |
145 | struct drm_crtc_state *crtc_state) | 298 | struct drm_crtc_state *crtc_state) |
146 | { | 299 | { |
@@ -198,8 +351,14 @@ done: | |||
198 | * @state: atomic state of DRM device | 351 | * @state: atomic state of DRM device |
199 | * | 352 | * |
200 | * This function calculates normalized zpos value for all modified planes in | 353 | * This function calculates normalized zpos value for all modified planes in |
201 | * the provided atomic state of DRM device. For more information, see | 354 | * the provided atomic state of DRM device. |
202 | * drm_atomic_helper_crtc_normalize_zpos() function. | 355 | * |
356 | * For every CRTC this function checks new states of all planes assigned to | ||
357 | * it and calculates normalized zpos value for these planes. Planes are compared | ||
358 | * first by their zpos values, then by plane id (if zpos is equal). The plane | ||
359 | * with lowest zpos value is at the bottom. The plane_state->normalized_zpos is | ||
360 | * then filled with unique values from 0 to number of active planes in crtc | ||
361 | * minus one. | ||
203 | * | 362 | * |
204 | * RETURNS | 363 | * RETURNS |
205 | * Zero for success or -errno | 364 | * Zero for success or -errno |
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 484046664d6c..0ee052b7c21a 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c | |||
@@ -23,10 +23,9 @@ | |||
23 | 23 | ||
24 | #include <linux/err.h> | 24 | #include <linux/err.h> |
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/mutex.h> | ||
26 | 27 | ||
27 | #include <drm/drm_crtc.h> | 28 | #include <drm/drm_bridge.h> |
28 | |||
29 | #include "drm/drmP.h" | ||
30 | 29 | ||
31 | /** | 30 | /** |
32 | * DOC: overview | 31 | * DOC: overview |
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 32191513e82d..adb1dd7fde5f 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c | |||
@@ -755,7 +755,7 @@ int drm_legacy_addbufs_agp(struct drm_device *dev, | |||
755 | return -EINVAL; | 755 | return -EINVAL; |
756 | } | 756 | } |
757 | 757 | ||
758 | entry->buflist = kzalloc(count * sizeof(*entry->buflist), GFP_KERNEL); | 758 | entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL); |
759 | if (!entry->buflist) { | 759 | if (!entry->buflist) { |
760 | mutex_unlock(&dev->struct_mutex); | 760 | mutex_unlock(&dev->struct_mutex); |
761 | atomic_dec(&dev->buf_alloc); | 761 | atomic_dec(&dev->buf_alloc); |
@@ -905,14 +905,14 @@ int drm_legacy_addbufs_pci(struct drm_device *dev, | |||
905 | return -EINVAL; | 905 | return -EINVAL; |
906 | } | 906 | } |
907 | 907 | ||
908 | entry->buflist = kzalloc(count * sizeof(*entry->buflist), GFP_KERNEL); | 908 | entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL); |
909 | if (!entry->buflist) { | 909 | if (!entry->buflist) { |
910 | mutex_unlock(&dev->struct_mutex); | 910 | mutex_unlock(&dev->struct_mutex); |
911 | atomic_dec(&dev->buf_alloc); | 911 | atomic_dec(&dev->buf_alloc); |
912 | return -ENOMEM; | 912 | return -ENOMEM; |
913 | } | 913 | } |
914 | 914 | ||
915 | entry->seglist = kzalloc(count * sizeof(*entry->seglist), GFP_KERNEL); | 915 | entry->seglist = kcalloc(count, sizeof(*entry->seglist), GFP_KERNEL); |
916 | if (!entry->seglist) { | 916 | if (!entry->seglist) { |
917 | kfree(entry->buflist); | 917 | kfree(entry->buflist); |
918 | mutex_unlock(&dev->struct_mutex); | 918 | mutex_unlock(&dev->struct_mutex); |
@@ -923,8 +923,9 @@ int drm_legacy_addbufs_pci(struct drm_device *dev, | |||
923 | /* Keep the original pagelist until we know all the allocations | 923 | /* Keep the original pagelist until we know all the allocations |
924 | * have succeeded | 924 | * have succeeded |
925 | */ | 925 | */ |
926 | temp_pagelist = kmalloc((dma->page_count + (count << page_order)) * | 926 | temp_pagelist = kmalloc_array(dma->page_count + (count << page_order), |
927 | sizeof(*dma->pagelist), GFP_KERNEL); | 927 | sizeof(*dma->pagelist), |
928 | GFP_KERNEL); | ||
928 | if (!temp_pagelist) { | 929 | if (!temp_pagelist) { |
929 | kfree(entry->buflist); | 930 | kfree(entry->buflist); |
930 | kfree(entry->seglist); | 931 | kfree(entry->seglist); |
@@ -1116,8 +1117,7 @@ static int drm_legacy_addbufs_sg(struct drm_device *dev, | |||
1116 | return -EINVAL; | 1117 | return -EINVAL; |
1117 | } | 1118 | } |
1118 | 1119 | ||
1119 | entry->buflist = kzalloc(count * sizeof(*entry->buflist), | 1120 | entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL); |
1120 | GFP_KERNEL); | ||
1121 | if (!entry->buflist) { | 1121 | if (!entry->buflist) { |
1122 | mutex_unlock(&dev->struct_mutex); | 1122 | mutex_unlock(&dev->struct_mutex); |
1123 | atomic_dec(&dev->buf_alloc); | 1123 | atomic_dec(&dev->buf_alloc); |
diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c new file mode 100644 index 000000000000..d28ffdd2b929 --- /dev/null +++ b/drivers/gpu/drm/drm_color_mgmt.c | |||
@@ -0,0 +1,296 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 Intel Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that copyright | ||
7 | * notice and this permission notice appear in supporting documentation, and | ||
8 | * that the name of the copyright holders not be used in advertising or | ||
9 | * publicity pertaining to distribution of the software without specific, | ||
10 | * written prior permission. The copyright holders make no representations | ||
11 | * about the suitability of this software for any purpose. It is provided "as | ||
12 | * is" without express or implied warranty. | ||
13 | * | ||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
20 | * OF THIS SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <drm/drmP.h> | ||
24 | #include <drm/drm_crtc.h> | ||
25 | #include <drm/drm_color_mgmt.h> | ||
26 | |||
27 | #include "drm_crtc_internal.h" | ||
28 | |||
29 | /** | ||
30 | * DOC: overview | ||
31 | * | ||
32 | * Color management or color space adjustments is supported through a set of 5 | ||
33 | * properties on the &drm_crtc object. They are set up by calling | ||
34 | * drm_crtc_enable_color_mgmt(). | ||
35 | * | ||
36 | * "DEGAMMA_LUT”: | ||
37 | * Blob property to set the degamma lookup table (LUT) mapping pixel data | ||
38 | * from the framebuffer before it is given to the transformation matrix. | ||
39 | * The data is interpreted as an array of struct &drm_color_lut elements. | ||
40 | * Hardware might choose not to use the full precision of the LUT elements | ||
41 | * nor use all the elements of the LUT (for example the hardware might | ||
42 | * choose to interpolate between LUT[0] and LUT[4]). | ||
43 | * | ||
44 | * “DEGAMMA_LUT_SIZE”: | ||
45 | * Unsinged range property to give the size of the lookup table to be set | ||
46 | * on the DEGAMMA_LUT property (the size depends on the underlying | ||
47 | * hardware). If drivers support multiple LUT sizes then they should | ||
48 | * publish the largest size, and sub-sample smaller sized LUTs (e.g. for | ||
49 | * split-gamma modes) appropriately. | ||
50 | * | ||
51 | * “CTM”: | ||
52 | * Blob property to set the current transformation matrix (CTM) apply to | ||
53 | * pixel data after the lookup through the degamma LUT and before the | ||
54 | * lookup through the gamma LUT. The data is interpreted as a struct | ||
55 | * &drm_color_ctm. | ||
56 | * | ||
57 | * “GAMMA_LUT”: | ||
58 | * Blob property to set the gamma lookup table (LUT) mapping pixel data | ||
59 | * after the transformation matrix to data sent to the connector. The | ||
60 | * data is interpreted as an array of struct &drm_color_lut elements. | ||
61 | * Hardware might choose not to use the full precision of the LUT elements | ||
62 | * nor use all the elements of the LUT (for example the hardware might | ||
63 | * choose to interpolate between LUT[0] and LUT[4]). | ||
64 | * | ||
65 | * “GAMMA_LUT_SIZE”: | ||
66 | * Unsigned range property to give the size of the lookup table to be set | ||
67 | * on the GAMMA_LUT property (the size depends on the underlying hardware). | ||
68 | * If drivers support multiple LUT sizes then they should publish the | ||
69 | * largest size, and sub-sample smaller sized LUTs (e.g. for split-gamma | ||
70 | * modes) appropriately. | ||
71 | * | ||
72 | * There is also support for a legacy gamma table, which is set up by calling | ||
73 | * drm_mode_crtc_set_gamma_size(). Drivers which support both should use | ||
74 | * drm_atomic_helper_legacy_gamma_set() to alias the legacy gamma ramp with the | ||
75 | * "GAMMA_LUT" property above. | ||
76 | */ | ||
77 | |||
78 | /** | ||
79 | * drm_crtc_enable_color_mgmt - enable color management properties | ||
80 | * @crtc: DRM CRTC | ||
81 | * @degamma_lut_size: the size of the degamma lut (before CSC) | ||
82 | * @has_ctm: whether to attach ctm_property for CSC matrix | ||
83 | * @gamma_lut_size: the size of the gamma lut (after CSC) | ||
84 | * | ||
85 | * This function lets the driver enable the color correction | ||
86 | * properties on a CRTC. This includes 3 degamma, csc and gamma | ||
87 | * properties that userspace can set and 2 size properties to inform | ||
88 | * the userspace of the lut sizes. Each of the properties are | ||
89 | * optional. The gamma and degamma properties are only attached if | ||
90 | * their size is not 0 and ctm_property is only attached if has_ctm is | ||
91 | * true. | ||
92 | */ | ||
93 | void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, | ||
94 | uint degamma_lut_size, | ||
95 | bool has_ctm, | ||
96 | uint gamma_lut_size) | ||
97 | { | ||
98 | struct drm_device *dev = crtc->dev; | ||
99 | struct drm_mode_config *config = &dev->mode_config; | ||
100 | |||
101 | if (degamma_lut_size) { | ||
102 | drm_object_attach_property(&crtc->base, | ||
103 | config->degamma_lut_property, 0); | ||
104 | drm_object_attach_property(&crtc->base, | ||
105 | config->degamma_lut_size_property, | ||
106 | degamma_lut_size); | ||
107 | } | ||
108 | |||
109 | if (has_ctm) | ||
110 | drm_object_attach_property(&crtc->base, | ||
111 | config->ctm_property, 0); | ||
112 | |||
113 | if (gamma_lut_size) { | ||
114 | drm_object_attach_property(&crtc->base, | ||
115 | config->gamma_lut_property, 0); | ||
116 | drm_object_attach_property(&crtc->base, | ||
117 | config->gamma_lut_size_property, | ||
118 | gamma_lut_size); | ||
119 | } | ||
120 | } | ||
121 | EXPORT_SYMBOL(drm_crtc_enable_color_mgmt); | ||
122 | |||
123 | /** | ||
124 | * drm_mode_crtc_set_gamma_size - set the gamma table size | ||
125 | * @crtc: CRTC to set the gamma table size for | ||
126 | * @gamma_size: size of the gamma table | ||
127 | * | ||
128 | * Drivers which support gamma tables should set this to the supported gamma | ||
129 | * table size when initializing the CRTC. Currently the drm core only supports a | ||
130 | * fixed gamma table size. | ||
131 | * | ||
132 | * Returns: | ||
133 | * Zero on success, negative errno on failure. | ||
134 | */ | ||
135 | int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, | ||
136 | int gamma_size) | ||
137 | { | ||
138 | uint16_t *r_base, *g_base, *b_base; | ||
139 | int i; | ||
140 | |||
141 | crtc->gamma_size = gamma_size; | ||
142 | |||
143 | crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, | ||
144 | GFP_KERNEL); | ||
145 | if (!crtc->gamma_store) { | ||
146 | crtc->gamma_size = 0; | ||
147 | return -ENOMEM; | ||
148 | } | ||
149 | |||
150 | r_base = crtc->gamma_store; | ||
151 | g_base = r_base + gamma_size; | ||
152 | b_base = g_base + gamma_size; | ||
153 | for (i = 0; i < gamma_size; i++) { | ||
154 | r_base[i] = i << 8; | ||
155 | g_base[i] = i << 8; | ||
156 | b_base[i] = i << 8; | ||
157 | } | ||
158 | |||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); | ||
163 | |||
164 | /** | ||
165 | * drm_mode_gamma_set_ioctl - set the gamma table | ||
166 | * @dev: DRM device | ||
167 | * @data: ioctl data | ||
168 | * @file_priv: DRM file info | ||
169 | * | ||
170 | * Set the gamma table of a CRTC to the one passed in by the user. Userspace can | ||
171 | * inquire the required gamma table size through drm_mode_gamma_get_ioctl. | ||
172 | * | ||
173 | * Called by the user via ioctl. | ||
174 | * | ||
175 | * Returns: | ||
176 | * Zero on success, negative errno on failure. | ||
177 | */ | ||
178 | int drm_mode_gamma_set_ioctl(struct drm_device *dev, | ||
179 | void *data, struct drm_file *file_priv) | ||
180 | { | ||
181 | struct drm_mode_crtc_lut *crtc_lut = data; | ||
182 | struct drm_crtc *crtc; | ||
183 | void *r_base, *g_base, *b_base; | ||
184 | int size; | ||
185 | int ret = 0; | ||
186 | |||
187 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
188 | return -EINVAL; | ||
189 | |||
190 | drm_modeset_lock_all(dev); | ||
191 | crtc = drm_crtc_find(dev, crtc_lut->crtc_id); | ||
192 | if (!crtc) { | ||
193 | ret = -ENOENT; | ||
194 | goto out; | ||
195 | } | ||
196 | |||
197 | if (crtc->funcs->gamma_set == NULL) { | ||
198 | ret = -ENOSYS; | ||
199 | goto out; | ||
200 | } | ||
201 | |||
202 | /* memcpy into gamma store */ | ||
203 | if (crtc_lut->gamma_size != crtc->gamma_size) { | ||
204 | ret = -EINVAL; | ||
205 | goto out; | ||
206 | } | ||
207 | |||
208 | size = crtc_lut->gamma_size * (sizeof(uint16_t)); | ||
209 | r_base = crtc->gamma_store; | ||
210 | if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { | ||
211 | ret = -EFAULT; | ||
212 | goto out; | ||
213 | } | ||
214 | |||
215 | g_base = r_base + size; | ||
216 | if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { | ||
217 | ret = -EFAULT; | ||
218 | goto out; | ||
219 | } | ||
220 | |||
221 | b_base = g_base + size; | ||
222 | if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { | ||
223 | ret = -EFAULT; | ||
224 | goto out; | ||
225 | } | ||
226 | |||
227 | ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); | ||
228 | |||
229 | out: | ||
230 | drm_modeset_unlock_all(dev); | ||
231 | return ret; | ||
232 | |||
233 | } | ||
234 | |||
235 | /** | ||
236 | * drm_mode_gamma_get_ioctl - get the gamma table | ||
237 | * @dev: DRM device | ||
238 | * @data: ioctl data | ||
239 | * @file_priv: DRM file info | ||
240 | * | ||
241 | * Copy the current gamma table into the storage provided. This also provides | ||
242 | * the gamma table size the driver expects, which can be used to size the | ||
243 | * allocated storage. | ||
244 | * | ||
245 | * Called by the user via ioctl. | ||
246 | * | ||
247 | * Returns: | ||
248 | * Zero on success, negative errno on failure. | ||
249 | */ | ||
250 | int drm_mode_gamma_get_ioctl(struct drm_device *dev, | ||
251 | void *data, struct drm_file *file_priv) | ||
252 | { | ||
253 | struct drm_mode_crtc_lut *crtc_lut = data; | ||
254 | struct drm_crtc *crtc; | ||
255 | void *r_base, *g_base, *b_base; | ||
256 | int size; | ||
257 | int ret = 0; | ||
258 | |||
259 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
260 | return -EINVAL; | ||
261 | |||
262 | drm_modeset_lock_all(dev); | ||
263 | crtc = drm_crtc_find(dev, crtc_lut->crtc_id); | ||
264 | if (!crtc) { | ||
265 | ret = -ENOENT; | ||
266 | goto out; | ||
267 | } | ||
268 | |||
269 | /* memcpy into gamma store */ | ||
270 | if (crtc_lut->gamma_size != crtc->gamma_size) { | ||
271 | ret = -EINVAL; | ||
272 | goto out; | ||
273 | } | ||
274 | |||
275 | size = crtc_lut->gamma_size * (sizeof(uint16_t)); | ||
276 | r_base = crtc->gamma_store; | ||
277 | if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { | ||
278 | ret = -EFAULT; | ||
279 | goto out; | ||
280 | } | ||
281 | |||
282 | g_base = r_base + size; | ||
283 | if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { | ||
284 | ret = -EFAULT; | ||
285 | goto out; | ||
286 | } | ||
287 | |||
288 | b_base = g_base + size; | ||
289 | if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { | ||
290 | ret = -EFAULT; | ||
291 | goto out; | ||
292 | } | ||
293 | out: | ||
294 | drm_modeset_unlock_all(dev); | ||
295 | return ret; | ||
296 | } | ||
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 631691bae01d..2d7bedf28647 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -151,7 +151,11 @@ static void drm_crtc_unregister_all(struct drm_device *dev) | |||
151 | * @funcs: callbacks for the new CRTC | 151 | * @funcs: callbacks for the new CRTC |
152 | * @name: printf style format string for the CRTC name, or NULL for default name | 152 | * @name: printf style format string for the CRTC name, or NULL for default name |
153 | * | 153 | * |
154 | * Inits a new object created as base part of a driver crtc object. | 154 | * Inits a new object created as base part of a driver crtc object. Drivers |
155 | * should use this function instead of drm_crtc_init(), which is only provided | ||
156 | * for backwards compatibility with drivers which do not yet support universal | ||
157 | * planes). For really simple hardware which has only 1 plane look at | ||
158 | * drm_simple_display_pipe_init() instead. | ||
155 | * | 159 | * |
156 | * Returns: | 160 | * Returns: |
157 | * Zero on success, error code on failure. | 161 | * Zero on success, error code on failure. |
@@ -251,255 +255,6 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) | |||
251 | } | 255 | } |
252 | EXPORT_SYMBOL(drm_crtc_cleanup); | 256 | EXPORT_SYMBOL(drm_crtc_cleanup); |
253 | 257 | ||
254 | static unsigned int drm_num_planes(struct drm_device *dev) | ||
255 | { | ||
256 | unsigned int num = 0; | ||
257 | struct drm_plane *tmp; | ||
258 | |||
259 | drm_for_each_plane(tmp, dev) { | ||
260 | num++; | ||
261 | } | ||
262 | |||
263 | return num; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * drm_universal_plane_init - Initialize a new universal plane object | ||
268 | * @dev: DRM device | ||
269 | * @plane: plane object to init | ||
270 | * @possible_crtcs: bitmask of possible CRTCs | ||
271 | * @funcs: callbacks for the new plane | ||
272 | * @formats: array of supported formats (DRM_FORMAT\_\*) | ||
273 | * @format_count: number of elements in @formats | ||
274 | * @type: type of plane (overlay, primary, cursor) | ||
275 | * @name: printf style format string for the plane name, or NULL for default name | ||
276 | * | ||
277 | * Initializes a plane object of type @type. | ||
278 | * | ||
279 | * Returns: | ||
280 | * Zero on success, error code on failure. | ||
281 | */ | ||
282 | int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | ||
283 | unsigned long possible_crtcs, | ||
284 | const struct drm_plane_funcs *funcs, | ||
285 | const uint32_t *formats, unsigned int format_count, | ||
286 | enum drm_plane_type type, | ||
287 | const char *name, ...) | ||
288 | { | ||
289 | struct drm_mode_config *config = &dev->mode_config; | ||
290 | int ret; | ||
291 | |||
292 | ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); | ||
293 | if (ret) | ||
294 | return ret; | ||
295 | |||
296 | drm_modeset_lock_init(&plane->mutex); | ||
297 | |||
298 | plane->base.properties = &plane->properties; | ||
299 | plane->dev = dev; | ||
300 | plane->funcs = funcs; | ||
301 | plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), | ||
302 | GFP_KERNEL); | ||
303 | if (!plane->format_types) { | ||
304 | DRM_DEBUG_KMS("out of memory when allocating plane\n"); | ||
305 | drm_mode_object_unregister(dev, &plane->base); | ||
306 | return -ENOMEM; | ||
307 | } | ||
308 | |||
309 | if (name) { | ||
310 | va_list ap; | ||
311 | |||
312 | va_start(ap, name); | ||
313 | plane->name = kvasprintf(GFP_KERNEL, name, ap); | ||
314 | va_end(ap); | ||
315 | } else { | ||
316 | plane->name = kasprintf(GFP_KERNEL, "plane-%d", | ||
317 | drm_num_planes(dev)); | ||
318 | } | ||
319 | if (!plane->name) { | ||
320 | kfree(plane->format_types); | ||
321 | drm_mode_object_unregister(dev, &plane->base); | ||
322 | return -ENOMEM; | ||
323 | } | ||
324 | |||
325 | memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); | ||
326 | plane->format_count = format_count; | ||
327 | plane->possible_crtcs = possible_crtcs; | ||
328 | plane->type = type; | ||
329 | |||
330 | list_add_tail(&plane->head, &config->plane_list); | ||
331 | plane->index = config->num_total_plane++; | ||
332 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) | ||
333 | config->num_overlay_plane++; | ||
334 | |||
335 | drm_object_attach_property(&plane->base, | ||
336 | config->plane_type_property, | ||
337 | plane->type); | ||
338 | |||
339 | if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { | ||
340 | drm_object_attach_property(&plane->base, config->prop_fb_id, 0); | ||
341 | drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); | ||
342 | drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); | ||
343 | drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); | ||
344 | drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); | ||
345 | drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); | ||
346 | drm_object_attach_property(&plane->base, config->prop_src_x, 0); | ||
347 | drm_object_attach_property(&plane->base, config->prop_src_y, 0); | ||
348 | drm_object_attach_property(&plane->base, config->prop_src_w, 0); | ||
349 | drm_object_attach_property(&plane->base, config->prop_src_h, 0); | ||
350 | } | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | EXPORT_SYMBOL(drm_universal_plane_init); | ||
355 | |||
356 | static int drm_plane_register_all(struct drm_device *dev) | ||
357 | { | ||
358 | struct drm_plane *plane; | ||
359 | int ret = 0; | ||
360 | |||
361 | drm_for_each_plane(plane, dev) { | ||
362 | if (plane->funcs->late_register) | ||
363 | ret = plane->funcs->late_register(plane); | ||
364 | if (ret) | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static void drm_plane_unregister_all(struct drm_device *dev) | ||
372 | { | ||
373 | struct drm_plane *plane; | ||
374 | |||
375 | drm_for_each_plane(plane, dev) { | ||
376 | if (plane->funcs->early_unregister) | ||
377 | plane->funcs->early_unregister(plane); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | /** | ||
382 | * drm_plane_init - Initialize a legacy plane | ||
383 | * @dev: DRM device | ||
384 | * @plane: plane object to init | ||
385 | * @possible_crtcs: bitmask of possible CRTCs | ||
386 | * @funcs: callbacks for the new plane | ||
387 | * @formats: array of supported formats (DRM_FORMAT\_\*) | ||
388 | * @format_count: number of elements in @formats | ||
389 | * @is_primary: plane type (primary vs overlay) | ||
390 | * | ||
391 | * Legacy API to initialize a DRM plane. | ||
392 | * | ||
393 | * New drivers should call drm_universal_plane_init() instead. | ||
394 | * | ||
395 | * Returns: | ||
396 | * Zero on success, error code on failure. | ||
397 | */ | ||
398 | int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, | ||
399 | unsigned long possible_crtcs, | ||
400 | const struct drm_plane_funcs *funcs, | ||
401 | const uint32_t *formats, unsigned int format_count, | ||
402 | bool is_primary) | ||
403 | { | ||
404 | enum drm_plane_type type; | ||
405 | |||
406 | type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; | ||
407 | return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, | ||
408 | formats, format_count, type, NULL); | ||
409 | } | ||
410 | EXPORT_SYMBOL(drm_plane_init); | ||
411 | |||
412 | /** | ||
413 | * drm_plane_cleanup - Clean up the core plane usage | ||
414 | * @plane: plane to cleanup | ||
415 | * | ||
416 | * This function cleans up @plane and removes it from the DRM mode setting | ||
417 | * core. Note that the function does *not* free the plane structure itself, | ||
418 | * this is the responsibility of the caller. | ||
419 | */ | ||
420 | void drm_plane_cleanup(struct drm_plane *plane) | ||
421 | { | ||
422 | struct drm_device *dev = plane->dev; | ||
423 | |||
424 | drm_modeset_lock_all(dev); | ||
425 | kfree(plane->format_types); | ||
426 | drm_mode_object_unregister(dev, &plane->base); | ||
427 | |||
428 | BUG_ON(list_empty(&plane->head)); | ||
429 | |||
430 | /* Note that the plane_list is considered to be static; should we | ||
431 | * remove the drm_plane at runtime we would have to decrement all | ||
432 | * the indices on the drm_plane after us in the plane_list. | ||
433 | */ | ||
434 | |||
435 | list_del(&plane->head); | ||
436 | dev->mode_config.num_total_plane--; | ||
437 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) | ||
438 | dev->mode_config.num_overlay_plane--; | ||
439 | drm_modeset_unlock_all(dev); | ||
440 | |||
441 | WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); | ||
442 | if (plane->state && plane->funcs->atomic_destroy_state) | ||
443 | plane->funcs->atomic_destroy_state(plane, plane->state); | ||
444 | |||
445 | kfree(plane->name); | ||
446 | |||
447 | memset(plane, 0, sizeof(*plane)); | ||
448 | } | ||
449 | EXPORT_SYMBOL(drm_plane_cleanup); | ||
450 | |||
451 | /** | ||
452 | * drm_plane_from_index - find the registered plane at an index | ||
453 | * @dev: DRM device | ||
454 | * @idx: index of registered plane to find for | ||
455 | * | ||
456 | * Given a plane index, return the registered plane from DRM device's | ||
457 | * list of planes with matching index. | ||
458 | */ | ||
459 | struct drm_plane * | ||
460 | drm_plane_from_index(struct drm_device *dev, int idx) | ||
461 | { | ||
462 | struct drm_plane *plane; | ||
463 | |||
464 | drm_for_each_plane(plane, dev) | ||
465 | if (idx == plane->index) | ||
466 | return plane; | ||
467 | |||
468 | return NULL; | ||
469 | } | ||
470 | EXPORT_SYMBOL(drm_plane_from_index); | ||
471 | |||
472 | /** | ||
473 | * drm_plane_force_disable - Forcibly disable a plane | ||
474 | * @plane: plane to disable | ||
475 | * | ||
476 | * Forces the plane to be disabled. | ||
477 | * | ||
478 | * Used when the plane's current framebuffer is destroyed, | ||
479 | * and when restoring fbdev mode. | ||
480 | */ | ||
481 | void drm_plane_force_disable(struct drm_plane *plane) | ||
482 | { | ||
483 | int ret; | ||
484 | |||
485 | if (!plane->fb) | ||
486 | return; | ||
487 | |||
488 | plane->old_fb = plane->fb; | ||
489 | ret = plane->funcs->disable_plane(plane); | ||
490 | if (ret) { | ||
491 | DRM_ERROR("failed to disable plane with busy fb\n"); | ||
492 | plane->old_fb = NULL; | ||
493 | return; | ||
494 | } | ||
495 | /* disconnect the plane from the fb and crtc: */ | ||
496 | drm_framebuffer_unreference(plane->old_fb); | ||
497 | plane->old_fb = NULL; | ||
498 | plane->fb = NULL; | ||
499 | plane->crtc = NULL; | ||
500 | } | ||
501 | EXPORT_SYMBOL(drm_plane_force_disable); | ||
502 | |||
503 | int drm_modeset_register_all(struct drm_device *dev) | 258 | int drm_modeset_register_all(struct drm_device *dev) |
504 | { | 259 | { |
505 | int ret; | 260 | int ret; |
@@ -855,343 +610,6 @@ int drm_mode_getcrtc(struct drm_device *dev, | |||
855 | } | 610 | } |
856 | 611 | ||
857 | /** | 612 | /** |
858 | * drm_mode_getplane_res - enumerate all plane resources | ||
859 | * @dev: DRM device | ||
860 | * @data: ioctl data | ||
861 | * @file_priv: DRM file info | ||
862 | * | ||
863 | * Construct a list of plane ids to return to the user. | ||
864 | * | ||
865 | * Called by the user via ioctl. | ||
866 | * | ||
867 | * Returns: | ||
868 | * Zero on success, negative errno on failure. | ||
869 | */ | ||
870 | int drm_mode_getplane_res(struct drm_device *dev, void *data, | ||
871 | struct drm_file *file_priv) | ||
872 | { | ||
873 | struct drm_mode_get_plane_res *plane_resp = data; | ||
874 | struct drm_mode_config *config; | ||
875 | struct drm_plane *plane; | ||
876 | uint32_t __user *plane_ptr; | ||
877 | int copied = 0; | ||
878 | unsigned num_planes; | ||
879 | |||
880 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
881 | return -EINVAL; | ||
882 | |||
883 | config = &dev->mode_config; | ||
884 | |||
885 | if (file_priv->universal_planes) | ||
886 | num_planes = config->num_total_plane; | ||
887 | else | ||
888 | num_planes = config->num_overlay_plane; | ||
889 | |||
890 | /* | ||
891 | * This ioctl is called twice, once to determine how much space is | ||
892 | * needed, and the 2nd time to fill it. | ||
893 | */ | ||
894 | if (num_planes && | ||
895 | (plane_resp->count_planes >= num_planes)) { | ||
896 | plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; | ||
897 | |||
898 | /* Plane lists are invariant, no locking needed. */ | ||
899 | drm_for_each_plane(plane, dev) { | ||
900 | /* | ||
901 | * Unless userspace set the 'universal planes' | ||
902 | * capability bit, only advertise overlays. | ||
903 | */ | ||
904 | if (plane->type != DRM_PLANE_TYPE_OVERLAY && | ||
905 | !file_priv->universal_planes) | ||
906 | continue; | ||
907 | |||
908 | if (put_user(plane->base.id, plane_ptr + copied)) | ||
909 | return -EFAULT; | ||
910 | copied++; | ||
911 | } | ||
912 | } | ||
913 | plane_resp->count_planes = num_planes; | ||
914 | |||
915 | return 0; | ||
916 | } | ||
917 | |||
918 | /** | ||
919 | * drm_mode_getplane - get plane configuration | ||
920 | * @dev: DRM device | ||
921 | * @data: ioctl data | ||
922 | * @file_priv: DRM file info | ||
923 | * | ||
924 | * Construct a plane configuration structure to return to the user. | ||
925 | * | ||
926 | * Called by the user via ioctl. | ||
927 | * | ||
928 | * Returns: | ||
929 | * Zero on success, negative errno on failure. | ||
930 | */ | ||
931 | int drm_mode_getplane(struct drm_device *dev, void *data, | ||
932 | struct drm_file *file_priv) | ||
933 | { | ||
934 | struct drm_mode_get_plane *plane_resp = data; | ||
935 | struct drm_plane *plane; | ||
936 | uint32_t __user *format_ptr; | ||
937 | |||
938 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
939 | return -EINVAL; | ||
940 | |||
941 | plane = drm_plane_find(dev, plane_resp->plane_id); | ||
942 | if (!plane) | ||
943 | return -ENOENT; | ||
944 | |||
945 | drm_modeset_lock(&plane->mutex, NULL); | ||
946 | if (plane->crtc) | ||
947 | plane_resp->crtc_id = plane->crtc->base.id; | ||
948 | else | ||
949 | plane_resp->crtc_id = 0; | ||
950 | |||
951 | if (plane->fb) | ||
952 | plane_resp->fb_id = plane->fb->base.id; | ||
953 | else | ||
954 | plane_resp->fb_id = 0; | ||
955 | drm_modeset_unlock(&plane->mutex); | ||
956 | |||
957 | plane_resp->plane_id = plane->base.id; | ||
958 | plane_resp->possible_crtcs = plane->possible_crtcs; | ||
959 | plane_resp->gamma_size = 0; | ||
960 | |||
961 | /* | ||
962 | * This ioctl is called twice, once to determine how much space is | ||
963 | * needed, and the 2nd time to fill it. | ||
964 | */ | ||
965 | if (plane->format_count && | ||
966 | (plane_resp->count_format_types >= plane->format_count)) { | ||
967 | format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; | ||
968 | if (copy_to_user(format_ptr, | ||
969 | plane->format_types, | ||
970 | sizeof(uint32_t) * plane->format_count)) { | ||
971 | return -EFAULT; | ||
972 | } | ||
973 | } | ||
974 | plane_resp->count_format_types = plane->format_count; | ||
975 | |||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | /** | ||
980 | * drm_plane_check_pixel_format - Check if the plane supports the pixel format | ||
981 | * @plane: plane to check for format support | ||
982 | * @format: the pixel format | ||
983 | * | ||
984 | * Returns: | ||
985 | * Zero of @plane has @format in its list of supported pixel formats, -EINVAL | ||
986 | * otherwise. | ||
987 | */ | ||
988 | int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) | ||
989 | { | ||
990 | unsigned int i; | ||
991 | |||
992 | for (i = 0; i < plane->format_count; i++) { | ||
993 | if (format == plane->format_types[i]) | ||
994 | return 0; | ||
995 | } | ||
996 | |||
997 | return -EINVAL; | ||
998 | } | ||
999 | |||
1000 | static int check_src_coords(uint32_t src_x, uint32_t src_y, | ||
1001 | uint32_t src_w, uint32_t src_h, | ||
1002 | const struct drm_framebuffer *fb) | ||
1003 | { | ||
1004 | unsigned int fb_width, fb_height; | ||
1005 | |||
1006 | fb_width = fb->width << 16; | ||
1007 | fb_height = fb->height << 16; | ||
1008 | |||
1009 | /* Make sure source coordinates are inside the fb. */ | ||
1010 | if (src_w > fb_width || | ||
1011 | src_x > fb_width - src_w || | ||
1012 | src_h > fb_height || | ||
1013 | src_y > fb_height - src_h) { | ||
1014 | DRM_DEBUG_KMS("Invalid source coordinates " | ||
1015 | "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", | ||
1016 | src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, | ||
1017 | src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, | ||
1018 | src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, | ||
1019 | src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); | ||
1020 | return -ENOSPC; | ||
1021 | } | ||
1022 | |||
1023 | return 0; | ||
1024 | } | ||
1025 | |||
1026 | /* | ||
1027 | * setplane_internal - setplane handler for internal callers | ||
1028 | * | ||
1029 | * Note that we assume an extra reference has already been taken on fb. If the | ||
1030 | * update fails, this reference will be dropped before return; if it succeeds, | ||
1031 | * the previous framebuffer (if any) will be unreferenced instead. | ||
1032 | * | ||
1033 | * src_{x,y,w,h} are provided in 16.16 fixed point format | ||
1034 | */ | ||
1035 | static int __setplane_internal(struct drm_plane *plane, | ||
1036 | struct drm_crtc *crtc, | ||
1037 | struct drm_framebuffer *fb, | ||
1038 | int32_t crtc_x, int32_t crtc_y, | ||
1039 | uint32_t crtc_w, uint32_t crtc_h, | ||
1040 | /* src_{x,y,w,h} values are 16.16 fixed point */ | ||
1041 | uint32_t src_x, uint32_t src_y, | ||
1042 | uint32_t src_w, uint32_t src_h) | ||
1043 | { | ||
1044 | int ret = 0; | ||
1045 | |||
1046 | /* No fb means shut it down */ | ||
1047 | if (!fb) { | ||
1048 | plane->old_fb = plane->fb; | ||
1049 | ret = plane->funcs->disable_plane(plane); | ||
1050 | if (!ret) { | ||
1051 | plane->crtc = NULL; | ||
1052 | plane->fb = NULL; | ||
1053 | } else { | ||
1054 | plane->old_fb = NULL; | ||
1055 | } | ||
1056 | goto out; | ||
1057 | } | ||
1058 | |||
1059 | /* Check whether this plane is usable on this CRTC */ | ||
1060 | if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { | ||
1061 | DRM_DEBUG_KMS("Invalid crtc for plane\n"); | ||
1062 | ret = -EINVAL; | ||
1063 | goto out; | ||
1064 | } | ||
1065 | |||
1066 | /* Check whether this plane supports the fb pixel format. */ | ||
1067 | ret = drm_plane_check_pixel_format(plane, fb->pixel_format); | ||
1068 | if (ret) { | ||
1069 | char *format_name = drm_get_format_name(fb->pixel_format); | ||
1070 | DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name); | ||
1071 | kfree(format_name); | ||
1072 | goto out; | ||
1073 | } | ||
1074 | |||
1075 | /* Give drivers some help against integer overflows */ | ||
1076 | if (crtc_w > INT_MAX || | ||
1077 | crtc_x > INT_MAX - (int32_t) crtc_w || | ||
1078 | crtc_h > INT_MAX || | ||
1079 | crtc_y > INT_MAX - (int32_t) crtc_h) { | ||
1080 | DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", | ||
1081 | crtc_w, crtc_h, crtc_x, crtc_y); | ||
1082 | ret = -ERANGE; | ||
1083 | goto out; | ||
1084 | } | ||
1085 | |||
1086 | ret = check_src_coords(src_x, src_y, src_w, src_h, fb); | ||
1087 | if (ret) | ||
1088 | goto out; | ||
1089 | |||
1090 | plane->old_fb = plane->fb; | ||
1091 | ret = plane->funcs->update_plane(plane, crtc, fb, | ||
1092 | crtc_x, crtc_y, crtc_w, crtc_h, | ||
1093 | src_x, src_y, src_w, src_h); | ||
1094 | if (!ret) { | ||
1095 | plane->crtc = crtc; | ||
1096 | plane->fb = fb; | ||
1097 | fb = NULL; | ||
1098 | } else { | ||
1099 | plane->old_fb = NULL; | ||
1100 | } | ||
1101 | |||
1102 | out: | ||
1103 | if (fb) | ||
1104 | drm_framebuffer_unreference(fb); | ||
1105 | if (plane->old_fb) | ||
1106 | drm_framebuffer_unreference(plane->old_fb); | ||
1107 | plane->old_fb = NULL; | ||
1108 | |||
1109 | return ret; | ||
1110 | } | ||
1111 | |||
1112 | static int setplane_internal(struct drm_plane *plane, | ||
1113 | struct drm_crtc *crtc, | ||
1114 | struct drm_framebuffer *fb, | ||
1115 | int32_t crtc_x, int32_t crtc_y, | ||
1116 | uint32_t crtc_w, uint32_t crtc_h, | ||
1117 | /* src_{x,y,w,h} values are 16.16 fixed point */ | ||
1118 | uint32_t src_x, uint32_t src_y, | ||
1119 | uint32_t src_w, uint32_t src_h) | ||
1120 | { | ||
1121 | int ret; | ||
1122 | |||
1123 | drm_modeset_lock_all(plane->dev); | ||
1124 | ret = __setplane_internal(plane, crtc, fb, | ||
1125 | crtc_x, crtc_y, crtc_w, crtc_h, | ||
1126 | src_x, src_y, src_w, src_h); | ||
1127 | drm_modeset_unlock_all(plane->dev); | ||
1128 | |||
1129 | return ret; | ||
1130 | } | ||
1131 | |||
1132 | /** | ||
1133 | * drm_mode_setplane - configure a plane's configuration | ||
1134 | * @dev: DRM device | ||
1135 | * @data: ioctl data* | ||
1136 | * @file_priv: DRM file info | ||
1137 | * | ||
1138 | * Set plane configuration, including placement, fb, scaling, and other factors. | ||
1139 | * Or pass a NULL fb to disable (planes may be disabled without providing a | ||
1140 | * valid crtc). | ||
1141 | * | ||
1142 | * Returns: | ||
1143 | * Zero on success, negative errno on failure. | ||
1144 | */ | ||
1145 | int drm_mode_setplane(struct drm_device *dev, void *data, | ||
1146 | struct drm_file *file_priv) | ||
1147 | { | ||
1148 | struct drm_mode_set_plane *plane_req = data; | ||
1149 | struct drm_plane *plane; | ||
1150 | struct drm_crtc *crtc = NULL; | ||
1151 | struct drm_framebuffer *fb = NULL; | ||
1152 | |||
1153 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1154 | return -EINVAL; | ||
1155 | |||
1156 | /* | ||
1157 | * First, find the plane, crtc, and fb objects. If not available, | ||
1158 | * we don't bother to call the driver. | ||
1159 | */ | ||
1160 | plane = drm_plane_find(dev, plane_req->plane_id); | ||
1161 | if (!plane) { | ||
1162 | DRM_DEBUG_KMS("Unknown plane ID %d\n", | ||
1163 | plane_req->plane_id); | ||
1164 | return -ENOENT; | ||
1165 | } | ||
1166 | |||
1167 | if (plane_req->fb_id) { | ||
1168 | fb = drm_framebuffer_lookup(dev, plane_req->fb_id); | ||
1169 | if (!fb) { | ||
1170 | DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", | ||
1171 | plane_req->fb_id); | ||
1172 | return -ENOENT; | ||
1173 | } | ||
1174 | |||
1175 | crtc = drm_crtc_find(dev, plane_req->crtc_id); | ||
1176 | if (!crtc) { | ||
1177 | DRM_DEBUG_KMS("Unknown crtc ID %d\n", | ||
1178 | plane_req->crtc_id); | ||
1179 | return -ENOENT; | ||
1180 | } | ||
1181 | } | ||
1182 | |||
1183 | /* | ||
1184 | * setplane_internal will take care of deref'ing either the old or new | ||
1185 | * framebuffer depending on success. | ||
1186 | */ | ||
1187 | return setplane_internal(plane, crtc, fb, | ||
1188 | plane_req->crtc_x, plane_req->crtc_y, | ||
1189 | plane_req->crtc_w, plane_req->crtc_h, | ||
1190 | plane_req->src_x, plane_req->src_y, | ||
1191 | plane_req->src_w, plane_req->src_h); | ||
1192 | } | ||
1193 | |||
1194 | /** | ||
1195 | * drm_mode_set_config_internal - helper to call ->set_config | 613 | * drm_mode_set_config_internal - helper to call ->set_config |
1196 | * @set: modeset config to set | 614 | * @set: modeset config to set |
1197 | * | 615 | * |
@@ -1281,8 +699,9 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, | |||
1281 | DRM_ROTATE_270)) | 699 | DRM_ROTATE_270)) |
1282 | swap(hdisplay, vdisplay); | 700 | swap(hdisplay, vdisplay); |
1283 | 701 | ||
1284 | return check_src_coords(x << 16, y << 16, | 702 | return drm_framebuffer_check_src_coords(x << 16, y << 16, |
1285 | hdisplay << 16, vdisplay << 16, fb); | 703 | hdisplay << 16, vdisplay << 16, |
704 | fb); | ||
1286 | } | 705 | } |
1287 | EXPORT_SYMBOL(drm_crtc_check_viewport); | 706 | EXPORT_SYMBOL(drm_crtc_check_viewport); |
1288 | 707 | ||
@@ -1469,208 +888,6 @@ out: | |||
1469 | return ret; | 888 | return ret; |
1470 | } | 889 | } |
1471 | 890 | ||
1472 | /** | ||
1473 | * drm_mode_cursor_universal - translate legacy cursor ioctl call into a | ||
1474 | * universal plane handler call | ||
1475 | * @crtc: crtc to update cursor for | ||
1476 | * @req: data pointer for the ioctl | ||
1477 | * @file_priv: drm file for the ioctl call | ||
1478 | * | ||
1479 | * Legacy cursor ioctl's work directly with driver buffer handles. To | ||
1480 | * translate legacy ioctl calls into universal plane handler calls, we need to | ||
1481 | * wrap the native buffer handle in a drm_framebuffer. | ||
1482 | * | ||
1483 | * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB | ||
1484 | * buffer with a pitch of 4*width; the universal plane interface should be used | ||
1485 | * directly in cases where the hardware can support other buffer settings and | ||
1486 | * userspace wants to make use of these capabilities. | ||
1487 | * | ||
1488 | * Returns: | ||
1489 | * Zero on success, negative errno on failure. | ||
1490 | */ | ||
1491 | static int drm_mode_cursor_universal(struct drm_crtc *crtc, | ||
1492 | struct drm_mode_cursor2 *req, | ||
1493 | struct drm_file *file_priv) | ||
1494 | { | ||
1495 | struct drm_device *dev = crtc->dev; | ||
1496 | struct drm_framebuffer *fb = NULL; | ||
1497 | struct drm_mode_fb_cmd2 fbreq = { | ||
1498 | .width = req->width, | ||
1499 | .height = req->height, | ||
1500 | .pixel_format = DRM_FORMAT_ARGB8888, | ||
1501 | .pitches = { req->width * 4 }, | ||
1502 | .handles = { req->handle }, | ||
1503 | }; | ||
1504 | int32_t crtc_x, crtc_y; | ||
1505 | uint32_t crtc_w = 0, crtc_h = 0; | ||
1506 | uint32_t src_w = 0, src_h = 0; | ||
1507 | int ret = 0; | ||
1508 | |||
1509 | BUG_ON(!crtc->cursor); | ||
1510 | WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); | ||
1511 | |||
1512 | /* | ||
1513 | * Obtain fb we'll be using (either new or existing) and take an extra | ||
1514 | * reference to it if fb != null. setplane will take care of dropping | ||
1515 | * the reference if the plane update fails. | ||
1516 | */ | ||
1517 | if (req->flags & DRM_MODE_CURSOR_BO) { | ||
1518 | if (req->handle) { | ||
1519 | fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv); | ||
1520 | if (IS_ERR(fb)) { | ||
1521 | DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); | ||
1522 | return PTR_ERR(fb); | ||
1523 | } | ||
1524 | fb->hot_x = req->hot_x; | ||
1525 | fb->hot_y = req->hot_y; | ||
1526 | } else { | ||
1527 | fb = NULL; | ||
1528 | } | ||
1529 | } else { | ||
1530 | fb = crtc->cursor->fb; | ||
1531 | if (fb) | ||
1532 | drm_framebuffer_reference(fb); | ||
1533 | } | ||
1534 | |||
1535 | if (req->flags & DRM_MODE_CURSOR_MOVE) { | ||
1536 | crtc_x = req->x; | ||
1537 | crtc_y = req->y; | ||
1538 | } else { | ||
1539 | crtc_x = crtc->cursor_x; | ||
1540 | crtc_y = crtc->cursor_y; | ||
1541 | } | ||
1542 | |||
1543 | if (fb) { | ||
1544 | crtc_w = fb->width; | ||
1545 | crtc_h = fb->height; | ||
1546 | src_w = fb->width << 16; | ||
1547 | src_h = fb->height << 16; | ||
1548 | } | ||
1549 | |||
1550 | /* | ||
1551 | * setplane_internal will take care of deref'ing either the old or new | ||
1552 | * framebuffer depending on success. | ||
1553 | */ | ||
1554 | ret = __setplane_internal(crtc->cursor, crtc, fb, | ||
1555 | crtc_x, crtc_y, crtc_w, crtc_h, | ||
1556 | 0, 0, src_w, src_h); | ||
1557 | |||
1558 | /* Update successful; save new cursor position, if necessary */ | ||
1559 | if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { | ||
1560 | crtc->cursor_x = req->x; | ||
1561 | crtc->cursor_y = req->y; | ||
1562 | } | ||
1563 | |||
1564 | return ret; | ||
1565 | } | ||
1566 | |||
1567 | static int drm_mode_cursor_common(struct drm_device *dev, | ||
1568 | struct drm_mode_cursor2 *req, | ||
1569 | struct drm_file *file_priv) | ||
1570 | { | ||
1571 | struct drm_crtc *crtc; | ||
1572 | int ret = 0; | ||
1573 | |||
1574 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1575 | return -EINVAL; | ||
1576 | |||
1577 | if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) | ||
1578 | return -EINVAL; | ||
1579 | |||
1580 | crtc = drm_crtc_find(dev, req->crtc_id); | ||
1581 | if (!crtc) { | ||
1582 | DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); | ||
1583 | return -ENOENT; | ||
1584 | } | ||
1585 | |||
1586 | /* | ||
1587 | * If this crtc has a universal cursor plane, call that plane's update | ||
1588 | * handler rather than using legacy cursor handlers. | ||
1589 | */ | ||
1590 | drm_modeset_lock_crtc(crtc, crtc->cursor); | ||
1591 | if (crtc->cursor) { | ||
1592 | ret = drm_mode_cursor_universal(crtc, req, file_priv); | ||
1593 | goto out; | ||
1594 | } | ||
1595 | |||
1596 | if (req->flags & DRM_MODE_CURSOR_BO) { | ||
1597 | if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { | ||
1598 | ret = -ENXIO; | ||
1599 | goto out; | ||
1600 | } | ||
1601 | /* Turns off the cursor if handle is 0 */ | ||
1602 | if (crtc->funcs->cursor_set2) | ||
1603 | ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, | ||
1604 | req->width, req->height, req->hot_x, req->hot_y); | ||
1605 | else | ||
1606 | ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, | ||
1607 | req->width, req->height); | ||
1608 | } | ||
1609 | |||
1610 | if (req->flags & DRM_MODE_CURSOR_MOVE) { | ||
1611 | if (crtc->funcs->cursor_move) { | ||
1612 | ret = crtc->funcs->cursor_move(crtc, req->x, req->y); | ||
1613 | } else { | ||
1614 | ret = -EFAULT; | ||
1615 | goto out; | ||
1616 | } | ||
1617 | } | ||
1618 | out: | ||
1619 | drm_modeset_unlock_crtc(crtc); | ||
1620 | |||
1621 | return ret; | ||
1622 | |||
1623 | } | ||
1624 | |||
1625 | |||
1626 | /** | ||
1627 | * drm_mode_cursor_ioctl - set CRTC's cursor configuration | ||
1628 | * @dev: drm device for the ioctl | ||
1629 | * @data: data pointer for the ioctl | ||
1630 | * @file_priv: drm file for the ioctl call | ||
1631 | * | ||
1632 | * Set the cursor configuration based on user request. | ||
1633 | * | ||
1634 | * Called by the user via ioctl. | ||
1635 | * | ||
1636 | * Returns: | ||
1637 | * Zero on success, negative errno on failure. | ||
1638 | */ | ||
1639 | int drm_mode_cursor_ioctl(struct drm_device *dev, | ||
1640 | void *data, struct drm_file *file_priv) | ||
1641 | { | ||
1642 | struct drm_mode_cursor *req = data; | ||
1643 | struct drm_mode_cursor2 new_req; | ||
1644 | |||
1645 | memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); | ||
1646 | new_req.hot_x = new_req.hot_y = 0; | ||
1647 | |||
1648 | return drm_mode_cursor_common(dev, &new_req, file_priv); | ||
1649 | } | ||
1650 | |||
1651 | /** | ||
1652 | * drm_mode_cursor2_ioctl - set CRTC's cursor configuration | ||
1653 | * @dev: drm device for the ioctl | ||
1654 | * @data: data pointer for the ioctl | ||
1655 | * @file_priv: drm file for the ioctl call | ||
1656 | * | ||
1657 | * Set the cursor configuration based on user request. This implements the 2nd | ||
1658 | * version of the cursor ioctl, which allows userspace to additionally specify | ||
1659 | * the hotspot of the pointer. | ||
1660 | * | ||
1661 | * Called by the user via ioctl. | ||
1662 | * | ||
1663 | * Returns: | ||
1664 | * Zero on success, negative errno on failure. | ||
1665 | */ | ||
1666 | int drm_mode_cursor2_ioctl(struct drm_device *dev, | ||
1667 | void *data, struct drm_file *file_priv) | ||
1668 | { | ||
1669 | struct drm_mode_cursor2 *req = data; | ||
1670 | |||
1671 | return drm_mode_cursor_common(dev, req, file_priv); | ||
1672 | } | ||
1673 | |||
1674 | int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, | 891 | int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, |
1675 | struct drm_property *property, | 892 | struct drm_property *property, |
1676 | uint64_t value) | 893 | uint64_t value) |
@@ -1687,376 +904,6 @@ int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, | |||
1687 | } | 904 | } |
1688 | 905 | ||
1689 | /** | 906 | /** |
1690 | * drm_mode_plane_set_obj_prop - set the value of a property | ||
1691 | * @plane: drm plane object to set property value for | ||
1692 | * @property: property to set | ||
1693 | * @value: value the property should be set to | ||
1694 | * | ||
1695 | * This functions sets a given property on a given plane object. This function | ||
1696 | * calls the driver's ->set_property callback and changes the software state of | ||
1697 | * the property if the callback succeeds. | ||
1698 | * | ||
1699 | * Returns: | ||
1700 | * Zero on success, error code on failure. | ||
1701 | */ | ||
1702 | int drm_mode_plane_set_obj_prop(struct drm_plane *plane, | ||
1703 | struct drm_property *property, | ||
1704 | uint64_t value) | ||
1705 | { | ||
1706 | int ret = -EINVAL; | ||
1707 | struct drm_mode_object *obj = &plane->base; | ||
1708 | |||
1709 | if (plane->funcs->set_property) | ||
1710 | ret = plane->funcs->set_property(plane, property, value); | ||
1711 | if (!ret) | ||
1712 | drm_object_property_set_value(obj, property, value); | ||
1713 | |||
1714 | return ret; | ||
1715 | } | ||
1716 | EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); | ||
1717 | |||
1718 | /** | ||
1719 | * drm_mode_crtc_set_gamma_size - set the gamma table size | ||
1720 | * @crtc: CRTC to set the gamma table size for | ||
1721 | * @gamma_size: size of the gamma table | ||
1722 | * | ||
1723 | * Drivers which support gamma tables should set this to the supported gamma | ||
1724 | * table size when initializing the CRTC. Currently the drm core only supports a | ||
1725 | * fixed gamma table size. | ||
1726 | * | ||
1727 | * Returns: | ||
1728 | * Zero on success, negative errno on failure. | ||
1729 | */ | ||
1730 | int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, | ||
1731 | int gamma_size) | ||
1732 | { | ||
1733 | uint16_t *r_base, *g_base, *b_base; | ||
1734 | int i; | ||
1735 | |||
1736 | crtc->gamma_size = gamma_size; | ||
1737 | |||
1738 | crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, | ||
1739 | GFP_KERNEL); | ||
1740 | if (!crtc->gamma_store) { | ||
1741 | crtc->gamma_size = 0; | ||
1742 | return -ENOMEM; | ||
1743 | } | ||
1744 | |||
1745 | r_base = crtc->gamma_store; | ||
1746 | g_base = r_base + gamma_size; | ||
1747 | b_base = g_base + gamma_size; | ||
1748 | for (i = 0; i < gamma_size; i++) { | ||
1749 | r_base[i] = i << 8; | ||
1750 | g_base[i] = i << 8; | ||
1751 | b_base[i] = i << 8; | ||
1752 | } | ||
1753 | |||
1754 | |||
1755 | return 0; | ||
1756 | } | ||
1757 | EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); | ||
1758 | |||
1759 | /** | ||
1760 | * drm_mode_gamma_set_ioctl - set the gamma table | ||
1761 | * @dev: DRM device | ||
1762 | * @data: ioctl data | ||
1763 | * @file_priv: DRM file info | ||
1764 | * | ||
1765 | * Set the gamma table of a CRTC to the one passed in by the user. Userspace can | ||
1766 | * inquire the required gamma table size through drm_mode_gamma_get_ioctl. | ||
1767 | * | ||
1768 | * Called by the user via ioctl. | ||
1769 | * | ||
1770 | * Returns: | ||
1771 | * Zero on success, negative errno on failure. | ||
1772 | */ | ||
1773 | int drm_mode_gamma_set_ioctl(struct drm_device *dev, | ||
1774 | void *data, struct drm_file *file_priv) | ||
1775 | { | ||
1776 | struct drm_mode_crtc_lut *crtc_lut = data; | ||
1777 | struct drm_crtc *crtc; | ||
1778 | void *r_base, *g_base, *b_base; | ||
1779 | int size; | ||
1780 | int ret = 0; | ||
1781 | |||
1782 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1783 | return -EINVAL; | ||
1784 | |||
1785 | drm_modeset_lock_all(dev); | ||
1786 | crtc = drm_crtc_find(dev, crtc_lut->crtc_id); | ||
1787 | if (!crtc) { | ||
1788 | ret = -ENOENT; | ||
1789 | goto out; | ||
1790 | } | ||
1791 | |||
1792 | if (crtc->funcs->gamma_set == NULL) { | ||
1793 | ret = -ENOSYS; | ||
1794 | goto out; | ||
1795 | } | ||
1796 | |||
1797 | /* memcpy into gamma store */ | ||
1798 | if (crtc_lut->gamma_size != crtc->gamma_size) { | ||
1799 | ret = -EINVAL; | ||
1800 | goto out; | ||
1801 | } | ||
1802 | |||
1803 | size = crtc_lut->gamma_size * (sizeof(uint16_t)); | ||
1804 | r_base = crtc->gamma_store; | ||
1805 | if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { | ||
1806 | ret = -EFAULT; | ||
1807 | goto out; | ||
1808 | } | ||
1809 | |||
1810 | g_base = r_base + size; | ||
1811 | if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { | ||
1812 | ret = -EFAULT; | ||
1813 | goto out; | ||
1814 | } | ||
1815 | |||
1816 | b_base = g_base + size; | ||
1817 | if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { | ||
1818 | ret = -EFAULT; | ||
1819 | goto out; | ||
1820 | } | ||
1821 | |||
1822 | ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); | ||
1823 | |||
1824 | out: | ||
1825 | drm_modeset_unlock_all(dev); | ||
1826 | return ret; | ||
1827 | |||
1828 | } | ||
1829 | |||
1830 | /** | ||
1831 | * drm_mode_gamma_get_ioctl - get the gamma table | ||
1832 | * @dev: DRM device | ||
1833 | * @data: ioctl data | ||
1834 | * @file_priv: DRM file info | ||
1835 | * | ||
1836 | * Copy the current gamma table into the storage provided. This also provides | ||
1837 | * the gamma table size the driver expects, which can be used to size the | ||
1838 | * allocated storage. | ||
1839 | * | ||
1840 | * Called by the user via ioctl. | ||
1841 | * | ||
1842 | * Returns: | ||
1843 | * Zero on success, negative errno on failure. | ||
1844 | */ | ||
1845 | int drm_mode_gamma_get_ioctl(struct drm_device *dev, | ||
1846 | void *data, struct drm_file *file_priv) | ||
1847 | { | ||
1848 | struct drm_mode_crtc_lut *crtc_lut = data; | ||
1849 | struct drm_crtc *crtc; | ||
1850 | void *r_base, *g_base, *b_base; | ||
1851 | int size; | ||
1852 | int ret = 0; | ||
1853 | |||
1854 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1855 | return -EINVAL; | ||
1856 | |||
1857 | drm_modeset_lock_all(dev); | ||
1858 | crtc = drm_crtc_find(dev, crtc_lut->crtc_id); | ||
1859 | if (!crtc) { | ||
1860 | ret = -ENOENT; | ||
1861 | goto out; | ||
1862 | } | ||
1863 | |||
1864 | /* memcpy into gamma store */ | ||
1865 | if (crtc_lut->gamma_size != crtc->gamma_size) { | ||
1866 | ret = -EINVAL; | ||
1867 | goto out; | ||
1868 | } | ||
1869 | |||
1870 | size = crtc_lut->gamma_size * (sizeof(uint16_t)); | ||
1871 | r_base = crtc->gamma_store; | ||
1872 | if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { | ||
1873 | ret = -EFAULT; | ||
1874 | goto out; | ||
1875 | } | ||
1876 | |||
1877 | g_base = r_base + size; | ||
1878 | if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { | ||
1879 | ret = -EFAULT; | ||
1880 | goto out; | ||
1881 | } | ||
1882 | |||
1883 | b_base = g_base + size; | ||
1884 | if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { | ||
1885 | ret = -EFAULT; | ||
1886 | goto out; | ||
1887 | } | ||
1888 | out: | ||
1889 | drm_modeset_unlock_all(dev); | ||
1890 | return ret; | ||
1891 | } | ||
1892 | |||
1893 | /** | ||
1894 | * drm_mode_page_flip_ioctl - schedule an asynchronous fb update | ||
1895 | * @dev: DRM device | ||
1896 | * @data: ioctl data | ||
1897 | * @file_priv: DRM file info | ||
1898 | * | ||
1899 | * This schedules an asynchronous update on a given CRTC, called page flip. | ||
1900 | * Optionally a drm event is generated to signal the completion of the event. | ||
1901 | * Generic drivers cannot assume that a pageflip with changed framebuffer | ||
1902 | * properties (including driver specific metadata like tiling layout) will work, | ||
1903 | * but some drivers support e.g. pixel format changes through the pageflip | ||
1904 | * ioctl. | ||
1905 | * | ||
1906 | * Called by the user via ioctl. | ||
1907 | * | ||
1908 | * Returns: | ||
1909 | * Zero on success, negative errno on failure. | ||
1910 | */ | ||
1911 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
1912 | void *data, struct drm_file *file_priv) | ||
1913 | { | ||
1914 | struct drm_mode_crtc_page_flip_target *page_flip = data; | ||
1915 | struct drm_crtc *crtc; | ||
1916 | struct drm_framebuffer *fb = NULL; | ||
1917 | struct drm_pending_vblank_event *e = NULL; | ||
1918 | u32 target_vblank = page_flip->sequence; | ||
1919 | int ret = -EINVAL; | ||
1920 | |||
1921 | if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS) | ||
1922 | return -EINVAL; | ||
1923 | |||
1924 | if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) | ||
1925 | return -EINVAL; | ||
1926 | |||
1927 | /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags | ||
1928 | * can be specified | ||
1929 | */ | ||
1930 | if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET) | ||
1931 | return -EINVAL; | ||
1932 | |||
1933 | if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) | ||
1934 | return -EINVAL; | ||
1935 | |||
1936 | crtc = drm_crtc_find(dev, page_flip->crtc_id); | ||
1937 | if (!crtc) | ||
1938 | return -ENOENT; | ||
1939 | |||
1940 | if (crtc->funcs->page_flip_target) { | ||
1941 | u32 current_vblank; | ||
1942 | int r; | ||
1943 | |||
1944 | r = drm_crtc_vblank_get(crtc); | ||
1945 | if (r) | ||
1946 | return r; | ||
1947 | |||
1948 | current_vblank = drm_crtc_vblank_count(crtc); | ||
1949 | |||
1950 | switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) { | ||
1951 | case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE: | ||
1952 | if ((int)(target_vblank - current_vblank) > 1) { | ||
1953 | DRM_DEBUG("Invalid absolute flip target %u, " | ||
1954 | "must be <= %u\n", target_vblank, | ||
1955 | current_vblank + 1); | ||
1956 | drm_crtc_vblank_put(crtc); | ||
1957 | return -EINVAL; | ||
1958 | } | ||
1959 | break; | ||
1960 | case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE: | ||
1961 | if (target_vblank != 0 && target_vblank != 1) { | ||
1962 | DRM_DEBUG("Invalid relative flip target %u, " | ||
1963 | "must be 0 or 1\n", target_vblank); | ||
1964 | drm_crtc_vblank_put(crtc); | ||
1965 | return -EINVAL; | ||
1966 | } | ||
1967 | target_vblank += current_vblank; | ||
1968 | break; | ||
1969 | default: | ||
1970 | target_vblank = current_vblank + | ||
1971 | !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC); | ||
1972 | break; | ||
1973 | } | ||
1974 | } else if (crtc->funcs->page_flip == NULL || | ||
1975 | (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) { | ||
1976 | return -EINVAL; | ||
1977 | } | ||
1978 | |||
1979 | drm_modeset_lock_crtc(crtc, crtc->primary); | ||
1980 | if (crtc->primary->fb == NULL) { | ||
1981 | /* The framebuffer is currently unbound, presumably | ||
1982 | * due to a hotplug event, that userspace has not | ||
1983 | * yet discovered. | ||
1984 | */ | ||
1985 | ret = -EBUSY; | ||
1986 | goto out; | ||
1987 | } | ||
1988 | |||
1989 | fb = drm_framebuffer_lookup(dev, page_flip->fb_id); | ||
1990 | if (!fb) { | ||
1991 | ret = -ENOENT; | ||
1992 | goto out; | ||
1993 | } | ||
1994 | |||
1995 | if (crtc->state) { | ||
1996 | const struct drm_plane_state *state = crtc->primary->state; | ||
1997 | |||
1998 | ret = check_src_coords(state->src_x, state->src_y, | ||
1999 | state->src_w, state->src_h, fb); | ||
2000 | } else { | ||
2001 | ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); | ||
2002 | } | ||
2003 | if (ret) | ||
2004 | goto out; | ||
2005 | |||
2006 | if (crtc->primary->fb->pixel_format != fb->pixel_format) { | ||
2007 | DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); | ||
2008 | ret = -EINVAL; | ||
2009 | goto out; | ||
2010 | } | ||
2011 | |||
2012 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { | ||
2013 | e = kzalloc(sizeof *e, GFP_KERNEL); | ||
2014 | if (!e) { | ||
2015 | ret = -ENOMEM; | ||
2016 | goto out; | ||
2017 | } | ||
2018 | e->event.base.type = DRM_EVENT_FLIP_COMPLETE; | ||
2019 | e->event.base.length = sizeof(e->event); | ||
2020 | e->event.user_data = page_flip->user_data; | ||
2021 | ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); | ||
2022 | if (ret) { | ||
2023 | kfree(e); | ||
2024 | goto out; | ||
2025 | } | ||
2026 | } | ||
2027 | |||
2028 | crtc->primary->old_fb = crtc->primary->fb; | ||
2029 | if (crtc->funcs->page_flip_target) | ||
2030 | ret = crtc->funcs->page_flip_target(crtc, fb, e, | ||
2031 | page_flip->flags, | ||
2032 | target_vblank); | ||
2033 | else | ||
2034 | ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); | ||
2035 | if (ret) { | ||
2036 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) | ||
2037 | drm_event_cancel_free(dev, &e->base); | ||
2038 | /* Keep the old fb, don't unref it. */ | ||
2039 | crtc->primary->old_fb = NULL; | ||
2040 | } else { | ||
2041 | crtc->primary->fb = fb; | ||
2042 | /* Unref only the old framebuffer. */ | ||
2043 | fb = NULL; | ||
2044 | } | ||
2045 | |||
2046 | out: | ||
2047 | if (ret && crtc->funcs->page_flip_target) | ||
2048 | drm_crtc_vblank_put(crtc); | ||
2049 | if (fb) | ||
2050 | drm_framebuffer_unreference(fb); | ||
2051 | if (crtc->primary->old_fb) | ||
2052 | drm_framebuffer_unreference(crtc->primary->old_fb); | ||
2053 | crtc->primary->old_fb = NULL; | ||
2054 | drm_modeset_unlock_crtc(crtc); | ||
2055 | |||
2056 | return ret; | ||
2057 | } | ||
2058 | |||
2059 | /** | ||
2060 | * drm_mode_config_reset - call ->reset callbacks | 907 | * drm_mode_config_reset - call ->reset callbacks |
2061 | * @dev: drm device | 908 | * @dev: drm device |
2062 | * | 909 | * |
@@ -2201,37 +1048,6 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, | |||
2201 | } | 1048 | } |
2202 | 1049 | ||
2203 | /** | 1050 | /** |
2204 | * drm_rotation_simplify() - Try to simplify the rotation | ||
2205 | * @rotation: Rotation to be simplified | ||
2206 | * @supported_rotations: Supported rotations | ||
2207 | * | ||
2208 | * Attempt to simplify the rotation to a form that is supported. | ||
2209 | * Eg. if the hardware supports everything except DRM_REFLECT_X | ||
2210 | * one could call this function like this: | ||
2211 | * | ||
2212 | * drm_rotation_simplify(rotation, DRM_ROTATE_0 | | ||
2213 | * DRM_ROTATE_90 | DRM_ROTATE_180 | | ||
2214 | * DRM_ROTATE_270 | DRM_REFLECT_Y); | ||
2215 | * | ||
2216 | * to eliminate the DRM_ROTATE_X flag. Depending on what kind of | ||
2217 | * transforms the hardware supports, this function may not | ||
2218 | * be able to produce a supported transform, so the caller should | ||
2219 | * check the result afterwards. | ||
2220 | */ | ||
2221 | unsigned int drm_rotation_simplify(unsigned int rotation, | ||
2222 | unsigned int supported_rotations) | ||
2223 | { | ||
2224 | if (rotation & ~supported_rotations) { | ||
2225 | rotation ^= DRM_REFLECT_X | DRM_REFLECT_Y; | ||
2226 | rotation = (rotation & DRM_REFLECT_MASK) | | ||
2227 | BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4); | ||
2228 | } | ||
2229 | |||
2230 | return rotation; | ||
2231 | } | ||
2232 | EXPORT_SYMBOL(drm_rotation_simplify); | ||
2233 | |||
2234 | /** | ||
2235 | * drm_mode_config_init - initialize DRM mode_configuration structure | 1051 | * drm_mode_config_init - initialize DRM mode_configuration structure |
2236 | * @dev: DRM device | 1052 | * @dev: DRM device |
2237 | * | 1053 | * |
@@ -2347,24 +1163,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) | |||
2347 | } | 1163 | } |
2348 | EXPORT_SYMBOL(drm_mode_config_cleanup); | 1164 | EXPORT_SYMBOL(drm_mode_config_cleanup); |
2349 | 1165 | ||
2350 | struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, | ||
2351 | unsigned int supported_rotations) | ||
2352 | { | ||
2353 | static const struct drm_prop_enum_list props[] = { | ||
2354 | { __builtin_ffs(DRM_ROTATE_0) - 1, "rotate-0" }, | ||
2355 | { __builtin_ffs(DRM_ROTATE_90) - 1, "rotate-90" }, | ||
2356 | { __builtin_ffs(DRM_ROTATE_180) - 1, "rotate-180" }, | ||
2357 | { __builtin_ffs(DRM_ROTATE_270) - 1, "rotate-270" }, | ||
2358 | { __builtin_ffs(DRM_REFLECT_X) - 1, "reflect-x" }, | ||
2359 | { __builtin_ffs(DRM_REFLECT_Y) - 1, "reflect-y" }, | ||
2360 | }; | ||
2361 | |||
2362 | return drm_property_create_bitmask(dev, 0, "rotation", | ||
2363 | props, ARRAY_SIZE(props), | ||
2364 | supported_rotations); | ||
2365 | } | ||
2366 | EXPORT_SYMBOL(drm_mode_create_rotation_property); | ||
2367 | |||
2368 | /** | 1166 | /** |
2369 | * DOC: Tile group | 1167 | * DOC: Tile group |
2370 | * | 1168 | * |
@@ -2463,48 +1261,3 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, | |||
2463 | return tg; | 1261 | return tg; |
2464 | } | 1262 | } |
2465 | EXPORT_SYMBOL(drm_mode_create_tile_group); | 1263 | EXPORT_SYMBOL(drm_mode_create_tile_group); |
2466 | |||
2467 | /** | ||
2468 | * drm_crtc_enable_color_mgmt - enable color management properties | ||
2469 | * @crtc: DRM CRTC | ||
2470 | * @degamma_lut_size: the size of the degamma lut (before CSC) | ||
2471 | * @has_ctm: whether to attach ctm_property for CSC matrix | ||
2472 | * @gamma_lut_size: the size of the gamma lut (after CSC) | ||
2473 | * | ||
2474 | * This function lets the driver enable the color correction | ||
2475 | * properties on a CRTC. This includes 3 degamma, csc and gamma | ||
2476 | * properties that userspace can set and 2 size properties to inform | ||
2477 | * the userspace of the lut sizes. Each of the properties are | ||
2478 | * optional. The gamma and degamma properties are only attached if | ||
2479 | * their size is not 0 and ctm_property is only attached if has_ctm is | ||
2480 | * true. | ||
2481 | */ | ||
2482 | void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, | ||
2483 | uint degamma_lut_size, | ||
2484 | bool has_ctm, | ||
2485 | uint gamma_lut_size) | ||
2486 | { | ||
2487 | struct drm_device *dev = crtc->dev; | ||
2488 | struct drm_mode_config *config = &dev->mode_config; | ||
2489 | |||
2490 | if (degamma_lut_size) { | ||
2491 | drm_object_attach_property(&crtc->base, | ||
2492 | config->degamma_lut_property, 0); | ||
2493 | drm_object_attach_property(&crtc->base, | ||
2494 | config->degamma_lut_size_property, | ||
2495 | degamma_lut_size); | ||
2496 | } | ||
2497 | |||
2498 | if (has_ctm) | ||
2499 | drm_object_attach_property(&crtc->base, | ||
2500 | config->ctm_property, 0); | ||
2501 | |||
2502 | if (gamma_lut_size) { | ||
2503 | drm_object_attach_property(&crtc->base, | ||
2504 | config->gamma_lut_property, 0); | ||
2505 | drm_object_attach_property(&crtc->base, | ||
2506 | config->gamma_lut_size_property, | ||
2507 | gamma_lut_size); | ||
2508 | } | ||
2509 | } | ||
2510 | EXPORT_SYMBOL(drm_crtc_enable_color_mgmt); | ||
diff --git a/drivers/gpu/drm/drm_crtc_helper_internal.h b/drivers/gpu/drm/drm_crtc_helper_internal.h index 4e6b57ae7188..28295e5d0d9e 100644 --- a/drivers/gpu/drm/drm_crtc_helper_internal.h +++ b/drivers/gpu/drm/drm_crtc_helper_internal.h | |||
@@ -29,7 +29,14 @@ | |||
29 | #include <drm/drm_dp_helper.h> | 29 | #include <drm/drm_dp_helper.h> |
30 | 30 | ||
31 | /* drm_fb_helper.c */ | 31 | /* drm_fb_helper.c */ |
32 | #ifdef CONFIG_DRM_FBDEV_EMULATION | ||
32 | int drm_fb_helper_modinit(void); | 33 | int drm_fb_helper_modinit(void); |
34 | #else | ||
35 | static inline int drm_fb_helper_modinit(void) | ||
36 | { | ||
37 | return 0; | ||
38 | } | ||
39 | #endif | ||
33 | 40 | ||
34 | /* drm_dp_aux_dev.c */ | 41 | /* drm_dp_aux_dev.c */ |
35 | #ifdef CONFIG_DRM_DP_AUX_CHARDEV | 42 | #ifdef CONFIG_DRM_DP_AUX_CHARDEV |
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 444e609078cc..c48ba02c5365 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h | |||
@@ -36,8 +36,6 @@ | |||
36 | int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, | 36 | int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, |
37 | struct drm_property *property, | 37 | struct drm_property *property, |
38 | uint64_t value); | 38 | uint64_t value); |
39 | int drm_plane_check_pixel_format(const struct drm_plane *plane, | ||
40 | u32 format); | ||
41 | int drm_crtc_check_viewport(const struct drm_crtc *crtc, | 39 | int drm_crtc_check_viewport(const struct drm_crtc *crtc, |
42 | int x, int y, | 40 | int x, int y, |
43 | const struct drm_display_mode *mode, | 41 | const struct drm_display_mode *mode, |
@@ -56,28 +54,19 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, | |||
56 | /* IOCTLs */ | 54 | /* IOCTLs */ |
57 | int drm_mode_getresources(struct drm_device *dev, | 55 | int drm_mode_getresources(struct drm_device *dev, |
58 | void *data, struct drm_file *file_priv); | 56 | void *data, struct drm_file *file_priv); |
59 | int drm_mode_getplane_res(struct drm_device *dev, void *data, | ||
60 | struct drm_file *file_priv); | ||
61 | int drm_mode_getcrtc(struct drm_device *dev, | 57 | int drm_mode_getcrtc(struct drm_device *dev, |
62 | void *data, struct drm_file *file_priv); | 58 | void *data, struct drm_file *file_priv); |
63 | int drm_mode_setcrtc(struct drm_device *dev, | 59 | int drm_mode_setcrtc(struct drm_device *dev, |
64 | void *data, struct drm_file *file_priv); | 60 | void *data, struct drm_file *file_priv); |
65 | int drm_mode_getplane(struct drm_device *dev, | 61 | |
66 | void *data, struct drm_file *file_priv); | 62 | /* drm_color_mgmt.c */ |
67 | int drm_mode_setplane(struct drm_device *dev, | 63 | |
68 | void *data, struct drm_file *file_priv); | 64 | /* IOCTLs */ |
69 | int drm_mode_cursor_ioctl(struct drm_device *dev, | ||
70 | void *data, struct drm_file *file_priv); | ||
71 | int drm_mode_cursor2_ioctl(struct drm_device *dev, | ||
72 | void *data, struct drm_file *file_priv); | ||
73 | int drm_mode_gamma_get_ioctl(struct drm_device *dev, | 65 | int drm_mode_gamma_get_ioctl(struct drm_device *dev, |
74 | void *data, struct drm_file *file_priv); | 66 | void *data, struct drm_file *file_priv); |
75 | int drm_mode_gamma_set_ioctl(struct drm_device *dev, | 67 | int drm_mode_gamma_set_ioctl(struct drm_device *dev, |
76 | void *data, struct drm_file *file_priv); | 68 | void *data, struct drm_file *file_priv); |
77 | 69 | ||
78 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
79 | void *data, struct drm_file *file_priv); | ||
80 | |||
81 | /* drm_property.c */ | 70 | /* drm_property.c */ |
82 | void drm_property_destroy_user_blobs(struct drm_device *dev, | 71 | void drm_property_destroy_user_blobs(struct drm_device *dev, |
83 | struct drm_file *file_priv); | 72 | struct drm_file *file_priv); |
@@ -155,6 +144,9 @@ drm_internal_framebuffer_create(struct drm_device *dev, | |||
155 | const struct drm_mode_fb_cmd2 *r, | 144 | const struct drm_mode_fb_cmd2 *r, |
156 | struct drm_file *file_priv); | 145 | struct drm_file *file_priv); |
157 | void drm_framebuffer_free(struct kref *kref); | 146 | void drm_framebuffer_free(struct kref *kref); |
147 | int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, | ||
148 | uint32_t src_w, uint32_t src_h, | ||
149 | const struct drm_framebuffer *fb); | ||
158 | 150 | ||
159 | /* IOCTL */ | 151 | /* IOCTL */ |
160 | int drm_mode_addfb(struct drm_device *dev, | 152 | int drm_mode_addfb(struct drm_device *dev, |
@@ -177,6 +169,23 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, | |||
177 | int drm_modeset_register_all(struct drm_device *dev); | 169 | int drm_modeset_register_all(struct drm_device *dev); |
178 | void drm_modeset_unregister_all(struct drm_device *dev); | 170 | void drm_modeset_unregister_all(struct drm_device *dev); |
179 | 171 | ||
180 | /* drm_blend.c */ | 172 | |
181 | int drm_atomic_normalize_zpos(struct drm_device *dev, | 173 | /* drm_plane.c */ |
182 | struct drm_atomic_state *state); | 174 | int drm_plane_register_all(struct drm_device *dev); |
175 | void drm_plane_unregister_all(struct drm_device *dev); | ||
176 | int drm_plane_check_pixel_format(const struct drm_plane *plane, | ||
177 | u32 format); | ||
178 | |||
179 | /* IOCTL */ | ||
180 | int drm_mode_getplane_res(struct drm_device *dev, void *data, | ||
181 | struct drm_file *file_priv); | ||
182 | int drm_mode_getplane(struct drm_device *dev, | ||
183 | void *data, struct drm_file *file_priv); | ||
184 | int drm_mode_setplane(struct drm_device *dev, | ||
185 | void *data, struct drm_file *file_priv); | ||
186 | int drm_mode_cursor_ioctl(struct drm_device *dev, | ||
187 | void *data, struct drm_file *file_priv); | ||
188 | int drm_mode_cursor2_ioctl(struct drm_device *dev, | ||
189 | void *data, struct drm_file *file_priv); | ||
190 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
191 | void *data, struct drm_file *file_priv); | ||
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 0ad20f1cdf69..ac3924a877e0 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
28 | #include <linux/sched.h> | 28 | #include <linux/sched.h> |
29 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
30 | #include <linux/seq_file.h> | ||
30 | #include <drm/drm_dp_helper.h> | 31 | #include <drm/drm_dp_helper.h> |
31 | #include <drm/drmP.h> | 32 | #include <drm/drmP.h> |
32 | 33 | ||
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index acf6a5f38920..80c7f25b5b74 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include <linux/mount.h> | 33 | #include <linux/mount.h> |
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> | ||
37 | #include "drm_crtc_internal.h" | 36 | #include "drm_crtc_internal.h" |
38 | #include "drm_legacy.h" | 37 | #include "drm_legacy.h" |
39 | #include "drm_internal.h" | 38 | #include "drm_internal.h" |
@@ -46,8 +45,8 @@ | |||
46 | unsigned int drm_debug = 0; | 45 | unsigned int drm_debug = 0; |
47 | EXPORT_SYMBOL(drm_debug); | 46 | EXPORT_SYMBOL(drm_debug); |
48 | 47 | ||
49 | MODULE_AUTHOR(CORE_AUTHOR); | 48 | MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl"); |
50 | MODULE_DESCRIPTION(CORE_DESC); | 49 | MODULE_DESCRIPTION("DRM shared core routines"); |
51 | MODULE_LICENSE("GPL and additional rights"); | 50 | MODULE_LICENSE("GPL and additional rights"); |
52 | MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n" | 51 | MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n" |
53 | "\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n" | 52 | "\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n" |
@@ -339,6 +338,9 @@ void drm_minor_release(struct drm_minor *minor) | |||
339 | 338 | ||
340 | static int drm_dev_set_unique(struct drm_device *dev, const char *name) | 339 | static int drm_dev_set_unique(struct drm_device *dev, const char *name) |
341 | { | 340 | { |
341 | if (!name) | ||
342 | return -EINVAL; | ||
343 | |||
342 | kfree(dev->unique); | 344 | kfree(dev->unique); |
343 | dev->unique = kstrdup(name, GFP_KERNEL); | 345 | dev->unique = kstrdup(name, GFP_KERNEL); |
344 | 346 | ||
@@ -589,7 +591,7 @@ EXPORT_SYMBOL(drm_dev_init); | |||
589 | * own struct should look at using drm_dev_init() instead. | 591 | * own struct should look at using drm_dev_init() instead. |
590 | * | 592 | * |
591 | * RETURNS: | 593 | * RETURNS: |
592 | * Pointer to new DRM device, or NULL if out of memory. | 594 | * Pointer to new DRM device, or ERR_PTR on failure. |
593 | */ | 595 | */ |
594 | struct drm_device *drm_dev_alloc(struct drm_driver *driver, | 596 | struct drm_device *drm_dev_alloc(struct drm_driver *driver, |
595 | struct device *parent) | 597 | struct device *parent) |
@@ -599,12 +601,12 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, | |||
599 | 601 | ||
600 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 602 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
601 | if (!dev) | 603 | if (!dev) |
602 | return NULL; | 604 | return ERR_PTR(-ENOMEM); |
603 | 605 | ||
604 | ret = drm_dev_init(dev, driver, parent); | 606 | ret = drm_dev_init(dev, driver, parent); |
605 | if (ret) { | 607 | if (ret) { |
606 | kfree(dev); | 608 | kfree(dev); |
607 | return NULL; | 609 | return ERR_PTR(ret); |
608 | } | 610 | } |
609 | 611 | ||
610 | return dev; | 612 | return dev; |
@@ -821,53 +823,48 @@ static const struct file_operations drm_stub_fops = { | |||
821 | .llseek = noop_llseek, | 823 | .llseek = noop_llseek, |
822 | }; | 824 | }; |
823 | 825 | ||
826 | static void drm_core_exit(void) | ||
827 | { | ||
828 | unregister_chrdev(DRM_MAJOR, "drm"); | ||
829 | debugfs_remove(drm_debugfs_root); | ||
830 | drm_sysfs_destroy(); | ||
831 | idr_destroy(&drm_minors_idr); | ||
832 | drm_connector_ida_destroy(); | ||
833 | drm_global_release(); | ||
834 | } | ||
835 | |||
824 | static int __init drm_core_init(void) | 836 | static int __init drm_core_init(void) |
825 | { | 837 | { |
826 | int ret = -ENOMEM; | 838 | int ret; |
827 | 839 | ||
828 | drm_global_init(); | 840 | drm_global_init(); |
829 | drm_connector_ida_init(); | 841 | drm_connector_ida_init(); |
830 | idr_init(&drm_minors_idr); | 842 | idr_init(&drm_minors_idr); |
831 | 843 | ||
832 | if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) | ||
833 | goto err_p1; | ||
834 | |||
835 | ret = drm_sysfs_init(); | 844 | ret = drm_sysfs_init(); |
836 | if (ret < 0) { | 845 | if (ret < 0) { |
837 | printk(KERN_ERR "DRM: Error creating drm class.\n"); | 846 | DRM_ERROR("Cannot create DRM class: %d\n", ret); |
838 | goto err_p2; | 847 | goto error; |
839 | } | 848 | } |
840 | 849 | ||
841 | drm_debugfs_root = debugfs_create_dir("dri", NULL); | 850 | drm_debugfs_root = debugfs_create_dir("dri", NULL); |
842 | if (!drm_debugfs_root) { | 851 | if (!drm_debugfs_root) { |
843 | DRM_ERROR("Cannot create /sys/kernel/debug/dri\n"); | 852 | ret = -ENOMEM; |
844 | ret = -1; | 853 | DRM_ERROR("Cannot create debugfs-root: %d\n", ret); |
845 | goto err_p3; | 854 | goto error; |
846 | } | 855 | } |
847 | 856 | ||
848 | DRM_INFO("Initialized %s %d.%d.%d %s\n", | 857 | ret = register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops); |
849 | CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); | 858 | if (ret < 0) |
859 | goto error; | ||
860 | |||
861 | DRM_INFO("Initialized\n"); | ||
850 | return 0; | 862 | return 0; |
851 | err_p3: | ||
852 | drm_sysfs_destroy(); | ||
853 | err_p2: | ||
854 | unregister_chrdev(DRM_MAJOR, "drm"); | ||
855 | 863 | ||
856 | idr_destroy(&drm_minors_idr); | 864 | error: |
857 | err_p1: | 865 | drm_core_exit(); |
858 | return ret; | 866 | return ret; |
859 | } | 867 | } |
860 | 868 | ||
861 | static void __exit drm_core_exit(void) | ||
862 | { | ||
863 | debugfs_remove(drm_debugfs_root); | ||
864 | drm_sysfs_destroy(); | ||
865 | |||
866 | unregister_chrdev(DRM_MAJOR, "drm"); | ||
867 | |||
868 | drm_connector_ida_destroy(); | ||
869 | idr_destroy(&drm_minors_idr); | ||
870 | } | ||
871 | |||
872 | module_init(drm_core_init); | 869 | module_init(drm_core_init); |
873 | module_exit(drm_core_exit); | 870 | module_exit(drm_core_exit); |
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index 998a6743a586..5c067719164d 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c | |||
@@ -31,20 +31,21 @@ | |||
31 | * | 31 | * |
32 | * Encoders represent the connecting element between the CRTC (as the overall | 32 | * Encoders represent the connecting element between the CRTC (as the overall |
33 | * pixel pipeline, represented by struct &drm_crtc) and the connectors (as the | 33 | * pixel pipeline, represented by struct &drm_crtc) and the connectors (as the |
34 | * generic sink entity, represented by struct &drm_connector). Encoders are | 34 | * generic sink entity, represented by struct &drm_connector). An encoder takes |
35 | * objects exposed to userspace, originally to allow userspace to infer cloning | 35 | * pixel data from a CRTC and converts it to a format suitable for any attached |
36 | * and connector/CRTC restrictions. Unfortunately almost all drivers get this | 36 | * connector. Encoders are objects exposed to userspace, originally to allow |
37 | * wrong, making the uabi pretty much useless. On top of that the exposed | 37 | * userspace to infer cloning and connector/CRTC restrictions. Unfortunately |
38 | * restrictions are too simple for todays hardware, and the recommend way to | 38 | * almost all drivers get this wrong, making the uabi pretty much useless. On |
39 | * infer restrictions is by using the DRM_MODE_ATOMIC_TEST_ONLY flag for the | 39 | * top of that the exposed restrictions are too simple for today's hardware, and |
40 | * atomic IOCTL. | 40 | * the recommended way to infer restrictions is by using the |
41 | * DRM_MODE_ATOMIC_TEST_ONLY flag for the atomic IOCTL. | ||
41 | * | 42 | * |
42 | * Otherwise encoders aren't used in the uapi at all (any modeset request from | 43 | * Otherwise encoders aren't used in the uapi at all (any modeset request from |
43 | * userspace directly connects a connector with a CRTC), drivers are therefore | 44 | * userspace directly connects a connector with a CRTC), drivers are therefore |
44 | * free to use them however they wish. Modeset helper libraries make strong use | 45 | * free to use them however they wish. Modeset helper libraries make strong use |
45 | * of encoders to facilitate code sharing. But for more complex settings it is | 46 | * of encoders to facilitate code sharing. But for more complex settings it is |
46 | * usually better to move shared code into a separate &drm_bridge. Compared to | 47 | * usually better to move shared code into a separate &drm_bridge. Compared to |
47 | * encoders bridges also have the benefit of not being purely an internal | 48 | * encoders, bridges also have the benefit of being purely an internal |
48 | * abstraction since they are not exposed to userspace at all. | 49 | * abstraction since they are not exposed to userspace at all. |
49 | * | 50 | * |
50 | * Encoders are initialized with drm_encoder_init() and cleaned up using | 51 | * Encoders are initialized with drm_encoder_init() and cleaned up using |
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index c4d350086def..5e830281bebd 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -41,6 +41,8 @@ | |||
41 | #include <drm/drm_atomic.h> | 41 | #include <drm/drm_atomic.h> |
42 | #include <drm/drm_atomic_helper.h> | 42 | #include <drm/drm_atomic_helper.h> |
43 | 43 | ||
44 | #include "drm_crtc_helper_internal.h" | ||
45 | |||
44 | static bool drm_fbdev_emulation = true; | 46 | static bool drm_fbdev_emulation = true; |
45 | module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600); | 47 | module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600); |
46 | MODULE_PARM_DESC(fbdev_emulation, | 48 | MODULE_PARM_DESC(fbdev_emulation, |
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 036cd275c53e..e84faecf5225 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c | |||
@@ -199,7 +199,6 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) | |||
199 | 199 | ||
200 | filp->private_data = priv; | 200 | filp->private_data = priv; |
201 | priv->filp = filp; | 201 | priv->filp = filp; |
202 | priv->uid = current_euid(); | ||
203 | priv->pid = get_pid(task_pid(current)); | 202 | priv->pid = get_pid(task_pid(current)); |
204 | priv->minor = minor; | 203 | priv->minor = minor; |
205 | 204 | ||
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 30dc01e6eb5d..398efd67cb93 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c | |||
@@ -62,6 +62,32 @@ | |||
62 | * &drm_framebuffer. | 62 | * &drm_framebuffer. |
63 | */ | 63 | */ |
64 | 64 | ||
65 | int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, | ||
66 | uint32_t src_w, uint32_t src_h, | ||
67 | const struct drm_framebuffer *fb) | ||
68 | { | ||
69 | unsigned int fb_width, fb_height; | ||
70 | |||
71 | fb_width = fb->width << 16; | ||
72 | fb_height = fb->height << 16; | ||
73 | |||
74 | /* Make sure source coordinates are inside the fb. */ | ||
75 | if (src_w > fb_width || | ||
76 | src_x > fb_width - src_w || | ||
77 | src_h > fb_height || | ||
78 | src_y > fb_height - src_h) { | ||
79 | DRM_DEBUG_KMS("Invalid source coordinates " | ||
80 | "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", | ||
81 | src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, | ||
82 | src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, | ||
83 | src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, | ||
84 | src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); | ||
85 | return -ENOSPC; | ||
86 | } | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
65 | /** | 91 | /** |
66 | * drm_mode_addfb - add an FB to the graphics configuration | 92 | * drm_mode_addfb - add an FB to the graphics configuration |
67 | * @dev: drm device for the ioctl | 93 | * @dev: drm device for the ioctl |
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 9134ae134667..465bacd0a630 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c | |||
@@ -257,7 +257,7 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) | |||
257 | 257 | ||
258 | if (drm_core_check_feature(dev, DRIVER_PRIME)) | 258 | if (drm_core_check_feature(dev, DRIVER_PRIME)) |
259 | drm_gem_remove_prime_handles(obj, file_priv); | 259 | drm_gem_remove_prime_handles(obj, file_priv); |
260 | drm_vma_node_revoke(&obj->vma_node, file_priv->filp); | 260 | drm_vma_node_revoke(&obj->vma_node, file_priv); |
261 | 261 | ||
262 | if (dev->driver->gem_close_object) | 262 | if (dev->driver->gem_close_object) |
263 | dev->driver->gem_close_object(obj, file_priv); | 263 | dev->driver->gem_close_object(obj, file_priv); |
@@ -372,7 +372,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, | |||
372 | 372 | ||
373 | handle = ret; | 373 | handle = ret; |
374 | 374 | ||
375 | ret = drm_vma_node_allow(&obj->vma_node, file_priv->filp); | 375 | ret = drm_vma_node_allow(&obj->vma_node, file_priv); |
376 | if (ret) | 376 | if (ret) |
377 | goto err_remove; | 377 | goto err_remove; |
378 | 378 | ||
@@ -386,7 +386,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, | |||
386 | return 0; | 386 | return 0; |
387 | 387 | ||
388 | err_revoke: | 388 | err_revoke: |
389 | drm_vma_node_revoke(&obj->vma_node, file_priv->filp); | 389 | drm_vma_node_revoke(&obj->vma_node, file_priv); |
390 | err_remove: | 390 | err_remove: |
391 | spin_lock(&file_priv->table_lock); | 391 | spin_lock(&file_priv->table_lock); |
392 | idr_remove(&file_priv->object_idr, handle); | 392 | idr_remove(&file_priv->object_idr, handle); |
@@ -991,7 +991,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) | |||
991 | if (!obj) | 991 | if (!obj) |
992 | return -EINVAL; | 992 | return -EINVAL; |
993 | 993 | ||
994 | if (!drm_vma_node_is_allowed(node, filp)) { | 994 | if (!drm_vma_node_is_allowed(node, priv)) { |
995 | drm_gem_object_unreference_unlocked(obj); | 995 | drm_gem_object_unreference_unlocked(obj); |
996 | return -EACCES; | 996 | return -EACCES; |
997 | } | 997 | } |
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index 9ae353f4dd06..1df2d33d0b40 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c | |||
@@ -80,6 +80,7 @@ int drm_clients_info(struct seq_file *m, void *data) | |||
80 | struct drm_info_node *node = (struct drm_info_node *) m->private; | 80 | struct drm_info_node *node = (struct drm_info_node *) m->private; |
81 | struct drm_device *dev = node->minor->dev; | 81 | struct drm_device *dev = node->minor->dev; |
82 | struct drm_file *priv; | 82 | struct drm_file *priv; |
83 | kuid_t uid; | ||
83 | 84 | ||
84 | seq_printf(m, | 85 | seq_printf(m, |
85 | "%20s %5s %3s master a %5s %10s\n", | 86 | "%20s %5s %3s master a %5s %10s\n", |
@@ -98,13 +99,14 @@ int drm_clients_info(struct seq_file *m, void *data) | |||
98 | 99 | ||
99 | rcu_read_lock(); /* locks pid_task()->comm */ | 100 | rcu_read_lock(); /* locks pid_task()->comm */ |
100 | task = pid_task(priv->pid, PIDTYPE_PID); | 101 | task = pid_task(priv->pid, PIDTYPE_PID); |
102 | uid = task ? __task_cred(task)->euid : GLOBAL_ROOT_UID; | ||
101 | seq_printf(m, "%20s %5d %3d %c %c %5d %10u\n", | 103 | seq_printf(m, "%20s %5d %3d %c %c %5d %10u\n", |
102 | task ? task->comm : "<unknown>", | 104 | task ? task->comm : "<unknown>", |
103 | pid_vnr(priv->pid), | 105 | pid_vnr(priv->pid), |
104 | priv->minor->index, | 106 | priv->minor->index, |
105 | drm_is_current_master(priv) ? 'y' : 'n', | 107 | drm_is_current_master(priv) ? 'y' : 'n', |
106 | priv->authenticated ? 'y' : 'n', | 108 | priv->authenticated ? 'y' : 'n', |
107 | from_kuid_munged(seq_user_ns(m), priv->uid), | 109 | from_kuid_munged(seq_user_ns(m), uid), |
108 | priv->magic); | 110 | priv->magic); |
109 | rcu_read_unlock(); | 111 | rcu_read_unlock(); |
110 | } | 112 | } |
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index b86dc9b921a5..e66af289a016 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h | |||
@@ -21,6 +21,9 @@ | |||
21 | * OTHER DEALINGS IN THE SOFTWARE. | 21 | * OTHER DEALINGS IN THE SOFTWARE. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #define DRM_IF_MAJOR 1 | ||
25 | #define DRM_IF_MINOR 4 | ||
26 | |||
24 | /* drm_irq.c */ | 27 | /* drm_irq.c */ |
25 | extern unsigned int drm_timestamp_monotonic; | 28 | extern unsigned int drm_timestamp_monotonic; |
26 | 29 | ||
diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 5f896e723f73..867ab8c1582b 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include <linux/export.h> | 32 | #include <linux/export.h> |
33 | 33 | ||
34 | #include <drm/drmP.h> | 34 | #include <drm/drmP.h> |
35 | #include <drm/drm_core.h> | ||
36 | 35 | ||
37 | #define DRM_IOCTL_VERSION32 DRM_IOWR(0x00, drm_version32_t) | 36 | #define DRM_IOCTL_VERSION32 DRM_IOWR(0x00, drm_version32_t) |
38 | #define DRM_IOCTL_GET_UNIQUE32 DRM_IOWR(0x01, drm_unique32_t) | 37 | #define DRM_IOCTL_GET_UNIQUE32 DRM_IOWR(0x01, drm_unique32_t) |
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index b97c421c65f4..0ad2c47f808f 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c | |||
@@ -29,7 +29,6 @@ | |||
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <drm/drmP.h> | 31 | #include <drm/drmP.h> |
32 | #include <drm/drm_core.h> | ||
33 | #include <drm/drm_auth.h> | 32 | #include <drm/drm_auth.h> |
34 | #include "drm_legacy.h" | 33 | #include "drm_legacy.h" |
35 | #include "drm_internal.h" | 34 | #include "drm_internal.h" |
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index d86362fc8ac6..3ceea9cb9d3e 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c | |||
@@ -236,8 +236,8 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, | |||
236 | DRM_DEBUG("\n"); | 236 | DRM_DEBUG("\n"); |
237 | 237 | ||
238 | dev = drm_dev_alloc(driver, &pdev->dev); | 238 | dev = drm_dev_alloc(driver, &pdev->dev); |
239 | if (!dev) | 239 | if (IS_ERR(dev)) |
240 | return -ENOMEM; | 240 | return PTR_ERR(dev); |
241 | 241 | ||
242 | ret = pci_enable_device(pdev); | 242 | ret = pci_enable_device(pdev); |
243 | if (ret) | 243 | if (ret) |
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c new file mode 100644 index 000000000000..cd0d475bf3c3 --- /dev/null +++ b/drivers/gpu/drm/drm_plane.c | |||
@@ -0,0 +1,907 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 Intel Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that copyright | ||
7 | * notice and this permission notice appear in supporting documentation, and | ||
8 | * that the name of the copyright holders not be used in advertising or | ||
9 | * publicity pertaining to distribution of the software without specific, | ||
10 | * written prior permission. The copyright holders make no representations | ||
11 | * about the suitability of this software for any purpose. It is provided "as | ||
12 | * is" without express or implied warranty. | ||
13 | * | ||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
20 | * OF THIS SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <drm/drmP.h> | ||
24 | #include <drm/drm_plane.h> | ||
25 | |||
26 | #include "drm_crtc_internal.h" | ||
27 | |||
28 | /** | ||
29 | * DOC: overview | ||
30 | * | ||
31 | * A plane represents an image source that can be blended with or overlayed on | ||
32 | * top of a CRTC during the scanout process. Planes take their input data from a | ||
33 | * &drm_framebuffer object. The plane itself specifies the cropping and scaling | ||
34 | * of that image, and where it is placed on the visible are of a display | ||
35 | * pipeline, represented by &drm_crtc. A plane can also have additional | ||
36 | * properties that specify how the pixels are positioned and blended, like | ||
37 | * rotation or Z-position. All these properties are stored in &drm_plane_state. | ||
38 | * | ||
39 | * To create a plane, a KMS drivers allocates and zeroes an instances of | ||
40 | * struct &drm_plane (possibly as part of a larger structure) and registers it | ||
41 | * with a call to drm_universal_plane_init(). | ||
42 | * | ||
43 | * Cursor and overlay planes are optional. All drivers should provide one | ||
44 | * primary plane per CRTC to avoid surprising userspace too much. See enum | ||
45 | * &drm_plane_type for a more in-depth discussion of these special uapi-relevant | ||
46 | * plane types. Special planes are associated with their CRTC by calling | ||
47 | * drm_crtc_init_with_planes(). | ||
48 | * | ||
49 | * The type of a plane is exposed in the immutable "type" enumeration property, | ||
50 | * which has one of the following values: "Overlay", "Primary", "Cursor". | ||
51 | */ | ||
52 | |||
53 | static unsigned int drm_num_planes(struct drm_device *dev) | ||
54 | { | ||
55 | unsigned int num = 0; | ||
56 | struct drm_plane *tmp; | ||
57 | |||
58 | drm_for_each_plane(tmp, dev) { | ||
59 | num++; | ||
60 | } | ||
61 | |||
62 | return num; | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * drm_universal_plane_init - Initialize a new universal plane object | ||
67 | * @dev: DRM device | ||
68 | * @plane: plane object to init | ||
69 | * @possible_crtcs: bitmask of possible CRTCs | ||
70 | * @funcs: callbacks for the new plane | ||
71 | * @formats: array of supported formats (DRM_FORMAT\_\*) | ||
72 | * @format_count: number of elements in @formats | ||
73 | * @type: type of plane (overlay, primary, cursor) | ||
74 | * @name: printf style format string for the plane name, or NULL for default name | ||
75 | * | ||
76 | * Initializes a plane object of type @type. | ||
77 | * | ||
78 | * Returns: | ||
79 | * Zero on success, error code on failure. | ||
80 | */ | ||
81 | int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | ||
82 | unsigned long possible_crtcs, | ||
83 | const struct drm_plane_funcs *funcs, | ||
84 | const uint32_t *formats, unsigned int format_count, | ||
85 | enum drm_plane_type type, | ||
86 | const char *name, ...) | ||
87 | { | ||
88 | struct drm_mode_config *config = &dev->mode_config; | ||
89 | int ret; | ||
90 | |||
91 | ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); | ||
92 | if (ret) | ||
93 | return ret; | ||
94 | |||
95 | drm_modeset_lock_init(&plane->mutex); | ||
96 | |||
97 | plane->base.properties = &plane->properties; | ||
98 | plane->dev = dev; | ||
99 | plane->funcs = funcs; | ||
100 | plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), | ||
101 | GFP_KERNEL); | ||
102 | if (!plane->format_types) { | ||
103 | DRM_DEBUG_KMS("out of memory when allocating plane\n"); | ||
104 | drm_mode_object_unregister(dev, &plane->base); | ||
105 | return -ENOMEM; | ||
106 | } | ||
107 | |||
108 | if (name) { | ||
109 | va_list ap; | ||
110 | |||
111 | va_start(ap, name); | ||
112 | plane->name = kvasprintf(GFP_KERNEL, name, ap); | ||
113 | va_end(ap); | ||
114 | } else { | ||
115 | plane->name = kasprintf(GFP_KERNEL, "plane-%d", | ||
116 | drm_num_planes(dev)); | ||
117 | } | ||
118 | if (!plane->name) { | ||
119 | kfree(plane->format_types); | ||
120 | drm_mode_object_unregister(dev, &plane->base); | ||
121 | return -ENOMEM; | ||
122 | } | ||
123 | |||
124 | memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); | ||
125 | plane->format_count = format_count; | ||
126 | plane->possible_crtcs = possible_crtcs; | ||
127 | plane->type = type; | ||
128 | |||
129 | list_add_tail(&plane->head, &config->plane_list); | ||
130 | plane->index = config->num_total_plane++; | ||
131 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) | ||
132 | config->num_overlay_plane++; | ||
133 | |||
134 | drm_object_attach_property(&plane->base, | ||
135 | config->plane_type_property, | ||
136 | plane->type); | ||
137 | |||
138 | if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { | ||
139 | drm_object_attach_property(&plane->base, config->prop_fb_id, 0); | ||
140 | drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); | ||
141 | drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); | ||
142 | drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); | ||
143 | drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); | ||
144 | drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); | ||
145 | drm_object_attach_property(&plane->base, config->prop_src_x, 0); | ||
146 | drm_object_attach_property(&plane->base, config->prop_src_y, 0); | ||
147 | drm_object_attach_property(&plane->base, config->prop_src_w, 0); | ||
148 | drm_object_attach_property(&plane->base, config->prop_src_h, 0); | ||
149 | } | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | EXPORT_SYMBOL(drm_universal_plane_init); | ||
154 | |||
155 | int drm_plane_register_all(struct drm_device *dev) | ||
156 | { | ||
157 | struct drm_plane *plane; | ||
158 | int ret = 0; | ||
159 | |||
160 | drm_for_each_plane(plane, dev) { | ||
161 | if (plane->funcs->late_register) | ||
162 | ret = plane->funcs->late_register(plane); | ||
163 | if (ret) | ||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | void drm_plane_unregister_all(struct drm_device *dev) | ||
171 | { | ||
172 | struct drm_plane *plane; | ||
173 | |||
174 | drm_for_each_plane(plane, dev) { | ||
175 | if (plane->funcs->early_unregister) | ||
176 | plane->funcs->early_unregister(plane); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * drm_plane_init - Initialize a legacy plane | ||
182 | * @dev: DRM device | ||
183 | * @plane: plane object to init | ||
184 | * @possible_crtcs: bitmask of possible CRTCs | ||
185 | * @funcs: callbacks for the new plane | ||
186 | * @formats: array of supported formats (DRM_FORMAT\_\*) | ||
187 | * @format_count: number of elements in @formats | ||
188 | * @is_primary: plane type (primary vs overlay) | ||
189 | * | ||
190 | * Legacy API to initialize a DRM plane. | ||
191 | * | ||
192 | * New drivers should call drm_universal_plane_init() instead. | ||
193 | * | ||
194 | * Returns: | ||
195 | * Zero on success, error code on failure. | ||
196 | */ | ||
197 | int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, | ||
198 | unsigned long possible_crtcs, | ||
199 | const struct drm_plane_funcs *funcs, | ||
200 | const uint32_t *formats, unsigned int format_count, | ||
201 | bool is_primary) | ||
202 | { | ||
203 | enum drm_plane_type type; | ||
204 | |||
205 | type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; | ||
206 | return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, | ||
207 | formats, format_count, type, NULL); | ||
208 | } | ||
209 | EXPORT_SYMBOL(drm_plane_init); | ||
210 | |||
211 | /** | ||
212 | * drm_plane_cleanup - Clean up the core plane usage | ||
213 | * @plane: plane to cleanup | ||
214 | * | ||
215 | * This function cleans up @plane and removes it from the DRM mode setting | ||
216 | * core. Note that the function does *not* free the plane structure itself, | ||
217 | * this is the responsibility of the caller. | ||
218 | */ | ||
219 | void drm_plane_cleanup(struct drm_plane *plane) | ||
220 | { | ||
221 | struct drm_device *dev = plane->dev; | ||
222 | |||
223 | drm_modeset_lock_all(dev); | ||
224 | kfree(plane->format_types); | ||
225 | drm_mode_object_unregister(dev, &plane->base); | ||
226 | |||
227 | BUG_ON(list_empty(&plane->head)); | ||
228 | |||
229 | /* Note that the plane_list is considered to be static; should we | ||
230 | * remove the drm_plane at runtime we would have to decrement all | ||
231 | * the indices on the drm_plane after us in the plane_list. | ||
232 | */ | ||
233 | |||
234 | list_del(&plane->head); | ||
235 | dev->mode_config.num_total_plane--; | ||
236 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) | ||
237 | dev->mode_config.num_overlay_plane--; | ||
238 | drm_modeset_unlock_all(dev); | ||
239 | |||
240 | WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); | ||
241 | if (plane->state && plane->funcs->atomic_destroy_state) | ||
242 | plane->funcs->atomic_destroy_state(plane, plane->state); | ||
243 | |||
244 | kfree(plane->name); | ||
245 | |||
246 | memset(plane, 0, sizeof(*plane)); | ||
247 | } | ||
248 | EXPORT_SYMBOL(drm_plane_cleanup); | ||
249 | |||
250 | /** | ||
251 | * drm_plane_from_index - find the registered plane at an index | ||
252 | * @dev: DRM device | ||
253 | * @idx: index of registered plane to find for | ||
254 | * | ||
255 | * Given a plane index, return the registered plane from DRM device's | ||
256 | * list of planes with matching index. | ||
257 | */ | ||
258 | struct drm_plane * | ||
259 | drm_plane_from_index(struct drm_device *dev, int idx) | ||
260 | { | ||
261 | struct drm_plane *plane; | ||
262 | |||
263 | drm_for_each_plane(plane, dev) | ||
264 | if (idx == plane->index) | ||
265 | return plane; | ||
266 | |||
267 | return NULL; | ||
268 | } | ||
269 | EXPORT_SYMBOL(drm_plane_from_index); | ||
270 | |||
271 | /** | ||
272 | * drm_plane_force_disable - Forcibly disable a plane | ||
273 | * @plane: plane to disable | ||
274 | * | ||
275 | * Forces the plane to be disabled. | ||
276 | * | ||
277 | * Used when the plane's current framebuffer is destroyed, | ||
278 | * and when restoring fbdev mode. | ||
279 | */ | ||
280 | void drm_plane_force_disable(struct drm_plane *plane) | ||
281 | { | ||
282 | int ret; | ||
283 | |||
284 | if (!plane->fb) | ||
285 | return; | ||
286 | |||
287 | plane->old_fb = plane->fb; | ||
288 | ret = plane->funcs->disable_plane(plane); | ||
289 | if (ret) { | ||
290 | DRM_ERROR("failed to disable plane with busy fb\n"); | ||
291 | plane->old_fb = NULL; | ||
292 | return; | ||
293 | } | ||
294 | /* disconnect the plane from the fb and crtc: */ | ||
295 | drm_framebuffer_unreference(plane->old_fb); | ||
296 | plane->old_fb = NULL; | ||
297 | plane->fb = NULL; | ||
298 | plane->crtc = NULL; | ||
299 | } | ||
300 | EXPORT_SYMBOL(drm_plane_force_disable); | ||
301 | |||
302 | /** | ||
303 | * drm_mode_plane_set_obj_prop - set the value of a property | ||
304 | * @plane: drm plane object to set property value for | ||
305 | * @property: property to set | ||
306 | * @value: value the property should be set to | ||
307 | * | ||
308 | * This functions sets a given property on a given plane object. This function | ||
309 | * calls the driver's ->set_property callback and changes the software state of | ||
310 | * the property if the callback succeeds. | ||
311 | * | ||
312 | * Returns: | ||
313 | * Zero on success, error code on failure. | ||
314 | */ | ||
315 | int drm_mode_plane_set_obj_prop(struct drm_plane *plane, | ||
316 | struct drm_property *property, | ||
317 | uint64_t value) | ||
318 | { | ||
319 | int ret = -EINVAL; | ||
320 | struct drm_mode_object *obj = &plane->base; | ||
321 | |||
322 | if (plane->funcs->set_property) | ||
323 | ret = plane->funcs->set_property(plane, property, value); | ||
324 | if (!ret) | ||
325 | drm_object_property_set_value(obj, property, value); | ||
326 | |||
327 | return ret; | ||
328 | } | ||
329 | EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); | ||
330 | |||
331 | int drm_mode_getplane_res(struct drm_device *dev, void *data, | ||
332 | struct drm_file *file_priv) | ||
333 | { | ||
334 | struct drm_mode_get_plane_res *plane_resp = data; | ||
335 | struct drm_mode_config *config; | ||
336 | struct drm_plane *plane; | ||
337 | uint32_t __user *plane_ptr; | ||
338 | int copied = 0; | ||
339 | unsigned num_planes; | ||
340 | |||
341 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
342 | return -EINVAL; | ||
343 | |||
344 | config = &dev->mode_config; | ||
345 | |||
346 | if (file_priv->universal_planes) | ||
347 | num_planes = config->num_total_plane; | ||
348 | else | ||
349 | num_planes = config->num_overlay_plane; | ||
350 | |||
351 | /* | ||
352 | * This ioctl is called twice, once to determine how much space is | ||
353 | * needed, and the 2nd time to fill it. | ||
354 | */ | ||
355 | if (num_planes && | ||
356 | (plane_resp->count_planes >= num_planes)) { | ||
357 | plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; | ||
358 | |||
359 | /* Plane lists are invariant, no locking needed. */ | ||
360 | drm_for_each_plane(plane, dev) { | ||
361 | /* | ||
362 | * Unless userspace set the 'universal planes' | ||
363 | * capability bit, only advertise overlays. | ||
364 | */ | ||
365 | if (plane->type != DRM_PLANE_TYPE_OVERLAY && | ||
366 | !file_priv->universal_planes) | ||
367 | continue; | ||
368 | |||
369 | if (put_user(plane->base.id, plane_ptr + copied)) | ||
370 | return -EFAULT; | ||
371 | copied++; | ||
372 | } | ||
373 | } | ||
374 | plane_resp->count_planes = num_planes; | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | int drm_mode_getplane(struct drm_device *dev, void *data, | ||
380 | struct drm_file *file_priv) | ||
381 | { | ||
382 | struct drm_mode_get_plane *plane_resp = data; | ||
383 | struct drm_plane *plane; | ||
384 | uint32_t __user *format_ptr; | ||
385 | |||
386 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
387 | return -EINVAL; | ||
388 | |||
389 | plane = drm_plane_find(dev, plane_resp->plane_id); | ||
390 | if (!plane) | ||
391 | return -ENOENT; | ||
392 | |||
393 | drm_modeset_lock(&plane->mutex, NULL); | ||
394 | if (plane->crtc) | ||
395 | plane_resp->crtc_id = plane->crtc->base.id; | ||
396 | else | ||
397 | plane_resp->crtc_id = 0; | ||
398 | |||
399 | if (plane->fb) | ||
400 | plane_resp->fb_id = plane->fb->base.id; | ||
401 | else | ||
402 | plane_resp->fb_id = 0; | ||
403 | drm_modeset_unlock(&plane->mutex); | ||
404 | |||
405 | plane_resp->plane_id = plane->base.id; | ||
406 | plane_resp->possible_crtcs = plane->possible_crtcs; | ||
407 | plane_resp->gamma_size = 0; | ||
408 | |||
409 | /* | ||
410 | * This ioctl is called twice, once to determine how much space is | ||
411 | * needed, and the 2nd time to fill it. | ||
412 | */ | ||
413 | if (plane->format_count && | ||
414 | (plane_resp->count_format_types >= plane->format_count)) { | ||
415 | format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; | ||
416 | if (copy_to_user(format_ptr, | ||
417 | plane->format_types, | ||
418 | sizeof(uint32_t) * plane->format_count)) { | ||
419 | return -EFAULT; | ||
420 | } | ||
421 | } | ||
422 | plane_resp->count_format_types = plane->format_count; | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) | ||
428 | { | ||
429 | unsigned int i; | ||
430 | |||
431 | for (i = 0; i < plane->format_count; i++) { | ||
432 | if (format == plane->format_types[i]) | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | return -EINVAL; | ||
437 | } | ||
438 | |||
439 | /* | ||
440 | * setplane_internal - setplane handler for internal callers | ||
441 | * | ||
442 | * Note that we assume an extra reference has already been taken on fb. If the | ||
443 | * update fails, this reference will be dropped before return; if it succeeds, | ||
444 | * the previous framebuffer (if any) will be unreferenced instead. | ||
445 | * | ||
446 | * src_{x,y,w,h} are provided in 16.16 fixed point format | ||
447 | */ | ||
448 | static int __setplane_internal(struct drm_plane *plane, | ||
449 | struct drm_crtc *crtc, | ||
450 | struct drm_framebuffer *fb, | ||
451 | int32_t crtc_x, int32_t crtc_y, | ||
452 | uint32_t crtc_w, uint32_t crtc_h, | ||
453 | /* src_{x,y,w,h} values are 16.16 fixed point */ | ||
454 | uint32_t src_x, uint32_t src_y, | ||
455 | uint32_t src_w, uint32_t src_h) | ||
456 | { | ||
457 | int ret = 0; | ||
458 | |||
459 | /* No fb means shut it down */ | ||
460 | if (!fb) { | ||
461 | plane->old_fb = plane->fb; | ||
462 | ret = plane->funcs->disable_plane(plane); | ||
463 | if (!ret) { | ||
464 | plane->crtc = NULL; | ||
465 | plane->fb = NULL; | ||
466 | } else { | ||
467 | plane->old_fb = NULL; | ||
468 | } | ||
469 | goto out; | ||
470 | } | ||
471 | |||
472 | /* Check whether this plane is usable on this CRTC */ | ||
473 | if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { | ||
474 | DRM_DEBUG_KMS("Invalid crtc for plane\n"); | ||
475 | ret = -EINVAL; | ||
476 | goto out; | ||
477 | } | ||
478 | |||
479 | /* Check whether this plane supports the fb pixel format. */ | ||
480 | ret = drm_plane_check_pixel_format(plane, fb->pixel_format); | ||
481 | if (ret) { | ||
482 | char *format_name = drm_get_format_name(fb->pixel_format); | ||
483 | DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name); | ||
484 | kfree(format_name); | ||
485 | goto out; | ||
486 | } | ||
487 | |||
488 | /* Give drivers some help against integer overflows */ | ||
489 | if (crtc_w > INT_MAX || | ||
490 | crtc_x > INT_MAX - (int32_t) crtc_w || | ||
491 | crtc_h > INT_MAX || | ||
492 | crtc_y > INT_MAX - (int32_t) crtc_h) { | ||
493 | DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", | ||
494 | crtc_w, crtc_h, crtc_x, crtc_y); | ||
495 | ret = -ERANGE; | ||
496 | goto out; | ||
497 | } | ||
498 | |||
499 | ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb); | ||
500 | if (ret) | ||
501 | goto out; | ||
502 | |||
503 | plane->old_fb = plane->fb; | ||
504 | ret = plane->funcs->update_plane(plane, crtc, fb, | ||
505 | crtc_x, crtc_y, crtc_w, crtc_h, | ||
506 | src_x, src_y, src_w, src_h); | ||
507 | if (!ret) { | ||
508 | plane->crtc = crtc; | ||
509 | plane->fb = fb; | ||
510 | fb = NULL; | ||
511 | } else { | ||
512 | plane->old_fb = NULL; | ||
513 | } | ||
514 | |||
515 | out: | ||
516 | if (fb) | ||
517 | drm_framebuffer_unreference(fb); | ||
518 | if (plane->old_fb) | ||
519 | drm_framebuffer_unreference(plane->old_fb); | ||
520 | plane->old_fb = NULL; | ||
521 | |||
522 | return ret; | ||
523 | } | ||
524 | |||
525 | static int setplane_internal(struct drm_plane *plane, | ||
526 | struct drm_crtc *crtc, | ||
527 | struct drm_framebuffer *fb, | ||
528 | int32_t crtc_x, int32_t crtc_y, | ||
529 | uint32_t crtc_w, uint32_t crtc_h, | ||
530 | /* src_{x,y,w,h} values are 16.16 fixed point */ | ||
531 | uint32_t src_x, uint32_t src_y, | ||
532 | uint32_t src_w, uint32_t src_h) | ||
533 | { | ||
534 | int ret; | ||
535 | |||
536 | drm_modeset_lock_all(plane->dev); | ||
537 | ret = __setplane_internal(plane, crtc, fb, | ||
538 | crtc_x, crtc_y, crtc_w, crtc_h, | ||
539 | src_x, src_y, src_w, src_h); | ||
540 | drm_modeset_unlock_all(plane->dev); | ||
541 | |||
542 | return ret; | ||
543 | } | ||
544 | |||
545 | int drm_mode_setplane(struct drm_device *dev, void *data, | ||
546 | struct drm_file *file_priv) | ||
547 | { | ||
548 | struct drm_mode_set_plane *plane_req = data; | ||
549 | struct drm_plane *plane; | ||
550 | struct drm_crtc *crtc = NULL; | ||
551 | struct drm_framebuffer *fb = NULL; | ||
552 | |||
553 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
554 | return -EINVAL; | ||
555 | |||
556 | /* | ||
557 | * First, find the plane, crtc, and fb objects. If not available, | ||
558 | * we don't bother to call the driver. | ||
559 | */ | ||
560 | plane = drm_plane_find(dev, plane_req->plane_id); | ||
561 | if (!plane) { | ||
562 | DRM_DEBUG_KMS("Unknown plane ID %d\n", | ||
563 | plane_req->plane_id); | ||
564 | return -ENOENT; | ||
565 | } | ||
566 | |||
567 | if (plane_req->fb_id) { | ||
568 | fb = drm_framebuffer_lookup(dev, plane_req->fb_id); | ||
569 | if (!fb) { | ||
570 | DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", | ||
571 | plane_req->fb_id); | ||
572 | return -ENOENT; | ||
573 | } | ||
574 | |||
575 | crtc = drm_crtc_find(dev, plane_req->crtc_id); | ||
576 | if (!crtc) { | ||
577 | DRM_DEBUG_KMS("Unknown crtc ID %d\n", | ||
578 | plane_req->crtc_id); | ||
579 | return -ENOENT; | ||
580 | } | ||
581 | } | ||
582 | |||
583 | /* | ||
584 | * setplane_internal will take care of deref'ing either the old or new | ||
585 | * framebuffer depending on success. | ||
586 | */ | ||
587 | return setplane_internal(plane, crtc, fb, | ||
588 | plane_req->crtc_x, plane_req->crtc_y, | ||
589 | plane_req->crtc_w, plane_req->crtc_h, | ||
590 | plane_req->src_x, plane_req->src_y, | ||
591 | plane_req->src_w, plane_req->src_h); | ||
592 | } | ||
593 | |||
594 | static int drm_mode_cursor_universal(struct drm_crtc *crtc, | ||
595 | struct drm_mode_cursor2 *req, | ||
596 | struct drm_file *file_priv) | ||
597 | { | ||
598 | struct drm_device *dev = crtc->dev; | ||
599 | struct drm_framebuffer *fb = NULL; | ||
600 | struct drm_mode_fb_cmd2 fbreq = { | ||
601 | .width = req->width, | ||
602 | .height = req->height, | ||
603 | .pixel_format = DRM_FORMAT_ARGB8888, | ||
604 | .pitches = { req->width * 4 }, | ||
605 | .handles = { req->handle }, | ||
606 | }; | ||
607 | int32_t crtc_x, crtc_y; | ||
608 | uint32_t crtc_w = 0, crtc_h = 0; | ||
609 | uint32_t src_w = 0, src_h = 0; | ||
610 | int ret = 0; | ||
611 | |||
612 | BUG_ON(!crtc->cursor); | ||
613 | WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); | ||
614 | |||
615 | /* | ||
616 | * Obtain fb we'll be using (either new or existing) and take an extra | ||
617 | * reference to it if fb != null. setplane will take care of dropping | ||
618 | * the reference if the plane update fails. | ||
619 | */ | ||
620 | if (req->flags & DRM_MODE_CURSOR_BO) { | ||
621 | if (req->handle) { | ||
622 | fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv); | ||
623 | if (IS_ERR(fb)) { | ||
624 | DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); | ||
625 | return PTR_ERR(fb); | ||
626 | } | ||
627 | fb->hot_x = req->hot_x; | ||
628 | fb->hot_y = req->hot_y; | ||
629 | } else { | ||
630 | fb = NULL; | ||
631 | } | ||
632 | } else { | ||
633 | fb = crtc->cursor->fb; | ||
634 | if (fb) | ||
635 | drm_framebuffer_reference(fb); | ||
636 | } | ||
637 | |||
638 | if (req->flags & DRM_MODE_CURSOR_MOVE) { | ||
639 | crtc_x = req->x; | ||
640 | crtc_y = req->y; | ||
641 | } else { | ||
642 | crtc_x = crtc->cursor_x; | ||
643 | crtc_y = crtc->cursor_y; | ||
644 | } | ||
645 | |||
646 | if (fb) { | ||
647 | crtc_w = fb->width; | ||
648 | crtc_h = fb->height; | ||
649 | src_w = fb->width << 16; | ||
650 | src_h = fb->height << 16; | ||
651 | } | ||
652 | |||
653 | /* | ||
654 | * setplane_internal will take care of deref'ing either the old or new | ||
655 | * framebuffer depending on success. | ||
656 | */ | ||
657 | ret = __setplane_internal(crtc->cursor, crtc, fb, | ||
658 | crtc_x, crtc_y, crtc_w, crtc_h, | ||
659 | 0, 0, src_w, src_h); | ||
660 | |||
661 | /* Update successful; save new cursor position, if necessary */ | ||
662 | if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { | ||
663 | crtc->cursor_x = req->x; | ||
664 | crtc->cursor_y = req->y; | ||
665 | } | ||
666 | |||
667 | return ret; | ||
668 | } | ||
669 | |||
670 | static int drm_mode_cursor_common(struct drm_device *dev, | ||
671 | struct drm_mode_cursor2 *req, | ||
672 | struct drm_file *file_priv) | ||
673 | { | ||
674 | struct drm_crtc *crtc; | ||
675 | int ret = 0; | ||
676 | |||
677 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
678 | return -EINVAL; | ||
679 | |||
680 | if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) | ||
681 | return -EINVAL; | ||
682 | |||
683 | crtc = drm_crtc_find(dev, req->crtc_id); | ||
684 | if (!crtc) { | ||
685 | DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); | ||
686 | return -ENOENT; | ||
687 | } | ||
688 | |||
689 | /* | ||
690 | * If this crtc has a universal cursor plane, call that plane's update | ||
691 | * handler rather than using legacy cursor handlers. | ||
692 | */ | ||
693 | drm_modeset_lock_crtc(crtc, crtc->cursor); | ||
694 | if (crtc->cursor) { | ||
695 | ret = drm_mode_cursor_universal(crtc, req, file_priv); | ||
696 | goto out; | ||
697 | } | ||
698 | |||
699 | if (req->flags & DRM_MODE_CURSOR_BO) { | ||
700 | if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { | ||
701 | ret = -ENXIO; | ||
702 | goto out; | ||
703 | } | ||
704 | /* Turns off the cursor if handle is 0 */ | ||
705 | if (crtc->funcs->cursor_set2) | ||
706 | ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, | ||
707 | req->width, req->height, req->hot_x, req->hot_y); | ||
708 | else | ||
709 | ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, | ||
710 | req->width, req->height); | ||
711 | } | ||
712 | |||
713 | if (req->flags & DRM_MODE_CURSOR_MOVE) { | ||
714 | if (crtc->funcs->cursor_move) { | ||
715 | ret = crtc->funcs->cursor_move(crtc, req->x, req->y); | ||
716 | } else { | ||
717 | ret = -EFAULT; | ||
718 | goto out; | ||
719 | } | ||
720 | } | ||
721 | out: | ||
722 | drm_modeset_unlock_crtc(crtc); | ||
723 | |||
724 | return ret; | ||
725 | |||
726 | } | ||
727 | |||
728 | |||
729 | int drm_mode_cursor_ioctl(struct drm_device *dev, | ||
730 | void *data, struct drm_file *file_priv) | ||
731 | { | ||
732 | struct drm_mode_cursor *req = data; | ||
733 | struct drm_mode_cursor2 new_req; | ||
734 | |||
735 | memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); | ||
736 | new_req.hot_x = new_req.hot_y = 0; | ||
737 | |||
738 | return drm_mode_cursor_common(dev, &new_req, file_priv); | ||
739 | } | ||
740 | |||
741 | /* | ||
742 | * Set the cursor configuration based on user request. This implements the 2nd | ||
743 | * version of the cursor ioctl, which allows userspace to additionally specify | ||
744 | * the hotspot of the pointer. | ||
745 | */ | ||
746 | int drm_mode_cursor2_ioctl(struct drm_device *dev, | ||
747 | void *data, struct drm_file *file_priv) | ||
748 | { | ||
749 | struct drm_mode_cursor2 *req = data; | ||
750 | |||
751 | return drm_mode_cursor_common(dev, req, file_priv); | ||
752 | } | ||
753 | |||
754 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
755 | void *data, struct drm_file *file_priv) | ||
756 | { | ||
757 | struct drm_mode_crtc_page_flip_target *page_flip = data; | ||
758 | struct drm_crtc *crtc; | ||
759 | struct drm_framebuffer *fb = NULL; | ||
760 | struct drm_pending_vblank_event *e = NULL; | ||
761 | u32 target_vblank = page_flip->sequence; | ||
762 | int ret = -EINVAL; | ||
763 | |||
764 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
765 | return -EINVAL; | ||
766 | |||
767 | if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS) | ||
768 | return -EINVAL; | ||
769 | |||
770 | if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) | ||
771 | return -EINVAL; | ||
772 | |||
773 | /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags | ||
774 | * can be specified | ||
775 | */ | ||
776 | if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET) | ||
777 | return -EINVAL; | ||
778 | |||
779 | if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) | ||
780 | return -EINVAL; | ||
781 | |||
782 | crtc = drm_crtc_find(dev, page_flip->crtc_id); | ||
783 | if (!crtc) | ||
784 | return -ENOENT; | ||
785 | |||
786 | drm_modeset_lock_crtc(crtc, crtc->primary); | ||
787 | if (crtc->primary->fb == NULL) { | ||
788 | /* The framebuffer is currently unbound, presumably | ||
789 | * due to a hotplug event, that userspace has not | ||
790 | * yet discovered. | ||
791 | */ | ||
792 | ret = -EBUSY; | ||
793 | goto out; | ||
794 | } | ||
795 | |||
796 | if (crtc->funcs->page_flip == NULL) | ||
797 | goto out; | ||
798 | |||
799 | fb = drm_framebuffer_lookup(dev, page_flip->fb_id); | ||
800 | if (!fb) { | ||
801 | ret = -ENOENT; | ||
802 | goto out; | ||
803 | } | ||
804 | |||
805 | if (crtc->state) { | ||
806 | const struct drm_plane_state *state = crtc->primary->state; | ||
807 | |||
808 | ret = drm_framebuffer_check_src_coords(state->src_x, | ||
809 | state->src_y, | ||
810 | state->src_w, | ||
811 | state->src_h, | ||
812 | fb); | ||
813 | } else { | ||
814 | ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); | ||
815 | } | ||
816 | if (ret) | ||
817 | goto out; | ||
818 | |||
819 | if (crtc->primary->fb->pixel_format != fb->pixel_format) { | ||
820 | DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); | ||
821 | ret = -EINVAL; | ||
822 | goto out; | ||
823 | } | ||
824 | |||
825 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { | ||
826 | e = kzalloc(sizeof *e, GFP_KERNEL); | ||
827 | if (!e) { | ||
828 | ret = -ENOMEM; | ||
829 | goto out; | ||
830 | } | ||
831 | e->event.base.type = DRM_EVENT_FLIP_COMPLETE; | ||
832 | e->event.base.length = sizeof(e->event); | ||
833 | e->event.user_data = page_flip->user_data; | ||
834 | ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); | ||
835 | if (ret) { | ||
836 | kfree(e); | ||
837 | goto out; | ||
838 | } | ||
839 | } | ||
840 | |||
841 | crtc->primary->old_fb = crtc->primary->fb; | ||
842 | if (crtc->funcs->page_flip_target) { | ||
843 | u32 current_vblank; | ||
844 | int r; | ||
845 | |||
846 | r = drm_crtc_vblank_get(crtc); | ||
847 | if (r) | ||
848 | return r; | ||
849 | |||
850 | current_vblank = drm_crtc_vblank_count(crtc); | ||
851 | |||
852 | switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) { | ||
853 | case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE: | ||
854 | if ((int)(target_vblank - current_vblank) > 1) { | ||
855 | DRM_DEBUG("Invalid absolute flip target %u, " | ||
856 | "must be <= %u\n", target_vblank, | ||
857 | current_vblank + 1); | ||
858 | drm_crtc_vblank_put(crtc); | ||
859 | return -EINVAL; | ||
860 | } | ||
861 | break; | ||
862 | case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE: | ||
863 | if (target_vblank != 0 && target_vblank != 1) { | ||
864 | DRM_DEBUG("Invalid relative flip target %u, " | ||
865 | "must be 0 or 1\n", target_vblank); | ||
866 | drm_crtc_vblank_put(crtc); | ||
867 | return -EINVAL; | ||
868 | } | ||
869 | target_vblank += current_vblank; | ||
870 | break; | ||
871 | default: | ||
872 | target_vblank = current_vblank + | ||
873 | !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC); | ||
874 | break; | ||
875 | } | ||
876 | } else if (crtc->funcs->page_flip == NULL || | ||
877 | (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) { | ||
878 | return -EINVAL; | ||
879 | } | ||
880 | |||
881 | if (crtc->funcs->page_flip_target) | ||
882 | ret = crtc->funcs->page_flip_target(crtc, fb, e, | ||
883 | page_flip->flags, | ||
884 | target_vblank); | ||
885 | else | ||
886 | ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); | ||
887 | if (ret) { | ||
888 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) | ||
889 | drm_event_cancel_free(dev, &e->base); | ||
890 | /* Keep the old fb, don't unref it. */ | ||
891 | crtc->primary->old_fb = NULL; | ||
892 | } else { | ||
893 | crtc->primary->fb = fb; | ||
894 | /* Unref only the old framebuffer. */ | ||
895 | fb = NULL; | ||
896 | } | ||
897 | |||
898 | out: | ||
899 | if (ret && crtc->funcs->page_flip_target) | ||
900 | drm_crtc_vblank_put(crtc); | ||
901 | if (crtc->primary->old_fb) | ||
902 | drm_framebuffer_unreference(crtc->primary->old_fb); | ||
903 | crtc->primary->old_fb = NULL; | ||
904 | drm_modeset_unlock_crtc(crtc); | ||
905 | |||
906 | return ret; | ||
907 | } | ||
diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 2c819ef90090..026269851ce9 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c | |||
@@ -48,8 +48,8 @@ static int drm_get_platform_dev(struct platform_device *platdev, | |||
48 | DRM_DEBUG("\n"); | 48 | DRM_DEBUG("\n"); |
49 | 49 | ||
50 | dev = drm_dev_alloc(driver, &platdev->dev); | 50 | dev = drm_dev_alloc(driver, &platdev->dev); |
51 | if (!dev) | 51 | if (IS_ERR(dev)) |
52 | return -ENOMEM; | 52 | return PTR_ERR(dev); |
53 | 53 | ||
54 | dev->platformdev = platdev; | 54 | dev->platformdev = platdev; |
55 | 55 | ||
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 32dd821b7202..9a37196c1bf1 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/export.h> | 19 | #include <linux/export.h> |
20 | 20 | ||
21 | #include <drm/drm_sysfs.h> | 21 | #include <drm/drm_sysfs.h> |
22 | #include <drm/drm_core.h> | ||
23 | #include <drm/drmP.h> | 22 | #include <drm/drmP.h> |
24 | #include "drm_internal.h" | 23 | #include "drm_internal.h" |
25 | 24 | ||
@@ -37,12 +36,7 @@ static char *drm_devnode(struct device *dev, umode_t *mode) | |||
37 | return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); | 36 | return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); |
38 | } | 37 | } |
39 | 38 | ||
40 | static CLASS_ATTR_STRING(version, S_IRUGO, | 39 | static CLASS_ATTR_STRING(version, S_IRUGO, "drm 1.1.0 20060810"); |
41 | CORE_NAME " " | ||
42 | __stringify(CORE_MAJOR) "." | ||
43 | __stringify(CORE_MINOR) "." | ||
44 | __stringify(CORE_PATCHLEVEL) " " | ||
45 | CORE_DATE); | ||
46 | 40 | ||
47 | /** | 41 | /** |
48 | * drm_sysfs_init - initialize sysfs helpers | 42 | * drm_sysfs_init - initialize sysfs helpers |
diff --git a/drivers/gpu/drm/drm_vma_manager.c b/drivers/gpu/drm/drm_vma_manager.c index 0aef432679f9..20cc33d1bfc1 100644 --- a/drivers/gpu/drm/drm_vma_manager.c +++ b/drivers/gpu/drm/drm_vma_manager.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <drm/drmP.h> | 25 | #include <drm/drmP.h> |
26 | #include <drm/drm_mm.h> | 26 | #include <drm/drm_mm.h> |
27 | #include <drm/drm_vma_manager.h> | 27 | #include <drm/drm_vma_manager.h> |
28 | #include <linux/fs.h> | ||
29 | #include <linux/mm.h> | 28 | #include <linux/mm.h> |
30 | #include <linux/module.h> | 29 | #include <linux/module.h> |
31 | #include <linux/rbtree.h> | 30 | #include <linux/rbtree.h> |
@@ -252,9 +251,9 @@ EXPORT_SYMBOL(drm_vma_offset_remove); | |||
252 | /** | 251 | /** |
253 | * drm_vma_node_allow - Add open-file to list of allowed users | 252 | * drm_vma_node_allow - Add open-file to list of allowed users |
254 | * @node: Node to modify | 253 | * @node: Node to modify |
255 | * @filp: Open file to add | 254 | * @tag: Tag of file to remove |
256 | * | 255 | * |
257 | * Add @filp to the list of allowed open-files for this node. If @filp is | 256 | * Add @tag to the list of allowed open-files for this node. If @tag is |
258 | * already on this list, the ref-count is incremented. | 257 | * already on this list, the ref-count is incremented. |
259 | * | 258 | * |
260 | * The list of allowed-users is preserved across drm_vma_offset_add() and | 259 | * The list of allowed-users is preserved across drm_vma_offset_add() and |
@@ -269,7 +268,7 @@ EXPORT_SYMBOL(drm_vma_offset_remove); | |||
269 | * RETURNS: | 268 | * RETURNS: |
270 | * 0 on success, negative error code on internal failure (out-of-mem) | 269 | * 0 on success, negative error code on internal failure (out-of-mem) |
271 | */ | 270 | */ |
272 | int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp) | 271 | int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag) |
273 | { | 272 | { |
274 | struct rb_node **iter; | 273 | struct rb_node **iter; |
275 | struct rb_node *parent = NULL; | 274 | struct rb_node *parent = NULL; |
@@ -290,10 +289,10 @@ int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp) | |||
290 | parent = *iter; | 289 | parent = *iter; |
291 | entry = rb_entry(*iter, struct drm_vma_offset_file, vm_rb); | 290 | entry = rb_entry(*iter, struct drm_vma_offset_file, vm_rb); |
292 | 291 | ||
293 | if (filp == entry->vm_filp) { | 292 | if (tag == entry->vm_tag) { |
294 | entry->vm_count++; | 293 | entry->vm_count++; |
295 | goto unlock; | 294 | goto unlock; |
296 | } else if (filp > entry->vm_filp) { | 295 | } else if (tag > entry->vm_tag) { |
297 | iter = &(*iter)->rb_right; | 296 | iter = &(*iter)->rb_right; |
298 | } else { | 297 | } else { |
299 | iter = &(*iter)->rb_left; | 298 | iter = &(*iter)->rb_left; |
@@ -305,7 +304,7 @@ int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp) | |||
305 | goto unlock; | 304 | goto unlock; |
306 | } | 305 | } |
307 | 306 | ||
308 | new->vm_filp = filp; | 307 | new->vm_tag = tag; |
309 | new->vm_count = 1; | 308 | new->vm_count = 1; |
310 | rb_link_node(&new->vm_rb, parent, iter); | 309 | rb_link_node(&new->vm_rb, parent, iter); |
311 | rb_insert_color(&new->vm_rb, &node->vm_files); | 310 | rb_insert_color(&new->vm_rb, &node->vm_files); |
@@ -321,17 +320,18 @@ EXPORT_SYMBOL(drm_vma_node_allow); | |||
321 | /** | 320 | /** |
322 | * drm_vma_node_revoke - Remove open-file from list of allowed users | 321 | * drm_vma_node_revoke - Remove open-file from list of allowed users |
323 | * @node: Node to modify | 322 | * @node: Node to modify |
324 | * @filp: Open file to remove | 323 | * @tag: Tag of file to remove |
325 | * | 324 | * |
326 | * Decrement the ref-count of @filp in the list of allowed open-files on @node. | 325 | * Decrement the ref-count of @tag in the list of allowed open-files on @node. |
327 | * If the ref-count drops to zero, remove @filp from the list. You must call | 326 | * If the ref-count drops to zero, remove @tag from the list. You must call |
328 | * this once for every drm_vma_node_allow() on @filp. | 327 | * this once for every drm_vma_node_allow() on @tag. |
329 | * | 328 | * |
330 | * This is locked against concurrent access internally. | 329 | * This is locked against concurrent access internally. |
331 | * | 330 | * |
332 | * If @filp is not on the list, nothing is done. | 331 | * If @tag is not on the list, nothing is done. |
333 | */ | 332 | */ |
334 | void drm_vma_node_revoke(struct drm_vma_offset_node *node, struct file *filp) | 333 | void drm_vma_node_revoke(struct drm_vma_offset_node *node, |
334 | struct drm_file *tag) | ||
335 | { | 335 | { |
336 | struct drm_vma_offset_file *entry; | 336 | struct drm_vma_offset_file *entry; |
337 | struct rb_node *iter; | 337 | struct rb_node *iter; |
@@ -341,13 +341,13 @@ void drm_vma_node_revoke(struct drm_vma_offset_node *node, struct file *filp) | |||
341 | iter = node->vm_files.rb_node; | 341 | iter = node->vm_files.rb_node; |
342 | while (likely(iter)) { | 342 | while (likely(iter)) { |
343 | entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb); | 343 | entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb); |
344 | if (filp == entry->vm_filp) { | 344 | if (tag == entry->vm_tag) { |
345 | if (!--entry->vm_count) { | 345 | if (!--entry->vm_count) { |
346 | rb_erase(&entry->vm_rb, &node->vm_files); | 346 | rb_erase(&entry->vm_rb, &node->vm_files); |
347 | kfree(entry); | 347 | kfree(entry); |
348 | } | 348 | } |
349 | break; | 349 | break; |
350 | } else if (filp > entry->vm_filp) { | 350 | } else if (tag > entry->vm_tag) { |
351 | iter = iter->rb_right; | 351 | iter = iter->rb_right; |
352 | } else { | 352 | } else { |
353 | iter = iter->rb_left; | 353 | iter = iter->rb_left; |
@@ -361,9 +361,9 @@ EXPORT_SYMBOL(drm_vma_node_revoke); | |||
361 | /** | 361 | /** |
362 | * drm_vma_node_is_allowed - Check whether an open-file is granted access | 362 | * drm_vma_node_is_allowed - Check whether an open-file is granted access |
363 | * @node: Node to check | 363 | * @node: Node to check |
364 | * @filp: Open-file to check for | 364 | * @tag: Tag of file to remove |
365 | * | 365 | * |
366 | * Search the list in @node whether @filp is currently on the list of allowed | 366 | * Search the list in @node whether @tag is currently on the list of allowed |
367 | * open-files (see drm_vma_node_allow()). | 367 | * open-files (see drm_vma_node_allow()). |
368 | * | 368 | * |
369 | * This is locked against concurrent access internally. | 369 | * This is locked against concurrent access internally. |
@@ -372,7 +372,7 @@ EXPORT_SYMBOL(drm_vma_node_revoke); | |||
372 | * true iff @filp is on the list | 372 | * true iff @filp is on the list |
373 | */ | 373 | */ |
374 | bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, | 374 | bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, |
375 | struct file *filp) | 375 | struct drm_file *tag) |
376 | { | 376 | { |
377 | struct drm_vma_offset_file *entry; | 377 | struct drm_vma_offset_file *entry; |
378 | struct rb_node *iter; | 378 | struct rb_node *iter; |
@@ -382,9 +382,9 @@ bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, | |||
382 | iter = node->vm_files.rb_node; | 382 | iter = node->vm_files.rb_node; |
383 | while (likely(iter)) { | 383 | while (likely(iter)) { |
384 | entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb); | 384 | entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb); |
385 | if (filp == entry->vm_filp) | 385 | if (tag == entry->vm_tag) |
386 | break; | 386 | break; |
387 | else if (filp > entry->vm_filp) | 387 | else if (tag > entry->vm_tag) |
388 | iter = iter->rb_right; | 388 | iter = iter->rb_right; |
389 | else | 389 | else |
390 | iter = iter->rb_left; | 390 | iter = iter->rb_left; |
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index e3164d90399d..aa687669e22b 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c | |||
@@ -529,8 +529,8 @@ static int etnaviv_bind(struct device *dev) | |||
529 | int ret; | 529 | int ret; |
530 | 530 | ||
531 | drm = drm_dev_alloc(&etnaviv_drm_driver, dev); | 531 | drm = drm_dev_alloc(&etnaviv_drm_driver, dev); |
532 | if (!drm) | 532 | if (IS_ERR(drm)) |
533 | return -ENOMEM; | 533 | return PTR_ERR(drm); |
534 | 534 | ||
535 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 535 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
536 | if (!priv) { | 536 | if (!priv) { |
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index 092aaecc7482..0884c45aefe8 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | |||
@@ -410,8 +410,8 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev) | |||
410 | fsl_dev->tcon = fsl_tcon_init(dev); | 410 | fsl_dev->tcon = fsl_tcon_init(dev); |
411 | 411 | ||
412 | drm = drm_dev_alloc(driver, dev); | 412 | drm = drm_dev_alloc(driver, dev); |
413 | if (!drm) { | 413 | if (IS_ERR(drm)) { |
414 | ret = -ENOMEM; | 414 | ret = PTR_ERR(drm); |
415 | goto disable_pix_clk; | 415 | goto disable_pix_clk; |
416 | } | 416 | } |
417 | 417 | ||
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index 1fc2f502d20d..90377a609c98 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | |||
@@ -207,8 +207,8 @@ static int kirin_drm_bind(struct device *dev) | |||
207 | int ret; | 207 | int ret; |
208 | 208 | ||
209 | drm_dev = drm_dev_alloc(driver, dev); | 209 | drm_dev = drm_dev_alloc(driver, dev); |
210 | if (!drm_dev) | 210 | if (IS_ERR(drm_dev)) |
211 | return -ENOMEM; | 211 | return PTR_ERR(drm_dev); |
212 | 212 | ||
213 | drm_dev->platformdev = to_platform_device(dev); | 213 | drm_dev->platformdev = to_platform_device(dev); |
214 | 214 | ||
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 72c1ae4e02d4..cf83f6507ec8 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c | |||
@@ -294,8 +294,8 @@ static int mtk_drm_bind(struct device *dev) | |||
294 | int ret; | 294 | int ret; |
295 | 295 | ||
296 | drm = drm_dev_alloc(&mtk_drm_driver, dev); | 296 | drm = drm_dev_alloc(&mtk_drm_driver, dev); |
297 | if (!drm) | 297 | if (IS_ERR(drm)) |
298 | return -ENOMEM; | 298 | return PTR_ERR(drm); |
299 | 299 | ||
300 | drm->dev_private = private; | 300 | drm->dev_private = private; |
301 | private->drm = drm; | 301 | private->drm = drm; |
diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index 68268e55d595..919b35f2ad24 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c | |||
@@ -150,7 +150,8 @@ static int mgag200_bo_verify_access(struct ttm_buffer_object *bo, struct file *f | |||
150 | { | 150 | { |
151 | struct mgag200_bo *mgabo = mgag200_bo(bo); | 151 | struct mgag200_bo *mgabo = mgag200_bo(bo); |
152 | 152 | ||
153 | return drm_vma_node_verify_access(&mgabo->gem.vma_node, filp); | 153 | return drm_vma_node_verify_access(&mgabo->gem.vma_node, |
154 | filp->private_data); | ||
154 | } | 155 | } |
155 | 156 | ||
156 | static int mgag200_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | 157 | static int mgag200_ttm_io_mem_reserve(struct ttm_bo_device *bdev, |
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 8a0237008f74..042bde48200d 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c | |||
@@ -347,9 +347,9 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) | |||
347 | int ret; | 347 | int ret; |
348 | 348 | ||
349 | ddev = drm_dev_alloc(drv, dev); | 349 | ddev = drm_dev_alloc(drv, dev); |
350 | if (!ddev) { | 350 | if (IS_ERR(ddev)) { |
351 | dev_err(dev, "failed to allocate drm_device\n"); | 351 | dev_err(dev, "failed to allocate drm_device\n"); |
352 | return -ENOMEM; | 352 | return PTR_ERR(ddev); |
353 | } | 353 | } |
354 | 354 | ||
355 | platform_set_drvdata(pdev, ddev); | 355 | platform_set_drvdata(pdev, ddev); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 8ab9ce5089fe..66f31c3eb8ba 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c | |||
@@ -1315,7 +1315,8 @@ nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) | |||
1315 | { | 1315 | { |
1316 | struct nouveau_bo *nvbo = nouveau_bo(bo); | 1316 | struct nouveau_bo *nvbo = nouveau_bo(bo); |
1317 | 1317 | ||
1318 | return drm_vma_node_verify_access(&nvbo->gem.vma_node, filp); | 1318 | return drm_vma_node_verify_access(&nvbo->gem.vma_node, |
1319 | filp->private_data); | ||
1319 | } | 1320 | } |
1320 | 1321 | ||
1321 | static int | 1322 | static int |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 652ab111dd74..3100fd88a015 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -1067,8 +1067,8 @@ nouveau_platform_device_create(const struct nvkm_device_tegra_func *func, | |||
1067 | goto err_free; | 1067 | goto err_free; |
1068 | 1068 | ||
1069 | drm = drm_dev_alloc(&driver_platform, &pdev->dev); | 1069 | drm = drm_dev_alloc(&driver_platform, &pdev->dev); |
1070 | if (!drm) { | 1070 | if (IS_ERR(drm)) { |
1071 | err = -ENOMEM; | 1071 | err = PTR_ERR(drm); |
1072 | goto err_free; | 1072 | goto err_free; |
1073 | } | 1073 | } |
1074 | 1074 | ||
diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index a257ad26beef..e26c82db948b 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c | |||
@@ -210,7 +210,8 @@ static int qxl_verify_access(struct ttm_buffer_object *bo, struct file *filp) | |||
210 | { | 210 | { |
211 | struct qxl_bo *qbo = to_qxl_bo(bo); | 211 | struct qxl_bo *qbo = to_qxl_bo(bo); |
212 | 212 | ||
213 | return drm_vma_node_verify_access(&qbo->gem_base.vma_node, filp); | 213 | return drm_vma_node_verify_access(&qbo->gem_base.vma_node, |
214 | filp->private_data); | ||
214 | } | 215 | } |
215 | 216 | ||
216 | static int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | 217 | static int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev, |
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 93414aca60d6..27ee0ab0e1a7 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c | |||
@@ -237,7 +237,8 @@ static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp) | |||
237 | 237 | ||
238 | if (radeon_ttm_tt_has_userptr(bo->ttm)) | 238 | if (radeon_ttm_tt_has_userptr(bo->ttm)) |
239 | return -EPERM; | 239 | return -EPERM; |
240 | return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp); | 240 | return drm_vma_node_verify_access(&rbo->gem_base.vma_node, |
241 | filp->private_data); | ||
241 | } | 242 | } |
242 | 243 | ||
243 | static void radeon_move_null(struct ttm_buffer_object *bo, | 244 | static void radeon_move_null(struct ttm_buffer_object *bo, |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 899ef7a2a7b4..73c971e39b1c 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c | |||
@@ -316,8 +316,8 @@ static int rcar_du_probe(struct platform_device *pdev) | |||
316 | rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data; | 316 | rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data; |
317 | 317 | ||
318 | ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev); | 318 | ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev); |
319 | if (!ddev) | 319 | if (IS_ERR(ddev)) |
320 | return -ENOMEM; | 320 | return PTR_ERR(ddev); |
321 | 321 | ||
322 | rcdu->ddev = ddev; | 322 | rcdu->ddev = ddev; |
323 | ddev->dev_private = rcdu; | 323 | ddev->dev_private = rcdu; |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 76eaf1de52e4..446b5d7e85f7 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c | |||
@@ -143,8 +143,8 @@ static int rockchip_drm_bind(struct device *dev) | |||
143 | int ret; | 143 | int ret; |
144 | 144 | ||
145 | drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev); | 145 | drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev); |
146 | if (!drm_dev) | 146 | if (IS_ERR(drm_dev)) |
147 | return -ENOMEM; | 147 | return PTR_ERR(drm_dev); |
148 | 148 | ||
149 | dev_set_drvdata(dev, drm_dev); | 149 | dev_set_drvdata(dev, drm_dev); |
150 | 150 | ||
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 7cd3804c6dee..49ed3c4b7ac5 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c | |||
@@ -365,8 +365,8 @@ static int sti_bind(struct device *dev) | |||
365 | int ret; | 365 | int ret; |
366 | 366 | ||
367 | ddev = drm_dev_alloc(&sti_driver, dev); | 367 | ddev = drm_dev_alloc(&sti_driver, dev); |
368 | if (!ddev) | 368 | if (IS_ERR(ddev)) |
369 | return -ENOMEM; | 369 | return PTR_ERR(ddev); |
370 | 370 | ||
371 | ddev->platformdev = to_platform_device(dev); | 371 | ddev->platformdev = to_platform_device(dev); |
372 | 372 | ||
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 9059e3ef9786..0da9862ad8ed 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c | |||
@@ -121,8 +121,8 @@ static int sun4i_drv_bind(struct device *dev) | |||
121 | int ret; | 121 | int ret; |
122 | 122 | ||
123 | drm = drm_dev_alloc(&sun4i_drv_driver, dev); | 123 | drm = drm_dev_alloc(&sun4i_drv_driver, dev); |
124 | if (!drm) | 124 | if (IS_ERR(drm)) |
125 | return -ENOMEM; | 125 | return PTR_ERR(drm); |
126 | 126 | ||
127 | drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); | 127 | drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); |
128 | if (!drv) { | 128 | if (!drv) { |
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 4b9f1c79cd7b..8ab47b502d83 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c | |||
@@ -983,8 +983,8 @@ static int host1x_drm_probe(struct host1x_device *dev) | |||
983 | int err; | 983 | int err; |
984 | 984 | ||
985 | drm = drm_dev_alloc(driver, &dev->dev); | 985 | drm = drm_dev_alloc(driver, &dev->dev); |
986 | if (!drm) | 986 | if (IS_ERR(drm)) |
987 | return -ENOMEM; | 987 | return PTR_ERR(drm); |
988 | 988 | ||
989 | dev_set_drvdata(&dev->dev, drm); | 989 | dev_set_drvdata(&dev->dev, drm); |
990 | 990 | ||
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 208768922030..cb9df104fe5b 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c | |||
@@ -15,9 +15,11 @@ | |||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | 15 | * this program. If not, see <http://www.gnu.org/licenses/>. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include "drm_flip_work.h" | 18 | #include <drm/drm_atomic.h> |
19 | #include <drm/drm_plane_helper.h> | ||
20 | #include <drm/drm_atomic_helper.h> | 19 | #include <drm/drm_atomic_helper.h> |
20 | #include <drm/drm_crtc.h> | ||
21 | #include <drm/drm_flip_work.h> | ||
22 | #include <drm/drm_plane_helper.h> | ||
21 | 23 | ||
22 | #include "tilcdc_drv.h" | 24 | #include "tilcdc_drv.h" |
23 | #include "tilcdc_regs.h" | 25 | #include "tilcdc_regs.h" |
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index f0851db6ba6c..cc45d98f9bb5 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c | |||
@@ -86,8 +86,8 @@ static int udl_usb_probe(struct usb_interface *interface, | |||
86 | int r; | 86 | int r; |
87 | 87 | ||
88 | dev = drm_dev_alloc(&driver, &interface->dev); | 88 | dev = drm_dev_alloc(&driver, &interface->dev); |
89 | if (!dev) | 89 | if (IS_ERR(dev)) |
90 | return -ENOMEM; | 90 | return PTR_ERR(dev); |
91 | 91 | ||
92 | r = drm_dev_register(dev, (unsigned long)udev); | 92 | r = drm_dev_register(dev, (unsigned long)udev); |
93 | if (r) | 93 | if (r) |
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index deec53545bea..3c9e7f64b926 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c | |||
@@ -233,8 +233,8 @@ static int vc4_drm_bind(struct device *dev) | |||
233 | return -ENOMEM; | 233 | return -ENOMEM; |
234 | 234 | ||
235 | drm = drm_dev_alloc(&vc4_drm_driver, dev); | 235 | drm = drm_dev_alloc(&vc4_drm_driver, dev); |
236 | if (!drm) | 236 | if (IS_ERR(drm)) |
237 | return -ENOMEM; | 237 | return PTR_ERR(drm); |
238 | platform_set_drvdata(pdev, drm); | 238 | platform_set_drvdata(pdev, drm); |
239 | vc4->dev = drm; | 239 | vc4->dev = drm; |
240 | drm->dev_private = vc4; | 240 | drm->dev_private = vc4; |
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index c15bafb06665..f36c14729b55 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c | |||
@@ -334,8 +334,8 @@ static int __init vgem_init(void) | |||
334 | int ret; | 334 | int ret; |
335 | 335 | ||
336 | vgem_device = drm_dev_alloc(&vgem_driver, NULL); | 336 | vgem_device = drm_dev_alloc(&vgem_driver, NULL); |
337 | if (!vgem_device) { | 337 | if (IS_ERR(vgem_device)) { |
338 | ret = -ENOMEM; | 338 | ret = PTR_ERR(vgem_device); |
339 | goto out; | 339 | goto out; |
340 | } | 340 | } |
341 | 341 | ||
diff --git a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c index a59d0e309bfc..26197dd95d5c 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c +++ b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c | |||
@@ -54,8 +54,8 @@ int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev) | |||
54 | int ret; | 54 | int ret; |
55 | 55 | ||
56 | dev = drm_dev_alloc(driver, &vdev->dev); | 56 | dev = drm_dev_alloc(driver, &vdev->dev); |
57 | if (!dev) | 57 | if (IS_ERR(dev)) |
58 | return -ENOMEM; | 58 | return PTR_ERR(dev); |
59 | dev->virtdev = vdev; | 59 | dev->virtdev = vdev; |
60 | vdev->priv = dev; | 60 | vdev->priv = dev; |
61 | 61 | ||