diff options
130 files changed, 2307 insertions, 974 deletions
diff --git a/Documentation/devicetree/bindings/display/zte,vou.txt b/Documentation/devicetree/bindings/display/zte,vou.txt index 740e5bd2e4f7..9c356284232b 100644 --- a/Documentation/devicetree/bindings/display/zte,vou.txt +++ b/Documentation/devicetree/bindings/display/zte,vou.txt @@ -49,6 +49,15 @@ Required properties: "osc_clk" "xclk" +* TV Encoder output device + +Required properties: + - compatible: should be "zte,zx296718-tvenc" + - reg: Physical base address and length of the TVENC device IO region + - zte,tvenc-power-control: the phandle to SYSCTRL block followed by two + integer cells. The first cell is the offset of SYSCTRL register used + to control TV Encoder DAC power, and the second cell is the bit mask. + Example: vou: vou@1440000 { @@ -81,4 +90,10 @@ vou: vou@1440000 { <&topcrm HDMI_XCLK>; clock-names = "osc_cec", "osc_clk", "xclk"; }; + + tvenc: tvenc@2000 { + compatible = "zte,zx296718-tvenc"; + reg = <0x2000 0x1000>; + zte,tvenc-power-control = <&sysctrl 0x170 0x10>; + }; }; diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 0c9abdc0ee31..4d4068855ec4 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -48,11 +48,17 @@ CRTC Abstraction ================ .. kernel-doc:: drivers/gpu/drm/drm_crtc.c - :export: + :doc: overview + +CRTC Functions Reference +-------------------------------- .. kernel-doc:: include/drm/drm_crtc.h :internal: +.. kernel-doc:: drivers/gpu/drm/drm_crtc.c + :export: + Frame Buffer Abstraction ======================== diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index a1bfc098ea10..d1f1f456f5c4 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -28,6 +28,7 @@ EXPORT_TRACEPOINT_SYMBOL(dma_fence_annotate_wait_on); EXPORT_TRACEPOINT_SYMBOL(dma_fence_emit); +EXPORT_TRACEPOINT_SYMBOL(dma_fence_enable_signal); /* * fence context counter: each execution context should have its own diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 147ce0ebf092..94a64e3bc682 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1148,7 +1148,6 @@ int amdgpu_debugfs_fence_init(struct amdgpu_device *adev); #if defined(CONFIG_DEBUG_FS) int amdgpu_debugfs_init(struct drm_minor *minor); -void amdgpu_debugfs_cleanup(struct drm_minor *minor); #endif int amdgpu_debugfs_firmware_init(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index c6ce0c586d59..944ba0d3874a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1895,8 +1895,6 @@ failed: return r; } -static void amdgpu_debugfs_remove_files(struct amdgpu_device *adev); - /** * amdgpu_device_fini - tear down the driver * @@ -1936,7 +1934,6 @@ void amdgpu_device_fini(struct amdgpu_device *adev) if (adev->asic_type >= CHIP_BONAIRE) amdgpu_doorbell_fini(adev); amdgpu_debugfs_regs_cleanup(adev); - amdgpu_debugfs_remove_files(adev); } @@ -2553,19 +2550,6 @@ int amdgpu_debugfs_add_files(struct amdgpu_device *adev, return 0; } -static void amdgpu_debugfs_remove_files(struct amdgpu_device *adev) -{ -#if defined(CONFIG_DEBUG_FS) - unsigned i; - - for (i = 0; i < adev->debugfs_count; i++) { - drm_debugfs_remove_files(adev->debugfs[i].files, - adev->debugfs[i].num_files, - adev->ddev->primary); - } -#endif -} - #if defined(CONFIG_DEBUG_FS) static ssize_t amdgpu_debugfs_regs_read(struct file *f, char __user *buf, @@ -3205,10 +3189,6 @@ int amdgpu_debugfs_init(struct drm_minor *minor) { return 0; } - -void amdgpu_debugfs_cleanup(struct drm_minor *minor) -{ -} #else static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 521c9790d7d6..75fc376ba735 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -682,7 +682,6 @@ static struct drm_driver kms_driver = { DRIVER_USE_AGP | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_MODESET, - .dev_priv_size = 0, .load = amdgpu_driver_load_kms, .open = amdgpu_driver_open_kms, .preclose = amdgpu_driver_preclose_kms, @@ -697,7 +696,6 @@ static struct drm_driver kms_driver = { .get_scanout_position = amdgpu_get_crtc_scanoutpos, #if defined(CONFIG_DEBUG_FS) .debugfs_init = amdgpu_debugfs_init, - .debugfs_cleanup = amdgpu_debugfs_cleanup, #endif .irq_preinstall = amdgpu_irq_preinstall, .irq_postinstall = amdgpu_irq_postinstall, diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index e5f4f4a6546d..a2e5b04cdee3 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -255,12 +255,6 @@ static int hdlcd_debugfs_init(struct drm_minor *minor) return drm_debugfs_create_files(hdlcd_debugfs_list, ARRAY_SIZE(hdlcd_debugfs_list), minor->debugfs_root, minor); } - -static void hdlcd_debugfs_cleanup(struct drm_minor *minor) -{ - drm_debugfs_remove_files(hdlcd_debugfs_list, - ARRAY_SIZE(hdlcd_debugfs_list), minor); -} #endif static const struct file_operations fops = { @@ -303,7 +297,6 @@ static struct drm_driver hdlcd_driver = { .gem_prime_mmap = drm_gem_cma_prime_mmap, #ifdef CONFIG_DEBUG_FS .debugfs_init = hdlcd_debugfs_init, - .debugfs_cleanup = hdlcd_debugfs_cleanup, #endif .fops = &fops, .name = "hdlcd", diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 32f746e31379..99fb0ab39191 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -22,7 +22,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> -#include <drm/drm_fb_helper.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_of.h> @@ -256,6 +255,60 @@ static const struct of_device_id malidp_drm_of_match[] = { }; MODULE_DEVICE_TABLE(of, malidp_drm_of_match); +static bool malidp_is_compatible_hw_id(struct malidp_hw_device *hwdev, + const struct of_device_id *dev_id) +{ + u32 core_id; + const char *compatstr_dp500 = "arm,mali-dp500"; + bool is_dp500; + bool dt_is_dp500; + + /* + * The DP500 CORE_ID register is in a different location, so check it + * first. If the product id field matches, then this is DP500, otherwise + * check the DP550/650 CORE_ID register. + */ + core_id = malidp_hw_read(hwdev, MALIDP500_DC_BASE + MALIDP_DE_CORE_ID); + /* Offset 0x18 will never read 0x500 on products other than DP500. */ + is_dp500 = (MALIDP_PRODUCT_ID(core_id) == 0x500); + dt_is_dp500 = strnstr(dev_id->compatible, compatstr_dp500, + sizeof(dev_id->compatible)) != NULL; + if (is_dp500 != dt_is_dp500) { + DRM_ERROR("Device-tree expects %s, but hardware %s DP500.\n", + dev_id->compatible, is_dp500 ? "is" : "is not"); + return false; + } else if (!dt_is_dp500) { + u16 product_id; + char buf[32]; + + core_id = malidp_hw_read(hwdev, + MALIDP550_DC_BASE + MALIDP_DE_CORE_ID); + product_id = MALIDP_PRODUCT_ID(core_id); + snprintf(buf, sizeof(buf), "arm,mali-dp%X", product_id); + if (!strnstr(dev_id->compatible, buf, + sizeof(dev_id->compatible))) { + DRM_ERROR("Device-tree expects %s, but hardware is DP%03X.\n", + dev_id->compatible, product_id); + return false; + } + } + return true; +} + +static bool malidp_has_sufficient_address_space(const struct resource *res, + const struct of_device_id *dev_id) +{ + resource_size_t res_size = resource_size(res); + const char *compatstr_dp500 = "arm,mali-dp500"; + + if (!strnstr(dev_id->compatible, compatstr_dp500, + sizeof(dev_id->compatible))) + return res_size >= MALIDP550_ADDR_SPACE_SIZE; + else if (res_size < MALIDP500_ADDR_SPACE_SIZE) + return false; + return true; +} + #define MAX_OUTPUT_CHANNELS 3 static int malidp_bind(struct device *dev) @@ -266,6 +319,7 @@ static int malidp_bind(struct device *dev) struct malidp_drm *malidp; struct malidp_hw_device *hwdev; struct platform_device *pdev = to_platform_device(dev); + struct of_device_id const *dev_id; /* number of lines for the R, G and B output */ u8 output_width[MAX_OUTPUT_CHANNELS]; int ret = 0, i; @@ -286,7 +340,6 @@ static int malidp_bind(struct device *dev) memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev)); malidp->dev = hwdev; - INIT_LIST_HEAD(&malidp->event_list); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hwdev->regs = devm_ioremap_resource(dev, res); @@ -329,6 +382,23 @@ static int malidp_bind(struct device *dev) clk_prepare_enable(hwdev->aclk); clk_prepare_enable(hwdev->mclk); + dev_id = of_match_device(malidp_drm_of_match, dev); + if (!dev_id) { + ret = -EINVAL; + goto query_hw_fail; + } + + if (!malidp_has_sufficient_address_space(res, dev_id)) { + DRM_ERROR("Insufficient address space in device-tree.\n"); + ret = -EINVAL; + goto query_hw_fail; + } + + if (!malidp_is_compatible_hw_id(hwdev, dev_id)) { + ret = -EINVAL; + goto query_hw_fail; + } + ret = hwdev->query_hw(hwdev); if (ret) { DRM_ERROR("Invalid HW configuration\n"); diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index 9fc8a2e405e4..dbc617c6e4ef 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -15,12 +15,12 @@ #include <linux/mutex.h> #include <linux/wait.h> +#include <drm/drmP.h> #include "malidp_hw.h" struct malidp_drm { struct malidp_hw_device *dev; struct drm_fbdev_cma *fbdev; - struct list_head event_list; struct drm_crtc crtc; wait_queue_head_t wq; atomic_t config_valid; diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index 4bdf531f7844..488aedf5b58d 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -21,7 +21,7 @@ #include "malidp_drv.h" #include "malidp_hw.h" -static const struct malidp_input_format malidp500_de_formats[] = { +static const struct malidp_format_id malidp500_de_formats[] = { /* fourcc, layers supporting the format, internal id */ { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 0 }, { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 1 }, @@ -69,21 +69,21 @@ static const struct malidp_input_format malidp500_de_formats[] = { { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) }, \ { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) } -static const struct malidp_input_format malidp550_de_formats[] = { +static const struct malidp_format_id malidp550_de_formats[] = { MALIDP_COMMON_FORMATS, }; static const struct malidp_layer malidp500_layers[] = { - { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE }, - { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE }, - { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE }, + { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0 }, + { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE }, + { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE }, }; static const struct malidp_layer malidp550_layers[] = { - { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE }, - { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE }, - { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE }, - { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE }, + { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0 }, + { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE }, + { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0 }, + { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, 0 }, }; #define MALIDP_DE_DEFAULT_PREFETCH_START 5 @@ -436,8 +436,8 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .irq_mask = MALIDP500_DE_IRQ_CONF_VALID, .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID, }, - .input_formats = malidp500_de_formats, - .n_input_formats = ARRAY_SIZE(malidp500_de_formats), + .pixel_formats = malidp500_de_formats, + .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats), .bus_align_bytes = 8, }, .query_hw = malidp500_query_hw, @@ -447,6 +447,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .set_config_valid = malidp500_set_config_valid, .modeset = malidp500_modeset, .rotmem_required = malidp500_rotmem_required, + .features = MALIDP_DEVICE_LV_HAS_3_STRIDES, }, [MALIDP_550] = { .map = { @@ -469,8 +470,8 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .irq_mask = MALIDP550_DC_IRQ_CONF_VALID, .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, }, - .input_formats = malidp550_de_formats, - .n_input_formats = ARRAY_SIZE(malidp550_de_formats), + .pixel_formats = malidp550_de_formats, + .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats), .bus_align_bytes = 8, }, .query_hw = malidp550_query_hw, @@ -480,6 +481,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .set_config_valid = malidp550_set_config_valid, .modeset = malidp550_modeset, .rotmem_required = malidp550_rotmem_required, + .features = 0, }, [MALIDP_650] = { .map = { @@ -503,8 +505,8 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .irq_mask = MALIDP550_DC_IRQ_CONF_VALID, .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, }, - .input_formats = malidp550_de_formats, - .n_input_formats = ARRAY_SIZE(malidp550_de_formats), + .pixel_formats = malidp550_de_formats, + .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats), .bus_align_bytes = 16, }, .query_hw = malidp650_query_hw, @@ -514,6 +516,7 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .set_config_valid = malidp550_set_config_valid, .modeset = malidp550_modeset, .rotmem_required = malidp550_rotmem_required, + .features = 0, }, }; @@ -522,10 +525,10 @@ u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map, { unsigned int i; - for (i = 0; i < map->n_input_formats; i++) { - if (((map->input_formats[i].layer & layer_id) == layer_id) && - (map->input_formats[i].format == format)) - return map->input_formats[i].id; + for (i = 0; i < map->n_pixel_formats; i++) { + if (((map->pixel_formats[i].layer & layer_id) == layer_id) && + (map->pixel_formats[i].format == format)) + return map->pixel_formats[i].id; } return MALIDP_INVALID_FORMAT_ID; diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index 087e1202db3d..00974b59407d 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -35,7 +35,7 @@ enum { DE_SMART = BIT(4), }; -struct malidp_input_format { +struct malidp_format_id { u32 format; /* DRM fourcc */ u8 layer; /* bitmask of layers supporting it */ u8 id; /* used internally */ @@ -58,6 +58,7 @@ struct malidp_layer { u16 id; /* layer ID */ u16 base; /* address offset for the register bank */ u16 ptr; /* address offset for the pointer register */ + u16 stride_offset; /* Offset to the first stride register. */ }; /* regmap features */ @@ -85,14 +86,18 @@ struct malidp_hw_regmap { const struct malidp_irq_map se_irq_map; const struct malidp_irq_map dc_irq_map; - /* list of supported input formats for each layer */ - const struct malidp_input_format *input_formats; - const u8 n_input_formats; + /* list of supported pixel formats for each layer */ + const struct malidp_format_id *pixel_formats; + const u8 n_pixel_formats; /* pitch alignment requirement in bytes */ const u8 bus_align_bytes; }; +/* device features */ +/* Unlike DP550/650, DP500 has 3 stride registers in its video layer. */ +#define MALIDP_DEVICE_LV_HAS_3_STRIDES BIT(0) + struct malidp_hw_device { const struct malidp_hw_regmap map; void __iomem *regs; diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index eff2fe47e26a..414aada10fe5 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -11,6 +11,7 @@ */ #include <drm/drmP.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> @@ -36,7 +37,6 @@ #define LAYER_V_VAL(x) (((x) & 0x1fff) << 16) #define MALIDP_LAYER_COMP_SIZE 0x010 #define MALIDP_LAYER_OFFSET 0x014 -#define MALIDP_LAYER_STRIDE 0x018 /* * This 4-entry look-up-table is used to determine the full 8-bit alpha value @@ -67,13 +67,14 @@ drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane) return NULL; state = kmalloc(sizeof(*state), GFP_KERNEL); - if (state) { - m_state = to_malidp_plane_state(plane->state); - __drm_atomic_helper_plane_duplicate_state(plane, &state->base); - state->rotmem_size = m_state->rotmem_size; - state->format = m_state->format; - state->n_planes = m_state->n_planes; - } + if (!state) + return NULL; + + m_state = to_malidp_plane_state(plane->state); + __drm_atomic_helper_plane_duplicate_state(plane, &state->base); + state->rotmem_size = m_state->rotmem_size; + state->format = m_state->format; + state->n_planes = m_state->n_planes; return &state->base; } @@ -102,8 +103,10 @@ static int malidp_de_plane_check(struct drm_plane *plane, { struct malidp_plane *mp = to_malidp_plane(plane); struct malidp_plane_state *ms = to_malidp_plane_state(state); + struct drm_crtc_state *crtc_state; struct drm_framebuffer *fb; - int i; + struct drm_rect clip = { 0 }; + int i, ret; u32 src_w, src_h; if (!state->crtc || !state->fb) @@ -131,8 +134,17 @@ static int malidp_de_plane_check(struct drm_plane *plane, if ((state->crtc_w > mp->hwdev->max_line_size) || (state->crtc_h > mp->hwdev->max_line_size) || (state->crtc_w < mp->hwdev->min_line_size) || - (state->crtc_h < mp->hwdev->min_line_size) || - (state->crtc_w != src_w) || (state->crtc_h != src_h)) + (state->crtc_h < mp->hwdev->min_line_size)) + return -EINVAL; + + /* + * DP550/650 video layers can accept 3 plane formats only if + * fb->pitches[1] == fb->pitches[2] since they don't have a + * third plane stride register. + */ + if (ms->n_planes == 3 && + !(mp->hwdev->features & MALIDP_DEVICE_LV_HAS_3_STRIDES) && + (state->fb->pitches[1] != state->fb->pitches[2])) return -EINVAL; /* packed RGB888 / BGR888 can't be rotated or flipped */ @@ -141,6 +153,16 @@ static int malidp_de_plane_check(struct drm_plane *plane, fb->format->format == DRM_FORMAT_BGR888)) return -EINVAL; + crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc); + clip.x2 = crtc_state->adjusted_mode.hdisplay; + clip.y2 = crtc_state->adjusted_mode.vdisplay; + ret = drm_plane_helper_check_state(state, &clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); + if (ret) + return ret; + ms->rotmem_size = 0; if (state->rotation & MALIDP_ROTATED_MASK) { int val; @@ -157,6 +179,25 @@ static int malidp_de_plane_check(struct drm_plane *plane, return 0; } +static void malidp_de_set_plane_pitches(struct malidp_plane *mp, + int num_planes, unsigned int pitches[3]) +{ + int i; + int num_strides = num_planes; + + if (!mp->layer->stride_offset) + return; + + if (num_planes == 3) + num_strides = (mp->hwdev->features & + MALIDP_DEVICE_LV_HAS_3_STRIDES) ? 3 : 2; + + for (i = 0; i < num_strides; ++i) + malidp_hw_write(mp->hwdev, pitches[i], + mp->layer->base + + mp->layer->stride_offset + i * 4); +} + static void malidp_de_plane_update(struct drm_plane *plane, struct drm_plane_state *old_state) { @@ -174,13 +215,8 @@ static void malidp_de_plane_update(struct drm_plane *plane, /* convert src values from Q16 fixed point to integer */ src_w = plane->state->src_w >> 16; src_h = plane->state->src_h >> 16; - if (plane->state->rotation & MALIDP_ROTATED_MASK) { - dest_w = plane->state->crtc_h; - dest_h = plane->state->crtc_w; - } else { - dest_w = plane->state->crtc_w; - dest_h = plane->state->crtc_h; - } + dest_w = plane->state->crtc_w; + dest_h = plane->state->crtc_h; malidp_hw_write(mp->hwdev, ms->format, mp->layer->base); @@ -189,11 +225,12 @@ static void malidp_de_plane_update(struct drm_plane *plane, ptr = mp->layer->ptr + (i << 4); obj = drm_fb_cma_get_gem_obj(plane->state->fb, i); + obj->paddr += plane->state->fb->offsets[i]; malidp_hw_write(mp->hwdev, lower_32_bits(obj->paddr), ptr); malidp_hw_write(mp->hwdev, upper_32_bits(obj->paddr), ptr + 4); - malidp_hw_write(mp->hwdev, plane->state->fb->pitches[i], - mp->layer->base + MALIDP_LAYER_STRIDE); } + malidp_de_set_plane_pitches(mp, ms->n_planes, + plane->state->fb->pitches); malidp_hw_write(mp->hwdev, LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h), mp->layer->base + MALIDP_LAYER_SIZE); @@ -211,11 +248,12 @@ static void malidp_de_plane_update(struct drm_plane *plane, /* setup the rotation and axis flip bits */ if (plane->state->rotation & DRM_ROTATE_MASK) - val = ilog2(plane->state->rotation & DRM_ROTATE_MASK) << LAYER_ROT_OFFSET; + val |= ilog2(plane->state->rotation & DRM_ROTATE_MASK) << + LAYER_ROT_OFFSET; if (plane->state->rotation & DRM_REFLECT_X) - val |= LAYER_V_FLIP; - if (plane->state->rotation & DRM_REFLECT_Y) val |= LAYER_H_FLIP; + if (plane->state->rotation & DRM_REFLECT_Y) + val |= LAYER_V_FLIP; /* * always enable pixel alpha blending until we have a way to change @@ -258,7 +296,7 @@ int malidp_de_planes_init(struct drm_device *drm) u32 *formats; int ret, i, j, n; - formats = kcalloc(map->n_input_formats, sizeof(*formats), GFP_KERNEL); + formats = kcalloc(map->n_pixel_formats, sizeof(*formats), GFP_KERNEL); if (!formats) { ret = -ENOMEM; goto cleanup; @@ -274,9 +312,9 @@ int malidp_de_planes_init(struct drm_device *drm) } /* build the list of DRM supported formats based on the map */ - for (n = 0, j = 0; j < map->n_input_formats; j++) { - if ((map->input_formats[j].layer & id) == id) - formats[n++] = map->input_formats[j].format; + for (n = 0, j = 0; j < map->n_pixel_formats; j++) { + if ((map->pixel_formats[j].layer & id) == id) + formats[n++] = map->pixel_formats[j].format; } plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY : diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h index 73fecb38f955..aff6d4a84e99 100644 --- a/drivers/gpu/drm/arm/malidp_regs.h +++ b/drivers/gpu/drm/arm/malidp_regs.h @@ -81,6 +81,10 @@ #define MALIDP_DE_SYNC_WIDTH 0x8 #define MALIDP_DE_HV_ACTIVE 0xc +/* Stride register offsets relative to Lx_BASE */ +#define MALIDP_DE_LG_STRIDE 0x18 +#define MALIDP_DE_LV_STRIDE0 0x18 + /* macros to set values into registers */ #define MALIDP_DE_H_FRONTPORCH(x) (((x) & 0xfff) << 0) #define MALIDP_DE_H_BACKPORCH(x) (((x) & 0x3ff) << 16) @@ -92,7 +96,10 @@ #define MALIDP_DE_H_ACTIVE(x) (((x) & 0x1fff) << 0) #define MALIDP_DE_V_ACTIVE(x) (((x) & 0x1fff) << 16) +#define MALIDP_PRODUCT_ID(__core_id) ((u32)(__core_id) >> 16) + /* register offsets and bits specific to DP500 */ +#define MALIDP500_ADDR_SPACE_SIZE 0x01000 #define MALIDP500_DC_BASE 0x00000 #define MALIDP500_DC_CONTROL 0x0000c #define MALIDP500_DC_CONFIG_REQ (1 << 17) @@ -125,6 +132,7 @@ #define MALIDP500_CONFIG_ID 0x00fd4 /* register offsets and bits specific to DP550/DP650 */ +#define MALIDP550_ADDR_SPACE_SIZE 0x10000 #define MALIDP550_DE_CONTROL 0x00010 #define MALIDP550_DE_LINE_COUNTER 0x00014 #define MALIDP550_DE_AXI_CONTROL 0x00018 diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index cbd0070265c9..0bf32d6ac39b 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -431,15 +431,8 @@ static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev) { struct atmel_hlcdc_dc *dc = dev->dev_private; - if (dc->fbdev) { + if (dc->fbdev) drm_fbdev_cma_hotplug_event(dc->fbdev); - } else { - dc->fbdev = drm_fbdev_cma_init(dev, 24, - dev->mode_config.num_crtc, - dev->mode_config.num_connector); - if (IS_ERR(dc->fbdev)) - dc->fbdev = NULL; - } } struct atmel_hlcdc_dc_commit { @@ -653,10 +646,13 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev) platform_set_drvdata(pdev, dev); - drm_kms_helper_poll_init(dev); + dc->fbdev = drm_fbdev_cma_init(dev, 24, + dev->mode_config.num_crtc, + dev->mode_config.num_connector); + if (IS_ERR(dc->fbdev)) + dc->fbdev = NULL; - /* force connectors detection */ - drm_helper_hpd_irq_event(dev); + drm_kms_helper_poll_init(dev); return 0; diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 4fda0717e789..9a9ec27d9e28 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -2060,7 +2060,9 @@ __dw_hdmi_probe(struct platform_device *pdev, hdmi->bridge.driver_private = hdmi; hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; +#ifdef CONFIG_OF hdmi->bridge.of_node = pdev->dev.of_node; +#endif ret = dw_hdmi_fb_registered(hdmi); if (ret) diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c index d621c8a4cf00..c89953449e96 100644 --- a/drivers/gpu/drm/drm_agpsupport.c +++ b/drivers/gpu/drm/drm_agpsupport.c @@ -421,6 +421,8 @@ struct drm_agp_head *drm_agp_init(struct drm_device *dev) head->base = head->agp_info.aper_base; return head; } +/* Only exported for i810.ko */ +EXPORT_SYMBOL(drm_agp_init); /** * drm_legacy_agp_clear - Clear AGP resource list diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 6414bcf7f41b..e5b738660d66 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -195,8 +195,8 @@ EXPORT_SYMBOL(drm_atomic_state_default_clear); * all locks. So someone else could sneak in and change the current modeset * configuration. Which means that all the state assembled in @state is no * longer an atomic update to the current state, but to some arbitrary earlier - * state. Which could break assumptions the driver's ->atomic_check likely - * relies on. + * state. Which could break assumptions the driver's + * &drm_mode_config_funcs.atomic_check likely relies on. * * Hence we must clear all cached state and completely start over, using this * function. @@ -456,11 +456,10 @@ drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc, * @property: the property to set * @val: the new property value * - * Use this instead of calling crtc->atomic_set_property directly. - * This function handles generic/core properties and calls out to - * driver's ->atomic_set_property() for driver properties. To ensure - * consistent behavior you must call this function rather than the - * driver hook directly. + * This function handles generic/core properties and calls out to driver's + * &drm_crtc_funcs.atomic_set_property for driver properties. To ensure + * consistent behavior you must call this function rather than the driver hook + * directly. * * RETURNS: * Zero on success, error code on failure @@ -532,10 +531,10 @@ EXPORT_SYMBOL(drm_atomic_crtc_set_property); * @property: the property to set * @val: return location for the property value * - * This function handles generic/core properties and calls out to - * driver's ->atomic_get_property() for driver properties. To ensure - * consistent behavior you must call this function rather than the - * driver hook directly. + * This function handles generic/core properties and calls out to driver's + * &drm_crtc_funcs.atomic_get_property for driver properties. To ensure + * consistent behavior you must call this function rather than the driver hook + * directly. * * RETURNS: * Zero on success, error code on failure @@ -716,11 +715,10 @@ EXPORT_SYMBOL(drm_atomic_get_plane_state); * @property: the property to set * @val: the new property value * - * Use this instead of calling plane->atomic_set_property directly. - * This function handles generic/core properties and calls out to - * driver's ->atomic_set_property() for driver properties. To ensure - * consistent behavior you must call this function rather than the - * driver hook directly. + * This function handles generic/core properties and calls out to driver's + * &drm_plane_funcs.atomic_set_property for driver properties. To ensure + * consistent behavior you must call this function rather than the driver hook + * directly. * * RETURNS: * Zero on success, error code on failure @@ -791,10 +789,10 @@ EXPORT_SYMBOL(drm_atomic_plane_set_property); * @property: the property to set * @val: return location for the property value * - * This function handles generic/core properties and calls out to - * driver's ->atomic_get_property() for driver properties. To ensure - * consistent behavior you must call this function rather than the - * driver hook directly. + * This function handles generic/core properties and calls out to driver's + * &drm_plane_funcs.atomic_get_property for driver properties. To ensure + * consistent behavior you must call this function rather than the driver hook + * directly. * * RETURNS: * Zero on success, error code on failure @@ -1057,11 +1055,10 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state); * @property: the property to set * @val: the new property value * - * Use this instead of calling connector->atomic_set_property directly. - * This function handles generic/core properties and calls out to - * driver's ->atomic_set_property() for driver properties. To ensure - * consistent behavior you must call this function rather than the - * driver hook directly. + * This function handles generic/core properties and calls out to driver's + * &drm_connector_funcs.atomic_set_property for driver properties. To ensure + * consistent behavior you must call this function rather than the driver hook + * directly. * * RETURNS: * Zero on success, error code on failure @@ -1136,10 +1133,10 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, * @property: the property to set * @val: return location for the property value * - * This function handles generic/core properties and calls out to - * driver's ->atomic_get_property() for driver properties. To ensure - * consistent behavior you must call this function rather than the - * driver hook directly. + * This function handles generic/core properties and calls out to driver's + * &drm_connector_funcs.atomic_get_property for driver properties. To ensure + * consistent behavior you must call this function rather than the driver hook + * directly. * * RETURNS: * Zero on success, error code on failure @@ -1312,12 +1309,11 @@ EXPORT_SYMBOL(drm_atomic_set_fb_for_plane); * implicit or explicit fencing. * * This function will not set the fence to the state if it was set - * via explicit fencing interfaces on the atomic ioctl. It will - * all drope the reference to the fence as we not storing it - * anywhere. - * - * Otherwise, if plane_state->fence is not set this function we - * just set it with the received implict fence. + * via explicit fencing interfaces on the atomic ioctl. In that case it will + * drop the reference to the fence as we are not storing it anywhere. + * Otherwise, if &drm_plane_state.fence is not set this function we just set it + * with the received implicit fence. In both cases this function consumes a + * reference for @fence. */ void drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, @@ -1616,7 +1612,7 @@ int drm_atomic_commit(struct drm_atomic_state *state) EXPORT_SYMBOL(drm_atomic_commit); /** - * drm_atomic_nonblocking_commit - atomic&nonblocking configuration commit + * drm_atomic_nonblocking_commit - atomic nonblocking commit * @state: atomic configuration to check * * Note that this function can return -EDEADLK if the driver needed to acquire @@ -1731,13 +1727,6 @@ int drm_atomic_debugfs_init(struct drm_minor *minor) ARRAY_SIZE(drm_atomic_debugfs_list), minor->debugfs_root, minor); } - -int drm_atomic_debugfs_cleanup(struct drm_minor *minor) -{ - return drm_debugfs_remove_files(drm_atomic_debugfs_list, - ARRAY_SIZE(drm_atomic_debugfs_list), - minor); -} #endif /* @@ -1829,10 +1818,10 @@ static int atomic_set_prop(struct drm_atomic_state *state, * @plane_mask: plane mask for planes that were updated. * @ret: return value, can be -EDEADLK for a retry. * - * Before doing an update plane->old_fb is set to plane->fb, - * but before dropping the locks old_fb needs to be set to NULL - * and plane->fb updated. This is a common operation for each - * atomic update, so this call is split off as a helper. + * Before doing an update &drm_plane.old_fb is set to &drm_plane.fb, but before + * dropping the locks old_fb needs to be set to NULL and plane->fb updated. This + * is a common operation for each atomic update, so this call is split off as a + * helper. */ void drm_atomic_clean_old_fb(struct drm_device *dev, unsigned plane_mask, @@ -1873,7 +1862,7 @@ EXPORT_SYMBOL(drm_atomic_clean_old_fb); * As a contrast, with implicit fencing the kernel keeps track of any * ongoing rendering, and automatically ensures that the atomic update waits * for any pending rendering to complete. For shared buffers represented with - * a &struct dma_buf this is tracked in &reservation_object structures. + * a &struct dma_buf this is tracked in &struct reservation_object. * Implicit syncing is how Linux traditionally worked (e.g. DRI2/3 on X.org), * whereas explicit fencing is what Android wants. * diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index b26e3419027e..9a08445a7a7a 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -458,22 +458,25 @@ mode_fixup(struct drm_atomic_state *state) * Check the state object to see if the requested state is physically possible. * This does all the crtc and connector related computations for an atomic * update and adds any additional connectors needed for full modesets and calls - * down into ->mode_fixup functions of the driver backend. - * - * crtc_state->mode_changed is set when the input mode is changed. - * crtc_state->connectors_changed is set when a connector is added or - * removed from the crtc. - * crtc_state->active_changed is set when crtc_state->active changes, - * which is used for dpms. + * down into &drm_crtc_helper_funcs.mode_fixup and + * &drm_encoder_helper_funcs.mode_fixup or + * &drm_encoder_helper_funcs.atomic_check functions of the driver backend. + * + * &drm_crtc_state.mode_changed is set when the input mode is changed. + * &drm_crtc_state.connectors_changed is set when a connector is added or + * removed from the crtc. &drm_crtc_state.active_changed is set when + * &drm_crtc_state.active changes, which is used for DPMS. * See also: drm_atomic_crtc_needs_modeset() * * IMPORTANT: * - * Drivers which set ->mode_changed (e.g. in their ->atomic_check hooks if a - * plane update can't be done without a full modeset) _must_ call this function - * afterwards after that change. It is permitted to call this function multiple - * times for the same update, e.g. when the ->atomic_check functions depend upon - * the adjusted dotclock for fifo space allocation and watermark computation. + * Drivers which set &drm_crtc_state.mode_changed (e.g. in their + * &drm_plane_helper_funcs.atomic_check hooks if a plane update can't be done + * without a full modeset) _must_ call this function afterwards after that + * change. It is permitted to call this function multiple times for the same + * update, e.g. when the &drm_crtc_helper_funcs.atomic_check functions depend + * upon the adjusted dotclock for fifo space allocation and watermark + * computation. * * RETURNS: * Zero for success or -errno @@ -584,9 +587,10 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset); * * Check the state object to see if the requested state is physically possible. * This does all the plane update related checks using by calling into the - * ->atomic_check hooks provided by the driver. + * &drm_crtc_helper_funcs.atomic_check and &drm_plane_helper_funcs.atomic_check + * hooks provided by the driver. * - * It also sets crtc_state->planes_changed to indicate that a crtc has + * It also sets &drm_crtc_state.planes_changed to indicate that a crtc has * updated planes. * * RETURNS: @@ -648,14 +652,15 @@ EXPORT_SYMBOL(drm_atomic_helper_check_planes); * Check the state object to see if the requested state is physically possible. * Only crtcs and planes have check callbacks, so for any additional (global) * checking that a driver needs it can simply wrap that around this function. - * Drivers without such needs can directly use this as their ->atomic_check() - * callback. + * Drivers without such needs can directly use this as their + * &drm_mode_config_funcs.atomic_check callback. * * This just wraps the two parts of the state checking for planes and modeset * state in the default order: First it calls drm_atomic_helper_check_modeset() * and then drm_atomic_helper_check_planes(). The assumption is that the - * ->atomic_check functions depend upon an updated adjusted_mode.clock to - * e.g. properly compute watermarks. + * @drm_plane_helper_funcs.atomic_check and @drm_crtc_helper_funcs.atomic_check + * functions depend upon an updated adjusted_mode.clock to e.g. properly compute + * watermarks. * * RETURNS: * Zero for success or -errno @@ -1125,8 +1130,8 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); * drm_atomic_helper_commit_tail - commit atomic update to hardware * @old_state: atomic state object with old state structures * - * This is the default implemenation for the ->atomic_commit_tail() hook of the - * &drm_mode_config_helper_funcs vtable. + * This is the default implementation for the + * &drm_mode_config_helper_funcs.atomic_commit_tail hook. * * Note that the default ordering of how the various stages are called is to * match the legacy modeset helper library closest. One peculiarity of that is @@ -1203,8 +1208,8 @@ static void commit_work(struct work_struct *work) * drm_atomic_helper_setup_commit() and related functions. * * Committing the actual hardware state is done through the - * ->atomic_commit_tail() callback of the &drm_mode_config_helper_funcs vtable, - * or it's default implementation drm_atomic_helper_commit_tail(). + * &drm_mode_config_helper_funcs.atomic_commit_tail callback, or it's default + * implementation drm_atomic_helper_commit_tail(). * * RETURNS: * Zero for success or -errno. @@ -1357,7 +1362,7 @@ static int stall_checks(struct drm_crtc *crtc, bool nonblock) return ret < 0 ? ret : 0; } -void release_crtc_commit(struct completion *completion) +static void release_crtc_commit(struct completion *completion) { struct drm_crtc_commit *commit = container_of(completion, typeof(*commit), @@ -1373,14 +1378,15 @@ void release_crtc_commit(struct completion *completion) * * This function prepares @state to be used by the atomic helper's support for * nonblocking commits. Drivers using the nonblocking commit infrastructure - * should always call this function from their ->atomic_commit hook. + * should always call this function from their + * &drm_mode_config_funcs.atomic_commit hook. * * To be able to use this support drivers need to use a few more helper * functions. drm_atomic_helper_wait_for_dependencies() must be called before * actually committing the hardware state, and for nonblocking commits this call * must be placed in the async worker. See also drm_atomic_helper_swap_state() * and it's stall parameter, for when a driver's commit hooks look at the - * ->state pointers of &struct drm_crtc, &drm_plane or &drm_connector directly. + * &drm_crtc.state, &drm_plane.state or &drm_connector.state pointer directly. * * Completion of the hardware commit step must be signalled using * drm_atomic_helper_commit_hw_done(). After this step the driver is not allowed @@ -1489,8 +1495,7 @@ static struct drm_crtc_commit *preceeding_commit(struct drm_crtc *crtc) * This function waits for all preceeding commits that touch the same CRTC as * @old_state to both be committed to the hardware (as signalled by * drm_atomic_helper_commit_hw_done) and executed by the hardware (as signalled - * by calling drm_crtc_vblank_send_event on the event member of - * &drm_crtc_state). + * by calling drm_crtc_vblank_send_event() on the &drm_crtc_state.event). * * This is part of the atomic helper support for nonblocking commits, see * drm_atomic_helper_setup_commit() for an overview. @@ -1627,8 +1632,9 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_cleanup_done); * @state: atomic state object with new state structures * * This function prepares plane state, specifically framebuffers, for the new - * configuration. If any failure is encountered this function will call - * ->cleanup_fb on any already successfully prepared framebuffer. + * configuration, by calling &drm_plane_helper_funcs.prepare_fb. If any failure + * is encountered this function will call &drm_plane_helper_funcs.cleanup_fb on + * any already successfully prepared framebuffer. * * Returns: * 0 on success, negative error code on failure. @@ -1708,10 +1714,10 @@ static bool plane_crtc_active(const struct drm_plane_state *state) * * Drivers may set the NO_DISABLE_AFTER_MODESET flag in @flags if the relevant * display controllers require to disable a CRTC's planes when the CRTC is - * disabled. This function would skip the ->atomic_disable call for a plane if - * the CRTC of the old plane state needs a modesetting operation. Of course, - * the drivers need to disable the planes in their CRTC disable callbacks - * since no one else would do that. + * disabled. This function would skip the &drm_plane_helper_funcs.atomic_disable + * call for a plane if the CRTC of the old plane state needs a modesetting + * operation. Of course, the drivers need to disable the planes in their CRTC + * disable callbacks since no one else would do that. * * The drm_atomic_helper_commit() default implementation doesn't set the * ACTIVE_ONLY flag to most closely match the behaviour of the legacy helpers. @@ -1874,7 +1880,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc); * planes. * * It is a bug to call this function without having implemented the - * ->atomic_disable() plane hook. + * &drm_plane_helper_funcs.atomic_disable plane hook. */ void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state *old_crtc_state, @@ -1961,8 +1967,8 @@ EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes); * contains the old state. Also do any other cleanup required with that state. * * @stall must be set when nonblocking commits for this driver directly access - * the ->state pointer of &drm_plane, &drm_crtc or &drm_connector. With the - * current atomic helpers this is almost always the case, since the helpers + * the &drm_plane.state, &drm_crtc.state or &drm_connector.state pointer. With + * the current atomic helpers this is almost always the case, since the helpers * don't pass the right state structures to the callbacks. */ void drm_atomic_helper_swap_state(struct drm_atomic_state *state, @@ -2363,7 +2369,7 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, if (ret != 0) return ret; - drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay); + drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay); drm_atomic_set_fb_for_plane(primary_state, set->fb); primary_state->crtc_x = 0; @@ -2892,8 +2898,8 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip_target); * * This is the main helper function provided by the atomic helper framework for * implementing the legacy DPMS connector interface. It computes the new desired - * ->active state for the corresponding CRTC (if the connector is enabled) and - * updates it. + * &drm_crtc_state.active state for the corresponding CRTC (if the connector is + * enabled) and updates it. * * Returns: * Returns 0 on success, negative errno numbers on failure. @@ -2965,11 +2971,11 @@ backoff: EXPORT_SYMBOL(drm_atomic_helper_connector_dpms); /** - * drm_atomic_helper_best_encoder - Helper for &drm_connector_helper_funcs - * ->best_encoder callback + * drm_atomic_helper_best_encoder - Helper for + * &drm_connector_helper_funcs.best_encoder callback * @connector: Connector control structure * - * This is a &drm_connector_helper_funcs ->best_encoder callback helper for + * This is a &drm_connector_helper_funcs.best_encoder callback helper for * connectors that support exactly 1 encoder, statically determined at driver * init time. */ @@ -3003,7 +3009,7 @@ EXPORT_SYMBOL(drm_atomic_helper_best_encoder); */ /** - * drm_atomic_helper_crtc_reset - default ->reset hook for CRTCs + * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs * @crtc: drm CRTC * * Resets the atomic state for @crtc by freeing the state pointer (which might @@ -3110,7 +3116,7 @@ void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state); /** - * drm_atomic_helper_plane_reset - default ->reset hook for planes + * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes * @plane: drm plane * * Resets the atomic state for @plane by freeing the state pointer (which might @@ -3214,8 +3220,9 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state); * @conn_state: connector state to assign * * Initializes the newly allocated @conn_state and assigns it to - * #connector ->state, usually required when initializing the drivers - * or when called from the ->reset hook. + * the &drm_conector->state pointer of @connector, usually required when + * initializing the drivers or when called from the &drm_connector_funcs.reset + * hook. * * This is useful for drivers that subclass the connector state. */ @@ -3231,7 +3238,7 @@ __drm_atomic_helper_connector_reset(struct drm_connector *connector, EXPORT_SYMBOL(__drm_atomic_helper_connector_reset); /** - * drm_atomic_helper_connector_reset - default ->reset hook for connectors + * drm_atomic_helper_connector_reset - default &drm_connector_funcs.reset hook for connectors * @connector: drm connector * * Resets the atomic state for @connector by freeing the state pointer (which diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index 860cfe124c2a..7ff697389d74 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -40,8 +40,8 @@ * least once successfully became the device master (either through the * SET_MASTER IOCTL, or implicitly through opening the primary device node when * no one else is the current master that time) there exists one &drm_master. - * This is noted in the is_master member of &drm_file. All other clients have - * just a pointer to the &drm_master they are associated with. + * This is noted in &drm_file.is_master. All other clients have just a pointer + * to the &drm_master they are associated with. * * In addition only one &drm_master can be the current master for a &drm_device. * It can be switched through the DROP_MASTER and SET_MASTER IOCTL, or diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 1f2412c7ccfd..665aafc6ad68 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -40,9 +40,8 @@ * 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. + * and @vdisplay) of the requested mode (stored in &drm_crtc_state.mode). 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: @@ -215,7 +214,7 @@ EXPORT_SYMBOL(drm_rotation_simplify); * for it in drm core. Drivers can then attach this property to planes to enable * support for configurable planes arrangement during blending operation. * Once mutable zpos property has been enabled, the DRM core will automatically - * calculate drm_plane_state->normalized_zpos values. Usually min should be set + * calculate &drm_plane_state.normalized_zpos values. Usually min should be set * to 0 and max to maximal number of planes for given crtc - 1. * * If zpos of some planes cannot be changed (like fixed background or @@ -367,8 +366,8 @@ done: * 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 + * with lowest zpos value is at the bottom. The &drm_plane_state.normalized_zpos + * is then filled with unique values from 0 to number of active planes in crtc * minus one. * * RETURNS diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index 5066638928ec..c3b9aaccdf42 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -29,7 +29,9 @@ */ #include <linux/export.h> -#include <drm/drmP.h> +#include <linux/highmem.h> + +#include <drm/drm_cache.h> #if defined(CONFIG_X86) #include <asm/smp.h> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 799edd0d308e..e4d2c8a49076 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -38,18 +38,17 @@ * Hence they are reference-counted using drm_connector_reference() and * drm_connector_unreference(). * - * KMS driver must create, initialize, register and attach at a struct - * &drm_connector for each such sink. The instance is created as other KMS - * objects and initialized by setting the following fields. - * - * The connector is then registered with a call to drm_connector_init() with a - * pointer to the connector functions and a connector type, and exposed through - * sysfs with a call to drm_connector_register(). + * KMS driver must create, initialize, register and attach at a &struct + * drm_connector for each such sink. The instance is created as other KMS + * objects and initialized by setting the following fields. The connector is + * initialized with a call to drm_connector_init() with a pointer to the + * &struct drm_connector_funcs and a connector type, and then exposed to + * userspace with a call to drm_connector_register(). * * Connectors must be attached to an encoder to be used. For devices that map * connectors to encoders 1:1, the connector should be attached at * initialization time with a call to drm_mode_connector_attach_encoder(). The - * driver must also set the &struct drm_connector encoder field to point to the + * driver must also set the &drm_connector.encoder field to point to the * attached encoder. * * For connectors which are not fixed (like built-in panels) the driver needs to @@ -497,7 +496,7 @@ static struct lockdep_map connector_list_iter_dep_map = { * @dev: DRM device * @iter: connector_list iterator * - * Sets @iter up to walk the connector list in &drm_mode_config of @dev. @iter + * Sets @iter up to walk the &drm_mode_config.connector_list of @dev. @iter * must always be cleaned up again by calling drm_connector_list_iter_put(). * Iteration itself happens using drm_connector_list_iter_next() or * drm_for_each_connector_iter(). @@ -696,8 +695,8 @@ DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, * drivers this is only provided for backwards compatibility with existing * drivers, it remaps to controlling the "ACTIVE" property on the CRTC the * connector is linked to. Drivers should never set this property directly, - * it is handled by the DRM core by calling the ->dpms() callback in - * &drm_connector_funcs. Atomic drivers should implement this hook using + * it is handled by the DRM core by calling the &drm_connector_funcs.dpms + * callback. Atomic drivers should implement this hook using * drm_atomic_helper_connector_dpms(). This is the only property standard * connector property that userspace can change. * PATH: diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index bd3c8b243447..6915f897bd8e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -47,6 +47,27 @@ #include "drm_internal.h" /** + * DOC: overview + * + * A CRTC represents the overall display pipeline. It receives pixel data from + * &drm_plane and blends them together. The &drm_display_mode is also attached + * to the CRTC, specifying display timings. On the output side the data is fed + * to one or more &drm_encoder, which are then each connected to one + * &drm_connector. + * + * To create a CRTC, a KMS drivers allocates and zeroes an instances of + * &struct drm_crtc (possibly as part of a larger structure) and registers it + * with a call to drm_crtc_init_with_planes(). + * + * The CRTC is also the entry point for legacy modeset operations, see + * &drm_crtc_funcs.set_config, legacy plane operations, see + * &drm_crtc_funcs.page_flip and &drm_crtc_funcs.cursor_set2, and other legacy + * operations like &drm_crtc_funcs.gamma_set. For atomic drivers all these + * features are controlled through &drm_property and + * &drm_mode_config_funcs.atomic_check and &drm_mode_config_funcs.atomic_check. + */ + +/** * drm_crtc_from_index - find the registered CRTC at an index * @dev: DRM device * @idx: index of registered CRTC to find for @@ -415,11 +436,12 @@ int drm_mode_getcrtc(struct drm_device *dev, } /** - * drm_mode_set_config_internal - helper to call ->set_config + * drm_mode_set_config_internal - helper to call &drm_mode_config_funcs.set_config * @set: modeset config to set * - * This is a little helper to wrap internal calls to the ->set_config driver - * interface. The only thing it adds is correct refcounting dance. + * This is a little helper to wrap internal calls to the + * &drm_mode_config_funcs.set_config driver interface. The only thing it adds is + * correct refcounting dance. * * Returns: * Zero on success, negative errno on failure. @@ -460,27 +482,6 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) EXPORT_SYMBOL(drm_mode_set_config_internal); /** - * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode - * @mode: mode to query - * @hdisplay: hdisplay value to fill in - * @vdisplay: vdisplay value to fill in - * - * The vdisplay value will be doubled if the specified mode is a stereo mode of - * the appropriate layout. - */ -void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, - int *hdisplay, int *vdisplay) -{ - struct drm_display_mode adjusted; - - drm_mode_copy(&adjusted, mode); - drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY); - *hdisplay = adjusted.crtc_hdisplay; - *vdisplay = adjusted.crtc_vdisplay; -} -EXPORT_SYMBOL(drm_crtc_get_hv_timing); - -/** * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the * CRTC viewport * @crtc: CRTC that framebuffer will be displayed on @@ -497,7 +498,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, { int hdisplay, vdisplay; - drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); + drm_mode_get_hv_timing(mode, &hdisplay, &vdisplay); if (crtc->state && drm_rotation_90_or_270(crtc->primary->state->rotation)) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 1e281dd42e4b..44ba0e990d6c 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -53,9 +53,9 @@ * configuration on resume with drm_helper_resume_force_mode(). * * Note that this helper library doesn't track the current power state of CRTCs - * and encoders. It can call callbacks like ->dpms() even though the hardware is - * already in the desired state. This deficiency has been fixed in the atomic - * helpers. + * and encoders. It can call callbacks like &drm_encoder_helper_funcs.dpms even + * though the hardware is already in the desired state. This deficiency has been + * fixed in the atomic helpers. * * The driver callbacks are mostly compatible with the atomic modeset helpers, * except for the handling of the primary plane: Atomic helpers require that the @@ -477,12 +477,12 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) * drm_crtc_helper_set_config - set a new config from userspace * @set: mode set configuration * - * The drm_crtc_helper_set_config() helper function implements the set_config - * callback of &struct drm_crtc_funcs for drivers using the legacy CRTC helpers. + * The drm_crtc_helper_set_config() helper function implements the of + * &drm_crtc_funcs.set_config callback for drivers using the legacy CRTC + * helpers. * * It first tries to locate the best encoder for each connector by calling the - * connector ->best_encoder() (&struct drm_connector_helper_funcs) helper - * operation. + * connector @drm_connector_helper_funcs.best_encoder helper operation. * * After locating the appropriate encoders, the helper function will call the * mode_fixup encoder and CRTC helper operations to adjust the requested mode, @@ -493,8 +493,7 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) * * If the adjusted mode is identical to the current mode but changes to the * frame buffer need to be applied, the drm_crtc_helper_set_config() function - * will call the CRTC ->mode_set_base() (&struct drm_crtc_helper_funcs) helper - * operation. + * will call the CRTC &drm_crtc_helper_funcs.mode_set_base helper operation. * * If the adjusted mode differs from the current mode, or if the * ->mode_set_base() helper operation is not provided, the helper function @@ -851,14 +850,15 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc) * @connector: affected connector * @mode: DPMS mode * - * The drm_helper_connector_dpms() helper function implements the ->dpms() - * callback of &struct drm_connector_funcs for drivers using the legacy CRTC helpers. + * The drm_helper_connector_dpms() helper function implements the + * &drm_connector_funcs.dpms callback for drivers using the legacy CRTC + * helpers. * * This is the main helper function provided by the CRTC helper framework for * implementing the DPMS connector attribute. It computes the new desired DPMS - * state for all encoders and CRTCs in the output mesh and calls the ->dpms() - * callbacks provided by the driver in &struct drm_crtc_helper_funcs and struct - * &drm_encoder_helper_funcs appropriately. + * state for all encoders and CRTCs in the output mesh and calls the + * &drm_crtc_helper_funcs.dpms and &drm_encoder_helper_funcs.dpms callbacks + * provided by the driver. * * This function is deprecated. New drivers must implement atomic modeset * support, for which this function is unsuitable. Instead drivers should use diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 724c329186d5..1bdcfd566695 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -177,7 +177,6 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, #ifdef CONFIG_DEBUG_FS struct drm_minor; int drm_atomic_debugfs_init(struct drm_minor *minor); -int drm_atomic_debugfs_cleanup(struct drm_minor *minor); #endif int drm_atomic_get_property(struct drm_mode_object *obj, diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 37fd612d57a6..2290a74a6e46 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -81,7 +81,8 @@ static const struct file_operations drm_debugfs_fops = { * \return Zero on success, non-zero on failure * * Create a given set of debugfs files represented by an array of - * gdm_debugfs_lists in the given root directory. + * &drm_info_list in the given root directory. These files will be removed + * automatically on drm_debugfs_cleanup(). */ int drm_debugfs_create_files(const struct drm_info_list *files, int count, struct dentry *root, struct drm_minor *minor) @@ -218,6 +219,19 @@ int drm_debugfs_remove_files(const struct drm_info_list *files, int count, } EXPORT_SYMBOL(drm_debugfs_remove_files); +static void drm_debugfs_remove_all_files(struct drm_minor *minor) +{ + struct drm_info_node *node, *tmp; + + mutex_lock(&minor->debugfs_lock); + list_for_each_entry_safe(node, tmp, &minor->debugfs_list, list) { + debugfs_remove(node->dent); + list_del(&node->list); + kfree(node); + } + mutex_unlock(&minor->debugfs_lock); +} + /** * Cleanup the debugfs filesystem resources. * @@ -229,7 +243,6 @@ EXPORT_SYMBOL(drm_debugfs_remove_files); int drm_debugfs_cleanup(struct drm_minor *minor) { struct drm_device *dev = minor->dev; - int ret; if (!minor->debugfs_root) return 0; @@ -237,17 +250,9 @@ int drm_debugfs_cleanup(struct drm_minor *minor) if (dev->driver->debugfs_cleanup) dev->driver->debugfs_cleanup(minor); - if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { - ret = drm_atomic_debugfs_cleanup(minor); - if (ret) { - DRM_ERROR("DRM: Failed to remove atomic debugfs entries\n"); - return ret; - } - } - - drm_debugfs_remove_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES, minor); + drm_debugfs_remove_all_files(minor); - debugfs_remove(minor->debugfs_root); + debugfs_remove_recursive(minor->debugfs_root); minor->debugfs_root = NULL; return 0; diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 3e6fe82c6d64..68908c1d5ca1 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -725,7 +725,7 @@ MODULE_PARM_DESC(dp_aux_i2c_speed_khz, /* * Transfer a single I2C-over-AUX message and handle various error conditions, * retrying the transaction as appropriate. It is assumed that the - * aux->transfer function does not modify anything in the msg other than the + * &drm_dp_aux.transfer function does not modify anything in the msg other than the * reply field. * * Returns bytes transferred on success, or a negative error code on failure. diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index aa644487749c..122a1b04bebc 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -1086,7 +1086,7 @@ static void build_mst_prop_path(const struct drm_dp_mst_branch *mstb, } static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, - struct device *dev, + struct drm_device *dev, struct drm_dp_link_addr_reply_port *port_msg) { struct drm_dp_mst_port *port; @@ -1104,7 +1104,7 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, port->port_num = port_msg->port_number; port->mgr = mstb->mgr; port->aux.name = "DPMST"; - port->aux.dev = dev; + port->aux.dev = dev->dev; created = true; } else { old_pdt = port->pdt; @@ -2949,7 +2949,7 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) * Return 0 for success, or negative error code on failure */ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, - struct device *dev, struct drm_dp_aux *aux, + struct drm_device *dev, struct drm_dp_aux *aux, int max_dpcd_transaction_bytes, int max_payloads, int conn_base_id) { diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 72116978ec06..6cbd67f4fbc5 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -221,7 +221,7 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type) ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root); if (ret) { DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); - return ret; + goto err_debugfs; } ret = device_add(minor->kdev); @@ -309,7 +309,7 @@ void drm_minor_release(struct drm_minor *minor) * userspace the device instance can be published using drm_dev_register(). * * There is also deprecated support for initalizing device instances using - * bus-specific helpers and the ->load() callback. But due to + * bus-specific helpers and the &drm_driver.load callback. But due to * backwards-compatibility needs the device instance have to be published too * early, which requires unpretty global locking to make safe and is therefore * only support for existing drivers not yet converted to the new scheme. @@ -720,9 +720,9 @@ static void remove_compat_control_link(struct drm_device *dev) * Never call this twice on any device! * * NOTE: To ensure backward compatibility with existing drivers method this - * function calls the ->load() method after registering the device nodes, - * creating race conditions. Usage of the ->load() methods is therefore - * deprecated, drivers must perform all initialization before calling + * function calls the &drm_driver.load method after registering the device + * nodes, creating race conditions. Usage of the &drm_driver.load methods is + * therefore deprecated, drivers must perform all initialization before calling * drm_dev_register(). * * RETURNS: diff --git a/drivers/gpu/drm/drm_dumb_buffers.c b/drivers/gpu/drm/drm_dumb_buffers.c index e5c61cda4ae3..10307cc16d75 100644 --- a/drivers/gpu/drm/drm_dumb_buffers.c +++ b/drivers/gpu/drm/drm_dumb_buffers.c @@ -42,8 +42,8 @@ * create dumb buffers suitable for scanout, which can then be used to create * KMS frame buffers. * - * To support dumb objects drivers must implement the dumb_create, - * dumb_destroy and dumb_map_offset operations from &struct drm_driver. See + * To support dumb objects drivers must implement the &drm_driver.dumb_create, + * &drm_driver.dumb_destroy and &drm_driver.dumb_map_offset operations. See * there for further details. * * Note that dumb objects may not be used for gpu acceleration, as has been diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 4ff04aa84dd0..baa6ccb3e18b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3768,6 +3768,25 @@ bool drm_rgb_quant_range_selectable(struct edid *edid) } EXPORT_SYMBOL(drm_rgb_quant_range_selectable); +/** + * drm_default_rgb_quant_range - default RGB quantization range + * @mode: display mode + * + * Determine the default RGB quantization range for the mode, + * as specified in CEA-861. + * + * Return: The default RGB quantization range for the mode + */ +enum hdmi_quantization_range +drm_default_rgb_quant_range(const struct drm_display_mode *mode) +{ + /* All CEA modes other than VIC 1 use limited quantization range. */ + return drm_match_cea_mode(mode) > 1 ? + HDMI_QUANTIZATION_RANGE_LIMITED : + HDMI_QUANTIZATION_RANGE_FULL; +} +EXPORT_SYMBOL(drm_default_rgb_quant_range); + static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, const u8 *hdmi) { @@ -4273,6 +4292,52 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, } EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode); +/** + * drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe + * quantization range information + * @frame: HDMI AVI infoframe + * @mode: DRM display mode + * @rgb_quant_range: RGB quantization range (Q) + * @rgb_quant_range_selectable: Sink support selectable RGB quantization range (QS) + */ +void +drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, + const struct drm_display_mode *mode, + enum hdmi_quantization_range rgb_quant_range, + bool rgb_quant_range_selectable) +{ + /* + * CEA-861: + * "A Source shall not send a non-zero Q value that does not correspond + * to the default RGB Quantization Range for the transmitted Picture + * unless the Sink indicates support for the Q bit in a Video + * Capabilities Data Block." + * + * HDMI 2.0 recommends sending non-zero Q when it does match the + * default RGB quantization range for the mode, even when QS=0. + */ + if (rgb_quant_range_selectable || + rgb_quant_range == drm_default_rgb_quant_range(mode)) + frame->quantization_range = rgb_quant_range; + else + frame->quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; + + /* + * CEA-861-F: + * "When transmitting any RGB colorimetry, the Source should set the + * YQ-field to match the RGB Quantization Range being transmitted + * (e.g., when Limited Range RGB, set YQ=0 or when Full Range RGB, + * set YQ=1) and the Sink shall ignore the YQ-field." + */ + if (rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) + frame->ycc_quantization_range = + HDMI_YCC_QUANTIZATION_RANGE_LIMITED; + else + frame->ycc_quantization_range = + HDMI_YCC_QUANTIZATION_RANGE_FULL; +} +EXPORT_SYMBOL(drm_hdmi_avi_infoframe_quant_range); + static enum hdmi_3d_structure s3d_structure_from_display_mode(const struct drm_display_mode *mode) { diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index 487cfe3989e8..129450713bb7 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c @@ -98,7 +98,7 @@ void drm_encoder_unregister_all(struct drm_device *dev) * * Initialises a preallocated encoder. Encoder should be subclassed as part of * driver encoder objects. At driver unload time drm_encoder_cleanup() should be - * called from the driver's destroy hook in &drm_encoder_funcs. + * called from the driver's &drm_encoder_funcs.destroy hook. * * Returns: * Zero on success, error code on failure. diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c index 4484785cd9ac..cf804389f5ec 100644 --- a/drivers/gpu/drm/drm_encoder_slave.c +++ b/drivers/gpu/drm/drm_encoder_slave.c @@ -43,7 +43,7 @@ * &drm_encoder_slave. The @slave_funcs field will be initialized with * the hooks provided by the slave driver. * - * If @info->platform_data is non-NULL it will be used as the initial + * If @info.platform_data is non-NULL it will be used as the initial * slave config. * * Returns 0 on success or a negative errno on failure, in particular, diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 4364abfb6a71..0ef8b284a4b8 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -622,3 +622,21 @@ void drm_fbdev_cma_set_suspend(struct drm_fbdev_cma *fbdev_cma, int state) drm_fb_helper_set_suspend(&fbdev_cma->fb_helper, state); } EXPORT_SYMBOL(drm_fbdev_cma_set_suspend); + +/** + * drm_fbdev_cma_set_suspend_unlocked - wrapper around + * drm_fb_helper_set_suspend_unlocked + * @fbdev_cma: The drm_fbdev_cma struct, may be NULL + * @state: desired state, zero to resume, non-zero to suspend + * + * Calls drm_fb_helper_set_suspend, which is a wrapper around + * fb_set_suspend implemented by fbdev core. + */ +void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma, + int state) +{ + if (fbdev_cma) + drm_fb_helper_set_suspend_unlocked(&fbdev_cma->fb_helper, + state); +} +EXPORT_SYMBOL(drm_fbdev_cma_set_suspend_unlocked); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 0ab6aaacb7d6..c7fafa175755 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -66,11 +66,11 @@ static DEFINE_MUTEX(kernel_fb_helper_lock); * Teardown is done with drm_fb_helper_fini(). * * At runtime drivers should restore the fbdev console by calling - * drm_fb_helper_restore_fbdev_mode_unlocked() from their ->lastclose callback. - * They should also notify the fb helper code from updates to the output - * configuration by calling drm_fb_helper_hotplug_event(). For easier + * drm_fb_helper_restore_fbdev_mode_unlocked() from their &drm_driver.lastclose + * callback. They should also notify the fb helper code from updates to the + * output configuration by calling drm_fb_helper_hotplug_event(). For easier * integration with the output polling code in drm_crtc_helper.c the modeset - * code provides a ->output_poll_changed callback. + * code provides a &drm_mode_config_funcs.output_poll_changed callback. * * All other functions exported by the fb helper library can be used to * implement the fbdev driver interface by the driver. @@ -79,7 +79,7 @@ static DEFINE_MUTEX(kernel_fb_helper_lock); * hotplug detection using the fbdev helpers. The drm_fb_helper_prepare() * helper must be called first to initialize the minimum required to make * hotplug detection work. Drivers also need to make sure to properly set up - * the dev->mode_config.funcs member. After calling drm_kms_helper_poll_init() + * the &drm_mode_config.funcs member. After calling drm_kms_helper_poll_init() * it is safe to enable interrupts and start processing hotplug events. At the * same time, drivers should initialize all modeset objects such as CRTCs, * encoders and connectors. To finish up the fbdev helper initialization, the @@ -88,9 +88,9 @@ static DEFINE_MUTEX(kernel_fb_helper_lock); * should call drm_fb_helper_single_add_all_connectors() followed by * drm_fb_helper_initial_config(). * - * If &drm_framebuffer_funcs ->dirty is set, the + * If &drm_framebuffer_funcs.dirty is set, the * drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit} functions will - * accumulate changes and schedule &drm_fb_helper ->dirty_work to run right + * accumulate changes and schedule &drm_fb_helper.dirty_work to run right * away. This worker then calls the dirty() function ensuring that it will * always run in process context since the fb_*() function could be running in * atomic context. If drm_fb_helper_deferred_io() is used as the deferred_io @@ -247,7 +247,7 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc) } /** - * drm_fb_helper_debug_enter - implementation for ->fb_debug_enter + * drm_fb_helper_debug_enter - implementation for &fb_ops.fb_debug_enter * @info: fbdev registered by the helper */ int drm_fb_helper_debug_enter(struct fb_info *info) @@ -296,7 +296,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) } /** - * drm_fb_helper_debug_leave - implementation for ->fb_debug_leave + * drm_fb_helper_debug_leave - implementation for &fb_ops.fb_debug_leave * @info: fbdev registered by the helper */ int drm_fb_helper_debug_leave(struct fb_info *info) @@ -445,7 +445,7 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration * @fb_helper: fbcon to restore * - * This should be called from driver's drm ->lastclose callback + * This should be called from driver's drm &drm_driver.lastclose callback * when implementing an fbcon on top of kms using this helper. This ensures that * the user isn't greeted with a black screen when e.g. X dies. * @@ -585,7 +585,7 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) } /** - * drm_fb_helper_blank - implementation for ->fb_blank + * drm_fb_helper_blank - implementation for &fb_ops.fb_blank * @blank: desired blanking state * @info: fbdev registered by the helper */ @@ -912,7 +912,7 @@ static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y, * @info: fb_info struct pointer * @pagelist: list of dirty mmap framebuffer pages * - * This function is used as the &fb_deferred_io ->deferred_io + * This function is used as the &fb_deferred_io.deferred_io * callback function for flushing the fbdev mmap writes. */ void drm_fb_helper_deferred_io(struct fb_info *info, @@ -1103,7 +1103,7 @@ EXPORT_SYMBOL(drm_fb_helper_set_suspend); * due to all the printk activity. * * This function can be called multiple times with the same state since - * &fb_info->state is checked to see if fbdev is running or not before locking. + * &fb_info.state is checked to see if fbdev is running or not before locking. * * Use drm_fb_helper_set_suspend() if you need to take the lock yourself. */ @@ -1181,7 +1181,7 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, } /** - * drm_fb_helper_setcmap - implementation for ->fb_setcmap + * drm_fb_helper_setcmap - implementation for &fb_ops.fb_setcmap * @cmap: cmap to set * @info: fbdev registered by the helper */ @@ -1238,7 +1238,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) EXPORT_SYMBOL(drm_fb_helper_setcmap); /** - * drm_fb_helper_check_var - implementation for ->fb_check_var + * drm_fb_helper_check_var - implementation for &fb_ops.fb_check_var * @var: screeninfo to check * @info: fbdev registered by the helper */ @@ -1338,7 +1338,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, EXPORT_SYMBOL(drm_fb_helper_check_var); /** - * drm_fb_helper_set_par - implementation for ->fb_set_par + * drm_fb_helper_set_par - implementation for &fb_ops.fb_set_par * @info: fbdev registered by the helper * * This will let fbcon do the mode init and is called at initialization time by @@ -1422,7 +1422,7 @@ backoff: } /** - * drm_fb_helper_pan_display - implementation for ->fb_pan_display + * drm_fb_helper_pan_display - implementation for &fb_ops.fb_pan_display * @var: updated screen information * @info: fbdev registered by the helper */ @@ -1607,7 +1607,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, * additional constraints need to set up their own limits. * * Drivers should call this (or their equivalent setup code) from their - * ->fb_probe callback. + * &drm_fb_helper_funcs.fb_probe callback. */ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, uint32_t depth) @@ -1636,11 +1636,11 @@ EXPORT_SYMBOL(drm_fb_helper_fill_fix); * @fb_height: desired fb height * * Sets up the variable fbdev metainformation from the given fb helper instance - * and the drm framebuffer allocated in fb_helper->fb. + * and the drm framebuffer allocated in &drm_fb_helper.fb. * * Drivers should call this (or their equivalent setup code) from their - * ->fb_probe callback after having allocated the fbdev backing - * storage framebuffer. + * &drm_fb_helper_funcs.fb_probe callback after having allocated the fbdev + * backing storage framebuffer. */ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, uint32_t fb_width, uint32_t fb_height) @@ -2207,9 +2207,9 @@ out: * Note that this also registers the fbdev and so allows userspace to call into * the driver through the fbdev interfaces. * - * This function will call down into the ->fb_probe callback to let - * the driver allocate and initialize the fbdev info structure and the drm - * framebuffer used to back the fbdev. drm_fb_helper_fill_var() and + * This function will call down into the &drm_fb_helper_funcs.fb_probe callback + * to let the driver allocate and initialize the fbdev info structure and the + * drm framebuffer used to back the fbdev. drm_fb_helper_fill_var() and * drm_fb_helper_fill_fix() are provided as helpers to setup simple default * values for the fbdev info structure. * diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index e22645375e60..afdf5b147f39 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -580,7 +580,7 @@ EXPORT_SYMBOL(drm_poll); * kmalloc and @p must be the first member element. * * This is the locked version of drm_event_reserve_init() for callers which - * already hold dev->event_lock. + * already hold &drm_device.event_lock. * * RETURNS: * @@ -621,7 +621,7 @@ EXPORT_SYMBOL(drm_event_reserve_init_locked); * If callers embedded @p into a larger structure it must be allocated with * kmalloc and @p must be the first member element. * - * Callers which already hold dev->event_lock should use + * Callers which already hold &drm_device.event_lock should use * drm_event_reserve_init_locked() instead. * * RETURNS: @@ -677,7 +677,7 @@ EXPORT_SYMBOL(drm_event_cancel_free); * * This function sends the event @e, initialized with drm_event_reserve_init(), * to its associated userspace DRM file. Callers must already hold - * dev->event_lock, see drm_send_event() for the unlocked version. + * &drm_device.event_lock, see drm_send_event() for the unlocked version. * * Note that the core will take care of unlinking and disarming events when the * corresponding DRM file is closed. Drivers need not worry about whether the @@ -717,8 +717,9 @@ EXPORT_SYMBOL(drm_send_event_locked); * @e: DRM event to deliver * * This function sends the event @e, initialized with drm_event_reserve_init(), - * to its associated userspace DRM file. This function acquires dev->event_lock, - * see drm_send_event_locked() for callers which already hold this lock. + * to its associated userspace DRM file. This function acquires + * &drm_device.event_lock, see drm_send_event_locked() for callers which already + * hold this lock. * * Note that the core will take care of unlinking and disarming events when the * corresponding DRM file is closed. Drivers need not worry about whether the diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 588ccc3a2218..28a0108a1ab8 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -58,8 +58,8 @@ * fbdev framebuffer when the struct &struct drm_framebuffer is embedded into * the fbdev helper struct) drivers can manually clean up a framebuffer at * module unload time with drm_framebuffer_unregister_private(). But doing this - * is not recommended, and it's better to have a normal free-standing struct - * &drm_framebuffer. + * is not recommended, and it's better to have a normal free-standing &struct + * drm_framebuffer. */ int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, @@ -470,7 +470,7 @@ int drm_mode_getfb(struct drm_device *dev, * usb display-link, mipi manual update panels or edp panel self refresh modes. * * Modesetting drivers which always update the frontbuffer do not need to - * implement the corresponding ->dirty framebuffer callback. + * implement the corresponding &drm_framebuffer_funcs.dirty callback. * * Called by the user via ioctl. * @@ -709,10 +709,10 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private); * @fb: framebuffer to remove * * Cleanup framebuffer. This function is intended to be used from the drivers - * ->destroy callback. It can also be used to clean up driver private - * framebuffers embedded into a larger structure. + * &drm_framebuffer_funcs.destroy callback. It can also be used to clean up + * driver private framebuffers embedded into a larger structure. * - * Note that this function does not remove the fb from active usuage - if it is + * Note that this function does not remove the fb from active usage - if it is * still used anywhere, hilarity can ensue since userspace could call getfb on * the id and get back -EINVAL. Obviously no concern at driver unload time. * diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 465bacd0a630..bc93de308673 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -316,8 +316,8 @@ EXPORT_SYMBOL(drm_gem_handle_delete); * @dev: corresponding drm_device * @handle: the dumb handle to remove * - * This implements the ->dumb_destroy kms driver callback for drivers which use - * gem to manage their backing storage. + * This implements the &drm_driver.dumb_destroy kms driver callback for drivers + * which use gem to manage their backing storage. */ int drm_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, @@ -333,9 +333,9 @@ EXPORT_SYMBOL(drm_gem_dumb_destroy); * @obj: object to register * @handlep: pointer to return the created handle to the caller * - * This expects the dev->object_name_lock to be held already and will drop it - * before returning. Used to avoid races in establishing new handles when - * importing an object from either an flink name or a dma-buf. + * This expects the &drm_device.object_name_lock to be held already and will + * drop it before returning. Used to avoid races in establishing new handles + * when importing an object from either an flink name or a dma-buf. * * Handles must be release again through drm_gem_handle_delete(). This is done * when userspace closes @file_priv for all attached handles, or through the @@ -447,8 +447,8 @@ EXPORT_SYMBOL(drm_gem_free_mmap_offset); * structures. * * This routine allocates and attaches a fake offset for @obj, in cases where - * the virtual size differs from the physical size (ie. obj->size). Otherwise - * just use drm_gem_create_mmap_offset(). + * the virtual size differs from the physical size (ie. &drm_gem_object.size). + * Otherwise just use drm_gem_create_mmap_offset(). * * This function is idempotent and handles an already allocated mmap offset * transparently. Drivers do not need to check for this case. @@ -787,7 +787,7 @@ EXPORT_SYMBOL(drm_gem_object_release); * @kref: kref of the object to free * * Called after the last reference to the object has been lost. - * Must be called holding &drm_device->struct_mutex. + * Must be called holding &drm_device.struct_mutex. * * Frees the object */ @@ -813,7 +813,7 @@ EXPORT_SYMBOL(drm_gem_object_free); * @obj: GEM buffer object * * This releases a reference to @obj. Callers must not hold the - * dev->struct_mutex lock when calling this function. + * &drm_device.struct_mutex lock when calling this function. * * See also __drm_gem_object_unreference(). */ @@ -840,9 +840,9 @@ EXPORT_SYMBOL(drm_gem_object_unreference_unlocked); * drm_gem_object_unreference - release a GEM BO reference * @obj: GEM buffer object * - * This releases a reference to @obj. Callers must hold the dev->struct_mutex - * lock when calling this function, even when the driver doesn't use - * dev->struct_mutex for anything. + * This releases a reference to @obj. Callers must hold the + * &drm_device.struct_mutex lock when calling this function, even when the + * driver doesn't use &drm_device.struct_mutex for anything. * * For drivers not encumbered with legacy locking use * drm_gem_object_unreference_unlocked() instead. diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index a6213f814345..f37388cb2fde 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -31,6 +31,7 @@ void drm_lastclose(struct drm_device *dev); /* drm_pci.c */ int drm_irq_by_busid(struct drm_device *dev, void *data, struct drm_file *file_priv); +void drm_pci_agp_destroy(struct drm_device *dev); /* drm_prime.c */ int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 88c69e71102e..e06cf11ebb4a 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -95,7 +95,7 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe, * * Only to be called from drm_crtc_vblank_on(). * - * Note: caller must hold dev->vbl_lock since this reads & writes + * Note: caller must hold &drm_device.vbl_lock since this reads & writes * device vblank fields. */ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe) @@ -142,7 +142,7 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe * Only necessary when going from off->on, to account for frames we * didn't get an interrupt for. * - * Note: caller must hold dev->vbl_lock since this reads & writes + * Note: caller must hold &drm_device.vbl_lock since this reads & writes * device vblank fields. */ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, @@ -415,29 +415,6 @@ err: } EXPORT_SYMBOL(drm_vblank_init); -static void drm_irq_vgaarb_nokms(void *cookie, bool state) -{ - struct drm_device *dev = cookie; - - if (dev->driver->vgaarb_irq) { - dev->driver->vgaarb_irq(dev, state); - return; - } - - if (!dev->irq_enabled) - return; - - if (state) { - if (dev->driver->irq_uninstall) - dev->driver->irq_uninstall(dev); - } else { - if (dev->driver->irq_preinstall) - dev->driver->irq_preinstall(dev); - if (dev->driver->irq_postinstall) - dev->driver->irq_postinstall(dev); - } -} - /** * drm_irq_install - install IRQ handler * @dev: DRM device @@ -449,7 +426,7 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state) * * This is the simplified helper interface provided for drivers with no special * needs. Drivers which need to install interrupt handlers for multiple - * interrupts must instead set drm_device->irq_enabled to signal the DRM core + * interrupts must instead set &drm_device.irq_enabled to signal the DRM core * that vblank interrupts are available. * * Returns: @@ -492,9 +469,6 @@ int drm_irq_install(struct drm_device *dev, int irq) return ret; } - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL); - /* After installing handler */ if (dev->driver->irq_postinstall) ret = dev->driver->irq_postinstall(dev); @@ -519,7 +493,7 @@ EXPORT_SYMBOL(drm_irq_install); * Calls the driver's irq_uninstall() function and unregisters the IRQ handler. * This should only be called by drivers which used drm_irq_install() to set up * their interrupt handler. Other drivers must only reset - * drm_device->irq_enabled to false. + * &drm_device.irq_enabled to false. * * Note that for kernel modesetting drivers it is a bug if this function fails. * The sanity checks are only to catch buggy user modesetting drivers which call @@ -982,12 +956,11 @@ static void send_vblank_event(struct drm_device *dev, * period. This helper function implements exactly the required vblank arming * behaviour. * - * NOTE: Drivers using this to send out the event in &struct drm_crtc_state - * as part of an atomic commit must ensure that the next vblank happens at - * exactly the same time as the atomic commit is committed to the hardware. This - * function itself does **not** protect again the next vblank interrupt racing - * with either this function call or the atomic commit operation. A possible - * sequence could be: + * NOTE: Drivers using this to send out the &drm_crtc_state.event as part of an + * atomic commit must ensure that the next vblank happens at exactly the same + * time as the atomic commit is committed to the hardware. This function itself + * does **not** protect again the next vblank interrupt racing with either this + * function call or the atomic commit operation. A possible sequence could be: * * 1. Driver commits new hardware state into vblank-synchronized registers. * 2. A vblank happens, committing the hardware state. Also the corresponding diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 229b3f525dee..e51876e588d6 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -552,8 +552,8 @@ EXPORT_SYMBOL(drm_mm_replace_node); * objects to the roster, probably by walking an LRU list, but this can be * freely implemented. Eviction candiates are added using * drm_mm_scan_add_block() until a suitable hole is found or there are no - * further evictable objects. Eviction roster metadata is tracked in struct - * &drm_mm_scan. + * further evictable objects. Eviction roster metadata is tracked in &struct + * drm_mm_scan. * * The driver must walk through all objects again in exactly the reverse * order to restore the allocator state. Note that while the allocator is used diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index ed1ee5a44a7b..884cc4d26fb5 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -421,7 +421,12 @@ void drm_mode_config_cleanup(struct drm_device *dev) drm_connector_unreference(connector); } drm_connector_list_iter_put(&conn_iter); - WARN_ON(!list_empty(&dev->mode_config.connector_list)); + if (WARN_ON(!list_empty(&dev->mode_config.connector_list))) { + drm_connector_list_iter_get(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) + DRM_ERROR("connector %s leaked!\n", connector->name); + drm_connector_list_iter_put(&conn_iter); + } list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, head) { diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index e6b19bc9021a..a8616b1a8d22 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -797,6 +797,26 @@ int drm_mode_vrefresh(const struct drm_display_mode *mode) EXPORT_SYMBOL(drm_mode_vrefresh); /** + * drm_mode_get_hv_timing - Fetches hdisplay/vdisplay for given mode + * @mode: mode to query + * @hdisplay: hdisplay value to fill in + * @vdisplay: vdisplay value to fill in + * + * The vdisplay value will be doubled if the specified mode is a stereo mode of + * the appropriate layout. + */ +void drm_mode_get_hv_timing(const struct drm_display_mode *mode, + int *hdisplay, int *vdisplay) +{ + struct drm_display_mode adjusted = *mode; + + drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY); + *hdisplay = adjusted.crtc_hdisplay; + *vdisplay = adjusted.crtc_vdisplay; +} +EXPORT_SYMBOL(drm_mode_get_hv_timing); + +/** * drm_mode_set_crtcinfo - set CRTC modesetting timing parameters * @p: mode * @adjust_flags: a combination of adjustment flags diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 3551ae31f143..bf60f2645e55 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -33,7 +33,7 @@ * to use &ww_mutex and acquire-contexts to avoid deadlocks. But because * the locking is more distributed around the driver code, we want a bit * of extra utility/tracking out of our acquire-ctx. This is provided - * by drm_modeset_lock / drm_modeset_acquire_ctx. + * by &struct drm_modeset_lock and &struct drm_modeset_acquire_ctx. * * For basic principles of &ww_mutex, see: Documentation/locking/ww-mutex-design.txt * @@ -53,7 +53,7 @@ * drm_modeset_acquire_fini(&ctx); * * On top of of these per-object locks using &ww_mutex there's also an overall - * dev->mode_config.lock, for protecting everything else. Mostly this means + * &drm_mode_config.mutex, for protecting everything else. Mostly this means * probe state of connectors, and preventing hotplug add/removal of connectors. * * Finally there's a bunch of dedicated locks to protect drm core internal @@ -71,7 +71,7 @@ static DEFINE_WW_CLASS(crtc_ww_class); * drm_modeset_unlock_all() function. * * This function is deprecated. It allocates a lock acquisition context and - * stores it in the DRM device's ->mode_config. This facilitate conversion of + * stores it in &drm_device.mode_config. This facilitate conversion of * existing code because it removes the need to manually deal with the * acquisition context, but it is also brittle because the context is global * and care must be taken not to nest calls. New code should use the @@ -124,7 +124,7 @@ EXPORT_SYMBOL(drm_modeset_lock_all); * drm_modeset_lock_all() function. * * This function is deprecated. It uses the lock acquisition context stored - * in the DRM device's ->mode_config. This facilitates conversion of existing + * in &drm_device.mode_config. This facilitates conversion of existing * code because it removes the need to manually deal with the acquisition * context, but it is also brittle because the context is global and care must * be taken not to nest calls. New code should pass the acquisition context @@ -468,7 +468,7 @@ EXPORT_SYMBOL(drm_modeset_unlock); * This function takes all modeset locks, suitable where a more fine-grained * scheme isn't (yet) implemented. * - * Unlike drm_modeset_lock_all(), it doesn't take the dev->mode_config.mutex + * Unlike drm_modeset_lock_all(), it doesn't take the &drm_mode_config.mutex * since that lock isn't required for modeset state changes. Callers which * need to grab that lock too need to do so outside of the acquire context * @ctx. diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index dc358f860aea..a3b356e70b35 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -191,7 +191,7 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, static void drm_pci_agp_init(struct drm_device *dev) { if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { - if (drm_pci_device_is_agp(dev)) + if (pci_find_capability(dev->pdev, PCI_CAP_ID_AGP)) dev->agp = drm_agp_init(dev); if (dev->agp) { dev->agp->agp_mtrr = arch_phys_wc_add( @@ -223,7 +223,7 @@ void drm_pci_agp_destroy(struct drm_device *dev) * Try and register, if we fail to register, backout previous work. * * NOTE: This function is deprecated, please use drm_dev_alloc() and - * drm_dev_register() instead and remove your ->load() callback. + * drm_dev_register() instead and remove your &drm_driver.load callback. * * Return: 0 on success or a negative error code on failure. */ diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index eed66be18329..c464fc4a874d 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -42,7 +42,7 @@ * * 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 + * 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(). * diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 35d43607a47d..148688fb920a 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -39,9 +39,9 @@ * * This helper library has two parts. The first part has support to implement * primary plane support on top of the normal CRTC configuration interface. - * Since the legacy ->set_config interface ties the primary plane together with - * the CRTC state this does not allow userspace to disable the primary plane - * itself. To avoid too much duplicated code use + * Since the legacy &drm_mode_config_funcs.set_config interface ties the primary + * plane together with the CRTC state this does not allow userspace to disable + * the primary plane itself. To avoid too much duplicated code use * drm_plane_helper_check_update() which can be used to enforce the same * restrictions as primary planes had thus. The default primary plane only * expose XRBG8888 and ARGB8888 as valid pixel formats for the attached @@ -384,7 +384,8 @@ EXPORT_SYMBOL(drm_primary_helper_update); * is called in response to a userspace SetPlane operation on the plane with a * NULL framebuffer parameter. It unconditionally fails the disable call with * -EINVAL the only way to disable the primary plane without driver support is - * to disable the entier CRTC. Which does not match the plane ->disable hook. + * to disable the entire CRTC. Which does not match the plane + * &drm_plane_funcs.disable_plane hook. * * Note that some hardware may be able to disable the primary plane without * disabling the whole CRTC. Drivers for such hardware should provide their diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 7af3005a030c..56d2f93ed6b9 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -74,7 +74,7 @@ err_free: * .load() function. * * NOTE: This function is deprecated, please use drm_dev_alloc() and - * drm_dev_register() instead and remove your ->load() callback. + * drm_dev_register() instead and remove your &drm_driver.load callback. * * Return: 0 on success or a negative error code on failure. */ diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 8d77b2462594..25aa4558f1b5 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -40,8 +40,11 @@ * On the export the dma_buf holds a reference to the exporting GEM * object. It takes this reference in handle_to_fd_ioctl, when it * first calls .prime_export and stores the exporting GEM object in - * the dma_buf priv. This reference is released when the dma_buf - * object goes away in the driver .release function. + * the dma_buf priv. This reference needs to be released when the + * final reference to the &dma_buf itself is dropped and its + * &dma_buf_ops.release function is called. For GEM-based drivers, + * the dma_buf should be exported using drm_gem_dmabuf_export() and + * then released by drm_gem_dmabuf_release(). * * On the import the importing GEM object holds a reference to the * dma_buf (which in turn holds a ref to the exporting GEM object). @@ -51,6 +54,16 @@ * when the imported object is destroyed, we remove the attachment * and drop the reference to the dma_buf. * + * When all the references to the &dma_buf are dropped, i.e. when + * userspace has closed both handles to the imported GEM object (through the + * FD_TO_HANDLE IOCTL) and closed the file descriptor of the exported + * (through the HANDLE_TO_FD IOCTL) dma_buf, and all kernel-internal references + * are also gone, then the dma_buf gets destroyed. This can also happen as a + * part of the clean up procedure in the drm_release() function if userspace + * fails to properly clean up. Note that both the kernel and userspace (by + * keeeping the PRIME file descriptors open) can hold references onto a + * &dma_buf. + * * Thus the chain of references always flows in one direction * (avoiding loops): importing_gem -> dmabuf -> exporting_gem * @@ -291,7 +304,7 @@ static void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, * This wraps dma_buf_export() for use by generic GEM drivers that are using * drm_gem_dmabuf_release(). In addition to calling dma_buf_export(), we take * a reference to the &drm_device and the exported &drm_gem_object (stored in - * exp_info->priv) which is released by drm_gem_dmabuf_release(). + * &dma_buf_export_info.priv) which is released by drm_gem_dmabuf_release(). * * Returns the new dmabuf. */ diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 041a5504780f..93381454bdf7 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -43,7 +43,7 @@ * DOC: output probing helper overview * * This library provides some helper code for output probing. It provides an - * implementation of the core connector->fill_modes interface with + * implementation of the core &drm_connector_funcs.fill_modes interface with * drm_helper_probe_single_connector_modes. * * It also provides support for polling connectors with a work item and for @@ -187,9 +187,9 @@ drm_connector_detect(struct drm_connector *connector, bool force) * be added to the connector's probed_modes list, then culled (based on validity * and the @maxX, @maxY parameters) and put into the normal modes list. * - * Intended to be used as a generic implementation of the ->fill_modes() - * @connector vfunc for drivers that use the CRTC helpers for output mode - * filtering and detection. + * Intended to be used as a generic implementation of the + * &drm_connector_funcs.fill_modes() vfunc for drivers that use the CRTC helpers + * for output mode filtering and detection. * * The basic procedure is as follows * @@ -201,7 +201,7 @@ drm_connector_detect(struct drm_connector *connector, bool force) * * - debugfs 'override_edid' (used for testing only) * - firmware EDID (drm_load_edid_firmware()) - * - connector helper ->get_modes() vfunc + * - &drm_connector_helper_funcs.get_modes vfunc * - if the connector status is connector_status_connected, standard * VESA DMT modes up to 1024x768 are automatically added * (drm_add_modes_noedid()) @@ -222,8 +222,8 @@ drm_connector_detect(struct drm_connector *connector, bool force) * (if specified) * - drm_mode_validate_flag() checks the modes againt basic connector * capabilites (interlace_allowed,doublescan_allowed,stereo_allowed) - * - the optional connector ->mode_valid() helper can perform driver and/or - * hardware specific checks + * - the optional &drm_connector_helper_funcs.mode_valid helper can perform + * driver and/or hardware specific checks * * 5. Any mode whose status is not OK is pruned from the connector's modes list, * accompanied by a debug message indicating the reason for the mode's diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index 0d0e5dc0ee23..7fc070f3e49e 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -42,8 +42,8 @@ * drm_object_attach_property(). * * Property values are only 64bit. To support bigger piles of data (like gamma - * tables, color correction matrizes or large structures) a property can instead - * point at a &drm_property_blob with that additional data + * tables, color correction matrices or large structures) a property can instead + * point at a &drm_property_blob with that additional data. * * Properties are defined by their symbolic name, userspace must keep a * per-object mapping from those names to the property ID used in the atomic diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 9a37196c1bf1..513288b5c2f6 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -255,7 +255,7 @@ static const struct attribute_group *connector_dev_groups[] = { * @connector: connector to add * * Create a connector device in sysfs, along with its associated connector - * properties (so far, connection status, dpms, mode list & edid) and + * properties (so far, connection status, dpms, mode list and edid) and * generate a hotplug event so userspace knows there's a new connector * available. */ diff --git a/drivers/gpu/drm/etnaviv/Kconfig b/drivers/gpu/drm/etnaviv/Kconfig index 656c061b439d..cc1731c5289c 100644 --- a/drivers/gpu/drm/etnaviv/Kconfig +++ b/drivers/gpu/drm/etnaviv/Kconfig @@ -2,7 +2,7 @@ config DRM_ETNAVIV tristate "ETNAVIV (DRM support for Vivante GPU IP cores)" depends on DRM - depends on ARCH_MXC || ARCH_DOVE + depends on ARCH_MXC || ARCH_DOVE || (ARM && COMPILE_TEST) depends on MMU select SHMEM select TMPFS diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index b92c24e07cea..590be0d1dd95 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -258,12 +258,6 @@ static int etnaviv_debugfs_init(struct drm_minor *minor) return ret; } - -static void etnaviv_debugfs_cleanup(struct drm_minor *minor) -{ - drm_debugfs_remove_files(etnaviv_debugfs_list, - ARRAY_SIZE(etnaviv_debugfs_list), minor); -} #endif /* @@ -509,7 +503,6 @@ static struct drm_driver etnaviv_drm_driver = { .gem_prime_mmap = etnaviv_gem_prime_mmap, #ifdef CONFIG_DEBUG_FS .debugfs_init = etnaviv_debugfs_init, - .debugfs_cleanup = etnaviv_debugfs_cleanup, #endif .ioctls = etnaviv_ioctls, .num_ioctls = DRM_ETNAVIV_NUM_IOCTLS, diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index d706ca4e2f02..1d185347c64c 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -19,7 +19,6 @@ comment "CRTCs" config DRM_EXYNOS_FIMD bool "FIMD" depends on !FB_S3C - select FB_MODE_HELPERS select MFD_SYSCON help Choose this option if you want to use Exynos FIMD for DRM. @@ -32,7 +31,6 @@ config DRM_EXYNOS5433_DECON config DRM_EXYNOS7_DECON bool "DECON on Exynos7" depends on !FB_S3C - select FB_MODE_HELPERS help Choose this option if you want to use Exynos DECON for DRM. diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 0dc7ba2fdc22..5ee93ff55608 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -406,11 +406,6 @@ out_err: return ret; } -static int psb_driver_device_is_agp(struct drm_device *dev) -{ - return 0; -} - static inline void get_brightness(struct backlight_device *bd) { #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE @@ -487,7 +482,6 @@ static struct drm_driver driver = { .set_busid = drm_pci_set_busid, .num_ioctls = ARRAY_SIZE(psb_ioctls), - .device_is_agp = psb_driver_device_is_agp, .irq_preinstall = psb_irq_preinstall, .irq_postinstall = psb_irq_postinstall, .irq_uninstall = psb_irq_uninstall, diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c index 7a6957ae4b44..16fe79053ee1 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c @@ -121,7 +121,7 @@ static int hibmc_drm_fb_create(struct drm_fb_helper *helper, hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj); if (IS_ERR(hi_fbdev->fb)) { - ret = PTR_ERR(info); + ret = PTR_ERR(hi_fbdev->fb); DRM_ERROR("failed to initialize framebuffer: %d\n", ret); goto out_release_fbi; } diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index ab4e6cbe1f8b..576a417690d4 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c @@ -1190,6 +1190,14 @@ static int i810_flip_bufs(struct drm_device *dev, void *data, int i810_driver_load(struct drm_device *dev, unsigned long flags) { + dev->agp = drm_agp_init(dev); + if (dev->agp) { + dev->agp->agp_mtrr = arch_phys_wc_add( + dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size * + 1024 * 1024); + } + /* Our userspace depends upon the agp mapping support. */ if (!dev->agp) return -EINVAL; @@ -1249,19 +1257,3 @@ const struct drm_ioctl_desc i810_ioctls[] = { }; int i810_max_ioctl = ARRAY_SIZE(i810_ioctls); - -/** - * Determine if the device really is AGP or not. - * - * All Intel graphics chipsets are treated as AGP, even if they are really - * PCI-e. - * - * \param dev The device to be tested. - * - * \returns - * A value of 1 is always retured to indictate every i810 is AGP. - */ -int i810_driver_device_is_agp(struct drm_device *dev) -{ - return 1; -} diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c index 02504a7cfaf2..37fd0906f807 100644 --- a/drivers/gpu/drm/i810/i810_drv.c +++ b/drivers/gpu/drm/i810/i810_drv.c @@ -60,7 +60,6 @@ static struct drm_driver driver = { .lastclose = i810_driver_lastclose, .preclose = i810_driver_preclose, .set_busid = drm_pci_set_busid, - .device_is_agp = i810_driver_device_is_agp, .dma_quiescent = i810_driver_dma_quiescent, .ioctls = i810_ioctls, .fops = &i810_driver_fops, diff --git a/drivers/gpu/drm/i810/i810_drv.h b/drivers/gpu/drm/i810/i810_drv.h index 93ec5dc4e7d3..c73d2f2da57b 100644 --- a/drivers/gpu/drm/i810/i810_drv.h +++ b/drivers/gpu/drm/i810/i810_drv.h @@ -124,7 +124,6 @@ extern int i810_driver_load(struct drm_device *, unsigned long flags); extern void i810_driver_lastclose(struct drm_device *dev); extern void i810_driver_preclose(struct drm_device *dev, struct drm_file *file_priv); -extern int i810_driver_device_is_agp(struct drm_device *dev); extern long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg); extern const struct drm_ioctl_desc i810_ioctls[]; diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 307b22ae7791..155906e84812 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -91,7 +91,7 @@ vma_create(struct drm_i915_gem_object *obj, vma->size = obj->base.size; vma->display_alignment = I915_GTT_MIN_ALIGNMENT; - if (view) { + if (view && view->type != I915_GGTT_VIEW_NORMAL) { vma->ggtt_view = *view; if (view->type == I915_GGTT_VIEW_PARTIAL) { GEM_BUG_ON(range_overflows_t(u64, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0f4272f98648..b3e773c9f872 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11092,7 +11092,7 @@ static int intel_modeset_setup_plane_state(struct drm_atomic_state *state, return PTR_ERR(plane_state); if (mode) - drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); + drm_mode_get_hv_timing(mode, &hdisplay, &vdisplay); else hdisplay = vdisplay = 0; @@ -12981,7 +12981,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, * computation to clearly distinguish it from the adjusted mode, which * can be changed by the connectors in the below retry loop. */ - drm_crtc_get_hv_timing(&pipe_config->base.mode, + drm_mode_get_hv_timing(&pipe_config->base.mode, &pipe_config->pipe_src_w, &pipe_config->pipe_src_h); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index e80d620846c8..3d8ac8aa7214 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1713,7 +1713,9 @@ found: * VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry */ pipe_config->limited_color_range = - bpp != 18 && drm_match_cea_mode(adjusted_mode) > 1; + bpp != 18 && + drm_default_rgb_quant_range(adjusted_mode) == + HDMI_QUANTIZATION_RANGE_LIMITED; } else { pipe_config->limited_color_range = intel_dp->limited_color_range; diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 205fe4748ec5..38e3ca2f6f18 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -587,7 +587,8 @@ intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_ba /* create encoders */ intel_dp_create_fake_mst_encoders(intel_dig_port); - ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev->dev, &intel_dp->aux, 16, 3, conn_base_id); + ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev, + &intel_dp->aux, 16, 3, conn_base_id); if (ret) { intel_dp->can_mst = false; return ret; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 0bcfead14571..af16b0fa6b69 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -455,24 +455,23 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, const struct intel_crtc_state *crtc_state) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + const struct drm_display_mode *adjusted_mode = + &crtc_state->base.adjusted_mode; union hdmi_infoframe frame; int ret; ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, - &crtc_state->base.adjusted_mode); + adjusted_mode); if (ret < 0) { DRM_ERROR("couldn't fill AVI infoframe\n"); return; } - if (intel_hdmi->rgb_quant_range_selectable) { - if (crtc_state->limited_color_range) - frame.avi.quantization_range = - HDMI_QUANTIZATION_RANGE_LIMITED; - else - frame.avi.quantization_range = - HDMI_QUANTIZATION_RANGE_FULL; - } + drm_hdmi_avi_infoframe_quant_range(&frame.avi, adjusted_mode, + crtc_state->limited_color_range ? + HDMI_QUANTIZATION_RANGE_LIMITED : + HDMI_QUANTIZATION_RANGE_FULL, + intel_hdmi->rgb_quant_range_selectable); intel_write_infoframe(encoder, crtc_state, &frame); } @@ -1330,7 +1329,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, /* See CEA-861-E - 5.1 Default Encoding Parameters */ pipe_config->limited_color_range = pipe_config->has_hdmi_sink && - drm_match_cea_mode(adjusted_mode) > 1; + drm_default_rgb_quant_range(adjusted_mode) == + HDMI_QUANTIZATION_RANGE_LIMITED; } else { pipe_config->limited_color_range = intel_hdmi->limited_color_range; diff --git a/drivers/gpu/drm/mga/mga_dma.c b/drivers/gpu/drm/mga/mga_dma.c index a1d8dd15b131..1ffdafea27e4 100644 --- a/drivers/gpu/drm/mga/mga_dma.c +++ b/drivers/gpu/drm/mga/mga_dma.c @@ -392,6 +392,24 @@ int mga_driver_load(struct drm_device *dev, unsigned long flags) drm_mga_private_t *dev_priv; int ret; + /* There are PCI versions of the G450. These cards have the + * same PCI ID as the AGP G450, but have an additional PCI-to-PCI + * bridge chip. We detect these cards, which are not currently + * supported by this driver, by looking at the device ID of the + * bus the "card" is on. If vendor is 0x3388 (Hint Corp) and the + * device is 0x0021 (HB6 Universal PCI-PCI bridge), we reject the + * device. + */ + if ((dev->pdev->device == 0x0525) && dev->pdev->bus->self + && (dev->pdev->bus->self->vendor == 0x3388) + && (dev->pdev->bus->self->device == 0x0021) + && dev->agp) { + /* FIXME: This should be quirked in the pci core, but oh well + * the hw probably stopped existing. */ + arch_phys_wc_del(dev->agp->agp_mtrr); + kfree(dev->agp); + dev->agp = NULL; + } dev_priv = kzalloc(sizeof(drm_mga_private_t), GFP_KERNEL); if (!dev_priv) return -ENOMEM; @@ -698,7 +716,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device *dev, static int mga_do_dma_bootstrap(struct drm_device *dev, drm_mga_dma_bootstrap_t *dma_bs) { - const int is_agp = (dma_bs->agp_mode != 0) && drm_pci_device_is_agp(dev); + const int is_agp = (dma_bs->agp_mode != 0) && dev->agp; int err; drm_mga_private_t *const dev_priv = (drm_mga_private_t *) dev->dev_private; diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c index 25b2a1a424e6..63ba0699d107 100644 --- a/drivers/gpu/drm/mga/mga_drv.c +++ b/drivers/gpu/drm/mga/mga_drv.c @@ -37,8 +37,6 @@ #include <drm/drm_pciids.h> -static int mga_driver_device_is_agp(struct drm_device *dev); - static struct pci_device_id pciidlist[] = { mga_PCI_IDS }; @@ -66,7 +64,6 @@ static struct drm_driver driver = { .lastclose = mga_driver_lastclose, .set_busid = drm_pci_set_busid, .dma_quiescent = mga_driver_dma_quiescent, - .device_is_agp = mga_driver_device_is_agp, .get_vblank_counter = mga_get_vblank_counter, .enable_vblank = mga_enable_vblank, .disable_vblank = mga_disable_vblank, @@ -107,37 +104,3 @@ module_exit(mga_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL and additional rights"); - -/** - * Determine if the device really is AGP or not. - * - * In addition to the usual tests performed by \c drm_device_is_agp, this - * function detects PCI G450 cards that appear to the system exactly like - * AGP G450 cards. - * - * \param dev The device to be tested. - * - * \returns - * If the device is a PCI G450, zero is returned. Otherwise 2 is returned. - */ -static int mga_driver_device_is_agp(struct drm_device *dev) -{ - const struct pci_dev *const pdev = dev->pdev; - - /* There are PCI versions of the G450. These cards have the - * same PCI ID as the AGP G450, but have an additional PCI-to-PCI - * bridge chip. We detect these cards, which are not currently - * supported by this driver, by looking at the device ID of the - * bus the "card" is on. If vendor is 0x3388 (Hint Corp) and the - * device is 0x0021 (HB6 Universal PCI-PCI bridge), we reject the - * device. - */ - - if ((pdev->device == 0x0525) && pdev->bus->self - && (pdev->bus->self->vendor == 0x3388) - && (pdev->bus->self->device == 0x0021)) { - return 0; - } - - return 2; -} diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 7bd4683216d0..4df4f6ed4886 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -199,7 +199,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) if (!nvxx_device(device)->func->pci) getparam->value = 3; else - if (drm_pci_device_is_agp(dev)) + if (pci_find_capability(dev->pdev, PCI_CAP_ID_AGP)) getparam->value = 0; else if (!pci_is_pcie(dev->pdev)) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index cb85cb72dc1c..452da483ca01 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -3417,7 +3417,7 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max, mstm->outp = outp; mstm->mgr.cbs = &nv50_mstm; - ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev->dev, aux, aux_max, + ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev, aux, aux_max, max_payloads, conn_base_id); if (ret) return ret; diff --git a/drivers/gpu/drm/omapdrm/omap_debugfs.c b/drivers/gpu/drm/omapdrm/omap_debugfs.c index bf65862daf62..19b716745623 100644 --- a/drivers/gpu/drm/omapdrm/omap_debugfs.c +++ b/drivers/gpu/drm/omapdrm/omap_debugfs.c @@ -123,13 +123,4 @@ int omap_debugfs_init(struct drm_minor *minor) return ret; } -void omap_debugfs_cleanup(struct drm_minor *minor) -{ - drm_debugfs_remove_files(omap_debugfs_list, - ARRAY_SIZE(omap_debugfs_list), minor); - if (dmm_is_available()) - drm_debugfs_remove_files(omap_dmm_debugfs_list, - ARRAY_SIZE(omap_dmm_debugfs_list), minor); -} - #endif diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 00aa214b7560..afe8f05b927b 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -719,7 +719,6 @@ static struct drm_driver omap_drm_driver = { .disable_vblank = omap_irq_disable_vblank, #ifdef CONFIG_DEBUG_FS .debugfs_init = omap_debugfs_init, - .debugfs_cleanup = omap_debugfs_cleanup, #endif .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index b20377efd01b..36d93ce84a29 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -103,7 +103,6 @@ struct omap_drm_private { #ifdef CONFIG_DEBUG_FS int omap_debugfs_init(struct drm_minor *minor); -void omap_debugfs_cleanup(struct drm_minor *minor); void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m); void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m); void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 510ea371dacc..a8442f7196d6 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -121,7 +121,8 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) VRAM, also but everything into VRAM on AGP cards and older IGP chips to avoid image corruptions */ if (p->ring == R600_RING_TYPE_UVD_INDEX && - (i == 0 || drm_pci_device_is_agp(p->rdev->ddev) || + (i == 0 || pci_find_capability(p->rdev->ddev->pdev, + PCI_CAP_ID_AGP) || p->rdev->family == CHIP_RS780 || p->rdev->family == CHIP_RS880)) { diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 8a1df2a1afbd..4b0c388be3f5 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1549,8 +1549,6 @@ failed: return r; } -static void radeon_debugfs_remove_files(struct radeon_device *rdev); - /** * radeon_device_fini - tear down the driver * @@ -1577,7 +1575,6 @@ void radeon_device_fini(struct radeon_device *rdev) rdev->rmmio = NULL; if (rdev->family >= CHIP_BONAIRE) radeon_doorbell_fini(rdev); - radeon_debugfs_remove_files(rdev); } @@ -1954,16 +1951,3 @@ int radeon_debugfs_add_files(struct radeon_device *rdev, #endif return 0; } - -static void radeon_debugfs_remove_files(struct radeon_device *rdev) -{ -#if defined(CONFIG_DEBUG_FS) - unsigned i; - - for (i = 0; i < rdev->debugfs_count; i++) { - drm_debugfs_remove_files(rdev->debugfs[i].files, - rdev->debugfs[i].num_files, - rdev->ddev->primary); - } -#endif -} diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index 6d1237d6e1b8..7d5ada3980dc 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -667,7 +667,7 @@ radeon_dp_mst_init(struct radeon_connector *radeon_connector) return 0; radeon_connector->mst_mgr.cbs = &mst_cbs; - return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev->dev, + return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev, &radeon_connector->ddc_bus->aux, 16, 6, radeon_connector->base.base.id); } diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 116cf0d23595..56f35c06742c 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -105,7 +105,7 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) dev->dev_private = (void *)rdev; /* update BUS flag */ - if (drm_pci_device_is_agp(dev)) { + if (pci_find_capability(dev->pdev, PCI_CAP_ID_AGP)) { flags |= RADEON_IS_AGP; } else if (pci_is_pcie(dev->pdev)) { flags |= RADEON_IS_PCIE; diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 278a63f10d9f..acc056644cd0 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -89,38 +89,9 @@ static struct drm_info_list sti_drm_dbg_list[] = { {"fps_get", sti_drm_fps_dbg_show, 0}, }; -static int sti_drm_debugfs_create(struct dentry *root, - struct drm_minor *minor, - const char *name, - const struct file_operations *fops) -{ - struct drm_device *dev = minor->dev; - struct drm_info_node *node; - struct dentry *ent; - - ent = debugfs_create_file(name, S_IRUGO | S_IWUSR, root, dev, fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); - - node = kmalloc(sizeof(*node), GFP_KERNEL); - if (!node) { - debugfs_remove(ent); - return -ENOMEM; - } - - node->minor = minor; - node->dent = ent; - node->info_ent = (void *)fops; - - mutex_lock(&minor->debugfs_lock); - list_add(&node->list, &minor->debugfs_list); - mutex_unlock(&minor->debugfs_lock); - - return 0; -} - static int sti_drm_dbg_init(struct drm_minor *minor) { + struct dentry *dentry; int ret; ret = drm_debugfs_create_files(sti_drm_dbg_list, @@ -129,10 +100,13 @@ static int sti_drm_dbg_init(struct drm_minor *minor) if (ret) goto err; - ret = sti_drm_debugfs_create(minor->debugfs_root, minor, "fps_show", + dentry = debugfs_create_file("fps_show", S_IRUGO | S_IWUSR, + minor->debugfs_root, minor->dev, &sti_drm_fps_fops); - if (ret) + if (!dentry) { + ret = -ENOMEM; goto err; + } DRM_INFO("%s: debugfs installed\n", DRIVER_NAME); return 0; @@ -141,15 +115,6 @@ err: return ret; } -static void sti_drm_dbg_cleanup(struct drm_minor *minor) -{ - drm_debugfs_remove_files(sti_drm_dbg_list, - ARRAY_SIZE(sti_drm_dbg_list), minor); - - drm_debugfs_remove_files((struct drm_info_list *)&sti_drm_fps_fops, - 1, minor); -} - static void sti_atomic_schedule(struct sti_private *private, struct drm_atomic_state *state) { @@ -314,7 +279,6 @@ static struct drm_driver sti_driver = { .gem_prime_mmap = drm_gem_cma_prime_mmap, .debugfs_init = sti_drm_dbg_init, - .debugfs_cleanup = sti_drm_dbg_cleanup, .name = DRIVER_NAME, .desc = DRIVER_DESC, diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index 411dc6ec976e..bb23318a44b7 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -195,13 +195,6 @@ static struct drm_info_list dvo_debugfs_files[] = { { "dvo", dvo_dbg_show, 0, NULL }, }; -static void dvo_debugfs_exit(struct sti_dvo *dvo, struct drm_minor *minor) -{ - drm_debugfs_remove_files(dvo_debugfs_files, - ARRAY_SIZE(dvo_debugfs_files), - minor); -} - static int dvo_debugfs_init(struct sti_dvo *dvo, struct drm_minor *minor) { unsigned int i; @@ -514,9 +507,6 @@ static void sti_dvo_unbind(struct device *dev, struct device *master, void *data) { struct sti_dvo *dvo = dev_get_drvdata(dev); - struct drm_device *drm_dev = data; - - dvo_debugfs_exit(dvo, drm_dev->primary); drm_bridge_remove(dvo->bridge); } diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 66d37d78152a..0c0a75bc8bc3 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -365,13 +365,6 @@ static struct drm_info_list hda_debugfs_files[] = { { "hda", hda_dbg_show, 0, NULL }, }; -static void hda_debugfs_exit(struct sti_hda *hda, struct drm_minor *minor) -{ - drm_debugfs_remove_files(hda_debugfs_files, - ARRAY_SIZE(hda_debugfs_files), - minor); -} - static int hda_debugfs_init(struct sti_hda *hda, struct drm_minor *minor) { unsigned int i; @@ -739,10 +732,6 @@ err_sysfs: static void sti_hda_unbind(struct device *dev, struct device *master, void *data) { - struct sti_hda *hda = dev_get_drvdata(dev); - struct drm_device *drm_dev = data; - - hda_debugfs_exit(hda, drm_dev->primary); } static const struct component_ops sti_hda_ops = { diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 5ef1d1fce6d1..c9151849d604 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -731,13 +731,6 @@ static struct drm_info_list hdmi_debugfs_files[] = { { "hdmi", hdmi_dbg_show, 0, NULL }, }; -static void hdmi_debugfs_exit(struct sti_hdmi *hdmi, struct drm_minor *minor) -{ - drm_debugfs_remove_files(hdmi_debugfs_files, - ARRAY_SIZE(hdmi_debugfs_files), - minor); -} - static int hdmi_debugfs_init(struct sti_hdmi *hdmi, struct drm_minor *minor) { unsigned int i; @@ -1356,10 +1349,6 @@ err_sysfs: static void sti_hdmi_unbind(struct device *dev, struct device *master, void *data) { - struct sti_hdmi *hdmi = dev_get_drvdata(dev); - struct drm_device *drm_dev = data; - - hdmi_debugfs_exit(hdmi, drm_dev->primary); } static const struct component_ops sti_hdmi_ops = { diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index ad46d3558d91..8b8ea717c121 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c @@ -567,13 +567,6 @@ static struct drm_info_list tvout_debugfs_files[] = { { "tvout", tvout_dbg_show, 0, NULL }, }; -static void tvout_debugfs_exit(struct sti_tvout *tvout, struct drm_minor *minor) -{ - drm_debugfs_remove_files(tvout_debugfs_files, - ARRAY_SIZE(tvout_debugfs_files), - minor); -} - static int tvout_debugfs_init(struct sti_tvout *tvout, struct drm_minor *minor) { unsigned int i; @@ -627,7 +620,6 @@ static void sti_tvout_early_unregister(struct drm_encoder *encoder) if (!tvout->debugfs_registered) return; - tvout_debugfs_exit(tvout, encoder->dev->primary); tvout->debugfs_registered = false; } diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 2d57f6278db1..ef215fef63d6 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -894,12 +894,6 @@ static int tegra_debugfs_init(struct drm_minor *minor) ARRAY_SIZE(tegra_debugfs_list), minor->debugfs_root, minor); } - -static void tegra_debugfs_cleanup(struct drm_minor *minor) -{ - drm_debugfs_remove_files(tegra_debugfs_list, - ARRAY_SIZE(tegra_debugfs_list), minor); -} #endif static struct drm_driver tegra_drm_driver = { @@ -917,7 +911,6 @@ static struct drm_driver tegra_drm_driver = { #if defined(CONFIG_DEBUG_FS) .debugfs_init = tegra_debugfs_init, - .debugfs_cleanup = tegra_debugfs_cleanup, #endif .gem_free_object_unlocked = tegra_bo_free_object, diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index ec15585c7a27..919294a735fe 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -539,17 +539,6 @@ static int tilcdc_debugfs_init(struct drm_minor *minor) return ret; } - -static void tilcdc_debugfs_cleanup(struct drm_minor *minor) -{ - struct tilcdc_module *mod; - drm_debugfs_remove_files(tilcdc_debugfs_list, - ARRAY_SIZE(tilcdc_debugfs_list), minor); - - list_for_each_entry(mod, &module_list, list) - if (mod->funcs->debugfs_cleanup) - mod->funcs->debugfs_cleanup(mod, minor); -} #endif static const struct file_operations fops = { @@ -589,7 +578,6 @@ static struct drm_driver tilcdc_driver = { .gem_prime_mmap = drm_gem_cma_prime_mmap, #ifdef CONFIG_DEBUG_FS .debugfs_init = tilcdc_debugfs_init, - .debugfs_cleanup = tilcdc_debugfs_cleanup, #endif .fops = &fops, .name = "tilcdc", diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index 0e71daf5b5cb..8caa11bc7aec 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -111,8 +111,6 @@ struct tilcdc_module_ops { #ifdef CONFIG_DEBUG_FS /* create debugfs nodes (can be NULL): */ int (*debugfs_init)(struct tilcdc_module *mod, struct drm_minor *minor); - /* cleanup debugfs nodes (can be NULL): */ - void (*debugfs_cleanup)(struct tilcdc_module *mod, struct drm_minor *minor); #endif }; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index e7ab0264001d..4562e53c8244 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1668,7 +1668,6 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) struct ttm_buffer_object *bo; int ret = -EBUSY; int put_count; - uint32_t swap_placement = (TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM); unsigned i; spin_lock(&glob->lru_lock); @@ -1704,7 +1703,8 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) * Move to system cached */ - if ((bo->mem.placement & swap_placement) != swap_placement) { + if (bo->mem.mem_type != TTM_PL_SYSTEM || + bo->ttm->caching_state != tt_cached) { struct ttm_mem_reg evict_mem; evict_mem = bo->mem; diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c index caf817bac885..c4d5e6a8d6f2 100644 --- a/drivers/gpu/drm/vc4/vc4_debugfs.c +++ b/drivers/gpu/drm/vc4/vc4_debugfs.c @@ -36,9 +36,3 @@ vc4_debugfs_init(struct drm_minor *minor) return drm_debugfs_create_files(vc4_debugfs_list, VC4_DEBUGFS_ENTRIES, minor->debugfs_root, minor); } - -void -vc4_debugfs_cleanup(struct drm_minor *minor) -{ - drm_debugfs_remove_files(vc4_debugfs_list, VC4_DEBUGFS_ENTRIES, minor); -} diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index ac09ca7ff430..e4f42ebee517 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -145,7 +145,6 @@ static struct drm_driver vc4_drm_driver = { #if defined(CONFIG_DEBUG_FS) .debugfs_init = vc4_debugfs_init, - .debugfs_cleanup = vc4_debugfs_cleanup, #endif .gem_create_object = vc4_create_object, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index affcdeb70aa9..78e3e5a43fb0 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -457,7 +457,6 @@ int vc4_crtc_get_vblank_timestamp(struct drm_device *dev, unsigned int crtc_id, /* vc4_debugfs.c */ int vc4_debugfs_init(struct drm_minor *minor); -void vc4_debugfs_cleanup(struct drm_minor *minor); /* vc4_drv.c */ void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index c4cb2e26de32..93d5994f3a04 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -356,15 +356,11 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) return; } - if (vc4_encoder->rgb_range_selectable) { - if (vc4_encoder->limited_rgb_range) { - frame.avi.quantization_range = - HDMI_QUANTIZATION_RANGE_LIMITED; - } else { - frame.avi.quantization_range = - HDMI_QUANTIZATION_RANGE_FULL; - } - } + drm_hdmi_avi_infoframe_quant_range(&frame.avi, mode, + vc4_encoder->limited_rgb_range ? + HDMI_QUANTIZATION_RANGE_LIMITED : + HDMI_QUANTIZATION_RANGE_FULL, + vc4_encoder->rgb_range_selectable); vc4_hdmi_write_infoframe(encoder, &frame); } @@ -463,7 +459,9 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, VC4_HD_CSC_CTL_ORDER); - if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) { + if (vc4_encoder->hdmi_monitor && + drm_default_rgb_quant_range(mode) == + HDMI_QUANTIZATION_RANGE_LIMITED) { /* CEA VICs other than #1 requre limited range RGB * output unless overridden by an AVI infoframe. * Apply a colorspace conversion to squash 0-255 down diff --git a/drivers/gpu/drm/vgem/vgem_fence.c b/drivers/gpu/drm/vgem/vgem_fence.c index da25dfe7b80e..3109c8308eb5 100644 --- a/drivers/gpu/drm/vgem/vgem_fence.c +++ b/drivers/gpu/drm/vgem/vgem_fence.c @@ -190,12 +190,12 @@ int vgem_fence_attach_ioctl(struct drm_device *dev, /* Expose the fence via the dma-buf */ ret = 0; - ww_mutex_lock(&resv->lock, NULL); + reservation_object_lock(resv, NULL); if (arg->flags & VGEM_FENCE_WRITE) reservation_object_add_excl_fence(resv, fence); else if ((ret = reservation_object_reserve_shared(resv)) == 0) reservation_object_add_shared_fence(resv, fence); - ww_mutex_unlock(&resv->lock); + reservation_object_unlock(resv); /* Record the fence in our idr for later signaling */ if (ret == 0) { diff --git a/drivers/gpu/drm/zte/Kconfig b/drivers/gpu/drm/zte/Kconfig index 4065b2840f1c..5b36421ef3e5 100644 --- a/drivers/gpu/drm/zte/Kconfig +++ b/drivers/gpu/drm/zte/Kconfig @@ -4,5 +4,7 @@ config DRM_ZTE select DRM_KMS_CMA_HELPER select DRM_KMS_FB_HELPER select DRM_KMS_HELPER + select SND_SOC_HDMI_CODEC if SND_SOC + select VIDEOMODE_HELPERS help Choose this option to enable DRM on ZTE ZX SoCs. diff --git a/drivers/gpu/drm/zte/Makefile b/drivers/gpu/drm/zte/Makefile index 699180bfd57c..01352b56c418 100644 --- a/drivers/gpu/drm/zte/Makefile +++ b/drivers/gpu/drm/zte/Makefile @@ -2,6 +2,7 @@ zxdrm-y := \ zx_drm_drv.o \ zx_hdmi.o \ zx_plane.o \ + zx_tvenc.o \ zx_vou.o obj-$(CONFIG_DRM_ZTE) += zxdrm.o diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c index 3e76f72c92ff..13081fed902d 100644 --- a/drivers/gpu/drm/zte/zx_drm_drv.c +++ b/drivers/gpu/drm/zte/zx_drm_drv.c @@ -247,6 +247,7 @@ static struct platform_driver zx_drm_platform_driver = { static struct platform_driver *drivers[] = { &zx_crtc_driver, &zx_hdmi_driver, + &zx_tvenc_driver, &zx_drm_platform_driver, }; diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h index e65cd18a6cba..5ca035b079c7 100644 --- a/drivers/gpu/drm/zte/zx_drm_drv.h +++ b/drivers/gpu/drm/zte/zx_drm_drv.h @@ -13,6 +13,7 @@ extern struct platform_driver zx_crtc_driver; extern struct platform_driver zx_hdmi_driver; +extern struct platform_driver zx_tvenc_driver; static inline u32 zx_readl(void __iomem *reg) { diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c index 6bf6c364811e..c47b9cbfe270 100644 --- a/drivers/gpu/drm/zte/zx_hdmi.c +++ b/drivers/gpu/drm/zte/zx_hdmi.c @@ -25,6 +25,8 @@ #include <drm/drm_of.h> #include <drm/drmP.h> +#include <sound/hdmi-codec.h> + #include "zx_hdmi_regs.h" #include "zx_vou.h" @@ -49,17 +51,11 @@ struct zx_hdmi { bool sink_is_hdmi; bool sink_has_audio; const struct vou_inf *inf; + struct platform_device *audio_pdev; }; #define to_zx_hdmi(x) container_of(x, struct zx_hdmi, x) -static const struct vou_inf vou_inf_hdmi = { - .id = VOU_HDMI, - .data_sel = VOU_YUV444, - .clocks_en_bits = BIT(24) | BIT(18) | BIT(6), - .clocks_sel_bits = BIT(13) | BIT(2), -}; - static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset) { return readl_relaxed(hdmi->mmio + offset * 4); @@ -238,14 +234,14 @@ static void zx_hdmi_encoder_enable(struct drm_encoder *encoder) zx_hdmi_hw_enable(hdmi); - vou_inf_enable(hdmi->inf, encoder->crtc); + vou_inf_enable(VOU_HDMI, encoder->crtc); } static void zx_hdmi_encoder_disable(struct drm_encoder *encoder) { struct zx_hdmi *hdmi = to_zx_hdmi(encoder); - vou_inf_disable(hdmi->inf, encoder->crtc); + vou_inf_disable(VOU_HDMI, encoder->crtc); zx_hdmi_hw_disable(hdmi); @@ -366,6 +362,142 @@ static irqreturn_t zx_hdmi_irq_handler(int irq, void *dev_id) return IRQ_NONE; } +static int zx_hdmi_audio_startup(struct device *dev, void *data) +{ + struct zx_hdmi *hdmi = dev_get_drvdata(dev); + struct drm_encoder *encoder = &hdmi->encoder; + + vou_inf_hdmi_audio_sel(encoder->crtc, VOU_HDMI_AUD_SPDIF); + + return 0; +} + +static void zx_hdmi_audio_shutdown(struct device *dev, void *data) +{ + struct zx_hdmi *hdmi = dev_get_drvdata(dev); + + /* Disable audio input */ + hdmi_writeb_mask(hdmi, AUD_EN, AUD_IN_EN, 0); +} + +static inline int zx_hdmi_audio_get_n(unsigned int fs) +{ + unsigned int n; + + if (fs && (fs % 44100) == 0) + n = 6272 * (fs / 44100); + else + n = fs * 128 / 1000; + + return n; +} + +static int zx_hdmi_audio_hw_params(struct device *dev, + void *data, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct zx_hdmi *hdmi = dev_get_drvdata(dev); + struct hdmi_audio_infoframe *cea = ¶ms->cea; + union hdmi_infoframe frame; + int n; + + /* We only support spdif for now */ + if (daifmt->fmt != HDMI_SPDIF) { + DRM_DEV_ERROR(hdmi->dev, "invalid daifmt %d\n", daifmt->fmt); + return -EINVAL; + } + + switch (params->sample_width) { + case 16: + hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, SPDIF_SAMPLE_SIZE_MASK, + SPDIF_SAMPLE_SIZE_16BIT); + break; + case 20: + hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, SPDIF_SAMPLE_SIZE_MASK, + SPDIF_SAMPLE_SIZE_20BIT); + break; + case 24: + hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, SPDIF_SAMPLE_SIZE_MASK, + SPDIF_SAMPLE_SIZE_24BIT); + break; + default: + DRM_DEV_ERROR(hdmi->dev, "invalid sample width %d\n", + params->sample_width); + return -EINVAL; + } + + /* CTS is calculated by hardware, and we only need to take care of N */ + n = zx_hdmi_audio_get_n(params->sample_rate); + hdmi_writeb(hdmi, N_SVAL1, n & 0xff); + hdmi_writeb(hdmi, N_SVAL2, (n >> 8) & 0xff); + hdmi_writeb(hdmi, N_SVAL3, (n >> 16) & 0xf); + + /* Enable spdif mode */ + hdmi_writeb_mask(hdmi, AUD_MODE, SPDIF_EN, SPDIF_EN); + + /* Enable audio input */ + hdmi_writeb_mask(hdmi, AUD_EN, AUD_IN_EN, AUD_IN_EN); + + memcpy(&frame.audio, cea, sizeof(*cea)); + + return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_AUDIO); +} + +static int zx_hdmi_audio_digital_mute(struct device *dev, void *data, + bool enable) +{ + struct zx_hdmi *hdmi = dev_get_drvdata(dev); + + if (enable) + hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, TPI_AUD_MUTE, + TPI_AUD_MUTE); + else + hdmi_writeb_mask(hdmi, TPI_AUD_CONFIG, TPI_AUD_MUTE, 0); + + return 0; +} + +static int zx_hdmi_audio_get_eld(struct device *dev, void *data, + uint8_t *buf, size_t len) +{ + struct zx_hdmi *hdmi = dev_get_drvdata(dev); + struct drm_connector *connector = &hdmi->connector; + + memcpy(buf, connector->eld, min(sizeof(connector->eld), len)); + + return 0; +} + +static const struct hdmi_codec_ops zx_hdmi_codec_ops = { + .audio_startup = zx_hdmi_audio_startup, + .hw_params = zx_hdmi_audio_hw_params, + .audio_shutdown = zx_hdmi_audio_shutdown, + .digital_mute = zx_hdmi_audio_digital_mute, + .get_eld = zx_hdmi_audio_get_eld, +}; + +static struct hdmi_codec_pdata zx_hdmi_codec_pdata = { + .ops = &zx_hdmi_codec_ops, + .spdif = 1, +}; + +static int zx_hdmi_audio_register(struct zx_hdmi *hdmi) +{ + struct platform_device *pdev; + + pdev = platform_device_register_data(hdmi->dev, HDMI_CODEC_DRV_NAME, + PLATFORM_DEVID_AUTO, + &zx_hdmi_codec_pdata, + sizeof(zx_hdmi_codec_pdata)); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + hdmi->audio_pdev = pdev; + + return 0; +} + static int zx_hdmi_i2c_read(struct zx_hdmi *hdmi, struct i2c_msg *msg) { int len = msg->len; @@ -523,7 +655,6 @@ static int zx_hdmi_bind(struct device *dev, struct device *master, void *data) hdmi->dev = dev; hdmi->drm = drm; - hdmi->inf = &vou_inf_hdmi; dev_set_drvdata(dev, hdmi); @@ -566,6 +697,12 @@ static int zx_hdmi_bind(struct device *dev, struct device *master, void *data) return ret; } + ret = zx_hdmi_audio_register(hdmi); + if (ret) { + DRM_DEV_ERROR(dev, "failed to register audio: %d\n", ret); + return ret; + } + ret = zx_hdmi_register(drm, hdmi); if (ret) { DRM_DEV_ERROR(dev, "failed to register hdmi: %d\n", ret); @@ -590,6 +727,9 @@ static void zx_hdmi_unbind(struct device *dev, struct device *master, hdmi->connector.funcs->destroy(&hdmi->connector); hdmi->encoder.funcs->destroy(&hdmi->encoder); + + if (hdmi->audio_pdev) + platform_device_unregister(hdmi->audio_pdev); } static const struct component_ops zx_hdmi_component_ops = { diff --git a/drivers/gpu/drm/zte/zx_hdmi_regs.h b/drivers/gpu/drm/zte/zx_hdmi_regs.h index de911f66b658..c6d5d8211725 100644 --- a/drivers/gpu/drm/zte/zx_hdmi_regs.h +++ b/drivers/gpu/drm/zte/zx_hdmi_regs.h @@ -52,5 +52,19 @@ #define TPI_INFO_TRANS_RPT BIT(6) #define TPI_DDC_MASTER_EN 0x06f8 #define HW_DDC_MASTER BIT(7) +#define N_SVAL1 0xa03 +#define N_SVAL2 0xa04 +#define N_SVAL3 0xa05 +#define AUD_EN 0xa13 +#define AUD_IN_EN BIT(0) +#define AUD_MODE 0xa14 +#define SPDIF_EN BIT(1) +#define TPI_AUD_CONFIG 0xa62 +#define SPDIF_SAMPLE_SIZE_SHIFT 6 +#define SPDIF_SAMPLE_SIZE_MASK (0x3 << SPDIF_SAMPLE_SIZE_SHIFT) +#define SPDIF_SAMPLE_SIZE_16BIT (0x1 << SPDIF_SAMPLE_SIZE_SHIFT) +#define SPDIF_SAMPLE_SIZE_20BIT (0x2 << SPDIF_SAMPLE_SIZE_SHIFT) +#define SPDIF_SAMPLE_SIZE_24BIT (0x3 << SPDIF_SAMPLE_SIZE_SHIFT) +#define TPI_AUD_MUTE BIT(4) #endif /* __ZX_HDMI_REGS_H__ */ diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c index b634b090cdc1..1d08ba381098 100644 --- a/drivers/gpu/drm/zte/zx_plane.c +++ b/drivers/gpu/drm/zte/zx_plane.c @@ -21,16 +21,6 @@ #include "zx_plane_regs.h" #include "zx_vou.h" -struct zx_plane { - struct drm_plane plane; - void __iomem *layer; - void __iomem *csc; - void __iomem *hbsc; - void __iomem *rsz; -}; - -#define to_zx_plane(plane) container_of(plane, struct zx_plane, plane) - static const uint32_t gl_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, @@ -40,6 +30,261 @@ static const uint32_t gl_formats[] = { DRM_FORMAT_ARGB4444, }; +static const uint32_t vl_formats[] = { + DRM_FORMAT_NV12, /* Semi-planar YUV420 */ + DRM_FORMAT_YUV420, /* Planar YUV420 */ + DRM_FORMAT_YUYV, /* Packed YUV422 */ + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_YUV444, /* YUV444 8bit */ + /* + * TODO: add formats below that HW supports: + * - YUV420 P010 + * - YUV420 Hantro + * - YUV444 10bit + */ +}; + +#define FRAC_16_16(mult, div) (((mult) << 16) / (div)) + +static int zx_vl_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *plane_state) +{ + struct drm_framebuffer *fb = plane_state->fb; + struct drm_crtc *crtc = plane_state->crtc; + struct drm_crtc_state *crtc_state; + struct drm_rect clip; + int min_scale = FRAC_16_16(1, 8); + int max_scale = FRAC_16_16(8, 1); + + if (!crtc || !fb) + return 0; + + crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state, + crtc); + if (WARN_ON(!crtc_state)) + return -EINVAL; + + /* nothing to check when disabling or disabled */ + if (!crtc_state->enable) + return 0; + + /* plane must be enabled */ + if (!plane_state->crtc) + return -EINVAL; + + clip.x1 = 0; + clip.y1 = 0; + clip.x2 = crtc_state->adjusted_mode.hdisplay; + clip.y2 = crtc_state->adjusted_mode.vdisplay; + + return drm_plane_helper_check_state(plane_state, &clip, + min_scale, max_scale, + true, true); +} + +static int zx_vl_get_fmt(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_NV12: + return VL_FMT_YUV420; + case DRM_FORMAT_YUV420: + return VL_YUV420_PLANAR | VL_FMT_YUV420; + case DRM_FORMAT_YUYV: + return VL_YUV422_YUYV | VL_FMT_YUV422; + case DRM_FORMAT_YVYU: + return VL_YUV422_YVYU | VL_FMT_YUV422; + case DRM_FORMAT_UYVY: + return VL_YUV422_UYVY | VL_FMT_YUV422; + case DRM_FORMAT_VYUY: + return VL_YUV422_VYUY | VL_FMT_YUV422; + case DRM_FORMAT_YUV444: + return VL_FMT_YUV444_8BIT; + default: + WARN_ONCE(1, "invalid pixel format %d\n", format); + return -EINVAL; + } +} + +static inline void zx_vl_set_update(struct zx_plane *zplane) +{ + void __iomem *layer = zplane->layer; + + zx_writel_mask(layer + VL_CTRL0, VL_UPDATE, VL_UPDATE); +} + +static inline void zx_vl_rsz_set_update(struct zx_plane *zplane) +{ + zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1); +} + +static int zx_vl_rsz_get_fmt(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_YUV420: + return RSZ_VL_FMT_YCBCR420; + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + return RSZ_VL_FMT_YCBCR422; + case DRM_FORMAT_YUV444: + return RSZ_VL_FMT_YCBCR444; + default: + WARN_ONCE(1, "invalid pixel format %d\n", format); + return -EINVAL; + } +} + +static inline u32 rsz_step_value(u32 src, u32 dst) +{ + u32 val = 0; + + if (src == dst) + val = 0; + else if (src < dst) + val = RSZ_PARA_STEP((src << 16) / dst); + else if (src > dst) + val = RSZ_DATA_STEP(src / dst) | + RSZ_PARA_STEP(((src << 16) / dst) & 0xffff); + + return val; +} + +static void zx_vl_rsz_setup(struct zx_plane *zplane, uint32_t format, + u32 src_w, u32 src_h, u32 dst_w, u32 dst_h) +{ + void __iomem *rsz = zplane->rsz; + u32 src_chroma_w = src_w; + u32 src_chroma_h = src_h; + u32 fmt; + + /* Set up source and destination resolution */ + zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1)); + zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1)); + + /* Configure data format for VL RSZ */ + fmt = zx_vl_rsz_get_fmt(format); + if (fmt >= 0) + zx_writel_mask(rsz + RSZ_VL_CTRL_CFG, RSZ_VL_FMT_MASK, fmt); + + /* Calculate Chroma height and width */ + if (fmt == RSZ_VL_FMT_YCBCR420) { + src_chroma_w = src_w >> 1; + src_chroma_h = src_h >> 1; + } else if (fmt == RSZ_VL_FMT_YCBCR422) { + src_chroma_w = src_w >> 1; + } + + /* Set up Luma and Chroma step registers */ + zx_writel(rsz + RSZ_VL_LUMA_HOR, rsz_step_value(src_w, dst_w)); + zx_writel(rsz + RSZ_VL_LUMA_VER, rsz_step_value(src_h, dst_h)); + zx_writel(rsz + RSZ_VL_CHROMA_HOR, rsz_step_value(src_chroma_w, dst_w)); + zx_writel(rsz + RSZ_VL_CHROMA_VER, rsz_step_value(src_chroma_h, dst_h)); + + zx_vl_rsz_set_update(zplane); +} + +static void zx_vl_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct zx_plane *zplane = to_zx_plane(plane); + struct drm_plane_state *state = plane->state; + struct drm_framebuffer *fb = state->fb; + struct drm_rect *src = &state->src; + struct drm_rect *dst = &state->dst; + struct drm_gem_cma_object *cma_obj; + void __iomem *layer = zplane->layer; + void __iomem *hbsc = zplane->hbsc; + void __iomem *paddr_reg; + dma_addr_t paddr; + u32 src_x, src_y, src_w, src_h; + u32 dst_x, dst_y, dst_w, dst_h; + uint32_t format; + u32 fmt; + int num_planes; + int i; + + if (!fb) + return; + + format = fb->format->format; + + src_x = src->x1 >> 16; + src_y = src->y1 >> 16; + src_w = drm_rect_width(src) >> 16; + src_h = drm_rect_height(src) >> 16; + + dst_x = dst->x1; + dst_y = dst->y1; + dst_w = drm_rect_width(dst); + dst_h = drm_rect_height(dst); + + /* Set up data address registers for Y, Cb and Cr planes */ + num_planes = drm_format_num_planes(format); + paddr_reg = layer + VL_Y; + for (i = 0; i < num_planes; i++) { + cma_obj = drm_fb_cma_get_gem_obj(fb, i); + paddr = cma_obj->paddr + fb->offsets[i]; + paddr += src_y * fb->pitches[i]; + paddr += src_x * drm_format_plane_cpp(format, i); + zx_writel(paddr_reg, paddr); + paddr_reg += 4; + } + + /* Set up source height/width register */ + zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h)); + + /* Set up start position register */ + zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y)); + + /* Set up end position register */ + zx_writel(layer + VL_POS_END, + GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h)); + + /* Strides of Cb and Cr planes should be identical */ + zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) | + CHROMA_STRIDE(fb->pitches[1])); + + /* Set up video layer data format */ + fmt = zx_vl_get_fmt(format); + if (fmt >= 0) + zx_writel(layer + VL_CTRL1, fmt); + + /* Always use scaler since it exists (set for not bypass) */ + zx_writel_mask(layer + VL_CTRL2, VL_SCALER_BYPASS_MODE, + VL_SCALER_BYPASS_MODE); + + zx_vl_rsz_setup(zplane, format, src_w, src_h, dst_w, dst_h); + + /* Enable HBSC block */ + zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN); + + zx_vou_layer_enable(plane); + + zx_vl_set_update(zplane); +} + +static void zx_plane_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct zx_plane *zplane = to_zx_plane(plane); + void __iomem *hbsc = zplane->hbsc; + + zx_vou_layer_disable(plane); + + /* Disable HBSC block */ + zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0); +} + +static const struct drm_plane_helper_funcs zx_vl_plane_helper_funcs = { + .atomic_check = zx_vl_plane_atomic_check, + .atomic_update = zx_vl_plane_atomic_update, + .atomic_disable = zx_plane_atomic_disable, +}; + static int zx_gl_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *plane_state) { @@ -107,14 +352,6 @@ static inline void zx_gl_rsz_set_update(struct zx_plane *zplane) zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1); } -void zx_plane_set_update(struct drm_plane *plane) -{ - struct zx_plane *zplane = to_zx_plane(plane); - - zx_gl_rsz_set_update(zplane); - zx_gl_set_update(zplane); -} - static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h, u32 dst_w, u32 dst_h) { @@ -207,12 +444,15 @@ static void zx_gl_plane_atomic_update(struct drm_plane *plane, /* Enable HBSC block */ zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN); + zx_vou_layer_enable(plane); + zx_gl_set_update(zplane); } static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = { .atomic_check = zx_gl_plane_atomic_check, .atomic_update = zx_gl_plane_atomic_update, + .atomic_disable = zx_plane_atomic_disable, }; static void zx_plane_destroy(struct drm_plane *plane) @@ -230,6 +470,28 @@ static const struct drm_plane_funcs zx_plane_funcs = { .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; +void zx_plane_set_update(struct drm_plane *plane) +{ + struct zx_plane *zplane = to_zx_plane(plane); + + /* Do nothing if the plane is not enabled */ + if (!plane->state->crtc) + return; + + switch (plane->type) { + case DRM_PLANE_TYPE_PRIMARY: + zx_gl_rsz_set_update(zplane); + zx_gl_set_update(zplane); + break; + case DRM_PLANE_TYPE_OVERLAY: + zx_vl_rsz_set_update(zplane); + zx_vl_set_update(zplane); + break; + default: + WARN_ONCE(1, "unsupported plane type %d\n", plane->type); + } +} + static void zx_plane_hbsc_init(struct zx_plane *zplane) { void __iomem *hbsc = zplane->hbsc; @@ -248,28 +510,16 @@ static void zx_plane_hbsc_init(struct zx_plane *zplane) zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40); } -struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev, - struct zx_layer_data *data, - enum drm_plane_type type) +int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane, + enum drm_plane_type type) { const struct drm_plane_helper_funcs *helper; - struct zx_plane *zplane; - struct drm_plane *plane; + struct drm_plane *plane = &zplane->plane; + struct device *dev = zplane->dev; const uint32_t *formats; unsigned int format_count; int ret; - zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL); - if (!zplane) - return ERR_PTR(-ENOMEM); - - plane = &zplane->plane; - - zplane->layer = data->layer; - zplane->hbsc = data->hbsc; - zplane->csc = data->csc; - zplane->rsz = data->rsz; - zx_plane_hbsc_init(zplane); switch (type) { @@ -279,10 +529,12 @@ struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev, format_count = ARRAY_SIZE(gl_formats); break; case DRM_PLANE_TYPE_OVERLAY: - /* TODO: add video layer (vl) support */ + helper = &zx_vl_plane_helper_funcs; + formats = vl_formats; + format_count = ARRAY_SIZE(vl_formats); break; default: - return ERR_PTR(-ENODEV); + return -ENODEV; } ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK, @@ -290,10 +542,10 @@ struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev, type, NULL); if (ret) { DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret); - return ERR_PTR(ret); + return ret; } drm_plane_helper_add(plane, helper); - return plane; + return 0; } diff --git a/drivers/gpu/drm/zte/zx_plane.h b/drivers/gpu/drm/zte/zx_plane.h index 2b82cd558d9d..933611ddffd0 100644 --- a/drivers/gpu/drm/zte/zx_plane.h +++ b/drivers/gpu/drm/zte/zx_plane.h @@ -11,16 +11,20 @@ #ifndef __ZX_PLANE_H__ #define __ZX_PLANE_H__ -struct zx_layer_data { +struct zx_plane { + struct drm_plane plane; + struct device *dev; void __iomem *layer; void __iomem *csc; void __iomem *hbsc; void __iomem *rsz; + const struct vou_layer_bits *bits; }; -struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev, - struct zx_layer_data *data, - enum drm_plane_type type); +#define to_zx_plane(plane) container_of(plane, struct zx_plane, plane) + +int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane, + enum drm_plane_type type); void zx_plane_set_update(struct drm_plane *plane); #endif /* __ZX_PLANE_H__ */ diff --git a/drivers/gpu/drm/zte/zx_plane_regs.h b/drivers/gpu/drm/zte/zx_plane_regs.h index 3dde6716a558..65f271aeabed 100644 --- a/drivers/gpu/drm/zte/zx_plane_regs.h +++ b/drivers/gpu/drm/zte/zx_plane_regs.h @@ -46,6 +46,37 @@ #define GL_POS_X(x) (((x) << GL_POS_X_SHIFT) & GL_POS_X_MASK) #define GL_POS_Y(x) (((x) << GL_POS_Y_SHIFT) & GL_POS_Y_MASK) +/* VL registers */ +#define VL_CTRL0 0x00 +#define VL_UPDATE BIT(3) +#define VL_CTRL1 0x04 +#define VL_YUV420_PLANAR BIT(5) +#define VL_YUV422_SHIFT 3 +#define VL_YUV422_YUYV (0 << VL_YUV422_SHIFT) +#define VL_YUV422_YVYU (1 << VL_YUV422_SHIFT) +#define VL_YUV422_UYVY (2 << VL_YUV422_SHIFT) +#define VL_YUV422_VYUY (3 << VL_YUV422_SHIFT) +#define VL_FMT_YUV420 0 +#define VL_FMT_YUV422 1 +#define VL_FMT_YUV420_P010 2 +#define VL_FMT_YUV420_HANTRO 3 +#define VL_FMT_YUV444_8BIT 4 +#define VL_FMT_YUV444_10BIT 5 +#define VL_CTRL2 0x08 +#define VL_SCALER_BYPASS_MODE BIT(0) +#define VL_STRIDE 0x0c +#define LUMA_STRIDE_SHIFT 16 +#define LUMA_STRIDE_MASK (0xffff << LUMA_STRIDE_SHIFT) +#define CHROMA_STRIDE_SHIFT 0 +#define CHROMA_STRIDE_MASK (0xffff << CHROMA_STRIDE_SHIFT) +#define VL_SRC_SIZE 0x10 +#define VL_Y 0x14 +#define VL_POS_START 0x30 +#define VL_POS_END 0x34 + +#define LUMA_STRIDE(x) (((x) << LUMA_STRIDE_SHIFT) & LUMA_STRIDE_MASK) +#define CHROMA_STRIDE(x) (((x) << CHROMA_STRIDE_SHIFT) & CHROMA_STRIDE_MASK) + /* CSC registers */ #define CSC_CTRL0 0x30 #define CSC_COV_MODE_SHIFT 16 @@ -69,6 +100,18 @@ #define RSZ_DEST_CFG 0x04 #define RSZ_ENABLE_CFG 0x14 +#define RSZ_VL_LUMA_HOR 0x08 +#define RSZ_VL_LUMA_VER 0x0c +#define RSZ_VL_CHROMA_HOR 0x10 +#define RSZ_VL_CHROMA_VER 0x14 +#define RSZ_VL_CTRL_CFG 0x18 +#define RSZ_VL_FMT_SHIFT 3 +#define RSZ_VL_FMT_MASK (0x3 << RSZ_VL_FMT_SHIFT) +#define RSZ_VL_FMT_YCBCR420 (0x0 << RSZ_VL_FMT_SHIFT) +#define RSZ_VL_FMT_YCBCR422 (0x1 << RSZ_VL_FMT_SHIFT) +#define RSZ_VL_FMT_YCBCR444 (0x2 << RSZ_VL_FMT_SHIFT) +#define RSZ_VL_ENABLE_CFG 0x1c + #define RSZ_VER_SHIFT 16 #define RSZ_VER_MASK (0xffff << RSZ_VER_SHIFT) #define RSZ_HOR_SHIFT 0 @@ -77,6 +120,14 @@ #define RSZ_VER(x) (((x) << RSZ_VER_SHIFT) & RSZ_VER_MASK) #define RSZ_HOR(x) (((x) << RSZ_HOR_SHIFT) & RSZ_HOR_MASK) +#define RSZ_DATA_STEP_SHIFT 16 +#define RSZ_DATA_STEP_MASK (0xffff << RSZ_DATA_STEP_SHIFT) +#define RSZ_PARA_STEP_SHIFT 0 +#define RSZ_PARA_STEP_MASK (0xffff << RSZ_PARA_STEP_SHIFT) + +#define RSZ_DATA_STEP(x) (((x) << RSZ_DATA_STEP_SHIFT) & RSZ_DATA_STEP_MASK) +#define RSZ_PARA_STEP(x) (((x) << RSZ_PARA_STEP_SHIFT) & RSZ_PARA_STEP_MASK) + /* HBSC registers */ #define HBSC_SATURATION 0x00 #define HBSC_HUE 0x04 diff --git a/drivers/gpu/drm/zte/zx_tvenc.c b/drivers/gpu/drm/zte/zx_tvenc.c new file mode 100644 index 000000000000..b56dc69843fc --- /dev/null +++ b/drivers/gpu/drm/zte/zx_tvenc.c @@ -0,0 +1,407 @@ +/* + * Copyright 2017 Linaro Ltd. + * Copyright 2017 ZTE Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/clk.h> +#include <linux/component.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drmP.h> + +#include "zx_drm_drv.h" +#include "zx_tvenc_regs.h" +#include "zx_vou.h" + +struct zx_tvenc_pwrctrl { + struct regmap *regmap; + u32 reg; + u32 mask; +}; + +struct zx_tvenc { + struct drm_connector connector; + struct drm_encoder encoder; + struct device *dev; + void __iomem *mmio; + const struct vou_inf *inf; + struct zx_tvenc_pwrctrl pwrctrl; +}; + +#define to_zx_tvenc(x) container_of(x, struct zx_tvenc, x) + +struct zx_tvenc_mode { + struct drm_display_mode mode; + u32 video_info; + u32 video_res; + u32 field1_param; + u32 field2_param; + u32 burst_line_odd1; + u32 burst_line_even1; + u32 burst_line_odd2; + u32 burst_line_even2; + u32 line_timing_param; + u32 weight_value; + u32 blank_black_level; + u32 burst_level; + u32 control_param; + u32 sub_carrier_phase1; + u32 phase_line_incr_cvbs; +}; + +/* + * The CRM cannot directly provide a suitable frequency, and we have to + * ask a multiplied rate from CRM and use the divider in VOU to get the + * desired one. + */ +#define TVENC_CLOCK_MULTIPLIER 4 + +static const struct zx_tvenc_mode tvenc_mode_pal = { + .mode = { + .clock = 13500 * TVENC_CLOCK_MULTIPLIER, + .hdisplay = 720, + .hsync_start = 720 + 12, + .hsync_end = 720 + 12 + 2, + .htotal = 720 + 12 + 2 + 130, + .vdisplay = 576, + .vsync_start = 576 + 2, + .vsync_end = 576 + 2 + 2, + .vtotal = 576 + 2 + 2 + 20, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE, + }, + .video_info = 0x00040040, + .video_res = 0x05a9c760, + .field1_param = 0x0004d416, + .field2_param = 0x0009b94f, + .burst_line_odd1 = 0x0004d406, + .burst_line_even1 = 0x0009b53e, + .burst_line_odd2 = 0x0004d805, + .burst_line_even2 = 0x0009b93f, + .line_timing_param = 0x06a96fdf, + .weight_value = 0x00c188a0, + .blank_black_level = 0x0000fcfc, + .burst_level = 0x00001595, + .control_param = 0x00000001, + .sub_carrier_phase1 = 0x1504c566, + .phase_line_incr_cvbs = 0xc068db8c, +}; + +static const struct zx_tvenc_mode tvenc_mode_ntsc = { + .mode = { + .clock = 13500 * TVENC_CLOCK_MULTIPLIER, + .hdisplay = 720, + .hsync_start = 720 + 16, + .hsync_end = 720 + 16 + 2, + .htotal = 720 + 16 + 2 + 120, + .vdisplay = 480, + .vsync_start = 480 + 3, + .vsync_end = 480 + 3 + 2, + .vtotal = 480 + 3 + 2 + 17, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | + DRM_MODE_FLAG_INTERLACE, + }, + .video_info = 0x00040080, + .video_res = 0x05a8375a, + .field1_param = 0x00041817, + .field2_param = 0x0008351e, + .burst_line_odd1 = 0x00041006, + .burst_line_even1 = 0x0008290d, + .burst_line_odd2 = 0x00000000, + .burst_line_even2 = 0x00000000, + .line_timing_param = 0x06a8ef9e, + .weight_value = 0x00b68197, + .blank_black_level = 0x0000f0f0, + .burst_level = 0x0000009c, + .control_param = 0x00000001, + .sub_carrier_phase1 = 0x10f83e10, + .phase_line_incr_cvbs = 0x80000000, +}; + +static const struct zx_tvenc_mode *tvenc_modes[] = { + &tvenc_mode_pal, + &tvenc_mode_ntsc, +}; + +static const struct zx_tvenc_mode * +zx_tvenc_find_zmode(struct drm_display_mode *mode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tvenc_modes); i++) { + const struct zx_tvenc_mode *zmode = tvenc_modes[i]; + + if (drm_mode_equal(mode, &zmode->mode)) + return zmode; + } + + return NULL; +} + +static void zx_tvenc_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + struct zx_tvenc *tvenc = to_zx_tvenc(encoder); + const struct zx_tvenc_mode *zmode; + struct vou_div_config configs[] = { + { VOU_DIV_INF, VOU_DIV_4 }, + { VOU_DIV_TVENC, VOU_DIV_1 }, + { VOU_DIV_LAYER, VOU_DIV_2 }, + }; + + zx_vou_config_dividers(encoder->crtc, configs, ARRAY_SIZE(configs)); + + zmode = zx_tvenc_find_zmode(mode); + if (!zmode) { + DRM_DEV_ERROR(tvenc->dev, "failed to find zmode\n"); + return; + } + + zx_writel(tvenc->mmio + VENC_VIDEO_INFO, zmode->video_info); + zx_writel(tvenc->mmio + VENC_VIDEO_RES, zmode->video_res); + zx_writel(tvenc->mmio + VENC_FIELD1_PARAM, zmode->field1_param); + zx_writel(tvenc->mmio + VENC_FIELD2_PARAM, zmode->field2_param); + zx_writel(tvenc->mmio + VENC_LINE_O_1, zmode->burst_line_odd1); + zx_writel(tvenc->mmio + VENC_LINE_E_1, zmode->burst_line_even1); + zx_writel(tvenc->mmio + VENC_LINE_O_2, zmode->burst_line_odd2); + zx_writel(tvenc->mmio + VENC_LINE_E_2, zmode->burst_line_even2); + zx_writel(tvenc->mmio + VENC_LINE_TIMING_PARAM, + zmode->line_timing_param); + zx_writel(tvenc->mmio + VENC_WEIGHT_VALUE, zmode->weight_value); + zx_writel(tvenc->mmio + VENC_BLANK_BLACK_LEVEL, + zmode->blank_black_level); + zx_writel(tvenc->mmio + VENC_BURST_LEVEL, zmode->burst_level); + zx_writel(tvenc->mmio + VENC_CONTROL_PARAM, zmode->control_param); + zx_writel(tvenc->mmio + VENC_SUB_CARRIER_PHASE1, + zmode->sub_carrier_phase1); + zx_writel(tvenc->mmio + VENC_PHASE_LINE_INCR_CVBS, + zmode->phase_line_incr_cvbs); +} + +static void zx_tvenc_encoder_enable(struct drm_encoder *encoder) +{ + struct zx_tvenc *tvenc = to_zx_tvenc(encoder); + struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl; + + /* Set bit to power up TVENC DAC */ + regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask, + pwrctrl->mask); + + vou_inf_enable(VOU_TV_ENC, encoder->crtc); + + zx_writel(tvenc->mmio + VENC_ENABLE, 1); +} + +static void zx_tvenc_encoder_disable(struct drm_encoder *encoder) +{ + struct zx_tvenc *tvenc = to_zx_tvenc(encoder); + struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl; + + zx_writel(tvenc->mmio + VENC_ENABLE, 0); + + vou_inf_disable(VOU_TV_ENC, encoder->crtc); + + /* Clear bit to power down TVENC DAC */ + regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask, 0); +} + +static const struct drm_encoder_helper_funcs zx_tvenc_encoder_helper_funcs = { + .enable = zx_tvenc_encoder_enable, + .disable = zx_tvenc_encoder_disable, + .mode_set = zx_tvenc_encoder_mode_set, +}; + +static const struct drm_encoder_funcs zx_tvenc_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static int zx_tvenc_connector_get_modes(struct drm_connector *connector) +{ + struct zx_tvenc *tvenc = to_zx_tvenc(connector); + struct device *dev = tvenc->dev; + int i; + + for (i = 0; i < ARRAY_SIZE(tvenc_modes); i++) { + const struct zx_tvenc_mode *zmode = tvenc_modes[i]; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &zmode->mode); + if (!mode) { + DRM_DEV_ERROR(dev, "failed to duplicate drm mode\n"); + continue; + } + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + } + + return i; +} + +static enum drm_mode_status +zx_tvenc_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct zx_tvenc *tvenc = to_zx_tvenc(connector); + const struct zx_tvenc_mode *zmode; + + zmode = zx_tvenc_find_zmode(mode); + if (!zmode) { + DRM_DEV_ERROR(tvenc->dev, "unsupported mode: %s\n", mode->name); + return MODE_NOMODE; + } + + return MODE_OK; +} + +static struct drm_connector_helper_funcs zx_tvenc_connector_helper_funcs = { + .get_modes = zx_tvenc_connector_get_modes, + .mode_valid = zx_tvenc_connector_mode_valid, +}; + +static const struct drm_connector_funcs zx_tvenc_connector_funcs = { + .dpms = drm_atomic_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int zx_tvenc_register(struct drm_device *drm, struct zx_tvenc *tvenc) +{ + struct drm_encoder *encoder = &tvenc->encoder; + struct drm_connector *connector = &tvenc->connector; + + /* + * The tvenc is designed to use aux channel, as there is a deflicker + * block for the channel. + */ + encoder->possible_crtcs = BIT(1); + + drm_encoder_init(drm, encoder, &zx_tvenc_encoder_funcs, + DRM_MODE_ENCODER_TVDAC, NULL); + drm_encoder_helper_add(encoder, &zx_tvenc_encoder_helper_funcs); + + connector->interlace_allowed = true; + + drm_connector_init(drm, connector, &zx_tvenc_connector_funcs, + DRM_MODE_CONNECTOR_Composite); + drm_connector_helper_add(connector, &zx_tvenc_connector_helper_funcs); + + drm_mode_connector_attach_encoder(connector, encoder); + + return 0; +} + +static int zx_tvenc_pwrctrl_init(struct zx_tvenc *tvenc) +{ + struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl; + struct device *dev = tvenc->dev; + struct of_phandle_args out_args; + struct regmap *regmap; + int ret; + + ret = of_parse_phandle_with_fixed_args(dev->of_node, + "zte,tvenc-power-control", 2, 0, &out_args); + if (ret) + return ret; + + regmap = syscon_node_to_regmap(out_args.np); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto out; + } + + pwrctrl->regmap = regmap; + pwrctrl->reg = out_args.args[0]; + pwrctrl->mask = out_args.args[1]; + +out: + of_node_put(out_args.np); + return ret; +} + +static int zx_tvenc_bind(struct device *dev, struct device *master, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = data; + struct resource *res; + struct zx_tvenc *tvenc; + int ret; + + tvenc = devm_kzalloc(dev, sizeof(*tvenc), GFP_KERNEL); + if (!tvenc) + return -ENOMEM; + + tvenc->dev = dev; + dev_set_drvdata(dev, tvenc); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + tvenc->mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(tvenc->mmio)) { + ret = PTR_ERR(tvenc->mmio); + DRM_DEV_ERROR(dev, "failed to remap tvenc region: %d\n", ret); + return ret; + } + + ret = zx_tvenc_pwrctrl_init(tvenc); + if (ret) { + DRM_DEV_ERROR(dev, "failed to init power control: %d\n", ret); + return ret; + } + + ret = zx_tvenc_register(drm, tvenc); + if (ret) { + DRM_DEV_ERROR(dev, "failed to register tvenc: %d\n", ret); + return ret; + } + + return 0; +} + +static void zx_tvenc_unbind(struct device *dev, struct device *master, + void *data) +{ + /* Nothing to do */ +} + +static const struct component_ops zx_tvenc_component_ops = { + .bind = zx_tvenc_bind, + .unbind = zx_tvenc_unbind, +}; + +static int zx_tvenc_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &zx_tvenc_component_ops); +} + +static int zx_tvenc_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &zx_tvenc_component_ops); + return 0; +} + +static const struct of_device_id zx_tvenc_of_match[] = { + { .compatible = "zte,zx296718-tvenc", }, + { /* end */ }, +}; +MODULE_DEVICE_TABLE(of, zx_tvenc_of_match); + +struct platform_driver zx_tvenc_driver = { + .probe = zx_tvenc_probe, + .remove = zx_tvenc_remove, + .driver = { + .name = "zx-tvenc", + .of_match_table = zx_tvenc_of_match, + }, +}; diff --git a/drivers/gpu/drm/zte/zx_tvenc_regs.h b/drivers/gpu/drm/zte/zx_tvenc_regs.h new file mode 100644 index 000000000000..bd91f5dcc1f3 --- /dev/null +++ b/drivers/gpu/drm/zte/zx_tvenc_regs.h @@ -0,0 +1,31 @@ +/* + * Copyright 2017 Linaro Ltd. + * Copyright 2017 ZTE Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __ZX_TVENC_REGS_H__ +#define __ZX_TVENC_REGS_H__ + +#define VENC_VIDEO_INFO 0x04 +#define VENC_VIDEO_RES 0x08 +#define VENC_FIELD1_PARAM 0x10 +#define VENC_FIELD2_PARAM 0x14 +#define VENC_LINE_O_1 0x18 +#define VENC_LINE_E_1 0x1c +#define VENC_LINE_O_2 0x20 +#define VENC_LINE_E_2 0x24 +#define VENC_LINE_TIMING_PARAM 0x28 +#define VENC_WEIGHT_VALUE 0x2c +#define VENC_BLANK_BLACK_LEVEL 0x30 +#define VENC_BURST_LEVEL 0x34 +#define VENC_CONTROL_PARAM 0x3c +#define VENC_SUB_CARRIER_PHASE1 0x40 +#define VENC_PHASE_LINE_INCR_CVBS 0x48 +#define VENC_ENABLE 0xa8 + +#endif /* __ZX_TVENC_REGS_H__ */ diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c index a86e3a5852a2..cf92d675feaa 100644 --- a/drivers/gpu/drm/zte/zx_vou.c +++ b/drivers/gpu/drm/zte/zx_vou.c @@ -40,6 +40,7 @@ struct zx_crtc_regs { u32 fir_active; u32 fir_htiming; u32 fir_vtiming; + u32 sec_vtiming; u32 timing_shift; u32 timing_pi_shift; }; @@ -48,6 +49,7 @@ static const struct zx_crtc_regs main_crtc_regs = { .fir_active = FIR_MAIN_ACTIVE, .fir_htiming = FIR_MAIN_H_TIMING, .fir_vtiming = FIR_MAIN_V_TIMING, + .sec_vtiming = SEC_MAIN_V_TIMING, .timing_shift = TIMING_MAIN_SHIFT, .timing_pi_shift = TIMING_MAIN_PI_SHIFT, }; @@ -56,6 +58,7 @@ static const struct zx_crtc_regs aux_crtc_regs = { .fir_active = FIR_AUX_ACTIVE, .fir_htiming = FIR_AUX_H_TIMING, .fir_vtiming = FIR_AUX_V_TIMING, + .sec_vtiming = SEC_AUX_V_TIMING, .timing_shift = TIMING_AUX_SHIFT, .timing_pi_shift = TIMING_AUX_PI_SHIFT, }; @@ -65,7 +68,17 @@ struct zx_crtc_bits { u32 polarity_shift; u32 int_frame_mask; u32 tc_enable; - u32 gl_enable; + u32 sec_vactive_shift; + u32 sec_vactive_mask; + u32 interlace_select; + u32 pi_enable; + u32 div_vga_shift; + u32 div_pic_shift; + u32 div_tvenc_shift; + u32 div_hdmi_pnx_shift; + u32 div_hdmi_shift; + u32 div_inf_shift; + u32 div_layer_shift; }; static const struct zx_crtc_bits main_crtc_bits = { @@ -73,7 +86,17 @@ static const struct zx_crtc_bits main_crtc_bits = { .polarity_shift = MAIN_POL_SHIFT, .int_frame_mask = TIMING_INT_MAIN_FRAME, .tc_enable = MAIN_TC_EN, - .gl_enable = OSD_CTRL0_GL0_EN, + .sec_vactive_shift = SEC_VACT_MAIN_SHIFT, + .sec_vactive_mask = SEC_VACT_MAIN_MASK, + .interlace_select = MAIN_INTERLACE_SEL, + .pi_enable = MAIN_PI_EN, + .div_vga_shift = VGA_MAIN_DIV_SHIFT, + .div_pic_shift = PIC_MAIN_DIV_SHIFT, + .div_tvenc_shift = TVENC_MAIN_DIV_SHIFT, + .div_hdmi_pnx_shift = HDMI_MAIN_PNX_DIV_SHIFT, + .div_hdmi_shift = HDMI_MAIN_DIV_SHIFT, + .div_inf_shift = INF_MAIN_DIV_SHIFT, + .div_layer_shift = LAYER_MAIN_DIV_SHIFT, }; static const struct zx_crtc_bits aux_crtc_bits = { @@ -81,7 +104,17 @@ static const struct zx_crtc_bits aux_crtc_bits = { .polarity_shift = AUX_POL_SHIFT, .int_frame_mask = TIMING_INT_AUX_FRAME, .tc_enable = AUX_TC_EN, - .gl_enable = OSD_CTRL0_GL1_EN, + .sec_vactive_shift = SEC_VACT_AUX_SHIFT, + .sec_vactive_mask = SEC_VACT_AUX_MASK, + .interlace_select = AUX_INTERLACE_SEL, + .pi_enable = AUX_PI_EN, + .div_vga_shift = VGA_AUX_DIV_SHIFT, + .div_pic_shift = PIC_AUX_DIV_SHIFT, + .div_tvenc_shift = TVENC_AUX_DIV_SHIFT, + .div_hdmi_pnx_shift = HDMI_AUX_PNX_DIV_SHIFT, + .div_hdmi_shift = HDMI_AUX_DIV_SHIFT, + .div_inf_shift = INF_AUX_DIV_SHIFT, + .div_layer_shift = LAYER_AUX_DIV_SHIFT, }; struct zx_crtc { @@ -97,6 +130,40 @@ struct zx_crtc { #define to_zx_crtc(x) container_of(x, struct zx_crtc, crtc) +struct vou_layer_bits { + u32 enable; + u32 chnsel; + u32 clksel; +}; + +static const struct vou_layer_bits zx_gl_bits[GL_NUM] = { + { + .enable = OSD_CTRL0_GL0_EN, + .chnsel = OSD_CTRL0_GL0_SEL, + .clksel = VOU_CLK_GL0_SEL, + }, { + .enable = OSD_CTRL0_GL1_EN, + .chnsel = OSD_CTRL0_GL1_SEL, + .clksel = VOU_CLK_GL1_SEL, + }, +}; + +static const struct vou_layer_bits zx_vl_bits[VL_NUM] = { + { + .enable = OSD_CTRL0_VL0_EN, + .chnsel = OSD_CTRL0_VL0_SEL, + .clksel = VOU_CLK_VL0_SEL, + }, { + .enable = OSD_CTRL0_VL1_EN, + .chnsel = OSD_CTRL0_VL1_SEL, + .clksel = VOU_CLK_VL1_SEL, + }, { + .enable = OSD_CTRL0_VL2_EN, + .chnsel = OSD_CTRL0_VL2_SEL, + .clksel = VOU_CLK_VL2_SEL, + }, +}; + struct zx_vou_hw { struct device *dev; void __iomem *osd; @@ -112,6 +179,33 @@ struct zx_vou_hw { struct zx_crtc *aux_crtc; }; +enum vou_inf_data_sel { + VOU_YUV444 = 0, + VOU_RGB_101010 = 1, + VOU_RGB_888 = 2, + VOU_RGB_666 = 3, +}; + +struct vou_inf { + enum vou_inf_id id; + enum vou_inf_data_sel data_sel; + u32 clocks_en_bits; + u32 clocks_sel_bits; +}; + +static struct vou_inf vou_infs[] = { + [VOU_HDMI] = { + .data_sel = VOU_YUV444, + .clocks_en_bits = BIT(24) | BIT(18) | BIT(6), + .clocks_sel_bits = BIT(13) | BIT(2), + }, + [VOU_TV_ENC] = { + .data_sel = VOU_YUV444, + .clocks_en_bits = BIT(15), + .clocks_sel_bits = BIT(11) | BIT(0), + }, +}; + static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc) { struct zx_crtc *zcrtc = to_zx_crtc(crtc); @@ -119,20 +213,30 @@ static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc) return zcrtc->vou; } -void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc) +void vou_inf_hdmi_audio_sel(struct drm_crtc *crtc, + enum vou_inf_hdmi_audio aud) { struct zx_crtc *zcrtc = to_zx_crtc(crtc); struct zx_vou_hw *vou = zcrtc->vou; + + zx_writel_mask(vou->vouctl + VOU_INF_HDMI_CTRL, VOU_HDMI_AUD_MASK, aud); +} + +void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc) +{ + struct zx_crtc *zcrtc = to_zx_crtc(crtc); + struct zx_vou_hw *vou = zcrtc->vou; + struct vou_inf *inf = &vou_infs[id]; bool is_main = zcrtc->chn_type == VOU_CHN_MAIN; - u32 data_sel_shift = inf->id << 1; + u32 data_sel_shift = id << 1; /* Select data format */ zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift, inf->data_sel << data_sel_shift); /* Select channel */ - zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << inf->id, - zcrtc->chn_type << inf->id); + zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << id, + zcrtc->chn_type << id); /* Select interface clocks */ zx_writel_mask(vou->vouctl + VOU_CLK_SEL, inf->clocks_sel_bits, @@ -143,20 +247,79 @@ void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc) inf->clocks_en_bits); /* Enable the device */ - zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 1 << inf->id); + zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 1 << id); } -void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc) +void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc) { struct zx_vou_hw *vou = crtc_to_vou(crtc); + struct vou_inf *inf = &vou_infs[id]; /* Disable the device */ - zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 0); + zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 0); /* Disable interface clocks */ zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0); } +void zx_vou_config_dividers(struct drm_crtc *crtc, + struct vou_div_config *configs, int num) +{ + struct zx_crtc *zcrtc = to_zx_crtc(crtc); + struct zx_vou_hw *vou = zcrtc->vou; + const struct zx_crtc_bits *bits = zcrtc->bits; + int i; + + /* Clear update flag bit */ + zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE, 0); + + for (i = 0; i < num; i++) { + struct vou_div_config *cfg = configs + i; + u32 reg, shift; + + switch (cfg->id) { + case VOU_DIV_VGA: + reg = VOU_CLK_SEL; + shift = bits->div_vga_shift; + break; + case VOU_DIV_PIC: + reg = VOU_CLK_SEL; + shift = bits->div_pic_shift; + break; + case VOU_DIV_TVENC: + reg = VOU_DIV_PARA; + shift = bits->div_tvenc_shift; + break; + case VOU_DIV_HDMI_PNX: + reg = VOU_DIV_PARA; + shift = bits->div_hdmi_pnx_shift; + break; + case VOU_DIV_HDMI: + reg = VOU_DIV_PARA; + shift = bits->div_hdmi_shift; + break; + case VOU_DIV_INF: + reg = VOU_DIV_PARA; + shift = bits->div_inf_shift; + break; + case VOU_DIV_LAYER: + reg = VOU_DIV_PARA; + shift = bits->div_layer_shift; + break; + default: + continue; + } + + /* Each divider occupies 3 bits */ + zx_writel_mask(vou->vouctl + reg, 0x7 << shift, + cfg->val << shift); + } + + /* Set update flag bit to get dividers effected */ + zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE, + DIV_PARA_UPDATE); +} + static inline void vou_chn_set_update(struct zx_crtc *zcrtc) { zx_writel(zcrtc->chnreg + CHN_UPDATE, 1); @@ -165,11 +328,13 @@ static inline void vou_chn_set_update(struct zx_crtc *zcrtc) static void zx_crtc_enable(struct drm_crtc *crtc) { struct drm_display_mode *mode = &crtc->state->adjusted_mode; + bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; struct zx_crtc *zcrtc = to_zx_crtc(crtc); struct zx_vou_hw *vou = zcrtc->vou; const struct zx_crtc_regs *regs = zcrtc->regs; const struct zx_crtc_bits *bits = zcrtc->bits; struct videomode vm; + u32 scan_mask; u32 pol = 0; u32 val; int ret; @@ -177,7 +342,7 @@ static void zx_crtc_enable(struct drm_crtc *crtc) drm_display_mode_to_videomode(mode, &vm); /* Set up timing parameters */ - val = V_ACTIVE(vm.vactive - 1); + val = V_ACTIVE((interlaced ? vm.vactive / 2 : vm.vactive) - 1); val |= H_ACTIVE(vm.hactive - 1); zx_writel(vou->timing + regs->fir_active, val); @@ -191,6 +356,25 @@ static void zx_crtc_enable(struct drm_crtc *crtc) val |= FRONT_PORCH(vm.vfront_porch - 1); zx_writel(vou->timing + regs->fir_vtiming, val); + if (interlaced) { + u32 shift = bits->sec_vactive_shift; + u32 mask = bits->sec_vactive_mask; + + val = zx_readl(vou->timing + SEC_V_ACTIVE); + val &= ~mask; + val |= ((vm.vactive / 2 - 1) << shift) & mask; + zx_writel(vou->timing + SEC_V_ACTIVE, val); + + val = SYNC_WIDE(vm.vsync_len - 1); + /* + * The vback_porch for the second field needs to shift one on + * the value for the first field. + */ + val |= BACK_PORCH(vm.vback_porch); + val |= FRONT_PORCH(vm.vfront_porch - 1); + zx_writel(vou->timing + regs->sec_vtiming, val); + } + /* Set up polarities */ if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW) pol |= 1 << POL_VSYNC_SHIFT; @@ -201,9 +385,17 @@ static void zx_crtc_enable(struct drm_crtc *crtc) pol << bits->polarity_shift); /* Setup SHIFT register by following what ZTE BSP does */ - zx_writel(vou->timing + regs->timing_shift, H_SHIFT_VAL); + val = H_SHIFT_VAL; + if (interlaced) + val |= V_SHIFT_VAL << 16; + zx_writel(vou->timing + regs->timing_shift, val); zx_writel(vou->timing + regs->timing_pi_shift, H_PI_SHIFT_VAL); + /* Progressive or interlace scan select */ + scan_mask = bits->interlace_select | bits->pi_enable; + zx_writel_mask(vou->timing + SCAN_CTRL, scan_mask, + interlaced ? scan_mask : 0); + /* Enable TIMING_CTRL */ zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable, bits->tc_enable); @@ -214,16 +406,16 @@ static void zx_crtc_enable(struct drm_crtc *crtc) zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_H_MASK, vm.vactive << CHN_SCREEN_H_SHIFT); + /* Configure channel interlace buffer control */ + zx_writel_mask(zcrtc->chnreg + CHN_INTERLACE_BUF_CTRL, CHN_INTERLACE_EN, + interlaced ? CHN_INTERLACE_EN : 0); + /* Update channel */ vou_chn_set_update(zcrtc); /* Enable channel */ zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, CHN_ENABLE); - /* Enable Graphic Layer */ - zx_writel_mask(vou->osd + OSD_CTRL0, bits->gl_enable, - bits->gl_enable); - drm_crtc_vblank_on(crtc); ret = clk_set_rate(zcrtc->pixclk, mode->clock * 1000); @@ -247,9 +439,6 @@ static void zx_crtc_disable(struct drm_crtc *crtc) drm_crtc_vblank_off(crtc); - /* Disable Graphic Layer */ - zx_writel_mask(vou->osd + OSD_CTRL0, bits->gl_enable, 0); - /* Disable channel */ zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, 0); @@ -294,7 +483,7 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou, enum vou_chn_type chn_type) { struct device *dev = vou->dev; - struct zx_layer_data data; + struct zx_plane *zplane; struct zx_crtc *zcrtc; int ret; @@ -305,19 +494,27 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou, zcrtc->vou = vou; zcrtc->chn_type = chn_type; + zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL); + if (!zplane) + return -ENOMEM; + + zplane->dev = dev; + if (chn_type == VOU_CHN_MAIN) { - data.layer = vou->osd + MAIN_GL_OFFSET; - data.csc = vou->osd + MAIN_CSC_OFFSET; - data.hbsc = vou->osd + MAIN_HBSC_OFFSET; - data.rsz = vou->otfppu + MAIN_RSZ_OFFSET; + zplane->layer = vou->osd + MAIN_GL_OFFSET; + zplane->csc = vou->osd + MAIN_CSC_OFFSET; + zplane->hbsc = vou->osd + MAIN_HBSC_OFFSET; + zplane->rsz = vou->otfppu + MAIN_RSZ_OFFSET; + zplane->bits = &zx_gl_bits[0]; zcrtc->chnreg = vou->osd + OSD_MAIN_CHN; zcrtc->regs = &main_crtc_regs; zcrtc->bits = &main_crtc_bits; } else { - data.layer = vou->osd + AUX_GL_OFFSET; - data.csc = vou->osd + AUX_CSC_OFFSET; - data.hbsc = vou->osd + AUX_HBSC_OFFSET; - data.rsz = vou->otfppu + AUX_RSZ_OFFSET; + zplane->layer = vou->osd + AUX_GL_OFFSET; + zplane->csc = vou->osd + AUX_CSC_OFFSET; + zplane->hbsc = vou->osd + AUX_HBSC_OFFSET; + zplane->rsz = vou->otfppu + AUX_RSZ_OFFSET; + zplane->bits = &zx_gl_bits[1]; zcrtc->chnreg = vou->osd + OSD_AUX_CHN; zcrtc->regs = &aux_crtc_regs; zcrtc->bits = &aux_crtc_bits; @@ -331,13 +528,14 @@ static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou, return ret; } - zcrtc->primary = zx_plane_init(drm, dev, &data, DRM_PLANE_TYPE_PRIMARY); - if (IS_ERR(zcrtc->primary)) { - ret = PTR_ERR(zcrtc->primary); + ret = zx_plane_init(drm, zplane, DRM_PLANE_TYPE_PRIMARY); + if (ret) { DRM_DEV_ERROR(dev, "failed to init primary plane: %d\n", ret); return ret; } + zcrtc->primary = &zplane->plane; + ret = drm_crtc_init_with_planes(drm, &zcrtc->crtc, zcrtc->primary, NULL, &zx_crtc_funcs, NULL); if (ret) { @@ -393,6 +591,78 @@ void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe) zcrtc->bits->int_frame_mask, 0); } +void zx_vou_layer_enable(struct drm_plane *plane) +{ + struct zx_crtc *zcrtc = to_zx_crtc(plane->state->crtc); + struct zx_vou_hw *vou = zcrtc->vou; + struct zx_plane *zplane = to_zx_plane(plane); + const struct vou_layer_bits *bits = zplane->bits; + + if (zcrtc->chn_type == VOU_CHN_MAIN) { + zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel, 0); + zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel, 0); + } else { + zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel, + bits->chnsel); + zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel, + bits->clksel); + } + + zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, bits->enable); +} + +void zx_vou_layer_disable(struct drm_plane *plane) +{ + struct zx_crtc *zcrtc = to_zx_crtc(plane->crtc); + struct zx_vou_hw *vou = zcrtc->vou; + struct zx_plane *zplane = to_zx_plane(plane); + const struct vou_layer_bits *bits = zplane->bits; + + zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, 0); +} + +static void zx_overlay_init(struct drm_device *drm, struct zx_vou_hw *vou) +{ + struct device *dev = vou->dev; + struct zx_plane *zplane; + int i; + int ret; + + /* + * VL0 has some quirks on scaling support which need special handling. + * Let's leave it out for now. + */ + for (i = 1; i < VL_NUM; i++) { + zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL); + if (!zplane) { + DRM_DEV_ERROR(dev, "failed to allocate zplane %d\n", i); + return; + } + + zplane->layer = vou->osd + OSD_VL_OFFSET(i); + zplane->hbsc = vou->osd + HBSC_VL_OFFSET(i); + zplane->rsz = vou->otfppu + RSZ_VL_OFFSET(i); + zplane->bits = &zx_vl_bits[i]; + + ret = zx_plane_init(drm, zplane, DRM_PLANE_TYPE_OVERLAY); + if (ret) { + DRM_DEV_ERROR(dev, "failed to init overlay %d\n", i); + continue; + } + } +} + +static inline void zx_osd_int_update(struct zx_crtc *zcrtc) +{ + struct drm_crtc *crtc = &zcrtc->crtc; + struct drm_plane *plane; + + vou_chn_set_update(zcrtc); + + drm_for_each_plane_mask(plane, crtc->dev, crtc->state->plane_mask) + zx_plane_set_update(plane); +} + static irqreturn_t vou_irq_handler(int irq, void *dev_id) { struct zx_vou_hw *vou = dev_id; @@ -412,15 +682,11 @@ static irqreturn_t vou_irq_handler(int irq, void *dev_id) state = zx_readl(vou->osd + OSD_INT_STA); zx_writel(vou->osd + OSD_INT_CLRSTA, state); - if (state & OSD_INT_MAIN_UPT) { - vou_chn_set_update(vou->main_crtc); - zx_plane_set_update(vou->main_crtc->primary); - } + if (state & OSD_INT_MAIN_UPT) + zx_osd_int_update(vou->main_crtc); - if (state & OSD_INT_AUX_UPT) { - vou_chn_set_update(vou->aux_crtc); - zx_plane_set_update(vou->aux_crtc->primary); - } + if (state & OSD_INT_AUX_UPT) + zx_osd_int_update(vou->aux_crtc); if (state & OSD_INT_ERROR) DRM_DEV_ERROR(vou->dev, "OSD ERROR: 0x%08x!\n", state); @@ -451,19 +717,9 @@ static void vou_dtrc_init(struct zx_vou_hw *vou) static void vou_hw_init(struct zx_vou_hw *vou) { - /* Set GL0 to main channel and GL1 to aux channel */ - zx_writel_mask(vou->osd + OSD_CTRL0, OSD_CTRL0_GL0_SEL, 0); - zx_writel_mask(vou->osd + OSD_CTRL0, OSD_CTRL0_GL1_SEL, - OSD_CTRL0_GL1_SEL); - /* Release reset for all VOU modules */ zx_writel(vou->vouctl + VOU_SOFT_RST, ~0); - /* Select main clock for GL0 and aux clock for GL1 module */ - zx_writel_mask(vou->vouctl + VOU_CLK_SEL, VOU_CLK_GL0_SEL, 0); - zx_writel_mask(vou->vouctl + VOU_CLK_SEL, VOU_CLK_GL1_SEL, - VOU_CLK_GL1_SEL); - /* Enable clock auto-gating for all VOU modules */ zx_writel(vou->vouctl + VOU_CLK_REQEN, ~0); @@ -600,6 +856,8 @@ static int zx_crtc_bind(struct device *dev, struct device *master, void *data) goto disable_ppu_clk; } + zx_overlay_init(drm, vou); + return 0; disable_ppu_clk: diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h index 349e06cd86f4..57e3c31ee6a5 100644 --- a/drivers/gpu/drm/zte/zx_vou.h +++ b/drivers/gpu/drm/zte/zx_vou.h @@ -23,24 +23,48 @@ enum vou_inf_id { VOU_VGA = 5, }; -enum vou_inf_data_sel { - VOU_YUV444 = 0, - VOU_RGB_101010 = 1, - VOU_RGB_888 = 2, - VOU_RGB_666 = 3, +enum vou_inf_hdmi_audio { + VOU_HDMI_AUD_SPDIF = BIT(0), + VOU_HDMI_AUD_I2S = BIT(1), + VOU_HDMI_AUD_DSD = BIT(2), + VOU_HDMI_AUD_HBR = BIT(3), + VOU_HDMI_AUD_PARALLEL = BIT(4), }; -struct vou_inf { - enum vou_inf_id id; - enum vou_inf_data_sel data_sel; - u32 clocks_en_bits; - u32 clocks_sel_bits; +void vou_inf_hdmi_audio_sel(struct drm_crtc *crtc, + enum vou_inf_hdmi_audio aud); +void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc); +void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc); + +enum vou_div_id { + VOU_DIV_VGA, + VOU_DIV_PIC, + VOU_DIV_TVENC, + VOU_DIV_HDMI_PNX, + VOU_DIV_HDMI, + VOU_DIV_INF, + VOU_DIV_LAYER, +}; + +enum vou_div_val { + VOU_DIV_1 = 0, + VOU_DIV_2 = 1, + VOU_DIV_4 = 3, + VOU_DIV_8 = 7, }; -void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc); -void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc); +struct vou_div_config { + enum vou_div_id id; + enum vou_div_val val; +}; + +void zx_vou_config_dividers(struct drm_crtc *crtc, + struct vou_div_config *configs, int num); int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe); void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe); +void zx_vou_layer_enable(struct drm_plane *plane); +void zx_vou_layer_disable(struct drm_plane *plane); + #endif /* __ZX_VOU_H__ */ diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h index f44e7a4ae441..c066ef123434 100644 --- a/drivers/gpu/drm/zte/zx_vou_regs.h +++ b/drivers/gpu/drm/zte/zx_vou_regs.h @@ -22,6 +22,15 @@ #define AUX_HBSC_OFFSET 0x860 #define AUX_RSZ_OFFSET 0x800 +#define OSD_VL0_OFFSET 0x040 +#define OSD_VL_OFFSET(i) (OSD_VL0_OFFSET + 0x050 * (i)) + +#define HBSC_VL0_OFFSET 0x760 +#define HBSC_VL_OFFSET(i) (HBSC_VL0_OFFSET + 0x040 * (i)) + +#define RSZ_VL1_U0 0xa00 +#define RSZ_VL_OFFSET(i) (RSZ_VL1_U0 + 0x200 * (i)) + /* OSD (GPC_GLOBAL) registers */ #define OSD_INT_STA 0x04 #define OSD_INT_CLRSTA 0x08 @@ -42,6 +51,12 @@ ) #define OSD_INT_ENABLE (OSD_INT_ERROR | OSD_INT_AUX_UPT | OSD_INT_MAIN_UPT) #define OSD_CTRL0 0x10 +#define OSD_CTRL0_VL0_EN BIT(13) +#define OSD_CTRL0_VL0_SEL BIT(12) +#define OSD_CTRL0_VL1_EN BIT(11) +#define OSD_CTRL0_VL1_SEL BIT(10) +#define OSD_CTRL0_VL2_EN BIT(9) +#define OSD_CTRL0_VL2_SEL BIT(8) #define OSD_CTRL0_GL0_EN BIT(7) #define OSD_CTRL0_GL0_SEL BIT(6) #define OSD_CTRL0_GL1_EN BIT(5) @@ -60,6 +75,8 @@ #define CHN_SCREEN_H_SHIFT 5 #define CHN_SCREEN_H_MASK (0x1fff << CHN_SCREEN_H_SHIFT) #define CHN_UPDATE 0x08 +#define CHN_INTERLACE_BUF_CTRL 0x24 +#define CHN_INTERLACE_EN BIT(2) /* TIMING_CTRL registers */ #define TIMING_TC_ENABLE 0x04 @@ -102,6 +119,19 @@ #define TIMING_MAIN_SHIFT 0x2c #define TIMING_AUX_SHIFT 0x30 #define H_SHIFT_VAL 0x0048 +#define V_SHIFT_VAL 0x0001 +#define SCAN_CTRL 0x34 +#define AUX_PI_EN BIT(19) +#define MAIN_PI_EN BIT(18) +#define AUX_INTERLACE_SEL BIT(1) +#define MAIN_INTERLACE_SEL BIT(0) +#define SEC_V_ACTIVE 0x38 +#define SEC_VACT_MAIN_SHIFT 0 +#define SEC_VACT_MAIN_MASK (0xffff << SEC_VACT_MAIN_SHIFT) +#define SEC_VACT_AUX_SHIFT 16 +#define SEC_VACT_AUX_MASK (0xffff << SEC_VACT_AUX_SHIFT) +#define SEC_MAIN_V_TIMING 0x3c +#define SEC_AUX_V_TIMING 0x40 #define TIMING_MAIN_PI_SHIFT 0x68 #define TIMING_AUX_PI_SHIFT 0x6c #define H_PI_SHIFT_VAL 0x000f @@ -146,10 +176,31 @@ #define VOU_INF_DATA_SEL 0x08 #define VOU_SOFT_RST 0x14 #define VOU_CLK_SEL 0x18 +#define VGA_AUX_DIV_SHIFT 29 +#define VGA_MAIN_DIV_SHIFT 26 +#define PIC_MAIN_DIV_SHIFT 23 +#define PIC_AUX_DIV_SHIFT 20 +#define VOU_CLK_VL2_SEL BIT(8) +#define VOU_CLK_VL1_SEL BIT(7) +#define VOU_CLK_VL0_SEL BIT(6) #define VOU_CLK_GL1_SEL BIT(5) #define VOU_CLK_GL0_SEL BIT(4) +#define VOU_DIV_PARA 0x1c +#define DIV_PARA_UPDATE BIT(31) +#define TVENC_AUX_DIV_SHIFT 28 +#define HDMI_AUX_PNX_DIV_SHIFT 25 +#define HDMI_MAIN_PNX_DIV_SHIFT 22 +#define HDMI_AUX_DIV_SHIFT 19 +#define HDMI_MAIN_DIV_SHIFT 16 +#define TVENC_MAIN_DIV_SHIFT 13 +#define INF_AUX_DIV_SHIFT 9 +#define INF_MAIN_DIV_SHIFT 6 +#define LAYER_AUX_DIV_SHIFT 3 +#define LAYER_MAIN_DIV_SHIFT 0 #define VOU_CLK_REQEN 0x20 #define VOU_CLK_EN 0x24 +#define VOU_INF_HDMI_CTRL 0x30 +#define VOU_HDMI_AUD_MASK 0x1f /* OTFPPU_CTRL registers */ #define OTFPPU_RSZ_DATA_SOURCE 0x04 diff --git a/include/drm/drmP.h b/include/drm/drmP.h index e5882d5a68e5..21a3a666a2fd 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -790,21 +790,6 @@ extern void drm_sysfs_hotplug_event(struct drm_device *dev); /*@}*/ -/* PCI section */ -static __inline__ int drm_pci_device_is_agp(struct drm_device *dev) -{ - if (dev->driver->device_is_agp != NULL) { - int err = (*dev->driver->device_is_agp) (dev); - - if (err != 2) { - return err; - } - } - - return pci_find_capability(dev->pdev, PCI_CAP_ID_AGP); -} -void drm_pci_agp_destroy(struct drm_device *dev); - extern int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver); extern void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver); #ifdef CONFIG_PCI diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index f96220ed4004..2e28fdca9c3d 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -123,7 +123,8 @@ struct drm_crtc_commit { /** * @commit_entry: * - * Entry on the per-CRTC commit_list. Protected by crtc->commit_lock. + * Entry on the per-CRTC &drm_crtc.commit_list. Protected by + * $drm_crtc.commit_lock. */ struct list_head commit_entry; @@ -429,7 +430,8 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); * * For example if the CRTC mode has changed, and the hardware is able to enact * the requested mode change without going through a full modeset, the driver - * should clear mode_changed during its ->atomic_check. + * should clear mode_changed in its &drm_mode_config_funcs.atomic_check + * implementation. */ static inline bool drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state) diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 9afcd3810785..d066e9491ae3 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -177,7 +177,8 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, * * This iterates over the current state, useful (for example) when applying * atomic state after it has been checked and swapped. To iterate over the - * planes which *will* be attached (for ->atomic_check()) see + * planes which *will* be attached (more useful in code called from + * &drm_mode_config_funcs.atomic_check) see * drm_atomic_crtc_state_for_each_plane(). */ #define drm_atomic_crtc_for_each_plane(plane, crtc) \ @@ -189,8 +190,9 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, * @crtc_state: the incoming crtc-state * * Similar to drm_crtc_for_each_plane(), but iterates the planes that will be - * attached if the specified state is applied. Useful during (for example) - * ->atomic_check() operations, to validate the incoming state. + * attached if the specified state is applied. Useful during for example + * in code called from &drm_mode_config_funcs.atomic_check operations, to + * validate the incoming state. */ #define drm_atomic_crtc_state_for_each_plane(plane, crtc_state) \ drm_for_each_plane_mask(plane, (crtc_state)->state->dev, (crtc_state)->plane_mask) @@ -202,8 +204,9 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, * @crtc_state: the incoming crtc-state * * Similar to drm_crtc_for_each_plane(), but iterates the planes that will be - * attached if the specified state is applied. Useful during (for example) - * ->atomic_check() operations, to validate the incoming state. + * attached if the specified state is applied. Useful during for example + * in code called from &drm_mode_config_funcs.atomic_check operations, to + * validate the incoming state. * * Compared to just drm_atomic_crtc_state_for_each_plane() this also fills in a * const plane_state. This is useful when a driver just wants to peek at other diff --git a/include/drm/drm_auth.h b/include/drm/drm_auth.h index eecbc2f43f55..1eb4a52cad8d 100644 --- a/include/drm/drm_auth.h +++ b/include/drm/drm_auth.h @@ -43,18 +43,18 @@ struct drm_master { struct kref refcount; struct drm_device *dev; /** - * @unique: Unique identifier: e.g. busid. Protected by struct - * &drm_device master_mutex. + * @unique: Unique identifier: e.g. busid. Protected by + * &drm_device.master_mutex. */ char *unique; /** - * @unique_len: Length of unique field. Protected by &struct drm_device - * master_mutex. + * @unique_len: Length of unique field. Protected by + * &drm_device.master_mutex. */ int unique_len; /** - * @magic_map: Map of used authentication tokens. Protected by struct - * &drm_device master_mutex. + * @magic_map: Map of used authentication tokens. Protected by + * &drm_device.master_mutex. */ struct idr magic_map; struct drm_lock_data lock; diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h index c767238ac9d5..d9c2f680f5ae 100644 --- a/include/drm/drm_color_mgmt.h +++ b/include/drm/drm_color_mgmt.h @@ -34,7 +34,7 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, int gamma_size); /** - * drm_color_lut_extract - clamp&round LUT entries + * drm_color_lut_extract - clamp and round LUT entries * @user_input: input value * @bit_precision: number of bits the hw LUT supports * diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index d489cc003b7e..e5e1eddd19fb 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -331,15 +331,15 @@ struct drm_connector_funcs { * * Entry point for output detection and basic mode validation. The * driver should reprobe the output if needed (e.g. when hotplug - * handling is unreliable), add all detected modes to connector->modes + * handling is unreliable), add all detected modes to &drm_connector.modes * and filter out any the device can't support in any configuration. It * also needs to filter out any modes wider or higher than the * parameters max_width and max_height indicate. * * The drivers must also prune any modes no longer valid from - * connector->modes. Furthermore it must update connector->status and - * connector->edid. If no EDID has been received for this output - * connector->edid must be NULL. + * &drm_connector.modes. Furthermore it must update + * &drm_connector.status and &drm_connector.edid. If no EDID has been + * received for this output connector->edid must be NULL. * * Drivers using the probe helpers should use * drm_helper_probe_single_connector_modes() or @@ -348,7 +348,7 @@ struct drm_connector_funcs { * * RETURNS: * - * The number of modes detected and filled into connector->modes. + * The number of modes detected and filled into &drm_connector.modes. */ int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); @@ -381,7 +381,7 @@ struct drm_connector_funcs { * core drm connector interfaces. Everything added from this callback * should be unregistered in the early_unregister callback. * - * This is called while holding drm_connector->mutex. + * This is called while holding &drm_connector.mutex. * * Returns: * @@ -398,7 +398,7 @@ struct drm_connector_funcs { * early in the driver unload sequence to disable userspace access * before data structures are torndown. * - * This is called while holding drm_connector->mutex. + * This is called while holding &drm_connector.mutex. */ void (*early_unregister)(struct drm_connector *connector); @@ -418,9 +418,9 @@ struct drm_connector_funcs { * Duplicate the current atomic state for this connector and return it. * The core and helpers guarantee that any atomic state duplicated with * this hook and still owned by the caller (i.e. not transferred to the - * driver by calling ->atomic_commit() from struct - * &drm_mode_config_funcs) will be cleaned up by calling the - * @atomic_destroy_state hook in this structure. + * driver by calling &drm_mode_config_funcs.atomic_commit) will be + * cleaned up by calling the @atomic_destroy_state hook in this + * structure. * * Atomic drivers which don't subclass &struct drm_connector_state should use * drm_atomic_helper_connector_duplicate_state(). Drivers that subclass the @@ -428,7 +428,7 @@ struct drm_connector_funcs { * __drm_atomic_helper_connector_duplicate_state() to make sure shared state is * duplicated in a consistent fashion across drivers. * - * It is an error to call this hook before connector->state has been + * It is an error to call this hook before &drm_connector.state has been * initialized correctly. * * NOTE: @@ -609,8 +609,8 @@ struct drm_connector { /** * @mutex: Lock for general connector state, but currently only protects - * @registered. Most of the connector state is still protected by the - * mutex in &drm_mode_config. + * @registered. Most of the connector state is still protected by + * &drm_mode_config.mutex. */ struct mutex mutex; @@ -636,22 +636,22 @@ struct drm_connector { /** * @modes: * Modes available on this connector (from fill_modes() + user). - * Protected by dev->mode_config.mutex. + * Protected by &drm_mode_config.mutex. */ - struct list_head modes; /* list of modes on this connector */ + struct list_head modes; /** * @status: * One of the drm_connector_status enums (connected, not, or unknown). - * Protected by dev->mode_config.mutex. + * Protected by &drm_mode_config.mutex. */ enum drm_connector_status status; /** * @probed_modes: * These are modes added by probing with DDC or the BIOS, before - * filtering is applied. Used by the probe helpers.Protected by - * dev->mode_config.mutex. + * filtering is applied. Used by the probe helpers. Protected by + * &drm_mode_config.mutex. */ struct list_head probed_modes; @@ -659,10 +659,10 @@ struct drm_connector { * @display_info: Display information is filled from EDID information * when a display is detected. For non hot-pluggable displays such as * flat panels in embedded systems, the driver should initialize the - * display_info.width_mm and display_info.height_mm fields with the - * physical size of the display. + * &drm_display_info.width_mm and &drm_display_info.height_mm fields + * with the physical size of the display. * - * Protected by dev->mode_config.mutex. + * Protected by &drm_mode_config.mutex. */ struct drm_display_info display_info; const struct drm_connector_funcs *funcs; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 06c943d1e04c..8f0b195e4a59 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -81,8 +81,8 @@ struct drm_plane_helper_funcs; * @enable: whether the CRTC should be enabled, gates all other state * @active: whether the CRTC is actively displaying (used for DPMS) * @planes_changed: planes on this crtc are updated - * @mode_changed: crtc_state->mode or crtc_state->enable has been changed - * @active_changed: crtc_state->active has been toggled. + * @mode_changed: @mode or @enable has been changed + * @active_changed: @active has been toggled. * @connectors_changed: connectors to this crtc have been updated * @zpos_changed: zpos values of planes on this crtc have been updated * @color_mgmt_changed: color management properties have changed (degamma or @@ -102,9 +102,10 @@ struct drm_plane_helper_funcs; * * Note that the distinction between @enable and @active is rather subtile: * Flipping @active while @enable is set without changing anything else may - * never return in a failure from the ->atomic_check callback. Userspace assumes - * that a DPMS On will always succeed. In other words: @enable controls resource - * assignment, @active controls the actual hardware state. + * never return in a failure from the &drm_mode_config_funcs.atomic_check + * callback. Userspace assumes that a DPMS On will always succeed. In other + * words: @enable controls resource assignment, @active controls the actual + * hardware state. * * The three booleans active_changed, connectors_changed and mode_changed are * intended to indicate whether a full modeset is needed, rather than strictly @@ -346,8 +347,8 @@ struct drm_crtc_funcs { * through the DRM_MODE_PAGE_FLIP_ASYNC flag). When an application * requests a page flip the DRM core verifies that the new frame buffer * is large enough to be scanned out by the CRTC in the currently - * configured mode and then calls the CRTC ->page_flip() operation with a - * pointer to the new frame buffer. + * configured mode and then calls this hook with a pointer to the new + * frame buffer. * * The driver must wait for any pending rendering to the new framebuffer * to complete before executing the flip. It should also wait for any @@ -382,7 +383,7 @@ struct drm_crtc_funcs { * RETURNS: * * 0 on success or a negative error code on failure. Note that if a - * ->page_flip() operation is already pending the callback should return + * page flip operation is already pending the callback should return * -EBUSY. Pageflips on a disabled CRTC (either by setting a NULL mode * or just runtime disabled through DPMS respectively the new atomic * "ACTIVE" state) should result in an -EINVAL error code. Note that @@ -434,19 +435,19 @@ struct drm_crtc_funcs { * @atomic_duplicate_state: * * Duplicate the current atomic state for this CRTC and return it. - * The core and helpers gurantee that any atomic state duplicated with + * The core and helpers guarantee that any atomic state duplicated with * this hook and still owned by the caller (i.e. not transferred to the - * driver by calling ->atomic_commit() from struct - * &drm_mode_config_funcs) will be cleaned up by calling the - * @atomic_destroy_state hook in this structure. + * driver by calling &drm_mode_config_funcs.atomic_commit) will be + * cleaned up by calling the @atomic_destroy_state hook in this + * structure. * - * Atomic drivers which don't subclass &struct drm_crtc should use + * Atomic drivers which don't subclass &struct drm_crtc_state should use * drm_atomic_helper_crtc_duplicate_state(). Drivers that subclass the * state structure to extend it with driver-private state should use * __drm_atomic_helper_crtc_duplicate_state() to make sure shared state is * duplicated in a consistent fashion across drivers. * - * It is an error to call this hook before crtc->state has been + * It is an error to call this hook before &drm_crtc.state has been * initialized correctly. * * NOTE: @@ -559,7 +560,7 @@ struct drm_crtc_funcs { * * This optional hook should be used to unregister the additional * userspace interfaces attached to the crtc from - * late_unregister(). It is called from drm_dev_unregister(), + * @late_register. It is called from drm_dev_unregister(), * early in the driver unload sequence to disable userspace access * before data structures are torndown. */ @@ -640,8 +641,8 @@ struct drm_crtc { * * This provides a read lock for the overall crtc state (mode, dpms * state, ...) and a write lock for everything which can be update - * without a full modeset (fb, cursor data, crtc properties ...). Full - * modeset also need to grab dev->mode_config.connection_mutex. + * without a full modeset (fb, cursor data, crtc properties ...). A full + * modeset also need to grab &drm_mode_config.connection_mutex. */ struct drm_modeset_lock mutex; @@ -773,10 +774,8 @@ struct drm_crtc { * @connectors: array of connectors to drive with this CRTC if possible * @num_connectors: size of @connectors array * - * Represents a single crtc the connectors that it drives with what mode - * and from which framebuffer it scans out from. - * - * This is used to set modes. + * This represents a modeset configuration for the legacy SETCRTC ioctl and is + * also used internally. Atomic drivers instead use &drm_atomic_state. */ struct drm_mode_set { struct drm_framebuffer *fb; @@ -825,15 +824,21 @@ static inline uint32_t drm_crtc_mask(const struct drm_crtc *crtc) return 1 << drm_crtc_index(crtc); } -void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, - int *hdisplay, int *vdisplay); int drm_crtc_force_disable(struct drm_crtc *crtc); int drm_crtc_force_disable_all(struct drm_device *dev); int drm_mode_set_config_internal(struct drm_mode_set *set); struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx); -/* Helpers */ +/** + * drm_crtc_find - look up a CRTC object from its ID + * @dev: DRM device + * @id: &drm_mode_object ID + * + * This can be used to look up a CRTC from its userspace ID. Only used by + * drivers for legacy IOCTLs and interface, nowadays extensions to the KMS + * userspace interface should be done using &drm_property. + */ static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev, uint32_t id) { @@ -842,6 +847,13 @@ static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev, return mo ? obj_to_crtc(mo) : NULL; } +/** + * drm_for_each_crtc - iterate over all CRTCs + * @crtc: a &struct drm_crtc as the loop cursor + * @dev: the &struct drm_device + * + * Iterate over all CRTCs of @dev. + */ #define drm_for_each_crtc(crtc, dev) \ list_for_each_entry(crtc, &(dev)->mode_config.crtc_list, head) diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 003207670597..f4b4d154b98e 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -414,7 +414,7 @@ struct drm_dp_mst_topology_mgr { /** * @dev: device pointer for adding i2c devices etc. */ - struct device *dev; + struct drm_device *dev; /** * @cbs: callbacks for connector addition and destruction. */ @@ -493,8 +493,8 @@ struct drm_dp_mst_topology_mgr { int total_pbn; /** - * @qlock: protects @tx_msg_downq, the tx_slots in struct - * &drm_dp_mst_branch and txmsg->state once they are queued + * @qlock: protects @tx_msg_downq, the &drm_dp_mst_branch.txslost and + * &drm_dp_sideband_msg_tx.state once they are queued */ struct mutex qlock; /** @@ -508,8 +508,7 @@ struct drm_dp_mst_topology_mgr { struct mutex payload_lock; /** * @proposed_vcpis: Array of pointers for the new VCPI allocation. The - * VCPI structure itself is embedded into the corresponding - * &drm_dp_mst_port structure. + * VCPI structure itself is &drm_dp_mst_port.vcpi. */ struct drm_dp_vcpi **proposed_vcpis; /** @@ -556,7 +555,10 @@ struct drm_dp_mst_topology_mgr { struct work_struct destroy_connector_work; }; -int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, struct device *dev, struct drm_dp_aux *aux, int max_dpcd_transaction_bytes, int max_payloads, int conn_base_id); +int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, + struct drm_device *dev, struct drm_dp_aux *aux, + int max_dpcd_transaction_bytes, + int max_payloads, int conn_base_id); void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr); diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 34ece393c639..732e85652d1e 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -81,7 +81,6 @@ struct drm_driver { * Zero on success, non-zero value on failure. */ int (*load) (struct drm_device *, unsigned long flags); - int (*firstopen) (struct drm_device *); int (*open) (struct drm_device *, struct drm_file *); void (*preclose) (struct drm_device *, struct drm_file *file_priv); void (*postclose) (struct drm_device *, struct drm_file *); @@ -103,9 +102,6 @@ struct drm_driver { * */ void (*unload) (struct drm_device *); - int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); - int (*dma_quiescent) (struct drm_device *); - int (*context_dtor) (struct drm_device *dev, int context); int (*set_busid)(struct drm_device *dev, struct drm_master *master); /** @@ -151,20 +147,6 @@ struct drm_driver { void (*disable_vblank) (struct drm_device *dev, unsigned int pipe); /** - * @device_is_agp: - * - * Called by drm_device_is_agp(). Typically used to determine if a card - * is really attached to AGP or not. - * - * Returns: - * - * One of three values is returned depending on whether or not the - * card is absolutely not AGP (return of 0), absolutely is AGP - * (return of 1), or may or may not be AGP (return of 2). - */ - int (*device_is_agp) (struct drm_device *dev); - - /** * @get_scanout_position: * * Called by vblank timestamping code. @@ -314,7 +296,7 @@ struct drm_driver { /** * @gem_free_object_unlocked: deconstructor for drm_gem_objects * - * This is for drivers which are not encumbered with dev->struct_mutex + * This is for drivers which are not encumbered with &drm_device.struct_mutex * legacy locking schemes. Use this hook instead of @gem_free_object. */ void (*gem_free_object_unlocked) (struct drm_gem_object *obj); @@ -359,9 +341,6 @@ struct drm_driver { int (*gem_prime_mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma); - /* vga arb irq handler */ - void (*vgaarb_irq)(struct drm_device *dev, bool state); - /** * @dumb_create: * @@ -430,13 +409,20 @@ struct drm_driver { char *date; u32 driver_features; - int dev_priv_size; const struct drm_ioctl_desc *ioctls; int num_ioctls; const struct file_operations *fops; + /* Everything below here is for legacy driver, never use! */ + /* private: */ + /* List of devices hanging off this driver with stealth attach. */ struct list_head legacy_dev_list; + int (*firstopen) (struct drm_device *); + int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); + int (*dma_quiescent) (struct drm_device *); + int (*context_dtor) (struct drm_device *dev, int context); + int dev_priv_size; }; extern __printf(6, 7) diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 38eabf65f19d..43fb0ac5eb9c 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -24,6 +24,7 @@ #define __DRM_EDID_H__ #include <linux/types.h> +#include <linux/hdmi.h> struct drm_device; struct i2c_adapter; @@ -322,8 +323,6 @@ struct cea_sad { struct drm_encoder; struct drm_connector; struct drm_display_mode; -struct hdmi_avi_infoframe; -struct hdmi_vendor_infoframe; void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid); int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads); @@ -346,6 +345,11 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, int drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, const struct drm_display_mode *mode); +void +drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, + const struct drm_display_mode *mode, + enum hdmi_quantization_range rgb_quant_range, + bool rgb_quant_range_selectable); /** * drm_eld_mnl - Get ELD monitor name length in bytes. @@ -442,6 +446,8 @@ enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code); bool drm_detect_hdmi_monitor(struct edid *edid); bool drm_detect_monitor_audio(struct edid *edid); bool drm_rgb_quant_range_selectable(struct edid *edid); +enum hdmi_quantization_range +drm_default_rgb_quant_range(const struct drm_display_mode *mode); int drm_add_modes_noedid(struct drm_connector *connector, int hdisplay, int vdisplay); void drm_set_preferred_mode(struct drm_connector *connector, diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h index 5f58f65344e0..8d8245ec0181 100644 --- a/include/drm/drm_encoder.h +++ b/include/drm/drm_encoder.h @@ -75,7 +75,7 @@ struct drm_encoder_funcs { * * This optional hook should be used to unregister the additional * userspace interfaces attached to the encoder from - * late_unregister(). It is called from drm_dev_unregister(), + * @late_register. It is called from drm_dev_unregister(), * early in the driver unload sequence to disable userspace access * before data structures are torndown. */ diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h index 9f4e34ea99fd..8dd6e5585e51 100644 --- a/include/drm/drm_fb_cma_helper.h +++ b/include/drm/drm_fb_cma_helper.h @@ -26,6 +26,8 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma); void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma); void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma); void drm_fbdev_cma_set_suspend(struct drm_fbdev_cma *fbdev_cma, int state); +void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma, + int state); void drm_fb_cma_destroy(struct drm_framebuffer *fb); int drm_fb_cma_create_handle(struct drm_framebuffer *fb, diff --git a/include/drm/drm_flip_work.h b/include/drm/drm_flip_work.h index d387cf06ae05..21c3d512d25c 100644 --- a/include/drm/drm_flip_work.h +++ b/include/drm/drm_flip_work.h @@ -54,7 +54,7 @@ typedef void (*drm_flip_func_t)(struct drm_flip_work *work, void *val); /** * struct drm_flip_task - flip work task * @node: list entry element - * @data: data to pass to work->func + * @data: data to pass to &drm_flip_work.func */ struct drm_flip_task { struct list_head node; diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index 046c35e54099..04c77eee9c20 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -40,8 +40,8 @@ struct drm_framebuffer_funcs { * * Clean up framebuffer resources, specifically also unreference the * backing storage. The core guarantees to call this function for every - * framebuffer successfully created by ->fb_create() in - * &drm_mode_config_funcs. Drivers must also call + * framebuffer successfully created by calling + * &drm_mode_config_funcs.fb_create. Drivers must also call * drm_framebuffer_cleanup() to release DRM core resources for this * framebuffer. */ @@ -112,8 +112,8 @@ struct drm_framebuffer { */ struct drm_device *dev; /** - * @head: Place on the dev->mode_config.fb_list, access protected by - * dev->mode_config.fb_lock. + * @head: Place on the &drm_mode_config.fb_list, access protected by + * &drm_mode_config.fb_lock. */ struct list_head head; @@ -187,8 +187,7 @@ struct drm_framebuffer { */ int hot_y; /** - * @filp_head: Placed on &struct drm_file fbs list_head, protected by - * fbs_lock in the same structure. + * @filp_head: Placed on &drm_file.fbs, protected by &drm_file.fbs_lock. */ struct list_head filp_head; }; @@ -260,8 +259,8 @@ static inline void drm_framebuffer_assign(struct drm_framebuffer **p, * @fb: the loop cursor * @dev: the DRM device * - * Iterate over all framebuffers of @dev. User must hold the fb_lock from - * &drm_mode_config. + * Iterate over all framebuffers of @dev. User must hold + * &drm_mode_config.fb_lock. */ #define drm_for_each_fb(fb, dev) \ for (WARN_ON(!mutex_is_locked(&(dev)->mode_config.fb_lock)), \ diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index 9f63736e6163..449a41b56ffc 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -63,7 +63,7 @@ struct drm_gem_object { * drops to 0 any global names (e.g. the id in the flink namespace) will * be cleared. * - * Protected by dev->object_name_lock. + * Protected by &drm_device.object_name_lock. */ unsigned handle_count; @@ -106,8 +106,8 @@ struct drm_gem_object { * @name: * * Global name for this object, starts at 1. 0 means unnamed. - * Access is covered by dev->object_name_lock. This is used by the GEM_FLINK - * and GEM_OPEN ioctls. + * Access is covered by &drm_device.object_name_lock. This is used by + * the GEM_FLINK and GEM_OPEN ioctls. */ int name; @@ -150,7 +150,7 @@ struct drm_gem_object { * through importing or exporting). We break the resulting reference * loop when the last gem handle for this object is released. * - * Protected by obj->object_name_lock. + * Protected by &drm_device.object_name_lock. */ struct dma_buf *dma_buf; @@ -163,7 +163,7 @@ struct drm_gem_object { * attachment point for the device. This is invariant over the lifetime * of a gem object. * - * The driver's ->gem_free_object callback is responsible for cleaning + * The &drm_driver.gem_free_object callback is responsible for cleaning * up the dma_buf attachment and references acquired at import time. * * Note that the drm gem/prime core does not depend upon drivers setting @@ -204,7 +204,7 @@ drm_gem_object_reference(struct drm_gem_object *obj) * @obj: GEM buffer object * * This function is meant to be used by drivers which are not encumbered with - * dev->struct_mutex legacy locking and which are using the + * &drm_device.struct_mutex legacy locking and which are using the * gem_free_object_unlocked callback. It avoids all the locking checks and * locking overhead of drm_gem_object_unreference() and * drm_gem_object_unreference_unlocked(). @@ -212,8 +212,8 @@ drm_gem_object_reference(struct drm_gem_object *obj) * Drivers should never call this directly in their code. Instead they should * wrap it up into a ``driver_gem_object_unreference(struct driver_gem_object * *obj)`` wrapper function, and use that. Shared code should never call this, to - * avoid breaking drivers by accident which still depend upon dev->struct_mutex - * locking. + * avoid breaking drivers by accident which still depend upon + * &drm_device.struct_mutex locking. */ static inline void __drm_gem_object_unreference(struct drm_gem_object *obj) diff --git a/include/drm/drm_irq.h b/include/drm/drm_irq.h index 18cfd11307e1..2fb880462a57 100644 --- a/include/drm/drm_irq.h +++ b/include/drm/drm_irq.h @@ -67,7 +67,7 @@ struct drm_vblank_crtc { * @disable_timer: Disable timer for the delayed vblank disabling * hysteresis logic. Vblank disabling is controlled through the * drm_vblank_offdelay module option and the setting of the - * max_vblank_count value in the &drm_device structure. + * &drm_device.max_vblank_count value. */ struct timer_list disable_timer; @@ -92,7 +92,7 @@ struct drm_vblank_crtc { */ atomic_t refcount; /* number of users of vblank interruptsper crtc */ /** - * @last: Protected by dev->vbl_lock, used for wraparound handling. + * @last: Protected by &drm_device.vbl_lock, used for wraparound handling. */ u32 last; /** diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 17942c0f32a8..5a29978062d3 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -132,8 +132,8 @@ struct drm_mode_config_funcs { * that before calling this hook. * * See the documentation of @atomic_commit for an exhaustive list of - * error conditions which don't have to be checked at the - * ->atomic_check() stage? + * error conditions which don't have to be checked at the in this + * callback. * * See the documentation for &struct drm_atomic_state for how exactly * an atomic modeset update is described. @@ -198,10 +198,10 @@ struct drm_mode_config_funcs { * completed. These events are per-CRTC and can be distinguished by the * CRTC index supplied in &drm_event to userspace. * - * The drm core will supply a &struct drm_event in the event - * member of each CRTC's &drm_crtc_state structure. See the - * documentation for &drm_crtc_state for more details about the precise - * semantics of this event. + * The drm core will supply a &struct drm_event in each CRTC's + * &drm_crtc_state.event. See the documentation for + * &drm_crtc_state.event for more details about the precise semantics of + * this event. * * NOTE: * diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h index 43460b21d112..2c017adf6d74 100644 --- a/include/drm/drm_mode_object.h +++ b/include/drm/drm_mode_object.h @@ -86,10 +86,15 @@ struct drm_object_properties { * * Note that atomic drivers do not store mutable properties in this * array, but only the decoded values in the corresponding state - * structure. The decoding is done using the ->atomic_get_property and - * ->atomic_set_property hooks of the corresponding object. Hence atomic - * drivers should not use drm_object_property_set_value() and - * drm_object_property_get_value() on mutable objects, i.e. those + * structure. The decoding is done using the &drm_crtc.atomic_get_property and + * &drm_crtc.atomic_set_property hooks for &struct drm_crtc. For + * &struct drm_plane the hooks are &drm_plane_funcs.atomic_get_property and + * &drm_plane_funcs.atomic_set_property. And for &struct drm_connector + * the hooks are &drm_connector_funcs.atomic_get_property and + * &drm_connector_funcs.atomic_set_property . + * + * Hence atomic drivers should not use drm_object_property_set_value() + * and drm_object_property_get_value() on mutable objects, i.e. those * without the DRM_MODE_PROP_IMMUTABLE flag set. */ uint64_t values[DRM_OBJECT_MAX_PROPERTY]; diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 9934d91619c1..6dd34280e892 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -459,6 +459,8 @@ int of_get_drm_display_mode(struct device_node *np, void drm_mode_set_name(struct drm_display_mode *mode); int drm_mode_hsync(const struct drm_display_mode *mode); int drm_mode_vrefresh(const struct drm_display_mode *mode); +void drm_mode_get_hv_timing(const struct drm_display_mode *mode, + int *hdisplay, int *vdisplay); void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 46f5b349f059..091c42205667 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -111,9 +111,9 @@ struct drm_crtc_helper_funcs { * This callback is used to validate a mode. The parameter mode is the * display mode that userspace requested, adjusted_mode is the mode the * encoders need to be fed with. Note that this is the inverse semantics - * of the meaning for the &drm_encoder and &drm_bridge - * ->mode_fixup() functions. If the CRTC cannot support the requested - * conversion from mode to adjusted_mode it should reject the modeset. + * of the meaning for the &drm_encoder and &drm_bridge_funcs.mode_fixup + * vfunc. If the CRTC cannot support the requested conversion from mode + * to adjusted_mode it should reject the modeset. * * This function is used by both legacy CRTC helpers and atomic helpers. * With atomic helpers it is optional. @@ -134,17 +134,18 @@ struct drm_crtc_helper_funcs { * * Also beware that neither core nor helpers filter modes before * passing them to the driver: While the list of modes that is - * advertised to userspace is filtered using the connector's - * ->mode_valid() callback, neither the core nor the helpers do any - * filtering on modes passed in from userspace when setting a mode. It - * is therefore possible for userspace to pass in a mode that was - * previously filtered out using ->mode_valid() or add a custom mode - * that wasn't probed from EDID or similar to begin with. Even though - * this is an advanced feature and rarely used nowadays, some users rely - * on being able to specify modes manually so drivers must be prepared - * to deal with it. Specifically this means that all drivers need not - * only validate modes in ->mode_valid() but also in ->mode_fixup() to - * make sure invalid modes passed in from userspace are rejected. + * advertised to userspace is filtered using the + * &drm_connector.mode_valid callback, neither the core nor the helpers + * do any filtering on modes passed in from userspace when setting a + * mode. It is therefore possible for userspace to pass in a mode that + * was previously filtered out using &drm_connector.mode_valid or add a + * custom mode that wasn't probed from EDID or similar to begin with. + * Even though this is an advanced feature and rarely used nowadays, + * some users rely on being able to specify modes manually so drivers + * must be prepared to deal with it. Specifically this means that all + * drivers need not only validate modes in &drm_connector.mode_valid but + * also in this or in the &drm_encoder_helper_funcs.mode_fixup callback + * to make sure invalid modes passed in from userspace are rejected. * * RETURNS: * @@ -205,7 +206,7 @@ struct drm_crtc_helper_funcs { * optimized fast-path instead of a full mode set operation with all the * resulting flickering. If it is not present * drm_crtc_helper_set_config() will fall back to a full modeset, using - * the ->mode_set() callback. Since it can't update other planes it's + * the @mode_set callback. Since it can't update other planes it's * incompatible with atomic modeset support. * * This callback is only used by the CRTC helpers and deprecated. @@ -238,8 +239,7 @@ struct drm_crtc_helper_funcs { /** * @load_lut: * - * Load a LUT prepared with the @gamma_set functions from - * &drm_fb_helper_funcs. + * Load a LUT prepared with the &drm_fb_helper_funcs.gamma_set vfunc. * * This callback is optional and is only used by the fbdev emulation * helpers. @@ -257,10 +257,11 @@ struct drm_crtc_helper_funcs { * * This callback should be used to disable the CRTC. With the atomic * drivers it is called after all encoders connected to this CRTC have - * been shut off already using their own ->disable hook. If that - * sequence is too simple drivers can just add their own hooks and call - * it from this CRTC callback here by looping over all encoders - * connected to it using for_each_encoder_on_crtc(). + * been shut off already using their own + * &drm_encoder_helper_funcs.disable hook. If that sequence is too + * simple drivers can just add their own hooks and call it from this + * CRTC callback here by looping over all encoders connected to it using + * for_each_encoder_on_crtc(). * * This hook is used both by legacy CRTC helpers and atomic helpers. * Atomic drivers don't need to implement it if there's no need to @@ -289,10 +290,10 @@ struct drm_crtc_helper_funcs { * * This callback should be used to enable the CRTC. With the atomic * drivers it is called before all encoders connected to this CRTC are - * enabled through the encoder's own ->enable hook. If that sequence is - * too simple drivers can just add their own hooks and call it from this - * CRTC callback here by looping over all encoders connected to it using - * for_each_encoder_on_crtc(). + * enabled through the encoder's own &drm_encoder_helper_funcs.enable + * hook. If that sequence is too simple drivers can just add their own + * hooks and call it from this CRTC callback here by looping over all + * encoders connected to it using for_each_encoder_on_crtc(). * * This hook is used only by atomic helpers, for symmetry with @disable. * Atomic drivers don't need to implement it if there's no need to @@ -316,16 +317,16 @@ struct drm_crtc_helper_funcs { * beforehand. This is calling order used by the default helper * implementation in drm_atomic_helper_check(). * - * When using drm_atomic_helper_check_planes() CRTCs' ->atomic_check() - * hooks are called after the ones for planes, which allows drivers to - * assign shared resources requested by planes in the CRTC callback - * here. For more complicated dependencies the driver can call the provided - * check helpers multiple times until the computed state has a final - * configuration and everything has been checked. + * When using drm_atomic_helper_check_planes() this hook is called + * after the &drm_plane_helper_funcs.atomc_check hook for planes, which + * allows drivers to assign shared resources requested by planes in this + * callback here. For more complicated dependencies the driver can call + * the provided check helpers multiple times until the computed state + * has a final configuration and everything has been checked. * * This function is also allowed to inspect any other object's state and * can add more state objects to the atomic commit if needed. Care must - * be taken though to ensure that state check&compute functions for + * be taken though to ensure that state check and compute functions for * these added states are all called, and derived state in other objects * all updated. Again the recommendation is to just call check helpers * until a maximal configuration is reached. @@ -400,10 +401,11 @@ struct drm_crtc_helper_funcs { * * This callback should be used to disable the CRTC. With the atomic * drivers it is called after all encoders connected to this CRTC have - * been shut off already using their own ->disable hook. If that - * sequence is too simple drivers can just add their own hooks and call - * it from this CRTC callback here by looping over all encoders - * connected to it using for_each_encoder_on_crtc(). + * been shut off already using their own + * &drm_encoder_helper_funcs.disable hook. If that sequence is too + * simple drivers can just add their own hooks and call it from this + * CRTC callback here by looping over all encoders connected to it using + * for_each_encoder_on_crtc(). * * This hook is used only by atomic helpers. Atomic drivers don't * need to implement it if there's no need to disable anything at the @@ -483,16 +485,18 @@ struct drm_encoder_helper_funcs { * Also beware that neither core nor helpers filter modes before * passing them to the driver: While the list of modes that is * advertised to userspace is filtered using the connector's - * ->mode_valid() callback, neither the core nor the helpers do any - * filtering on modes passed in from userspace when setting a mode. It - * is therefore possible for userspace to pass in a mode that was - * previously filtered out using ->mode_valid() or add a custom mode - * that wasn't probed from EDID or similar to begin with. Even though - * this is an advanced feature and rarely used nowadays, some users rely - * on being able to specify modes manually so drivers must be prepared - * to deal with it. Specifically this means that all drivers need not - * only validate modes in ->mode_valid() but also in ->mode_fixup() to - * make sure invalid modes passed in from userspace are rejected. + * &drm_connector_helper_funcs.mode_valid callback, neither the core nor + * the helpers do any filtering on modes passed in from userspace when + * setting a mode. It is therefore possible for userspace to pass in a + * mode that was previously filtered out using + * &drm_connector_helper_funcs.mode_valid or add a custom mode that + * wasn't probed from EDID or similar to begin with. Even though this + * is an advanced feature and rarely used nowadays, some users rely on + * being able to specify modes manually so drivers must be prepared to + * deal with it. Specifically this means that all drivers need not only + * validate modes in &drm_connector.mode_valid but also in this or in + * the &drm_crtc_helper_funcs.mode_fixup callback to make sure + * invalid modes passed in from userspace are rejected. * * RETURNS: * @@ -544,7 +548,7 @@ struct drm_encoder_helper_funcs { * use this hook, because the helper library calls it only once and not * every time the display pipeline is suspend using either DPMS or the * new "ACTIVE" property. Such drivers should instead move all their - * encoder setup into the ->enable() callback. + * encoder setup into the @enable callback. * * This callback is used both by the legacy CRTC helpers and the atomic * modeset helpers. It is optional in the atomic helpers. @@ -570,7 +574,7 @@ struct drm_encoder_helper_funcs { * use this hook, because the helper library calls it only once and not * every time the display pipeline is suspended using either DPMS or the * new "ACTIVE" property. Such drivers should instead move all their - * encoder setup into the ->enable() callback. + * encoder setup into the @enable callback. * * This callback is used by the atomic modeset helpers in place of the * @mode_set callback, if set by the driver. It is optional and should @@ -621,10 +625,10 @@ struct drm_encoder_helper_funcs { * * This callback should be used to disable the encoder. With the atomic * drivers it is called before this encoder's CRTC has been shut off - * using the CRTC's own ->disable hook. If that sequence is too simple - * drivers can just add their own driver private encoder hooks and call - * them from CRTC's callback by looping over all encoders connected to - * it using for_each_encoder_on_crtc(). + * using their own &drm_crtc_helper_funcs.disable hook. If that + * sequence is too simple drivers can just add their own driver private + * encoder hooks and call them from CRTC's callback by looping over all + * encoders connected to it using for_each_encoder_on_crtc(). * * This hook is used both by legacy CRTC helpers and atomic helpers. * Atomic drivers don't need to implement it if there's no need to @@ -651,10 +655,10 @@ struct drm_encoder_helper_funcs { * * This callback should be used to enable the encoder. With the atomic * drivers it is called after this encoder's CRTC has been enabled using - * the CRTC's own ->enable hook. If that sequence is too simple drivers - * can just add their own driver private encoder hooks and call them - * from CRTC's callback by looping over all encoders connected to it - * using for_each_encoder_on_crtc(). + * their own &drm_crtc_helper_funcs.enable hook. If that sequence is + * too simple drivers can just add their own driver private encoder + * hooks and call them from CRTC's callback by looping over all encoders + * connected to it using for_each_encoder_on_crtc(). * * This hook is used only by atomic helpers, for symmetry with @disable. * Atomic drivers don't need to implement it if there's no need to @@ -716,7 +720,7 @@ struct drm_connector_helper_funcs { * @get_modes: * * This function should fill in all modes currently valid for the sink - * into the connector->probed_modes list. It should also update the + * into the &drm_connector.probed_modes list. It should also update the * EDID property by calling drm_mode_connector_update_edid_property(). * * The usual way to implement this is to cache the EDID retrieved in the @@ -725,8 +729,9 @@ struct drm_connector_helper_funcs { * them by calling drm_add_edid_modes(). But connectors that driver a * fixed panel can also manually add specific modes using * drm_mode_probed_add(). Drivers which manually add modes should also - * make sure that the @display_info, @width_mm and @height_mm fields of the - * &struct drm_connector are filled in. + * make sure that the &drm_connector.display_info, + * &drm_connector.width_mm and &drm_connector.height_mm fields are + * filled in. * * Virtual drivers that just want some standard VESA mode with a given * resolution can call drm_add_modes_noedid(), and mark the preferred @@ -735,7 +740,7 @@ struct drm_connector_helper_funcs { * Finally drivers that support audio probably want to update the ELD * data, too, using drm_edid_to_eld(). * - * This function is only called after the ->detect() hook has indicated + * This function is only called after the @detect hook has indicated * that a sink is connected and when the EDID isn't overridden through * sysfs or the kernel commandline. * @@ -768,8 +773,8 @@ struct drm_connector_helper_funcs { * * RETURNS: * - * Either MODE_OK or one of the failure reasons in enum - * &drm_mode_status. + * Either &drm_mode_status.MODE_OK or one of the failure reasons in &enum + * drm_mode_status. */ enum drm_mode_status (*mode_valid)(struct drm_connector *connector, struct drm_display_mode *mode); @@ -875,7 +880,7 @@ struct drm_plane_helper_funcs { * RETURNS: * * 0 on success or one of the following negative error codes allowed by - * the atomic_commit hook in &drm_mode_config_funcs. When using helpers + * the &drm_mode_config_funcs.atomic_commit vfunc. When using helpers * this callback is the only one which can fail an atomic commit, * everything else must complete successfully. */ @@ -898,7 +903,7 @@ struct drm_plane_helper_funcs { * * Drivers should check plane specific constraints in this hook. * - * When using drm_atomic_helper_check_planes() plane's ->atomic_check() + * When using drm_atomic_helper_check_planes() plane's @atomic_check * hooks are called before the ones for CRTCs, which allows drivers to * request shared resources that the CRTC controls here. For more * complicated dependencies the driver can call the provided check helpers @@ -907,7 +912,7 @@ struct drm_plane_helper_funcs { * * This function is also allowed to inspect any other object's state and * can add more state objects to the atomic commit if needed. Care must - * be taken though to ensure that state check&compute functions for + * be taken though to ensure that state check and compute functions for * these added states are all called, and derived state in other objects * all updated. Again the recommendation is to just call check helpers * until a maximal configuration is reached. @@ -936,8 +941,8 @@ struct drm_plane_helper_funcs { * @atomic_update: * * Drivers should use this function to update the plane state. This - * hook is called in-between the ->atomic_begin() and - * ->atomic_flush() of &drm_crtc_helper_funcs. + * hook is called in-between the &drm_crtc_helper_funcs.atomic_begin and + * drm_crtc_helper_funcs.atomic_flush callbacks. * * Note that the power state of the display pipe when this function is * called depends upon the exact helpers and calling sequence the driver @@ -953,14 +958,15 @@ struct drm_plane_helper_funcs { * @atomic_disable: * * Drivers should use this function to unconditionally disable a plane. - * This hook is called in-between the ->atomic_begin() and - * ->atomic_flush() of &drm_crtc_helper_funcs. It is an alternative to + * This hook is called in-between the + * &drm_crtc_helper_funcs.atomic_begin and + * drm_crtc_helper_funcs.atomic_flush callbacks. It is an alternative to * @atomic_update, which will be called for disabling planes, too, if * the @atomic_disable hook isn't implemented. * * This hook is also useful to disable planes in preparation of a modeset, * by calling drm_atomic_helper_disable_planes_on_crtc() from the - * ->disable() hook in &drm_crtc_helper_funcs. + * &drm_crtc_helper_funcs.disable hook. * * Note that the power state of the display pipe when this function is * called depends upon the exact helpers and calling sequence the driver diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index d918ce45ec2c..96d39fbd12ca 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -64,7 +64,7 @@ struct drm_modeset_acquire_ctx { /** * struct drm_modeset_lock - used for locking modeset resources. * @mutex: resource locking - * @head: used to hold it's place on state->locked list when + * @head: used to hold it's place on &drm_atomi_state.locked list when * part of an atomic update * * Used for locking CRTCs and other modeset resources. diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index e049bc52fb07..20867b4371ab 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -247,11 +247,11 @@ struct drm_plane_funcs { * @atomic_duplicate_state: * * Duplicate the current atomic state for this plane and return it. - * The core and helpers gurantee that any atomic state duplicated with + * The core and helpers guarantee that any atomic state duplicated with * this hook and still owned by the caller (i.e. not transferred to the - * driver by calling ->atomic_commit() from struct - * &drm_mode_config_funcs) will be cleaned up by calling the - * @atomic_destroy_state hook in this structure. + * driver by calling &drm_mode_config_funcs.atomic_commit) will be + * cleaned up by calling the @atomic_destroy_state hook in this + * structure. * * Atomic drivers which don't subclass &struct drm_plane_state should use * drm_atomic_helper_plane_duplicate_state(). Drivers that subclass the @@ -259,7 +259,7 @@ struct drm_plane_funcs { * __drm_atomic_helper_plane_duplicate_state() to make sure shared state is * duplicated in a consistent fashion across drivers. * - * It is an error to call this hook before plane->state has been + * It is an error to call this hook before &drm_plane.state has been * initialized correctly. * * NOTE: @@ -372,7 +372,7 @@ struct drm_plane_funcs { * * This optional hook should be used to unregister the additional * userspace interfaces attached to the plane from - * late_unregister(). It is called from drm_dev_unregister(), + * @late_register. It is called from drm_dev_unregister(), * early in the driver unload sequence to disable userspace access * before data structures are torndown. */ @@ -423,8 +423,8 @@ enum drm_plane_type { * * Primary planes represent a "main" plane for a CRTC. Primary planes * are the planes operated upon by CRTC modesetting and flipping - * operations described in the page_flip and set_config hooks in struct - * &drm_crtc_funcs. + * operations described in the &drm_crtc_funcs.page_flip and + * &drm_crtc_funcs.set_config hooks. */ DRM_PLANE_TYPE_PRIMARY, @@ -470,9 +470,9 @@ struct drm_plane { /** * @mutex: * - * Protects modeset plane state, together with the mutex of &drm_crtc - * this plane is linked to (when active, getting actived or getting - * disabled). + * Protects modeset plane state, together with the &drm_crtc.mutex of + * CRTC this plane is linked to (when active, getting activated or + * getting disabled). */ struct drm_modeset_lock mutex; @@ -580,7 +580,7 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev, * * Iterate over all legacy planes of @dev, excluding primary and cursor planes. * This is useful for implementing userspace apis when userspace is not - * universal plane aware. See also enum &drm_plane_type. + * universal plane aware. See also &enum drm_plane_type. */ #define drm_for_each_legacy_plane(plane, dev) \ list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \ diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h index 43c4b6a2046d..f66fdb47551c 100644 --- a/include/drm/drm_property.h +++ b/include/drm/drm_property.h @@ -30,7 +30,7 @@ /** * struct drm_property_enum - symbolic values for enumerations * @value: numeric property value for this enum entry - * @head: list of enum values, linked to enum_list in &drm_property + * @head: list of enum values, linked to &drm_property.enum_list * @name: symbolic name for the enum * * For enumeration and bitmask properties this structure stores the symbolic @@ -191,9 +191,9 @@ struct drm_property { * struct drm_property_blob - Blob data for &drm_property * @base: base KMS object * @dev: DRM device - * @head_global: entry on the global blob list in &drm_mode_config - * property_blob_list. - * @head_file: entry on the per-file blob list in &drm_file blobs list. + * @head_global: entry on the global blob list in + * &drm_mode_config.property_blob_list. + * @head_file: entry on the per-file blob list in &drm_file.blobs list. * @length: size of the blob in bytes, invariant over the lifetime of the object * @data: actual data, embedded at the end of this structure * diff --git a/include/drm/drm_simple_kms_helper.h b/include/drm/drm_simple_kms_helper.h index fe8c4ba905ac..fffbb95a0915 100644 --- a/include/drm/drm_simple_kms_helper.h +++ b/include/drm/drm_simple_kms_helper.h @@ -10,6 +10,10 @@ #ifndef __LINUX_DRM_SIMPLE_KMS_HELPER_H #define __LINUX_DRM_SIMPLE_KMS_HELPER_H +#include <drm/drm_crtc.h> +#include <drm/drm_encoder.h> +#include <drm/drm_plane.h> + struct drm_simple_display_pipe; /** @@ -73,9 +77,9 @@ struct drm_simple_display_pipe_funcs { /** * @prepare_fb: * - * Optional, called by &struct drm_plane_helper_funcs ->prepare_fb . - * Please read the documentation for the ->prepare_fb hook in - * &struct drm_plane_helper_funcs for more details. + * Optional, called by &drm_plane_helper_funcs.prepare_fb. Please read + * the documentation for the &drm_plane_helper_funcs.prepare_fb hook for + * more details. */ int (*prepare_fb)(struct drm_simple_display_pipe *pipe, struct drm_plane_state *plane_state); @@ -83,9 +87,9 @@ struct drm_simple_display_pipe_funcs { /** * @cleanup_fb: * - * Optional, called by &struct drm_plane_helper_funcs ->cleanup_fb . - * Please read the documentation for the ->cleanup_fb hook in - * &struct drm_plane_helper_funcs for more details. + * Optional, called by &drm_plane_helper_funcs.cleanup_fb. Please read + * the documentation for the &drm_plane_helper_funcs.cleanup_fb hook for + * more details. */ void (*cleanup_fb)(struct drm_simple_display_pipe *pipe, struct drm_plane_state *plane_state); diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 1596d53c9ccf..ef20abb8119b 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -167,6 +167,7 @@ extern "C" { #define DRM_FORMAT_MOD_VENDOR_NV 0x03 #define DRM_FORMAT_MOD_VENDOR_SAMSUNG 0x04 #define DRM_FORMAT_MOD_VENDOR_QCOM 0x05 +#define DRM_FORMAT_MOD_VENDOR_VIVANTE 0x06 /* add more to the end as needed */ #define fourcc_mod_code(vendor, val) \ @@ -251,6 +252,46 @@ extern "C" { */ #define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE fourcc_mod_code(SAMSUNG, 1) +/* Vivante framebuffer modifiers */ + +/* + * Vivante 4x4 tiling layout + * + * This is a simple tiled layout using tiles of 4x4 pixels in a row-major + * layout. + */ +#define DRM_FORMAT_MOD_VIVANTE_TILED fourcc_mod_code(VIVANTE, 1) + +/* + * Vivante 64x64 super-tiling layout + * + * This is a tiled layout using 64x64 pixel super-tiles, where each super-tile + * contains 8x4 groups of 2x4 tiles of 4x4 pixels (like above) each, all in row- + * major layout. + * + * For more information: see + * https://github.com/etnaviv/etna_viv/blob/master/doc/hardware.md#texture-tiling + */ +#define DRM_FORMAT_MOD_VIVANTE_SUPER_TILED fourcc_mod_code(VIVANTE, 2) + +/* + * Vivante 4x4 tiling layout for dual-pipe + * + * Same as the 4x4 tiling layout, except every second 4x4 pixel tile starts at a + * different base address. Offsets from the base addresses are therefore halved + * compared to the non-split tiled layout. + */ +#define DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED fourcc_mod_code(VIVANTE, 3) + +/* + * Vivante 64x64 super-tiling layout for dual-pipe + * + * Same as the 64x64 super-tiling layout, except every second 4x4 pixel tile + * starts at a different base address. Offsets from the base addresses are + * therefore halved compared to the non-split super-tiled layout. + */ +#define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4) + #if defined(__cplusplus) } #endif diff --git a/lib/prime_numbers.c b/lib/prime_numbers.c index c9b3c29614aa..550eec457c2e 100644 --- a/lib/prime_numbers.c +++ b/lib/prime_numbers.c @@ -124,7 +124,8 @@ static bool expand_to_next_prime(unsigned long x) return false; sz = round_up(sz, BITS_PER_LONG); - new = kmalloc(sizeof(*new) + bitmap_size(sz), GFP_KERNEL); + new = kmalloc(sizeof(*new) + bitmap_size(sz), + GFP_KERNEL | __GFP_NOWARN); if (!new) return false; |