diff options
author | Dave Airlie <airlied@redhat.com> | 2016-09-28 03:28:23 +0300 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-09-28 03:28:23 +0300 |
commit | 3f346d5dcb591c2a5a26653d093af710cf2e5a31 (patch) | |
tree | 24384b63b4ba23912afa6dac409f354b097156ff /drivers/gpu | |
parent | 196ebdcc1db26977948c760664f024fa766950e4 (diff) | |
parent | 089cfdd9b0ec1b21d3356d2e057f69b89d46ae66 (diff) | |
download | linux-3f346d5dcb591c2a5a26653d093af710cf2e5a31.tar.xz |
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')
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 \ drm_rect.o drm_vma_manager.o drm_flip_work.o \ drm_modeset_lock.o drm_atomic.o drm_bridge.o \ drm_framebuffer.o drm_connector.o drm_blend.o \ - drm_encoder.o drm_mode_object.o drm_property.o + drm_encoder.o drm_mode_object.o drm_property.o \ + drm_plane.o drm_color_mgmt.o drm-$(CONFIG_COMPAT) += drm_ioc32.o 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) if (amdgpu_ttm_tt_get_usermm(bo->ttm)) return -EPERM; - return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp); + return drm_vma_node_verify_access(&rbo->gem_base.vma_node, + filp->private_data); } 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) int ret; drm = drm_dev_alloc(&arcpgu_drm_driver, &pdev->dev); - if (!drm) - return -ENOMEM; + if (IS_ERR(drm)) + return PTR_ERR(drm); ret = arcpgu_load(drm); 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) return -ENOMEM; drm = drm_dev_alloc(&hdlcd_driver, dev); - if (!drm) - return -ENOMEM; + if (IS_ERR(drm)) + return PTR_ERR(drm); drm->dev_private = hdlcd; 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) return ret; drm = drm_dev_alloc(&malidp_driver, dev); - if (!drm) { - ret = -ENOMEM; + if (IS_ERR(drm)) { + ret = PTR_ERR(drm); goto alloc_fail; } 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) { struct ast_bo *astbo = ast_bo(bo); - return drm_vma_node_verify_access(&astbo->gem.vma_node, filp); + return drm_vma_node_verify_access(&astbo->gem.vma_node, + filp->private_data); } 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) int ret; ddev = drm_dev_alloc(&atmel_hlcdc_dc_driver, &pdev->dev); - if (!ddev) - return -ENOMEM; + if (IS_ERR(ddev)) + return PTR_ERR(ddev); ret = atmel_hlcdc_dc_load(ddev); 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) } -int bochs_connector_get_modes(struct drm_connector *connector) +static int bochs_connector_get_modes(struct drm_connector *connector) { int count; 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, { struct bochs_bo *bochsbo = bochs_bo(bo); - return drm_vma_node_verify_access(&bochsbo->gem.vma_node, filp); + return drm_vma_node_verify_access(&bochsbo->gem.vma_node, + filp->private_data); } 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 @@ #include <drm/bridge/analogix_dp.h> #include "analogix_dp_core.h" +#include "analogix_dp_reg.h" #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) @@ -147,7 +148,7 @@ static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) { unsigned char psr_version; - analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, &psr_version); + drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version); dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); 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) unsigned char psr_en; /* Disable psr function */ - analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en); + drm_dp_dpcd_readb(&dp->aux, DP_PSR_EN_CFG, &psr_en); psr_en &= ~DP_PSR_ENABLE; - analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en); /* Main-Link transmitter remains active during PSR active states */ psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; - analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en); /* Enable psr function */ psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; - analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en); analogix_dp_enable_psr_crc(dp); } -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static int analogix_dp_read_edid(struct analogix_dp_device *dp) -{ - unsigned char *edid = dp->edid; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* - * EDID device address is 0x50. - * However, if necessary, you must have set upper address - * into E-EDID in I2C device, 0x30. - */ - - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_EXTENSION_FLAG, - &extend_block); - if (retval) - return retval; - - if (extend_block > 0) { - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - &edid[EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - /* Read additional EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - &edid[EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - &test_vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_RESPONSE, - DP_TEST_EDID_CHECKSUM_WRITE); - } - } else { - dev_info(dp->dev, "EDID data does not include any extensions.\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - &test_vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_RESPONSE, DP_TEST_EDID_CHECKSUM_WRITE); - } - } - - dev_dbg(dp->dev, "EDID Read success!\n"); - return 0; -} - -static int analogix_dp_handle_edid(struct analogix_dp_device *dp) -{ - u8 buf[12]; - int i; - int retval; - - /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */ - retval = analogix_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, 12, buf); - if (retval) - return retval; - - /* Read EDID */ - for (i = 0; i < 3; i++) { - retval = analogix_dp_read_edid(dp); - if (!retval) - break; - } - - return retval; -} - static void analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp, bool enable) { u8 data; - analogix_dp_read_byte_from_dpcd(dp, DP_LANE_COUNT_SET, &data); + drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data); if (enable) - analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, - DP_LANE_COUNT_ENHANCED_FRAME_EN | - DPCD_LANE_COUNT_SET(data)); + drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, + DP_LANE_COUNT_ENHANCED_FRAME_EN | + DPCD_LANE_COUNT_SET(data)); else - analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, - DPCD_LANE_COUNT_SET(data)); + drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, + DPCD_LANE_COUNT_SET(data)); } 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) u8 data; int retval; - analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); + drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data); retval = DPCD_ENHANCED_FRAME_CAP(data); return retval; @@ -344,8 +216,8 @@ static void analogix_dp_training_pattern_dis(struct analogix_dp_device *dp) { analogix_dp_set_training_pattern(dp, DP_NONE); - analogix_dp_write_byte_to_dpcd(dp, DP_TRAINING_PATTERN_SET, - DP_TRAINING_PATTERN_DISABLE); + drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_DISABLE); } static void @@ -390,8 +262,8 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) /* Setup RX configuration */ buf[0] = dp->link_train.link_rate; buf[1] = dp->link_train.lane_count; - retval = analogix_dp_write_bytes_to_dpcd(dp, DP_LINK_BW_SET, 2, buf); - if (retval) + retval = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, 2); + if (retval < 0) return retval; /* Set TX pre-emphasis to minimum */ @@ -415,20 +287,22 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) analogix_dp_set_training_pattern(dp, TRAINING_PTN1); /* Set RX training pattern */ - retval = analogix_dp_write_byte_to_dpcd(dp, - DP_TRAINING_PATTERN_SET, - DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1); - if (retval) + retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, + DP_LINK_SCRAMBLING_DISABLE | + DP_TRAINING_PATTERN_1); + if (retval < 0) return retval; for (lane = 0; lane < lane_count; lane++) buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 | DP_TRAIN_VOLTAGE_SWING_LEVEL_0; - retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, - lane_count, buf); + retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, + lane_count); + if (retval < 0) + return retval; - return retval; + return 0; } 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) lane_count = dp->link_train.lane_count; - retval = analogix_dp_read_bytes_from_dpcd(dp, - DP_LANE0_1_STATUS, 2, link_status); - if (retval) + retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); + if (retval < 0) return retval; - retval = analogix_dp_read_bytes_from_dpcd(dp, - DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); - if (retval) + retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, + adjust_request, 2); + if (retval < 0) return retval; if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) { /* set training pattern 2 for EQ */ analogix_dp_set_training_pattern(dp, TRAINING_PTN2); - retval = analogix_dp_write_byte_to_dpcd(dp, - DP_TRAINING_PATTERN_SET, - DP_LINK_SCRAMBLING_DISABLE | - DP_TRAINING_PATTERN_2); - if (retval) + retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, + DP_LINK_SCRAMBLING_DISABLE | + DP_TRAINING_PATTERN_2); + if (retval < 0) return retval; 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) analogix_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); - retval = analogix_dp_write_bytes_to_dpcd(dp, - DP_TRAINING_LANE0_SET, lane_count, - dp->link_train.training_lane); - if (retval) + retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, + dp->link_train.training_lane, lane_count); + if (retval < 0) return retval; - return retval; + return 0; } 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) lane_count = dp->link_train.lane_count; - retval = analogix_dp_read_bytes_from_dpcd(dp, - DP_LANE0_1_STATUS, 2, link_status); - if (retval) + retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); + if (retval < 0) return retval; 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) return -EIO; } - retval = analogix_dp_read_bytes_from_dpcd(dp, - DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); - if (retval) + retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, + adjust_request, 2); + if (retval < 0) return retval; - retval = analogix_dp_read_byte_from_dpcd(dp, - DP_LANE_ALIGN_STATUS_UPDATED, &link_align); - if (retval) + retval = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED, + &link_align); + if (retval < 0) return retval; 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) analogix_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); - retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, - lane_count, dp->link_train.training_lane); + retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, + dp->link_train.training_lane, lane_count); + if (retval < 0) + return retval; - return retval; + return 0; } 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, * For DP rev.1.2, Maximum link rate of Main Link lanes * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps */ - analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data); + drm_dp_dpcd_readb(&dp->aux, DP_MAX_LINK_RATE, &data); *bandwidth = data; } @@ -743,7 +615,7 @@ static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp, * For DP rev.1.1, Maximum number of Main Link lanes * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes */ - analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); + drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data); *lane_count = DPCD_MAX_LANE_COUNT(data); } @@ -912,19 +784,15 @@ static void analogix_dp_enable_scramble(struct analogix_dp_device *dp, if (enable) { analogix_dp_enable_scrambling(dp); - analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, - &data); - analogix_dp_write_byte_to_dpcd(dp, - DP_TRAINING_PATTERN_SET, - (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); + drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data); + drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, + (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); } else { analogix_dp_disable_scrambling(dp); - analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, - &data); - analogix_dp_write_byte_to_dpcd(dp, - DP_TRAINING_PATTERN_SET, - (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); + drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data); + drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, + (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); } } @@ -1050,33 +918,37 @@ out: return ret; } -int analogix_dp_get_modes(struct drm_connector *connector) +static int analogix_dp_get_modes(struct drm_connector *connector) { struct analogix_dp_device *dp = to_dp(connector); - struct edid *edid = (struct edid *)dp->edid; + struct edid *edid; int ret, num_modes = 0; - ret = analogix_dp_prepare_panel(dp, true, false); - if (ret) { - DRM_ERROR("Failed to prepare panel (%d)\n", ret); - return 0; - } + if (dp->plat_data->panel) { + num_modes += drm_panel_get_modes(dp->plat_data->panel); + } else { + ret = analogix_dp_prepare_panel(dp, true, false); + if (ret) { + DRM_ERROR("Failed to prepare panel (%d)\n", ret); + return 0; + } - if (analogix_dp_handle_edid(dp) == 0) { - drm_mode_connector_update_edid_property(&dp->connector, edid); - num_modes += drm_add_edid_modes(&dp->connector, edid); - } + edid = drm_get_edid(connector, &dp->aux.ddc); + if (edid) { + drm_mode_connector_update_edid_property(&dp->connector, + edid); + num_modes += drm_add_edid_modes(&dp->connector, edid); + kfree(edid); + } - if (dp->plat_data->panel) - num_modes += drm_panel_get_modes(dp->plat_data->panel); + ret = analogix_dp_prepare_panel(dp, false, false); + if (ret) + DRM_ERROR("Failed to unprepare panel (%d)\n", ret); + } if (dp->plat_data->get_modes) num_modes += dp->plat_data->get_modes(dp->plat_data, connector); - ret = analogix_dp_prepare_panel(dp, false, false); - if (ret) - DRM_ERROR("Failed to unprepare panel (%d)\n", ret); - return num_modes; } @@ -1093,13 +965,16 @@ static const struct drm_connector_helper_funcs analogix_dp_connector_helper_func .best_encoder = analogix_dp_best_encoder, }; -enum drm_connector_status +static enum drm_connector_status analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); enum drm_connector_status status = connector_status_disconnected; int ret; + if (dp->plat_data->panel) + return connector_status_connected; + ret = analogix_dp_prepare_panel(dp, true, false); if (ret) { 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) return 0; } +static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct analogix_dp_device *dp = to_dp(aux); + + return analogix_dp_transfer(dp, msg); +} + int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, struct analogix_dp_plat_data *plat_data) { @@ -1515,6 +1398,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, dp->drm_dev = drm_dev; dp->encoder = dp->plat_data->encoder; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = analogix_dpaux_transfer; + dp->aux.dev = &pdev->dev; + + ret = drm_dp_aux_register(&dp->aux); + if (ret) + goto err_disable_pm_runtime; + ret = analogix_dp_create_bridge(drm_dev, dp); if (ret) { 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 @@ #define MAX_CR_LOOP 5 #define MAX_EQ_LOOP 5 -/* I2C EDID Chip ID, Slave Address */ -#define I2C_EDID_DEVICE_ADDR 0x50 -#define I2C_E_EDID_DEVICE_ADDR 0x30 - -#define EDID_BLOCK_LENGTH 0x80 -#define EDID_HEADER_PATTERN 0x00 -#define EDID_EXTENSION_FLAG 0x7e -#define EDID_CHECKSUM 0x7f - /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) @@ -166,6 +157,7 @@ struct analogix_dp_device { struct drm_device *drm_dev; struct drm_connector connector; struct drm_bridge *bridge; + struct drm_dp_aux aux; struct clk *clock; unsigned int irq; void __iomem *reg_base; @@ -176,7 +168,6 @@ struct analogix_dp_device { int dpms_mode; int hpd_gpio; bool force_hpd; - unsigned char edid[EDID_BLOCK_LENGTH * 2]; bool psr_support; struct mutex panel_lock; @@ -210,33 +201,6 @@ void analogix_dp_reset_aux(struct analogix_dp_device *dp); void analogix_dp_init_aux(struct analogix_dp_device *dp); int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp); void analogix_dp_enable_sw_function(struct analogix_dp_device *dp); -int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp); -int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned char data); -int analogix_dp_read_byte_from_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned char *data); -int analogix_dp_write_bytes_to_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned int count, - unsigned char data[]); -int analogix_dp_read_bytes_from_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned int count, - unsigned char data[]); -int analogix_dp_select_i2c_device(struct analogix_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr); -int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr, - unsigned int *data); -int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr, - unsigned int count, - unsigned char edid[]); void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype); void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype); 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); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, struct edp_vsc_psr *vsc); +ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, + struct drm_dp_aux_msg *msg); #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, return retval; } -int analogix_dp_read_byte_from_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned char *data) -{ - u32 reg; - int i; - int retval; - - for (i = 0; i < 3; i++) { - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); - - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); - reg = AUX_ADDR_15_8(reg_addr); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); - reg = AUX_ADDR_19_16(reg_addr); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); - - /* - * Set DisplayPort transaction and read 1 byte - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = analogix_dp_start_aux_transaction(dp); - if (retval == 0) - break; - - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); - } - - /* Read data buffer */ - reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0); - *data = (unsigned char)(reg & 0xff); - - return retval; -} - -int analogix_dp_write_bytes_to_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned int count, - unsigned char data[]) -{ - u32 reg; - unsigned int start_offset; - unsigned int cur_data_count; - unsigned int cur_data_idx; - int i; - int retval = 0; - - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); - - start_offset = 0; - while (start_offset < count) { - /* Buffer size of AUX CH is 16 * 4bytes */ - if ((count - start_offset) > 16) - cur_data_count = 16; - else - cur_data_count = count - start_offset; - - for (i = 0; i < 3; i++) { - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr + start_offset); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); - reg = AUX_ADDR_15_8(reg_addr + start_offset); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); - reg = AUX_ADDR_19_16(reg_addr + start_offset); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); - - for (cur_data_idx = 0; cur_data_idx < cur_data_count; - cur_data_idx++) { - reg = data[start_offset + cur_data_idx]; - writel(reg, dp->reg_base + - ANALOGIX_DP_BUF_DATA_0 + - 4 * cur_data_idx); - } - - /* - * Set DisplayPort transaction and write - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_LENGTH(cur_data_count) | - AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = analogix_dp_start_aux_transaction(dp); - if (retval == 0) - break; - - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", - __func__); - } - - start_offset += cur_data_count; - } - - return retval; -} - -int analogix_dp_read_bytes_from_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned int count, - unsigned char data[]) -{ - u32 reg; - unsigned int start_offset; - unsigned int cur_data_count; - unsigned int cur_data_idx; - int i; - int retval = 0; - - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); - - start_offset = 0; - while (start_offset < count) { - /* Buffer size of AUX CH is 16 * 4bytes */ - if ((count - start_offset) > 16) - cur_data_count = 16; - else - cur_data_count = count - start_offset; - - /* AUX CH Request Transaction process */ - for (i = 0; i < 3; i++) { - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr + start_offset); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); - reg = AUX_ADDR_15_8(reg_addr + start_offset); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); - reg = AUX_ADDR_19_16(reg_addr + start_offset); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); - - /* - * Set DisplayPort transaction and read - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_LENGTH(cur_data_count) | - AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = analogix_dp_start_aux_transaction(dp); - if (retval == 0) - break; - - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", - __func__); - } - - for (cur_data_idx = 0; cur_data_idx < cur_data_count; - cur_data_idx++) { - reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 - + 4 * cur_data_idx); - data[start_offset + cur_data_idx] = - (unsigned char)reg; - } - - start_offset += cur_data_count; - } - - return retval; -} - -int analogix_dp_select_i2c_device(struct analogix_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr) -{ - u32 reg; - int retval; - - /* Set EDID device address */ - reg = device_addr; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); - writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); - writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); - - /* Set offset from base address of EDID device */ - writel(reg_addr, dp->reg_base + ANALOGIX_DP_BUF_DATA_0); - - /* - * Set I2C transaction and write address - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | - AUX_TX_COMM_WRITE; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = analogix_dp_start_aux_transaction(dp); - if (retval != 0) - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); - - return retval; -} - -int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr, - unsigned int *data) -{ - u32 reg; - int i; - int retval; - - for (i = 0; i < 3; i++) { - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); - - /* Select EDID device */ - retval = analogix_dp_select_i2c_device(dp, device_addr, - reg_addr); - if (retval != 0) - continue; - - /* - * Set I2C transaction and read data - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_I2C_TRANSACTION | - AUX_TX_COMM_READ; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = analogix_dp_start_aux_transaction(dp); - if (retval == 0) - break; - - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); - } - - /* Read data */ - if (retval == 0) - *data = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0); - - return retval; -} - -int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr, - unsigned int count, - unsigned char edid[]) -{ - u32 reg; - unsigned int i, j; - unsigned int cur_data_idx; - unsigned int defer = 0; - int retval = 0; - - for (i = 0; i < count; i += 16) { - for (j = 0; j < 3; j++) { - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); - - /* Set normal AUX CH command */ - reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); - reg &= ~ADDR_ONLY; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); - - /* - * If Rx sends defer, Tx sends only reads - * request without sending address - */ - if (!defer) - retval = analogix_dp_select_i2c_device(dp, - device_addr, reg_addr + i); - else - defer = 0; - - if (retval == 0) { - /* - * Set I2C transaction and write data - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_LENGTH(16) | - AUX_TX_COMM_I2C_TRANSACTION | - AUX_TX_COMM_READ; - writel(reg, dp->reg_base + - ANALOGIX_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = analogix_dp_start_aux_transaction(dp); - if (retval == 0) - break; - - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", - __func__); - } - /* Check if Rx sends defer */ - reg = readl(dp->reg_base + ANALOGIX_DP_AUX_RX_COMM); - if (reg == AUX_RX_COMM_AUX_DEFER || - reg == AUX_RX_COMM_I2C_DEFER) { - dev_err(dp->dev, "Defer: %d\n\n", reg); - defer = 1; - } - } - - for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { - reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 - + 4 * cur_data_idx); - edid[i + cur_data_idx] = (unsigned char)reg; - } - } - - return retval; -} - void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype) { u32 reg; @@ -1361,3 +1037,130 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); } + +ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, + struct drm_dp_aux_msg *msg) +{ + u32 reg; + u8 *buffer = msg->buffer; + int timeout_loop = 0; + unsigned int i; + int num_transferred = 0; + + /* Buffer size of AUX CH is 16 bytes */ + if (WARN_ON(msg->size > 16)) + return -E2BIG; + + /* Clear AUX CH data buffer */ + reg = BUF_CLR; + writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_I2C_WRITE: + reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_I2C_TRANSACTION; + if (msg->request & DP_AUX_I2C_MOT) + reg |= AUX_TX_COMM_MOT; + break; + + case DP_AUX_I2C_READ: + reg = AUX_TX_COMM_READ | AUX_TX_COMM_I2C_TRANSACTION; + if (msg->request & DP_AUX_I2C_MOT) + reg |= AUX_TX_COMM_MOT; + break; + + case DP_AUX_NATIVE_WRITE: + reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_DP_TRANSACTION; + break; + + case DP_AUX_NATIVE_READ: + reg = AUX_TX_COMM_READ | AUX_TX_COMM_DP_TRANSACTION; + break; + + default: + return -EINVAL; + } + + reg |= AUX_LENGTH(msg->size); + writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); + + /* Select DPCD device address */ + reg = AUX_ADDR_7_0(msg->address); + writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); + reg = AUX_ADDR_15_8(msg->address); + writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); + reg = AUX_ADDR_19_16(msg->address); + writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); + + if (!(msg->request & DP_AUX_I2C_READ)) { + for (i = 0; i < msg->size; i++) { + reg = buffer[i]; + writel(reg, dp->reg_base + ANALOGIX_DP_BUF_DATA_0 + + 4 * i); + num_transferred++; + } + } + + /* Enable AUX CH operation */ + reg = AUX_EN; + + /* Zero-sized messages specify address-only transactions. */ + if (msg->size < 1) + reg |= ADDR_ONLY; + + writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); + + /* Is AUX CH command reply received? */ + /* TODO: Wait for an interrupt instead of looping? */ + reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); + while (!(reg & RPLY_RECEIV)) { + timeout_loop++; + if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { + dev_err(dp->dev, "AUX CH command reply failed!\n"); + return -ETIMEDOUT; + } + reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); + usleep_range(10, 11); + } + + /* Clear interrupt source for AUX CH command reply */ + writel(RPLY_RECEIV, dp->reg_base + ANALOGIX_DP_INT_STA); + + /* Clear interrupt source for AUX CH access error */ + reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); + if (reg & AUX_ERR) { + writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA); + return -EREMOTEIO; + } + + /* Check AUX CH error access status */ + reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA); + if ((reg & AUX_STATUS_MASK)) { + dev_err(dp->dev, "AUX CH error happened: %d\n\n", + reg & AUX_STATUS_MASK); + return -EREMOTEIO; + } + + if (msg->request & DP_AUX_I2C_READ) { + for (i = 0; i < msg->size; i++) { + reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 + + 4 * i); + buffer[i] = (unsigned char)reg; + num_transferred++; + } + } + + /* Check if Rx sends defer */ + reg = readl(dp->reg_base + ANALOGIX_DP_AUX_RX_COMM); + if (reg == AUX_RX_COMM_AUX_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + else if (reg == AUX_RX_COMM_I2C_DEFER) + msg->reply = DP_AUX_I2C_REPLY_DEFER; + else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE || + (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_READ) + msg->reply = DP_AUX_I2C_REPLY_ACK; + else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE || + (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_READ) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + + return num_transferred; +} 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 { struct cirrus_bo *cirrusbo = cirrus_bo(bo); - return drm_vma_node_verify_access(&cirrusbo->gem.vma_node, filp); + return drm_vma_node_verify_access(&cirrusbo->gem.vma_node, + filp->private_data); } 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: } EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); -bool plane_crtc_active(struct drm_plane_state *state) +static bool plane_crtc_active(const struct drm_plane_state *state) { return state->crtc && state->crtc->state->active; } 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 @@ */ #include <drm/drmP.h> #include <drm/drm_atomic.h> -#include <drm/drm_crtc.h> +#include <drm/drm_blend.h> #include <linux/export.h> #include <linux/slab.h> #include <linux/sort.h> -#include "drm_internal.h" +#include "drm_crtc_internal.h" + +/** + * DOC: overview + * + * The basic plane composition model supported by standard plane properties only + * has a source rectangle (in logical pixels within the &drm_framebuffer), with + * sub-pixel accuracy, which is scaled up to a pixel-aligned destination + * rectangle in the visible area of a &drm_crtc. The visible area of a CRTC is + * defined by the horizontal and vertical visible pixels (stored in @hdisplay + * and @vdisplay) of the requested mode (stored in @mode in the + * &drm_crtc_state). These two rectangles are both stored in the + * &drm_plane_state. + * + * For the atomic ioctl the following standard (atomic) properties on the plane object + * encode the basic plane composition model: + * + * SRC_X: + * X coordinate offset for the source rectangle within the + * &drm_framebuffer, in 16.16 fixed point. Must be positive. + * SRC_Y: + * Y coordinate offset for the source rectangle within the + * &drm_framebuffer, in 16.16 fixed point. Must be positive. + * SRC_W: + * Width for the source rectangle within the &drm_framebuffer, in 16.16 + * fixed point. SRC_X plus SRC_W must be within the width of the source + * framebuffer. Must be positive. + * SRC_H: + * Height for the source rectangle within the &drm_framebuffer, in 16.16 + * fixed point. SRC_Y plus SRC_H must be within the height of the source + * framebuffer. Must be positive. + * CRTC_X: + * X coordinate offset for the destination rectangle. Can be negative. + * CRTC_Y: + * Y coordinate offset for the destination rectangle. Can be negative. + * CRTC_W: + * Width for the destination rectangle. CRTC_X plus CRTC_W can extend past + * the currently visible horizontal area of the &drm_crtc. + * CRTC_H: + * Height for the destination rectangle. CRTC_Y plus CRTC_H can extend past + * the currently visible vertical area of the &drm_crtc. + * FB_ID: + * Mode object ID of the &drm_framebuffer this plane should scan out. + * CRTC_ID: + * Mode object ID of the &drm_crtc this plane should be connected to. + * + * Note that the source rectangle must fully lie within the bounds of the + * &drm_framebuffer. The destination rectangle can lie outside of the visible + * area of the current mode of the CRTC. It must be apprpriately clipped by the + * driver, which can be done by calling drm_plane_helper_check_update(). Drivers + * are also allowed to round the subpixel sampling positions appropriately, but + * only to the next full pixel. No pixel outside of the source rectangle may + * ever be sampled, which is important when applying more sophisticated + * filtering than just a bilinear one when scaling. The filtering mode when + * scaling is unspecified. + * + * On top of this basic transformation additional properties can be exposed by + * the driver: + * + * - Rotation is set up with drm_mode_create_rotation_property(). It adds a + * rotation and reflection step between the source and destination rectangles. + * Without this property the rectangle is only scaled, but not rotated or + * reflected. + * + * - Z position is set up with drm_plane_create_zpos_immutable_property() and + * drm_plane_create_zpos_property(). It controls the visibility of overlapping + * planes. Without this property the primary plane is always below the cursor + * plane, and ordering between all other planes is undefined. + * + * Note that all the property extensions described here apply either to the + * plane or the CRTC (e.g. for the background color, which currently is not + * exposed and assumed to be black). + */ + +/** + * drm_mode_create_rotation_property - create a new rotation property + * @dev: DRM device + * @supported_rotations: bitmask of supported rotations and reflections + * + * This creates a new property with the selected support for transformations. + * The resulting property should be stored in @rotation_property in + * &drm_mode_config. It then must be attached to each plane which supports + * rotations using drm_object_attach_property(). + * + * FIXME: Probably better if the rotation property is created on each plane, + * like the zpos property. Otherwise it's not possible to allow different + * rotation modes on different planes. + * + * Since a rotation by 180° degress is the same as reflecting both along the x + * and the y axis the rotation property is somewhat redundant. Drivers can use + * drm_rotation_simplify() to normalize values of this property. + * + * The property exposed to userspace is a bitmask property (see + * drm_property_create_bitmask()) called "rotation" and has the following + * bitmask enumaration values: + * + * DRM_ROTATE_0: + * "rotate-0" + * DRM_ROTATE_90: + * "rotate-90" + * DRM_ROTATE_180: + * "rotate-180" + * DRM_ROTATE_270: + * "rotate-270" + * DRM_REFLECT_X: + * "reflect-x" + * DRM_REFELCT_Y: + * "reflect-y" + * + * Rotation is the specified amount in degrees in counter clockwise direction, + * the X and Y axis are within the source rectangle, i.e. the X/Y axis before + * rotation. After reflection, the rotation is applied to the image sampled from + * the source rectangle, before scaling it to fit the destination rectangle. + */ +struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, + unsigned int supported_rotations) +{ + static const struct drm_prop_enum_list props[] = { + { __builtin_ffs(DRM_ROTATE_0) - 1, "rotate-0" }, + { __builtin_ffs(DRM_ROTATE_90) - 1, "rotate-90" }, + { __builtin_ffs(DRM_ROTATE_180) - 1, "rotate-180" }, + { __builtin_ffs(DRM_ROTATE_270) - 1, "rotate-270" }, + { __builtin_ffs(DRM_REFLECT_X) - 1, "reflect-x" }, + { __builtin_ffs(DRM_REFLECT_Y) - 1, "reflect-y" }, + }; + + return drm_property_create_bitmask(dev, 0, "rotation", + props, ARRAY_SIZE(props), + supported_rotations); +} +EXPORT_SYMBOL(drm_mode_create_rotation_property); + +/** + * drm_rotation_simplify() - Try to simplify the rotation + * @rotation: Rotation to be simplified + * @supported_rotations: Supported rotations + * + * Attempt to simplify the rotation to a form that is supported. + * Eg. if the hardware supports everything except DRM_REFLECT_X + * one could call this function like this: + * + * drm_rotation_simplify(rotation, DRM_ROTATE_0 | + * DRM_ROTATE_90 | DRM_ROTATE_180 | + * DRM_ROTATE_270 | DRM_REFLECT_Y); + * + * to eliminate the DRM_ROTATE_X flag. Depending on what kind of + * transforms the hardware supports, this function may not + * be able to produce a supported transform, so the caller should + * check the result afterwards. + */ +unsigned int drm_rotation_simplify(unsigned int rotation, + unsigned int supported_rotations) +{ + if (rotation & ~supported_rotations) { + rotation ^= DRM_REFLECT_X | DRM_REFLECT_Y; + rotation = (rotation & DRM_REFLECT_MASK) | + BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4); + } + + return rotation; +} +EXPORT_SYMBOL(drm_rotation_simplify); /** * drm_plane_create_zpos_property - create mutable zpos property @@ -49,10 +210,14 @@ * If zpos of some planes cannot be changed (like fixed background or * cursor/topmost planes), driver should adjust min/max values and assign those * planes immutable zpos property with lower or higher values (for more - * information, see drm_mode_create_zpos_immutable_property() function). In such + * information, see drm_plane_create_zpos_immutable_property() function). In such * case driver should also assign proper initial zpos values for all planes in * its plane_reset() callback, so the planes will be always sorted properly. * + * See also drm_atomic_normalize_zpos(). + * + * The property exposed to userspace is called "zpos". + * * Returns: * Zero on success, negative errno on failure. */ @@ -88,7 +253,9 @@ EXPORT_SYMBOL(drm_plane_create_zpos_property); * support for it in drm core. Using this property driver lets userspace * to get the arrangement of the planes for blending operation and notifies * it that the hardware (or driver) doesn't support changing of the planes' - * order. + * order. For mutable zpos see drm_plane_create_zpos_property(). + * + * The property exposed to userspace is called "zpos". * * Returns: * Zero on success, negative errno on failure. @@ -127,20 +294,6 @@ static int drm_atomic_state_zpos_cmp(const void *a, const void *b) return sa->plane->base.id - sb->plane->base.id; } -/** - * drm_atomic_helper_crtc_normalize_zpos - calculate normalized zpos values - * @crtc: crtc with planes, which have to be considered for normalization - * @crtc_state: new atomic state to apply - * - * This function checks new states of all planes assigned to given crtc and - * calculates normalized zpos value for them. Planes are compared first by their - * zpos values, then by plane id (if zpos equals). Plane with lowest zpos value - * is at the bottom. The plane_state->normalized_zpos is then filled with unique - * values from 0 to number of active planes in crtc minus one. - * - * RETURNS - * Zero for success or -errno - */ static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { @@ -198,8 +351,14 @@ done: * @state: atomic state of DRM device * * This function calculates normalized zpos value for all modified planes in - * the provided atomic state of DRM device. For more information, see - * drm_atomic_helper_crtc_normalize_zpos() function. + * the provided atomic state of DRM device. + * + * For every CRTC this function checks new states of all planes assigned to + * it and calculates normalized zpos value for these planes. Planes are compared + * first by their zpos values, then by plane id (if zpos is equal). The plane + * with lowest zpos value is at the bottom. The plane_state->normalized_zpos is + * then filled with unique values from 0 to number of active planes in crtc + * minus one. * * RETURNS * 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 @@ #include <linux/err.h> #include <linux/module.h> +#include <linux/mutex.h> -#include <drm/drm_crtc.h> - -#include "drm/drmP.h" +#include <drm/drm_bridge.h> /** * 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, return -EINVAL; } - entry->buflist = kzalloc(count * sizeof(*entry->buflist), GFP_KERNEL); + entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL); if (!entry->buflist) { mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); @@ -905,14 +905,14 @@ int drm_legacy_addbufs_pci(struct drm_device *dev, return -EINVAL; } - entry->buflist = kzalloc(count * sizeof(*entry->buflist), GFP_KERNEL); + entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL); if (!entry->buflist) { mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } - entry->seglist = kzalloc(count * sizeof(*entry->seglist), GFP_KERNEL); + entry->seglist = kcalloc(count, sizeof(*entry->seglist), GFP_KERNEL); if (!entry->seglist) { kfree(entry->buflist); mutex_unlock(&dev->struct_mutex); @@ -923,8 +923,9 @@ int drm_legacy_addbufs_pci(struct drm_device *dev, /* Keep the original pagelist until we know all the allocations * have succeeded */ - temp_pagelist = kmalloc((dma->page_count + (count << page_order)) * - sizeof(*dma->pagelist), GFP_KERNEL); + temp_pagelist = kmalloc_array(dma->page_count + (count << page_order), + sizeof(*dma->pagelist), + GFP_KERNEL); if (!temp_pagelist) { kfree(entry->buflist); kfree(entry->seglist); @@ -1116,8 +1117,7 @@ static int drm_legacy_addbufs_sg(struct drm_device *dev, return -EINVAL; } - entry->buflist = kzalloc(count * sizeof(*entry->buflist), - GFP_KERNEL); + entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL); if (!entry->buflist) { mutex_unlock(&dev->struct_mutex); 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 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_color_mgmt.h> + +#include "drm_crtc_internal.h" + +/** + * DOC: overview + * + * Color management or color space adjustments is supported through a set of 5 + * properties on the &drm_crtc object. They are set up by calling + * drm_crtc_enable_color_mgmt(). + * + * "DEGAMMA_LUT”: + * Blob property to set the degamma lookup table (LUT) mapping pixel data + * from the framebuffer before it is given to the transformation matrix. + * The data is interpreted as an array of struct &drm_color_lut elements. + * Hardware might choose not to use the full precision of the LUT elements + * nor use all the elements of the LUT (for example the hardware might + * choose to interpolate between LUT[0] and LUT[4]). + * + * “DEGAMMA_LUT_SIZE”: + * Unsinged range property to give the size of the lookup table to be set + * on the DEGAMMA_LUT property (the size depends on the underlying + * hardware). If drivers support multiple LUT sizes then they should + * publish the largest size, and sub-sample smaller sized LUTs (e.g. for + * split-gamma modes) appropriately. + * + * “CTM”: + * Blob property to set the current transformation matrix (CTM) apply to + * pixel data after the lookup through the degamma LUT and before the + * lookup through the gamma LUT. The data is interpreted as a struct + * &drm_color_ctm. + * + * “GAMMA_LUT”: + * Blob property to set the gamma lookup table (LUT) mapping pixel data + * after the transformation matrix to data sent to the connector. The + * data is interpreted as an array of struct &drm_color_lut elements. + * Hardware might choose not to use the full precision of the LUT elements + * nor use all the elements of the LUT (for example the hardware might + * choose to interpolate between LUT[0] and LUT[4]). + * + * “GAMMA_LUT_SIZE”: + * Unsigned range property to give the size of the lookup table to be set + * on the GAMMA_LUT property (the size depends on the underlying hardware). + * If drivers support multiple LUT sizes then they should publish the + * largest size, and sub-sample smaller sized LUTs (e.g. for split-gamma + * modes) appropriately. + * + * There is also support for a legacy gamma table, which is set up by calling + * drm_mode_crtc_set_gamma_size(). Drivers which support both should use + * drm_atomic_helper_legacy_gamma_set() to alias the legacy gamma ramp with the + * "GAMMA_LUT" property above. + */ + +/** + * drm_crtc_enable_color_mgmt - enable color management properties + * @crtc: DRM CRTC + * @degamma_lut_size: the size of the degamma lut (before CSC) + * @has_ctm: whether to attach ctm_property for CSC matrix + * @gamma_lut_size: the size of the gamma lut (after CSC) + * + * This function lets the driver enable the color correction + * properties on a CRTC. This includes 3 degamma, csc and gamma + * properties that userspace can set and 2 size properties to inform + * the userspace of the lut sizes. Each of the properties are + * optional. The gamma and degamma properties are only attached if + * their size is not 0 and ctm_property is only attached if has_ctm is + * true. + */ +void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, + uint degamma_lut_size, + bool has_ctm, + uint gamma_lut_size) +{ + struct drm_device *dev = crtc->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (degamma_lut_size) { + drm_object_attach_property(&crtc->base, + config->degamma_lut_property, 0); + drm_object_attach_property(&crtc->base, + config->degamma_lut_size_property, + degamma_lut_size); + } + + if (has_ctm) + drm_object_attach_property(&crtc->base, + config->ctm_property, 0); + + if (gamma_lut_size) { + drm_object_attach_property(&crtc->base, + config->gamma_lut_property, 0); + drm_object_attach_property(&crtc->base, + config->gamma_lut_size_property, + gamma_lut_size); + } +} +EXPORT_SYMBOL(drm_crtc_enable_color_mgmt); + +/** + * drm_mode_crtc_set_gamma_size - set the gamma table size + * @crtc: CRTC to set the gamma table size for + * @gamma_size: size of the gamma table + * + * Drivers which support gamma tables should set this to the supported gamma + * table size when initializing the CRTC. Currently the drm core only supports a + * fixed gamma table size. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, + int gamma_size) +{ + uint16_t *r_base, *g_base, *b_base; + int i; + + crtc->gamma_size = gamma_size; + + crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, + GFP_KERNEL); + if (!crtc->gamma_store) { + crtc->gamma_size = 0; + return -ENOMEM; + } + + r_base = crtc->gamma_store; + g_base = r_base + gamma_size; + b_base = g_base + gamma_size; + for (i = 0; i < gamma_size; i++) { + r_base[i] = i << 8; + g_base[i] = i << 8; + b_base[i] = i << 8; + } + + + return 0; +} +EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); + +/** + * drm_mode_gamma_set_ioctl - set the gamma table + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Set the gamma table of a CRTC to the one passed in by the user. Userspace can + * inquire the required gamma table size through drm_mode_gamma_get_ioctl. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_gamma_set_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_crtc_lut *crtc_lut = data; + struct drm_crtc *crtc; + void *r_base, *g_base, *b_base; + int size; + int ret = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + drm_modeset_lock_all(dev); + crtc = drm_crtc_find(dev, crtc_lut->crtc_id); + if (!crtc) { + ret = -ENOENT; + goto out; + } + + if (crtc->funcs->gamma_set == NULL) { + ret = -ENOSYS; + goto out; + } + + /* memcpy into gamma store */ + if (crtc_lut->gamma_size != crtc->gamma_size) { + ret = -EINVAL; + goto out; + } + + size = crtc_lut->gamma_size * (sizeof(uint16_t)); + r_base = crtc->gamma_store; + if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { + ret = -EFAULT; + goto out; + } + + g_base = r_base + size; + if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { + ret = -EFAULT; + goto out; + } + + b_base = g_base + size; + if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { + ret = -EFAULT; + goto out; + } + + ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); + +out: + drm_modeset_unlock_all(dev); + return ret; + +} + +/** + * drm_mode_gamma_get_ioctl - get the gamma table + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Copy the current gamma table into the storage provided. This also provides + * the gamma table size the driver expects, which can be used to size the + * allocated storage. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_gamma_get_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_crtc_lut *crtc_lut = data; + struct drm_crtc *crtc; + void *r_base, *g_base, *b_base; + int size; + int ret = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + drm_modeset_lock_all(dev); + crtc = drm_crtc_find(dev, crtc_lut->crtc_id); + if (!crtc) { + ret = -ENOENT; + goto out; + } + + /* memcpy into gamma store */ + if (crtc_lut->gamma_size != crtc->gamma_size) { + ret = -EINVAL; + goto out; + } + + size = crtc_lut->gamma_size * (sizeof(uint16_t)); + r_base = crtc->gamma_store; + if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { + ret = -EFAULT; + goto out; + } + + g_base = r_base + size; + if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { + ret = -EFAULT; + goto out; + } + + b_base = g_base + size; + if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { + ret = -EFAULT; + goto out; + } +out: + drm_modeset_unlock_all(dev); + return ret; +} 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) * @funcs: callbacks for the new CRTC * @name: printf style format string for the CRTC name, or NULL for default name * - * Inits a new object created as base part of a driver crtc object. + * Inits a new object created as base part of a driver crtc object. Drivers + * should use this function instead of drm_crtc_init(), which is only provided + * for backwards compatibility with drivers which do not yet support universal + * planes). For really simple hardware which has only 1 plane look at + * drm_simple_display_pipe_init() instead. * * Returns: * Zero on success, error code on failure. @@ -251,255 +255,6 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_cleanup); -static unsigned int drm_num_planes(struct drm_device *dev) -{ - unsigned int num = 0; - struct drm_plane *tmp; - - drm_for_each_plane(tmp, dev) { - num++; - } - - return num; -} - -/** - * drm_universal_plane_init - Initialize a new universal plane object - * @dev: DRM device - * @plane: plane object to init - * @possible_crtcs: bitmask of possible CRTCs - * @funcs: callbacks for the new plane - * @formats: array of supported formats (DRM_FORMAT\_\*) - * @format_count: number of elements in @formats - * @type: type of plane (overlay, primary, cursor) - * @name: printf style format string for the plane name, or NULL for default name - * - * Initializes a plane object of type @type. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, - unsigned long possible_crtcs, - const struct drm_plane_funcs *funcs, - const uint32_t *formats, unsigned int format_count, - enum drm_plane_type type, - const char *name, ...) -{ - struct drm_mode_config *config = &dev->mode_config; - int ret; - - ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); - if (ret) - return ret; - - drm_modeset_lock_init(&plane->mutex); - - plane->base.properties = &plane->properties; - plane->dev = dev; - plane->funcs = funcs; - plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), - GFP_KERNEL); - if (!plane->format_types) { - DRM_DEBUG_KMS("out of memory when allocating plane\n"); - drm_mode_object_unregister(dev, &plane->base); - return -ENOMEM; - } - - if (name) { - va_list ap; - - va_start(ap, name); - plane->name = kvasprintf(GFP_KERNEL, name, ap); - va_end(ap); - } else { - plane->name = kasprintf(GFP_KERNEL, "plane-%d", - drm_num_planes(dev)); - } - if (!plane->name) { - kfree(plane->format_types); - drm_mode_object_unregister(dev, &plane->base); - return -ENOMEM; - } - - memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); - plane->format_count = format_count; - plane->possible_crtcs = possible_crtcs; - plane->type = type; - - list_add_tail(&plane->head, &config->plane_list); - plane->index = config->num_total_plane++; - if (plane->type == DRM_PLANE_TYPE_OVERLAY) - config->num_overlay_plane++; - - drm_object_attach_property(&plane->base, - config->plane_type_property, - plane->type); - - if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { - drm_object_attach_property(&plane->base, config->prop_fb_id, 0); - drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); - drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); - drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); - drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); - drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); - drm_object_attach_property(&plane->base, config->prop_src_x, 0); - drm_object_attach_property(&plane->base, config->prop_src_y, 0); - drm_object_attach_property(&plane->base, config->prop_src_w, 0); - drm_object_attach_property(&plane->base, config->prop_src_h, 0); - } - - return 0; -} -EXPORT_SYMBOL(drm_universal_plane_init); - -static int drm_plane_register_all(struct drm_device *dev) -{ - struct drm_plane *plane; - int ret = 0; - - drm_for_each_plane(plane, dev) { - if (plane->funcs->late_register) - ret = plane->funcs->late_register(plane); - if (ret) - return ret; - } - - return 0; -} - -static void drm_plane_unregister_all(struct drm_device *dev) -{ - struct drm_plane *plane; - - drm_for_each_plane(plane, dev) { - if (plane->funcs->early_unregister) - plane->funcs->early_unregister(plane); - } -} - -/** - * drm_plane_init - Initialize a legacy plane - * @dev: DRM device - * @plane: plane object to init - * @possible_crtcs: bitmask of possible CRTCs - * @funcs: callbacks for the new plane - * @formats: array of supported formats (DRM_FORMAT\_\*) - * @format_count: number of elements in @formats - * @is_primary: plane type (primary vs overlay) - * - * Legacy API to initialize a DRM plane. - * - * New drivers should call drm_universal_plane_init() instead. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, - unsigned long possible_crtcs, - const struct drm_plane_funcs *funcs, - const uint32_t *formats, unsigned int format_count, - bool is_primary) -{ - enum drm_plane_type type; - - type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; - return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, - formats, format_count, type, NULL); -} -EXPORT_SYMBOL(drm_plane_init); - -/** - * drm_plane_cleanup - Clean up the core plane usage - * @plane: plane to cleanup - * - * This function cleans up @plane and removes it from the DRM mode setting - * core. Note that the function does *not* free the plane structure itself, - * this is the responsibility of the caller. - */ -void drm_plane_cleanup(struct drm_plane *plane) -{ - struct drm_device *dev = plane->dev; - - drm_modeset_lock_all(dev); - kfree(plane->format_types); - drm_mode_object_unregister(dev, &plane->base); - - BUG_ON(list_empty(&plane->head)); - - /* Note that the plane_list is considered to be static; should we - * remove the drm_plane at runtime we would have to decrement all - * the indices on the drm_plane after us in the plane_list. - */ - - list_del(&plane->head); - dev->mode_config.num_total_plane--; - if (plane->type == DRM_PLANE_TYPE_OVERLAY) - dev->mode_config.num_overlay_plane--; - drm_modeset_unlock_all(dev); - - WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); - if (plane->state && plane->funcs->atomic_destroy_state) - plane->funcs->atomic_destroy_state(plane, plane->state); - - kfree(plane->name); - - memset(plane, 0, sizeof(*plane)); -} -EXPORT_SYMBOL(drm_plane_cleanup); - -/** - * drm_plane_from_index - find the registered plane at an index - * @dev: DRM device - * @idx: index of registered plane to find for - * - * Given a plane index, return the registered plane from DRM device's - * list of planes with matching index. - */ -struct drm_plane * -drm_plane_from_index(struct drm_device *dev, int idx) -{ - struct drm_plane *plane; - - drm_for_each_plane(plane, dev) - if (idx == plane->index) - return plane; - - return NULL; -} -EXPORT_SYMBOL(drm_plane_from_index); - -/** - * drm_plane_force_disable - Forcibly disable a plane - * @plane: plane to disable - * - * Forces the plane to be disabled. - * - * Used when the plane's current framebuffer is destroyed, - * and when restoring fbdev mode. - */ -void drm_plane_force_disable(struct drm_plane *plane) -{ - int ret; - - if (!plane->fb) - return; - - plane->old_fb = plane->fb; - ret = plane->funcs->disable_plane(plane); - if (ret) { - DRM_ERROR("failed to disable plane with busy fb\n"); - plane->old_fb = NULL; - return; - } - /* disconnect the plane from the fb and crtc: */ - drm_framebuffer_unreference(plane->old_fb); - plane->old_fb = NULL; - plane->fb = NULL; - plane->crtc = NULL; -} -EXPORT_SYMBOL(drm_plane_force_disable); - int drm_modeset_register_all(struct drm_device *dev) { int ret; @@ -855,343 +610,6 @@ int drm_mode_getcrtc(struct drm_device *dev, } /** - * drm_mode_getplane_res - enumerate all plane resources - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * Construct a list of plane ids to return to the user. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_getplane_res(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_mode_get_plane_res *plane_resp = data; - struct drm_mode_config *config; - struct drm_plane *plane; - uint32_t __user *plane_ptr; - int copied = 0; - unsigned num_planes; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - config = &dev->mode_config; - - if (file_priv->universal_planes) - num_planes = config->num_total_plane; - else - num_planes = config->num_overlay_plane; - - /* - * This ioctl is called twice, once to determine how much space is - * needed, and the 2nd time to fill it. - */ - if (num_planes && - (plane_resp->count_planes >= num_planes)) { - plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; - - /* Plane lists are invariant, no locking needed. */ - drm_for_each_plane(plane, dev) { - /* - * Unless userspace set the 'universal planes' - * capability bit, only advertise overlays. - */ - if (plane->type != DRM_PLANE_TYPE_OVERLAY && - !file_priv->universal_planes) - continue; - - if (put_user(plane->base.id, plane_ptr + copied)) - return -EFAULT; - copied++; - } - } - plane_resp->count_planes = num_planes; - - return 0; -} - -/** - * drm_mode_getplane - get plane configuration - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * Construct a plane configuration structure to return to the user. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_getplane(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_mode_get_plane *plane_resp = data; - struct drm_plane *plane; - uint32_t __user *format_ptr; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - plane = drm_plane_find(dev, plane_resp->plane_id); - if (!plane) - return -ENOENT; - - drm_modeset_lock(&plane->mutex, NULL); - if (plane->crtc) - plane_resp->crtc_id = plane->crtc->base.id; - else - plane_resp->crtc_id = 0; - - if (plane->fb) - plane_resp->fb_id = plane->fb->base.id; - else - plane_resp->fb_id = 0; - drm_modeset_unlock(&plane->mutex); - - plane_resp->plane_id = plane->base.id; - plane_resp->possible_crtcs = plane->possible_crtcs; - plane_resp->gamma_size = 0; - - /* - * This ioctl is called twice, once to determine how much space is - * needed, and the 2nd time to fill it. - */ - if (plane->format_count && - (plane_resp->count_format_types >= plane->format_count)) { - format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; - if (copy_to_user(format_ptr, - plane->format_types, - sizeof(uint32_t) * plane->format_count)) { - return -EFAULT; - } - } - plane_resp->count_format_types = plane->format_count; - - return 0; -} - -/** - * drm_plane_check_pixel_format - Check if the plane supports the pixel format - * @plane: plane to check for format support - * @format: the pixel format - * - * Returns: - * Zero of @plane has @format in its list of supported pixel formats, -EINVAL - * otherwise. - */ -int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) -{ - unsigned int i; - - for (i = 0; i < plane->format_count; i++) { - if (format == plane->format_types[i]) - return 0; - } - - return -EINVAL; -} - -static int check_src_coords(uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h, - const struct drm_framebuffer *fb) -{ - unsigned int fb_width, fb_height; - - fb_width = fb->width << 16; - fb_height = fb->height << 16; - - /* Make sure source coordinates are inside the fb. */ - if (src_w > fb_width || - src_x > fb_width - src_w || - src_h > fb_height || - src_y > fb_height - src_h) { - DRM_DEBUG_KMS("Invalid source coordinates " - "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", - src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, - src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, - src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, - src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); - return -ENOSPC; - } - - return 0; -} - -/* - * setplane_internal - setplane handler for internal callers - * - * Note that we assume an extra reference has already been taken on fb. If the - * update fails, this reference will be dropped before return; if it succeeds, - * the previous framebuffer (if any) will be unreferenced instead. - * - * src_{x,y,w,h} are provided in 16.16 fixed point format - */ -static int __setplane_internal(struct drm_plane *plane, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int32_t crtc_x, int32_t crtc_y, - uint32_t crtc_w, uint32_t crtc_h, - /* src_{x,y,w,h} values are 16.16 fixed point */ - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) -{ - int ret = 0; - - /* No fb means shut it down */ - if (!fb) { - plane->old_fb = plane->fb; - ret = plane->funcs->disable_plane(plane); - if (!ret) { - plane->crtc = NULL; - plane->fb = NULL; - } else { - plane->old_fb = NULL; - } - goto out; - } - - /* Check whether this plane is usable on this CRTC */ - if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { - DRM_DEBUG_KMS("Invalid crtc for plane\n"); - ret = -EINVAL; - goto out; - } - - /* Check whether this plane supports the fb pixel format. */ - ret = drm_plane_check_pixel_format(plane, fb->pixel_format); - if (ret) { - char *format_name = drm_get_format_name(fb->pixel_format); - DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name); - kfree(format_name); - goto out; - } - - /* Give drivers some help against integer overflows */ - if (crtc_w > INT_MAX || - crtc_x > INT_MAX - (int32_t) crtc_w || - crtc_h > INT_MAX || - crtc_y > INT_MAX - (int32_t) crtc_h) { - DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", - crtc_w, crtc_h, crtc_x, crtc_y); - ret = -ERANGE; - goto out; - } - - ret = check_src_coords(src_x, src_y, src_w, src_h, fb); - if (ret) - goto out; - - plane->old_fb = plane->fb; - ret = plane->funcs->update_plane(plane, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); - if (!ret) { - plane->crtc = crtc; - plane->fb = fb; - fb = NULL; - } else { - plane->old_fb = NULL; - } - -out: - if (fb) - drm_framebuffer_unreference(fb); - if (plane->old_fb) - drm_framebuffer_unreference(plane->old_fb); - plane->old_fb = NULL; - - return ret; -} - -static int setplane_internal(struct drm_plane *plane, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int32_t crtc_x, int32_t crtc_y, - uint32_t crtc_w, uint32_t crtc_h, - /* src_{x,y,w,h} values are 16.16 fixed point */ - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) -{ - int ret; - - drm_modeset_lock_all(plane->dev); - ret = __setplane_internal(plane, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); - drm_modeset_unlock_all(plane->dev); - - return ret; -} - -/** - * drm_mode_setplane - configure a plane's configuration - * @dev: DRM device - * @data: ioctl data* - * @file_priv: DRM file info - * - * Set plane configuration, including placement, fb, scaling, and other factors. - * Or pass a NULL fb to disable (planes may be disabled without providing a - * valid crtc). - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_setplane(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_mode_set_plane *plane_req = data; - struct drm_plane *plane; - struct drm_crtc *crtc = NULL; - struct drm_framebuffer *fb = NULL; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - /* - * First, find the plane, crtc, and fb objects. If not available, - * we don't bother to call the driver. - */ - plane = drm_plane_find(dev, plane_req->plane_id); - if (!plane) { - DRM_DEBUG_KMS("Unknown plane ID %d\n", - plane_req->plane_id); - return -ENOENT; - } - - if (plane_req->fb_id) { - fb = drm_framebuffer_lookup(dev, plane_req->fb_id); - if (!fb) { - DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", - plane_req->fb_id); - return -ENOENT; - } - - crtc = drm_crtc_find(dev, plane_req->crtc_id); - if (!crtc) { - DRM_DEBUG_KMS("Unknown crtc ID %d\n", - plane_req->crtc_id); - return -ENOENT; - } - } - - /* - * setplane_internal will take care of deref'ing either the old or new - * framebuffer depending on success. - */ - return setplane_internal(plane, crtc, fb, - plane_req->crtc_x, plane_req->crtc_y, - plane_req->crtc_w, plane_req->crtc_h, - plane_req->src_x, plane_req->src_y, - plane_req->src_w, plane_req->src_h); -} - -/** * drm_mode_set_config_internal - helper to call ->set_config * @set: modeset config to set * @@ -1281,8 +699,9 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, DRM_ROTATE_270)) swap(hdisplay, vdisplay); - return check_src_coords(x << 16, y << 16, - hdisplay << 16, vdisplay << 16, fb); + return drm_framebuffer_check_src_coords(x << 16, y << 16, + hdisplay << 16, vdisplay << 16, + fb); } EXPORT_SYMBOL(drm_crtc_check_viewport); @@ -1469,208 +888,6 @@ out: return ret; } -/** - * drm_mode_cursor_universal - translate legacy cursor ioctl call into a - * universal plane handler call - * @crtc: crtc to update cursor for - * @req: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Legacy cursor ioctl's work directly with driver buffer handles. To - * translate legacy ioctl calls into universal plane handler calls, we need to - * wrap the native buffer handle in a drm_framebuffer. - * - * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB - * buffer with a pitch of 4*width; the universal plane interface should be used - * directly in cases where the hardware can support other buffer settings and - * userspace wants to make use of these capabilities. - * - * Returns: - * Zero on success, negative errno on failure. - */ -static int drm_mode_cursor_universal(struct drm_crtc *crtc, - struct drm_mode_cursor2 *req, - struct drm_file *file_priv) -{ - struct drm_device *dev = crtc->dev; - struct drm_framebuffer *fb = NULL; - struct drm_mode_fb_cmd2 fbreq = { - .width = req->width, - .height = req->height, - .pixel_format = DRM_FORMAT_ARGB8888, - .pitches = { req->width * 4 }, - .handles = { req->handle }, - }; - int32_t crtc_x, crtc_y; - uint32_t crtc_w = 0, crtc_h = 0; - uint32_t src_w = 0, src_h = 0; - int ret = 0; - - BUG_ON(!crtc->cursor); - WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); - - /* - * Obtain fb we'll be using (either new or existing) and take an extra - * reference to it if fb != null. setplane will take care of dropping - * the reference if the plane update fails. - */ - if (req->flags & DRM_MODE_CURSOR_BO) { - if (req->handle) { - fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv); - if (IS_ERR(fb)) { - DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); - return PTR_ERR(fb); - } - fb->hot_x = req->hot_x; - fb->hot_y = req->hot_y; - } else { - fb = NULL; - } - } else { - fb = crtc->cursor->fb; - if (fb) - drm_framebuffer_reference(fb); - } - - if (req->flags & DRM_MODE_CURSOR_MOVE) { - crtc_x = req->x; - crtc_y = req->y; - } else { - crtc_x = crtc->cursor_x; - crtc_y = crtc->cursor_y; - } - - if (fb) { - crtc_w = fb->width; - crtc_h = fb->height; - src_w = fb->width << 16; - src_h = fb->height << 16; - } - - /* - * setplane_internal will take care of deref'ing either the old or new - * framebuffer depending on success. - */ - ret = __setplane_internal(crtc->cursor, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - 0, 0, src_w, src_h); - - /* Update successful; save new cursor position, if necessary */ - if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { - crtc->cursor_x = req->x; - crtc->cursor_y = req->y; - } - - return ret; -} - -static int drm_mode_cursor_common(struct drm_device *dev, - struct drm_mode_cursor2 *req, - struct drm_file *file_priv) -{ - struct drm_crtc *crtc; - int ret = 0; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) - return -EINVAL; - - crtc = drm_crtc_find(dev, req->crtc_id); - if (!crtc) { - DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); - return -ENOENT; - } - - /* - * If this crtc has a universal cursor plane, call that plane's update - * handler rather than using legacy cursor handlers. - */ - drm_modeset_lock_crtc(crtc, crtc->cursor); - if (crtc->cursor) { - ret = drm_mode_cursor_universal(crtc, req, file_priv); - goto out; - } - - if (req->flags & DRM_MODE_CURSOR_BO) { - if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { - ret = -ENXIO; - goto out; - } - /* Turns off the cursor if handle is 0 */ - if (crtc->funcs->cursor_set2) - ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, - req->width, req->height, req->hot_x, req->hot_y); - else - ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, - req->width, req->height); - } - - if (req->flags & DRM_MODE_CURSOR_MOVE) { - if (crtc->funcs->cursor_move) { - ret = crtc->funcs->cursor_move(crtc, req->x, req->y); - } else { - ret = -EFAULT; - goto out; - } - } -out: - drm_modeset_unlock_crtc(crtc); - - return ret; - -} - - -/** - * drm_mode_cursor_ioctl - set CRTC's cursor configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Set the cursor configuration based on user request. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_cursor_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_cursor *req = data; - struct drm_mode_cursor2 new_req; - - memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); - new_req.hot_x = new_req.hot_y = 0; - - return drm_mode_cursor_common(dev, &new_req, file_priv); -} - -/** - * drm_mode_cursor2_ioctl - set CRTC's cursor configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Set the cursor configuration based on user request. This implements the 2nd - * version of the cursor ioctl, which allows userspace to additionally specify - * the hotspot of the pointer. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_cursor2_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_cursor2 *req = data; - - return drm_mode_cursor_common(dev, req, file_priv); -} - int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, struct drm_property *property, uint64_t value) @@ -1687,376 +904,6 @@ int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, } /** - * drm_mode_plane_set_obj_prop - set the value of a property - * @plane: drm plane object to set property value for - * @property: property to set - * @value: value the property should be set to - * - * This functions sets a given property on a given plane object. This function - * calls the driver's ->set_property callback and changes the software state of - * the property if the callback succeeds. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_mode_plane_set_obj_prop(struct drm_plane *plane, - struct drm_property *property, - uint64_t value) -{ - int ret = -EINVAL; - struct drm_mode_object *obj = &plane->base; - - if (plane->funcs->set_property) - ret = plane->funcs->set_property(plane, property, value); - if (!ret) - drm_object_property_set_value(obj, property, value); - - return ret; -} -EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); - -/** - * drm_mode_crtc_set_gamma_size - set the gamma table size - * @crtc: CRTC to set the gamma table size for - * @gamma_size: size of the gamma table - * - * Drivers which support gamma tables should set this to the supported gamma - * table size when initializing the CRTC. Currently the drm core only supports a - * fixed gamma table size. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, - int gamma_size) -{ - uint16_t *r_base, *g_base, *b_base; - int i; - - crtc->gamma_size = gamma_size; - - crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, - GFP_KERNEL); - if (!crtc->gamma_store) { - crtc->gamma_size = 0; - return -ENOMEM; - } - - r_base = crtc->gamma_store; - g_base = r_base + gamma_size; - b_base = g_base + gamma_size; - for (i = 0; i < gamma_size; i++) { - r_base[i] = i << 8; - g_base[i] = i << 8; - b_base[i] = i << 8; - } - - - return 0; -} -EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); - -/** - * drm_mode_gamma_set_ioctl - set the gamma table - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * Set the gamma table of a CRTC to the one passed in by the user. Userspace can - * inquire the required gamma table size through drm_mode_gamma_get_ioctl. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_gamma_set_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_crtc_lut *crtc_lut = data; - struct drm_crtc *crtc; - void *r_base, *g_base, *b_base; - int size; - int ret = 0; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - drm_modeset_lock_all(dev); - crtc = drm_crtc_find(dev, crtc_lut->crtc_id); - if (!crtc) { - ret = -ENOENT; - goto out; - } - - if (crtc->funcs->gamma_set == NULL) { - ret = -ENOSYS; - goto out; - } - - /* memcpy into gamma store */ - if (crtc_lut->gamma_size != crtc->gamma_size) { - ret = -EINVAL; - goto out; - } - - size = crtc_lut->gamma_size * (sizeof(uint16_t)); - r_base = crtc->gamma_store; - if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { - ret = -EFAULT; - goto out; - } - - g_base = r_base + size; - if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { - ret = -EFAULT; - goto out; - } - - b_base = g_base + size; - if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { - ret = -EFAULT; - goto out; - } - - ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); - -out: - drm_modeset_unlock_all(dev); - return ret; - -} - -/** - * drm_mode_gamma_get_ioctl - get the gamma table - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * Copy the current gamma table into the storage provided. This also provides - * the gamma table size the driver expects, which can be used to size the - * allocated storage. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_gamma_get_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_crtc_lut *crtc_lut = data; - struct drm_crtc *crtc; - void *r_base, *g_base, *b_base; - int size; - int ret = 0; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - drm_modeset_lock_all(dev); - crtc = drm_crtc_find(dev, crtc_lut->crtc_id); - if (!crtc) { - ret = -ENOENT; - goto out; - } - - /* memcpy into gamma store */ - if (crtc_lut->gamma_size != crtc->gamma_size) { - ret = -EINVAL; - goto out; - } - - size = crtc_lut->gamma_size * (sizeof(uint16_t)); - r_base = crtc->gamma_store; - if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { - ret = -EFAULT; - goto out; - } - - g_base = r_base + size; - if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { - ret = -EFAULT; - goto out; - } - - b_base = g_base + size; - if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { - ret = -EFAULT; - goto out; - } -out: - drm_modeset_unlock_all(dev); - return ret; -} - -/** - * drm_mode_page_flip_ioctl - schedule an asynchronous fb update - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * This schedules an asynchronous update on a given CRTC, called page flip. - * Optionally a drm event is generated to signal the completion of the event. - * Generic drivers cannot assume that a pageflip with changed framebuffer - * properties (including driver specific metadata like tiling layout) will work, - * but some drivers support e.g. pixel format changes through the pageflip - * ioctl. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_page_flip_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_crtc_page_flip_target *page_flip = data; - struct drm_crtc *crtc; - struct drm_framebuffer *fb = NULL; - struct drm_pending_vblank_event *e = NULL; - u32 target_vblank = page_flip->sequence; - int ret = -EINVAL; - - if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS) - return -EINVAL; - - if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) - return -EINVAL; - - /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags - * can be specified - */ - if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET) - return -EINVAL; - - if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) - return -EINVAL; - - crtc = drm_crtc_find(dev, page_flip->crtc_id); - if (!crtc) - return -ENOENT; - - if (crtc->funcs->page_flip_target) { - u32 current_vblank; - int r; - - r = drm_crtc_vblank_get(crtc); - if (r) - return r; - - current_vblank = drm_crtc_vblank_count(crtc); - - switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) { - case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE: - if ((int)(target_vblank - current_vblank) > 1) { - DRM_DEBUG("Invalid absolute flip target %u, " - "must be <= %u\n", target_vblank, - current_vblank + 1); - drm_crtc_vblank_put(crtc); - return -EINVAL; - } - break; - case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE: - if (target_vblank != 0 && target_vblank != 1) { - DRM_DEBUG("Invalid relative flip target %u, " - "must be 0 or 1\n", target_vblank); - drm_crtc_vblank_put(crtc); - return -EINVAL; - } - target_vblank += current_vblank; - break; - default: - target_vblank = current_vblank + - !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC); - break; - } - } else if (crtc->funcs->page_flip == NULL || - (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) { - return -EINVAL; - } - - drm_modeset_lock_crtc(crtc, crtc->primary); - if (crtc->primary->fb == NULL) { - /* The framebuffer is currently unbound, presumably - * due to a hotplug event, that userspace has not - * yet discovered. - */ - ret = -EBUSY; - goto out; - } - - fb = drm_framebuffer_lookup(dev, page_flip->fb_id); - if (!fb) { - ret = -ENOENT; - goto out; - } - - if (crtc->state) { - const struct drm_plane_state *state = crtc->primary->state; - - ret = check_src_coords(state->src_x, state->src_y, - state->src_w, state->src_h, fb); - } else { - ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); - } - if (ret) - goto out; - - if (crtc->primary->fb->pixel_format != fb->pixel_format) { - DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); - ret = -EINVAL; - goto out; - } - - if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { - e = kzalloc(sizeof *e, GFP_KERNEL); - if (!e) { - ret = -ENOMEM; - goto out; - } - e->event.base.type = DRM_EVENT_FLIP_COMPLETE; - e->event.base.length = sizeof(e->event); - e->event.user_data = page_flip->user_data; - ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); - if (ret) { - kfree(e); - goto out; - } - } - - crtc->primary->old_fb = crtc->primary->fb; - if (crtc->funcs->page_flip_target) - ret = crtc->funcs->page_flip_target(crtc, fb, e, - page_flip->flags, - target_vblank); - else - ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); - if (ret) { - if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) - drm_event_cancel_free(dev, &e->base); - /* Keep the old fb, don't unref it. */ - crtc->primary->old_fb = NULL; - } else { - crtc->primary->fb = fb; - /* Unref only the old framebuffer. */ - fb = NULL; - } - -out: - if (ret && crtc->funcs->page_flip_target) - drm_crtc_vblank_put(crtc); - if (fb) - drm_framebuffer_unreference(fb); - if (crtc->primary->old_fb) - drm_framebuffer_unreference(crtc->primary->old_fb); - crtc->primary->old_fb = NULL; - drm_modeset_unlock_crtc(crtc); - - return ret; -} - -/** * drm_mode_config_reset - call ->reset callbacks * @dev: drm device * @@ -2201,37 +1048,6 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, } /** - * drm_rotation_simplify() - Try to simplify the rotation - * @rotation: Rotation to be simplified - * @supported_rotations: Supported rotations - * - * Attempt to simplify the rotation to a form that is supported. - * Eg. if the hardware supports everything except DRM_REFLECT_X - * one could call this function like this: - * - * drm_rotation_simplify(rotation, DRM_ROTATE_0 | - * DRM_ROTATE_90 | DRM_ROTATE_180 | - * DRM_ROTATE_270 | DRM_REFLECT_Y); - * - * to eliminate the DRM_ROTATE_X flag. Depending on what kind of - * transforms the hardware supports, this function may not - * be able to produce a supported transform, so the caller should - * check the result afterwards. - */ -unsigned int drm_rotation_simplify(unsigned int rotation, - unsigned int supported_rotations) -{ - if (rotation & ~supported_rotations) { - rotation ^= DRM_REFLECT_X | DRM_REFLECT_Y; - rotation = (rotation & DRM_REFLECT_MASK) | - BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4); - } - - return rotation; -} -EXPORT_SYMBOL(drm_rotation_simplify); - -/** * drm_mode_config_init - initialize DRM mode_configuration structure * @dev: DRM device * @@ -2347,24 +1163,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_config_cleanup); -struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, - unsigned int supported_rotations) -{ - static const struct drm_prop_enum_list props[] = { - { __builtin_ffs(DRM_ROTATE_0) - 1, "rotate-0" }, - { __builtin_ffs(DRM_ROTATE_90) - 1, "rotate-90" }, - { __builtin_ffs(DRM_ROTATE_180) - 1, "rotate-180" }, - { __builtin_ffs(DRM_ROTATE_270) - 1, "rotate-270" }, - { __builtin_ffs(DRM_REFLECT_X) - 1, "reflect-x" }, - { __builtin_ffs(DRM_REFLECT_Y) - 1, "reflect-y" }, - }; - - return drm_property_create_bitmask(dev, 0, "rotation", - props, ARRAY_SIZE(props), - supported_rotations); -} -EXPORT_SYMBOL(drm_mode_create_rotation_property); - /** * DOC: Tile group * @@ -2463,48 +1261,3 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, return tg; } EXPORT_SYMBOL(drm_mode_create_tile_group); - -/** - * drm_crtc_enable_color_mgmt - enable color management properties - * @crtc: DRM CRTC - * @degamma_lut_size: the size of the degamma lut (before CSC) - * @has_ctm: whether to attach ctm_property for CSC matrix - * @gamma_lut_size: the size of the gamma lut (after CSC) - * - * This function lets the driver enable the color correction - * properties on a CRTC. This includes 3 degamma, csc and gamma - * properties that userspace can set and 2 size properties to inform - * the userspace of the lut sizes. Each of the properties are - * optional. The gamma and degamma properties are only attached if - * their size is not 0 and ctm_property is only attached if has_ctm is - * true. - */ -void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, - uint degamma_lut_size, - bool has_ctm, - uint gamma_lut_size) -{ - struct drm_device *dev = crtc->dev; - struct drm_mode_config *config = &dev->mode_config; - - if (degamma_lut_size) { - drm_object_attach_property(&crtc->base, - config->degamma_lut_property, 0); - drm_object_attach_property(&crtc->base, - config->degamma_lut_size_property, - degamma_lut_size); - } - - if (has_ctm) - drm_object_attach_property(&crtc->base, - config->ctm_property, 0); - - if (gamma_lut_size) { - drm_object_attach_property(&crtc->base, - config->gamma_lut_property, 0); - drm_object_attach_property(&crtc->base, - config->gamma_lut_size_property, - gamma_lut_size); - } -} -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 @@ #include <drm/drm_dp_helper.h> /* drm_fb_helper.c */ +#ifdef CONFIG_DRM_FBDEV_EMULATION int drm_fb_helper_modinit(void); +#else +static inline int drm_fb_helper_modinit(void) +{ + return 0; +} +#endif /* drm_dp_aux_dev.c */ #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 @@ int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, struct drm_property *property, uint64_t value); -int drm_plane_check_pixel_format(const struct drm_plane *plane, - u32 format); int drm_crtc_check_viewport(const struct drm_crtc *crtc, int x, int y, const struct drm_display_mode *mode, @@ -56,28 +54,19 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, /* IOCTLs */ int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_mode_getplane_res(struct drm_device *dev, void *data, - struct drm_file *file_priv); int drm_mode_getcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_mode_getplane(struct drm_device *dev, - void *data, struct drm_file *file_priv); -int drm_mode_setplane(struct drm_device *dev, - void *data, struct drm_file *file_priv); -int drm_mode_cursor_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); -int drm_mode_cursor2_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); + +/* drm_color_mgmt.c */ + +/* IOCTLs */ int drm_mode_gamma_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_gamma_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_mode_page_flip_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); - /* drm_property.c */ void drm_property_destroy_user_blobs(struct drm_device *dev, struct drm_file *file_priv); @@ -155,6 +144,9 @@ drm_internal_framebuffer_create(struct drm_device *dev, const struct drm_mode_fb_cmd2 *r, struct drm_file *file_priv); void drm_framebuffer_free(struct kref *kref); +int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h, + const struct drm_framebuffer *fb); /* IOCTL */ int drm_mode_addfb(struct drm_device *dev, @@ -177,6 +169,23 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, int drm_modeset_register_all(struct drm_device *dev); void drm_modeset_unregister_all(struct drm_device *dev); -/* drm_blend.c */ -int drm_atomic_normalize_zpos(struct drm_device *dev, - struct drm_atomic_state *state); + +/* drm_plane.c */ +int drm_plane_register_all(struct drm_device *dev); +void drm_plane_unregister_all(struct drm_device *dev); +int drm_plane_check_pixel_format(const struct drm_plane *plane, + u32 format); + +/* IOCTL */ +int drm_mode_getplane_res(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_mode_getplane(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_setplane(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_cursor_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_cursor2_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_page_flip_ioctl(struct drm_device *dev, + 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 @@ #include <linux/errno.h> #include <linux/sched.h> #include <linux/i2c.h> +#include <linux/seq_file.h> #include <drm/drm_dp_helper.h> #include <drm/drmP.h> 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 @@ #include <linux/mount.h> #include <linux/slab.h> #include <drm/drmP.h> -#include <drm/drm_core.h> #include "drm_crtc_internal.h" #include "drm_legacy.h" #include "drm_internal.h" @@ -46,8 +45,8 @@ unsigned int drm_debug = 0; EXPORT_SYMBOL(drm_debug); -MODULE_AUTHOR(CORE_AUTHOR); -MODULE_DESCRIPTION(CORE_DESC); +MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl"); +MODULE_DESCRIPTION("DRM shared core routines"); MODULE_LICENSE("GPL and additional rights"); MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n" "\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n" @@ -339,6 +338,9 @@ void drm_minor_release(struct drm_minor *minor) static int drm_dev_set_unique(struct drm_device *dev, const char *name) { + if (!name) + return -EINVAL; + kfree(dev->unique); dev->unique = kstrdup(name, GFP_KERNEL); @@ -589,7 +591,7 @@ EXPORT_SYMBOL(drm_dev_init); * own struct should look at using drm_dev_init() instead. * * RETURNS: - * Pointer to new DRM device, or NULL if out of memory. + * Pointer to new DRM device, or ERR_PTR on failure. */ struct drm_device *drm_dev_alloc(struct drm_driver *driver, struct device *parent) @@ -599,12 +601,12 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) - return NULL; + return ERR_PTR(-ENOMEM); ret = drm_dev_init(dev, driver, parent); if (ret) { kfree(dev); - return NULL; + return ERR_PTR(ret); } return dev; @@ -821,53 +823,48 @@ static const struct file_operations drm_stub_fops = { .llseek = noop_llseek, }; +static void drm_core_exit(void) +{ + unregister_chrdev(DRM_MAJOR, "drm"); + debugfs_remove(drm_debugfs_root); + drm_sysfs_destroy(); + idr_destroy(&drm_minors_idr); + drm_connector_ida_destroy(); + drm_global_release(); +} + static int __init drm_core_init(void) { - int ret = -ENOMEM; + int ret; drm_global_init(); drm_connector_ida_init(); idr_init(&drm_minors_idr); - if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) - goto err_p1; - ret = drm_sysfs_init(); if (ret < 0) { - printk(KERN_ERR "DRM: Error creating drm class.\n"); - goto err_p2; + DRM_ERROR("Cannot create DRM class: %d\n", ret); + goto error; } drm_debugfs_root = debugfs_create_dir("dri", NULL); if (!drm_debugfs_root) { - DRM_ERROR("Cannot create /sys/kernel/debug/dri\n"); - ret = -1; - goto err_p3; + ret = -ENOMEM; + DRM_ERROR("Cannot create debugfs-root: %d\n", ret); + goto error; } - DRM_INFO("Initialized %s %d.%d.%d %s\n", - CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); + ret = register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops); + if (ret < 0) + goto error; + + DRM_INFO("Initialized\n"); return 0; -err_p3: - drm_sysfs_destroy(); -err_p2: - unregister_chrdev(DRM_MAJOR, "drm"); - idr_destroy(&drm_minors_idr); -err_p1: +error: + drm_core_exit(); return ret; } -static void __exit drm_core_exit(void) -{ - debugfs_remove(drm_debugfs_root); - drm_sysfs_destroy(); - - unregister_chrdev(DRM_MAJOR, "drm"); - - drm_connector_ida_destroy(); - idr_destroy(&drm_minors_idr); -} - module_init(drm_core_init); 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 @@ * * Encoders represent the connecting element between the CRTC (as the overall * pixel pipeline, represented by struct &drm_crtc) and the connectors (as the - * generic sink entity, represented by struct &drm_connector). Encoders are - * objects exposed to userspace, originally to allow userspace to infer cloning - * and connector/CRTC restrictions. Unfortunately almost all drivers get this - * wrong, making the uabi pretty much useless. On top of that the exposed - * restrictions are too simple for todays hardware, and the recommend way to - * infer restrictions is by using the DRM_MODE_ATOMIC_TEST_ONLY flag for the - * atomic IOCTL. + * generic sink entity, represented by struct &drm_connector). An encoder takes + * pixel data from a CRTC and converts it to a format suitable for any attached + * connector. Encoders are objects exposed to userspace, originally to allow + * userspace to infer cloning and connector/CRTC restrictions. Unfortunately + * almost all drivers get this wrong, making the uabi pretty much useless. On + * top of that the exposed restrictions are too simple for today's hardware, and + * the recommended way to infer restrictions is by using the + * DRM_MODE_ATOMIC_TEST_ONLY flag for the atomic IOCTL. * * Otherwise encoders aren't used in the uapi at all (any modeset request from * userspace directly connects a connector with a CRTC), drivers are therefore * free to use them however they wish. Modeset helper libraries make strong use * of encoders to facilitate code sharing. But for more complex settings it is * usually better to move shared code into a separate &drm_bridge. Compared to - * encoders bridges also have the benefit of not being purely an internal + * encoders, bridges also have the benefit of being purely an internal * abstraction since they are not exposed to userspace at all. * * 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 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include "drm_crtc_helper_internal.h" + static bool drm_fbdev_emulation = true; module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600); 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) filp->private_data = priv; priv->filp = filp; - priv->uid = current_euid(); priv->pid = get_pid(task_pid(current)); priv->minor = minor; 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 @@ * &drm_framebuffer. */ +int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h, + const struct drm_framebuffer *fb) +{ + unsigned int fb_width, fb_height; + + fb_width = fb->width << 16; + fb_height = fb->height << 16; + + /* Make sure source coordinates are inside the fb. */ + if (src_w > fb_width || + src_x > fb_width - src_w || + src_h > fb_height || + src_y > fb_height - src_h) { + DRM_DEBUG_KMS("Invalid source coordinates " + "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", + src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, + src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, + src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, + src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); + return -ENOSPC; + } + + return 0; +} + /** * drm_mode_addfb - add an FB to the graphics configuration * @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) if (drm_core_check_feature(dev, DRIVER_PRIME)) drm_gem_remove_prime_handles(obj, file_priv); - drm_vma_node_revoke(&obj->vma_node, file_priv->filp); + drm_vma_node_revoke(&obj->vma_node, file_priv); if (dev->driver->gem_close_object) dev->driver->gem_close_object(obj, file_priv); @@ -372,7 +372,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, handle = ret; - ret = drm_vma_node_allow(&obj->vma_node, file_priv->filp); + ret = drm_vma_node_allow(&obj->vma_node, file_priv); if (ret) goto err_remove; @@ -386,7 +386,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, return 0; err_revoke: - drm_vma_node_revoke(&obj->vma_node, file_priv->filp); + drm_vma_node_revoke(&obj->vma_node, file_priv); err_remove: spin_lock(&file_priv->table_lock); idr_remove(&file_priv->object_idr, handle); @@ -991,7 +991,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) if (!obj) return -EINVAL; - if (!drm_vma_node_is_allowed(node, filp)) { + if (!drm_vma_node_is_allowed(node, priv)) { drm_gem_object_unreference_unlocked(obj); return -EACCES; } 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) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; struct drm_file *priv; + kuid_t uid; seq_printf(m, "%20s %5s %3s master a %5s %10s\n", @@ -98,13 +99,14 @@ int drm_clients_info(struct seq_file *m, void *data) rcu_read_lock(); /* locks pid_task()->comm */ task = pid_task(priv->pid, PIDTYPE_PID); + uid = task ? __task_cred(task)->euid : GLOBAL_ROOT_UID; seq_printf(m, "%20s %5d %3d %c %c %5d %10u\n", task ? task->comm : "<unknown>", pid_vnr(priv->pid), priv->minor->index, drm_is_current_master(priv) ? 'y' : 'n', priv->authenticated ? 'y' : 'n', - from_kuid_munged(seq_user_ns(m), priv->uid), + from_kuid_munged(seq_user_ns(m), uid), priv->magic); rcu_read_unlock(); } 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 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#define DRM_IF_MAJOR 1 +#define DRM_IF_MINOR 4 + /* drm_irq.c */ extern unsigned int drm_timestamp_monotonic; 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 @@ #include <linux/export.h> #include <drm/drmP.h> -#include <drm/drm_core.h> #define DRM_IOCTL_VERSION32 DRM_IOWR(0x00, drm_version32_t) #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 @@ */ #include <drm/drmP.h> -#include <drm/drm_core.h> #include <drm/drm_auth.h> #include "drm_legacy.h" #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, DRM_DEBUG("\n"); dev = drm_dev_alloc(driver, &pdev->dev); - if (!dev) - return -ENOMEM; + if (IS_ERR(dev)) + return PTR_ERR(dev); ret = pci_enable_device(pdev); 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 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include <drm/drmP.h> +#include <drm/drm_plane.h> + +#include "drm_crtc_internal.h" + +/** + * DOC: overview + * + * A plane represents an image source that can be blended with or overlayed on + * top of a CRTC during the scanout process. Planes take their input data from a + * &drm_framebuffer object. The plane itself specifies the cropping and scaling + * of that image, and where it is placed on the visible are of a display + * pipeline, represented by &drm_crtc. A plane can also have additional + * properties that specify how the pixels are positioned and blended, like + * rotation or Z-position. All these properties are stored in &drm_plane_state. + * + * To create a plane, a KMS drivers allocates and zeroes an instances of + * struct &drm_plane (possibly as part of a larger structure) and registers it + * with a call to drm_universal_plane_init(). + * + * Cursor and overlay planes are optional. All drivers should provide one + * primary plane per CRTC to avoid surprising userspace too much. See enum + * &drm_plane_type for a more in-depth discussion of these special uapi-relevant + * plane types. Special planes are associated with their CRTC by calling + * drm_crtc_init_with_planes(). + * + * The type of a plane is exposed in the immutable "type" enumeration property, + * which has one of the following values: "Overlay", "Primary", "Cursor". + */ + +static unsigned int drm_num_planes(struct drm_device *dev) +{ + unsigned int num = 0; + struct drm_plane *tmp; + + drm_for_each_plane(tmp, dev) { + num++; + } + + return num; +} + +/** + * drm_universal_plane_init - Initialize a new universal plane object + * @dev: DRM device + * @plane: plane object to init + * @possible_crtcs: bitmask of possible CRTCs + * @funcs: callbacks for the new plane + * @formats: array of supported formats (DRM_FORMAT\_\*) + * @format_count: number of elements in @formats + * @type: type of plane (overlay, primary, cursor) + * @name: printf style format string for the plane name, or NULL for default name + * + * Initializes a plane object of type @type. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, + unsigned long possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + enum drm_plane_type type, + const char *name, ...) +{ + struct drm_mode_config *config = &dev->mode_config; + int ret; + + ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); + if (ret) + return ret; + + drm_modeset_lock_init(&plane->mutex); + + plane->base.properties = &plane->properties; + plane->dev = dev; + plane->funcs = funcs; + plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), + GFP_KERNEL); + if (!plane->format_types) { + DRM_DEBUG_KMS("out of memory when allocating plane\n"); + drm_mode_object_unregister(dev, &plane->base); + return -ENOMEM; + } + + if (name) { + va_list ap; + + va_start(ap, name); + plane->name = kvasprintf(GFP_KERNEL, name, ap); + va_end(ap); + } else { + plane->name = kasprintf(GFP_KERNEL, "plane-%d", + drm_num_planes(dev)); + } + if (!plane->name) { + kfree(plane->format_types); + drm_mode_object_unregister(dev, &plane->base); + return -ENOMEM; + } + + memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); + plane->format_count = format_count; + plane->possible_crtcs = possible_crtcs; + plane->type = type; + + list_add_tail(&plane->head, &config->plane_list); + plane->index = config->num_total_plane++; + if (plane->type == DRM_PLANE_TYPE_OVERLAY) + config->num_overlay_plane++; + + drm_object_attach_property(&plane->base, + config->plane_type_property, + plane->type); + + if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { + drm_object_attach_property(&plane->base, config->prop_fb_id, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); + drm_object_attach_property(&plane->base, config->prop_src_x, 0); + drm_object_attach_property(&plane->base, config->prop_src_y, 0); + drm_object_attach_property(&plane->base, config->prop_src_w, 0); + drm_object_attach_property(&plane->base, config->prop_src_h, 0); + } + + return 0; +} +EXPORT_SYMBOL(drm_universal_plane_init); + +int drm_plane_register_all(struct drm_device *dev) +{ + struct drm_plane *plane; + int ret = 0; + + drm_for_each_plane(plane, dev) { + if (plane->funcs->late_register) + ret = plane->funcs->late_register(plane); + if (ret) + return ret; + } + + return 0; +} + +void drm_plane_unregister_all(struct drm_device *dev) +{ + struct drm_plane *plane; + + drm_for_each_plane(plane, dev) { + if (plane->funcs->early_unregister) + plane->funcs->early_unregister(plane); + } +} + +/** + * drm_plane_init - Initialize a legacy plane + * @dev: DRM device + * @plane: plane object to init + * @possible_crtcs: bitmask of possible CRTCs + * @funcs: callbacks for the new plane + * @formats: array of supported formats (DRM_FORMAT\_\*) + * @format_count: number of elements in @formats + * @is_primary: plane type (primary vs overlay) + * + * Legacy API to initialize a DRM plane. + * + * New drivers should call drm_universal_plane_init() instead. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, + unsigned long possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + bool is_primary) +{ + enum drm_plane_type type; + + type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; + return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, + formats, format_count, type, NULL); +} +EXPORT_SYMBOL(drm_plane_init); + +/** + * drm_plane_cleanup - Clean up the core plane usage + * @plane: plane to cleanup + * + * This function cleans up @plane and removes it from the DRM mode setting + * core. Note that the function does *not* free the plane structure itself, + * this is the responsibility of the caller. + */ +void drm_plane_cleanup(struct drm_plane *plane) +{ + struct drm_device *dev = plane->dev; + + drm_modeset_lock_all(dev); + kfree(plane->format_types); + drm_mode_object_unregister(dev, &plane->base); + + BUG_ON(list_empty(&plane->head)); + + /* Note that the plane_list is considered to be static; should we + * remove the drm_plane at runtime we would have to decrement all + * the indices on the drm_plane after us in the plane_list. + */ + + list_del(&plane->head); + dev->mode_config.num_total_plane--; + if (plane->type == DRM_PLANE_TYPE_OVERLAY) + dev->mode_config.num_overlay_plane--; + drm_modeset_unlock_all(dev); + + WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); + if (plane->state && plane->funcs->atomic_destroy_state) + plane->funcs->atomic_destroy_state(plane, plane->state); + + kfree(plane->name); + + memset(plane, 0, sizeof(*plane)); +} +EXPORT_SYMBOL(drm_plane_cleanup); + +/** + * drm_plane_from_index - find the registered plane at an index + * @dev: DRM device + * @idx: index of registered plane to find for + * + * Given a plane index, return the registered plane from DRM device's + * list of planes with matching index. + */ +struct drm_plane * +drm_plane_from_index(struct drm_device *dev, int idx) +{ + struct drm_plane *plane; + + drm_for_each_plane(plane, dev) + if (idx == plane->index) + return plane; + + return NULL; +} +EXPORT_SYMBOL(drm_plane_from_index); + +/** + * drm_plane_force_disable - Forcibly disable a plane + * @plane: plane to disable + * + * Forces the plane to be disabled. + * + * Used when the plane's current framebuffer is destroyed, + * and when restoring fbdev mode. + */ +void drm_plane_force_disable(struct drm_plane *plane) +{ + int ret; + + if (!plane->fb) + return; + + plane->old_fb = plane->fb; + ret = plane->funcs->disable_plane(plane); + if (ret) { + DRM_ERROR("failed to disable plane with busy fb\n"); + plane->old_fb = NULL; + return; + } + /* disconnect the plane from the fb and crtc: */ + drm_framebuffer_unreference(plane->old_fb); + plane->old_fb = NULL; + plane->fb = NULL; + plane->crtc = NULL; +} +EXPORT_SYMBOL(drm_plane_force_disable); + +/** + * drm_mode_plane_set_obj_prop - set the value of a property + * @plane: drm plane object to set property value for + * @property: property to set + * @value: value the property should be set to + * + * This functions sets a given property on a given plane object. This function + * calls the driver's ->set_property callback and changes the software state of + * the property if the callback succeeds. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_mode_plane_set_obj_prop(struct drm_plane *plane, + struct drm_property *property, + uint64_t value) +{ + int ret = -EINVAL; + struct drm_mode_object *obj = &plane->base; + + if (plane->funcs->set_property) + ret = plane->funcs->set_property(plane, property, value); + if (!ret) + drm_object_property_set_value(obj, property, value); + + return ret; +} +EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); + +int drm_mode_getplane_res(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_get_plane_res *plane_resp = data; + struct drm_mode_config *config; + struct drm_plane *plane; + uint32_t __user *plane_ptr; + int copied = 0; + unsigned num_planes; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + config = &dev->mode_config; + + if (file_priv->universal_planes) + num_planes = config->num_total_plane; + else + num_planes = config->num_overlay_plane; + + /* + * This ioctl is called twice, once to determine how much space is + * needed, and the 2nd time to fill it. + */ + if (num_planes && + (plane_resp->count_planes >= num_planes)) { + plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; + + /* Plane lists are invariant, no locking needed. */ + drm_for_each_plane(plane, dev) { + /* + * Unless userspace set the 'universal planes' + * capability bit, only advertise overlays. + */ + if (plane->type != DRM_PLANE_TYPE_OVERLAY && + !file_priv->universal_planes) + continue; + + if (put_user(plane->base.id, plane_ptr + copied)) + return -EFAULT; + copied++; + } + } + plane_resp->count_planes = num_planes; + + return 0; +} + +int drm_mode_getplane(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_get_plane *plane_resp = data; + struct drm_plane *plane; + uint32_t __user *format_ptr; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + plane = drm_plane_find(dev, plane_resp->plane_id); + if (!plane) + return -ENOENT; + + drm_modeset_lock(&plane->mutex, NULL); + if (plane->crtc) + plane_resp->crtc_id = plane->crtc->base.id; + else + plane_resp->crtc_id = 0; + + if (plane->fb) + plane_resp->fb_id = plane->fb->base.id; + else + plane_resp->fb_id = 0; + drm_modeset_unlock(&plane->mutex); + + plane_resp->plane_id = plane->base.id; + plane_resp->possible_crtcs = plane->possible_crtcs; + plane_resp->gamma_size = 0; + + /* + * This ioctl is called twice, once to determine how much space is + * needed, and the 2nd time to fill it. + */ + if (plane->format_count && + (plane_resp->count_format_types >= plane->format_count)) { + format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; + if (copy_to_user(format_ptr, + plane->format_types, + sizeof(uint32_t) * plane->format_count)) { + return -EFAULT; + } + } + plane_resp->count_format_types = plane->format_count; + + return 0; +} + +int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) +{ + unsigned int i; + + for (i = 0; i < plane->format_count; i++) { + if (format == plane->format_types[i]) + return 0; + } + + return -EINVAL; +} + +/* + * setplane_internal - setplane handler for internal callers + * + * Note that we assume an extra reference has already been taken on fb. If the + * update fails, this reference will be dropped before return; if it succeeds, + * the previous framebuffer (if any) will be unreferenced instead. + * + * src_{x,y,w,h} are provided in 16.16 fixed point format + */ +static int __setplane_internal(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int32_t crtc_x, int32_t crtc_y, + uint32_t crtc_w, uint32_t crtc_h, + /* src_{x,y,w,h} values are 16.16 fixed point */ + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + int ret = 0; + + /* No fb means shut it down */ + if (!fb) { + plane->old_fb = plane->fb; + ret = plane->funcs->disable_plane(plane); + if (!ret) { + plane->crtc = NULL; + plane->fb = NULL; + } else { + plane->old_fb = NULL; + } + goto out; + } + + /* Check whether this plane is usable on this CRTC */ + if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { + DRM_DEBUG_KMS("Invalid crtc for plane\n"); + ret = -EINVAL; + goto out; + } + + /* Check whether this plane supports the fb pixel format. */ + ret = drm_plane_check_pixel_format(plane, fb->pixel_format); + if (ret) { + char *format_name = drm_get_format_name(fb->pixel_format); + DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name); + kfree(format_name); + goto out; + } + + /* Give drivers some help against integer overflows */ + if (crtc_w > INT_MAX || + crtc_x > INT_MAX - (int32_t) crtc_w || + crtc_h > INT_MAX || + crtc_y > INT_MAX - (int32_t) crtc_h) { + DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", + crtc_w, crtc_h, crtc_x, crtc_y); + ret = -ERANGE; + goto out; + } + + ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb); + if (ret) + goto out; + + plane->old_fb = plane->fb; + ret = plane->funcs->update_plane(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); + if (!ret) { + plane->crtc = crtc; + plane->fb = fb; + fb = NULL; + } else { + plane->old_fb = NULL; + } + +out: + if (fb) + drm_framebuffer_unreference(fb); + if (plane->old_fb) + drm_framebuffer_unreference(plane->old_fb); + plane->old_fb = NULL; + + return ret; +} + +static int setplane_internal(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int32_t crtc_x, int32_t crtc_y, + uint32_t crtc_w, uint32_t crtc_h, + /* src_{x,y,w,h} values are 16.16 fixed point */ + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + int ret; + + drm_modeset_lock_all(plane->dev); + ret = __setplane_internal(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); + drm_modeset_unlock_all(plane->dev); + + return ret; +} + +int drm_mode_setplane(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_set_plane *plane_req = data; + struct drm_plane *plane; + struct drm_crtc *crtc = NULL; + struct drm_framebuffer *fb = NULL; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + /* + * First, find the plane, crtc, and fb objects. If not available, + * we don't bother to call the driver. + */ + plane = drm_plane_find(dev, plane_req->plane_id); + if (!plane) { + DRM_DEBUG_KMS("Unknown plane ID %d\n", + plane_req->plane_id); + return -ENOENT; + } + + if (plane_req->fb_id) { + fb = drm_framebuffer_lookup(dev, plane_req->fb_id); + if (!fb) { + DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", + plane_req->fb_id); + return -ENOENT; + } + + crtc = drm_crtc_find(dev, plane_req->crtc_id); + if (!crtc) { + DRM_DEBUG_KMS("Unknown crtc ID %d\n", + plane_req->crtc_id); + return -ENOENT; + } + } + + /* + * setplane_internal will take care of deref'ing either the old or new + * framebuffer depending on success. + */ + return setplane_internal(plane, crtc, fb, + plane_req->crtc_x, plane_req->crtc_y, + plane_req->crtc_w, plane_req->crtc_h, + plane_req->src_x, plane_req->src_y, + plane_req->src_w, plane_req->src_h); +} + +static int drm_mode_cursor_universal(struct drm_crtc *crtc, + struct drm_mode_cursor2 *req, + struct drm_file *file_priv) +{ + struct drm_device *dev = crtc->dev; + struct drm_framebuffer *fb = NULL; + struct drm_mode_fb_cmd2 fbreq = { + .width = req->width, + .height = req->height, + .pixel_format = DRM_FORMAT_ARGB8888, + .pitches = { req->width * 4 }, + .handles = { req->handle }, + }; + int32_t crtc_x, crtc_y; + uint32_t crtc_w = 0, crtc_h = 0; + uint32_t src_w = 0, src_h = 0; + int ret = 0; + + BUG_ON(!crtc->cursor); + WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); + + /* + * Obtain fb we'll be using (either new or existing) and take an extra + * reference to it if fb != null. setplane will take care of dropping + * the reference if the plane update fails. + */ + if (req->flags & DRM_MODE_CURSOR_BO) { + if (req->handle) { + fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv); + if (IS_ERR(fb)) { + DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); + return PTR_ERR(fb); + } + fb->hot_x = req->hot_x; + fb->hot_y = req->hot_y; + } else { + fb = NULL; + } + } else { + fb = crtc->cursor->fb; + if (fb) + drm_framebuffer_reference(fb); + } + + if (req->flags & DRM_MODE_CURSOR_MOVE) { + crtc_x = req->x; + crtc_y = req->y; + } else { + crtc_x = crtc->cursor_x; + crtc_y = crtc->cursor_y; + } + + if (fb) { + crtc_w = fb->width; + crtc_h = fb->height; + src_w = fb->width << 16; + src_h = fb->height << 16; + } + + /* + * setplane_internal will take care of deref'ing either the old or new + * framebuffer depending on success. + */ + ret = __setplane_internal(crtc->cursor, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + 0, 0, src_w, src_h); + + /* Update successful; save new cursor position, if necessary */ + if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { + crtc->cursor_x = req->x; + crtc->cursor_y = req->y; + } + + return ret; +} + +static int drm_mode_cursor_common(struct drm_device *dev, + struct drm_mode_cursor2 *req, + struct drm_file *file_priv) +{ + struct drm_crtc *crtc; + int ret = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) + return -EINVAL; + + crtc = drm_crtc_find(dev, req->crtc_id); + if (!crtc) { + DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); + return -ENOENT; + } + + /* + * If this crtc has a universal cursor plane, call that plane's update + * handler rather than using legacy cursor handlers. + */ + drm_modeset_lock_crtc(crtc, crtc->cursor); + if (crtc->cursor) { + ret = drm_mode_cursor_universal(crtc, req, file_priv); + goto out; + } + + if (req->flags & DRM_MODE_CURSOR_BO) { + if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { + ret = -ENXIO; + goto out; + } + /* Turns off the cursor if handle is 0 */ + if (crtc->funcs->cursor_set2) + ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, + req->width, req->height, req->hot_x, req->hot_y); + else + ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, + req->width, req->height); + } + + if (req->flags & DRM_MODE_CURSOR_MOVE) { + if (crtc->funcs->cursor_move) { + ret = crtc->funcs->cursor_move(crtc, req->x, req->y); + } else { + ret = -EFAULT; + goto out; + } + } +out: + drm_modeset_unlock_crtc(crtc); + + return ret; + +} + + +int drm_mode_cursor_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_cursor *req = data; + struct drm_mode_cursor2 new_req; + + memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); + new_req.hot_x = new_req.hot_y = 0; + + return drm_mode_cursor_common(dev, &new_req, file_priv); +} + +/* + * Set the cursor configuration based on user request. This implements the 2nd + * version of the cursor ioctl, which allows userspace to additionally specify + * the hotspot of the pointer. + */ +int drm_mode_cursor2_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_cursor2 *req = data; + + return drm_mode_cursor_common(dev, req, file_priv); +} + +int drm_mode_page_flip_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_crtc_page_flip_target *page_flip = data; + struct drm_crtc *crtc; + struct drm_framebuffer *fb = NULL; + struct drm_pending_vblank_event *e = NULL; + u32 target_vblank = page_flip->sequence; + int ret = -EINVAL; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS) + return -EINVAL; + + if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) + return -EINVAL; + + /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags + * can be specified + */ + if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET) + return -EINVAL; + + if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) + return -EINVAL; + + crtc = drm_crtc_find(dev, page_flip->crtc_id); + if (!crtc) + return -ENOENT; + + drm_modeset_lock_crtc(crtc, crtc->primary); + if (crtc->primary->fb == NULL) { + /* The framebuffer is currently unbound, presumably + * due to a hotplug event, that userspace has not + * yet discovered. + */ + ret = -EBUSY; + goto out; + } + + if (crtc->funcs->page_flip == NULL) + goto out; + + fb = drm_framebuffer_lookup(dev, page_flip->fb_id); + if (!fb) { + ret = -ENOENT; + goto out; + } + + if (crtc->state) { + const struct drm_plane_state *state = crtc->primary->state; + + ret = drm_framebuffer_check_src_coords(state->src_x, + state->src_y, + state->src_w, + state->src_h, + fb); + } else { + ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); + } + if (ret) + goto out; + + if (crtc->primary->fb->pixel_format != fb->pixel_format) { + DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); + ret = -EINVAL; + goto out; + } + + if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { + e = kzalloc(sizeof *e, GFP_KERNEL); + if (!e) { + ret = -ENOMEM; + goto out; + } + e->event.base.type = DRM_EVENT_FLIP_COMPLETE; + e->event.base.length = sizeof(e->event); + e->event.user_data = page_flip->user_data; + ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); + if (ret) { + kfree(e); + goto out; + } + } + + crtc->primary->old_fb = crtc->primary->fb; + if (crtc->funcs->page_flip_target) { + u32 current_vblank; + int r; + + r = drm_crtc_vblank_get(crtc); + if (r) + return r; + + current_vblank = drm_crtc_vblank_count(crtc); + + switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) { + case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE: + if ((int)(target_vblank - current_vblank) > 1) { + DRM_DEBUG("Invalid absolute flip target %u, " + "must be <= %u\n", target_vblank, + current_vblank + 1); + drm_crtc_vblank_put(crtc); + return -EINVAL; + } + break; + case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE: + if (target_vblank != 0 && target_vblank != 1) { + DRM_DEBUG("Invalid relative flip target %u, " + "must be 0 or 1\n", target_vblank); + drm_crtc_vblank_put(crtc); + return -EINVAL; + } + target_vblank += current_vblank; + break; + default: + target_vblank = current_vblank + + !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC); + break; + } + } else if (crtc->funcs->page_flip == NULL || + (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) { + return -EINVAL; + } + + if (crtc->funcs->page_flip_target) + ret = crtc->funcs->page_flip_target(crtc, fb, e, + page_flip->flags, + target_vblank); + else + ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); + if (ret) { + if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) + drm_event_cancel_free(dev, &e->base); + /* Keep the old fb, don't unref it. */ + crtc->primary->old_fb = NULL; + } else { + crtc->primary->fb = fb; + /* Unref only the old framebuffer. */ + fb = NULL; + } + +out: + if (ret && crtc->funcs->page_flip_target) + drm_crtc_vblank_put(crtc); + if (crtc->primary->old_fb) + drm_framebuffer_unreference(crtc->primary->old_fb); + crtc->primary->old_fb = NULL; + drm_modeset_unlock_crtc(crtc); + + return ret; +} 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, DRM_DEBUG("\n"); dev = drm_dev_alloc(driver, &platdev->dev); - if (!dev) - return -ENOMEM; + if (IS_ERR(dev)) + return PTR_ERR(dev); dev->platformdev = platdev; 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 @@ #include <linux/export.h> #include <drm/drm_sysfs.h> -#include <drm/drm_core.h> #include <drm/drmP.h> #include "drm_internal.h" @@ -37,12 +36,7 @@ static char *drm_devnode(struct device *dev, umode_t *mode) return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); } -static CLASS_ATTR_STRING(version, S_IRUGO, - CORE_NAME " " - __stringify(CORE_MAJOR) "." - __stringify(CORE_MINOR) "." - __stringify(CORE_PATCHLEVEL) " " - CORE_DATE); +static CLASS_ATTR_STRING(version, S_IRUGO, "drm 1.1.0 20060810"); /** * 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 @@ #include <drm/drmP.h> #include <drm/drm_mm.h> #include <drm/drm_vma_manager.h> -#include <linux/fs.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/rbtree.h> @@ -252,9 +251,9 @@ EXPORT_SYMBOL(drm_vma_offset_remove); /** * drm_vma_node_allow - Add open-file to list of allowed users * @node: Node to modify - * @filp: Open file to add + * @tag: Tag of file to remove * - * Add @filp to the list of allowed open-files for this node. If @filp is + * Add @tag to the list of allowed open-files for this node. If @tag is * already on this list, the ref-count is incremented. * * The list of allowed-users is preserved across drm_vma_offset_add() and @@ -269,7 +268,7 @@ EXPORT_SYMBOL(drm_vma_offset_remove); * RETURNS: * 0 on success, negative error code on internal failure (out-of-mem) */ -int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp) +int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag) { struct rb_node **iter; struct rb_node *parent = NULL; @@ -290,10 +289,10 @@ int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp) parent = *iter; entry = rb_entry(*iter, struct drm_vma_offset_file, vm_rb); - if (filp == entry->vm_filp) { + if (tag == entry->vm_tag) { entry->vm_count++; goto unlock; - } else if (filp > entry->vm_filp) { + } else if (tag > entry->vm_tag) { iter = &(*iter)->rb_right; } else { iter = &(*iter)->rb_left; @@ -305,7 +304,7 @@ int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp) goto unlock; } - new->vm_filp = filp; + new->vm_tag = tag; new->vm_count = 1; rb_link_node(&new->vm_rb, parent, iter); rb_insert_color(&new->vm_rb, &node->vm_files); @@ -321,17 +320,18 @@ EXPORT_SYMBOL(drm_vma_node_allow); /** * drm_vma_node_revoke - Remove open-file from list of allowed users * @node: Node to modify - * @filp: Open file to remove + * @tag: Tag of file to remove * - * Decrement the ref-count of @filp in the list of allowed open-files on @node. - * If the ref-count drops to zero, remove @filp from the list. You must call - * this once for every drm_vma_node_allow() on @filp. + * Decrement the ref-count of @tag in the list of allowed open-files on @node. + * If the ref-count drops to zero, remove @tag from the list. You must call + * this once for every drm_vma_node_allow() on @tag. * * This is locked against concurrent access internally. * - * If @filp is not on the list, nothing is done. + * If @tag is not on the list, nothing is done. */ -void drm_vma_node_revoke(struct drm_vma_offset_node *node, struct file *filp) +void drm_vma_node_revoke(struct drm_vma_offset_node *node, + struct drm_file *tag) { struct drm_vma_offset_file *entry; struct rb_node *iter; @@ -341,13 +341,13 @@ void drm_vma_node_revoke(struct drm_vma_offset_node *node, struct file *filp) iter = node->vm_files.rb_node; while (likely(iter)) { entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb); - if (filp == entry->vm_filp) { + if (tag == entry->vm_tag) { if (!--entry->vm_count) { rb_erase(&entry->vm_rb, &node->vm_files); kfree(entry); } break; - } else if (filp > entry->vm_filp) { + } else if (tag > entry->vm_tag) { iter = iter->rb_right; } else { iter = iter->rb_left; @@ -361,9 +361,9 @@ EXPORT_SYMBOL(drm_vma_node_revoke); /** * drm_vma_node_is_allowed - Check whether an open-file is granted access * @node: Node to check - * @filp: Open-file to check for + * @tag: Tag of file to remove * - * Search the list in @node whether @filp is currently on the list of allowed + * Search the list in @node whether @tag is currently on the list of allowed * open-files (see drm_vma_node_allow()). * * This is locked against concurrent access internally. @@ -372,7 +372,7 @@ EXPORT_SYMBOL(drm_vma_node_revoke); * true iff @filp is on the list */ bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, - struct file *filp) + struct drm_file *tag) { struct drm_vma_offset_file *entry; struct rb_node *iter; @@ -382,9 +382,9 @@ bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, iter = node->vm_files.rb_node; while (likely(iter)) { entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb); - if (filp == entry->vm_filp) + if (tag == entry->vm_tag) break; - else if (filp > entry->vm_filp) + else if (tag > entry->vm_tag) iter = iter->rb_right; else 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) int ret; drm = drm_dev_alloc(&etnaviv_drm_driver, dev); - if (!drm) - return -ENOMEM; + if (IS_ERR(drm)) + return PTR_ERR(drm); priv = kzalloc(sizeof(*priv), GFP_KERNEL); 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) fsl_dev->tcon = fsl_tcon_init(dev); drm = drm_dev_alloc(driver, dev); - if (!drm) { - ret = -ENOMEM; + if (IS_ERR(drm)) { + ret = PTR_ERR(drm); goto disable_pix_clk; } 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) int ret; drm_dev = drm_dev_alloc(driver, dev); - if (!drm_dev) - return -ENOMEM; + if (IS_ERR(drm_dev)) + return PTR_ERR(drm_dev); drm_dev->platformdev = to_platform_device(dev); 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) int ret; drm = drm_dev_alloc(&mtk_drm_driver, dev); - if (!drm) - return -ENOMEM; + if (IS_ERR(drm)) + return PTR_ERR(drm); drm->dev_private = private; 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 { struct mgag200_bo *mgabo = mgag200_bo(bo); - return drm_vma_node_verify_access(&mgabo->gem.vma_node, filp); + return drm_vma_node_verify_access(&mgabo->gem.vma_node, + filp->private_data); } 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) int ret; ddev = drm_dev_alloc(drv, dev); - if (!ddev) { + if (IS_ERR(ddev)) { dev_err(dev, "failed to allocate drm_device\n"); - return -ENOMEM; + return PTR_ERR(ddev); } 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) { struct nouveau_bo *nvbo = nouveau_bo(bo); - return drm_vma_node_verify_access(&nvbo->gem.vma_node, filp); + return drm_vma_node_verify_access(&nvbo->gem.vma_node, + filp->private_data); } 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, goto err_free; drm = drm_dev_alloc(&driver_platform, &pdev->dev); - if (!drm) { - err = -ENOMEM; + if (IS_ERR(drm)) { + err = PTR_ERR(drm); goto err_free; } 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) { struct qxl_bo *qbo = to_qxl_bo(bo); - return drm_vma_node_verify_access(&qbo->gem_base.vma_node, filp); + return drm_vma_node_verify_access(&qbo->gem_base.vma_node, + filp->private_data); } 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) if (radeon_ttm_tt_has_userptr(bo->ttm)) return -EPERM; - return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp); + return drm_vma_node_verify_access(&rbo->gem_base.vma_node, + filp->private_data); } 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) rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data; ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev); - if (!ddev) - return -ENOMEM; + if (IS_ERR(ddev)) + return PTR_ERR(ddev); rcdu->ddev = ddev; 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) int ret; drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev); - if (!drm_dev) - return -ENOMEM; + if (IS_ERR(drm_dev)) + return PTR_ERR(drm_dev); dev_set_drvdata(dev, drm_dev); 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) int ret; ddev = drm_dev_alloc(&sti_driver, dev); - if (!ddev) - return -ENOMEM; + if (IS_ERR(ddev)) + return PTR_ERR(ddev); ddev->platformdev = to_platform_device(dev); 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) int ret; drm = drm_dev_alloc(&sun4i_drv_driver, dev); - if (!drm) - return -ENOMEM; + if (IS_ERR(drm)) + return PTR_ERR(drm); drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); 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) int err; drm = drm_dev_alloc(driver, &dev->dev); - if (!drm) - return -ENOMEM; + if (IS_ERR(drm)) + return PTR_ERR(drm); dev_set_drvdata(&dev->dev, drm); 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 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "drm_flip_work.h" -#include <drm/drm_plane_helper.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc.h> +#include <drm/drm_flip_work.h> +#include <drm/drm_plane_helper.h> #include "tilcdc_drv.h" #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, int r; dev = drm_dev_alloc(&driver, &interface->dev); - if (!dev) - return -ENOMEM; + if (IS_ERR(dev)) + return PTR_ERR(dev); r = drm_dev_register(dev, (unsigned long)udev); 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) return -ENOMEM; drm = drm_dev_alloc(&vc4_drm_driver, dev); - if (!drm) - return -ENOMEM; + if (IS_ERR(drm)) + return PTR_ERR(drm); platform_set_drvdata(pdev, drm); vc4->dev = drm; 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) int ret; vgem_device = drm_dev_alloc(&vgem_driver, NULL); - if (!vgem_device) { - ret = -ENOMEM; + if (IS_ERR(vgem_device)) { + ret = PTR_ERR(vgem_device); goto out; } 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) int ret; dev = drm_dev_alloc(driver, &vdev->dev); - if (!dev) - return -ENOMEM; + if (IS_ERR(dev)) + return PTR_ERR(dev); dev->virtdev = vdev; vdev->priv = dev; |